Merge remote-tracking branch 'upstream/develop' into
authortobiasKaminsky <tobias@kaminsky.me>
Fri, 24 Oct 2014 16:44:04 +0000 (18:44 +0200)
committertobiasKaminsky <tobias@kaminsky.me>
Fri, 24 Oct 2014 16:44:04 +0000 (18:44 +0200)
bugfixMultipleSelect

Conflicts:
src/com/owncloud/android/ui/fragment/LocalFileListFragment.java

404 files changed:
.classpath
.gitignore
.gitmodules
.travis.yml [new file with mode: 0644]
AndroidManifest.xml
SETUP.md
THIRD_PARTY.txt
libs/disklrucache-2.0.2.jar [new file with mode: 0644]
libs/jackrabbit-webdav-2.2.5-jar-with-dependencies.jar [deleted file]
libs/touch-image-view.jar [new file with mode: 0644]
lint.xml [deleted file]
oc_jb_workaround/AndroidManifest.xml
oc_jb_workaround/res/drawable-xhdpi/main_app_icon.png [deleted file]
oc_jb_workaround/res/drawable-xhdpi/workaround_app_icon.png [deleted file]
owncloud-android-library [new submodule]
pom.xml
project.properties
res/drawable-hdpi-v11/notification_icon.png [new file with mode: 0644]
res/drawable-hdpi-v9/ic_action_create_dir.png [deleted file]
res/drawable-hdpi-v9/ic_action_settings.png [new file with mode: 0644]
res/drawable-hdpi-v9/ic_action_upload.png [deleted file]
res/drawable-hdpi/copy_link.png [new file with mode: 0644]
res/drawable-hdpi/file.png
res/drawable-hdpi/file_doc.png
res/drawable-hdpi/file_image.png
res/drawable-hdpi/file_movie.png
res/drawable-hdpi/file_pdf.png
res/drawable-hdpi/file_ppt.png [new file with mode: 0644]
res/drawable-hdpi/file_sound.png
res/drawable-hdpi/file_xls.png [new file with mode: 0644]
res/drawable-hdpi/file_zip.png
res/drawable-hdpi/folder_public.png [new file with mode: 0644]
res/drawable-hdpi/ic_action_create_dir.png
res/drawable-hdpi/ic_action_settings.png [new file with mode: 0644]
res/drawable-hdpi/ic_action_upload.png
res/drawable-hdpi/ic_favorite.png [new file with mode: 0644]
res/drawable-hdpi/ic_menu_archive.png
res/drawable-hdpi/notification_icon.png [new file with mode: 0644]
res/drawable-hdpi/shared_with_me.png [new file with mode: 0644]
res/drawable-hdpi/shared_with_me_folder.png [new file with mode: 0644]
res/drawable-hdpi/sharedlink.png [new file with mode: 0644]
res/drawable-hdpi/winter_holidays_icon.png [new file with mode: 0644]
res/drawable-ldpi-v9/ic_action_create_dir.png [deleted file]
res/drawable-ldpi-v9/ic_action_settings.png [new file with mode: 0644]
res/drawable-ldpi-v9/ic_action_upload.png [deleted file]
res/drawable-ldpi/copy_link.png [new file with mode: 0644]
res/drawable-ldpi/file.png
res/drawable-ldpi/file_doc.png
res/drawable-ldpi/file_image.png
res/drawable-ldpi/file_movie.png
res/drawable-ldpi/file_pdf.png
res/drawable-ldpi/file_ppt.png [new file with mode: 0644]
res/drawable-ldpi/file_sound.png
res/drawable-ldpi/file_xls.png [new file with mode: 0644]
res/drawable-ldpi/file_zip.png
res/drawable-ldpi/ic_action_create_dir.png
res/drawable-ldpi/ic_action_settings.png [new file with mode: 0644]
res/drawable-ldpi/ic_action_upload.png
res/drawable-ldpi/ic_menu_archive.png
res/drawable-ldpi/winter_holidays_icon.png [new file with mode: 0644]
res/drawable-mdpi-v11/notification_icon.png [new file with mode: 0644]
res/drawable-mdpi-v9/ic_action_create_dir.png [deleted file]
res/drawable-mdpi-v9/ic_action_settings.png [new file with mode: 0644]
res/drawable-mdpi-v9/ic_action_upload.png [deleted file]
res/drawable-mdpi/copy_link.png [new file with mode: 0644]
res/drawable-mdpi/file.png
res/drawable-mdpi/file_doc.png
res/drawable-mdpi/file_image.png
res/drawable-mdpi/file_movie.png
res/drawable-mdpi/file_pdf.png
res/drawable-mdpi/file_ppt.png [new file with mode: 0644]
res/drawable-mdpi/file_sound.png
res/drawable-mdpi/file_xls.png [new file with mode: 0644]
res/drawable-mdpi/file_zip.png
res/drawable-mdpi/folder_public.png [new file with mode: 0644]
res/drawable-mdpi/ic_action_create_dir.png
res/drawable-mdpi/ic_action_settings.png [new file with mode: 0644]
res/drawable-mdpi/ic_action_upload.png
res/drawable-mdpi/ic_favorite.png [new file with mode: 0644]
res/drawable-mdpi/ic_menu_archive.png
res/drawable-mdpi/notification_icon.png [new file with mode: 0644]
res/drawable-mdpi/shared_with_me.png [new file with mode: 0644]
res/drawable-mdpi/shared_with_me_folder.png [new file with mode: 0644]
res/drawable-mdpi/sharedlink.png [new file with mode: 0644]
res/drawable-mdpi/winter_holidays_icon.png [new file with mode: 0644]
res/drawable-xhdpi-v11/notification_icon.png [new file with mode: 0644]
res/drawable-xhdpi/copy_link.png [new file with mode: 0644]
res/drawable-xhdpi/ic_favorite.png [new file with mode: 0644]
res/drawable-xhdpi/icon.png [new file with mode: 0644]
res/drawable-xhdpi/notification_icon.png [new file with mode: 0644]
res/drawable-xhdpi/shared_with_me.png [new file with mode: 0644]
res/drawable-xhdpi/sharedlink.png [new file with mode: 0644]
res/drawable/downloading_file_indicator.png
res/drawable/ic_favorite.png [deleted file]
res/drawable/local_file_indicator.png
res/drawable/uploading_file_indicator.png
res/layout-land/account_setup.xml
res/layout-v11/activity_row.xml [new file with mode: 0644]
res/layout-v11/notification_with_progress_bar.xml [new file with mode: 0644]
res/layout/account_setup.xml
res/layout/activity_row.xml [new file with mode: 0644]
res/layout/failed_upload_files.xml [deleted file]
res/layout/failed_upload_message_view.xml [deleted file]
res/layout/file_download_fragment.xml
res/layout/files_move.xml [new file with mode: 0644]
res/layout/list_fragment.xml
res/layout/list_item.xml
res/layout/log_send_file.xml
res/layout/notification_with_progress_bar.xml [new file with mode: 0644]
res/layout/preview_image_activity.xml
res/layout/preview_image_fragment.xml
res/layout/progressbar_layout.xml [deleted file]
res/layout/ssl_untrusted_cert_layout.xml [new file with mode: 0644]
res/layout/ssl_validator_layout.xml
res/layout/sso_dialog.xml
res/menu/account_picker.xml [deleted file]
res/menu/file_actions_menu.xml
res/menu/main_menu.xml
res/values-af-rZA/strings.xml
res/values-ak/strings.xml [new file with mode: 0644]
res/values-am-rET/strings.xml [new file with mode: 0644]
res/values-ar/strings.xml
res/values-az/strings.xml [new file with mode: 0644]
res/values-be/strings.xml
res/values-bg-rBG/strings.xml
res/values-bn-rBD/strings.xml
res/values-bn-rIN/strings.xml [new file with mode: 0644]
res/values-bs/strings.xml
res/values-ca/strings.xml
res/values-cs-rCZ/strings.xml
res/values-cy-rGB/strings.xml
res/values-da/strings.xml
res/values-de-rAT/strings.xml
res/values-de-rCH/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-en-rNZ/strings.xml [new file with mode: 0644]
res/values-eo/strings.xml
res/values-es-rAR/strings.xml
res/values-es-rBO/strings.xml [new file with mode: 0644]
res/values-es-rCL/strings.xml [new file with mode: 0644]
res/values-es-rCO/strings.xml [new file with mode: 0644]
res/values-es-rCR/strings.xml [new file with mode: 0644]
res/values-es-rEC/strings.xml [new file with mode: 0644]
res/values-es-rMX/strings.xml
res/values-es-rPE/strings.xml [new file with mode: 0644]
res/values-es-rPY/strings.xml [new file with mode: 0644]
res/values-es-rUS/strings.xml [new file with mode: 0644]
res/values-es-rUY/strings.xml [new file with mode: 0644]
res/values-es/strings.xml
res/values-et-rEE/strings.xml
res/values-eu-rES/strings.xml [new file with mode: 0644]
res/values-eu/strings.xml
res/values-fa/strings.xml
res/values-fi-rFI/strings.xml
res/values-fr-rCA/strings.xml [new file with mode: 0644]
res/values-fr/strings.xml
res/values-fy-rNL/strings.xml [new file with mode: 0644]
res/values-gl/strings.xml
res/values-gu/strings.xml [new file with mode: 0644]
res/values-he/strings.xml
res/values-hi-rIN/strings.xml [new file with mode: 0644]
res/values-hi/strings.xml
res/values-hr/strings.xml
res/values-hu-rHU/strings.xml
res/values-hy/strings.xml
res/values-ia/strings.xml
res/values-id/strings.xml
res/values-io/strings.xml [new file with mode: 0644]
res/values-is/strings.xml
res/values-it/strings.xml
res/values-ja-rJP/strings.xml
res/values-jv/strings.xml [new file with mode: 0644]
res/values-ka-rGE/strings.xml
res/values-km/strings.xml
res/values-kn/strings.xml
res/values-ko/strings.xml
res/values-ku-rIQ/strings.xml
res/values-lb/strings.xml
res/values-lt-rLT/strings.xml
res/values-lv/strings.xml
res/values-mg/strings.xml [new file with mode: 0644]
res/values-mk/strings.xml
res/values-ml-rIN/strings.xml
res/values-ml/strings.xml [new file with mode: 0644]
res/values-mn/strings.xml [new file with mode: 0644]
res/values-ms-rMY/strings.xml
res/values-mt-rMT/strings.xml [new file with mode: 0644]
res/values-my/strings.xml
res/values-nb-rNO/strings.xml
res/values-ne/strings.xml
res/values-nl/strings.xml
res/values-nn-rNO/strings.xml
res/values-oc/strings.xml
res/values-or-rIN/strings.xml [new file with mode: 0644]
res/values-pa/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-rRU/strings.xml
res/values-ru/strings.xml
res/values-si-rLK/strings.xml
res/values-sk-rSK/strings.xml
res/values-sk/strings.xml
res/values-sl/strings.xml
res/values-sq/strings.xml
res/values-sr-rSP/strings.xml
res/values-sr/strings.xml
res/values-su/strings.xml [new file with mode: 0644]
res/values-sv/strings.xml
res/values-sw-rKE/strings.xml
res/values-ta-rIN/strings.xml [new file with mode: 0644]
res/values-ta-rLK/strings.xml
res/values-te/strings.xml
res/values-tg-rTJ/strings.xml [new file with mode: 0644]
res/values-th-rTH/strings.xml
res/values-tr/strings.xml
res/values-ug/strings.xml
res/values-uk/strings.xml
res/values-ur-rPK/strings.xml
res/values-ur/strings.xml [new file with mode: 0644]
res/values-uz/strings.xml
res/values-v11/versioned_styles.xml
res/values-v9/versioned_styles.xml [new file with mode: 0644]
res/values-vi/strings.xml
res/values-zh-rCN/strings.xml
res/values-zh-rHK/strings.xml
res/values-zh-rTW/strings.xml
res/values/colors.xml
res/values/setup.xml
res/values/strings.xml
res/values/styles.xml
res/values/versioned_styles.xml
res/xml/preferences.xml
setup_env.bat
setup_env.sh
src/com/owncloud/android/DisplayUtils.java [deleted file]
src/com/owncloud/android/Log_OC.java [deleted file]
src/com/owncloud/android/MainApp.java
src/com/owncloud/android/OwnCloudSession.java [deleted file]
src/com/owncloud/android/Uploader.java [deleted file]
src/com/owncloud/android/authentication/AccountAuthenticator.java
src/com/owncloud/android/authentication/AccountUtils.java
src/com/owncloud/android/authentication/AuthenticatorActivity.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 [new file with mode: 0644]
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/FileHandler.java [deleted file]
src/com/owncloud/android/files/FileMenuFilter.java [new file with mode: 0644]
src/com/owncloud/android/files/FileOperationsHelper.java [new file with mode: 0644]
src/com/owncloud/android/files/InstantUploadBroadcastReceiver.java
src/com/owncloud/android/files/OwnCloudFileObserver.java [deleted file]
src/com/owncloud/android/files/managers/OCNotificationManager.java [deleted file]
src/com/owncloud/android/files/services/FileDownloader.java
src/com/owncloud/android/files/services/FileObserverService.java [deleted file]
src/com/owncloud/android/files/services/FileUploader.java
src/com/owncloud/android/media/MediaService.java
src/com/owncloud/android/media/MediaServiceBinder.java
src/com/owncloud/android/network/AdvancedSslSocketFactory.java [deleted file]
src/com/owncloud/android/network/AdvancedX509TrustManager.java [deleted file]
src/com/owncloud/android/network/BearerAuthScheme.java [deleted file]
src/com/owncloud/android/network/BearerCredentials.java [deleted file]
src/com/owncloud/android/network/CertificateCombinedException.java [deleted file]
src/com/owncloud/android/network/OwnCloudClientUtils.java [deleted file]
src/com/owncloud/android/network/ProgressiveDataTransferer.java [deleted file]
src/com/owncloud/android/notifications/NotificationBuilderWithProgressBar.java [new file with mode: 0644]
src/com/owncloud/android/notifications/NotificationDelayer.java [new file with mode: 0644]
src/com/owncloud/android/operations/ChunkedUploadFileOperation.java [deleted file]
src/com/owncloud/android/operations/CreateFolderOperation.java
src/com/owncloud/android/operations/CreateShareOperation.java [new file with mode: 0644]
src/com/owncloud/android/operations/DetectAuthenticationMethodOperation.java [new file with mode: 0644]
src/com/owncloud/android/operations/DownloadFileOperation.java
src/com/owncloud/android/operations/ExistenceCheckOperation.java [deleted file]
src/com/owncloud/android/operations/GetServerInfoOperation.java [new file with mode: 0644]
src/com/owncloud/android/operations/GetSharesForFileOperation.java [new file with mode: 0644]
src/com/owncloud/android/operations/GetSharesOperation.java [new file with mode: 0644]
src/com/owncloud/android/operations/MoveFileOperation.java [new file with mode: 0644]
src/com/owncloud/android/operations/OAuth2GetAccessToken.java
src/com/owncloud/android/operations/OnRemoteOperationListener.java [deleted file]
src/com/owncloud/android/operations/OperationCancelledException.java [deleted file]
src/com/owncloud/android/operations/OwnCloudServerCheckOperation.java [deleted file]
src/com/owncloud/android/operations/RemoteOperation.java [deleted file]
src/com/owncloud/android/operations/RemoteOperationResult.java [deleted file]
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 [new file with mode: 0644]
src/com/owncloud/android/operations/UpdateOCVersionOperation.java
src/com/owncloud/android/operations/UploadFileOperation.java
src/com/owncloud/android/operations/common/SyncOperation.java [new file with mode: 0644]
src/com/owncloud/android/providers/FileContentProvider.java
src/com/owncloud/android/services/OperationsService.java [new file with mode: 0644]
src/com/owncloud/android/services/observer/FileObserverService.java [new file with mode: 0644]
src/com/owncloud/android/services/observer/FolderObserver.java [new file with mode: 0644]
src/com/owncloud/android/syncadapter/AbstractOwnCloudSyncAdapter.java
src/com/owncloud/android/syncadapter/ContactSyncAdapter.java
src/com/owncloud/android/syncadapter/FileSyncAdapter.java
src/com/owncloud/android/syncadapter/FileSyncService.java
src/com/owncloud/android/ui/CheckBoxPreferenceWithLongTitle.java [new file with mode: 0644]
src/com/owncloud/android/ui/LongClickableCheckBoxPreference.java [new file with mode: 0644]
src/com/owncloud/android/ui/activity/AccountSelectActivity.java [deleted file]
src/com/owncloud/android/ui/activity/ComponentsGetter.java [new file with mode: 0644]
src/com/owncloud/android/ui/activity/ConflictsResolveActivity.java
src/com/owncloud/android/ui/activity/CopyToClipboardActivity.java [new file with mode: 0644]
src/com/owncloud/android/ui/activity/ErrorsWhileCopyingHandlerActivity.java
src/com/owncloud/android/ui/activity/FailedUploadActivity.java [deleted file]
src/com/owncloud/android/ui/activity/FileActivity.java
src/com/owncloud/android/ui/activity/FileDisplayActivity.java
src/com/owncloud/android/ui/activity/GenericExplanationActivity.java
src/com/owncloud/android/ui/activity/HookActivity.java [new file with mode: 0644]
src/com/owncloud/android/ui/activity/InstantUploadActivity.java [deleted file]
src/com/owncloud/android/ui/activity/LogHistoryActivity.java
src/com/owncloud/android/ui/activity/MoveActivity.java [new file with mode: 0644]
src/com/owncloud/android/ui/activity/OnEnforceableRefreshListener.java [new file with mode: 0644]
src/com/owncloud/android/ui/activity/PinCodeActivity.java
src/com/owncloud/android/ui/activity/Preferences.java
src/com/owncloud/android/ui/activity/TransferServiceGetter.java [deleted file]
src/com/owncloud/android/ui/activity/UploadFilesActivity.java
src/com/owncloud/android/ui/activity/Uploader.java [new file with mode: 0644]
src/com/owncloud/android/ui/adapter/CertificateCombinedExceptionViewAdapter.java [new file with mode: 0644]
src/com/owncloud/android/ui/adapter/DiskLruImageCache.java [new file with mode: 0644]
src/com/owncloud/android/ui/adapter/FileListListAdapter.java
src/com/owncloud/android/ui/adapter/LocalFileListAdapter.java
src/com/owncloud/android/ui/adapter/SslCertificateViewAdapter.java [new file with mode: 0644]
src/com/owncloud/android/ui/adapter/SslErrorViewAdapter.java [new file with mode: 0644]
src/com/owncloud/android/ui/adapter/X509CertificateViewAdapter.java [new file with mode: 0644]
src/com/owncloud/android/ui/dialog/ChangelogDialog.java
src/com/owncloud/android/ui/dialog/ConfirmationDialogFragment.java [new file with mode: 0644]
src/com/owncloud/android/ui/dialog/ConflictsResolveDialog.java
src/com/owncloud/android/ui/dialog/CreateFolderDialogFragment.java [new file with mode: 0644]
src/com/owncloud/android/ui/dialog/CredentialsDialogFragment.java [new file with mode: 0644]
src/com/owncloud/android/ui/dialog/EditNameDialog.java [deleted file]
src/com/owncloud/android/ui/dialog/LoadingDialog.java
src/com/owncloud/android/ui/dialog/RemoveFileDialogFragment.java [new file with mode: 0644]
src/com/owncloud/android/ui/dialog/RenameFileDialogFragment.java [new file with mode: 0644]
src/com/owncloud/android/ui/dialog/SamlWebViewDialog.java
src/com/owncloud/android/ui/dialog/ShareLinkToDialog.java [new file with mode: 0644]
src/com/owncloud/android/ui/dialog/SslUntrustedCertDialog.java [new file with mode: 0644]
src/com/owncloud/android/ui/dialog/SslValidatorDialog.java
src/com/owncloud/android/ui/fragment/ConfirmationDialogFragment.java [deleted file]
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/ImageViewCustom.java [new file with mode: 0644]
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 [new file with mode: 0644]
src/com/owncloud/android/utils/DisplayUtils.java [new file with mode: 0644]
src/com/owncloud/android/utils/ErrorMessageAdapter.java [new file with mode: 0644]
src/com/owncloud/android/utils/FileStorageUtils.java
src/com/owncloud/android/utils/OwnCloudSession.java [new file with mode: 0644]
src/com/owncloud/android/utils/OwnCloudVersion.java [deleted file]
src/com/owncloud/android/utils/TouchImageViewCustom.java [new file with mode: 0644]
src/eu/alefzero/webdav/ChunkFromFileChannelRequestEntity.java [deleted file]
src/eu/alefzero/webdav/FileRequestEntity.java [deleted file]
src/eu/alefzero/webdav/OnDatatransferProgressListener.java [deleted file]
src/eu/alefzero/webdav/WebdavClient.java [deleted file]
src/eu/alefzero/webdav/WebdavEntry.java [deleted file]
src/eu/alefzero/webdav/WebdavUtils.java [deleted file]
src/third_parties/daveKoeller/AlphanumComparator.java [new file with mode: 0644]
src/third_parties/daveKoeller/lgpl-2.1.txt [new file with mode: 0644]
tests/.classpath
tests/ant.properties [new file with mode: 0644]
tests/build.xml [new file with mode: 0644]
tests/project.properties
tests/src/com/owncloud/android/test/AccountUtilsTest.java
third_party/android-support-library/android-support-v4.jar
third_party/touch-image-view/LICENSE [new file with mode: 0644]
third_party/transifex-client/.gitignore [deleted file]
third_party/transifex-client/DEVELOPMENT.rst [deleted file]
third_party/transifex-client/LICENSE [deleted file]
third_party/transifex-client/MANIFEST.in [deleted file]
third_party/transifex-client/README.rst [deleted file]
third_party/transifex-client/setup.py [deleted file]
third_party/transifex-client/tests/__init__.py [deleted file]
third_party/transifex-client/tests/test_processors.py [deleted file]
third_party/transifex-client/tests/test_project.py [deleted file]
third_party/transifex-client/tx [deleted file]
third_party/transifex-client/txclib/__init__.py [deleted file]
third_party/transifex-client/txclib/commands.py [deleted file]
third_party/transifex-client/txclib/config.py [deleted file]
third_party/transifex-client/txclib/exceptions.py [deleted file]
third_party/transifex-client/txclib/http_utils.py [deleted file]
third_party/transifex-client/txclib/log.py [deleted file]
third_party/transifex-client/txclib/parsers.py [deleted file]
third_party/transifex-client/txclib/processors.py [deleted file]
third_party/transifex-client/txclib/project.py [deleted file]
third_party/transifex-client/txclib/urls.py [deleted file]
third_party/transifex-client/txclib/utils.py [deleted file]
third_party/transifex-client/txclib/web.py [deleted file]

index 7bc01d9..5176974 100644 (file)
@@ -1,9 +1,9 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <classpath>
-       <classpathentry kind="src" path="src"/>
-       <classpathentry kind="src" path="gen"/>
        <classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
        <classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
        <classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.DEPENDENCIES"/>
+       <classpathentry kind="src" path="src"/>
+       <classpathentry kind="src" path="gen"/>
        <classpathentry kind="output" path="bin/classes"/>
 </classpath>
index ac30011..9b9bd8e 100644 (file)
@@ -13,18 +13,22 @@ bin/
 gen/
 target/
 
-# Local configuration file (sdk path, etc)
+# Local configuration files (sdk path, etc)
 local.properties
+oc_workaround/local.properties
+oc_framework/local.properties
+oc_framework-test-project/local.properties
+tests/local.properties
 
 # Mac .DS_Store files
 .DS_Store
 
-# These files are created automatically by Eclipse:
-tests/proguard-project.txt
-tests/project.properties
-tests/ant.properties
-tests/build.xml
+# Proguard README
 proguard-project.txt
+oc_workaround/proguard-project.txt
+oc_framework/proguard-project.txt
+oc_framework-test-project/proguard-project.txt
+tests/proguard-project.txt
 
 # Should not be commited inside this repo:
 actionbarsherlock/
\ No newline at end of file
index b41da32..f0ca872 100644 (file)
@@ -1,3 +1,6 @@
 [submodule "actionbarsherlock"]
        path = actionbarsherlock
        url = git://github.com/JakeWharton/ActionBarSherlock.git
+[submodule "owncloud-android-library"]
+       path = owncloud-android-library
+       url = git://github.com/owncloud/android-library.git
diff --git a/.travis.yml b/.travis.yml
new file mode 100644 (file)
index 0000000..50b73d1
--- /dev/null
@@ -0,0 +1,22 @@
+language: android
+android:
+  components:
+    - build-tools-20.0.0
+    - android-19
+    - android-17
+    - android-14
+    - extra-android-support
+  licenses:
+    - 'android-sdk-license-5be876d5'
+    - 'android-sdk-license-598b93a6'
+  
+jdk: oraclejdk7
+
+before_install:
+  - rm pom.xml
+  - ./setup_env.sh
+
+script:
+  - ant clean
+  - ant debug
+
index f1900f8..a5990af 100644 (file)
@@ -3,7 +3,7 @@
   ownCloud Android client application
 
   Copyright (C) 2012  Bartek Przybylski
-  Copyright (C) 2012-2013 ownCloud Inc.
+  Copyright (C) 2012-2014 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="105000"
-    android:versionName="1.5.0" xmlns:android="http://schemas.android.com/apk/res/android">
+    android:versionCode="10600100"
+    android:versionName="1.6.1" 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" />
             >
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
-
                 <category android:name="android.intent.category.LAUNCHER" />
             </intent-filter>
         </activity>
         <activity android:name=".ui.activity.UploadFilesActivity">
         </activity>
-               <activity android:name=".ui.activity.InstantUploadActivity">
-        </activity>
-        <activity android:name=".ui.activity.FailedUploadActivity" android:theme="@android:style/Theme.Dialog" android:excludeFromRecents="true"/>
-        <activity android:name=".Uploader" >
+        <activity android:name=".ui.activity.Uploader" >
             <intent-filter>
                 <action android:name="android.intent.action.SEND" >
                 </action>
@@ -83,7 +79,8 @@
 
                 <data android:mimeType="*/*" >
                 </data>
-            </intent-filter>
+
+                       </intent-filter>
         </activity>
         <activity
             android:name=".ui.activity.Preferences"
         <activity android:name=".ui.activity.PreferencesNewSessionewSession" >
         </activity>
         
-        <activity      android:name=".ui.preview.PreviewImageActivity" />
+        <activity      
+            android:name=".ui.preview.PreviewImageActivity" 
+            />
                        
-        <activity      android:name=".ui.preview.PreviewVideoActivity"
-                                       android:label="@string/app_name"
-                                       android:theme="@style/Theme.ownCloud.Fullscreen" >
+        <activity      
+            android:name=".ui.preview.PreviewVideoActivity"
+                       android:label="@string/app_name"
+                       android:theme="@style/Theme.ownCloud.Fullscreen" 
+                       >
                </activity>        
 
         <service
         <service
             android:name=".syncadapter.FileSyncService"
             android:exported="true" 
-            android:process=":sync">
+            >
             <intent-filter>
                 <action android:name="android.content.SyncAdapter" />
             </intent-filter>
             </intent-filter>
         </activity>
 
+        <service android:name=".services.OperationsService" />
         <service android:name=".files.services.FileDownloader" />
         <service android:name=".files.services.FileUploader" />
         <service android:name=".media.MediaService" />
         
         <activity android:name=".ui.activity.PinCodeActivity" />
-        <activity android:name=".ui.activity.AccountSelectActivity" android:uiOptions="none" android:label="@string/prefs_accounts"></activity>
         <activity android:name=".ui.activity.ConflictsResolveActivity"/>
         <activity android:name=".ui.activity.GenericExplanationActivity"/>
         <activity android:name=".ui.activity.ErrorsWhileCopyingHandlerActivity"/>
                 <data android:mimeType="image/*" />
             </intent-filter>
             <intent-filter>
+                <action android:name="android.hardware.action.NEW_VIDEO" />
+                <data android:mimeType="video/*" />
+            </intent-filter>
+            <intent-filter>
                 <action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>
             </intent-filter>
         </receiver>
                 <action android:name="android.intent.action.BOOT_COMPLETED"/>
             </intent-filter>
         </receiver>
-        <service android:name=".files.services.FileObserverService"/>
+        <service android:name=".services.observer.FileObserverService"/>
+        
+               <activity
+                       android:name=".ui.activity.CopyToClipboardActivity"
+                       android:label="@string/copy_link"
+                       android:icon="@drawable/copy_link"/>
+
+        <activity 
+                       android:name=".ui.activity.MoveActivity"
+                       android:label="@string/app_name"/>
         
     </application>
 
index 6e7b7f6..3953903 100644 (file)
--- a/SETUP.md
+++ b/SETUP.md
@@ -1,56 +1,92 @@
   
-  If you want to start help developing ownCloud please follow the [contribution guidlines][0] and observe these instructions:
+If you want to start help developing ownCloud please follow the [contribution guidelines][0] and observe these instructions.
+
+If you have any problems, start again with 1) and work your way down. If something still does not work as described here, please open a new issue describing exactly what you did, what happened, and what should have happened.
+  
+### 1) Fork and download android/develop repository:
+
+NOTE: Android SDK with platforms 8, 14 and 19 (and maybe others) need to be installed.
+      You must have the Android SDK 'tools/', and 'platforms-tools/' folders in your environment path variable.
+      "git" need to be installed and in your environment path variable.
+
+* Navigate to https://github.com/owncloud/android, click fork.
+* Clone your new repo: "git clone git@github.com:YOURGITHUBNAME/android.git"
+* Move to the project folder with "cd android"
+* Checkout remote develop branch: "git checkout -b develop remotes/origin/develop"
+* Pull changes from your develop branch: "git pull origin develop"
+* Make official ownCloud repo known as upstream: "git remote add upstream git@github.com:owncloud/android.git"
+* Make sure to get the latest changes from official android/develop branch: "git pull upstream develop"
+* Complete the setup of project properties and resolve pending dependencies running "setup_env.bat" or "./setup_env.sh" .
+
+At this point you can continue using different tools to build the project. Sections 2a), 2b), and 2c) describe some of the existing alternatives.
+
+### 2a) Building with Ant:
   
-  1. Fork and download android/develop repository:
-
-  -  NOTE: You must have git in your enviroment path
-  -  Navigate to https://github.com/owncloud/android, click fork.
-  -  Clone your new repo: "git clone git@github.com:YOURGITHUBNAME/android.git"
-  -  "cd android"
-  -  Checkout remote develop branch: "git checkout -b develop remotes/origin/develop"
-  -  Pull changes from your develop branch: "git pull origin develop"
-  -  Make sure to get the latest changes from official android/develop branch:
-  -  Make official owncloud repo known as upstream: "git remote add upstream git@github.com:owncloud/android.git"
-  -  Pull latest changes from upstream: "git pull upstream develop"
-
-  2. Building with console/maven:
-
-  -  OPTIONAL, CONTINUE WITH STEP 3 IF NOT REQUIRED!
-  -  NOTE: You must have mvn in your enviroment path
-  -  Download/install Android plugin for Maven, then build ownCloud with mvn:
-  -  "cd .."
-  -  "git clone https://github.com/mosabua/maven-android-sdk-deployer.git"
-  -  "cd maven-android-sdk-deployer"
-  -  "mvn -pl com.simpligility.android.sdk-deployer:android-17 -am install"
-  -  "cd ../android"
-  -  Now you can create APK using "mvn package"
-
-  3. Building with Eclipse:
-
-  -  NOTE: You must have android/tools, and 'platforms-tools' in your enviroment path
-  -  Prepare building with Eclipse:
-  -  "setup_env.bat" or "./setup_env.sh"
-  -  Open Eclipse and create new "Android Project from Existing Code". As root choose android/actionbarsherlock/library
-  -  Increase Android API level until project compiles. 14 should work. 
-  -  Clean project and compile.
-  -  Make sure android/actionbarsherlock/library/bin/library.jar was created!
-  -  Import OwnCloud Android project.
-  -  Increase Android API level to 17.
-  -  Clean project and compile.
-  -  After those actions you should be good to go. HAVE FUN!
-  -  NOTE: Even though API level is set to 17, APK also runs on older devices because in AndroidManifest.xml minSdkVersion is set to 8.
-
-  4. Create pull request:
+NOTE: You must have the Android SDK 'tools/', and 'platforms-tools/' folders in your environment path variable.
+
+* Run "ant clean" .
+* Run "ant debug" to generate a debuggable version of the ownCloud app.
+
+### 2b) Building with console/maven:
+
+NOTE: You must have mvn (version >= 3.1.1) in your environment path. Current Android 'platforms-tools' need to be installed.
+
+Download/install Android plugin for Maven, install owncloud-android-library, then build ownCloud with mvn:
+
+* cd ..
+* git clone https://github.com/mosabua/maven-android-sdk-deployer.git
+* cd maven-android-sdk-deployer
+* mvn -pl com.simpligility.android.sdk-deployer:android-19 -am install
+* cd ../android/owncloud-android-library
+* mvn install
+* cd ..
+
+Now you can create ownCloud APK using "mvn package"
+
+### 2c) Building with Eclipse:
+
+NOTE: You must have the Android SDK 'tools/', and 'platforms-tools/' folders in your environment path variable.
+
+* Complete the setup of project properties and resolve pending dependencies running "setup_env.bat" or "./setup_env.sh" .
+* Open Eclipse and create new "Android Project from Existing Code". Choose android/actionbarsherlock/library as root.
+* Clean project and compile.
+* If any error appear, check the project properties; in the 'Android' section, API Level should be greater or equal than 14.
+* If "error loading libz.so.1" appears, try "sudo apt-get install lib32z1"
+* Make sure android/actionbarsherlock/library/bin/library.jar was created.
+* Create a new "Android Project from Existing Code". Choose android/owncloud-android-library as root. (test and sample clients are not required.)
+* Clean project and compile.
+* If any error appear, check the project properties; in the 'Android' section, API Level should be 19 or greater.
+* Make sure 'android/owncloud-android-library/bin/owncloud android library.jar' was created.
+* Import ownCloud Android project.
+* Clean project and compile.
+* If any error appears, check the project properties of owncloud-android project; in the 'Android' section:
+  - API Level should be 19 or greater.
+  - Two library projects should appear referred in the bottom square: actionbarsherlock/library and owncloud-android-library. Add them if needed. 
+* After those actions you should be good to go. HAVE FUN!
+
+NOTE: Even though API level is set to 19, APK also runs on older devices because in AndroidManifest.xml minSdkVersion is set to 8.
+
+### 3) Create pull request:
   
-  -  NOTE: You must sign the [Contributor Agreement][1] before your changes can be accepted!
-  -  Commit your changes locally: "git commit -a"
-  -  Push your changes to your Github repo: "git push"
-  -  Browse to https://github.com/YOURGITHUBNAME/android/pulls and issue pull request
-  -  Click "Edit" and set "base:develop"
-  -  Again, click "Edit" and set "compare:develop"
-  -  Enter description and send pull request.
+NOTE: You must sign the [Contributor Agreement][1] before your changes can be accepted!
+
+* Commit your changes locally: "git commit -a"
+* Push your changes to your Github repo: "git push"
+* Browse to https://github.com/YOURGITHUBNAME/android/pulls and issue pull request
+* Click "Edit" and set "base:develop"
+* Again, click "Edit" and set "compare:develop"
+* Enter description and send pull request.
+
+### 4) Create another pull request:
+
+To make sure your new pull request does not contain commits which are already contained in previous PRs, create a new branch which is a clone of upstream/develop.
+
+* git fetch upstream
+* git checkout -b my_new_develop_branch upstream/develop
+* If you want to rename that branch later: "git checkout -b my_new_develop_branch_with_new_name"
+* Push branch to server: "git push -u origin name_of_local_develop_branch"
+* Use Github to issue PR
 
 
 [0]: https://github.com/owncloud/android/blob/master/CONTRIBUTING.md
 [1]: http://owncloud.org/about/contributor-agreement/
-
index d85eb89..6df2e9a 100644 (file)
@@ -60,4 +60,12 @@ The third party software included and used by this project is:
    A binary JAR file must be generated from this linked project
    and included in the ownCloud client APK.
    See http://http://actionbarsherlock.com/
+   
+ * TouchImageView, commit 6dbeac4f11936185ba374c73144ac431c23c9aab
+   Copyright (c) 2012 Michael Ortiz
+   Licensed under MIT License
+   JAR file libs/touch-image-view.jar has been generated by ownCloud Inc., including without 
+   modifications com.ortiz.touch.ExtendedViewPager and com.ortiz.touch.TouchImageView classes. 
+   See https://github.com/MikeOrtiz/TouchImageView
  
\ No newline at end of file
diff --git a/libs/disklrucache-2.0.2.jar b/libs/disklrucache-2.0.2.jar
new file mode 100644 (file)
index 0000000..ca7907d
Binary files /dev/null and b/libs/disklrucache-2.0.2.jar differ
diff --git a/libs/jackrabbit-webdav-2.2.5-jar-with-dependencies.jar b/libs/jackrabbit-webdav-2.2.5-jar-with-dependencies.jar
deleted file mode 100755 (executable)
index 2dd374f..0000000
Binary files a/libs/jackrabbit-webdav-2.2.5-jar-with-dependencies.jar and /dev/null differ
diff --git a/libs/touch-image-view.jar b/libs/touch-image-view.jar
new file mode 100644 (file)
index 0000000..539f615
Binary files /dev/null and b/libs/touch-image-view.jar differ
diff --git a/lint.xml b/lint.xml
deleted file mode 100644 (file)
index ee0eead..0000000
--- a/lint.xml
+++ /dev/null
@@ -1,3 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<lint>
-</lint>
\ No newline at end of file
index 1b12fb4..ada508c 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="0100010"
-    android:versionName="1.0.10" >
+    android:versionCode="0100019"
+    android:versionName="1.0.19" >
 
     <uses-sdk
         android:minSdkVersion="16"
diff --git a/oc_jb_workaround/res/drawable-xhdpi/main_app_icon.png b/oc_jb_workaround/res/drawable-xhdpi/main_app_icon.png
deleted file mode 100644 (file)
index e388c7b..0000000
Binary files a/oc_jb_workaround/res/drawable-xhdpi/main_app_icon.png and /dev/null differ
diff --git a/oc_jb_workaround/res/drawable-xhdpi/workaround_app_icon.png b/oc_jb_workaround/res/drawable-xhdpi/workaround_app_icon.png
deleted file mode 100644 (file)
index 7daeea4..0000000
Binary files a/oc_jb_workaround/res/drawable-xhdpi/workaround_app_icon.png and /dev/null differ
diff --git a/owncloud-android-library b/owncloud-android-library
new file mode 160000 (submodule)
index 0000000..5bd0d73
--- /dev/null
@@ -0,0 +1 @@
+Subproject commit 5bd0d7387712ce3f53869294761ac4d8537841cd
diff --git a/pom.xml b/pom.xml
index a55a77a..6a8cf6a 100644 (file)
--- a/pom.xml
+++ b/pom.xml
@@ -5,13 +5,17 @@
     <modelVersion>4.0.0</modelVersion>
     <groupId>com.owncloud.android</groupId>
     <artifactId>owncloud</artifactId>
-    <version>1.3.21-SNAPSHOT</version>
+    <version>${owncloud.version}</version>
     <packaging>apk</packaging>
     <name>Owncloud Android</name>
 
     <properties>
+        <owncloud.version>1.5.1-SNAPSHOT</owncloud.version>
         <java-version>1.6</java-version>
-        <google.android-version>4.2.2_r2</google.android-version>
+        <!-- Given by maven-android-sdk-deployer -->
+        <google.android-version>4.4.2_r3</google.android-version>
+        <!-- Usually the latest Android API -->
+        <google.android-api>19</google.android-api>
         <actionbarsherlock-version>4.2.0</actionbarsherlock-version>
     </properties>
 
         <developerConnection>scm:git:git@github.com:owncloud/android.git</developerConnection>
         <url>https://github.com/owncloud/android</url>
     </scm>
-
+    
     <dependencies>
-
+        <!-- Dirty trick, but it works. TouchImageView library is not available as Maven project. -->
+        <dependency>
+            <groupId>touch-image-view.jar</groupId>
+            <artifactId>touch-image-view.jar</artifactId>
+            <version>1.0</version>
+            <scope>system</scope>
+            <systemPath>${basedir}/libs/touch-image-view.jar</systemPath>
+        </dependency>
+          
+        <!-- This causes a (version?) conflict during packaging since sherlockactionbar also includes compatibility-v4 -->
+        <!--<dependency>
+            <groupId>android.support</groupId>
+            <artifactId>compatibility-v4</artifactId>
+            <version>19.1.0</version>
+        </dependency>-->
+        <!-- Instead we need to include the exact same version -->
+        <dependency>
+            <groupId>android-support-v4.jar</groupId>
+            <artifactId>android-support-v4.jar</artifactId>
+            <version>1.0</version>
+            <scope>system</scope>
+            <systemPath>${basedir}/third_party/android-support-library/android-support-v4.jar</systemPath>
+        </dependency>
+        
         <dependency>
             <groupId>android</groupId>
             <artifactId>android</artifactId>
             <type>apklib</type>
         </dependency>
 
+        <!-- MUST BE INSTALLED FIRST: cd owncloud-android-library; mvn install -->
         <dependency>
-            <groupId>org.apache.jackrabbit</groupId>
-            <artifactId>jackrabbit-webdav</artifactId>
-            <version>2.5.2</version>
-        </dependency>
+         <groupId>com.owncloud.android</groupId>
+         <artifactId>owncloud-android-library</artifactId>
+         <version>${owncloud.version}</version>
+      </dependency>
 
     </dependencies>
 
             <plugin>
                 <groupId>com.jayway.maven.plugins.android.generation2</groupId>
                 <artifactId>android-maven-plugin</artifactId>
-                <version>3.5.0</version>
+                <version>3.8.0</version>
                 <configuration>
                     <sdk>
-                        <!-- platform or api level (api level 4 = platform 1.6)-->
                         <path>${env.ANDROID_HOME}</path>
-                        <platform>17</platform>
+                        <platform>${google.android-api}</platform>
                     </sdk>
                 </configuration>
                 <extensions>true</extensions>
index c9e5840..3c67d77 100644 (file)
@@ -10,3 +10,5 @@
 # Project target.
 target=android-19
 android.library.reference.1=actionbarsherlock/library
+android.library.reference.2=owncloud-android-library
+android.library.reference.3=../android-library/android-library
diff --git a/res/drawable-hdpi-v11/notification_icon.png b/res/drawable-hdpi-v11/notification_icon.png
new file mode 100644 (file)
index 0000000..9e634a8
Binary files /dev/null and b/res/drawable-hdpi-v11/notification_icon.png differ
diff --git a/res/drawable-hdpi-v9/ic_action_create_dir.png b/res/drawable-hdpi-v9/ic_action_create_dir.png
deleted file mode 100644 (file)
index ece0eb4..0000000
Binary files a/res/drawable-hdpi-v9/ic_action_create_dir.png and /dev/null differ
diff --git a/res/drawable-hdpi-v9/ic_action_settings.png b/res/drawable-hdpi-v9/ic_action_settings.png
new file mode 100644 (file)
index 0000000..86b54f4
Binary files /dev/null and b/res/drawable-hdpi-v9/ic_action_settings.png differ
diff --git a/res/drawable-hdpi-v9/ic_action_upload.png b/res/drawable-hdpi-v9/ic_action_upload.png
deleted file mode 100644 (file)
index 2369348..0000000
Binary files a/res/drawable-hdpi-v9/ic_action_upload.png and /dev/null differ
diff --git a/res/drawable-hdpi/copy_link.png b/res/drawable-hdpi/copy_link.png
new file mode 100644 (file)
index 0000000..35df55f
Binary files /dev/null and b/res/drawable-hdpi/copy_link.png differ
index 08f9937..71d7390 100644 (file)
Binary files a/res/drawable-hdpi/file.png and b/res/drawable-hdpi/file.png differ
index 068ed57..e9c2323 100644 (file)
Binary files a/res/drawable-hdpi/file_doc.png and b/res/drawable-hdpi/file_doc.png differ
index dc40bae..bdb2e65 100644 (file)
Binary files a/res/drawable-hdpi/file_image.png and b/res/drawable-hdpi/file_image.png differ
index 2acfaf8..e178cce 100644 (file)
Binary files a/res/drawable-hdpi/file_movie.png and b/res/drawable-hdpi/file_movie.png differ
index a4af281..85c8953 100644 (file)
Binary files a/res/drawable-hdpi/file_pdf.png and b/res/drawable-hdpi/file_pdf.png differ
diff --git a/res/drawable-hdpi/file_ppt.png b/res/drawable-hdpi/file_ppt.png
new file mode 100644 (file)
index 0000000..4fb809e
Binary files /dev/null and b/res/drawable-hdpi/file_ppt.png differ
index 33045af..30f5367 100644 (file)
Binary files a/res/drawable-hdpi/file_sound.png and b/res/drawable-hdpi/file_sound.png differ
diff --git a/res/drawable-hdpi/file_xls.png b/res/drawable-hdpi/file_xls.png
new file mode 100644 (file)
index 0000000..f6a2cc8
Binary files /dev/null and b/res/drawable-hdpi/file_xls.png differ
index 398f601..bffacb4 100644 (file)
Binary files a/res/drawable-hdpi/file_zip.png and b/res/drawable-hdpi/file_zip.png differ
diff --git a/res/drawable-hdpi/folder_public.png b/res/drawable-hdpi/folder_public.png
new file mode 100644 (file)
index 0000000..337aba9
Binary files /dev/null and b/res/drawable-hdpi/folder_public.png differ
index 15068bc..ece0eb4 100644 (file)
Binary files a/res/drawable-hdpi/ic_action_create_dir.png and b/res/drawable-hdpi/ic_action_create_dir.png differ
diff --git a/res/drawable-hdpi/ic_action_settings.png b/res/drawable-hdpi/ic_action_settings.png
new file mode 100644 (file)
index 0000000..999d0f0
Binary files /dev/null and b/res/drawable-hdpi/ic_action_settings.png differ
index b372b7e..2369348 100644 (file)
Binary files a/res/drawable-hdpi/ic_action_upload.png and b/res/drawable-hdpi/ic_action_upload.png differ
diff --git a/res/drawable-hdpi/ic_favorite.png b/res/drawable-hdpi/ic_favorite.png
new file mode 100644 (file)
index 0000000..1cb4d85
Binary files /dev/null and b/res/drawable-hdpi/ic_favorite.png differ
index 0bdcac5..7d25b82 100644 (file)
Binary files a/res/drawable-hdpi/ic_menu_archive.png and b/res/drawable-hdpi/ic_menu_archive.png differ
diff --git a/res/drawable-hdpi/notification_icon.png b/res/drawable-hdpi/notification_icon.png
new file mode 100644 (file)
index 0000000..fd2bc5b
Binary files /dev/null and b/res/drawable-hdpi/notification_icon.png differ
diff --git a/res/drawable-hdpi/shared_with_me.png b/res/drawable-hdpi/shared_with_me.png
new file mode 100644 (file)
index 0000000..222172a
Binary files /dev/null and b/res/drawable-hdpi/shared_with_me.png differ
diff --git a/res/drawable-hdpi/shared_with_me_folder.png b/res/drawable-hdpi/shared_with_me_folder.png
new file mode 100644 (file)
index 0000000..271e7b2
Binary files /dev/null and b/res/drawable-hdpi/shared_with_me_folder.png differ
diff --git a/res/drawable-hdpi/sharedlink.png b/res/drawable-hdpi/sharedlink.png
new file mode 100644 (file)
index 0000000..a3c42a9
Binary files /dev/null and b/res/drawable-hdpi/sharedlink.png differ
diff --git a/res/drawable-hdpi/winter_holidays_icon.png b/res/drawable-hdpi/winter_holidays_icon.png
new file mode 100644 (file)
index 0000000..c1764b6
Binary files /dev/null and b/res/drawable-hdpi/winter_holidays_icon.png differ
diff --git a/res/drawable-ldpi-v9/ic_action_create_dir.png b/res/drawable-ldpi-v9/ic_action_create_dir.png
deleted file mode 100644 (file)
index 8ed2dae..0000000
Binary files a/res/drawable-ldpi-v9/ic_action_create_dir.png and /dev/null differ
diff --git a/res/drawable-ldpi-v9/ic_action_settings.png b/res/drawable-ldpi-v9/ic_action_settings.png
new file mode 100644 (file)
index 0000000..e2c2d51
Binary files /dev/null and b/res/drawable-ldpi-v9/ic_action_settings.png differ
diff --git a/res/drawable-ldpi-v9/ic_action_upload.png b/res/drawable-ldpi-v9/ic_action_upload.png
deleted file mode 100644 (file)
index 2d4ba56..0000000
Binary files a/res/drawable-ldpi-v9/ic_action_upload.png and /dev/null differ
diff --git a/res/drawable-ldpi/copy_link.png b/res/drawable-ldpi/copy_link.png
new file mode 100644 (file)
index 0000000..b3caf52
Binary files /dev/null and b/res/drawable-ldpi/copy_link.png differ
index bbe560b..b669fdf 100644 (file)
Binary files a/res/drawable-ldpi/file.png and b/res/drawable-ldpi/file.png differ
index a407043..0ea07e3 100644 (file)
Binary files a/res/drawable-ldpi/file_doc.png and b/res/drawable-ldpi/file_doc.png differ
index b3af57c..1bf2015 100644 (file)
Binary files a/res/drawable-ldpi/file_image.png and b/res/drawable-ldpi/file_image.png differ
index 53bf0e7..e50c168 100644 (file)
Binary files a/res/drawable-ldpi/file_movie.png and b/res/drawable-ldpi/file_movie.png differ
index ded8249..a05afdd 100644 (file)
Binary files a/res/drawable-ldpi/file_pdf.png and b/res/drawable-ldpi/file_pdf.png differ
diff --git a/res/drawable-ldpi/file_ppt.png b/res/drawable-ldpi/file_ppt.png
new file mode 100644 (file)
index 0000000..11a9cc9
Binary files /dev/null and b/res/drawable-ldpi/file_ppt.png differ
index 6fc963f..26e5a5f 100644 (file)
Binary files a/res/drawable-ldpi/file_sound.png and b/res/drawable-ldpi/file_sound.png differ
diff --git a/res/drawable-ldpi/file_xls.png b/res/drawable-ldpi/file_xls.png
new file mode 100644 (file)
index 0000000..9855367
Binary files /dev/null and b/res/drawable-ldpi/file_xls.png differ
index 04340f4..88d0040 100644 (file)
Binary files a/res/drawable-ldpi/file_zip.png and b/res/drawable-ldpi/file_zip.png differ
index 78356fe..8ed2dae 100644 (file)
Binary files a/res/drawable-ldpi/ic_action_create_dir.png and b/res/drawable-ldpi/ic_action_create_dir.png differ
diff --git a/res/drawable-ldpi/ic_action_settings.png b/res/drawable-ldpi/ic_action_settings.png
new file mode 100644 (file)
index 0000000..c290e59
Binary files /dev/null and b/res/drawable-ldpi/ic_action_settings.png differ
index 9e3f745..2d4ba56 100644 (file)
Binary files a/res/drawable-ldpi/ic_action_upload.png and b/res/drawable-ldpi/ic_action_upload.png differ
index 7818537..e4d0ee5 100644 (file)
Binary files a/res/drawable-ldpi/ic_menu_archive.png and b/res/drawable-ldpi/ic_menu_archive.png differ
diff --git a/res/drawable-ldpi/winter_holidays_icon.png b/res/drawable-ldpi/winter_holidays_icon.png
new file mode 100644 (file)
index 0000000..9261d32
Binary files /dev/null and b/res/drawable-ldpi/winter_holidays_icon.png differ
diff --git a/res/drawable-mdpi-v11/notification_icon.png b/res/drawable-mdpi-v11/notification_icon.png
new file mode 100644 (file)
index 0000000..e33e653
Binary files /dev/null and b/res/drawable-mdpi-v11/notification_icon.png differ
diff --git a/res/drawable-mdpi-v9/ic_action_create_dir.png b/res/drawable-mdpi-v9/ic_action_create_dir.png
deleted file mode 100644 (file)
index 9215a62..0000000
Binary files a/res/drawable-mdpi-v9/ic_action_create_dir.png and /dev/null differ
diff --git a/res/drawable-mdpi-v9/ic_action_settings.png b/res/drawable-mdpi-v9/ic_action_settings.png
new file mode 100644 (file)
index 0000000..47ef3f4
Binary files /dev/null and b/res/drawable-mdpi-v9/ic_action_settings.png differ
diff --git a/res/drawable-mdpi-v9/ic_action_upload.png b/res/drawable-mdpi-v9/ic_action_upload.png
deleted file mode 100644 (file)
index 0faf43b..0000000
Binary files a/res/drawable-mdpi-v9/ic_action_upload.png and /dev/null differ
diff --git a/res/drawable-mdpi/copy_link.png b/res/drawable-mdpi/copy_link.png
new file mode 100644 (file)
index 0000000..4e2af28
Binary files /dev/null and b/res/drawable-mdpi/copy_link.png differ
index 0a1ca52..5fa8505 100644 (file)
Binary files a/res/drawable-mdpi/file.png and b/res/drawable-mdpi/file.png differ
index 95651f8..2e7628a 100644 (file)
Binary files a/res/drawable-mdpi/file_doc.png and b/res/drawable-mdpi/file_doc.png differ
index 2b2fff4..eedd41f 100644 (file)
Binary files a/res/drawable-mdpi/file_image.png and b/res/drawable-mdpi/file_image.png differ
index 4c0254c..b37e98d 100644 (file)
Binary files a/res/drawable-mdpi/file_movie.png and b/res/drawable-mdpi/file_movie.png differ
index 306ad99..07aa238 100644 (file)
Binary files a/res/drawable-mdpi/file_pdf.png and b/res/drawable-mdpi/file_pdf.png differ
diff --git a/res/drawable-mdpi/file_ppt.png b/res/drawable-mdpi/file_ppt.png
new file mode 100644 (file)
index 0000000..db7d58d
Binary files /dev/null and b/res/drawable-mdpi/file_ppt.png differ
index 8789e5c..6b8b589 100644 (file)
Binary files a/res/drawable-mdpi/file_sound.png and b/res/drawable-mdpi/file_sound.png differ
diff --git a/res/drawable-mdpi/file_xls.png b/res/drawable-mdpi/file_xls.png
new file mode 100644 (file)
index 0000000..b0264d7
Binary files /dev/null and b/res/drawable-mdpi/file_xls.png differ
index 92647b8..61974b8 100644 (file)
Binary files a/res/drawable-mdpi/file_zip.png and b/res/drawable-mdpi/file_zip.png differ
diff --git a/res/drawable-mdpi/folder_public.png b/res/drawable-mdpi/folder_public.png
new file mode 100644 (file)
index 0000000..374cf91
Binary files /dev/null and b/res/drawable-mdpi/folder_public.png differ
index 636cf0e..9215a62 100644 (file)
Binary files a/res/drawable-mdpi/ic_action_create_dir.png and b/res/drawable-mdpi/ic_action_create_dir.png differ
diff --git a/res/drawable-mdpi/ic_action_settings.png b/res/drawable-mdpi/ic_action_settings.png
new file mode 100644 (file)
index 0000000..0eb78f7
Binary files /dev/null and b/res/drawable-mdpi/ic_action_settings.png differ
index d30ee8a..0faf43b 100644 (file)
Binary files a/res/drawable-mdpi/ic_action_upload.png and b/res/drawable-mdpi/ic_action_upload.png differ
diff --git a/res/drawable-mdpi/ic_favorite.png b/res/drawable-mdpi/ic_favorite.png
new file mode 100644 (file)
index 0000000..dead474
Binary files /dev/null and b/res/drawable-mdpi/ic_favorite.png differ
index 2c50285..7f29fbc 100644 (file)
Binary files a/res/drawable-mdpi/ic_menu_archive.png and b/res/drawable-mdpi/ic_menu_archive.png differ
diff --git a/res/drawable-mdpi/notification_icon.png b/res/drawable-mdpi/notification_icon.png
new file mode 100644 (file)
index 0000000..2e8beda
Binary files /dev/null and b/res/drawable-mdpi/notification_icon.png differ
diff --git a/res/drawable-mdpi/shared_with_me.png b/res/drawable-mdpi/shared_with_me.png
new file mode 100644 (file)
index 0000000..8300eac
Binary files /dev/null and b/res/drawable-mdpi/shared_with_me.png differ
diff --git a/res/drawable-mdpi/shared_with_me_folder.png b/res/drawable-mdpi/shared_with_me_folder.png
new file mode 100644 (file)
index 0000000..3b8aeee
Binary files /dev/null and b/res/drawable-mdpi/shared_with_me_folder.png differ
diff --git a/res/drawable-mdpi/sharedlink.png b/res/drawable-mdpi/sharedlink.png
new file mode 100644 (file)
index 0000000..772838a
Binary files /dev/null and b/res/drawable-mdpi/sharedlink.png differ
diff --git a/res/drawable-mdpi/winter_holidays_icon.png b/res/drawable-mdpi/winter_holidays_icon.png
new file mode 100644 (file)
index 0000000..b0226dc
Binary files /dev/null and b/res/drawable-mdpi/winter_holidays_icon.png differ
diff --git a/res/drawable-xhdpi-v11/notification_icon.png b/res/drawable-xhdpi-v11/notification_icon.png
new file mode 100644 (file)
index 0000000..1ad4971
Binary files /dev/null and b/res/drawable-xhdpi-v11/notification_icon.png differ
diff --git a/res/drawable-xhdpi/copy_link.png b/res/drawable-xhdpi/copy_link.png
new file mode 100644 (file)
index 0000000..c69eb05
Binary files /dev/null and b/res/drawable-xhdpi/copy_link.png differ
diff --git a/res/drawable-xhdpi/ic_favorite.png b/res/drawable-xhdpi/ic_favorite.png
new file mode 100644 (file)
index 0000000..c187f0c
Binary files /dev/null and b/res/drawable-xhdpi/ic_favorite.png differ
diff --git a/res/drawable-xhdpi/icon.png b/res/drawable-xhdpi/icon.png
new file mode 100644 (file)
index 0000000..041efc6
Binary files /dev/null and b/res/drawable-xhdpi/icon.png differ
diff --git a/res/drawable-xhdpi/notification_icon.png b/res/drawable-xhdpi/notification_icon.png
new file mode 100644 (file)
index 0000000..b3855d6
Binary files /dev/null and b/res/drawable-xhdpi/notification_icon.png differ
diff --git a/res/drawable-xhdpi/shared_with_me.png b/res/drawable-xhdpi/shared_with_me.png
new file mode 100644 (file)
index 0000000..3879663
Binary files /dev/null and b/res/drawable-xhdpi/shared_with_me.png differ
diff --git a/res/drawable-xhdpi/sharedlink.png b/res/drawable-xhdpi/sharedlink.png
new file mode 100644 (file)
index 0000000..9ef8f3e
Binary files /dev/null and b/res/drawable-xhdpi/sharedlink.png differ
index 179a3f7..7c49554 100644 (file)
Binary files a/res/drawable/downloading_file_indicator.png and b/res/drawable/downloading_file_indicator.png differ
diff --git a/res/drawable/ic_favorite.png b/res/drawable/ic_favorite.png
deleted file mode 100644 (file)
index 4843dc1..0000000
Binary files a/res/drawable/ic_favorite.png and /dev/null differ
index 08a7b80..85d5271 100644 (file)
Binary files a/res/drawable/local_file_indicator.png and b/res/drawable/local_file_indicator.png differ
index b0b5634..b71add0 100644 (file)
Binary files a/res/drawable/uploading_file_indicator.png and b/res/drawable/uploading_file_indicator.png differ
index 1025bcf..88b1ab3 100644 (file)
@@ -27,7 +27,7 @@
     <LinearLayout\r
         android:layout_width="match_parent"\r
         android:layout_height="wrap_content"\r
-        android:layout_above="@id/buttonOK"\r
+        android:layout_above="@+id/bottom_block"\r
         android:layout_alignParentTop="true"\r
         android:orientation="horizontal" >\r
         \r
@@ -67,7 +67,7 @@
                                    android:text="@string/auth_check_server"\r
                                    android:visibility="gone" />\r
                                <TextView\r
-                                   android:id="@+id/auth_message"\r
+                                   android:id="@+id/instructions_message"\r
                                    android:layout_width="wrap_content"\r
                                    android:layout_height="wrap_content"\r
                                    android:layout_gravity="fill_horizontal"\r
                                                           \r
        </LinearLayout>\r
        \r
-       <Button\r
-           android:id="@id/buttonOK"\r
-           android:layout_width="match_parent"\r
-           android:layout_height="wrap_content"\r
-           android:layout_above="@+id/welcome_link"\r
-           android:layout_centerHorizontal="true"\r
-           android:enabled="false"\r
-           android:onClick="onOkClick"\r
-           android:text="@string/setup_btn_connect" />\r
-\r
-       <Button\r
-           android:id="@id/welcome_link"\r
-           android:layout_width="wrap_content"\r
-           android:layout_height="wrap_content"\r
-           android:layout_alignParentBottom="true"\r
-           android:layout_centerHorizontal="true"\r
-           android:background="@android:color/transparent"\r
-           android:onClick="onRegisterClick"\r
-           android:paddingBottom="5dp"\r
-           android:paddingTop="5dp"\r
-           android:text="@string/auth_register"\r
-           android:textColor="#0000FF"/>\r
-       \r
+    <LinearLayout\r
+        android:id="@id/bottom_block"\r
+        android:layout_width="match_parent"\r
+        android:layout_height="wrap_content"\r
+               android:layout_alignParentBottom="true"\r
+        android:orientation="vertical" >\r
+        \r
+               <Button\r
+                   android:id="@+id/buttonOK"\r
+                   android:layout_width="match_parent"\r
+                   android:layout_height="wrap_content"\r
+                   android:layout_gravity="center_horizontal"\r
+                   android:enabled="false"\r
+                   android:onClick="onOkClick"\r
+                   android:text="@string/setup_btn_connect" />\r
+               \r
+               <Button\r
+                   android:id="@+id/welcome_link"\r
+                   android:layout_width="wrap_content"\r
+                   android:layout_height="wrap_content"\r
+                   android:layout_gravity="center_horizontal"\r
+                   android:background="@android:color/transparent"\r
+                   android:onClick="onRegisterClick"\r
+                   android:paddingBottom="5dp"\r
+                   android:paddingTop="5dp"\r
+                   android:text="@string/auth_register"\r
+                   android:textColor="#0000FF"/>\r
+       </LinearLayout>\r
+               \r
 </RelativeLayout>\r
diff --git a/res/layout-v11/activity_row.xml b/res/layout-v11/activity_row.xml
new file mode 100644 (file)
index 0000000..95c7dfc
--- /dev/null
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ownCloud Android client application
+
+  Copyright (C) 2012-2014 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/list_item"
+                               android:layout_width="match_parent"
+                               android:layout_height="48dp"
+                               android:paddingStart="16dip"
+                               android:paddingEnd="16dip"
+                               android:paddingRight="16dip"
+                               android:paddingLeft="16dip"
+                               android:minWidth="196dip"
+                               android:background="?android:attr/activatedBackgroundIndicator"
+                       android:orientation="vertical" >
+
+       <LinearLayout
+               android:layout_width="wrap_content"
+               android:layout_height="match_parent"
+               android:duplicateParentState="true" >
+
+               <ImageView
+                       android:id="@+id/icon"
+                       android:layout_width="40dip"
+                       android:layout_height="40dip"
+                       android:layout_gravity="center_vertical"
+                       android:layout_marginEnd="8dip"
+                       android:layout_marginRight="8dip"
+                       android:duplicateParentState="true" />
+
+        <TextView
+            android:id="@+id/title"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_vertical"
+            android:textAppearance="?android:attr/textAppearanceLargePopupMenu"
+            android:duplicateParentState="true"
+            android:singleLine="true"
+            android:ellipsize="marquee"
+            android:fadingEdge="horizontal" />
+
+    </LinearLayout>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/res/layout-v11/notification_with_progress_bar.xml b/res/layout-v11/notification_with_progress_bar.xml
new file mode 100644 (file)
index 0000000..f4d4fab
--- /dev/null
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 
+    ownCloud Android client application
+    Copyright (C) 2014 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"
+    >
+    <ImageView android:id="@+id/icon"
+        android:layout_width="@android:dimen/notification_large_icon_width"
+        android:layout_height="@android:dimen/notification_large_icon_height"
+        android:scaleType="center"
+        />
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center"
+        android:minHeight="64dp"
+        android:orientation="vertical"
+        android:paddingRight="12dp"
+        android:paddingLeft="12dp"
+        >
+               <TextView android:id="@+id/title"
+                       android:layout_width="match_parent"
+                       android:layout_height="wrap_content"
+                       android:singleLine="true"
+                       android:ellipsize="marquee"
+            android:fadingEdge="horizontal"
+            style="@style/Theme.ownCloud.NotificationText.Title"
+               />
+        <TextView android:id="@+id/text"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="-2dp"
+            android:layout_marginBottom="-2dp"
+            android:singleLine="true"
+            android:fadingEdge="horizontal"
+            android:ellipsize="marquee"
+            style="@style/Theme.ownCloud.NotificationText.Content"
+            />
+        <FrameLayout android:id="@+id/progressHolder"
+            android:layout_width="match_parent"
+            android:layout_height="12dp"
+            >
+            <!--  the FrameLayout is needed to change visibility of the
+               progress bar in Android 2.2, even though 
+               https://code.google.com/p/android/issues/detail?id=11040 -->
+               <ProgressBar
+                   android:id="@+id/progress"
+                   android:layout_width="match_parent"
+                   android:layout_height="match_parent"
+                   style="?android:attr/progressBarStyleHorizontal"
+                   />
+        </FrameLayout>
+    </LinearLayout>
+</LinearLayout>
\ No newline at end of file
index d147780..e3321f9 100644 (file)
@@ -54,7 +54,7 @@
             android:visibility="gone" />\r
         \r
         <TextView\r
-            android:id="@+id/auth_message"\r
+            android:id="@+id/instructions_message"\r
             android:layout_width="wrap_content"\r
             android:layout_height="wrap_content"\r
             android:layout_gravity="fill_horizontal"\r
diff --git a/res/layout/activity_row.xml b/res/layout/activity_row.xml
new file mode 100644 (file)
index 0000000..b917600
--- /dev/null
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ownCloud Android client application
+
+  Copyright (C) 2012-2014 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/list_item"
+                               android:layout_width="match_parent"
+                               android:layout_height="48dp"
+                               android:paddingRight="16dip"
+                               android:paddingLeft="16dip"
+                               android:minWidth="196dip"
+                       android:orientation="vertical" >
+
+       <LinearLayout
+               android:layout_width="wrap_content"
+               android:layout_height="match_parent"
+               android:duplicateParentState="true" >
+
+               <ImageView
+                       android:id="@+id/icon"
+                       android:layout_width="40dip"
+                       android:layout_height="40dip"
+                       android:layout_gravity="center_vertical"
+                       android:layout_marginRight="8dip"
+                       android:duplicateParentState="true" />
+
+        <TextView
+            android:id="@+id/title"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_vertical"
+            android:textAppearance="?android:attr/textAppearanceLarge"
+            android:duplicateParentState="true"
+            android:singleLine="true"
+            android:ellipsize="marquee"
+            android:fadingEdge="horizontal" />
+
+    </LinearLayout>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/res/layout/failed_upload_files.xml b/res/layout/failed_upload_files.xml
deleted file mode 100644 (file)
index b4deeed..0000000
+++ /dev/null
@@ -1,104 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>\r
-<!-- \r
-  ownCloud Android client application\r
-\r
-  Copyright (C) 2012  Bartek Przybylski\r
-  Copyright (C) 2012-2013 ownCloud Inc.\r
-  \r
-  This program is free software: you can redistribute it and/or modify\r
-  it under the terms of the GNU General Public License version 2,\r
-  as published by the Free Software Foundation.\r
-\r
-  This program is distributed in the hope that it will be useful,\r
-  but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
-  GNU General Public License for more details.\r
-\r
-  You should have received a copy of the GNU General Public License\r
-  along with this program.  If not, see <http://www.gnu.org/licenses/>.\r
- -->\r
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"\r
-    android:layout_width="fill_parent"\r
-    android:layout_height="fill_parent"\r
-    android:background="@color/background_color"\r
-    android:orientation="vertical"\r
-    android:id="@+id/failed_files_list_view">\r
-\r
-    <LinearLayout\r
-        android:layout_width="match_parent"\r
-        android:layout_height="wrap_content"\r
-        android:layout_gravity="right"\r
-        android:orientation="horizontal" >\r
-\r
-    </LinearLayout>\r
-\r
-    <LinearLayout\r
-        android:layout_width="match_parent"\r
-        android:layout_height="wrap_content"\r
-        android:orientation="vertical" >\r
-\r
-        <LinearLayout\r
-            android:layout_width="match_parent"\r
-            android:layout_height="wrap_content" >\r
-\r
-            <TextView\r
-                android:id="@+id/failed_upload_headline_textview"\r
-                android:layout_width="wrap_content"\r
-                android:layout_height="wrap_content"\r
-                android:layout_weight="0.93"\r
-                android:hint="@string/failed_upload_headline_hint"\r
-                android:text="@string/failed_upload_headline_text" />\r
-\r
-        </LinearLayout>\r
-\r
-        <LinearLayout\r
-            android:layout_width="match_parent"\r
-            android:layout_height="wrap_content"\r
-            android:layout_gravity="bottom|right" >\r
-\r
-            <CheckBox\r
-                android:id="@+id/failed_upload_headline_cb"\r
-                android:layout_width="wrap_content"\r
-                android:layout_height="wrap_content"\r
-                android:text="@string/failed_upload_all_cb"\r
-                android:textSize="8sp" />\r
-\r
-            <Button\r
-                android:id="@+id/failed_upload_retry_all_btn"\r
-                android:layout_width="wrap_content"\r
-                android:layout_height="wrap_content"\r
-                android:minHeight="30dp"\r
-                android:minWidth="90dp"\r
-                android:text="@string/failed_upload_headline_retryall_btn"\r
-                android:textSize="8sp" />\r
-\r
-            <Button\r
-                android:id="@+id/failed_upload_delete_all_btn"\r
-                android:layout_width="wrap_content"\r
-                android:layout_height="wrap_content"\r
-                android:minHeight="30dp"\r
-                android:minWidth="90dp"\r
-                android:text="@string/failed_upload_headline_delete_all_btn"\r
-                android:textSize="8sp" />\r
-\r
-        </LinearLayout>\r
-\r
-    </LinearLayout>\r
\r
-      <ScrollView\r
-          android:id="@+id/failedUploadScrollView"\r
-          android:layout_width="match_parent"\r
-          android:layout_height="match_parent"\r
-          android:overScrollMode="ifContentScrolls" >\r
-\r
-         <LinearLayout\r
-             android:id="@+id/failed_upload_scrollviewlayout"\r
-             android:layout_width="match_parent"\r
-             android:layout_height="wrap_content"\r
-             android:orientation="vertical">\r
-\r
-           \r
-         </LinearLayout>\r
-     </ScrollView>\r
-\r
-</LinearLayout>\r
diff --git a/res/layout/failed_upload_message_view.xml b/res/layout/failed_upload_message_view.xml
deleted file mode 100644 (file)
index cf20544..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"\r
-    android:id="@+id/failed_upload_message_view"\r
-    android:layout_width="fill_parent"\r
-    android:layout_height="fill_parent"\r
-    android:background="@color/background_color"\r
-    android:orientation="vertical" >\r
-\r
-   <TextView android:id="@+id/faild_upload_message" \r
-       android:layout_width="match_parent"\r
-       android:layout_height="wrap_content"\r
-       android:minWidth="100dp"/>\r
-   \r
-   <Button\r
-    android:id="@+id/failed_uploadactivity_close_button"\r
-    android:layout_width="fill_parent"\r
-    android:layout_height="wrap_content"\r
-    android:text="Dismiss" />\r
-\r
-</LinearLayout>
\ No newline at end of file
index f881847..8f571dc 100644 (file)
@@ -16,6 +16,7 @@
   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/fileDownloadLL"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical" 
diff --git a/res/layout/files_move.xml b/res/layout/files_move.xml
new file mode 100644 (file)
index 0000000..491bcd8
--- /dev/null
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="@color/background_color"
+    android:orientation="vertical" >
+
+       <FrameLayout 
+               android:layout_width="match_parent"
+               android:layout_height="0dip"
+        android:layout_weight="1"
+               android:id="@+id/fragment_container" />
+       
+       <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:gravity="center"
+        android:orientation="horizontal" >
+
+        <Button
+            android:id="@+id/move_files_btn_cancel"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:text="@string/common_cancel" />
+
+               <Button
+                   android:id="@+id/move_files_btn_choose"
+                   android:layout_width="wrap_content"
+                   android:layout_height="wrap_content"
+                   android:layout_weight="1"
+                   android:text="@string/move_choose_button_text" />
+
+       </LinearLayout>
+
+ </LinearLayout>
\ No newline at end of file
index 00e6b41..4236d07 100644 (file)
   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"
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="0dp"
        android:layout_height="match_parent"
-       android:layout_weight="1"
-       android:orientation="vertical" >
+       android:layout_weight="1" >
 
-       <com.owncloud.android.ui.ExtendedListView
-        android:id="@+id/list_root"
+    <android.support.v4.widget.SwipeRefreshLayout
+        android:id="@+id/swipe_refresh_files"
         android:layout_width="match_parent"
-        android:layout_height="0dip"
-        android:layout_weight="1" 
-       />
-    
-    <TextView
-       android:id="@+id/empty_list_view"
+        android:layout_height="match_parent" >
+
+        <com.owncloud.android.ui.ExtendedListView
+            android:id="@+id/list_root"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent" />
+        
+    </android.support.v4.widget.SwipeRefreshLayout>
+
+    <android.support.v4.widget.SwipeRefreshLayout
+        android:id="@+id/swipe_refresh_files_emptyView"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
-        android:gravity="center_vertical|center_horizontal"
-        android:text="@string/file_list_empty"
-        android:visibility="gone"
-       />
+        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:gravity="center_vertical|center_horizontal"
+                               android:text="@string/empty"
+                                       android:layout_gravity="center"
+                               android:visibility="visible" />
 
-</LinearLayout>    
+        </ScrollView>
+    </android.support.v4.widget.SwipeRefreshLayout>
+</FrameLayout>
index ea73832..a4113de 100644 (file)
     android:layout_height="56dp">\r
 \r
     <FrameLayout\r
-        android:layout_width="wrap_content"\r
+        android:layout_width="56dp"\r
         android:layout_height="56dp"\r
         android:focusable="false"\r
         android:focusableInTouchMode="false">\r
-        \r
+\r
         <ImageView\r
             android:id="@+id/imageView2"\r
-            android:layout_width="wrap_content"\r
-            android:layout_height="wrap_content"\r
-            android:src="@drawable/local_file_indicator"/>\r
+            android:layout_width="32dp"\r
+            android:layout_height="32dp"\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="20dp"\r
-            android:layout_height="20dp"\r
-            android:layout_gravity="center_vertical|center"\r
-            android:layout_margin="4dp"\r
+            android:layout_width="32dp"\r
+            android:layout_height="32dp"\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"\r
-            android:layout_weight=".1"\r
-            android:maxHeight="15dip"\r
+            android:layout_gravity="bottom|right"\r
+            android:layout_marginBottom="10dp"\r
+            android:layout_marginRight="2dp"\r
             android:src="@drawable/ic_favorite" />\r
-        \r
     </FrameLayout>\r
-\r\r\r\r
+\r
     <LinearLayout\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\r
+\r
         <TextView\r
             android:id="@+id/Filename"\r
             android:layout_width="wrap_content"\r
@@ -88,6 +89,7 @@
                 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: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\r\r\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
+\r
+    </LinearLayout>\r
+\r
     <ImageView\r
         android:id="@+id/custom_checkbox"\r
         android:layout_width="wrap_content"\r
index 22e744b..6f129eb 100644 (file)
@@ -1,35 +1,43 @@
 <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout 
-        xmlns:android="http://schemas.android.com/apk/res/android"
-         android:orientation="vertical"
-         android:layout_width="match_parent"
-         android:layout_height="match_parent"
-         android:paddingLeft="8dp"
-         android:paddingRight="8dp">
-      
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical"
+    android:padding="10dp"
+    android:paddingLeft="8dp"
+    android:paddingRight="8dp"
+    android:weightSum="1" >
 
-     <ListView         android:id="@android:id/list"
-                       android:layout_width="match_parent"
-                       android:layout_height="wrap_content"
-               />
+    <ScrollView
+        android:id="@+id/scrollView1"
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_marginBottom="15dp"
+        android:layout_weight="1" >
 
-     <TextView         android:id="@android:id/empty"
-                       android:layout_width="match_parent"
-                       android:layout_height="wrap_content"
-                       android:background="#FF0000"
-                       android:text="No data"/>
-     <LinearLayout 
-         android:orientation="vertical"
-         android:layout_width="match_parent"
-         android:layout_height="wrap_content"
-         android:gravity="bottom">
-        
-     <Button
-               android:id="@+id/deleteLogHistoryButton"
-                       android:layout_width="match_parent"
-                       android:layout_height="wrap_content"
-                       android:text="@string/prefs_log_delete_history_button"/>
-     
-     </LinearLayout>
-     
- </LinearLayout>
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="vertical" >
+
+            <TextView
+                android:id="@+id/logTV"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:text="@string/empty" />
+        </LinearLayout>
+    </ScrollView>
+
+    <Button
+        android:id="@+id/deleteLogHistoryButton"
+        android:layout_width="match_parent"
+        android:layout_height="50dp"
+        android:text="@string/prefs_log_delete_history_button" />
+
+    <Button
+        android:id="@+id/sendLogHistoryButton"
+        android:layout_width="match_parent"
+       android:layout_height="50dp"
+        android:text="@string/log_send_history_button" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/res/layout/notification_with_progress_bar.xml b/res/layout/notification_with_progress_bar.xml
new file mode 100644 (file)
index 0000000..1df31dc
--- /dev/null
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 
+    ownCloud Android client application
+    Copyright (C) 2014 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"
+        android:orientation="vertical"
+        android:paddingTop="5dp"
+        android:paddingLeft="5dp"
+        >
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal"
+        android:paddingTop="3dp"
+        >
+        <ImageView android:id="@+id/icon"
+            android:layout_width="25dp"
+            android:layout_height="25dp"
+            android:scaleType="centerInside"
+            />
+        <TextView android:id="@+id/title"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:singleLine="true"
+            android:ellipsize="marquee"
+            android:fadingEdge="horizontal"
+            android:paddingLeft="4dp"
+               style="@style/Theme.ownCloud.NotificationText.Title"
+            />
+    </LinearLayout>
+       <TextView android:id="@+id/text"
+           android:layout_width="match_parent"
+           android:layout_height="wrap_content"
+           android:singleLine="true"
+           android:ellipsize="marquee"
+           android:fadingEdge="horizontal"
+        style="@style/Theme.ownCloud.NotificationText.Content"
+           />
+    <FrameLayout android:id="@+id/progressHolder"
+        android:layout_width="match_parent"
+        android:layout_height="10dp"
+        android:paddingTop="2dp"
+        android:paddingBottom="2dp"
+        >
+        <!--  the FrameLayout is needed to change visibility of the
+               progress bar in Android 2.2, even though 
+               https://code.google.com/p/android/issues/detail?id=11040 -->
+               <ProgressBar
+               android:id="@+id/progress"
+               android:layout_width="match_parent"
+               android:layout_height="match_parent"
+               style="?android:attr/progressBarStyleHorizontal"
+       />
+    </FrameLayout>
+</LinearLayout>
index 9f8b119..d712b7f 100644 (file)
@@ -21,7 +21,7 @@
     android:layout_height="match_parent"
     android:orientation="vertical" >
 
-    <android.support.v4.view.ViewPager 
+    <com.ortiz.touch.ExtendedViewPager
         android:id="@+id/fragmentPager"
                android:layout_width="match_parent"
                android:layout_height="match_parent" 
index 253c829..9467d34 100644 (file)
     android:background="@color/background_color" 
     android:gravity="center_horizontal"
 -->
-
 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:tools="http://schemas.android.com/tools"
     android:id="@+id/top"
     android:layout_width="fill_parent"
     android:layout_height="fill_parent"
-    android:background="@color/background_color"
+    android:background="#000000"
     tools:context=".ui.fragment.PreviewImageFragment" >
 
     <ProgressBar 
         android:layout_centerInParent="true"
         />
     
-    <ImageView
+    <com.owncloud.android.utils.TouchImageViewCustom
         android:id="@+id/image"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
         android:layout_margin="0dp"
         android:layout_centerInParent="true"
         android:contentDescription="@string/preview_image_description"
diff --git a/res/layout/progressbar_layout.xml b/res/layout/progressbar_layout.xml
deleted file mode 100644 (file)
index e5a5afe..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ownCloud Android client application
-
-  Copyright (C) 2012  Bartek Przybylski
-  Copyright (C) 2012-2013 ownCloud Inc.
-
-  This program is free software: you can redistribute it and/or modify
-  it under the terms of the GNU General Public License version 2,
-  as published by the Free Software Foundation.
-
-  This program is distributed in the hope that it will be useful,
-  but WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-  GNU General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with this program.  If not, see <http://www.gnu.org/licenses/>.
--->
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-  android:layout_width="fill_parent" android:layout_height="fill_parent"
-  android:padding="5dp">
-  <ImageView android:id="@+id/status_icon"
-    android:layout_width="wrap_content" android:layout_height="fill_parent"
-    android:layout_alignParentLeft="true" />
-
-  <RelativeLayout android:layout_width="fill_parent"
-    android:layout_height="fill_parent" android:layout_toRightOf="@id/status_icon">
-
-    <TextView android:id="@+id/status_text" android:layout_width="fill_parent"
-      android:layout_height="wrap_content" android:layout_alignParentTop="true" />
-    <ProgressBar android:id="@+id/status_progress"
-      android:layout_width="fill_parent" android:layout_height="wrap_content"
-      android:layout_below="@id/status_text"
-      android:progressDrawable="@android:drawable/progress_horizontal"
-      android:indeterminate="false" android:indeterminateOnly="false" />
-
-  </RelativeLayout>
-
-</RelativeLayout>
\ No newline at end of file
diff --git a/res/layout/ssl_untrusted_cert_layout.xml b/res/layout/ssl_untrusted_cert_layout.xml
new file mode 100644 (file)
index 0000000..6a30c2e
--- /dev/null
@@ -0,0 +1,460 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 
+    ownCloud Android client application
+
+    Copyright (C) 2012-2013 ownCloud Inc.
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License version 2,
+    as published by the Free Software Foundation.
+  
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/root"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:gravity="center"
+    android:orientation="vertical" >
+
+       <TextView
+               android:id="@+id/header"
+               android:layout_width="wrap_content"
+               android:layout_height="wrap_content"
+               android:layout_weight="0"
+               android:text="@string/ssl_validator_header"
+               android:padding="5dp"
+               android:textAppearance="?android:attr/textAppearanceMedium"
+                />
+    
+       <TextView
+               android:id="@+id/reason_cert_not_trusted"
+               android:layout_width="wrap_content"
+               android:layout_height="wrap_content"
+               android:layout_weight="0"
+               android:layout_gravity="left"
+               android:paddingLeft="20dp"
+               android:text="@string/ssl_validator_reason_cert_not_trusted"
+               android:textAppearance="?android:attr/textAppearanceSmall"
+                />
+               
+       
+       <TextView
+               android:id="@+id/reason_cert_expired"
+               android:layout_width="wrap_content"
+               android:layout_height="wrap_content"
+               android:layout_gravity="left"
+               android:paddingLeft="20dp"
+               android:text="@string/ssl_validator_reason_cert_expired"
+               android:textAppearance="?android:attr/textAppearanceSmall"
+                />
+       
+       <TextView
+               android:id="@+id/reason_cert_not_yet_valid"
+               android:layout_width="wrap_content"
+               android:layout_height="wrap_content"
+               android:layout_gravity="left"
+               android:paddingLeft="20dp"
+               android:text="@string/ssl_validator_reason_cert_not_yet_valid"
+               android:textAppearance="?android:attr/textAppearanceSmall"
+                />
+               
+       <TextView
+               android:id="@+id/reason_hostname_not_verified"
+               android:layout_width="wrap_content"
+               android:layout_height="wrap_content"
+               android:layout_gravity="left"
+               android:paddingLeft="20dp"
+               android:text="@string/ssl_validator_reason_hostname_not_verified"
+               android:textAppearance="?android:attr/textAppearanceSmall"
+                />
+       
+       <TextView
+               android:id="@+id/reason_no_info_about_error"
+               android:layout_width="wrap_content"
+               android:layout_height="wrap_content"
+               android:layout_gravity="left"
+               android:paddingLeft="20dp"
+               android:text="@string/ssl_validator_no_info_about_error"
+               android:textAppearance="?android:attr/textAppearanceSmall"
+                />
+       
+    <ScrollView 
+        android:id="@+id/details_scroll"
+        android:visibility="gone" 
+       android:padding="20dp"
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1"
+        >
+        
+               <LinearLayout 
+               android:id="@+id/details_view"
+               android:layout_width="wrap_content"
+               android:layout_height="wrap_content"
+               android:gravity="left"
+               android:orientation="vertical" >
+                       
+                   <TextView
+                       android:id="@+id/null_cert"
+                       android:layout_width="wrap_content"
+                       android:layout_height="wrap_content"
+                       android:layout_gravity="left"
+                       android:paddingLeft="20dp"
+                       android:text="@string/ssl_validator_null_cert"
+                       android:textAppearance="?android:attr/textAppearanceSmall" />
+
+                               <TextView
+                               android:id="@+id/label_subject"
+                               android:layout_width="wrap_content"
+                               android:layout_height="wrap_content"
+                                       android:paddingBottom="5dp"
+                               android:text="@string/ssl_validator_label_subject"
+                               android:textAppearance="?android:attr/textAppearanceMedium"
+                       />
+                               
+                               <TextView
+                                   android:id="@+id/label_subject_CN"
+                                   android:layout_width="wrap_content"
+                                   android:layout_height="wrap_content"
+                                   android:text="@string/ssl_validator_label_CN"
+                                   android:textAppearance="?android:attr/textAppearanceSmall"
+                               />
+                           
+                               <TextView
+                                   android:id="@+id/value_subject_CN"
+                                   android:layout_width="wrap_content"
+                                   android:layout_height="wrap_content"
+                                   android:paddingBottom="5dp"
+                                   android:text=""
+                                   android:textAppearance="?android:attr/textAppearanceSmall"
+                               />
+                               
+                               <TextView
+                                   android:id="@+id/label_subject_O"
+                                   android:layout_width="wrap_content"
+                                   android:layout_height="wrap_content"
+                                   android:text="@string/ssl_validator_label_O"
+                                   android:textAppearance="?android:attr/textAppearanceSmall"
+                               />
+                           
+                               <TextView
+                                   android:id="@+id/value_subject_O"
+                                   android:layout_width="wrap_content"
+                                   android:layout_height="wrap_content"
+                                   android:paddingBottom="5dp"
+                                   android:text=""
+                                   android:textAppearance="?android:attr/textAppearanceSmall"
+                               />
+                               
+                               <TextView
+                                   android:id="@+id/label_subject_OU"
+                                   android:layout_width="wrap_content"
+                                   android:layout_height="wrap_content"
+                                   android:text="@string/ssl_validator_label_OU"
+                                   android:textAppearance="?android:attr/textAppearanceSmall"
+                               />
+                           
+                               <TextView
+                                   android:id="@+id/value_subject_OU"
+                                   android:layout_width="wrap_content"
+                                   android:layout_height="wrap_content"
+                                   android:paddingBottom="5dp"
+                                   android:text=""
+                                   android:textAppearance="?android:attr/textAppearanceSmall"
+                               />
+                               
+                               <TextView
+                                   android:id="@+id/label_subject_ST"
+                                   android:layout_width="wrap_content"
+                                   android:layout_height="wrap_content"
+                                   android:text="@string/ssl_validator_label_ST"
+                                   android:textAppearance="?android:attr/textAppearanceSmall"
+                               />
+                           
+                               <TextView
+                                   android:id="@+id/value_subject_ST"
+                                   android:layout_width="wrap_content"
+                                   android:layout_height="wrap_content"
+                                   android:paddingBottom="5dp"
+                                   android:text=""
+                                   android:textAppearance="?android:attr/textAppearanceSmall"
+                               />
+
+                               <TextView
+                                   android:id="@+id/label_subject_C"
+                                   android:layout_width="wrap_content"
+                                   android:layout_height="wrap_content"
+                                   android:text="@string/ssl_validator_label_C"
+                                   android:textAppearance="?android:attr/textAppearanceSmall"
+                               />
+                               
+                               <TextView
+                                   android:id="@+id/value_subject_C"
+                                   android:layout_width="wrap_content"
+                                   android:layout_height="wrap_content"
+                                   android:paddingBottom="5dp"
+                                   android:text=""
+                                   android:textAppearance="?android:attr/textAppearanceSmall"
+                               />
+                               
+                               <TextView
+                                   android:id="@+id/label_subject_L"
+                                   android:layout_width="wrap_content"
+                                   android:layout_height="wrap_content"
+                                   android:text="@string/ssl_validator_label_L"
+                                   android:textAppearance="?android:attr/textAppearanceSmall"
+                               />
+                           
+                               <TextView
+                                   android:id="@+id/value_subject_L"
+                                   android:layout_width="wrap_content"
+                                   android:layout_height="wrap_content"
+                                   android:paddingBottom="5dp"
+                                   android:text=""
+                                   android:textAppearance="?android:attr/textAppearanceSmall"
+                               />
+                           
+
+                               <TextView
+                               android:id="@+id/label_issuer"
+                               android:layout_width="wrap_content"
+                               android:layout_height="wrap_content"
+                                       android:paddingBottom="5dp"
+                               android:text="@string/ssl_validator_label_issuer"
+                               android:textAppearance="?android:attr/textAppearanceMedium"
+                       />
+                               
+                               <TextView
+                                   android:id="@+id/label_issuer_CN"
+                                   android:layout_width="wrap_content"
+                                   android:layout_height="wrap_content"
+                                   android:text="@string/ssl_validator_label_CN"
+                                   android:textAppearance="?android:attr/textAppearanceSmall"
+                               />
+                           
+                               <TextView
+                                   android:id="@+id/value_issuer_CN"
+                                   android:layout_width="wrap_content"
+                                   android:layout_height="wrap_content"
+                                   android:paddingBottom="5dp"
+                                   android:text=""
+                                   android:textAppearance="?android:attr/textAppearanceSmall"
+                               />
+                               
+                               <TextView
+                                   android:id="@+id/label_issuer_O"
+                                   android:layout_width="wrap_content"
+                                   android:layout_height="wrap_content"
+                                   android:text="@string/ssl_validator_label_O"
+                                   android:textAppearance="?android:attr/textAppearanceSmall"
+                               />
+                           
+                               <TextView
+                                   android:id="@+id/value_issuer_O"
+                                   android:layout_width="wrap_content"
+                                   android:layout_height="wrap_content"
+                                   android:paddingBottom="5dp"
+                                   android:text=""
+                                   android:textAppearance="?android:attr/textAppearanceSmall"
+                               />
+                               
+                               <TextView
+                                   android:id="@+id/label_issuer_OU"
+                                   android:layout_width="wrap_content"
+                                   android:layout_height="wrap_content"
+                                   android:text="@string/ssl_validator_label_OU"
+                                   android:textAppearance="?android:attr/textAppearanceSmall"
+                               />
+                           
+                               <TextView
+                                   android:id="@+id/value_issuer_OU"
+                                   android:layout_width="wrap_content"
+                                   android:layout_height="wrap_content"
+                                   android:paddingBottom="5dp"
+                                   android:text=""
+                                   android:textAppearance="?android:attr/textAppearanceSmall"
+                               />
+                               
+                               <TextView
+                                   android:id="@+id/label_issuer_ST"
+                                   android:layout_width="wrap_content"
+                                   android:layout_height="wrap_content"
+                                   android:text="@string/ssl_validator_label_ST"
+                                   android:textAppearance="?android:attr/textAppearanceSmall"
+                               />
+                           
+                               <TextView
+                                   android:id="@+id/value_issuer_ST"
+                                   android:layout_width="wrap_content"
+                                   android:layout_height="wrap_content"
+                                   android:paddingBottom="5dp"
+                                   android:text=""
+                                   android:textAppearance="?android:attr/textAppearanceSmall"
+                               />
+
+                               <TextView
+                                   android:id="@+id/label_issuer_C"
+                                   android:layout_width="wrap_content"
+                                   android:layout_height="wrap_content"
+                                   android:text="@string/ssl_validator_label_C"
+                                   android:textAppearance="?android:attr/textAppearanceSmall"
+                               />
+                               
+                               <TextView
+                                   android:id="@+id/value_issuer_C"
+                                   android:layout_width="wrap_content"
+                                   android:layout_height="wrap_content"
+                                   android:paddingBottom="5dp"
+                                   android:text=""
+                                   android:textAppearance="?android:attr/textAppearanceSmall"
+                               />
+                               
+                               <TextView
+                                   android:id="@+id/label_issuer_L"
+                                   android:layout_width="wrap_content"
+                                   android:layout_height="wrap_content"
+                                   android:text="@string/ssl_validator_label_L"
+                                   android:textAppearance="?android:attr/textAppearanceSmall"
+                               />
+                           
+                               <TextView
+                                   android:id="@+id/value_issuer_L"
+                                   android:layout_width="wrap_content"
+                                   android:layout_height="wrap_content"
+                                   android:paddingBottom="5dp"
+                                   android:text=""
+                                   android:textAppearance="?android:attr/textAppearanceSmall"
+                               />
+                           
+                               <TextView
+                               android:id="@+id/label_validity"
+                               android:layout_width="wrap_content"
+                               android:layout_height="wrap_content"
+                                       android:paddingBottom="5dp"
+                               android:text="@string/ssl_validator_label_validity"
+                               android:textAppearance="?android:attr/textAppearanceMedium"
+                       />
+                               
+                               <TextView
+                                   android:id="@+id/label_validity_from"
+                                   android:layout_width="wrap_content"
+                                   android:layout_height="wrap_content"
+                                   android:text="@string/ssl_validator_label_validity_from"
+                                   android:textAppearance="?android:attr/textAppearanceSmall"
+                               />
+                           
+                               <TextView
+                                   android:id="@+id/value_validity_from"
+                                   android:layout_width="wrap_content"
+                                   android:layout_height="wrap_content"
+                                   android:paddingBottom="5dp"
+                                   android:text=""
+                                   android:textAppearance="?android:attr/textAppearanceSmall"
+                               />
+                               
+                               <TextView
+                                   android:id="@+id/label_validity_to"
+                                   android:layout_width="wrap_content"
+                                   android:layout_height="wrap_content"
+                                   android:text="@string/ssl_validator_label_validity_to"
+                                   android:textAppearance="?android:attr/textAppearanceSmall"
+                               />
+                           
+                               <TextView
+                                   android:id="@+id/value_validity_to"
+                                   android:layout_width="wrap_content"
+                                   android:layout_height="wrap_content"
+                                   android:paddingBottom="5dp"
+                                   android:text=""
+                                   android:textAppearance="?android:attr/textAppearanceSmall"
+                               />
+                               
+
+                               <TextView
+                               android:id="@+id/label_signature"
+                               android:layout_width="wrap_content"
+                               android:layout_height="wrap_content"
+                                       android:paddingBottom="5dp"
+                               android:text="@string/ssl_validator_label_signature"
+                               android:textAppearance="?android:attr/textAppearanceMedium"
+                       />
+                               
+                               <TextView
+                               android:id="@+id/label_signature_algorithm"
+                               android:layout_width="wrap_content"
+                               android:layout_height="wrap_content"
+                               android:text="@string/ssl_validator_label_signature_algorithm"
+                               android:textAppearance="?android:attr/textAppearanceSmall"
+                       />
+                               
+                               <TextView
+                               android:id="@+id/value_signature_algorithm"
+                               android:layout_width="wrap_content"
+                               android:layout_height="wrap_content"
+                                       android:paddingBottom="5dp"
+                               android:text=""
+                               android:textAppearance="?android:attr/textAppearanceSmall"
+                       />
+                                                                                                                                                                                               
+                                                               
+                               <TextView
+                               android:id="@+id/value_signature"
+                               android:layout_width="wrap_content"
+                               android:layout_height="wrap_content"
+                                       android:paddingBottom="5dp"
+                               android:text=""
+                               android:textAppearance="?android:attr/textAppearanceSmall"
+                       />
+                               
+               </LinearLayout>
+               
+    </ScrollView>
+       
+       <TextView
+        android:id="@+id/question"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+               android:layout_weight="0"
+               android:padding="5dp"
+        android:text="@string/ssl_validator_question"
+        android:textAppearance="?android:attr/textAppearanceMedium"
+        >
+    </TextView>
+
+       <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+               android:layout_weight="0"
+        android:gravity="center" >
+
+        <Button
+            android:id="@+id/cancel"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:text="@string/common_cancel" />
+
+        <Button
+            android:id="@+id/details_btn"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:text="@string/ssl_validator_btn_details_see" />
+
+        <Button
+            android:id="@+id/ok"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:text="@string/common_ok" />
+
+    </LinearLayout>
+
+</LinearLayout>
index 9da017b..27204a2 100644 (file)
@@ -79,7 +79,7 @@
         android:layout_width="wrap_content"
         android:layout_height="180dp">
         
-               <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+               <LinearLayout
                android:id="@+id/details_view"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
index 788a0e2..ccfb04b 100644 (file)
     android:layout_height="wrap_content"
     >
     
-    <com.owncloud.android.ui.dialog.SsoWebView
+    <!--  com.owncloud.android.ui.dialog.SsoWebView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
         android:id="@+id/sso_webview"
         android:focusable="true"
         android:focusableInTouchMode="true"
         android:clickable="true"
-        />
+        /-->
 
 </RelativeLayout>
diff --git a/res/menu/account_picker.xml b/res/menu/account_picker.xml
deleted file mode 100644 (file)
index 8532600..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ownCloud Android client application
-
-  Copyright (C) 2012  Bartek Przybylski
-  Copyright (C) 2012-2013 ownCloud Inc.
-
-  This program is free software: you can redistribute it and/or modify
-  it under the terms of the GNU General Public License version 2,
-  as published by the Free Software Foundation.
-
-  This program is distributed in the hope that it will be useful,
-  but WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-  GNU General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with this program.  If not, see <http://www.gnu.org/licenses/>.
--->
-<menu xmlns:android="http://schemas.android.com/apk/res/android" >
-    <item android:id="@+id/createAccount" android:title="@string/create_account" android:showAsAction="ifRoom|withText"></item>
-    
-
-</menu>
\ No newline at end of file
index 1aa2823..b60d542 100644 (file)
 -->
 <menu  xmlns:android="http://schemas.android.com/apk/res/android">
     
-       <item   android:id="@+id/action_open_file_with"                 android:title="@string/actionbar_open_with"                     android:icon="@android:drawable/ic_menu_edit"                                   android:orderInCategory="1" />
+       <item   android:id="@+id/action_share_file"                             android:title="@string/action_share_file"                       android:icon="@android:drawable/ic_menu_share"                                  android:orderInCategory="1" />
+       <item   android:id="@+id/action_unshare_file"               android:title="@string/action_unshare_file"                 android:icon="@android:drawable/ic_menu_share"                                  android:orderInCategory="1" />
+    <item      android:id="@+id/action_open_file_with"                 android:title="@string/actionbar_open_with"                     android:icon="@android:drawable/ic_menu_set_as"                                 android:orderInCategory="1" /> 
        <item   android:id="@+id/action_download_file"                  android:title="@string/filedetails_download"            android:icon="@drawable/ic_action_download"                                             android:orderInCategory="1" />
     <item      android:id="@+id/action_sync_file"                              android:title="@string/filedetails_sync_file"           android:icon="@drawable/ic_action_refresh"                                              android:orderInCategory="1" />
        <item   android:id="@+id/action_cancel_download"                android:title="@string/common_cancel_download"          android:icon="@android:drawable/ic_menu_close_clear_cancel"             android:orderInCategory="1" />
        <item   android:id="@+id/action_cancel_upload"                  android:title="@string/common_cancel_upload"            android:icon="@android:drawable/ic_menu_close_clear_cancel"             android:orderInCategory="1" />
-       <item   android:id="@+id/action_rename_file"                    android:title="@string/common_rename"                           android:icon="@android:drawable/ic_menu_set_as"                                 android:orderInCategory="1" />
+       <item   android:id="@+id/action_rename_file"                    android:title="@string/common_rename"                           android:icon="@android:drawable/ic_menu_edit"                                   android:orderInCategory="1" />
+    <item      android:id="@+id/action_move"                                   android:title="@string/actionbar_move"                          android:icon="@android:drawable/ic_menu_set_as"                                 android:orderInCategory="1" />
     <item      android:id="@+id/action_remove_file"                    android:title="@string/common_remove"                           android:icon="@android:drawable/ic_menu_delete"                                 android:orderInCategory="1" />
+    <item      android:id="@+id/action_send_file"                              android:title="@string/actionbar_send_file"                     android:icon="@android:drawable/ic_menu_set_as"                                 android:orderInCategory="1" />
     <item      android:id="@+id/action_see_details"                    android:title="@string/actionbar_see_details"           android:icon="@android:drawable/ic_menu_info_details"                   android:orderInCategory="1" />
-    
+
 </menu>
index 538dde7..b738322 100644 (file)
   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 -->
-<menu
-  xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:id="@+id/action_sync_account"        android:title="@string/actionbar_sync"          android:icon="@drawable/ic_action_refresh"                              android:orderInCategory="2" />
-    <item android:id="@+id/action_create_dir"          android:title="@string/actionbar_mkdir"         android:icon="@drawable/ic_action_create_dir"                   android:orderInCategory="2" />
-    <item android:id="@+id/action_upload"                      android:title="@string/actionbar_upload"        android:icon="@drawable/ic_action_upload"                               android:orderInCategory="2" />
-    <item android:id="@+id/action_settings"            android:title="@string/actionbar_settings"      android:icon="@android:drawable/ic_menu_preferences"    android:orderInCategory="2" />
-    
-    <!--  <item android:id="@+id/search" android:title="@string/actionbar_search" android:icon="@drawable/ic_action_search"></item>-->
-</menu>
+<menu xmlns:android="http://schemas.android.com/apk/res/android" >
+
+    <item
+        android:id="@+id/action_upload"
+        android:icon="@drawable/ic_action_upload"
+        android:orderInCategory="2"
+        android:showAsAction="always"
+        android:title="@string/actionbar_upload"/>
+    <item
+        android:id="@+id/action_create_dir"
+        android:icon="@drawable/ic_action_create_dir"
+        android:orderInCategory="2"
+        android:showAsAction="always"
+        android:title="@string/actionbar_mkdir"/>
+    <item
+        android:id="@+id/action_sync_account"
+        android:icon="@drawable/ic_action_refresh"
+        android:orderInCategory="2"
+        android:showAsAction="never"
+        android:title="@string/actionbar_sync"/>
+    <item
+        android:id="@+id/action_settings"
+        android:icon="@drawable/ic_action_settings"
+        android:orderInCategory="2"
+        android:showAsAction="never"
+        android:title="@string/actionbar_settings"/>
+    <item
+        android:id="@+id/action_logger"
+        android:icon="@drawable/ic_action_settings"
+        android:orderInCategory="2"
+        android:showAsAction="never"
+        android:title="@string/actionbar_logger"/>
+       <item
+        android:id="@+id/action_sort"
+        android:icon="@android:drawable/ic_menu_sort_alphabetically"
+        android:orderInCategory="2"
+        android:showAsAction="never"
+        android:title="@string/actionbar_sort"/>
+
+    <!-- <item android:id="@+id/search" android:title="@string/actionbar_search" android:icon="@drawable/ic_action_search"></item> -->
+
+</menu>
\ No newline at end of file
index d037a07..6ea4191 100644 (file)
@@ -4,4 +4,8 @@
   <string name="prefs_help">Hulp</string>
   <string name="auth_username">Gebruikersnaam</string>
   <string name="auth_password">Wagwoord</string>
+  <string name="common_ok">OK</string>
+  <string name="common_cancel">Kanseleer</string>
+  <string name="empty"></string>
+  <string name="move_choose_button_text">Kies</string>
 </resources>
diff --git a/res/values-ak/strings.xml b/res/values-ak/strings.xml
new file mode 100644 (file)
index 0000000..56e55a1
--- /dev/null
@@ -0,0 +1,4 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<resources>
+  <string name="empty"></string>
+</resources>
diff --git a/res/values-am-rET/strings.xml b/res/values-am-rET/strings.xml
new file mode 100644 (file)
index 0000000..56e55a1
--- /dev/null
@@ -0,0 +1,4 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<resources>
+  <string name="empty"></string>
+</resources>
index cbda0e7..4d89b57 100644 (file)
 <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_mkdir">إنشاء دليل</string>
-  <string name="actionbar_settings">تعديلات</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="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="auth_host_url">عنوان الخادم</string>
+  <string name="recommend_subject">جرب %1$s على جهازك الذكي</string>
+  <string name="auth_check_server">تحقق من الخادم</string>
+  <string name="auth_host_url">عنوان الخادم https://…</string>
   <string name="auth_username">إسم المستخدم</string>
-  <string name="auth_password">Ù\83Ù\84Ù\85ات السر</string>
-  <string name="auth_register">جدÙ\8aد Ù\84Ù\80 %1$s ؟</string>
+  <string name="auth_password">Ù\83Ù\84Ù\85Ø© السر</string>
+  <string name="auth_register">جدÙ\8aد Ù\81Ù\8a %1$s ؟</string>
   <string name="sync_string_files">الملفات</string>
   <string name="setup_btn_connect">اتصال</string>
-  <string name="uploader_btn_upload_text">إرفع</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_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">خروج</string>
-  <string name="uploader_wrn_no_content_title">Ù\84ا Ù\8aÙ\88جد Ù\85حتÙ\88Ù\8aات للرفع</string>
-  <string name="uploader_wrn_no_content_text">Ù\84Ù\85 Ù\8aتÙ\85 Ø§Ø³ØªÙ\84اÙ\85 Ø£Ù\8a Ù\85حتÙ\88Ù\8aات.</string>
-  <string name="uploader_error_forbidden_content">%1$s  ØºÙ\8aر Ù\85سÙ\85Ù\88Ø­ Ù\84Ù\87 Ø¨Ø§Ù\84Ù\88صÙ\88Ù\84 Ù\84Ù\84Ù\85حتÙ\88Ù\89 Ø§Ù\84Ù\85شترك</string>
+  <string name="uploader_wrn_no_content_title">Ù\84ا Ù\8aÙ\88جد Ù\85حتÙ\88Ù\89 للرفع</string>
+  <string name="uploader_wrn_no_content_text">Ù\84Ù\85 Ù\8aتÙ\85 Ø§Ø³ØªÙ\84اÙ\85 Ø£Ù\8a Ù\85حتÙ\88Ù\89. Ù\84ا Ø´Ù\8aØ¡ Ù\84Ù\84رÙ\81ع.</string>
+  <string name="uploader_error_forbidden_content">%1$s  ØºÙ\8aر Ù\85سÙ\85Ù\88Ø­ Ù\84Ù\87 Ø¨Ø§Ù\84Ù\88صÙ\88Ù\84 Ù\84Ù\84Ù\85حتÙ\88Ù\89 Ø§Ù\84Ù\85شارك</string>
   <string name="uploader_info_uploading">يتم الرفع</string>
+  <string name="file_list_empty">لا يوجد شيء هنا. إرفع بعض الملفات!</string>
+  <string name="file_list_loading">جاري التحميل ...</string>
   <string name="filedetails_select_file">اضغظ على الملف ليتم عرض خيارات أكثر</string>
-  <string name="filedetails_size">الحجم</string>
-  <string name="filedetails_type">النوع</string>
-  <string name="filedetails_modified">عُدل</string>
-  <string name="filedetails_download">انزال</string>
+  <string name="filedetails_size">الحجم :</string>
+  <string name="filedetails_type">النوع :</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_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_upload">إلغاء رفع الملفات</string>
-  <string name="common_cancel">الغاء</string>
+  <string name="common_cancel_download">إلغاء التحميل</string>
+  <string name="common_cancel_upload">إلغاء الرفع</string>
+  <string name="common_cancel">إلغاء</string>
+  <string name="common_save_exit">حفظ + خروج</string>
   <string name="common_error">خطأ</string>
-  <string name="common_error_unknown">حدث خطأ غير معروف. </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_upload_in_progress_ticker">يتم الرفع</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="downloader_download_in_progress_ticker">يتم التحميل</string>
-  <string name="downloader_download_in_progress_content">%1$d%% تنزيل  %2$s</string>
+  <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">يتم التحميل ...</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="common_choose_account">اختر حساب</string>
-  <string name="sync_fail_content">تعذر إكمال التزامن لـ %1$s  </string>
+  <string name="downloader_download_failed_content"> لم يكتمل تحميل %1$s</string>
+  <string name="downloader_not_downloaded_yet">لم يتم تحميلها بعد</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="sync_fail_content_unauthorized">كلمة السر غير صالحة لـ %1$s</string>
-  <string name="sync_fail_in_favourites_content"> جهات الاتصال لـ %1$d لا يمكن مزامنتها ( %2$d تعارض) </string>
+  <string name="sync_conflicts_in_favourites_ticker">هناك تعارض</string>
+  <string name="sync_conflicts_in_favourites_content">لم تنجح المزامنة الدائمة لـ %1$d ملفات</string>
+  <string name="sync_fail_in_favourites_ticker">لم تنجح المزامنة التلقائية للملفات</string>
+  <string name="sync_fail_in_favourites_content"> لا يمكن مزامنة جهات اتصال %1$d  ( %2$d تعارض) </string>
+  <string name="sync_foreign_files_forgotten_ticker">تم نسيان بعض الملفات المحلية</string>
+  <string name="sync_foreign_files_forgotten_content">%1$d لا يمكن نسخها داخل المجلد %2$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="upload_query_move_foreign_files">لا يوجد مساحة كافية لنسخ الملفات المحددة لمجلد  %1$s . هل ترغب بنقلهم للمجلد بدلاَ من ذلك؟</string>
-  <string name="pincode_enter_pin_code">فضلا, ادخل كلمة السر</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="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">سيتم طلب PIN في كل مرة يتم فيها تشغيل التطبيق</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_wrong_connection_title">لا يمكن إنشاء اتصال</string>
-  <string name="auth_secure_connection">تم إنشاء اتصال آمن</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_remote">حذف من الخادم</string>
-  <string name="remove_success_msg">يتم الحذف بنجاح</string>
-  <string name="remove_fail_msg">لقد فشل الحذف</string>
-  <string name="wait_a_moment">فضلاً, انتظر</string>
+  <string name="auth_connection_established">تم الاتصال</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_unverified_server_title">لا يمكن التحقق من هوية خادم SSL</string>
+  <string name="auth_bad_oc_version_title">إصدار الخادم غير معروف</string>
+  <string name="auth_wrong_connection_title">لم ينجح الاتصال</string>
+  <string name="auth_secure_connection">نجح الاتصال آمن</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="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="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_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_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">شهادة الخادم غير موثوقة</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">هل تريد أن تثق في هذه الشهادة على اي حال ؟</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">أصدرت بواسطة</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">البلد :</string>
+  <string name="ssl_validator_label_ST">الحالة :</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">placeholder.txt</string>
+  <string name="placeholder_filetype">صورة PNG</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">رفع الصور من خلال الـ WiFi فقط</string>
+  <string name="instant_video_upload_on_wifi">رفع فيديو عبر الواي فاي حصراً</string>
+  <string name="instant_upload_path">/InstantUpload</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="share_link_no_support_share_api">عذراً, المشاركة غير متاحة في الخادم الخاص بك. الرجاء الإتصال
+  بالمسؤول.</string>
+  <string name="share_link_file_error">حدث خطأ ما أثناء محاولة مشاركة هذا الملف أو المجلد</string>
+  <string name="unshare_link_file_error">حدث خطأ ما أثناء محاولة إلغاء مشاركة هذا الملف أو المجلد</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="prefs_category_accounts">حسابات</string>
+  <string name="saml_authentication_wrong_pass">كلمة مرور خاطئة</string>
+  <string name="move_choose_button_text">اختيار</string>
+  <string name="prefs_category_security">الأمان</string>
 </resources>
diff --git a/res/values-az/strings.xml b/res/values-az/strings.xml
new file mode 100644 (file)
index 0000000..b037311
--- /dev/null
@@ -0,0 +1,221 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<resources>
+  <string name="about_android">%1$s Android Programlar</string>
+  <string name="about_version">versiya %1$s</string>
+  <string name="actionbar_sync">Yenilənmə hesabı</string>
+  <string name="actionbar_upload">Serverə yüklə</string>
+  <string name="actionbar_upload_from_apps">Digər porgramların kontenti</string>
+  <string name="actionbar_upload_files">Fayllar</string>
+  <string name="actionbar_open_with">Bunula aç</string>
+  <string name="actionbar_mkdir">Yeni qovluq</string>
+  <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="prefs_category_general">Ümumi</string>
+  <string name="prefs_category_more">Daha da</string>
+  <string name="prefs_accounts">Hesablar</string>
+  <string name="prefs_manage_accounts">İstifadəçilərin idarəedilməsi</string>
+  <string name="prefs_pincode">Proqram təminatının PİN-i</string>
+  <string name="prefs_pincode_summary">Müştərini qoru</string>
+  <string name="prefs_instant_upload">Ani şəkil yükləmələri</string>
+  <string name="prefs_instant_upload_summary">Kamera vasitəsi ilə götürülmüş şəkillərin tez yüklənməsi</string>
+  <string name="prefs_instant_video_upload">Ani video yükləmələri</string>
+  <string name="prefs_instant_video_upload_summary">Kamera vasitəsi ilə yazılmış videoların tez yüklənməsi</string>
+  <string name="prefs_log_title">Jurnallamanın işə salınması</string>
+  <string name="prefs_log_summary">Bu problemlərin jurnal edilməsi üçün istifadə edilir</string>
+  <string name="prefs_log_title_history">Jurnalların Tarixçəsi</string>
+  <string name="prefs_log_summary_history">Bu, yazılmış jurnalları göstərir</string>
+  <string name="prefs_log_delete_history_button">Tarixçəni sil</string>
+  <string name="prefs_help">Kömək</string>
+  <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="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="auth_host_url">Server ünvanı https://…</string>
+  <string name="auth_username">İstifadəçi adı</string>
+  <string name="auth_password">Şifrə</string>
+  <string name="auth_register">Yeni edək %1$s?</string>
+  <string name="sync_string_files">Fayllar</string>
+  <string name="setup_btn_connect">Qoşul</string>
+  <string name="uploader_btn_upload_text">Serverə yüklə</string>
+  <string name="uploader_top_message">Yüklənmə qovluöunu seçin:</string>
+  <string name="uploader_wrn_no_account_title">Hesab tapılmadı</string>
+  <string name="uploader_wrn_no_account_text">Sizin alətinizda %1$s hesabi tapılmadı. Xahiş olunur öncə hesabi quraşdırasınız.</string>
+  <string name="uploader_wrn_no_account_setup_btn_text">Qurulum</string>
+  <string name="uploader_wrn_no_account_quit_btn_text">Çıx</string>
+  <string name="uploader_wrn_no_content_title">Yükləmək üçün kontent yoxdur</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_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="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>
+  <string name="filedetails_created">Yaradıldı:</string>
+  <string name="filedetails_modified">Dəyişdirildi:</string>
+  <string name="filedetails_download">Yüklə</string>
+  <string name="filedetails_sync_file">Faylı yenilə</string>
+  <string name="filedetails_renamed_in_upload_msg">Yüklənmə müddətində fayl buna %1$s yeniləndi</string>
+  <string name="action_share_file">Linki yayımla</string>
+  <string name="action_unshare_file">Link yayımlanmasını dayandır</string>
+  <string name="common_yes">Bəli</string>
+  <string name="common_no">Xeyir</string>
+  <string name="common_ok">Oldu</string>
+  <string name="common_cancel_download">Endirimi dayandır</string>
+  <string name="common_cancel_upload">Yüklənməni dayandır</string>
+  <string name="common_cancel">Dayandır</string>
+  <string name="common_save_exit">Saxla &amp; Çıx</string>
+  <string name="common_error">Səhv</string>
+  <string name="common_loading">Yüklənir...</string>
+  <string name="common_error_unknown">Bəlli olmayan səhv baş verdi</string>
+  <string name="about_title">Haqqında</string>
+  <string name="change_password">Şifrəni dəyiş</string>
+  <string name="delete_account">Hesabı sil</string>
+  <string name="create_account">Hesab yarat</string>
+  <string name="upload_chooser_title">Burdan yüklə ...</string>
+  <string name="uploader_info_dirname">Qovluq adı</string>
+  <string name="uploader_upload_in_progress_ticker">Yüklənmə gedir ...</string>
+  <string name="uploader_upload_in_progress_content">%1$d%% Yüklənmə gedir %2$s</string>
+  <string name="uploader_upload_succeeded_ticker">Uğurla yükləndi</string>
+  <string name="uploader_upload_succeeded_content_single">%1$s uğurla yüklənmişdir</string>
+  <string name="uploader_upload_failed_ticker">Yüklənmədə səhv baş verdi</string>
+  <string name="uploader_upload_failed_content_single">%1$s yüklənməsi bitə bilməz</string>
+  <string name="uploader_upload_failed_credentials_error">Yüklənmədə səhv baş verdi, siz yenidən daxil olmalısınız</string>
+  <string name="downloader_download_in_progress_ticker">Endirilir ...</string>
+  <string name="downloader_download_in_progress_content">%1$d%% Endirilir %2$s</string>
+  <string name="downloader_download_succeeded_ticker">Endirim uğurla bitdi</string>
+  <string name="downloader_download_succeeded_content">%1$s uğurla endirildi</string>
+  <string name="downloader_download_failed_ticker">Endirim olmadı</string>
+  <string name="downloader_download_failed_content">%1$s endirimi bitə bilməz</string>
+  <string name="downloader_not_downloaded_yet">Hələ endirilməyib</string>
+  <string name="downloader_download_failed_credentials_error">Endirmədə səhv, siz yenidən daxil olmalısınız</string>
+  <string name="common_choose_account">Hesabı seç</string>
+  <string name="sync_fail_ticker">Sinxronizasiyada səhv oldu</string>
+  <string name="sync_fail_ticker_unauthorized">Sinxronizasiyada səhv oldu, siz yenidən daxil olmalısınız</string>
+  <string name="sync_fail_content">%1$s sinxronizasiyası bitə bilməyəcək</string>
+  <string name="sync_fail_content_unauthorized">%1$s üçün yalnış şifrə</string>
+  <string name="sync_conflicts_in_favourites_ticker">Konflikt tapıldı</string>
+  <string name="sync_conflicts_in_favourites_content">%1$d sinxronizasiyada olan fayllar sinxronizasiya edilə bilməz</string>
+  <string name="sync_fail_in_favourites_ticker">Sinxronizasiyada saxlanılan fayllarda səhv baş verdi</string>
+  <string name="sync_fail_in_favourites_content">%1$d fayllarin kontentləri sinxronizasiya edilə bilməz (%2$d konfliktdədir)</string>
+  <string name="sync_foreign_files_forgotten_ticker">Bəzi lokal fayllar unudulmuşdur</string>
+  <string name="sync_foreign_files_forgotten_content">%1$d faylları %2$s qovluğundan kənardadır və qovluğun daxilinə nüsxələnə bilməz </string>
+  <string name="sync_foreign_files_forgotten_explanation">1.3.16 versiyasından başlayaraq, bu alətdən nüsxələnən fayllar daxili %1$s qovluğuna nüsxələnmişdir ki, bir fayl bir neçə hesabla sinxronizasiya edildikdə, data itkisinin qarşısı alınsın.
+
+Bu dəyişikliklə bağlı, bu proqramın öncəki versiyasında yüklənmiş olan fayllar %2$s qovluğuna nüsxələnmişdir. Ancaq bu hesabın sinxronizasiyası zamanı səhv baş vermişdir.\n\nSiz ya fayl(ları) saxlaya və %3$s üçün linki silə bilər, yada fayl(ları)  %1$s qovluğuna köçürə və linki %4$s -ə saxlaya bilərsiniz.
+
+Aşağıda göstərilən %5$s-də olan daxili və xarici fayl(lar) link edilmişdir.</string>
+  <string name="sync_current_folder_was_removed">%1$s qovluğu heç bir yerdə mövcud deyil</string>
+  <string name="foreign_files_move">Hamısını köçür</string>
+  <string name="foreign_files_success">Bütün fayllar köçürüldü</string>
+  <string name="foreign_files_fail">Bəzi fayllar köçürülə bilməz</string>
+  <string name="foreign_files_local_text">Daxili: %1$s</string>
+  <string name="foreign_files_remote_text">Uzaq: %1$s</string>
+  <string name="upload_query_move_foreign_files">Seçdiyiniz faylların %1$s qovluğuna köçüçrülməsi üçün kifayət qədər yer yoxdur. Əvəzinə onları köçürmək istəyirsinizmi?</string>
+  <string name="pincode_enter_pin_code">Xahiş olunur öz proqramınızın PİN-ni daxil edəsiniz</string>
+  <string name="pincode_configure_your_pin">Proqramınızın PİN-ni daxil edin</string>
+  <string name="pincode_configure_your_pin_explanation">Proqram hər dəfə işə düşdükdə PİN yenidən istəniləcək</string>
+  <string name="pincode_reenter_your_pincode">Öz proqramınızn PİN-ni yenidən daxil etməyi xahiş edirik</string>
+  <string name="pincode_remove_your_pincode">Öz proqramınızın PİN-ni silin</string>
+  <string name="pincode_mismatch">Proqram PİN-ləri eyni deyil</string>
+  <string name="pincode_wrong">Yalnış proqram PİN-i</string>
+  <string name="pincode_removed">Proqram PİN-i silindi</string>
+  <string name="pincode_stored">Proqram PİN-i saxlanıldı </string>
+  <string name="media_notif_ticker">%1$s musiqi oxuducusu</string>
+  <string name="media_state_playing">%1$s (oxuyur)</string>
+  <string name="media_state_loading">%1$s (yüklənir)</string>
+  <string name="media_event_done">%1$s geriyə oxunuş bitib</string>
+  <string name="media_err_nothing_to_play">Media faylı tapılmadı</string>
+  <string name="media_err_no_account">Heç bir hesab təqdim edilməyib</string>
+  <string name="media_err_not_in_owncloud">Fayl keçərli hesabda deyil</string>
+  <string name="media_err_unsupported">Media kodeki dəstəklənmir</string>
+  <string name="media_err_io">Media fayl oxunula bilmir</string>
+  <string name="media_err_malformed">Media fayl düzgün kodlaşdırılmayıb</string>
+  <string name="media_err_timeout">İşə salınmanın gözləmə vaxtı bitdi</string>
+  <string name="media_err_invalid_progressive_playback">Media faylı axınlı ola bilməz</string>
+  <string name="media_err_unknown">Media faylı anbarda olan media oxuyucusu ilə işlədilə bilmız</string>
+  <string name="media_err_security_ex">Oynamaya çalışarkən təhlükəsizlik xətası %1$s</string>
+  <string name="media_err_io_ex">Oynamaya çalışarkən daxiletmə xətası %1$s</string>
+  <string name="media_err_unexpected">Oynamaya çalışarkən gözlənilməyən xəta %1$s</string>
+  <string name="media_rewind_description">Geriyə qayıdış düyməsi</string>
+  <string name="media_play_pause_description">Oxunma və ya tənəffüs düyməsi</string>
+  <string name="media_forward_description">Sürətlə irəli düyməsi</string>
+  <string name="auth_getting_authorization">Yetki alınır...</string>
+  <string name="auth_trying_to_login">Girişə cəhd edilir...</string>
+  <string name="auth_no_net_conn_title">Şəbəkə qoşulması yoxdur</string>
+  <string name="auth_nossl_plain_ok_title">Təhlükəsiz qoşulma mümkün deyil.</string>
+  <string name="auth_connection_established">Əlaqə quruldu</string>
+  <string name="auth_testing_connection">Qoşulma test edilir...</string>
+  <string name="auth_not_configured_title">Yalnış qurulmuş server konfiqurasiyası</string>
+  <string name="auth_account_not_new">Avadanlıqda eyni istifadəçi və server üçün artıq hesab mövcuddur</string>
+  <string name="auth_account_not_the_same">Daxil edilən hesab bu hesabla üst-üstə düşmür</string>
+  <string name="auth_unknown_error_title">Yalnış səhv baş verdi!</string>
+  <string name="auth_unknown_host_title">Host-u tapmaq mümkün olmadı</string>
+  <string name="auth_incorrect_path_title">Server nüsxəsi tapılmadı</string>
+  <string name="auth_timeout_title">Server cavab üçün çox uzun müddət aldı</string>
+  <string name="auth_incorrect_address_title">Xətalı URL</string>
+  <string name="auth_ssl_general_error_title">SSL inisializasiyası səhvi</string>
+  <string name="auth_ssl_unverified_server_title">SSL serverin şəxsiliyini təyin etmək mümkün olmadı</string>
+  <string name="auth_bad_oc_version_title">Təyin edilməyən server versiyası</string>
+  <string name="auth_wrong_connection_title">Qoşulma yaratmaq mümkün olmadı</string>
+  <string name="auth_secure_connection">Təhlükəsiz qoşulma yaradıldı</string>
+  <string name="auth_unauthorized">Yalnış istifadəçi yada şifrə</string>
+  <string name="auth_oauth_error">Uğursuz yetkiləndirmə</string>
+  <string name="auth_oauth_error_access_denied">Yetkiləndirmə serveri tərəfindən giriş əngəlləndi</string>
+  <string name="auth_wtf_reenter_URL">Bəlli ediləbilməyən vəziyyət;  xahiş olunur, serverin URL-ni yenidən daxil edəsiniz</string>
+  <string name="auth_expired_oauth_token_toast">Sizin yetinizin vaxtı bitmişdir. Xahiş olunur, yenidən yetkilənəsiniz</string>
+  <string name="auth_expired_basic_auth_toast">Xahiş olunur, hazırki şifrəni daxil edəsiniz</string>
+  <string name="auth_expired_saml_sso_token_toast">Sizin sessiyanın vaxtı bitmişdir. Xahiş olunur yenidən qoşulasınız</string>
+  <string name="auth_connecting_auth_server">Yetkiləndirmə serverinə qoşulma gedir...</string>
+  <string name="auth_unsupported_auth_method">Server bu qeydiyyat metodikasını dəstəkləmir</string>
+  <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="fd_keep_in_sync">Faylı gündəmdə saxla</string>
+  <string name="common_rename">Adı dəyiş</string>
+  <string name="common_remove">Sil</string>
+  <string name="confirmation_remove_alert">Siz həqiqətən %1$s silmək istəyirsiniz?</string>
+  <string name="confirmation_remove_folder_alert">Siz həqiqətəndə %1$s və onun kontentini silmək istəyirsiniz?</string>
+  <string name="confirmation_remove_local">Yalnız daxili</string>
+  <string name="confirmation_remove_folder_local">Yalnız daxili kontent</string>
+  <string name="confirmation_remove_remote">Serverdən sil</string>
+  <string name="confirmation_remove_remote_and_local">Uzaq və lokal</string>
+  <string name="remove_success_msg">Silmə uğurlu oldu</string>
+  <string name="remove_fail_msg">Silmək mümkün olmadı</string>
+  <string name="rename_dialog_title">Yeni adı daxil edin</string>
+  <string name="rename_local_fail_msg">Daxili nüsxənin adı dəyişdirilə bilməz; fərqli ad yoxlayın</string>
+  <string name="rename_server_fail_msg">Ad dəyişmə bitə bilməz</string>
+  <string name="sync_file_fail_msg">Uzaq fayl yoxlanıla bilməz</string>
+  <string name="sync_file_nothing_to_do_msg">Faylın kontenti artıq sinxronizasiya edilmişdir</string>
+  <string name="create_dir_fail_msg">Qovluq yaradıla bilməz</string>
+  <string name="filename_forbidden_characters">Qadağan edilmiş simvollar: / \\ &lt; &gt; : \" | ? *</string>
+  <string name="filename_empty">Faylın adı boş ola bilməz</string>
+  <string name="wait_a_moment">Biraz gözləyin</string>
+  <string name="filedisplay_unexpected_bad_get_content">Naməlum problem; xahiş olunur faylı fərqli program təminatından seçəsiniz</string>
+  <string name="filedisplay_no_file_selected">Heç bir fayl seçilməyib</string>
+  <string name="activity_chooser_title">Linki yollayın ...</string>
+  <string name="oauth_check_onoff">oAuth2 ilə qeydiyyatdan keçin</string>
+  <string name="oauth_login_connection">oAuth2 serverinə qoşulur...</string>
+  <string name="ssl_validator_header">Sayta olan identifikasiya yoxlanıla bilməz</string>
+  <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_btn_details_see">Detallar</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="empty"></string>
+  <string name="forbidden_permissions">Sizin yetkiniz yoxdur %s</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="forbidden_permissions_create">fayl yaratmaq üçün</string>
+  <string name="uploader_upload_forbidden_permissions">bu qovluğa yükləmək üçün</string>
+  <string name="prefs_category_accounts">Hesablar</string>
+  <string name="prefs_add_account">Hesab əlavə et</string>
+  <string name="saml_authentication_wrong_pass">Yalnış şifrə</string>
+</resources>
index c757504..42e2078 100644 (file)
@@ -1,2 +1,10 @@
 <?xml version='1.0' encoding='UTF-8'?>
-<resources/>
+<resources>
+  <string name="actionbar_settings">Налады</string>
+  <string name="common_yes">Так</string>
+  <string name="common_no">Не</string>
+  <string name="common_ok">Добра</string>
+  <string name="common_error">Памылка</string>
+  <string name="empty"></string>
+  <string name="move_choose_button_text">Выбар</string>
+</resources>
index c84d705..47d243c 100644 (file)
 <?xml version='1.0' encoding='UTF-8'?>
 <resources>
+  <string name="about_android">%1$s Android приложение</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_mkdir">Нова директория</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="prefs_category_general">Общи</string>
   <string name="prefs_category_more">Още</string>
   <string name="prefs_accounts">Профили</string>
-  <string name="prefs_instant_upload_summary">Своевременно качване на снимки направени с камерата</string>
+  <string name="prefs_manage_accounts">Управление на профилите</string>
+  <string name="prefs_pincode">App PIN</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="auth_host_url">Адрес на сървъра</string>
+  <string name="prefs_recommend">Препоръчай на приятел</string>
+  <string name="prefs_feedback">Обратна Връзка</string>
+  <string name="prefs_imprint">Imprint</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="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_setup_btn_text">Инсталиране</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="uploader_wrn_no_content_text">Не беше получено съдържание. Няма какво да се качи.</string>
+  <string name="uploader_error_forbidden_content">%1$s няма разрешен достъп до споделеното съдържание.</string>
   <string name="uploader_info_uploading">Качване</string>
-  <string name="filedetails_select_file">Натиснете върху файл за да видите повече информация.</string>
+  <string name="file_list_empty">Тук няма нищо. Качете нещо!</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_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_upload">Спри качването</string>
+  <string name="common_cancel_download">Отказване на тегленето</string>
+  <string name="common_cancel_upload">Отказване на качването</string>
   <string name="common_cancel">Отказ</string>
-  <string name="common_save_exit">Ð\97апази Ð¸ Ð\98злез</string>
+  <string name="common_save_exit">Ð\97апазване Ð¸ Ð¸Ð·Ñ\85од</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">Ð\98зÑ\82Ñ\80ий Ð°ÐºÐ°Ñ\83нÑ\82</string>
-  <string name="create_account">СÑ\8aздай Ð°ÐºÐ°Ñ\83нÑ\82</string>
-  <string name="upload_chooser_title">Ð\9aаÑ\87ено Ð¾Ñ\82 ...</string>
-  <string name="uploader_info_dirname">Име на папка</string>
-  <string name="uploader_upload_in_progress_ticker">Качване ...</string>
+  <string name="change_password">Промяна на парола</string>
+  <string name="delete_account">Ð\98зÑ\82Ñ\80иване Ð½Ð° Ð¿Ñ\80оÑ\84ила</string>
+  <string name="create_account">СÑ\8aздаване Ð½Ð° Ð¿Ñ\80оÑ\84ил</string>
+  <string name="upload_chooser_title">Ð\9aаÑ\87ване Ð¾Ñ\82...</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_failed_ticker">Качването е неуспешно</string>
-  <string name="uploader_upload_failed_content_single">Качването на %1$s не може да бъде завършено</string>
-  <string name="downloader_download_in_progress_ticker">Сваляне ...</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_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_failed_ticker">Свалянето е неуспешно</string>
-  <string name="downloader_download_failed_content">Свалянето на %1$s не може да бъде завършено</string>
-  <string name="common_choose_account">Изберете акаунт</string>
-  <string name="sync_fail_ticker">Синхронизацияте е неуспешна</string>
-  <string name="sync_fail_content">Синхронизацията на %1$s не може да бъде осъществена</string>
-  <string name="pincode_enter_pin_code">Моля въведете Вашия App ПИН</string>
-  <string name="auth_no_net_conn_title">Няма мрежова свързаност</string>
-  <string name="auth_nossl_plain_ok_title">Защитена връзка не е налична</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_not_downloaded_yet">Все още не е изтеглено</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_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_conflicts_in_favourites_content">%1$d kept-in-sync файла не могат да бъдат сихронизирани</string>
+  <string name="sync_fail_in_favourites_ticker">Неуспешни Kept-in-sync файлове</string>
+  <string name="sync_fail_in_favourites_content">Неуспешно синхронизиране на съдържанието на %1$d файла (%2$d конфликта).</string>
+  <string name="sync_foreign_files_forgotten_ticker">Някои локални файлове бяха забравени.</string>
+  <string name="sync_foreign_files_forgotten_content">Неуспешно копиране на %1$d файла в папка %2$s.</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">Въведете своя App ПИН</string>
+  <string name="pincode_configure_your_pin">Въведете своя App ПИН</string>
+  <string name="pincode_configure_your_pin_explanation">ПИН-ът ще бъде поискан всеки път, когато програмата стартира.</string>
+  <string name="pincode_reenter_your_pincode">Въведете своя App ПИН отново.</string>
+  <string name="pincode_remove_your_pincode">Премахнете своя App ПИН</string>
+  <string name="pincode_mismatch">App ПИН-овете не съвпадат</string>
+  <string name="pincode_wrong">Неправилен App ПИН</string>
+  <string name="pincode_removed">App ПИН премахнат</string>
+  <string name="pincode_stored">App ПИН запазен</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_unknown_host_title">Невъзможност за намиране на хоста</string>
-  <string name="auth_timeout_title">Сървърът се забави прекалено много с отговора</string>
-  <string name="auth_incorrect_address_title">Грешен URL</string>
-  <string name="auth_ssl_general_error_title">Инициализацията на SSL е неуспешна</string>
-  <string name="auth_wrong_connection_title">Невъзможност за осъществяване на връзка</string>
-  <string name="auth_secure_connection">Осъществена защитена връзка</string>
-  <string name="fd_keep_in_sync">Дръж файлът обновен</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">Грешен URL адрес</string>
+  <string name="auth_ssl_general_error_title">Неуспешна инициализация на SSL.</string>
+  <string name="auth_ssl_unverified_server_title">Неуспешна проверка на SSL самоличността на сървъра.</string>
+  <string name="auth_bad_oc_version_title">Неизвестна версия на сървъра.</string>
+  <string name="auth_wrong_connection_title">Неуспешно осъществяване на връзка</string>
+  <string name="auth_secure_connection">Осъществена сигурна връзка.</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">Неочаквано състояние; въведете 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="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_remote">Премахни от сървъра</string>
-  <string name="rename_server_fail_msg">Преименуването не може да се осъществи</string>
+  <string name="confirmation_remove_folder_local">Само локалното съдържание</string>
+  <string name="confirmation_remove_remote">Премахване от сървъра</string>
+  <string name="confirmation_remove_remote_and_local">Отдалечено и локално</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_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_unexpected_bad_get_content">Неочакван проблем; моля, изберете файла от друга програма.</string>
   <string name="filedisplay_no_file_selected">Не е избран файл</string>
-  <string name="ssl_validator_header">Самоличността на сайта не може да бъде проверена</string>
+  <string name="activity_chooser_title">Изпращане на връзката до...</string>
+  <string name="oauth_check_onoff">Вписване с oAuth2</string>
+  <string name="oauth_login_connection">Свързване с оАутх2 сървър...</string>
+  <string name="ssl_validator_header">Самоличността на сайта не може да бъде проверена.</string>
+  <string name="ssl_validator_reason_cert_not_trusted">- Сертификатът на сървъра не е надежден.</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">- URL адресът не съвпада с този сертификата.</string>
+  <string name="ssl_validator_question">Въпреки всичко, искате ли да се доверите на сертификата?</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">Издаден от:</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">Държава:</string>
+  <string name="ssl_validator_label_ST">Област:</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">placeholder.txt</string>
+  <string name="placeholder_filetype">PNG Image</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_video_upload_on_wifi">Качване на видео само през WiFi</string>
+  <string name="instant_upload_path">/InstantUpload</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="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="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="actionbar_logger">Доклади</string>
+  <string name="log_send_history_button">Изпрати История</string>
+  <string name="log_mail_subject">ownCloud 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="file_list_empty_moving">Тук няма нищо. Можеш да добавиш папка!</string>
+  <string name="move_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_security">Сигурност</string>
 </resources>
index a9080e6..cae19b7 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_mkdir">ডিরেক্টরি তৈরী কর</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="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">অ্যাপ PIN</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="auth_host_url">সার্ভার ঠিকানা</string>
+  <string name="prefs_recommend">বন্ধুর কাছে সুপারিশ করুন</string>
+  <string name="prefs_feedback">মতামত</string>
+  <string name="prefs_imprint">প্রতিচ্ছাপ</string>
+  <string name="recommend_subject">আপনার স্মার্টফোনে %1$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="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">বন্ধ</string>
+  <string name="uploader_wrn_no_content_title">আপলোডের কনটেনট নেই</string>
+  <string name="uploader_wrn_no_content_text">কোন কনটেনট আসেনি৷ আপলোডের কনটেনট নেই</string>
+  <string name="uploader_error_forbidden_content">এই যৌথ কনটেন্ট এ %1$s এর প্রবেশ অনুমোদিত নয়</string>
   <string name="uploader_info_uploading">আপলোড করা হচ্ছে</string>
+  <string name="file_list_empty">এখানে কিছুই নেই। কিছু আপলোড করুন !</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_download">ডাউনলোড</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">আপলোড বাতিল কর</string>
   <string name="common_cancel">বাতিল</string>
   <string name="common_save_exit">সংরক্ষণ কর এবং &amp;প্রস্থান</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="uploader_info_dirname">ডিরেক্টরির নাম</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_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_not_downloaded_yet">এখনো ডাউনলোড শেষ হয়নি</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_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_conflicts_in_favourites_content">সমন্বয় করার জন্য রাখা %1$d ফাইলগুলো সমন্বয় করা যায়নি</string>
+  <string name="sync_fail_in_favourites_ticker">সমন্বয় করার জন্য ফাইল রাখা ব্যার্থ হয়েছে</string>
+  <string name="sync_fail_in_favourites_content">%1$d ফাইলসমূহের কনটেন্ট সিনক্রোনাইজ করা যায়নি (%2$d সংঘর্ষ)</string>
+  <string name="sync_foreign_files_forgotten_ticker">কিছু লোকাল ফাইল নেয়া হয়নি</string>
+  <string name="sync_foreign_files_forgotten_content">%2$s ফোল্ডারের %1$d ফাইলগুলি কপি করা যায়নি</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">দয়া করে আপনার App PIN দিন</string>
+  <string name="pincode_configure_your_pin">আপনার App PIN দিন</string>
+  <string name="pincode_configure_your_pin_explanation">প্রতিবার অ্যাপ চালু করার সময় PIN এর জন্য অনুরোধ করা হবে</string>
+  <string name="pincode_reenter_your_pincode">দয়া করে আবার App PIN দিন</string>
+  <string name="pincode_remove_your_pincode">আপনার অ্যাপ PIN সরিয়ে নিন</string>
+  <string name="pincode_mismatch">অ্যাপ PINগুলো একরকম নয়</string>
+  <string name="pincode_wrong">অশুদ্ধ অ্যাপ PIN</string>
+  <string name="pincode_removed">অ্যাপ PIN সরানো হয়েছে</string>
+  <string name="pincode_stored">অ্যাপ PIN সংরক্ষণ করা হয়েছে</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">মিডিয়া ফাইল সঠিকভাবে encoded নয়</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_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">ভুল গঠনের URL</string>
+  <string name="auth_ssl_general_error_title">SSL initialization ব্যার্থ</string>
+  <string name="auth_ssl_unverified_server_title">SSL server এর পরিচয় সুনিশ্চিত করা গেলনা</string>
+  <string name="auth_bad_oc_version_title">অজানা সার্ভার সংষ্করণ</string>
+  <string name="auth_wrong_connection_title">যোগাযোগ স্থাপন করা গেলনা</string>
+  <string name="auth_secure_connection">নিরাপদ যোগাযোগ স্থাপিত হয়েছে</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">অনাকাংখিত অবস্থা; পূণরায় সার্ভার 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="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="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_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_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">- সার্ভার প্রত্যয়নপত্রটি বিশ্বাসযোগ্য নয়</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">- প্রত্যয়নপত্রটিতে উল্লেখিত হোস্টনেমের সঙ্গে URL মেলেনা </string>
+  <string name="ssl_validator_question">আপনি কি তবুও প্রত্যয়নপত্রটিকে বিশ্বাস করতে চান?</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">প্রদান করলেন:</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">দেশ:</string>
+  <string name="ssl_validator_label_ST">প্রদেশ:</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">placeholder.txt</string>
+  <string name="placeholder_filetype">PNG ছবি</string>
+  <string name="placeholder_filesize">৩৮৯ কেবি</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">শুধুমাত্র ওয়াইফাই দিয়ে ছবি আপলোড করুন</string>
+  <string name="instant_video_upload_on_wifi">শুধুমাত্র ওয়াইফাই দিয়ে ভিডিও আপলোড করুন</string>
+  <string name="instant_upload_path">/তাৎক্ষণিক আপলোড</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="share_link_no_support_share_api">দুঃখিত, আপনার সার্ভার ভাগাভাগি উপযোগী নয়। দয়া করে আপনার
+⇥⇥প্রশাসকের সঙ্গে যোগাযোগ করুন।</string>
+  <string name="share_link_file_error">এই ফাইল অথবা ফোল্ডার ভাগাভাগির চেষ্টা করতে যেয়ে একটি জটিলতা হয়েছে</string>
+  <string name="unshare_link_file_error">এই ফাইল অথবা ফোল্ডার ভাগাভাগি রদ করার চেষ্টা করতে যেয়ে একটি জটিলতা হয়েছে</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="saml_authentication_wrong_pass">ভুল কুটশব্দ</string>
+  <string name="actionbar_move">সরাও</string>
+  <string name="file_list_empty_moving">এখানে কিছু নেই। একটি ফোল্ডার যোগ করতে পারেন!</string>
+  <string name="move_choose_button_text">বেছে নিন</string>
+  <string name="move_file_not_found">সরাতে ব্যার্থ হলো। ফাইলটি রয়েছে কিনা দেখুন।</string>
+  <string name="prefs_category_security">নিরাপত্তা</string>
 </resources>
diff --git a/res/values-bn-rIN/strings.xml b/res/values-bn-rIN/strings.xml
new file mode 100644 (file)
index 0000000..a49555a
--- /dev/null
@@ -0,0 +1,19 @@
+<?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_upload_files">ফাইলস</string>
+  <string name="actionbar_mkdir">নতুন ফোল্ডার</string>
+  <string name="actionbar_settings">সেটিংস</string>
+  <string name="prefs_imprint">অঙ্কিত করা</string>
+  <string name="auth_username">ইউজারনেম</string>
+  <string name="sync_string_files">ফাইলস</string>
+  <string name="file_list_loading">লোড করা হচ্ছে...</string>
+  <string name="filedetails_download">ডাউনলোড করুন</string>
+  <string name="common_cancel">বাতিল করা</string>
+  <string name="common_error">ভুল</string>
+  <string name="uploader_info_dirname">ফোল্ডারের নাম</string>
+  <string name="common_rename">পুনঃনামকরণ</string>
+  <string name="common_remove">সরান</string>
+  <string name="empty"></string>
+</resources>
index c757504..30f5ce2 100644 (file)
@@ -1,2 +1,5 @@
 <?xml version='1.0' encoding='UTF-8'?>
-<resources/>
+<resources>
+  <string name="actionbar_mkdir">Nova fascikla</string>
+  <string name="empty"></string>
+</resources>
index ebfd598..d0b98a1 100644 (file)
@@ -7,17 +7,20 @@
   <string name="actionbar_upload_from_apps">Contingut d\'altres aplicacions</string>
   <string name="actionbar_upload_files">Fitxers</string>
   <string name="actionbar_open_with">Obre amb</string>
-  <string name="actionbar_mkdir">Crea una carpeta</string>
+  <string name="actionbar_mkdir">Carpeta nova</string>
   <string name="actionbar_settings">Configuració</string>
   <string name="actionbar_see_details">Detalls</string>
+  <string name="actionbar_send_file">Envia</string>
   <string name="prefs_category_general">General</string>
   <string name="prefs_category_more">Més</string>
   <string name="prefs_accounts">Comptes</string>
   <string name="prefs_manage_accounts">Gestió de comptes</string>
   <string name="prefs_pincode">PIN de l\'aplicació</string>
   <string name="prefs_pincode_summary">Protegiu el client</string>
-  <string name="prefs_instant_upload">Activa la pujada instantània</string>
+  <string name="prefs_instant_upload">Pujada instantànies de fotografies</string>
   <string name="prefs_instant_upload_summary">Puja instantàniament les fotografies preses amb la càmera</string>
+  <string name="prefs_instant_video_upload">Pujades de vídeos instantanies</string>
+  <string name="prefs_instant_video_upload_summary">Pujar instantàniament vídeos gravats per la càmera</string>
   <string name="prefs_log_title">Habilita el registre</string>
   <string name="prefs_log_summary">Això s\'usa per registrar problemes</string>
   <string name="prefs_log_title_history">Història del registre</string>
@@ -28,9 +31,8 @@
   <string name="prefs_feedback">Comentaris</string>
   <string name="prefs_imprint">Imprint</string>
   <string name="recommend_subject">Proveu %1$s a un telèfon avançat!</string>
-  <string name="recommend_text">Vull convidar-te a usar l\'aplicació %1$s al teu telèfon avançat!\nBaixa\'l aquí: %2$s</string>
   <string name="auth_check_server">Comprova el servidor</string>
-  <string name="auth_host_url">Adreça del servidor</string>
+  <string name="auth_host_url">Adreça del servidor https://…</string>
   <string name="auth_username">Nom d\'usuari</string>
   <string name="auth_password">Contrasenya</string>
   <string name="auth_register">Nou a %1$s?</string>
@@ -46,7 +48,9 @@
   <string name="uploader_wrn_no_content_text">No s\'ha rebut cap contingut. Res per pujar</string>
   <string name="uploader_error_forbidden_content">%1$s no pot accedir al contingut compartit</string>
   <string name="uploader_info_uploading">S\'està pujant</string>
-  <string name="file_list_empty">No hi ha fitxers en aquesta carpeta.\nPodeu afegir fitxers a través de l\'opció \"Puja\"  del menú.</string>
+  <string name="file_list_empty">Res per aquí. Pugeu alguna cosa!</string>
+  <string name="file_list_loading">Carregant...</string>
+  <string name="local_file_list_empty">No hi ha arxius a aquesta carpeta</string>
   <string name="filedetails_select_file">Feu clic en un fitxer per mostrar informació addicional.</string>
   <string name="filedetails_size">Mida:</string>
   <string name="filedetails_type">Tipus:</string>
@@ -55,6 +59,8 @@
   <string name="filedetails_download">Baixa</string>
   <string name="filedetails_sync_file">Actualitza el fitxer</string>
   <string name="filedetails_renamed_in_upload_msg">L\'arxiu s\'ha canviat de nom a %1$s durant la càrrega</string>
+  <string name="action_share_file">Enllaç de compartició</string>
+  <string name="action_unshare_file">Deixa de compartir l\'enllaç</string>
   <string name="common_yes">Sí</string>
   <string name="common_no">No</string>
   <string name="common_ok">D\'acord</string>
@@ -77,6 +83,7 @@
   <string name="uploader_upload_succeeded_content_single">%1$s s\'ha pujat correctament</string>
   <string name="uploader_upload_failed_ticker">La pujada ha fallat</string>
   <string name="uploader_upload_failed_content_single">La pujada de %1$s no s\'ha pogut acabar</string>
+  <string name="uploader_upload_failed_credentials_error">La pujada ha fallat, t\'has de tornar a acreditar</string>
   <string name="downloader_download_in_progress_ticker">S\'està baixant ...</string>
   <string name="downloader_download_in_progress_content">%1$d%% pujant %2$s</string>
   <string name="downloader_download_succeeded_ticker">La baixada ha estat correcte</string>
   <string name="downloader_download_failed_ticker">La baixada ha fallat</string>
   <string name="downloader_download_failed_content">La baixada de %1$s no s\'ha pogut acabar</string>
   <string name="downloader_not_downloaded_yet">No baixat encara</string>
+  <string name="downloader_download_failed_credentials_error">La descàrrega ha fallat, t\'has de tornar a acreditar</string>
   <string name="common_choose_account">Escolliu el compte</string>
   <string name="sync_fail_ticker">La sincronització ha fallat</string>
+  <string name="sync_fail_ticker_unauthorized">La sincronització ha fallat, us heu d\'acreditar de nou</string>
   <string name="sync_fail_content">La sincronització de %1$s no s\'ha pogut acabar</string>
   <string name="sync_fail_content_unauthorized">Contrasenya no vàlida per %1$s</string>
   <string name="sync_conflicts_in_favourites_ticker">S\'han trobat conflictes</string>
   <string name="sync_fail_in_favourites_content">El contingut de %1$d arxius no es va poder sincronitzar (%2$d conflictes)</string>
   <string name="sync_foreign_files_forgotten_ticker">S\'han oblidat alguns fitxers locals</string>
   <string name="sync_foreign_files_forgotten_content">%1$d fitxers no s\'han pogut copiar dins de %2$s carpetes</string>
-  <string name="sync_foreign_files_forgotten_explanation">Des de la versió 1.3.16, els fitxers pujats des d\'aquest dispositiu es copien a la carpeta local %1$s per prevenir pèrdues de dades quan es sincronitza un únic fitxer amb diversos comptes.\n\nDegut a aquest canvi, tots els fitxers pujats en versions anteriors d\'aquesta aplicació es copiaven a la carpeta %2$s. Malgrat tot, un error impedia aquesta operació durant la sinconització del compte. Podeu deixar els fitxer(s) tal i com estan i eliminar l\'enllaç a %3$2, o moure els fitxer(s) a la carpeta %1$s i retenir l\'enllaç a %4$s.\n\nA baix hi ha els fitxers local(s) i els fitxer(s) remots a %5$s als que estaven enllaçats.</string>
   <string name="sync_current_folder_was_removed">La carpeta %1$s ja no existeix</string>
   <string name="foreign_files_move">Mou-los tots</string>
   <string name="foreign_files_success">S\'han mogut tots els fitxers</string>
   <string name="media_rewind_description">Botó de rebobinat</string>
   <string name="media_play_pause_description">Botó de reproducció o pausa</string>
   <string name="media_forward_description">Botó de reproducció ràpida</string>
+  <string name="auth_getting_authorization">S\'està autenticant...</string>
   <string name="auth_trying_to_login">S\'està intentant acreditar-vos...</string>
   <string name="auth_no_net_conn_title">Sense connexió de xarxa</string>
   <string name="auth_nossl_plain_ok_title">La connexió segura no està disponible.</string>
   <string name="auth_connecting_auth_server">S\'està connectant a un servidor d\'autenticació...</string>
   <string name="auth_unsupported_auth_method">El serivdor no permet aquest mètode d\'autenticació</string>
   <string name="auth_unsupported_multiaccount">%1$s no permet comptes múltiples</string>
+  <string name="auth_fail_get_user_name">El servidor no retorna una id d\'usuari correcta, contacteu amb l\'administrador.</string>
+  <string name="auth_can_not_auth_against_server">No es pot autenticar en aquest servidor</string>
   <string name="fd_keep_in_sync">Mantén el fitxer actualitzat</string>
   <string name="common_rename">Reanomena</string>
   <string name="common_remove">Elimina</string>
   <string name="sync_file_fail_msg">L\'arxiu remot no ha pogut ser comprovat</string>
   <string name="sync_file_nothing_to_do_msg">Contingut de l\'arxiu ja sincronitzat</string>
   <string name="create_dir_fail_msg">La carpeta no s\'ha pogut crear</string>
+  <string name="filename_forbidden_characters">Caràcters no permesos: / \\ &lt; &gt; : \" | ? *</string>
+  <string name="filename_empty">El Nom de l\'arxiu no pot estar buit</string>
   <string name="wait_a_moment">Espereu</string>
   <string name="filedisplay_unexpected_bad_get_content">S\'ha produït un problema inesperat; proveu una altra aplicació per seleccionar el fitxer</string>
   <string name="filedisplay_no_file_selected">No heu seleccionat cap fitxer</string>
+  <string name="activity_chooser_title">Envia l\'enllaç a...</string>
   <string name="oauth_check_onoff">Accés amb oAuth2</string>
   <string name="oauth_login_connection">Connectant amb el servidor oAuth2...</string>
   <string name="ssl_validator_header">No s\'ha pogut verificar la identitat del lloc web</string>
   <string name="ssl_validator_label_validity_to">A:</string>
   <string name="ssl_validator_label_signature">Signatura:</string>
   <string name="ssl_validator_label_signature_algorithm">Algoritme:</string>
+  <string name="ssl_validator_null_cert">No s\'ha pogut mostrar el certificat.</string>
+  <string name="ssl_validator_no_info_about_error">- No hi ha informació de l\'error</string>
   <string name="placeholder_sentence">Això és un text variable</string>
   <string name="placeholder_filename">placeholder.txt</string>
   <string name="placeholder_filetype">Imatge PNG</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">Puja les fotos només via WiFi</string>
+  <string name="instant_video_upload_on_wifi">Puja les fotos només via WiFi</string>
   <string name="instant_upload_path">/CarregaInstantània</string>
   <string name="conflict_title">Conflicte d\'actualització</string>
   <string name="conflict_message">El fitxer remot %s no està sincronitzat amb el fitxer local. Si continueu es substituirà el contingut del fitxer en el servidor.</string>
   <string name="conflict_overwrite">Sobrescriu</string>
   <string name="conflict_dont_upload">No el pugis</string>
   <string name="preview_image_description">Visualització prèvia d\'imatge</string>
-  <string name="preview_image_error_unknown_format">Auquesta imatge no es pot mostrar</string>
+  <string name="preview_image_error_unknown_format">Aquesta imatge no es pot mostrar</string>
   <string name="error__upload__local_file_not_copied">%1$s no s\'ha pogut copiar a la carpeta local %2$s</string>
-  <string name="actionbar_failed_instant_upload">ha fallat la pujada instantània\"</string>
-  <string name="failed_upload_headline_text">Fallada de pujades instantànies</string>
-  <string name="failed_upload_headline_hint">Resum de totes les pujades instantànies que han fallat</string>
-  <string name="failed_upload_all_cb">selecciona-ho tot</string>
-  <string name="failed_upload_headline_retryall_btn">reintenta els seleccionats</string>
-  <string name="failed_upload_headline_delete_all_btn">elimina tots els seleccionats de la cua de pujada</string>
-  <string name="failed_upload_retry_text">intenta pujar de nou la imatge:</string>
-  <string name="failed_upload_load_more_images">Carrega més imatges</string>
-  <string name="failed_upload_retry_do_nothing_text">no facis res, no estàs en lína per la pujada instantània</string>
-  <string name="failed_upload_failure_text">Missatge d\'Error:</string>
-  <string name="failed_upload_quota_exceeded_text">Comproveu la configuració del servidor, potser heu excedit la quota.</string>
+  <string name="share_link_no_support_share_api">La compartició no es troba disponible al vostre servidor. Contacteu amb l\'administrador.</string>
+  <string name="share_link_file_error">S\'ha produït un error en intentar compartir aquest fitxer o carpeta</string>
+  <string name="unshare_link_file_error">S\'ha produït un error en intentar deixar de compartir aquest fitxer o carpeta</string>
+  <string name="activity_chooser_send_file_title">Envia</string>
+  <string name="copy_link">Copia l\'enllaç</string>
+  <string name="clipboard_text_copied">S\'ha copiat al porta-retalls</string>
+  <string name="error_cant_bind_to_operations_service">Error crític: no es poden realitzar operacions</string>
+  <string name="network_error_socket_exception">Hi ha hagut un error mentre es connectava al servidor.</string>
+  <string name="network_error_socket_timeout_exception">Hi ha hagut un error esperant al servidor, l\'operació no s\'ha pogut realitzar</string>
+  <string name="network_error_connect_timeout_exception">Hi ha hagut un error esperant el servidor, l\'operació no s\'ha pogut realitzar</string>
+  <string name="network_host_not_available">La operació no s\'ha pogut completar, no es pot accedir al servidor</string>
+  <string name="empty"></string>
+  <string name="forbidden_permissions">No teniu permisos %s</string>
+  <string name="forbidden_permissions_rename">per canviar el nom d\'aquest fitxer</string>
+  <string name="forbidden_permissions_delete">per eliminar aquest fitxer</string>
+  <string name="share_link_forbidden_permissions">per compartir aquest fitxer</string>
+  <string name="unshare_link_forbidden_permissions">per deixar de compartir aquest fitxer</string>
+  <string name="forbidden_permissions_create">per crear el fitxer</string>
+  <string name="uploader_upload_forbidden_permissions">per pujar fitxers en aquesta carpeta</string>
+  <string name="downloader_download_file_not_found">El fitxer ja no està disponible en el servidor</string>
+  <string name="prefs_category_accounts">Comptes</string>
+  <string name="prefs_add_account">Afegeix compte</string>
+  <string name="saml_authentication_required_text">Es requereix autenticació</string>
+  <string name="saml_authentication_wrong_pass">Contrasenya incorrecta</string>
+  <string name="move_choose_button_text">Escull</string>
+  <string name="prefs_category_security">Seguretat</string>
 </resources>
index c77a1ad..6b8b96c 100644 (file)
@@ -7,34 +7,40 @@
   <string name="actionbar_upload_from_apps">Obsah z ostatních aplikací</string>
   <string name="actionbar_upload_files">Soubory</string>
   <string name="actionbar_open_with">Otevřít pomocí</string>
-  <string name="actionbar_mkdir">Vytvořit adresář</string>
+  <string name="actionbar_mkdir">Nová složka</string>
   <string name="actionbar_settings">Nastavení</string>
   <string name="actionbar_see_details">Podrobnosti</string>
+  <string name="actionbar_send_file">Odeslat</string>
   <string name="prefs_category_general">Obecné</string>
   <string name="prefs_category_more">Více</string>
   <string name="prefs_accounts">Účty</string>
   <string name="prefs_manage_accounts">Spravovat účty</string>
-  <string name="prefs_pincode">PIN aplikace</string>
+  <string name="prefs_pincode">PIN do aplikace</string>
   <string name="prefs_pincode_summary">Chraňte svého klienta</string>
-  <string name="prefs_instant_upload">Povolit okamžité odeslání</string>
-  <string name="prefs_instant_upload_summary">Okamžitě odesílat vytvořené fotografie</string>
+  <string name="prefs_instant_upload">Okamžité nahrávání obrázků</string>
+  <string name="prefs_instant_upload_summary">Okamžitě nahrávat vytvořené fotografie</string>
+  <string name="prefs_instant_video_upload">Okamžité nahrávání videa</string>
+  <string name="prefs_instant_video_upload_summary">Okamžitě odesílat nahrané video</string>
   <string name="prefs_log_title">Povolit logování</string>
   <string name="prefs_log_summary">Použito k zaznamenávání problémů</string>
   <string name="prefs_log_title_history">Historie logování</string>
   <string name="prefs_log_summary_history">Zobrazuje zaznamenané logy</string>
   <string name="prefs_log_delete_history_button">Smazat historii</string>
   <string name="prefs_help">Nápověda</string>
+  <string name="prefs_recommend">Doporučit přátelům</string>
   <string name="prefs_feedback">Odezva</string>
   <string name="prefs_imprint">Imprint</string>
+  <string name="recommend_subject">Zkuste %1$s na vašem smartphonu!</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</string>
+  <string name="auth_host_url">Adresa serveru https://...</string>
   <string name="auth_username">Uživatelské jméno</string>
   <string name="auth_password">Heslo</string>
   <string name="auth_register">Nováček s %1$s?</string>
   <string name="sync_string_files">Soubory</string>
   <string name="setup_btn_connect">Připojit</string>
   <string name="uploader_btn_upload_text">Odeslat</string>
-  <string name="uploader_top_message">Vyberte adresář pro nahrané soubory:</string>
+  <string name="uploader_top_message">Vyberte adresář pro nahrání:</string>
   <string name="uploader_wrn_no_account_title">Nenalezen žádný účet</string>
   <string name="uploader_wrn_no_account_text">Nemáte žádné %1$s účty. Vytvořte si, prosím, nejdříve účet.</string>
   <string name="uploader_wrn_no_account_setup_btn_text">Nastavení</string>
@@ -43,7 +49,9 @@
   <string name="uploader_wrn_no_content_text">Neobdržen žádný obsah. Nic k odeslání.</string>
   <string name="uploader_error_forbidden_content">%1$s nemá právo přistupovat ke sdílenému obsahu</string>
   <string name="uploader_info_uploading">Odesílání</string>
-  <string name="file_list_empty">Ve složce nejsou žádné soubory.\nNové soubory mohou být přidány pomocí volby \"Odeslat\".</string>
+  <string name="file_list_empty">Žádný obsah. Nahrajte něco!</string>
+  <string name="file_list_loading">Načítám...</string>
+  <string name="local_file_list_empty">V tomto adresáři nejsou žádné soubory.</string>
   <string name="filedetails_select_file">Více informací získáte klepnutím na soubor.</string>
   <string name="filedetails_size">Velikost:</string>
   <string name="filedetails_type">Typ:</string>
@@ -52,6 +60,8 @@
   <string name="filedetails_download">Stáhnout</string>
   <string name="filedetails_sync_file">Obnovit soubor</string>
   <string name="filedetails_renamed_in_upload_msg">Soubor byl v průběhu odesílání přejmenován na %1$s</string>
+  <string name="action_share_file">Sdílet odkaz</string>
+  <string name="action_unshare_file">Zrušit sdílení odkazu</string>
   <string name="common_yes">Ano</string>
   <string name="common_no">Ne</string>
   <string name="common_ok">OK</string>
   <string name="delete_account">Smazat účet</string>
   <string name="create_account">Vytvořit účet</string>
   <string name="upload_chooser_title">Odeslat z ...</string>
-  <string name="uploader_info_dirname">Název adresáře</string>
+  <string name="uploader_info_dirname">Název složky</string>
   <string name="uploader_upload_in_progress_ticker">Odesílám...</string>
   <string name="uploader_upload_in_progress_content">%1$d%% Odesílám %2$s</string>
   <string name="uploader_upload_succeeded_ticker">Odesílání úspěšné</string>
   <string name="uploader_upload_succeeded_content_single">%1$s byl úspěšně odeslán</string>
   <string name="uploader_upload_failed_ticker">Odesílání selhalo</string>
   <string name="uploader_upload_failed_content_single">Odesílání %1$s nemohlo být dokončeno</string>
+  <string name="uploader_upload_failed_credentials_error">Nahrávání selhalo. Je třeba se znovu přihlásit.</string>
   <string name="downloader_download_in_progress_ticker">Stahuji ...</string>
   <string name="downloader_download_in_progress_content">%1$d%% Stahuji %2$s</string>
   <string name="downloader_download_succeeded_ticker">Stažení úspěšné</string>
   <string name="downloader_download_failed_ticker">Stažení selhalo</string>
   <string name="downloader_download_failed_content">Stažení %1$s nemohlo být dokončeno</string>
   <string name="downloader_not_downloaded_yet">Ještě nestaženo</string>
+  <string name="downloader_download_failed_credentials_error">Stahování selhalo. Je třeba se znovu přihlásit.</string>
   <string name="common_choose_account">Vybrat účet</string>
   <string name="sync_fail_ticker">Synchronizace selhala</string>
+  <string name="sync_fail_ticker_unauthorized">Synchronizace selhala. Je třeba se znovu přihlásit.</string>
   <string name="sync_fail_content">Synchronizaci %1$s nelze dokončit</string>
   <string name="sync_fail_content_unauthorized">Chybné heslo pro %1$s</string>
   <string name="sync_conflicts_in_favourites_ticker">Nalezeny konflikty</string>
   <string name="sync_fail_in_favourites_ticker">Automatická synchronizace souborů selhala</string>
   <string name="sync_fail_in_favourites_content">Obsah %1$d souborů nemohl být synchronizován (počet konfliktů: %2$d)</string>
   <string name="sync_foreign_files_forgotten_ticker">Některé místní soubory byly zapomenuty</string>
-  <string name="sync_foreign_files_forgotten_content">%1$d souborů z adresáře %2$s nelze zkopírovat do</string>
-  <string name="sync_foreign_files_forgotten_explanation">Od verze 1.3.16 jsou soubory odeslané z tohoto zařízení, pro ochranu proti ztrátě dat při synchronizaci z více účtů, nahrány do místní složky %1$s.\n\nVšechny soubory odeslané předchozími verzemi byly kvůli této změně přesunuty do složky %2$s. Bohužel chyba zabránila dokončení této operace při synchronizaci účtu. Můžete nyní ponechat soubory ve stávajícím stavu a smazat odkaz na %3$s nebo přesunout soubory do adresáře %1$s a zachovat odkazy na %4$s.\n\nNásleduje seznam místních souborů a jejich odkazů na vzdálené soubory v %5$s.</string>
+  <string name="sync_foreign_files_forgotten_content">%1$d souborů z %2$s složek se nepodařilo zkopírovat do</string>
+  <string name="sync_foreign_files_forgotten_explanation">Od verze 1.3.16 jsou soubory nahrané z tohoto zařízení kopírovány do místní složky %1$s, aby se zabránilo ztrátě dat při synchronizaci jednoho souboru s více účty.\n\nVšechny soubory nahrané předchozími verzemi aplikace byly z tohoto důvodu překopírovány do složky %2$s. Bohužel se objevila chyba zabraňující dokončení této operace v průběhu synchronizace účtu. Buď můžete soubor(y) ponechat jak jsou a odebrat odkaz do složky %3$s, nebo přesunout soubor(y) do složky %1$s a zachovat odkaz na %4$s.\n\nNíže je seznam místních i vzdálených souborů ve složce %5$s, do které byly odkázány.</string>
+  <string name="sync_current_folder_was_removed">Složka %1$s již neexistuje</string>
   <string name="foreign_files_move">Přesunout vše</string>
   <string name="foreign_files_success">Všechny soubory byly přesunuty</string>
   <string name="foreign_files_fail">Některé soubory nebylo možno přesunout</string>
   <string name="foreign_files_local_text">Místní: %1$s</string>
   <string name="foreign_files_remote_text">Vzdálené: %1$s</string>
-  <string name="upload_query_move_foreign_files">Nedostatek místa pro zkopírování vybraných souborů do složky %1$s. Přejete si je místo kopírování přesunout?</string>
+  <string name="upload_query_move_foreign_files">Není dostatek místa pro zkopírování vybraných souborů do adresáře %1$s. Přejete si je místo kopírování přesunout?</string>
   <string name="pincode_enter_pin_code">Zadejte PIN aplikace</string>
   <string name="pincode_configure_your_pin">Zadat PIN aplikace</string>
   <string name="pincode_configure_your_pin_explanation">Při každém spuštění aplikace bude vyžadováno zadání PIN</string>
   <string name="media_err_unsupported">Nepodporovaný kodek</string>
   <string name="media_err_io">Multimediální soubor nelze přečíst</string>
   <string name="media_err_malformed">Multimediální soubor není správně kódován</string>
+  <string name="media_err_timeout">Vypršel čas při pokusu o přehrání</string>
   <string name="media_err_invalid_progressive_playback">Multimediální soubor nelze proudově odesílat</string>
   <string name="media_err_unknown">Multimediální soubor nemůže být přehrán s výchozím přehrávačem</string>
   <string name="media_err_security_ex">Chyba zabezpečení při pokusu o přehrání %1$s</string>
   <string name="media_rewind_description">Tlačítko Přetočit</string>
   <string name="media_play_pause_description">Tlačítko Přehrát/Pozastavit</string>
   <string name="media_forward_description">Tlačítko Rychle vpřed</string>
+  <string name="auth_getting_authorization">Kontroluji pověření...</string>
   <string name="auth_trying_to_login">Zkouším se přihlásit...</string>
   <string name="auth_no_net_conn_title">Žádné síťové spojení</string>
   <string name="auth_nossl_plain_ok_title">Zabezpečené spojení není k dispozici</string>
   <string name="auth_connection_established">Spojení navázáno</string>
   <string name="auth_testing_connection">Zkouším spojení...</string>
   <string name="auth_not_configured_title">Neplatné nastavení serveru</string>
+  <string name="auth_account_not_new">Účet pro stejného uživatele a server již v zařízení existuje</string>
+  <string name="auth_account_not_the_same">Zadaný uživatel neodpovídá uživateli tohoto účtu</string>
   <string name="auth_unknown_error_title">Nastala neznámá chyba</string>
   <string name="auth_unknown_host_title">Nelze najít hostitele</string>
   <string name="auth_incorrect_path_title">Instance serveru nenalezena</string>
   <string name="auth_timeout_title">Serveru trvalo příliš dlouho odpovědět</string>
   <string name="auth_incorrect_address_title">Neplatné URL</string>
   <string name="auth_ssl_general_error_title">Inicializace SSL selhala</string>
+  <string name="auth_ssl_unverified_server_title">Nemohu ověřit SSL identitu serveru</string>
   <string name="auth_bad_oc_version_title">Nerozpoznaná verze serveru</string>
   <string name="auth_wrong_connection_title">Nemohu navázat spojení</string>
   <string name="auth_secure_connection">Zabezpečené spojení navázáno</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_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_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 vašeho administrátora</string>
+  <string name="auth_can_not_auth_against_server">Není možné provést ověření  </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>
-  <string name="confirmation_remove_alert">Opravdu si přejete odstranit %1$s ?</string>
-  <string name="confirmation_remove_folder_alert">Opravdu si přejete odstranit %1$s a jeho obsah?</string>
+  <string name="confirmation_remove_alert">Opravdu chcete odstranit %1$s ?</string>
+  <string name="confirmation_remove_folder_alert">Opravdu chcete odstranit %1$s a jeho obsah?</string>
   <string name="confirmation_remove_local">Pouze místní</string>
   <string name="confirmation_remove_folder_local">Pouze místní obsah</string>
   <string name="confirmation_remove_remote">Odstranit ze serveru</string>
   <string name="rename_server_fail_msg">Přejmenování nelze dokončit</string>
   <string name="sync_file_fail_msg">Vzdálený soubor nemohl být zkontrolován</string>
   <string name="sync_file_nothing_to_do_msg">Obsah souboru je již synchronizován</string>
-  <string name="create_dir_fail_msg">Adresář nelze vytvořit</string>
+  <string name="create_dir_fail_msg">Adresář nemohl být vytvořen</string>
+  <string name="filename_forbidden_characters">Zakázané znaky: / \\ &lt; &gt; : \" | ? *</string>
+  <string name="filename_empty">Název nemůže být prázdný</string>
   <string name="wait_a_moment">Počkejte chvíli</string>
   <string name="filedisplay_unexpected_bad_get_content">Neočekávaný problém - zkuste zvolit soubor jinou aplikací</string>
   <string name="filedisplay_no_file_selected">Žádný soubor nebyl vybrán</string>
+  <string name="activity_chooser_title">Odeslat odkaz ...</string>
+  <string name="oauth_check_onoff">Přihlásit se s oAuth2</string>
   <string name="oauth_login_connection">Připojuji se k oAuth2 serveru...</string>
   <string name="ssl_validator_header">Identitu stránky nelze ověřit</string>
   <string name="ssl_validator_reason_cert_not_trusted">- Certifikát serveru je nedůvěryhodný</string>
   <string name="ssl_validator_label_validity_to">Pro:</string>
   <string name="ssl_validator_label_signature">Podpis:</string>
   <string name="ssl_validator_label_signature_algorithm">Alogritmus:</string>
+  <string name="ssl_validator_null_cert">Certifikát nemohl být zobrazen.</string>
+  <string name="ssl_validator_no_info_about_error">- Žádné informace o této chybě</string>
   <string name="placeholder_sentence">Zástupný text</string>
   <string name="placeholder_filename">placeholder.txt</string>
   <string name="placeholder_filetype">Obrázek PNG</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">Odesílat obrázky pouze skrze WiFi</string>
+  <string name="instant_upload_on_wifi">Odesílat obrázky pouze přes WiFi</string>
+  <string name="instant_video_upload_on_wifi">Nahrávat videa pouze přes WiFi</string>
   <string name="instant_upload_path">/InstantUpload</string>
   <string name="conflict_title">Konflikt při aktualizaci</string>
   <string name="conflict_message">Vzdálený soubor %s není synchronizován s místním souborem. Pokračování přepíše obsah souboru na serveru.</string>
   <string name="conflict_overwrite">Přepsat</string>
   <string name="conflict_dont_upload">Nenahrávat</string>
   <string name="preview_image_description">Náhled obrázku</string>
-  <string name="preview_image_error_unknown_format">Obrázek nemůže být zobrazen</string>
+  <string name="preview_image_error_unknown_format">Obrázek nelze zobrazit</string>
   <string name="error__upload__local_file_not_copied">%1$s nelze zkopírovat do místního adresáře %2$s</string>
-  <string name="actionbar_failed_instant_upload">Selhalo Okamžité odeslání\"</string>
-  <string name="failed_upload_headline_text">Selhaná okamžitá odeslání</string>
-  <string name="failed_upload_headline_hint">Souhrn všech selhaných okamžitých odeslání</string>
-  <string name="failed_upload_all_cb">vybrat vše</string>
-  <string name="failed_upload_headline_retryall_btn">zkusit znovu vybrané</string>
-  <string name="failed_upload_headline_delete_all_btn">smazat vybrané z fronty k nahrání</string>
-  <string name="failed_upload_retry_text">zkusit znovu odeslat obrázek:</string>
-  <string name="failed_upload_load_more_images">Načíst více obrázků</string>
-  <string name="failed_upload_retry_do_nothing_text">nic nedělat nejste připojeni pro okamžité odeslání</string>
-  <string name="failed_upload_failure_text">Chybová zpráva:</string>
-  <string name="failed_upload_quota_exceeded_text">Zkontrolujte prosím nastavení vašeho serveru, možná jste překročili kvótu.</string>
+  <string name="prefs_instant_upload_path_title">Cesta pro nahrání</string>
+  <string name="share_link_no_support_share_api">Je nám líto, ale sdílení není na vašem serveru povoleno. Kontaktujte svého
+administrátora.</string>
+  <string name="share_link_file_no_exist">Nelze sdílet. Zkontrolujte prosím že soubor existuje</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="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>
+  <string name="error_cant_bind_to_operations_service">Kritická chyba: operace nelze provést</string>
+  <string name="network_error_socket_exception">Při pokusu o připojení k serveru došlo k chybě.</string>
+  <string name="network_error_socket_timeout_exception">Při čekání na odpověď serveru se vyskytla chyba, operace nemohla být dokončena</string>
+  <string name="network_error_connect_timeout_exception">Při čekání na odpověď serveru se vyskytla chyba, operace nemohla být dokončena</string>
+  <string name="network_host_not_available">Operace nemohla být dokončena, server je nedostupný</string>
+  <string name="empty"></string>
+  <string name="forbidden_permissions">Nemáte oprávnění %s</string>
+  <string name="forbidden_permissions_rename">přejmenovat tento soubor</string>
+  <string name="forbidden_permissions_delete">smazat tento soubor</string>
+  <string name="share_link_forbidden_permissions">sdílet tento soubor</string>
+  <string name="unshare_link_forbidden_permissions">zrušit sdílení tohoto souboru</string>
+  <string name="forbidden_permissions_create">vytvořit tento soubor</string>
+  <string name="uploader_upload_forbidden_permissions">nahrávat do tohoto adresáře</string>
+  <string name="downloader_download_file_not_found">Tento soubor již není dostupný na serveru</string>
+  <string name="prefs_category_accounts">Účty</string>
+  <string name="prefs_add_account">Přidat účet</string>
+  <string name="auth_redirect_non_secure_connection_title">Bezpečné spojení je přesměrováno na nezabezpečenou trasu.</string>
+  <string name="actionbar_logger">Logy</string>
+  <string name="log_send_history_button">Odeslat historii</string>
+  <string name="log_mail_subject">Logy aplikace ownCloud pro Android</string>
+  <string name="log_progress_dialog_text">Načítám data...</string>
+  <string name="saml_authentication_required_text">Vyžadováno přihlášení</string>
+  <string name="saml_authentication_wrong_pass">Nesprávné heslo</string>
+  <string name="actionbar_move">Přesunout</string>
+  <string name="file_list_empty_moving">Zde nic není. Můžete přidat adresář!</string>
+  <string name="move_choose_button_text">Vybrat</string>
+  <string name="move_file_not_found">Nelze přesunout. Zkontrolujte prosím že soubor existuje</string>
+  <string name="move_file_invalid_into_descendent">Není možné adresář přesunout do vlastního podadresáře</string>
+  <string name="move_file_invalid_overwrite">Soubor již v cílovém adresáři existuje</string>
+  <string name="move_file_error">Při pokusu o přesun tohoto souboru či složky nastala chyba</string>
+  <string name="forbidden_permissions_move">pro přesun tohoto souboru</string>
+  <string name="prefs_category_instant_uploading">Okamžitá odesílání</string>
+  <string name="prefs_category_security">Zabezpečení</string>
 </resources>
index de4ffef..daace9c 100644 (file)
@@ -3,15 +3,13 @@
   <string name="actionbar_upload">Llwytho i fyny</string>
   <string name="actionbar_upload_from_apps">Cynnwys o becynnau eraill</string>
   <string name="actionbar_upload_files">Ffeiliau</string>
-  <string name="actionbar_mkdir">Creu cyfeiriadur</string>
   <string name="actionbar_settings">Gosodiadau</string>
+  <string name="actionbar_send_file">Anfon</string>
   <string name="prefs_category_general">Cyffredinol</string>
   <string name="prefs_accounts">Cyfrifon</string>
   <string name="prefs_manage_accounts">Rheoli Cyfrifon</string>
   <string name="prefs_pincode">PIN Ap</string>
   <string name="prefs_pincode_summary">Amddiffyn eich cleient</string>
-  <string name="prefs_instant_upload">Galluogi llwytho i fyny\'n syth</string>
-  <string name="prefs_instant_upload_summary">Llwytho lluniau dynnwyd â chamera i fyny\'n syth</string>
   <string name="prefs_help">Cymorth</string>
   <string name="prefs_imprint">Imprint</string>
   <string name="auth_username">Enw defnyddiwr</string>
@@ -27,7 +25,7 @@
   <string name="uploader_wrn_no_content_text">Heb dderbyn cynnwys. Dim cynnwys i lwytho i fyny</string>
   <string name="uploader_error_forbidden_content">Does dim mynediad gan %1$s i gynnwys a rennir</string>
   <string name="uploader_info_uploading">Yn llwytho i fyny</string>
-  <string name="file_list_empty">Does dim ffeilau yn y blygell hon.\nGellir ychwanegu rhai newydd drwy ddewis \"Llwytho i fyny\" yn y ddewislen.</string>
+  <string name="file_list_empty">Does dim byd fan hyn. Llwythwch rhywbeth i fyny!</string>
   <string name="filedetails_select_file">Tapiwch ffeil i ddangos gwybodaeth ychwanegol</string>
   <string name="filedetails_size">Maint:</string>
   <string name="filedetails_type">Math:</string>
@@ -47,7 +45,6 @@
   <string name="delete_account">Dileu cyfrif</string>
   <string name="create_account">Creu cyfrif</string>
   <string name="upload_chooser_title">Llwytho i fyny o ...</string>
-  <string name="uploader_info_dirname">Enw cyfeiriadur</string>
   <string name="uploader_upload_in_progress_ticker">Yn llwytho i fyny ...</string>
   <string name="uploader_upload_in_progress_content">%1$d%% Llwytho i fyny %2$s</string>
   <string name="uploader_upload_succeeded_ticker">Llwytho i fyny\'n llwyddiannus</string>
   <string name="sync_fail_in_favourites_ticker">Methodd ffeiliau cadw-yn-gydamserol</string>
   <string name="sync_fail_in_favourites_content">Methwyd cydamseru cynnwys ffeiliau %1$d (gwrthdaro %2$d )</string>
   <string name="sync_foreign_files_forgotten_ticker">Anghofiwyd am rai ffeiliau lleol</string>
-  <string name="sync_foreign_files_forgotten_content">Methwyd copio %1$d ffeil o gyfeiriadur %2$s i mewn i</string>
   <string name="foreign_files_move">Symud y cyfan</string>
   <string name="foreign_files_success">Symudwyd pob ffeil</string>
   <string name="foreign_files_fail">Methwyd symud rhai ffeiliau</string>
   <string name="foreign_files_local_text">Lleol: %1$s</string>
   <string name="foreign_files_remote_text">Pell: %1$s</string>
-  <string name="upload_query_move_foreign_files">Does dim digon o le i gopïo\'r ffeiliau ddewiswyd i blygell %1$s . Would like to move them into instead? </string>
   <string name="pincode_enter_pin_code">Cyflwynwch PIN eich Ap</string>
   <string name="pincode_configure_your_pin">Cyflwynwch PIN eich Ap</string>
   <string name="pincode_configure_your_pin_explanation">Bydd cais am y PIN bob tro mae\'r ap yn cychwyn</string>
   <string name="fd_keep_in_sync">Cadw\'r ffeil yn gyfredol</string>
   <string name="common_rename">Ailenwi</string>
   <string name="common_remove">Gwaredu</string>
-  <string name="confirmation_remove_alert">Ydych chi wir am gael gwared ar %1$s ?</string>
-  <string name="confirmation_remove_folder_alert">Ydych chi wir am waredu %1$s a\'i gynnwys?</string>
   <string name="confirmation_remove_local">Lleol yn unig</string>
   <string name="confirmation_remove_folder_local">Cynnwys lleol yn unig</string>
   <string name="confirmation_remove_remote">Gwaredu o\'r gweinydd</string>
   <string name="rename_server_fail_msg">Methwyd cwblhau\'r ailenwi</string>
   <string name="sync_file_fail_msg">Methwyd gwirio\'r ffeil bell</string>
   <string name="sync_file_nothing_to_do_msg">Cynnwys y ffeil eisoes wedi cydamseru</string>
-  <string name="create_dir_fail_msg">Methwyd creu cyfeiriadur</string>
   <string name="wait_a_moment">Arhoswch eiliad</string>
   <string name="filedisplay_unexpected_bad_get_content">Gwall annisgwyl ; dewiswch y ffeil o ap gwahanol</string>
   <string name="filedisplay_no_file_selected">Ni ddewiswyd ffeil</string>
   <string name="conflict_keep_both">Cadw\'r ddau</string>
   <string name="conflict_overwrite">Trosysgrifio</string>
   <string name="conflict_dont_upload">Peidio llwytho i fyny</string>
-  <string name="error__upload__local_file_not_copied">Methwyd copïo %1$s i blygell lleol %2$s</string>
+  <string name="activity_chooser_send_file_title">Anfon</string>
+  <string name="empty"></string>
+  <string name="prefs_category_accounts">Cyfrifon</string>
+  <string name="move_choose_button_text">Dewisiwch</string>
 </resources>
index 13c0c79..5444900 100644 (file)
@@ -7,33 +7,40 @@
   <string name="actionbar_upload_from_apps">Indhold fra andre apps</string>
   <string name="actionbar_upload_files">Filer</string>
   <string name="actionbar_open_with">Åben med</string>
-  <string name="actionbar_mkdir">Opret mappe</string>
+  <string name="actionbar_mkdir">Ny mappe</string>
   <string name="actionbar_settings">Indstillinger</string>
   <string name="actionbar_see_details">Detaljer</string>
+  <string name="actionbar_send_file">Send</string>
   <string name="prefs_category_general">Generel</string>
   <string name="prefs_category_more">Mere</string>
   <string name="prefs_accounts">Konti</string>
-  <string name="prefs_manage_accounts">Administrer konti</string>
+  <string name="prefs_manage_accounts">Administrér konti</string>
   <string name="prefs_pincode">App PIN</string>
   <string name="prefs_pincode_summary">Beskyt din klient</string>
-  <string name="prefs_instant_upload">Slå øjeblikkelig upload til</string>
-  <string name="prefs_instant_upload_summary">Upload billeder taget med kamera med det samme</string>
-  <string name="prefs_log_title">Aktiver Logning</string>
-  <string name="prefs_log_summary">Dette bruges til at logge problemer</string>
+  <string name="prefs_instant_upload">Upload billeder straks</string>
+  <string name="prefs_instant_upload_summary">Upload straks billeder taget med kameraet</string>
+  <string name="prefs_instant_video_upload">Upload videoer straks</string>
+  <string name="prefs_instant_video_upload_summary">Upload straks videor optaget med kameraet</string>
+  <string name="prefs_log_title">Aktivér logregistrering</string>
+  <string name="prefs_log_summary">Dette bruges til at logregistrere problemer</string>
   <string name="prefs_log_title_history">Logger Historik</string>
   <string name="prefs_log_summary_history">Dette viser de optagne logger</string>
-  <string name="prefs_log_delete_history_button">Slet Historik</string>
+  <string name="prefs_log_delete_history_button">Slet historik</string>
   <string name="prefs_help">Hjælp</string>
+  <string name="prefs_recommend">Anbefal til en ven</string>
+  <string name="prefs_feedback">Feedback</string>
   <string name="prefs_imprint">Imprint</string>
-  <string name="auth_check_server">Check Server</string>
-  <string name="auth_host_url">Serveradresse</string>
+  <string name="recommend_subject">Prøv %1$s på din smartphone!</string>
+  <string name="recommend_text">Jeg ønsker at invitere dig til at bruge %1$s på din smartphone!\nHent den her: %2$s</string>
+  <string name="auth_check_server">Tjek server</string>
+  <string name="auth_host_url">Serveradresse https://…</string>
   <string name="auth_username">Brugernavn</string>
   <string name="auth_password">Kodeord</string>
   <string name="auth_register">Uvant med %1$s</string>
   <string name="sync_string_files">Filer</string>
   <string name="setup_btn_connect">Tilslut</string>
   <string name="uploader_btn_upload_text">Upload</string>
-  <string name="uploader_top_message">Vælg upload mappe:</string>
+  <string name="uploader_top_message">Vælg upload-mappe:</string>
   <string name="uploader_wrn_no_account_title">Ingen konto fundet</string>
   <string name="uploader_wrn_no_account_text">Der er ingen %1$s brugere på din enhed. Sæt venligst en bruger op først.</string>
   <string name="uploader_wrn_no_account_setup_btn_text">Opsætning</string>
   <string name="uploader_wrn_no_content_text">Intet indhold blev modtaget. Intet at uploade.</string>
   <string name="uploader_error_forbidden_content">%1$s er ikke tilladt adgang til delt indhold</string>
   <string name="uploader_info_uploading">Uploader</string>
-  <string name="file_list_empty">Der er ingen filer i denne mappe.\nNye filer kan tilføjes med menu valgmuligheden \"Upload\".</string>
+  <string name="file_list_empty">Her er tomt. Upload noget!</string>
+  <string name="file_list_loading">Indlæser...</string>
+  <string name="local_file_list_empty">Der er ingen filer i denne mappe.</string>
   <string name="filedetails_select_file">Tryk på en fil for at vise yderligere information.</string>
   <string name="filedetails_size">Størelse:</string>
   <string name="filedetails_type">Type:</string>
   <string name="filedetails_created">Oprettet:</string>
   <string name="filedetails_modified">Ændret:</string>
   <string name="filedetails_download">Hent</string>
-  <string name="filedetails_sync_file">Opdater fil</string>
+  <string name="filedetails_sync_file">Genopfrisk fil</string>
   <string name="filedetails_renamed_in_upload_msg">Filen blev omdøbt til %1$s under upload</string>
+  <string name="action_share_file">Del link</string>
+  <string name="action_unshare_file">Ophæv deling</string>
   <string name="common_yes">Ja</string>
   <string name="common_no">Nej</string>
   <string name="common_ok">OK</string>
   <string name="delete_account">Slet konto</string>
   <string name="create_account">Opret konto</string>
   <string name="upload_chooser_title">Upload fra ...</string>
-  <string name="uploader_info_dirname">mappenavn</string>
+  <string name="uploader_info_dirname">Mappenavn</string>
   <string name="uploader_upload_in_progress_ticker">Uploader ...</string>
   <string name="uploader_upload_in_progress_content">%1$d%% Uploader %2$s</string>
   <string name="uploader_upload_succeeded_ticker">Upload færdig</string>
   <string name="uploader_upload_succeeded_content_single">%1$s blev uploadet med success</string>
   <string name="uploader_upload_failed_ticker">Upload fejlede</string>
   <string name="uploader_upload_failed_content_single">Upload af %1$s kunne ikke gennemføres</string>
+  <string name="uploader_upload_failed_credentials_error">Upload mislykkedes, du kan logge ind på ny</string>
   <string name="downloader_download_in_progress_ticker">Downloader ...</string>
   <string name="downloader_download_in_progress_content">%1$d%% Downloader %2$s</string>
   <string name="downloader_download_succeeded_ticker">Download fuldført</string>
   <string name="downloader_download_failed_ticker">Download fejlede</string>
   <string name="downloader_download_failed_content">Download af %1$s kunne ikke fuldføres</string>
   <string name="downloader_not_downloaded_yet">Endnu ikke downloadet</string>
+  <string name="downloader_download_failed_credentials_error">Download mislykkedes, du skal logge ind på ny</string>
   <string name="common_choose_account">Vælg konto</string>
   <string name="sync_fail_ticker">Synkronisering fejlede</string>
+  <string name="sync_fail_ticker_unauthorized">Synkroniseringen mislykkedes, du er nødt til at logge ind påny</string>
   <string name="sync_fail_content">Synkronisering af %1$s kunne ikke gennemføres</string>
   <string name="sync_fail_content_unauthorized">Ugyldig adgangskode for %1$s</string>
   <string name="sync_conflicts_in_favourites_ticker">Konflikter fundet</string>
   <string name="sync_fail_in_favourites_content">Indholdet af %1$d filer ikke kunne synkroniseres (%2$d konflikter)</string>
   <string name="sync_foreign_files_forgotten_ticker">Visse lokale filer blev glemt</string>
   <string name="sync_foreign_files_forgotten_content">%1$d filer ud af %2$s mappe kunne ikke kopieres ind i</string>
-  <string name="sync_foreign_files_forgotten_explanation">Fra version 1.3.16 bliver filer uploadet fra denne enhed kopieret til mappen %1$s for at forhindre datatab når en enkelt fil synkroniseres med flere konti.\n\nPå grund af denne ændring blev alle filer uploadet i tidligere versioner af denne app kopieret til mappen %2$s. Imidlertid forhindrede en fejl færdiggørelsen af denne operation under konto-synkronisering. Du kan enten lade filerne være som de er og fjerne linket til %3$s eller flytte filerne til mappen %1$s og beholde linket til %4$s.\n\nHerunder er en liste med de lokale filer og de eksterne filer i %5$s, som de var knyttet til.</string>
+  <string name="sync_foreign_files_forgotten_explanation">Fra version 1.3.16 bliver filer uploadet fra denne enhed kopieret til mappen %1$s for at forhindre datatab når en enkelt fil synkroniseres med flere konti.\n\nPå grund af denne ændring er alle filer som var uploadet i tidligere versioner af denne app kopieret til mappen %2$s. Imidlertid forhindrede en fejl færdiggørelsen af denne operation under konto-synkronisering. Du kan enten lade filen (el. filerne) være som de er og fjerne linket til %3$s eller flytte filen (el. filerne) til mappen %1$s og beholde linket til %4$s.\n\nHerunder er en liste med den lokale fil(er), og den fjerne mappe(r) i %5$s, som de var knyttet til.</string>
+  <string name="sync_current_folder_was_removed">Mappen %1$s eksistere ikke længere</string>
   <string name="foreign_files_move">Flyt alle</string>
   <string name="foreign_files_success">Alle filer blev flyttet</string>
   <string name="foreign_files_fail">Visse filer kunne ikke flyttes</string>
   <string name="foreign_files_local_text">Lokal: %1$s</string>
   <string name="foreign_files_remote_text">Fjernplacering: %1$s</string>
-  <string name="upload_query_move_foreign_files">Der er ikke tilstrækkelig plads til at kopiere de valgte filer ind i %1$s mappen. Vil du flytte dem i stedet?</string>
+  <string name="upload_query_move_foreign_files">Der er ikke plads nok til at kopiere de valgte filer ind i mappen %1$s. Vil du flytte dem i stedet?</string>
   <string name="pincode_enter_pin_code">Indsæt venligst din App PIN</string>
   <string name="pincode_configure_your_pin">Indtast App PIN</string>
   <string name="pincode_configure_your_pin_explanation">PIN koden vil blive anmodet om hver gang applikationen bliver startet</string>
   <string name="media_err_unsupported">Ikke-understøttet medie codec</string>
   <string name="media_err_io">Mediefilen kunne ikke læses</string>
   <string name="media_err_malformed">Mediefilen er ikke korrekt kodet</string>
+  <string name="media_err_timeout">Tiden udløb under forsøg på at afspille</string>
   <string name="media_err_invalid_progressive_playback">Mediefilen kan ikke streames</string>
   <string name="media_err_unknown">Mediefil kan ikke afspilles med tilgængelige medieafspiller</string>
   <string name="media_err_security_ex">Sikkerhedsfejl ved forsøg på afspilning af </string>
   <string name="media_err_io_ex">Inputfejl ved forsøg på afspilning af %1$s</string>
   <string name="media_err_unexpected">Uventet fejl ved forsøg på afspilning af %1$s</string>
-  <string name="media_rewind_description">Tilbagespolings knap</string>
+  <string name="media_rewind_description">Tilbagespolingsknap</string>
   <string name="media_play_pause_description">Afspil eller pause knap</string>
-  <string name="media_forward_description">Hurtigt fremad kanp</string>
+  <string name="media_forward_description">Hurtigt fremad-knap</string>
+  <string name="auth_getting_authorization">Forsøger godkendelse...</string>
   <string name="auth_trying_to_login">Forsøger at logge ind...</string>
   <string name="auth_no_net_conn_title">Ingen netværksforbindelse</string>
   <string name="auth_nossl_plain_ok_title">Sikker forbindelse ikke tilgængelig.</string>
   <string name="auth_connection_established">Forbindelse oprettet</string>
   <string name="auth_testing_connection">Afprøver forbindelse ...</string>
   <string name="auth_not_configured_title">Misdannet server konfiguration</string>
+  <string name="auth_account_not_new">En konto for den samme bruger og server eksisterer allerede på enheden</string>
+  <string name="auth_account_not_the_same">Den indtastede bruger passer ikke til brugeren for denne konto</string>
   <string name="auth_unknown_error_title">Ukendt fejl opstod!</string>
-  <string name="auth_unknown_host_title">Kunne ikke finde host</string>
+  <string name="auth_unknown_host_title">Kunne ikke finde værten</string>
   <string name="auth_incorrect_path_title">Server instans blev ikke fundet</string>
   <string name="auth_timeout_title">Serveren var for længe om at svare</string>
   <string name="auth_incorrect_address_title">Deform URL</string>
-  <string name="auth_ssl_general_error_title">SSL initialisering fejlede</string>
-  <string name="auth_bad_oc_version_title">Ikke genkendt server version</string>
+  <string name="auth_ssl_general_error_title">SSL-initialiseringen fejlede</string>
+  <string name="auth_ssl_unverified_server_title">Kunne ikke bekræfte SSl-serverens identitet</string>
+  <string name="auth_bad_oc_version_title">Ikke genkendt serverversion</string>
   <string name="auth_wrong_connection_title">Ikke ikke oprette forbindelse</string>
   <string name="auth_secure_connection">Sikker forbindelse oprettet</string>
   <string name="auth_unauthorized">Forkert brugernavn eller kodeord</string>
   <string name="auth_oauth_error">Mislykket godkendelse</string>
   <string name="auth_oauth_error_access_denied">Adgang afvist af autorisationsserver</string>
   <string name="auth_wtf_reenter_URL">Uventet tilstand; angiv server-URL\'en igen</string>
+  <string name="auth_expired_oauth_token_toast">Din godkendelse udløb. Gentag godkendelse</string>
   <string name="auth_expired_basic_auth_toast">Indtast venligst dit nuværende kodeord</string>
-  <string name="fd_keep_in_sync">Hold fil opdateret</string>
+  <string name="auth_expired_saml_sso_token_toast">Din session udløb. Forbind venligst igen</string>
+  <string name="auth_connecting_auth_server">Forbinder til godkendelsesserver ...</string>
+  <string name="auth_unsupported_auth_method">Serveren understøtter ikke denne godkendelsesmetode</string>
+  <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="fd_keep_in_sync">Hold filen opdateret</string>
   <string name="common_rename">Omdøb</string>
   <string name="common_remove">Fjern</string>
   <string name="confirmation_remove_alert">Er du sikker på at du vil fjerne %1$s ?</string>
-  <string name="confirmation_remove_folder_alert">Ønsker du virkelig at %1$s og dets indhold skal fjernes</string>
+  <string name="confirmation_remove_folder_alert">Ønsker du virkelig at slette %1$s og dets indhold?</string>
   <string name="confirmation_remove_local">Kun lokal</string>
   <string name="confirmation_remove_folder_local">Lokalt indhold kun</string>
   <string name="confirmation_remove_remote">Fjern fra server</string>
   <string name="rename_server_fail_msg">Omdøbning kunne ikke gennemføres</string>
   <string name="sync_file_fail_msg">Ekstern fil kunne ikke kontrolleres</string>
   <string name="sync_file_nothing_to_do_msg">Filindholdet allerede synkroniseret</string>
-  <string name="create_dir_fail_msg">Mappe kunne ikke oprettes</string>
+  <string name="create_dir_fail_msg">Kunne ikke oprette mappe</string>
+  <string name="filename_forbidden_characters">Ugyldige tegn: / \\ &lt; &gt; : \" | ? *</string>
+  <string name="filename_empty">Filnavnet kan ikke stå tomt.</string>
   <string name="wait_a_moment">Vent et øjeblik</string>
   <string name="filedisplay_unexpected_bad_get_content">Uforventet problem; prøv venligst anden applikation til at vælge filen</string>
   <string name="filedisplay_no_file_selected">Ingen fil blev valgt</string>
-  <string name="oauth_login_connection">Forbinder til oAuth2 server...</string>
+  <string name="activity_chooser_title">Send link til ...</string>
+  <string name="oauth_check_onoff">Log på med oAuth2</string>
+  <string name="oauth_login_connection">Forbinder til oAuth2-server...</string>
   <string name="ssl_validator_header">Sidens identitet kunne ikke verificeres</string>
   <string name="ssl_validator_reason_cert_not_trusted">- Serverens certifikat er ikke troværdigt</string>
   <string name="ssl_validator_reason_cert_expired">- Serverens certifikat er udløbet</string>
   <string name="ssl_validator_label_validity_to">Til:</string>
   <string name="ssl_validator_label_signature">Signatur:</string>
   <string name="ssl_validator_label_signature_algorithm">Algoritme:</string>
+  <string name="ssl_validator_null_cert">Certifikatet kunne ikke vises.</string>
+  <string name="ssl_validator_no_info_about_error">- Ingen information om fejlen</string>
   <string name="placeholder_sentence">Dette er en pladsholder</string>
-  <string name="placeholder_filename">stedfortræder.txt</string>
+  <string name="placeholder_filename">pladsholder.txt</string>
   <string name="placeholder_filetype">PNG Billede</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">Upload billeder kun via WiFi </string>
+  <string name="instant_upload_on_wifi">Upload kun billeder via WiFi </string>
+  <string name="instant_video_upload_on_wifi">Upload kun videoer via WiFi</string>
   <string name="instant_upload_path">/Øjeblikkelig upload</string>
   <string name="conflict_title">Opdaterings konflikt</string>
   <string name="conflict_message">Ekstern fil %s er ikke synkroniseret med lokal fil. At fortsætte vil erstatte indholdet af filen på serveren.</string>
   <string name="conflict_keep_both">Behold begge</string>
   <string name="conflict_overwrite">Overskriv</string>
   <string name="conflict_dont_upload">Upload ikke</string>
-  <string name="preview_image_description">Billede preview</string>
+  <string name="preview_image_description">Forhåndsvisning af billede</string>
   <string name="preview_image_error_unknown_format">Dette billede kan ikke vises</string>
   <string name="error__upload__local_file_not_copied">%1$s kunne ikke kopieres til %2$s lokale mappe</string>
-  <string name="actionbar_failed_instant_upload">InstantUpload mislykkedes\"</string>
-  <string name="failed_upload_headline_text">Øjeblikkelige uploads mislykkedes</string>
-  <string name="failed_upload_headline_hint">Sammenfatning af alle mislykkede øjeblikkelige uploads</string>
-  <string name="failed_upload_all_cb">Vælg alle</string>
-  <string name="failed_upload_headline_retryall_btn">prøv alle markerede igen</string>
-  <string name="failed_upload_headline_delete_all_btn">slet alle markerede fra uploadkøen</string>
-  <string name="failed_upload_retry_text">prøv at uploade billedet igen:</string>
-  <string name="failed_upload_load_more_images">Indlæs flere billeder</string>
-  <string name="failed_upload_retry_do_nothing_text">gør intet, du er ikke online til øjeblikkelig upload</string>
-  <string name="failed_upload_failure_text">Fejlmeddelelse</string>
-  <string name="failed_upload_quota_exceeded_text">Tjek din serverkonfiguration, måske er din kvota overskredet.</string>
+  <string name="prefs_instant_upload_path_title">Sti til upload</string>
+  <string name="share_link_no_support_share_api">Beklager, deling er ikke slået til på din server. Kontakt venligst din administrator.</string>
+  <string name="share_link_file_no_exist">Kan ikke dele. Tjek venligst om filen findes.</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="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="error_cant_bind_to_operations_service">Kritisk fejl: kan ikke udføre handlingerne</string>
+  <string name="network_error_socket_exception">Der opstod en fejl under tilslutningen til serveren.</string>
+  <string name="network_error_socket_timeout_exception">Der opstod en fejl mens vi ventede på serveren, handlingen kunne ikke gennemføres</string>
+  <string name="network_error_connect_timeout_exception">Der opstod en fejl mens vi ventede på serveren, handlingen kunne ikke gennemføres</string>
+  <string name="network_host_not_available">Handlingen kunne ikke gennemføres, serveren er utilgængelig</string>
+  <string name="empty"></string>
+  <string name="forbidden_permissions">Du har ikke rettigheden %s</string>
+  <string name="forbidden_permissions_rename">til at omdøbe denne fil</string>
+  <string name="forbidden_permissions_delete">til at slette denne fil</string>
+  <string name="share_link_forbidden_permissions">til at dele denne fil</string>
+  <string name="unshare_link_forbidden_permissions">til at stoppe deling af denne fil</string>
+  <string name="forbidden_permissions_create">til at oprette filen</string>
+  <string name="uploader_upload_forbidden_permissions">til at overføre til denne mappe</string>
+  <string name="downloader_download_file_not_found">Filen er ikke længere tilgængelig på serveren</string>
+  <string name="prefs_category_accounts">Konti</string>
+  <string name="prefs_add_account">Tilføj konto</string>
+  <string name="auth_redirect_non_secure_connection_title">Sikker forbindelse videredirigeres til en usikker rute.</string>
+  <string name="actionbar_logger">Logge</string>
+  <string name="log_send_history_button">Send historik</string>
+  <string name="log_mail_subject">App-logregistreringer for ownCloud Android</string>
+  <string name="log_progress_dialog_text">Indlæser data...</string>
+  <string name="saml_authentication_required_text">Godkendelse påkrævet</string>
+  <string name="saml_authentication_wrong_pass">Forkert kodeord</string>
+  <string name="actionbar_move">Flyt</string>
+  <string name="file_list_empty_moving">Der er intet her. Du kan tilføje en mappe!</string>
+  <string name="move_choose_button_text">Vælg</string>
+  <string name="move_file_not_found">Kan ikke flytte. Tjek venligst om filen findes</string>
+  <string name="move_file_invalid_into_descendent">Det er ikke muligt at flytte en mappe til en undermappe</string>
+  <string name="move_file_invalid_overwrite">Filen findes allerede i destinationsmappen</string>
+  <string name="move_file_error">Der opstod en fejl under forsøg på at flytte denne mappe eller fil</string>
+  <string name="forbidden_permissions_move">til at flytte denne fil</string>
+  <string name="prefs_category_instant_uploading">Øjeblikkelige uploads</string>
+  <string name="prefs_category_security">Sikkerhed</string>
 </resources>
index c757504..f2c13bf 100644 (file)
@@ -1,2 +1,13 @@
 <?xml version='1.0' encoding='UTF-8'?>
-<resources/>
+<resources>
+  <string name="actionbar_upload_files">Dateien</string>
+  <string name="actionbar_settings">Einstellungen</string>
+  <string name="prefs_category_general">Allgemein</string>
+  <string name="prefs_help">Hilfe</string>
+  <string name="auth_password">Passwort</string>
+  <string name="sync_string_files">Dateien</string>
+  <string name="filedetails_download">Herunterladen</string>
+  <string name="common_cancel">Abbrechen</string>
+  <string name="common_error">Fehler</string>
+  <string name="empty"></string>
+</resources>
index d5a2b7f..7a5b9e9 100644 (file)
@@ -7,17 +7,16 @@
   <string name="actionbar_upload_from_apps">Inhalt von anderen Apps</string>
   <string name="actionbar_upload_files">Dateien</string>
   <string name="actionbar_open_with">Öffnen mit</string>
-  <string name="actionbar_mkdir">Ordner anlegen</string>
+  <string name="actionbar_mkdir">Neues Verzeichnis</string>
   <string name="actionbar_settings">Einstellungen</string>
   <string name="actionbar_see_details">Details</string>
+  <string name="actionbar_send_file">Senden</string>
   <string name="prefs_category_general">Allgemein</string>
   <string name="prefs_category_more">Mehr</string>
   <string name="prefs_accounts">Konten</string>
   <string name="prefs_manage_accounts">Konten verwalten</string>
   <string name="prefs_pincode">App-PIN</string>
   <string name="prefs_pincode_summary">Schützen Sie Ihren Client</string>
-  <string name="prefs_instant_upload">Aktiviert den sofortigen Upload</string>
-  <string name="prefs_instant_upload_summary">Laden Sie Ihre Fotos von der Kamera sofort hoch</string>
   <string name="prefs_log_title">Protokollierung aktivieren</string>
   <string name="prefs_log_summary">Dies wird zur Protokollierung von Problemen genutzt</string>
   <string name="prefs_log_title_history">Protokollierungsverlauf</string>
   <string name="prefs_feedback">Rückmeldungen</string>
   <string name="prefs_imprint">Impressum</string>
   <string name="auth_check_server">Server überprüfen</string>
-  <string name="auth_host_url">Adresse des Servers</string>
   <string name="auth_username">Benutzername</string>
   <string name="auth_password">Passwort</string>
   <string name="auth_register">Ist %1$s neu für Sie?</string>
   <string name="sync_string_files">Dateien</string>
   <string name="setup_btn_connect">Verbinden</string>
   <string name="uploader_btn_upload_text">Hochladen</string>
-  <string name="uploader_top_message">Wähle Zielordner:</string>
   <string name="uploader_wrn_no_account_title">Kein Konto gefunden</string>
   <string name="uploader_wrn_no_account_text">Es sind keine %1$s-Konten auf Ihrem Gerät eingerichtet. Bitte richten Sie zuerst ein Konto ein.</string>
   <string name="uploader_wrn_no_account_setup_btn_text">Einrichten</string>
@@ -43,7 +40,7 @@
   <string name="uploader_wrn_no_content_text">Es wurden keine Inhalte empfangen. Es gibt nichts zum Hochladen.</string>
   <string name="uploader_error_forbidden_content">%1$s darf den freigegebenen Inhalt nicht nutzen.</string>
   <string name="uploader_info_uploading">Lade hoch</string>
-  <string name="file_list_empty">Es sind keine Dateien im Verzeichnis vorhanden.\nNeue Dateien können mit der Menüfunktion «Hochladen» hinzugefügt werden.</string>
+  <string name="file_list_empty">Alles leer. Laden Sie etwas hoch!</string>
   <string name="filedetails_select_file">Klicken Sie auf eine Datei für weitere Informationen.</string>
   <string name="filedetails_size">Grösse:</string>
   <string name="filedetails_type">Art:</string>
   <string name="sync_fail_in_favourites_ticker">Synchronisationsdateien konnten nicht synchronisiert werden.</string>
   <string name="sync_fail_in_favourites_content">Inhalte von %1$d konnte nicht synchronisiert werden (%2$d Konflikte)</string>
   <string name="sync_foreign_files_forgotten_ticker">Einige lokale Dateien wurden vergessen</string>
-  <string name="sync_foreign_files_forgotten_content">%1$d Dateien aus dem Verzeichnis %2$s konnten nicht kopiert werden nach</string>
-  <string name="sync_foreign_files_forgotten_explanation">«Mit Version 1.3.16 werden Dateien die von diesem Gerät aus hochgeladen werden in den lokalen Ordner %1$s kopiert um Datenverlust zu vermeiden, wenn eine einzelne Datei mit mehreren Accounts synchronisiert wird.\n\nInfolge dieser Änderung wurden alle Dateien, die mit vorherigen Versionen dieser App hochgeladen wurden, in den Ordner %2$s verschoben. Jedoch ist während der Account-Synchronisation ein Fehler aufgetreten, der das Abschliessen dieses Vorgangs verhindert. Sie können die Datei(en) entweder wie sie sind belassen und den Link zu %3$s entfernen oder die Datei(en) in den %1$s Ordner verschieben und  den Link zu %4$s beibehalten.\n\nUnten befindet sich eine Liste der lokalen Datei(en) und der mit ihnen verbundenen Remote-Datei(en) in %5$s.</string>
   <string name="foreign_files_move">Verschiebe alle</string>
   <string name="foreign_files_success">Alle Dateien wurden verschoben</string>
   <string name="foreign_files_fail">Einige Dateien konnten nicht verschoben werden</string>
   <string name="foreign_files_local_text">Lokal: %1$s</string>
   <string name="foreign_files_remote_text">Remote: %1$s</string>
-  <string name="upload_query_move_foreign_files">Es steht nicht genügend Speicherplatz zur Verfügung, um die ausgewählten Dateien in den %1$s Ordner zu kopieren. Möchten Sie sie stattdessen verschieben?</string>
   <string name="pincode_enter_pin_code">Bitte geben Sie Ihre App-PIN ein</string>
   <string name="pincode_configure_your_pin">Bitte geben Sie Ihre App-PIN ein</string>
   <string name="pincode_configure_your_pin_explanation">PIN-Abfrage erfolgt nach Starten der App.</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="confirmation_remove_alert">Möchten Sie %1$s wirklich löschen?</string>
-  <string name="confirmation_remove_folder_alert">Möchten Sie wirklich %1$s und dessen Inhalte entfernen?</string>
   <string name="confirmation_remove_local">Nur lokal</string>
   <string name="confirmation_remove_folder_local">Nur lokale Inhalte</string>
   <string name="confirmation_remove_remote">Vom Server entfernen</string>
   <string name="rename_server_fail_msg">Die Umbenennung konnte nicht abgeschlossen werden.</string>
   <string name="sync_file_fail_msg">Die entfernte Datei konnte nicht überprüft werden</string>
   <string name="sync_file_nothing_to_do_msg">Dateiinhalte bereits synchronisiert</string>
-  <string name="create_dir_fail_msg">Das Verzeichnis konnte nicht erstellt werden.</string>
   <string name="wait_a_moment">Bitte warten Sie einen Moment.</string>
   <string name="filedisplay_unexpected_bad_get_content">Ein unerwartetes Problem ist aufgetreten. Bitte versuchen Sie, die Datei in einer anderen App zu öffnen.</string>
   <string name="filedisplay_no_file_selected">Es wurde keine Datei ausgewählt.</string>
   <string name="conflict_overwrite">Überschreiben</string>
   <string name="conflict_dont_upload">Nicht hochladen</string>
   <string name="preview_image_description">Bildvorschau</string>
-  <string name="preview_image_error_unknown_format">Dieses Bild kann nicht angezeigt werden</string>
-  <string name="error__upload__local_file_not_copied">%1$s konnte nicht in den lokalen %2$s Ordner kopiert werden</string>
-  <string name="actionbar_failed_instant_upload">Sofort Upload fehlgeschlagen»</string>
-  <string name="failed_upload_headline_text">Sofortige Uploads fehlgeschlagen</string>
-  <string name="failed_upload_headline_hint">Zusammenfassung aller fehlgeschlagenen Uploads</string>
-  <string name="failed_upload_all_cb">Alle auswählen</string>
-  <string name="failed_upload_headline_retryall_btn">Versuche alle ausgewählten erneut</string>
-  <string name="failed_upload_headline_delete_all_btn">Lösche alle ausgewählten aus der Uploadwarteschlange</string>
-  <string name="failed_upload_retry_text">Bildupload erneut versuchen:</string>
-  <string name="failed_upload_load_more_images">Lade weitere Bilder</string>
-  <string name="failed_upload_retry_do_nothing_text">Nicht durchgeführt - Nicht online für sofortigen Upload</string>
-  <string name="failed_upload_failure_text">Fehlermeldung:</string>
-  <string name="failed_upload_quota_exceeded_text">Bitte überprüfen Sie Ihre Serverkonfiguration. Vielleicht ist Ihr Nutzungslimit überschritten.</string>
+  <string name="activity_chooser_send_file_title">Senden</string>
+  <string name="clipboard_text_copied">In die Zwischenablage kopiert</string>
+  <string name="empty"></string>
+  <string name="prefs_category_accounts">Konten</string>
+  <string name="move_choose_button_text">Auswählen</string>
+  <string name="prefs_category_security">Sicherheit</string>
 </resources>
index 5421ae0..70bd98f 100644 (file)
@@ -7,37 +7,40 @@
   <string name="actionbar_upload_from_apps">Inhalt von anderen Apps</string>
   <string name="actionbar_upload_files">Dateien</string>
   <string name="actionbar_open_with">Öffnen mit</string>
-  <string name="actionbar_mkdir">Ordner anlegen</string>
+  <string name="actionbar_mkdir">Neuer Ordner</string>
   <string name="actionbar_settings">Einstellungen</string>
   <string name="actionbar_see_details">Details</string>
+  <string name="actionbar_send_file">Senden</string>
   <string name="prefs_category_general">Allgemein</string>
   <string name="prefs_category_more">Mehr</string>
   <string name="prefs_accounts">Konten</string>
   <string name="prefs_manage_accounts">Konten verwalten</string>
   <string name="prefs_pincode">App-PIN</string>
   <string name="prefs_pincode_summary">Schützen Sie Ihren Client</string>
-  <string name="prefs_instant_upload">Aktiviert den sofortigen Upload</string>
-  <string name="prefs_instant_upload_summary">Laden Sie Ihre Fotos von der Kamera sofort hoch</string>
+  <string name="prefs_instant_upload">Sofortiges Bilderhochladen</string>
+  <string name="prefs_instant_upload_summary">Fotos von der Kamera sofort hochladen</string>
+  <string name="prefs_instant_video_upload">Sofortiges Videohochladen</string>
+  <string name="prefs_instant_video_upload_summary">Videos von der Kamera sofort hochladen</string>
   <string name="prefs_log_title">Protokollierung aktivieren</string>
-  <string name="prefs_log_summary">Dies wird zur Protokollierung von Problemen genutzt</string>
+  <string name="prefs_log_summary">Dieses wird zur Protokollierung von Problemen benutzt</string>
   <string name="prefs_log_title_history">Protokollierungsverlauf</string>
-  <string name="prefs_log_summary_history">Dies zeigt die gespeicherten Protokollierungen</string>
+  <string name="prefs_log_summary_history">Dieses zeigt die gespeicherten Protokollierungen</string>
   <string name="prefs_log_delete_history_button">Verlauf löschen</string>
   <string name="prefs_help">Hilfe</string>
-  <string name="prefs_recommend">Empfehlen Sie dies einem Freund</string>
+  <string name="prefs_recommend">Dieses einem Freund empfehlen</string>
   <string name="prefs_feedback">Rückmeldungen</string>
   <string name="prefs_imprint">Impressum</string>
-  <string name="recommend_subject">Probieren Sie %1$s auf Ihrem Smartphone!</string>
-  <string name="recommend_text">Ich möchte Sie zum Benutzen von %1$s auf Ihrem Smartphone einladen!\nLaden Sie es hier herunter: %2$s</string>
+  <string name="recommend_subject">%1$s auf Ihrem Smartphone ausprobieren!</string>
+  <string name="recommend_text">Ich möchte Sie zum Benutzen von %1$s auf Ihrem Smartphone einladen!\nHier herunterladen: %2$s</string>
   <string name="auth_check_server">Server überprüfen</string>
-  <string name="auth_host_url">Adresse des Servers</string>
+  <string name="auth_host_url">Server-Adresse https://…</string>
   <string name="auth_username">Benutzername</string>
   <string name="auth_password">Passwort</string>
   <string name="auth_register">Ist %1$s neu für Sie?</string>
   <string name="sync_string_files">Dateien</string>
   <string name="setup_btn_connect">Verbinden</string>
   <string name="uploader_btn_upload_text">Hochladen</string>
-  <string name="uploader_top_message">Wähle Zielordner:</string>
+  <string name="uploader_top_message">Zielordner auswählen:</string>
   <string name="uploader_wrn_no_account_title">Kein Konto gefunden</string>
   <string name="uploader_wrn_no_account_text">Es sind keine %1$s-Konten auf Ihrem Gerät eingerichtet. Bitte richten Sie zuerst ein Konto ein.</string>
   <string name="uploader_wrn_no_account_setup_btn_text">Einrichten</string>
@@ -46,7 +49,9 @@
   <string name="uploader_wrn_no_content_text">Es wurden keine Inhalte empfangen. Es gibt nichts zum Hochladen.</string>
   <string name="uploader_error_forbidden_content">%1$s darf den freigegebenen Inhalt nicht nutzen.</string>
   <string name="uploader_info_uploading">Lade hoch</string>
-  <string name="file_list_empty">Es sind keine Dateien im Verzeichnis vorhanden.\nNeue Dateien können mit der Menüfunktion \"Hochladen\" hinzugefügt werden.</string>
+  <string name="file_list_empty">Alles leer. Laden Sie etwas hoch!</string>
+  <string name="file_list_loading">Ladevorgang …</string>
+  <string name="local_file_list_empty">Es befinden sich keine Dateien in diesem Ordner.</string>
   <string name="filedetails_select_file">Klicken Sie auf eine Datei für weitere Informationen.</string>
   <string name="filedetails_size">Größe:</string>
   <string name="filedetails_type">Art:</string>
@@ -55,6 +60,8 @@
   <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_unshare_file">Link nicht mehr teilen</string>
   <string name="common_yes">Ja</string>
   <string name="common_no">Nein</string>
   <string name="common_ok">OK</string>
@@ -77,6 +84,7 @@
   <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, Sie müssen sich nochmals anmelden</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_failed_ticker">Herunterladen fehlgeschlagen</string>
   <string name="downloader_download_failed_content">Herunterladen von %1$s konnte nicht abgeschlossen werden</string>
   <string name="downloader_not_downloaded_yet">Noch nicht heruntergeladen</string>
+  <string name="downloader_download_failed_credentials_error">Herunterladen fehlgeschlagen, Sie müssen sich nochmals anmelden</string>
   <string name="common_choose_account">Konto auswählen</string>
   <string name="sync_fail_ticker">Synchronisation fehlgeschlagen</string>
+  <string name="sync_fail_ticker_unauthorized">Synchronisation fehlgeschlagen, Sie müssen sich neu anmelden</string>
   <string name="sync_fail_content">Bei der Synchronisation konnte %1$s nicht übertragen werden</string>
   <string name="sync_fail_content_unauthorized">Ungültiges Passwort für %1$s</string>
   <string name="sync_conflicts_in_favourites_ticker">Konflikte gefunden</string>
   <string name="sync_fail_in_favourites_ticker">Synchronisationsdateien konnten nicht synchronisiert werden.</string>
   <string name="sync_fail_in_favourites_content">Inhalte von %1$d konnte nicht synchronisiert werden (%2$d Konflikte)</string>
   <string name="sync_foreign_files_forgotten_ticker">Einige lokale Dateien wurden vergessen</string>
-  <string name="sync_foreign_files_forgotten_content">%1$d Dateien aus dem Verzeichnis %2$s konnten nicht kopiert werden nach</string>
-  <string name="sync_foreign_files_forgotten_explanation">\"Mit Version 1.3.16 werden Dateien die von diesem Gerät aus hochgeladen werden in den lokalen Ordner %1$s kopiert um Datenverlust zu vermeiden, wenn eine einzelne Datei mit mehreren Accounts synchronisiert wird.\n\nInfolge dieser Änderung wurden alle Dateien, die mit vorherigen Versionen dieser App hochgeladen wurden, in den Ordner %2$s verschoben. Jedoch ist während der Account-Synchronisation ein Fehler aufgetreten, der das Abschließen dieses Vorgangs verhindert. Sie können die Datei(en) entweder wie sie sind belassen und den Link zu %3$s entfernen oder die Datei(en) in den %1$s Ordner verschieben und  den Link zu %4$s beibehalten.\n\nUnten befindet sich eine Liste der lokalen Datei(en) und der mit ihnen verbundenen Remote-Datei(en) in %5$s.</string>
+  <string name="sync_foreign_files_forgotten_content">%1$d Dateien aus dem %2$s Ordner konnten nicht kopiert werden nach</string>
+  <string name="sync_foreign_files_forgotten_explanation">Mit Version 1.3.16 werden Dateien die von diesem Gerät aus hochgeladen werden in den lokalen Ordner %1$s kopiert um Datenverlust zu vermeiden, wenn eine einzelne Datei mit mehreren Accounts synchronisiert wird.\n\nInfolge dieser Änderung wurden alle Dateien, die mit vorherigen Versionen dieser App hochgeladen wurden, in den Ordner %2$s verschoben. Jedoch ist während der Account-Synchronisation ein Fehler aufgetreten, der das Abschließen dieses Vorgangs verhindert. Sie können die Datei(en) entweder wie sie sind belassen und den Link zu %3$s entfernen oder die Datei(en) in den %1$s Ordner verschieben und  den Link zu %4$s beibehalten.\n\nUnten befindet sich eine Liste der lokalen Datei(en) und der mit ihnen verbundenen Remote-Datei(en) in %5$s.</string>
   <string name="sync_current_folder_was_removed">Das Verzeichnis %1$s existiert nicht mehr</string>
   <string name="foreign_files_move">Verschiebe alle</string>
   <string name="foreign_files_success">Alle Dateien wurden verschoben</string>
   <string name="foreign_files_fail">Einige Dateien konnten nicht verschoben werden</string>
   <string name="foreign_files_local_text">Lokal: %1$s</string>
   <string name="foreign_files_remote_text">Remote: %1$s</string>
-  <string name="upload_query_move_foreign_files">Es steht nicht genügend Speicherplatz zur Verfügung, um die ausgewählten Dateien in den %1$s Ordner zu kopieren. Möchten Sie sie stattdessen verschieben?</string>
+  <string name="upload_query_move_foreign_files">Es steht nicht genügend Speicherplatz zur Verfügung um die ausgewählten Dateien in den %1$s Ordner zu kopieren. Möchten Sie diese stattdessen verschieben?</string>
   <string name="pincode_enter_pin_code">Bitte geben Sie Ihre App-PIN ein</string>
   <string name="pincode_configure_your_pin">Bitte geben Sie Ihre App-PIN ein</string>
   <string name="pincode_configure_your_pin_explanation">PIN-Abfrage erfolgt nach Starten der App.</string>
   <string name="media_rewind_description">Zurückspulen Button</string>
   <string name="media_play_pause_description">Abspielen oder Pausieren Button</string>
   <string name="media_forward_description">Vorspulen Button</string>
-  <string name="auth_trying_to_login">Anmeldungsversuch...</string>
+  <string name="auth_getting_authorization">Legitimierung 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">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_wrong_connection_title">Konnte keine Verbindung aufbauen.</string>
   <string name="auth_secure_connection">Sichere Verbindung hergestellt</string>
   <string name="auth_unauthorized">Falscher Benutzername oder Passwort</string>
-  <string name="auth_oauth_error">Autorisierung nicht erfolgreich</string>
-  <string name="auth_oauth_error_access_denied">Zugriff durch den Autorisierungsserver abgelehnt</string>
-  <string name="auth_wtf_reenter_URL">Unerwarteter Zustand; bitte geben Sie die URL des Servers nochmals ein</string>
-  <string name="auth_expired_oauth_token_toast">Ihre Autorisierung ist abgelaufen. Bitte Autorisierung nochmals durchführen</string>
+  <string name="auth_oauth_error">Legitimierung nicht erfolgreich</string>
+  <string name="auth_oauth_error_access_denied">Zugriff durch den Legitimierungsserver abgelehnt</string>
+  <string name="auth_wtf_reenter_URL">Unerwarteter Zustand; bitte geben Sie die Adresse des Servers nochmals ein</string>
+  <string name="auth_expired_oauth_token_toast">Ihre Legitimierung ist abgelaufen. Bitte Legitimierung nochmals durchführen</string>
   <string name="auth_expired_basic_auth_toast">Bitte geben Sie Ihr aktuelles Passwort ein</string>
   <string name="auth_expired_saml_sso_token_toast">Ihre Sitzung ist abgelaufen. Bitte Anmeldung nochmals durchführen</string>
-  <string name="auth_connecting_auth_server">Verbinde mit dem Authentifizierung-Server…</string>
-  <string name="auth_unsupported_auth_method">Der Server unterstützt diese Authentifizierung-Methode nicht</string>
+  <string name="auth_connecting_auth_server">Zum Legitimierungsserver wird verbunden …</string>
+  <string name="auth_unsupported_auth_method">Der Server unterstützt diese Legitimierungsmethode nicht</string>
   <string name="auth_unsupported_multiaccount">%1$s unterstützt nicht mehrere Benutzerkonten</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="fd_keep_in_sync">Datei aktuell halten</string>
   <string name="common_rename">Umbenennen</string>
   <string name="common_remove">Löschen</string>
   <string name="rename_server_fail_msg">Die Umbenennung konnte nicht abgeschlossen werden.</string>
   <string name="sync_file_fail_msg">Die entfernte Datei konnte nicht überprüft werden</string>
   <string name="sync_file_nothing_to_do_msg">Dateiinhalte bereits synchronisiert</string>
-  <string name="create_dir_fail_msg">Das Verzeichnis konnte nicht erstellt werden.</string>
+  <string name="create_dir_fail_msg">Ordner konnte nicht erstellt werden</string>
+  <string name="filename_forbidden_characters">Verbotene Zeichen: / \\ &lt; &gt; : \" | ? *</string>
+  <string name="filename_empty">Dateiname darf nicht leer sein</string>
   <string name="wait_a_moment">Bitte warten Sie einen Moment.</string>
   <string name="filedisplay_unexpected_bad_get_content">Ein unerwartetes Problem ist aufgetreten. Bitte versuchen Sie, 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="oauth_check_onoff">Anmelden mit oAuth2</string>
-  <string name="oauth_login_connection">Verbinde mit dem oAuth2-Server…</string>
+  <string name="oauth_login_connection">Mit dem oAuth2-Server wird verbunden …</string>
   <string name="ssl_validator_header">Die Identität der Website konnte nicht überprüft werden</string>
   <string name="ssl_validator_reason_cert_not_trusted">- Das Zertifikat des Servers ist nicht vertrauenswürdig</string>
   <string name="ssl_validator_reason_cert_expired">- Das Zertifikat des Servers ist abgelaufen</string>
   <string name="ssl_validator_label_validity_to">An:</string>
   <string name="ssl_validator_label_signature">Signatur:</string>
   <string name="ssl_validator_label_signature_algorithm">Algorithmus:</string>
+  <string name="ssl_validator_null_cert">Das Zertifikat konnte nicht angezeigt werden.</string>
+  <string name="ssl_validator_no_info_about_error">- Keine Informationen über den Fehler</string>
   <string name="placeholder_sentence">Dies ist ein Platzhalter</string>
   <string name="placeholder_filename">platzhalter.txt</string>
   <string name="placeholder_filetype">PNG Bild</string>
   <string name="placeholder_timestamp">18.05.2012 12:23</string>
   <string name="placeholder_media_time">12:23:45</string>
   <string name="instant_upload_on_wifi">Fotos nur über WiFi hochladen</string>
+  <string name="instant_video_upload_on_wifi">Videos nur über WiFi hochladen</string>
   <string name="instant_upload_path">/SofortUpload</string>
   <string name="conflict_title">Konflikt beim Update</string>
   <string name="conflict_message">Serverdatei %s ist nicht synchronisiert mit der lokalen Datei. Weitermachen bedeutet, dass der Inhalt der Datei auf dem Server ersetzt wird.</string>
   <string name="preview_image_description">Bildvorschau</string>
   <string name="preview_image_error_unknown_format">Dieses Bild kann nicht angezeigt werden</string>
   <string name="error__upload__local_file_not_copied">%1$s konnte nicht in den lokalen %2$s Ordner kopiert werden</string>
-  <string name="actionbar_failed_instant_upload">Sofort Upload fehlgeschlagen\"</string>
-  <string name="failed_upload_headline_text">Sofortige Uploads fehlgeschlagen</string>
-  <string name="failed_upload_headline_hint">Zusammenfassung aller fehlgeschlagenen Uploads</string>
-  <string name="failed_upload_all_cb">Alle auswählen</string>
-  <string name="failed_upload_headline_retryall_btn">Versuche alle ausgewählten erneut</string>
-  <string name="failed_upload_headline_delete_all_btn">Lösche alle ausgewählten aus der Uploadwarteschlange</string>
-  <string name="failed_upload_retry_text">Bildupload erneut versuchen:</string>
-  <string name="failed_upload_load_more_images">Lade weitere Bilder</string>
-  <string name="failed_upload_retry_do_nothing_text">Nicht durchgeführt - Nicht online für sofortigen Upload</string>
-  <string name="failed_upload_failure_text">Fehlermeldung:</string>
-  <string name="failed_upload_quota_exceeded_text">Bitte überprüfen Sie Ihre Serverkonfiguration. Vielleicht ist Ihr Nutzungslimit überschritten.</string>
+  <string name="prefs_instant_upload_path_title">Pfad hochladen</string>
+  <string name="share_link_no_support_share_api">Entschuldigung, Freigaben sind auf Ihrem Server nicht aktiviert. Bitte kontaktieren Sie Ihren
+⇥⇥Administrator.</string>
+  <string name="share_link_file_no_exist">Teilen nicht möglich. Prüfen Sie, dass die Datei existiert</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, 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="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="error_cant_bind_to_operations_service">Kritischer Fehler: Operationen können nicht ausgeführt werden</string>
+  <string name="network_error_socket_exception">Es ist ein Fehler beim Verbinden mit dem Server aufgetreten.</string>
+  <string name="network_error_socket_timeout_exception">Es ist ein Fehler beim Warten auf den Server aufgetreten, die Operation kann nicht ausgeführt werden</string>
+  <string name="network_error_connect_timeout_exception">Es ist ein Fehler beim Warten auf den Server aufgetreten, die Operation kann nicht ausgeführt werden</string>
+  <string name="network_host_not_available">Die Operation kann nicht abgeschlossen werden, der Server ist nicht erreichbar</string>
+  <string name="empty"></string>
+  <string name="forbidden_permissions">Sie haben keine Berechtigung %s</string>
+  <string name="forbidden_permissions_rename">diese Datei umzubenennen</string>
+  <string name="forbidden_permissions_delete">diese Datei zu löschen</string>
+  <string name="share_link_forbidden_permissions">diese Datei zu teilen</string>
+  <string name="unshare_link_forbidden_permissions">diese Datei nicht mehr zu teilen</string>
+  <string name="forbidden_permissions_create">eine Datei zu erstellen</string>
+  <string name="uploader_upload_forbidden_permissions">in diesem Order etwas hochzuladen</string>
+  <string name="downloader_download_file_not_found">Diese Datei steht auf dem Server nicht mehr zur Verfügung</string>
+  <string name="prefs_category_accounts">Konten</string>
+  <string name="prefs_add_account">Konto hinzufügen</string>
+  <string name="auth_redirect_non_secure_connection_title">Die gesicherte Verbindung wird auf eine unsichere Route weitergeleitet.</string>
+  <string name="actionbar_logger">Protokolle</string>
+  <string name="log_send_history_button">Verlauf senden</string>
+  <string name="log_mail_subject">Protokolle der ownCloud-Android-App</string>
+  <string name="log_progress_dialog_text">Daten werden geladen …</string>
+  <string name="saml_authentication_required_text">Legitimierung benötigt</string>
+  <string name="saml_authentication_wrong_pass">Falsches Passwort</string>
+  <string name="actionbar_move">Verschieben</string>
+  <string name="file_list_empty_moving">Nichts vorhanden. Sie können einen Ordner hinzufügen!</string>
+  <string name="move_choose_button_text">Auswählen</string>
+  <string name="move_file_not_found">Verschieben nicht möglich. Bitte überprüfen Sie, ob die Datei existiert</string>
+  <string name="move_file_invalid_into_descendent">Es ist nicht möglich einen Ordner eine Ebene tiefer zu verschieben</string>
+  <string name="move_file_invalid_overwrite">Die Datei ist bereits im Zielordner vorhanden</string>
+  <string name="move_file_error">Es ist ein Fehler beim Verschieben dieser Datei oder dieses Ordners aufgetreten.</string>
+  <string name="forbidden_permissions_move">um diese Datei zu verschieben</string>
+  <string name="prefs_category_instant_uploading">Sofortiges Hochladen</string>
+  <string name="prefs_category_security">Sicherheit</string>
 </resources>
index 4edae55..028b6bc 100644 (file)
@@ -7,17 +7,20 @@
   <string name="actionbar_upload_from_apps">Inhalt von anderen Apps</string>
   <string name="actionbar_upload_files">Dateien</string>
   <string name="actionbar_open_with">Öffnen mit</string>
-  <string name="actionbar_mkdir">Ordner anlegen</string>
+  <string name="actionbar_mkdir">Neuer Ordner</string>
   <string name="actionbar_settings">Einstellungen</string>
   <string name="actionbar_see_details">Details</string>
+  <string name="actionbar_send_file">Senden</string>
   <string name="prefs_category_general">Allgemein</string>
   <string name="prefs_category_more">Mehr</string>
   <string name="prefs_accounts">Konten</string>
   <string name="prefs_manage_accounts">Konten verwalten</string>
   <string name="prefs_pincode">App-PIN</string>
   <string name="prefs_pincode_summary">Schütze Deinen Client</string>
-  <string name="prefs_instant_upload">Aktiviert den sofortigen Upload</string>
-  <string name="prefs_instant_upload_summary">Lade Deine Fotos von der Kamera sofort hoch</string>
+  <string name="prefs_instant_upload">Sofortiger Bilder-Upload</string>
+  <string name="prefs_instant_upload_summary">Lade Fotos von der Kamera sofort hoch</string>
+  <string name="prefs_instant_video_upload">Sofortiger Video-Upload</string>
+  <string name="prefs_instant_video_upload_summary">Lade Videos von der Kamera sofort hoch</string>
   <string name="prefs_log_title">Protokollierung aktivieren</string>
   <string name="prefs_log_summary">Dies wird zur Protokollierung von Problemen genutzt</string>
   <string name="prefs_log_title_history">Protokollierungsverlauf</string>
   <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">Adresse des Servers</string>
+  <string name="auth_host_url">Server-Adresse 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>
   <string name="sync_string_files">Dateien</string>
   <string name="setup_btn_connect">Verbinden</string>
   <string name="uploader_btn_upload_text">Hochladen</string>
-  <string name="uploader_top_message">Wähle einen Ordner zum hochladen:</string>
+  <string name="uploader_top_message">Wähle Zielordner:</string>
   <string name="uploader_wrn_no_account_title">Kein Account gefunden</string>
   <string name="uploader_wrn_no_account_text">Es sind keine %1$s-Accounts auf Deinem Gerät eingerichtet. Bitte richte zuerst ein Konto ein.</string>
   <string name="uploader_wrn_no_account_setup_btn_text">Einrichten</string>
@@ -46,7 +49,9 @@
   <string name="uploader_wrn_no_content_text">Es wurden keine Inhalte empfangen. Es gibt nichts zum Hochladen.</string>
   <string name="uploader_error_forbidden_content">%1$s darf den freigegebenen Inhalt nicht nutzen.</string>
   <string name="uploader_info_uploading">Lade hoch</string>
-  <string name="file_list_empty">Es sind keine Dateien im Verzeichnis vorhanden.\nNeue Dateien können mit der \"Hochladen\" Menüfunktion hinzugefügt werden.</string>
+  <string name="file_list_empty">Alles leer. Lade etwas hoch!</string>
+  <string name="file_list_loading">Ladevorgang …</string>
+  <string name="local_file_list_empty">Es befinden sich keine Dateien in diesem Ordner.</string>
   <string name="filedetails_select_file">Klicken Sie auf eine Datei für weitere Informationen.</string>
   <string name="filedetails_size">Größe:</string>
   <string name="filedetails_type">Art:</string>
@@ -55,6 +60,8 @@
   <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_unshare_file">Link nicht mehr freigeben</string>
   <string name="common_yes">Ja</string>
   <string name="common_no">Nein</string>
   <string name="common_ok">OK</string>
@@ -77,6 +84,7 @@
   <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_content">%1$d%% Herunterladen %2$s</string>
   <string name="downloader_download_succeeded_ticker">Herunterladen erfolgreich</string>
   <string name="downloader_download_failed_ticker">Herunterladen fehlgeschlagen</string>
   <string name="downloader_download_failed_content">Herunterladen von %1$s konnte nicht abgeschlossen werden</string>
   <string name="downloader_not_downloaded_yet">Noch nicht Heruntergeladen</string>
+  <string name="downloader_download_failed_credentials_error">Herunterladen fehlgeschlagen, Du musst dich nochmals anmelden</string>
   <string name="common_choose_account">Account auswählen</string>
   <string name="sync_fail_ticker">Synchronisation fehlgeschlagen</string>
+  <string name="sync_fail_ticker_unauthorized">Synchronisation fehlgeschlagen, Du musst Dich neu anmelden</string>
   <string name="sync_fail_content">Bei der Synchronisation konnte %1$s nicht übertragen werden</string>
   <string name="sync_fail_content_unauthorized">Falsches Passwort für %1$s</string>
   <string name="sync_conflicts_in_favourites_ticker">Konflikte gefunden</string>
   <string name="sync_fail_in_favourites_ticker">Synchron halten schlug fehl.</string>
   <string name="sync_fail_in_favourites_content">Inhalte von %1$d konnte nicht synchronisiert werden (%2$d Konflikte)</string>
   <string name="sync_foreign_files_forgotten_ticker">Einige lokale Dateien wurden vergessen</string>
-  <string name="sync_foreign_files_forgotten_content">%1$d Dateien aus dem Verzeichnis %2$s konnten nicht kopiert werden nach</string>
-  <string name="sync_foreign_files_forgotten_explanation">\"Mit Version 1.3.16 werden Dateien die von diesem Gerät aus hochgeladen werden in den lokalen Ordner %1$s kopiert um Datenverlust zu vermeiden, wenn eine einzelne Datei mit mehreren Accounts synchronisiert wird.\n\nInfolge dieser Änderung wurden alle Dateien, die mit vorherigen Versionen dieser App hochgeladen wurden, in den Ordner %2$s verschoben. Jedoch ist während der Account-Synchronisation ein Fehler aufgetreten, der das Abschließen dieses Vorgangs verhindert. Du kannst die Datei(en) entweder wie sie sind belassen und den Link zu %3$s entfernen oder die Datei(en) in den %1$s Ordner verschieben und  den Link zu %4$s beibehalten.\n\nUnten befindet sich eine Liste der lokalen Datei(en) und der mit ihnen verbundenen Remote-Datei(en) in %5$s.</string>
+  <string name="sync_foreign_files_forgotten_content">%1$d Dateien aus dem %2$s Verzeichnis konnten nicht kopiert werden nach</string>
+  <string name="sync_foreign_files_forgotten_explanation">Mit Version 1.3.16 werden Dateien die von diesem Gerät aus hochgeladen werden in den lokalen Ordner %1$s kopiert um Datenverlust zu vermeiden, wenn eine einzelne Datei mit mehreren Accounts synchronisiert wird.\n\nInfolge dieser Änderung wurden alle Dateien, die mit vorherigen Versionen dieser App hochgeladen wurden, in den Ordner %2$s verschoben. Jedoch ist während der Account-Synchronisation ein Fehler aufgetreten, der das Abschließen dieses Vorgangs verhindert. Du kannst die Datei(en) entweder wie sie sind belassen und den Link zu %3$s entfernen oder die Datei(en) in den Ordner %1$s verschieben und  den Link zu %4$s beibehalten.\n\nUnten befindet sich eine Liste der lokalen Datei(en) und der mit ihnen verbundenen Remote-Datei(en) in %5$s.</string>
   <string name="sync_current_folder_was_removed">Das Verzeichnis %1$s existiert nicht mehr</string>
   <string name="foreign_files_move">Verschiebe alle</string>
   <string name="foreign_files_success">Alle Dateien wurden verschoben</string>
   <string name="foreign_files_fail">Einige Dateien konnten nicht verschoben werden</string>
   <string name="foreign_files_local_text">Lokal: %1$s</string>
   <string name="foreign_files_remote_text">Remote: %1$s</string>
-  <string name="upload_query_move_foreign_files">Es steht nicht genügend Speicherplatz zur Verfügung, um die ausgewählten Dateien in den %1$s Ordner zu kopieren. Möchtest Du sie stattdessen verschieben?</string>
+  <string name="upload_query_move_foreign_files">Es steht nicht genügend Speicherplatz zur Verfügung um die ausgewählten Dateien in den %1$s Ordner zu kopieren. Möchtest du diese stattdessen verschieben?</string>
   <string name="pincode_enter_pin_code">Bitte gib Deine App-PIN ein</string>
   <string name="pincode_configure_your_pin">Bitte gib Deine App-PIN ein</string>
   <string name="pincode_configure_your_pin_explanation">PIN-Abfrage erfolgt nach Starten der App.</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_no_net_conn_title">Keine Netzwerkverbindung</string>
   <string name="auth_nossl_plain_ok_title">Sichere Verbindung nicht verfügbar.</string>
   <string name="auth_oauth_error">Autorisierung nicht erfolgreich</string>
   <string name="auth_oauth_error_access_denied">Zugriff durch den Autorisierungsserver abgelehnt</string>
   <string name="auth_wtf_reenter_URL">Unerwarteter Zustand; bitte gib die URL des Servers nochmals ein</string>
-  <string name="auth_expired_oauth_token_toast">Ihre Autorisierung ist abgelaufen. Bitte Autorisierung nochmals durchführen</string>
+  <string name="auth_expired_oauth_token_toast">Deine Autorisierung ist abgelaufen. Bitte Autorisierung nochmals durchführen</string>
   <string name="auth_expired_basic_auth_toast">Bitte gib dein aktuelles Passwort ein</string>
-  <string name="auth_expired_saml_sso_token_toast">Ihre Sitzung ist abgelaufen. Bitte Anmeldung nochmals durchführen</string>
+  <string name="auth_expired_saml_sso_token_toast">Deine Sitzung ist abgelaufen. Bitte Anmeldung nochmals durchführen</string>
   <string name="auth_connecting_auth_server">Verbinde mit dem Authentifizierung-Server…</string>
   <string name="auth_unsupported_auth_method">Der Server unterstützt diese Authentifizierung-Methode nicht</string>
   <string name="auth_unsupported_multiaccount">%1$s unterstützt nicht mehrere Benutzerkonten</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="fd_keep_in_sync">Datei aktuell halten</string>
   <string name="common_rename">Umbenennen</string>
   <string name="common_remove">Löschen</string>
   <string name="rename_server_fail_msg">Die Umbenennung konnte nicht abgeschlossen werden.</string>
   <string name="sync_file_fail_msg">Die entfernte Datei konnte nicht überprüft werden</string>
   <string name="sync_file_nothing_to_do_msg">Dateiinhalte bereits synchronisiert</string>
-  <string name="create_dir_fail_msg">Das Verzeichnis konnte nicht erstellt werden.</string>
+  <string name="create_dir_fail_msg">Verzeichnis konnte nicht erstellt werden</string>
+  <string name="filename_forbidden_characters">Verbotene Zeichen: / \\ &lt; &gt; : \" | ? *</string>
+  <string name="filename_empty">Dateiname darf nicht leer sein</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="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="ssl_validator_label_validity_to">Bis:</string>
   <string name="ssl_validator_label_signature">Signatur:</string>
   <string name="ssl_validator_label_signature_algorithm">Algorithmus:</string>
+  <string name="ssl_validator_null_cert">Das Zertifikat konnte nicht gezeigt werden.</string>
+  <string name="ssl_validator_no_info_about_error">- Keine Informationen über den Fehler</string>
   <string name="placeholder_sentence">Dies ist ein Platzhalter</string>
   <string name="placeholder_filename">platzhalter.txt</string>
   <string name="placeholder_filetype">PNG-Bild</string>
   <string name="placeholder_timestamp">18.5.2012 12:23</string>
   <string name="placeholder_media_time">12:23:45</string>
   <string name="instant_upload_on_wifi">Fotos nur über WiFi hochladen</string>
+  <string name="instant_video_upload_on_wifi">Videos nur über WiFi hochladen</string>
   <string name="instant_upload_path">/SofortUpload</string>
   <string name="conflict_title">Konflikt beim Update</string>
   <string name="conflict_message">Serverdatei %s ist nicht synchronisiert mit der lokalen Datei. Weitermachen bedeutet, dass der Inhalt der Datei auf dem Server ersetzt wird.</string>
   <string name="preview_image_description">Bildvorschau</string>
   <string name="preview_image_error_unknown_format">Dieses Bild kann nicht angezeigt werden</string>
   <string name="error__upload__local_file_not_copied">%1$s konnte nicht in den lokalen %2$s Ordner kopiert werden</string>
-  <string name="actionbar_failed_instant_upload">Fehlgeschlagener SofortUpload\"</string>
-  <string name="failed_upload_headline_text">SofortUpload fehlgeschlagen</string>
-  <string name="failed_upload_headline_hint">Übersicht aller fehlgeschlagenen SofortUploads</string>
-  <string name="failed_upload_all_cb">Alles auswählen</string>
-  <string name="failed_upload_headline_retryall_btn">Alles auswählen erneut versuchen</string>
-  <string name="failed_upload_headline_delete_all_btn">Auswahl aus der Upload Warteschlange entfernen</string>
-  <string name="failed_upload_retry_text">Hochladen des Bildes erneut versuchen:</string>
-  <string name="failed_upload_load_more_images">Weitere Bilder laden</string>
-  <string name="failed_upload_retry_do_nothing_text">Nicht durchgeführt - Nicht online für sofortigen Upload</string>
-  <string name="failed_upload_failure_text">Fehlermeldung:</string>
-  <string name="failed_upload_quota_exceeded_text">Bitte überprüfe Deine Servereinstellungen. Eventuell ist Dein Nutzungslimit überschritten.</string>
+  <string name="prefs_instant_upload_path_title">Pfad hochladen</string>
+  <string name="share_link_no_support_share_api">Entschuldigung, Freigaben sind auf Deinem Server nicht aktiviert. Bitte kontaktiere Deinen
+⇥⇥Administrator.</string>
+  <string name="share_link_file_no_exist">Teilen nicht möglich. Prüfe, dass die Datei existiert</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="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="error_cant_bind_to_operations_service">Kritischer Fehler: Operationen können nicht ausgeführt werden</string>
+  <string name="network_error_socket_exception">Es ist ein Fehler beim Verbinden mit dem Server aufgetreten.</string>
+  <string name="network_error_socket_timeout_exception">Es ist ein Fehler beim Warten auf den Server aufgetreten, die Operation kann nicht ausgeführt werden</string>
+  <string name="network_error_connect_timeout_exception">Es ist ein Fehler beim Warten auf den Server aufgetreten, die Operation kann nicht ausgeführt werden</string>
+  <string name="network_host_not_available">Die Operation kann nicht abgeschlossen werden, der Server ist nicht erreichbar</string>
+  <string name="empty"></string>
+  <string name="forbidden_permissions">Du hast keine Berechtigung %s</string>
+  <string name="forbidden_permissions_rename">diese Datei umzubenennen</string>
+  <string name="forbidden_permissions_delete">diese Datei zu löschen</string>
+  <string name="share_link_forbidden_permissions">diese Datei zu teilen</string>
+  <string name="unshare_link_forbidden_permissions">diese Datei nicht mehr zu teilen</string>
+  <string name="forbidden_permissions_create">eine Datei zu erstellen</string>
+  <string name="uploader_upload_forbidden_permissions">in diesem Order etwas hochzuladen</string>
+  <string name="downloader_download_file_not_found">Diese Datei steht auf dem Server nicht mehr zur Verfügung</string>
+  <string name="prefs_category_accounts">Konten</string>
+  <string name="prefs_add_account">Konto hinzufügen</string>
+  <string name="auth_redirect_non_secure_connection_title">Die gesicherte Verbindung wird auf eine unsichere Route weitergeleitet.</string>
+  <string name="actionbar_logger">Protokolle</string>
+  <string name="log_send_history_button">Verlauf senden</string>
+  <string name="log_mail_subject">Protokolle der ownCloud-Android-App</string>
+  <string name="log_progress_dialog_text">Daten werden geladen …</string>
+  <string name="saml_authentication_required_text">Legitimierung benötigt</string>
+  <string name="saml_authentication_wrong_pass">Falsches Passwort</string>
+  <string name="actionbar_move">Verschieben</string>
+  <string name="file_list_empty_moving">Nichts vorhanden. Du kannst einen Ordner hinzufügen!</string>
+  <string name="move_choose_button_text">Auswählen</string>
+  <string name="move_file_not_found">Verschieben nicht möglich. Prüfe, dass die Datei existiert</string>
+  <string name="move_file_invalid_into_descendent">Es ist nicht möglich, einen Ordner in einen seiner Unterordner zu verschieben</string>
+  <string name="move_file_invalid_overwrite">Die Datei ist bereits im Zielordner vorhanden</string>
+  <string name="move_file_error">Es ist ein Fehler beim Verschieben der Datei oder des Ordners aufgetreten.</string>
+  <string name="forbidden_permissions_move">um diese Datei zu verschieben</string>
+  <string name="prefs_category_instant_uploading">Sofortiges Hochladen</string>
+  <string name="prefs_category_security">Sicherheit</string>
 </resources>
index 0837a49..94e35a6 100644 (file)
@@ -1,43 +1,57 @@
 <?xml version='1.0' encoding='UTF-8'?>
 <resources>
-  <string name="about_android">%1$s Εφαρμογή για Android</string>
+  <string name="about_android">Εφαρμογή %1$s Android</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">Î\94ημιοÏ\85Ï\81γία ÎºÎ±Ï\84αλÏ\8cγοÏ\85</string>
+  <string name="actionbar_mkdir">Î\9dέοÏ\82 Ï\86άκελοÏ\82</string>
   <string name="actionbar_settings">Ρυθμίσεις</string>
   <string name="actionbar_see_details">Λεπτομέρειες</string>
+  <string name="actionbar_send_file">Αποστολή</string>
   <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">PIN της εφαρμογής</string>
-  <string name="prefs_pincode_summary">Προστατέψτε την εφαρμογή</string>
-  <string name="prefs_instant_upload">Ενεργοποιήστε την άμεση μεταφόρτωση</string>
-  <string name="prefs_instant_upload_summary">Άμεση μεταφόρτωση των φωτογραφιών που τραβάει η φωτογρ. μηχανή</string>
+  <string name="prefs_manage_accounts">Διαχείριση Λογαριασμών</string>
+  <string name="prefs_pincode">PIN εφαρμογής</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="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">Î\94ιεÏ\8dθÏ\85νÏ\83η ÎµÎ¾Ï\85Ï\80ηÏ\81έÏ\84η</string>
+  <string name="auth_host_url">Î\94ιεÏ\8dθÏ\85νÏ\83η Î´Î¹Î±ÎºÎ¿Î¼Î¹Ï\83Ï\84ή https://â\80¦</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="uploader_btn_upload_text">Μεταφόρτωση</string>
-  <string name="uploader_top_message">Επιλέξτε κατάλογο ανεβάσματος</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">Î\9aλείÏ\83ιμο</string>
+  <string name="uploader_wrn_no_account_quit_btn_text">Î\88ξοδοÏ\82</string>
   <string name="uploader_wrn_no_content_title">Δεν υπάρχει περιεχόμενο για να μεταφορτώσετε</string>
   <string name="uploader_wrn_no_content_text">Δεν ελήφθη περιεχόμενο. Δεν υπάρχει τίποτα να μεταφορτώσετε.</string>
-  <string name="uploader_error_forbidden_content">Το %1$s δεν επιτρέπεται να έχει πρόσβαση στο κοινόχρηστο περιεχόμενο</string>
+  <string name="uploader_error_forbidden_content">Î\9f %1$s δεν επιτρέπεται να έχει πρόσβαση στο κοινόχρηστο περιεχόμενο</string>
   <string name="uploader_info_uploading">Μεταφόρτωση</string>
-  <string name="file_list_empty">Δεν υπάρχουν αρχεία σε αυτόν τον φάκελο.\nΝέα αρχεία μπορούν να προστεθούν με την επιλογή \"Μεταφόρτωση\" του μενού.</string>
+  <string name="file_list_empty">Δεν υπάρχει τίποτα εδώ. Ανεβάστε κάτι!</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_modified">Τροποποιήθηκε:</string>
   <string name="filedetails_download">Λήψη</string>
   <string name="filedetails_sync_file">Ανανέωση αρχείου</string>
-  <string name="filedetails_renamed_in_upload_msg">Το αρχείο μετονομάστηκε σε %1$s κατά την μεταφόρτωση</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">Î\91κÏ\8dÏ\81Ï\89Ï\83η Î±Ï\80οÏ\83Ï\84ολής</string>
+  <string name="common_cancel_upload">Î\91κÏ\8dÏ\81Ï\89Ï\83η Î¼ÎµÏ\84αÏ\86Ï\8cÏ\81Ï\84Ï\89Ï\83ης</string>
   <string name="common_cancel">Άκυρο</string>
   <string name="common_save_exit">Αποθήκευση &amp; Έξοδος</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="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_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="downloader_download_in_progress_ticker">Κατέβασμα ...</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">Το ÎºÎ±Ï\84έβαÏ\83μα ολοκληρώθηκε επιτυχώς</string>
+  <string name="downloader_download_succeeded_ticker">Î\97 Î»Î®Ï\88η ολοκληρώθηκε επιτυχώς</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_ticker">Η λήψη απέτυχε</string>
+  <string name="downloader_download_failed_content">Η λήψη του %1$s δεν μπόρεσε να ολοκληρωθεί</string>
+  <string name="downloader_not_downloaded_yet">Δεν έχει ληφθεί ακόμα</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="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_conflicts_in_favourites_content">%1$d αρχεία σε αναμονή συγχρονισμού, δεν μπόρεσαν να συγχρονιστούν</string>
+  <string name="sync_conflicts_in_favourites_ticker">Βρέθηκαν συγκρούσεις</string>
+  <string name="sync_conflicts_in_favourites_content">%1$d αρχεία σε αναμονή συγχρονισμού δεν μπόρεσαν να συγχρονιστούν</string>
   <string name="sync_fail_in_favourites_ticker">Τα αρχεία σε αναμονή συγχρονισμού απέτυχαν</string>
   <string name="sync_fail_in_favourites_content">Τα περιεχόμενα των %1$d αρχείων δεν μπόρεσαν να συγχρονιστούν (%2$d διενέξεις)</string>
   <string name="sync_foreign_files_forgotten_ticker">Ορισμένα τοπικά αρχεία ξεχάστηκαν</string>
-  <string name="sync_foreign_files_forgotten_content">%1$d αρχεια απο τον %2$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">Remote: %1$s</string>
-  <string name="upload_query_move_foreign_files">Δεν υπαρχει αρκετος χωρος για να αντιγραφθουν τα επιλεγμενα αρχεια στον χωρο αποθηκευσης  %1$s. Θελετε να μετακινηθουν μερικα?</string>
-  <string name="pincode_enter_pin_code">Παρακαλώ, εισάγετε το PIN σας</string>
+  <string name="sync_foreign_files_forgotten_content">%1$d αρχεία από τον %2$s χώρο αποθήκευσης δεν ήταν δυνατό να αντιγραφούν σε</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">Παρακαλώ, εισάγετε το PIN εφαρμογής σας</string>
   <string name="pincode_configure_your_pin">Εισάγετε το PIN της εφαρμογής</string>
-  <string name="pincode_configure_your_pin_explanation">Το PIN Î¸Î± Î¶Î·Ï\84είÏ\84αι ÎºÎ¬Î¸Îµ Ï\86οÏ\81ά Ï\83Ï\84ην ÎµÎºÎºÎ¯Î½Î·Ï\83η </string>
-  <string name="pincode_reenter_your_pincode">ΠαÏ\81ακαλÏ\8e ÎµÏ\80αναειÏ\83άγεÏ\84ε Ï\84ο PIN Ï\84ηÏ\82 ÎµÏ\86αÏ\81μογήÏ\82</string>
+  <string name="pincode_configure_your_pin_explanation">Το PIN Î¸Î± Î¶Î·Ï\84είÏ\84αι ÎºÎ¬Î¸Îµ Ï\86οÏ\81ά Ï\80οÏ\85 ÎµÎºÎºÎ¹Î½ÎµÎ¯Ï\84αι Î· ÎµÏ\86αÏ\81μογή</string>
+  <string name="pincode_reenter_your_pincode">Παρακαλώ επανεισάγετε το PIN της εφαρμογής</string>
   <string name="pincode_remove_your_pincode">Αφαιρέστε τον PIN της εφαρμογής</string>
   <string name="pincode_mismatch">Δεν ταιριάζουν τα PIN της εφαρμογής </string>
   <string name="pincode_wrong">Εσφαλμένο PIN της εφαρμογής</string>
   <string name="pincode_removed">Αφαιρέθηκε το PIN της εφαρμογής</string>
   <string name="pincode_stored">Το PIN της εφαρμογής αποθηκεύτηκε</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_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_testing_connection">Έλεγχος σύνδεσης...</string>
-  <string name="auth_not_configured_title">Λανθασμένες ρυθμίσεις </string>
-  <string name="auth_unknown_error_title">Παρουσιάστηκε άγνωστο σφάλμα</string>
-  <string name="auth_unknown_host_title">Δεν βρέθηκε υπολογιστής</string>
-  <string name="auth_incorrect_path_title">Δεν βρέθηκε στιγμιότυπο server σας</string>
-  <string name="auth_timeout_title">Ο εξυπηρετητής αργεί πολύ να απαντήσει</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">Κακώς διατυπωμένο URL</string>
   <string name="auth_ssl_general_error_title">Η αρχικοποίηση του SLL απέτυχε</string>
-  <string name="auth_bad_oc_version_title">Μη αναγνωρίσιμη έκδοση διακομιστή server σας</string>
+  <string name="auth_ssl_unverified_server_title">Αδυναμία επιβεβαίωσης της ταυτότητας του διακομιστή SSL </string>
+  <string name="auth_bad_oc_version_title">Μη-αναγνωρίσιμη έκδοση διακομιστή</string>
   <string name="auth_wrong_connection_title">Δεν ήταν δυνατή η σύνδεση</string>
   <string name="auth_secure_connection">Επιτεύχθηκε ασφαλής σύνδεση</string>
   <string name="auth_unauthorized">Λάθος όνομα χρήστη ή κωδικός</string>
   <string name="auth_oauth_error">Η πιστοποίηση απέτυχε</string>
-  <string name="auth_expired_basic_auth_toast">Παρακαλώ είσάγετε τον τρέχοντα κωδικό</string>
-  <string name="fd_keep_in_sync">Διατήρηση αρχείου ενημερωμένo</string>
+  <string name="auth_oauth_error_access_denied">Ο διακομιστής πιστοποίησης αρνήθηκε την πρόσβαση</string>
+  <string name="auth_wtf_reenter_URL">Απρόοπτη κατάσταση - παρακαλώ εισάγετε τη διεύθυνση 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="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_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">Î\91Ï\86αίÏ\81εÏ\83η Î±Ï\80Ï\8c Ï\84ο ÎµÎ¾Ï\85Ï\80ηÏ\81έÏ\84η</string>
-  <string name="confirmation_remove_remote_and_local">Î\9aαι Î±πομακρυσμένα και τοπικά</string>
-  <string name="remove_success_msg">Î\95Ï\80ιÏ\84Ï\85Ï\87ημένη Î±Ï\86αίÏ\81εÏ\83η</string>
-  <string name="remove_fail_msg">Î\97 Î±Ï\86αίÏ\81εÏ\83η Î´ÎµÎ½ Î¼Ï\80οÏ\81εί Î½Î± Î¿Î»Î¿ÎºÎ»Î·Ï\81Ï\89θεί</string>
+  <string name="confirmation_remove_folder_local">Μόνο τοπικό περιεχόμενο</string>
+  <string name="confirmation_remove_remote">Î\91Ï\86αίÏ\81εÏ\83η Î±Ï\80Ï\8c Ï\84ο Î´Î¹Î±ÎºÎ¿Î¼Î¹Ï\83Ï\84ή</string>
+  <string name="confirmation_remove_remote_and_local">Î\91πομακρυσμένα και τοπικά</string>
+  <string name="remove_success_msg">Î\91Ï\86αίÏ\81εÏ\83η ÎµÏ\80ιÏ\84Ï\85Ï\87ήÏ\82</string>
+  <string name="remove_fail_msg">Î\97 Î±Ï\86αίÏ\81εÏ\83η Î±Ï\80έÏ\84Ï\85Ï\87ε</string>
   <string name="rename_dialog_title">Εισάγετε νέο όνομα</string>
-  <string name="rename_local_fail_msg">Το Ï\84οÏ\80ικÏ\8c Î±Î½Ï\84ίγÏ\81αÏ\86ο Î´ÎµÎ½ Î®Ï\84αν Î´Ï\85ναÏ\84Ï\8cν Î½Î± Î¼ÎµÏ\84ονομαÏ\83Ï\84εί. Î Î±Ï\81ακαλÏ\8e ÎµÏ\80ιλέξÏ\84ε Î½Î­Î¿ Ï\8cνομα. </string>
+  <string name="rename_local_fail_msg">Το Ï\84οÏ\80ικÏ\8c Î±Î½Ï\84ίγÏ\81αÏ\86ο Î´ÎµÎ½ Î®Ï\84αν Î´Ï\85ναÏ\84Ï\8cν Î½Î± Î¼ÎµÏ\84ονομαÏ\83Ï\84εί. Î Î±Ï\81ακαλÏ\8e ÎµÏ\80ιλέξÏ\84ε Î­Î½Î± Î´Î¹Î±Ï\86οÏ\81εÏ\84ικÏ\8c Ï\8cνομα.</string>
   <string name="rename_server_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="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_unexpected_bad_get_content">Απροσδόκητο σφάλμα, δοκιμάστε με άλλη εφαρμογή</string>
+  <string name="filedisplay_unexpected_bad_get_content">Απροσδόκητο σφάλμα - παρακαλώ επιλέξτε το αρχείο από μια άλλη εφαρμογή</string>
   <string name="filedisplay_no_file_selected">Δεν επιλέχθηκαν αρχεία </string>
-  <string name="ssl_validator_header">Η ταυτότητα της σελίδας δεν μπορεί να εγκριθεί</string>
-  <string name="ssl_validator_reason_cert_not_trusted">- Το πιστοποιητικό του διακομιστή δεν είναι αξιόπιστο</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">- Το πιστοποιητικό του διακομιστή δεν είναι έμπιστο</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">- Η διεύθυνση URL δεν ταιριάζει με το όνομα στο πιστοποιητικό</string>
-  <string name="ssl_validator_question">Θέλετε να θεωρείται έμπιστο το πιστοποιητικό αυτό ούτως ή άλλως;</string>
+  <string name="ssl_validator_reason_hostname_not_verified">- Î\97 Î´Î¹ÎµÏ\8dθÏ\85νÏ\83η URL Î´ÎµÎ½ Ï\84αιÏ\81ιάζει Î¼Îµ Ï\84ο Ï\8cνομα Ï\84οÏ\85 ÎºÏ\8cμβοÏ\85 Ï\83Ï\84ο Ï\80ιÏ\83Ï\84οÏ\80οιηÏ\84ικÏ\8c</string>
+  <string name="ssl_validator_question">Θέλετε να θεωρείται έμπιστο το πιστοποιητικό αυτό παρ\' όλα αυτά;</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_subject">Εκδόθηκε για:</string>
   <string name="ssl_validator_label_issuer">Εκδόθηκε από:</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">Χώρα:</string>
-  <string name="ssl_validator_label_ST">Πολιτεία</string>
+  <string name="ssl_validator_label_ST">Πολιτεία:</string>
   <string name="ssl_validator_label_L">Τοποθεσία:</string>
-  <string name="ssl_validator_label_validity">Î\95γκÏ\85Ï\81Ï\8cÏ\84ηÏ\84α:</string>
+  <string name="ssl_validator_label_validity">ΠεÏ\81ίοδοÏ\82 Î¹Ï\83Ï\87Ï\8dοÏ\82:</string>
   <string name="ssl_validator_label_validity_from">Από:</string>
-  <string name="ssl_validator_label_validity_to">Μέχρι</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">placeholder.txt</string>
   <string name="placeholder_filetype">Εικόνα PNG</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_video_upload_on_wifi">Μεταφόρτωση βίντεο μόνο μέσω WiFi</string>
   <string name="instant_upload_path">/InstantUpload</string>
-  <string name="conflict_title">Î\95νημέÏ\81Ï\89Ï\83η Ï\83Ï\8dγκÏ\81οÏ\85Ï\83ηÏ\82</string>
-  <string name="conflict_message">Το απομακρυσμένο αρχείο %s δεν είναι συγχρονισμένο με το τοπικό. Η συνέχεια θα αντικαταστήσει το περιεχόμενο του αρχείου στον εξυπηρέτη. </string>
+  <string name="conflict_title">ΣÏ\8dγκÏ\81οÏ\85Ï\83η ÎµÎ½Î·Î¼ÎµÏ\81Ï\8eÏ\83εÏ\89ν</string>
+  <string name="conflict_message">Το απομακρυσμένο αρχείο %s δεν είναι συγχρονισμένο με το τοπικό αρχείο. Αν συνεχίσετε θα αντικατασταθεί το περιεχόμενο του αρχείου στο διακομιστή. </string>
   <string name="conflict_keep_both">Διατήρηση και των δύο</string>
   <string name="conflict_overwrite">Αντικατάσταση</string>
-  <string name="conflict_dont_upload">Î\94εν Î¼ÎµÏ\84αÏ\86οÏ\81Ï\84Ï\8eθηκε</string>
+  <string name="conflict_dont_upload">Î\9dα Î¼Î·Î½ Î¼ÎµÏ\84αÏ\86οÏ\81Ï\84Ï\89θεί</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="failed_upload_all_cb">επιλογή όλων</string>
-  <string name="failed_upload_load_more_images">Φόρτωση περισσότερων εικόνων</string>
-  <string name="failed_upload_failure_text">Μήνυμα Αποτυχίας:</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="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_mail_subject">αρχεία καταγραφής της εφαρμογής ownCloud 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="file_list_empty_moving">Δεν υπάρχει τίποτα εδώ. Μπορείτε να προσθέσετε ένα φάκελο!</string>
+  <string name="move_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>
 </resources>
index 678df10..320d1e6 100644 (file)
@@ -7,17 +7,20 @@
   <string name="actionbar_upload_from_apps">Content from other apps</string>
   <string name="actionbar_upload_files">Files</string>
   <string name="actionbar_open_with">Open with</string>
-  <string name="actionbar_mkdir">Create directory</string>
+  <string name="actionbar_mkdir">New folder</string>
   <string name="actionbar_settings">Settings</string>
   <string name="actionbar_see_details">Details</string>
+  <string name="actionbar_send_file">Send</string>
   <string name="prefs_category_general">General</string>
   <string name="prefs_category_more">More</string>
   <string name="prefs_accounts">Accounts</string>
   <string name="prefs_manage_accounts">Manage Accounts</string>
   <string name="prefs_pincode">App PIN</string>
   <string name="prefs_pincode_summary">Protect your client</string>
-  <string name="prefs_instant_upload">Enable instant uploads</string>
-  <string name="prefs_instant_upload_summary">Instantly upload photos taken by camera</string>
+  <string name="prefs_instant_upload">Instant picture uploads</string>
+  <string name="prefs_instant_upload_summary">Instantly upload pictures taken by camera</string>
+  <string name="prefs_instant_video_upload">Instant video uploads</string>
+  <string name="prefs_instant_video_upload_summary">Instantly upload videos recorded by camera</string>
   <string name="prefs_log_title">Enable Logging</string>
   <string name="prefs_log_summary">This is used to log problems</string>
   <string name="prefs_log_title_history">Logging History</string>
   <string name="recommend_subject">Try %1$s on your smartphone!</string>
   <string name="recommend_text">I want to invite you to use %1$s on your smartphone!\nDownload here: %2$s</string>
   <string name="auth_check_server">Check Server</string>
-  <string name="auth_host_url">Server address</string>
+  <string name="auth_host_url">Server address https://…</string>
   <string name="auth_username">Username</string>
   <string name="auth_password">Password</string>
   <string name="auth_register">New to %1$s?</string>
   <string name="sync_string_files">Files</string>
   <string name="setup_btn_connect">Connect</string>
   <string name="uploader_btn_upload_text">Upload</string>
-  <string name="uploader_top_message">Choose upload directory:</string>
+  <string name="uploader_top_message">Choose upload folder:</string>
   <string name="uploader_wrn_no_account_title">No account found</string>
   <string name="uploader_wrn_no_account_text">There are no %1$s accounts on your device. Please setup an account first.</string>
   <string name="uploader_wrn_no_account_setup_btn_text">Setup</string>
@@ -46,7 +49,9 @@
   <string name="uploader_wrn_no_content_text">No content was received. Nothing to upload.</string>
   <string name="uploader_error_forbidden_content">%1$s is not allowed to access the shared content</string>
   <string name="uploader_info_uploading">Uploading</string>
-  <string name="file_list_empty">There are no files in this folder.\nNew files can be added with the \"Upload\" menu option.</string>
+  <string name="file_list_empty">Nothing in here. Upload something!</string>
+  <string name="file_list_loading">Loading...</string>
+  <string name="local_file_list_empty">There are no files in this folder.</string>
   <string name="filedetails_select_file">Tap on a file to display additional information.</string>
   <string name="filedetails_size">Size:</string>
   <string name="filedetails_type">Type:</string>
@@ -55,6 +60,8 @@
   <string name="filedetails_download">Download</string>
   <string name="filedetails_sync_file">Refresh file</string>
   <string name="filedetails_renamed_in_upload_msg">File was renamed to %1$s during upload</string>
+  <string name="action_share_file">Share link</string>
+  <string name="action_unshare_file">Unshare link</string>
   <string name="common_yes">Yes</string>
   <string name="common_no">No</string>
   <string name="common_ok">OK</string>
   <string name="delete_account">Delete account</string>
   <string name="create_account">Create account</string>
   <string name="upload_chooser_title">Upload from …</string>
-  <string name="uploader_info_dirname">Directory name</string>
+  <string name="uploader_info_dirname">Folder name</string>
   <string name="uploader_upload_in_progress_ticker">Uploading …</string>
   <string name="uploader_upload_in_progress_content">%1$d%% Uploading %2$s</string>
   <string name="uploader_upload_succeeded_ticker">Upload succeeded</string>
   <string name="uploader_upload_succeeded_content_single">%1$s was successfully uploaded</string>
   <string name="uploader_upload_failed_ticker">Upload failed</string>
   <string name="uploader_upload_failed_content_single">Upload of %1$s could not be completed</string>
+  <string name="uploader_upload_failed_credentials_error">Upload failed, you need to login again</string>
   <string name="downloader_download_in_progress_ticker">Downloading …</string>
   <string name="downloader_download_in_progress_content">%1$d%% Downloading %2$s</string>
   <string name="downloader_download_succeeded_ticker">Download succeeded</string>
   <string name="downloader_download_failed_ticker">Download failed</string>
   <string name="downloader_download_failed_content">Download of %1$s could not be completed</string>
   <string name="downloader_not_downloaded_yet">Not downloaded yet</string>
+  <string name="downloader_download_failed_credentials_error">Download failed, you need to login again</string>
   <string name="common_choose_account">Choose account</string>
   <string name="sync_fail_ticker">Synchronisation failed</string>
+  <string name="sync_fail_ticker_unauthorized">Synchronisation failed, you need to relogin</string>
   <string name="sync_fail_content">Synchronisation of %1$s could not be completed</string>
   <string name="sync_fail_content_unauthorized">Invalid password for %1$s</string>
   <string name="sync_conflicts_in_favourites_ticker">Conflicts found</string>
   <string name="sync_fail_in_favourites_ticker">Kept-in-sync files failed</string>
   <string name="sync_fail_in_favourites_content">Contents of %1$d files could not be synced (%2$d conflicts)</string>
   <string name="sync_foreign_files_forgotten_ticker">Some local files were forgotten</string>
-  <string name="sync_foreign_files_forgotten_content">%1$d files out of the %2$s directory could not be copied into</string>
-  <string name="sync_foreign_files_forgotten_explanation">As of version 1.3.16, files uploaded from this device are copied into the local %1$s folder to prevent data loss when a single file is synced with multiple accounts.\n\nDue to this change, all files uploaded in previous versions of this app were copied into the %2$s folder. However, an error prevented the completion of this operation during account synchronisation. You may either leave the file(s) as is and remove the link to %3$s, or move the file(s) into the %1$s directory and retain the link to %4$s.\n\nListed below are the local file(s), and the the remote file(s) in %5$s they were linked to.</string>
+  <string name="sync_foreign_files_forgotten_content">%1$d files out of the %2$s folder could not be copied into</string>
+  <string name="sync_foreign_files_forgotten_explanation">As of version 1.3.16, files uploaded from this device are copied into the local %1$s folder to prevent data loss when a single file is synced with multiple accounts.\n\nDue to this change, all files uploaded in previous versions of this app were copied into the %2$s folder. However, an error prevented the completion of this operation during account synchronisation. You may either leave the file(s) as is and remove the link to %3$s, or move the file(s) into the %1$s folder and retain the link to %4$s.\n\nListed below are the local file(s), and the remote file(s) in %5$s they were linked to.</string>
   <string name="sync_current_folder_was_removed">Folder %1$s does not exist anymore</string>
   <string name="foreign_files_move">Move all</string>
   <string name="foreign_files_success">All files were moved</string>
   <string name="media_rewind_description">Rewind button</string>
   <string name="media_play_pause_description">Play or pause button</string>
   <string name="media_forward_description">Fast-forward button</string>
+  <string name="auth_getting_authorization">Getting authorisation…</string>
   <string name="auth_trying_to_login">Trying to login…</string>
   <string name="auth_no_net_conn_title">No network connection</string>
   <string name="auth_nossl_plain_ok_title">Secure connection unavailable.</string>
   <string name="auth_connecting_auth_server">Connecting to authentication server…</string>
   <string name="auth_unsupported_auth_method">The server does not support this authentication method</string>
   <string name="auth_unsupported_multiaccount">%1$s does not support multiple accounts</string>
+  <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="fd_keep_in_sync">Keep file up to date</string>
   <string name="common_rename">Rename</string>
   <string name="common_remove">Remove</string>
-  <string name="confirmation_remove_alert">Do you really want to remove %1$s ?</string>
-  <string name="confirmation_remove_folder_alert">Do you really want to remove %1$s and its contents ?</string>
+  <string name="confirmation_remove_alert">Do you really want to remove %1$s?</string>
+  <string name="confirmation_remove_folder_alert">Do you really want to remove %1$s and its contents?</string>
   <string name="confirmation_remove_local">Local only</string>
   <string name="confirmation_remove_folder_local">Local contents only</string>
   <string name="confirmation_remove_remote">Remove from server</string>
   <string name="rename_server_fail_msg">Rename could not be completed</string>
   <string name="sync_file_fail_msg">Remote file could not be checked</string>
   <string name="sync_file_nothing_to_do_msg">File contents already synchronised</string>
-  <string name="create_dir_fail_msg">Directory could not be created</string>
+  <string name="create_dir_fail_msg">Folder could not be created</string>
+  <string name="filename_forbidden_characters">Forbidden characters: / \\ &lt; &gt; : \" | ? *</string>
+  <string name="filename_empty">File name cannot be empty</string>
   <string name="wait_a_moment">Wait a moment</string>
   <string name="filedisplay_unexpected_bad_get_content">Unexpected problem; please select the file from a different app</string>
   <string name="filedisplay_no_file_selected">No file was selected</string>
+  <string name="activity_chooser_title">Send link to …</string>
   <string name="oauth_check_onoff">Log in with oAuth2</string>
   <string name="oauth_login_connection">Connecting to oAuth2 server…</string>
   <string name="ssl_validator_header">The identity of the site could not be verified</string>
   <string name="ssl_validator_label_validity_to">To:</string>
   <string name="ssl_validator_label_signature">Signature:</string>
   <string name="ssl_validator_label_signature_algorithm">Algorithm:</string>
+  <string name="ssl_validator_null_cert">The certificate could not be shown.</string>
+  <string name="ssl_validator_no_info_about_error">- No information about the error</string>
   <string name="placeholder_sentence">This is a placeholder</string>
   <string name="placeholder_filename">placeholder.txt</string>
   <string name="placeholder_filetype">PNG Image</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">Upload pictures via WiFi only</string>
+  <string name="instant_video_upload_on_wifi">Upload videos via WiFi only</string>
   <string name="instant_upload_path">/InstantUpload</string>
   <string name="conflict_title">Update conflict</string>
   <string name="conflict_message">Remote file %s is not synchronised with local file. Continuing will replace content of file on server.</string>
   <string name="conflict_dont_upload">Don\'t upload</string>
   <string name="preview_image_description">Image preview</string>
   <string name="preview_image_error_unknown_format">This image cannot be shown</string>
-  <string name="error__upload__local_file_not_copied">%1$s could not be copied to %2$s local directory</string>
-  <string name="actionbar_failed_instant_upload">Failed InstantUpload\"</string>
-  <string name="failed_upload_headline_text">Failed instant uploads</string>
-  <string name="failed_upload_headline_hint">Summary of all failed instant uploads</string>
-  <string name="failed_upload_all_cb">select all</string>
-  <string name="failed_upload_headline_retryall_btn">retry all selected</string>
-  <string name="failed_upload_headline_delete_all_btn">delete all  selected from uploadqueue</string>
-  <string name="failed_upload_retry_text">retry uploading the image: </string>
-  <string name="failed_upload_load_more_images">Load more Pictures</string>
-  <string name="failed_upload_retry_do_nothing_text">do nothing you are not online for instant upload</string>
-  <string name="failed_upload_failure_text">Failure Message: </string>
-  <string name="failed_upload_quota_exceeded_text">Please check your server configuration, perhaps your quota is exceeded.</string>
+  <string name="error__upload__local_file_not_copied">%1$s could not be copied to %2$s local folder</string>
+  <string name="prefs_instant_upload_path_title">Upload Path</string>
+  <string name="share_link_no_support_share_api">Sorry, sharing is not enabled on your server. Please contact your
+               administrator.</string>
+  <string name="share_link_file_no_exist">Unable to share. Please check whether the file exists</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="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="error_cant_bind_to_operations_service">Critical error: cannot perform operations</string>
+  <string name="network_error_socket_exception">An error occurred whilst connecting to the server.</string>
+  <string name="network_error_socket_timeout_exception">An error occurred whilst waiting for the server, the operation couldn\'t be done</string>
+  <string name="network_error_connect_timeout_exception">An error occurred whilst waiting for the server, the operation couldn\'t been done</string>
+  <string name="network_host_not_available">The operation couldn\'t be completed, server is unavailable</string>
+  <string name="empty"></string>
+  <string name="forbidden_permissions">You do not have permission %s</string>
+  <string name="forbidden_permissions_rename">to rename this file</string>
+  <string name="forbidden_permissions_delete">to delete this file</string>
+  <string name="share_link_forbidden_permissions">to share this file</string>
+  <string name="unshare_link_forbidden_permissions">to unshare this file</string>
+  <string name="forbidden_permissions_create">to create the file</string>
+  <string name="uploader_upload_forbidden_permissions">to upload to this folder</string>
+  <string name="downloader_download_file_not_found">The file is no longer available on the server</string>
+  <string name="prefs_category_accounts">Accounts</string>
+  <string name="prefs_add_account">Add account</string>
+  <string name="auth_redirect_non_secure_connection_title">Secure connection is redirected to an unsecured route.</string>
+  <string name="actionbar_logger">Logs</string>
+  <string name="log_send_history_button">Send History</string>
+  <string name="log_mail_subject">ownCloud Android app logs</string>
+  <string name="log_progress_dialog_text">Loading data...</string>
+  <string name="saml_authentication_required_text">Authentication required</string>
+  <string name="saml_authentication_wrong_pass">Incorrect password</string>
+  <string name="actionbar_move">Move</string>
+  <string name="file_list_empty_moving">Nothing in here. You can add a folder!</string>
+  <string name="move_choose_button_text">Choose</string>
+  <string name="move_file_not_found">Unable to move. Please check whether the file exists</string>
+  <string name="move_file_invalid_into_descendent">It is not possible to move a folder into a descendant</string>
+  <string name="move_file_invalid_overwrite">The file exists already in the destination folder</string>
+  <string name="move_file_error">An error occurred whilst trying to move this file or folder</string>
+  <string name="forbidden_permissions_move">to move this file</string>
+  <string name="prefs_category_instant_uploading">Instant Uploads</string>
+  <string name="prefs_category_security">Security</string>
 </resources>
diff --git a/res/values-en-rNZ/strings.xml b/res/values-en-rNZ/strings.xml
new file mode 100644 (file)
index 0000000..56e55a1
--- /dev/null
@@ -0,0 +1,4 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<resources>
+  <string name="empty"></string>
+</resources>
index debd294..2b4413c 100644 (file)
@@ -1,26 +1,31 @@
 <?xml version='1.0' encoding='UTF-8'?>
 <resources>
+  <string name="about_android">Android-aplikaĵo %1$s</string>
+  <string name="about_version">eldono %1$s</string>
   <string name="actionbar_upload">Alŝuti dosieron</string>
   <string name="actionbar_upload_from_apps">Enhavo el aliaj aplikaĵoj</string>
   <string name="actionbar_upload_files">Dosieroj</string>
-  <string name="actionbar_mkdir">Krei dosierujon</string>
+  <string name="actionbar_open_with">Malfermi per</string>
+  <string name="actionbar_mkdir">Nova dosierujo</string>
   <string name="actionbar_settings">Agordo</string>
   <string name="actionbar_see_details">Detaloj</string>
+  <string name="actionbar_send_file">Sendi</string>
   <string name="prefs_category_general">Ĝeneralo</string>
   <string name="prefs_category_more">Pli</string>
   <string name="prefs_accounts">Kontoj</string>
   <string name="prefs_manage_accounts">Administri kontojn</string>
   <string name="prefs_pincode">PIN de App-aplikaĵo</string>
   <string name="prefs_pincode_summary">Protekti vian klienton</string>
-  <string name="prefs_instant_upload">Kapabligi tujan alŝuton</string>
-  <string name="prefs_instant_upload_summary">Tuje alŝuti fotojn faritajn per fotilo</string>
   <string name="prefs_help">Helpo</string>
-  <string name="auth_host_url">Servila adreso</string>
+  <string name="prefs_recommend">Rekomendi al amiko</string>
+  <string name="auth_check_server">Kontroli servilon</string>
+  <string name="auth_host_url">Servila adreso https://...</string>
   <string name="auth_username">Uzantonomo</string>
   <string name="auth_password">Pasvorto</string>
   <string name="sync_string_files">Dosieroj</string>
   <string name="setup_btn_connect">Konekti</string>
   <string name="uploader_btn_upload_text">Alŝuti</string>
+  <string name="uploader_top_message">Elektu alŝutan dosierujon:</string>
   <string name="uploader_wrn_no_account_title">Neniu konto troviĝis</string>
   <string name="uploader_wrn_no_account_text">Estas neniu $1%s-konto en via aparato. Bonvolu agordi konton unue.</string>
   <string name="uploader_wrn_no_account_setup_btn_text">Agordi</string>
   <string name="uploader_wrn_no_content_text">Neniu enhavo riceviĝis. Nenio alŝutota.</string>
   <string name="uploader_error_forbidden_content">$1%s ne estas permesata aliri la kunhavigitan enhavon</string>
   <string name="uploader_info_uploading">Alŝutante</string>
-  <string name="file_list_empty">Neniu dosiero estas en ĉi tiu dosierujo.\nNovajn dosierojn vi povas aldoni per la menuero “Alŝuti”.</string>
+  <string name="file_list_empty">Nenio estas ĉi tie. Alŝutu ion!</string>
   <string name="filedetails_size">Grando:</string>
   <string name="filedetails_type">Tipo:</string>
   <string name="filedetails_created">Kreita je:</string>
   <string name="filedetails_modified">Modifita je:</string>
   <string name="filedetails_download">Elŝuti</string>
   <string name="filedetails_renamed_in_upload_msg">La dosiero alinomiĝis al %1$s dum alŝuto</string>
+  <string name="action_share_file">Konhavigi ligilon</string>
+  <string name="action_unshare_file">Malkunhavigi ligilon</string>
   <string name="common_yes">Jes</string>
   <string name="common_no">Ne</string>
   <string name="common_ok">Akcepti</string>
@@ -44,6 +51,7 @@
   <string name="common_cancel">Nuligi</string>
   <string name="common_save_exit">Konservi kaj forlasi</string>
   <string name="common_error">Eraro</string>
+  <string name="common_loading">Ŝargante...</string>
   <string name="common_error_unknown">Nekonata eraro</string>
   <string name="about_title">Pri</string>
   <string name="change_password">Ŝanĝi la pasvorton</string>
   <string name="uploader_upload_succeeded_content_single">%1$s sukcese alŝutiĝis</string>
   <string name="uploader_upload_failed_ticker">Alŝuto malsukcesis</string>
   <string name="uploader_upload_failed_content_single">Alŝuto de %1s ne eblis plenumiĝi</string>
+  <string name="uploader_upload_failed_credentials_error">Alŝuto malsukcesis, vi devas reensaluti</string>
   <string name="downloader_download_in_progress_ticker">Elŝutante...</string>
   <string name="downloader_download_in_progress_content">%1$d%% Elŝutante %2$s</string>
   <string name="downloader_download_succeeded_ticker">Elŝuto sukcesis</string>
   <string name="downloader_download_succeeded_content">%1$s sukcese elŝutiĝis</string>
   <string name="downloader_download_failed_ticker">Elŝuto malsukcesis</string>
   <string name="downloader_download_failed_content">Elŝuto de %1$s ne eblis plenumiĝi</string>
+  <string name="downloader_not_downloaded_yet">Ankoraŭ ne elŝutita</string>
+  <string name="downloader_download_failed_credentials_error">Elŝuto malsukcesis, vi devas reensaluti</string>
   <string name="common_choose_account">Elekti konton</string>
   <string name="sync_fail_ticker">Sinkronigo malsukcesis</string>
   <string name="sync_fail_content">Sinkronigo de %1$s ne povis plenumiĝi</string>
+  <string name="sync_fail_content_unauthorized">Nevalida pasvorto por %1$s</string>
   <string name="sync_conflicts_in_favourites_ticker">Konfliktoj troviĝis</string>
   <string name="sync_conflicts_in_favourites_content">%1$d ade sinkronigataj dosieroj ne povis sinkroniĝi</string>
   <string name="sync_fail_in_favourites_ticker">Malsukcesis ada sinkronigo de dosieroj</string>
   <string name="sync_fail_in_favourites_content">Enhavoj de %1$d dosieroj ne povis sinkroniĝi (%2$d konfliktas)</string>
+  <string name="sync_foreign_files_forgotten_ticker">Iuj lokaj dosieroj forgesiĝis</string>
+  <string name="sync_current_folder_was_removed">La dosierujo %1$s ne plu ekzistas</string>
+  <string name="foreign_files_move">Movi ĉion</string>
+  <string name="foreign_files_success">Ĉiuj dosieroj moviĝis</string>
+  <string name="foreign_files_fail">Iuj dosieroj ne povis moviĝi</string>
+  <string name="foreign_files_local_text">Loka: %1$s</string>
+  <string name="foreign_files_remote_text">Malloka: %1$s</string>
   <string name="pincode_enter_pin_code">Bonvolu enigi vian PIN-on de aplikaĵo</string>
   <string name="pincode_configure_your_pin">Enigu PIN-on de aplikaĵo</string>
   <string name="pincode_reenter_your_pincode">Bonvolu reenigi PIN-on de aplikaĵo</string>
@@ -78,6 +97,9 @@
   <string name="pincode_wrong">Malĝusta PIN de aplikaĵo</string>
   <string name="pincode_removed">PIN de aplikaĵo foriĝis</string>
   <string name="pincode_stored">PIN de aplikaĵo konserviĝis</string>
+  <string name="media_state_playing">%1$s (ludanta)</string>
+  <string name="media_state_loading">%1$s (ŝarganta)</string>
+  <string name="auth_getting_authorization">Ekhavante rajtigon...</string>
   <string name="auth_trying_to_login">Provante ensaluti...</string>
   <string name="auth_no_net_conn_title">Neniu reta konekto</string>
   <string name="auth_nossl_plain_ok_title">Sekura konekto ne haveblas.</string>
   <string name="auth_bad_oc_version_title">Nerekonita eldono de servilo</string>
   <string name="auth_wrong_connection_title">Ne eblis starigi konekton</string>
   <string name="auth_secure_connection">Sekura konekto stariĝis</string>
+  <string name="auth_unauthorized">Malĝusta uzantonomo aŭ pasvorto</string>
+  <string name="auth_oauth_error">Malsukcesa rajtigo</string>
+  <string name="auth_expired_basic_auth_toast">Bonvolu enigi la nunan pasvorton</string>
+  <string name="auth_connecting_auth_server">Konektante al aŭtentiga servilo...</string>
+  <string name="auth_unsupported_auth_method">La servilo ne kongruas kun ĉi tiu aŭtentiga metodo</string>
   <string name="fd_keep_in_sync">Teni dosieron ĝisdatigita</string>
   <string name="common_rename">Alinomigi</string>
   <string name="common_remove">Forigi</string>
   <string name="confirmation_remove_alert">Ĉu vi vere volas forigi %1$s?</string>
-  <string name="confirmation_remove_folder_alert">Ĉu vi vere volas forigi %1$s kaj sian enhavon?</string>
+  <string name="confirmation_remove_folder_alert">Ĉu vi vere volas forigi %1$s kaj ĝia enhavo?</string>
   <string name="confirmation_remove_local">Nur loka</string>
   <string name="confirmation_remove_folder_local">Nur lokaj enhavoj</string>
   <string name="confirmation_remove_remote">Forigi el la servilo</string>
   <string name="rename_server_fail_msg">Alinomigo ne povis plenumiĝi</string>
   <string name="sync_file_fail_msg">Malloka dosiero ne povis kontroliĝi</string>
   <string name="sync_file_nothing_to_do_msg">Dosierenhavoj jam sinkroniĝis</string>
-  <string name="create_dir_fail_msg">Dosierujo ne povis kreiĝi</string>
+  <string name="filename_forbidden_characters">Malpermesataj signoj: / \\ &lt; &gt; : \" | ? *</string>
+  <string name="filename_empty">Dosieronomo ne povas malpleni</string>
   <string name="wait_a_moment">Atendu momenton</string>
   <string name="filedisplay_unexpected_bad_get_content">Neatendita problemo; bonvolu provi alian aplikaĵon por elekti la dosieron</string>
   <string name="filedisplay_no_file_selected">Neniu dosiero elektiĝis</string>
+  <string name="activity_chooser_title">Sendi ligilon al...</string>
+  <string name="oauth_check_onoff">Ensaluti per oAuth2</string>
+  <string name="oauth_login_connection">Konektante al oAuth2-servilo...</string>
   <string name="ssl_validator_header">La idento de la ejo ne povis kontroliĝi</string>
   <string name="ssl_validator_reason_cert_not_trusted">- La servila atestilo ne fidindas</string>
   <string name="ssl_validator_reason_cert_expired">- La servila atestilo eksvalidiĝis</string>
   <string name="ssl_validator_label_signature">Subskribo:</string>
   <string name="ssl_validator_label_signature_algorithm">Algoritmo:</string>
   <string name="placeholder_sentence">Ĉi tio estas lokokupilo</string>
+  <string name="placeholder_filetype">PNG-bildo</string>
+  <string name="placeholder_filesize">389 KB</string>
+  <string name="placeholder_media_time">12:23:45</string>
   <string name="instant_upload_on_wifi">Alŝuti bildojn nur per WiFi</string>
   <string name="conflict_title">Alŝuta konflikto</string>
   <string name="conflict_message">La malloka dosiero %s estas ne sinkronigita kun loka dosiero. Se la ago daŭrus, enhavo de la dosiero en la servilo anstataŭiĝus.</string>
   <string name="conflict_keep_both">Konservi ambaŭ</string>
   <string name="conflict_overwrite">Anstataŭigi</string>
   <string name="conflict_dont_upload">Ne alŝuti</string>
+  <string name="preview_image_description">Antaŭvido de bildo</string>
+  <string name="preview_image_error_unknown_format">Ĉi tiu bildo ne povas montriĝi</string>
+  <string name="error__upload__local_file_not_copied">%1$s ne povis kopiiĝi al la loka dosierujo %2$s</string>
+  <string name="activity_chooser_send_file_title">Sendi</string>
+  <string name="copy_link">Kopii ligilon</string>
+  <string name="clipboard_text_copied">Kopiita en la tondejon</string>
+  <string name="network_error_socket_exception">Eraro okazis dum konekto al la servilo.</string>
+  <string name="empty"></string>
+  <string name="prefs_category_accounts">Kontoj</string>
+  <string name="saml_authentication_required_text">Aŭtentiĝo nepras</string>
+  <string name="saml_authentication_wrong_pass">Malĝusta pasvorto</string>
+  <string name="move_choose_button_text">Elekti</string>
+  <string name="prefs_category_security">Sekuro</string>
 </resources>
index f528665..780a604 100644 (file)
@@ -7,34 +7,39 @@
   <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">Crear directorio</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">Mandar</string>
   <string name="prefs_category_general">General</string>
   <string name="prefs_category_more">Más</string>
   <string name="prefs_accounts">Cuentas</string>
   <string name="prefs_manage_accounts">Gestionar cuentas</string>
   <string name="prefs_pincode">PIN de aplicación</string>
   <string name="prefs_pincode_summary">Protejé tu cliente</string>
-  <string name="prefs_instant_upload">Habilitar la subida inmediata</string>
-  <string name="prefs_instant_upload_summary">Subir inmediatamente las fotos sacadas con la cámara</string>
+  <string name="prefs_instant_upload">Subir fotos instantáneamente. </string>
+  <string name="prefs_instant_upload_summary">Subir instantáneamente fotos tomadas por la cámara.</string>
+  <string name="prefs_instant_video_upload">Subir videos instantáneamente. </string>
+  <string name="prefs_instant_video_upload_summary">Subir instantáneamente videos tomados por la cámara.</string>
   <string name="prefs_log_title">Habilitar registro</string>
   <string name="prefs_log_summary">Esto es usado para registrar problemas</string>
   <string name="prefs_log_title_history">Historia del Registro</string>
   <string name="prefs_log_summary_history">Esto muestra los registros grabados</string>
   <string name="prefs_log_delete_history_button">Eliminar Historial</string>
   <string name="prefs_help">Ayuda</string>
+  <string name="prefs_recommend">Recomendar a un amigo</string>
   <string name="prefs_feedback">Sugerencias</string>
   <string name="prefs_imprint">Imprint</string>
+  <string name="recommend_subject">¡Intento %1$s en tu teléfono inteligente!</string>
   <string name="auth_check_server">Verificar Servidor</string>
-  <string name="auth_host_url">Dirección del servidor</string>
+  <string name="auth_host_url">Dirección del servidor https://...</string>
   <string name="auth_username">Nombre de usuario</string>
   <string name="auth_password">Contraseña</string>
   <string name="auth_register">¿Sos nuevo para %1$s?</string>
   <string name="sync_string_files">Archivos</string>
   <string name="setup_btn_connect">Conectar</string>
   <string name="uploader_btn_upload_text">Subir</string>
-  <string name="uploader_top_message">Elegí el directorio de subida:</string>
+  <string name="uploader_top_message">Elija la carpeta de subida:</string>
   <string name="uploader_wrn_no_account_title">No se encontraron cuentas</string>
   <string name="uploader_wrn_no_account_text">No hay cuentas de %1$s en tu dispositivo. Creá una cuenta primero.</string>
   <string name="uploader_wrn_no_account_setup_btn_text">Configurar</string>
@@ -43,7 +48,9 @@
   <string name="uploader_wrn_no_content_text">No se recibió ningún contenido. No hay nada para subir.</string>
   <string name="uploader_error_forbidden_content">%1$s no está autorizado para acceder al contenido compartido</string>
   <string name="uploader_info_uploading">Subiendo</string>
-  <string name="file_list_empty">No hay archivos en este directorio.\nPodés agregar archivos a través de la opción del menú \"Subir\".</string>
+  <string name="file_list_empty">No hay nada. ¡Subí contenido!</string>
+  <string name="file_list_loading">Cargando...</string>
+  <string name="local_file_list_empty">No existen archivos en esta carpeta.</string>
   <string name="filedetails_select_file">Pulsá sobre un archivo para mostrar información adicional.</string>
   <string name="filedetails_size">Tamaño:</string>
   <string name="filedetails_type">Tipo:</string>
@@ -52,6 +59,8 @@
   <string name="filedetails_download">Descargar</string>
   <string name="filedetails_sync_file">Actualizar archivo</string>
   <string name="filedetails_renamed_in_upload_msg">El archivo fue renombrado como %1$s durante la subida</string>
+  <string name="action_share_file">Compartir vínculo</string>
+  <string name="action_unshare_file">Dejar de compartir vínculo</string>
   <string name="common_yes">Sí</string>
   <string name="common_no">No</string>
   <string name="common_ok">Aceptar</string>
   <string name="delete_account">Eliminar cuenta</string>
   <string name="create_account">Crear cuenta</string>
   <string name="upload_chooser_title">Subir desde ...</string>
-  <string name="uploader_info_dirname">Nombre del directorio</string>
+  <string name="uploader_info_dirname">Nombre de la carpeta</string>
   <string name="uploader_upload_in_progress_ticker">Subiendo...</string>
   <string name="uploader_upload_in_progress_content">%1$d%% Subiendo %2$s</string>
   <string name="uploader_upload_succeeded_ticker">Subido con éxito</string>
   <string name="uploader_upload_succeeded_content_single">%1$s se ha subido con éxito</string>
   <string name="uploader_upload_failed_ticker">Error al subir el archivo</string>
   <string name="uploader_upload_failed_content_single">No se pudo completar la subida de %1$s </string>
+  <string name="uploader_upload_failed_credentials_error">Subida fallida, necesita volver a iniciar sesión. </string>
   <string name="downloader_download_in_progress_ticker">Descargando ...</string>
   <string name="downloader_download_in_progress_content">%1$d%%  descargando %2$s</string>
   <string name="downloader_download_succeeded_ticker">Descarga completa</string>
   <string name="downloader_download_failed_ticker">Error al descargar</string>
   <string name="downloader_download_failed_content">No fue posible completar la descarga de %1$s</string>
   <string name="downloader_not_downloaded_yet">No descargado</string>
+  <string name="downloader_download_failed_credentials_error">Descarga fallida, necesita volver a iniciar sesión</string>
   <string name="common_choose_account">Elegí una cuenta</string>
   <string name="sync_fail_ticker">Error en la sincronización</string>
+  <string name="sync_fail_ticker_unauthorized">Sincronización fallida, debe volver a iniciar sesión</string>
   <string name="sync_fail_content">No se pudo completar la sincronización de %1$s </string>
   <string name="sync_fail_content_unauthorized">Contraseña no válida para %1$s</string>
   <string name="sync_conflicts_in_favourites_ticker">Se encontraron conflictos</string>
   <string name="sync_fail_in_favourites_ticker">Fallo la sincronización de archivos</string>
   <string name="sync_fail_in_favourites_content">%1$d archivos no pudieron ser sincronizados (%2$d conflictos)</string>
   <string name="sync_foreign_files_forgotten_ticker">Algunos archivos locales fueron olvidados</string>
-  <string name="sync_foreign_files_forgotten_content">%1$d archivos del directorio %2$s no pudieron ser copiados en</string>
-  <string name="sync_foreign_files_forgotten_explanation">Desde la versión 1.3.16, los archivos subidos desde este dispositivo se copian a un directorio local %1$s para prevenir la pérdida de datos cuando un único archivo es sincronizado con múltiples cuentas. \n\nDebido a este cambio, todos los archivos subidos en versiones previas de esta aplicación fueron copiados al directorio %2$s. No obstante, debido a un error, esta operación no pudo ser completada durante la sincronización de la cuenta. Podés dejar los archivos así y borrar el enlace a %3$s, o podés mover el/los archivos al directorio %1$s y conservar el enlace a %4$s. \n\nAbajo, encontrás la lista con los enlaces a los archivos locales y remotos en %5$s a los que están enlazados.</string>
+  <string name="sync_foreign_files_forgotten_content">%1$d archivos en la carpeta %2$s no pudieron ser copiados</string>
+  <string name="sync_current_folder_was_removed">El directorio %1$s ya no existe</string>
   <string name="foreign_files_move">Mover todos</string>
   <string name="foreign_files_success">Todos los archivos fueron movidos</string>
   <string name="foreign_files_fail">Algunos archivos no pudieron ser movidos</string>
   <string name="foreign_files_local_text">Local: %1$s</string>
   <string name="foreign_files_remote_text">Remote: %1$s</string>
-  <string name="upload_query_move_foreign_files">No hay suficiente espacio para copiar los archivos seleccionados al directorio %1$s. Querés moverlos ahí?</string>
+  <string name="upload_query_move_foreign_files">No hay espacio suficiente para copiar los archivos seleccionados dentro de la carpeta %1$s. ¿Te gustaría en su lugar moverlos?</string>
   <string name="pincode_enter_pin_code">Por favor, escribí el PIN de la aplicación</string>
   <string name="pincode_configure_your_pin">Ingresá el PIN de la aplicación</string>
   <string name="pincode_configure_your_pin_explanation">Se te pedirá el PIN cada vez que esta app sea iniciada.</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 está correctamente codificado</string>
+  <string name="media_err_timeout">Tiempo expirado mientras se intentaba reproducir</string>
   <string name="media_err_invalid_progressive_playback">Archivo de medios no puede ser transmitido</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_rewind_description">Botón 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">Obteniendo autorización...</string>
   <string name="auth_trying_to_login">Intentado iniciar sesión...</string>
   <string name="auth_no_net_conn_title">Sin conexión de red</string>
   <string name="auth_nossl_plain_ok_title">Conexión segura no disponible.</string>
   <string name="auth_connection_established">Conexión establecida</string>
   <string name="auth_testing_connection">Probando conexión...</string>
   <string name="auth_not_configured_title">Configuración de servidor en formato incorrecto</string>
+  <string name="auth_account_not_new">Una cuenta para el mismo usuario y servidor ya existe en el dispositivo</string>
+  <string name="auth_account_not_the_same">El usuario ingresado no concuerda con el usuario de esta cuenta</string>
   <string name="auth_unknown_error_title">¡Ocurrió un error desconocido!</string>
   <string name="auth_unknown_host_title">No fue posible encontrar la dirección</string>
   <string name="auth_incorrect_path_title">Instancia de servidor no encontrada</string>
   <string name="auth_timeout_title">El servidor tardó demasiado en responder</string>
   <string name="auth_incorrect_address_title">URL no válida</string>
   <string name="auth_ssl_general_error_title">Error al inicializar el SSL</string>
+  <string name="auth_ssl_unverified_server_title">No se ha podido verifica la identidad SSL del servidor</string>
   <string name="auth_bad_oc_version_title">No es posible reconocer la versión del servidor</string>
   <string name="auth_wrong_connection_title">No fue posible establecer la conexión</string>
   <string name="auth_secure_connection">Conexión segura establecida</string>
   <string name="auth_oauth_error">Autorización no satisfactoria</string>
   <string name="auth_oauth_error_access_denied">Acceso denegado por el servidor de autorización</string>
   <string name="auth_wtf_reenter_URL">Estado inesperado; por favor, introducí la URL del servidor de nuevo</string>
+  <string name="auth_expired_oauth_token_toast">Tu autorización ha expirado. Por favor, obtenga una nueva autorización</string>
   <string name="auth_expired_basic_auth_toast">Por favor, ingresá tu contraseña actual</string>
+  <string name="auth_expired_saml_sso_token_toast">Su sesión ha expirado. Por favor, conéctese de nuevo</string>
+  <string name="auth_connecting_auth_server">Conectando al servidor de autenticación...</string>
+  <string name="auth_unsupported_auth_method">El servidor no soporta este método de autenticación</string>
+  <string name="auth_unsupported_multiaccount">%1$s no soporta múltiples cuentas</string>
+  <string name="auth_fail_get_user_name">Tú servidor no esta regresando una identificación de usuario correcta, por favor contacta a un administrador</string>
+  <string name="auth_can_not_auth_against_server">No se puede autenticar contra este servidor</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="confirmation_remove_alert">¿Estás seguro que querés borrar %1$s?</string>
-  <string name="confirmation_remove_folder_alert">¿Realmente quieres borrar %1$s y todos sus contenidos ?</string>
+  <string name="confirmation_remove_alert">¿Realmente quieres eliminar %1$s?</string>
+  <string name="confirmation_remove_folder_alert">¿Realmente deseas eliminar %1$s y todo su contenido?</string>
   <string name="confirmation_remove_local">Sólo local</string>
   <string name="confirmation_remove_folder_local">Solo archivos locales</string>
   <string name="confirmation_remove_remote">Borrar del servidor</string>
   <string name="rename_server_fail_msg">No se pudo cambiar el nombre</string>
   <string name="sync_file_fail_msg">No pudo comprobarse el archivo remoto</string>
   <string name="sync_file_nothing_to_do_msg">Ya está sincronizado</string>
-  <string name="create_dir_fail_msg">No fue posible crear el directorio</string>
+  <string name="create_dir_fail_msg">La carpeta puede no haber sido creada</string>
+  <string name="filename_forbidden_characters">Caracteres prohibidos: / \\ &lt; &gt; : \" | ? *</string>
+  <string name="filename_empty">El nombre de archivo no puede estar vacío</string>
   <string name="wait_a_moment">Esperá un momento</string>
   <string name="filedisplay_unexpected_bad_get_content">Problema inesperado; por favor, intentá con otra aplicación para abrir el archivo</string>
   <string name="filedisplay_no_file_selected">No se seleccionó ningún archivo</string>
+  <string name="activity_chooser_title">Enviar enlace a...</string>
+  <string name="oauth_check_onoff">Iniciando sesión con oAuth2</string>
   <string name="oauth_login_connection">Conectando al servidor oAuth2...</string>
   <string name="ssl_validator_header">La identidad del sitio no pudo ser verificada</string>
   <string name="ssl_validator_reason_cert_not_trusted">- El certificado del servidor no es confiable</string>
   <string name="ssl_validator_label_validity_to">Para:</string>
   <string name="ssl_validator_label_signature">Firma:</string>
   <string name="ssl_validator_label_signature_algorithm">Algoritmo:</string>
+  <string name="ssl_validator_null_cert">El certificado no puede ser mostrado</string>
+  <string name="ssl_validator_no_info_about_error">- No existe información sobre el error</string>
   <string name="placeholder_sentence">Este es un texto temporario</string>
   <string name="placeholder_filename">marcadordeposición.txt</string>
   <string name="placeholder_filetype">Imagen PNG</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">Subir imágenes solamente a través de WiFi</string>
+  <string name="instant_video_upload_on_wifi">Cargar videos mediante WiFi solamente</string>
   <string name="instant_upload_path">/SubidasInstantáneas</string>
   <string name="conflict_title">Conflicto en la actualización</string>
   <string name="conflict_message">El archivo remoto %s no está sincronizado con el archivo local. Si seguís adelante, vas a reemplazar el contenido del archivo en el servidor.</string>
   <string name="conflict_overwrite">Sobrescribir</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">No se puede mostrar la imagen</string>
-  <string name="error__upload__local_file_not_copied">%1$s no pudo ser copiado al directorio local %2$s</string>
-  <string name="actionbar_failed_instant_upload">Error en Carga instantánea </string>
-  <string name="failed_upload_headline_text">Error en Cargas instantánea </string>
-  <string name="failed_upload_headline_hint">Resumen de todas las cargas instantáneas con error</string>
-  <string name="failed_upload_all_cb">Seleccionar todos</string>
-  <string name="failed_upload_headline_retryall_btn">Reintentar con todos los seleccionados</string>
-  <string name="failed_upload_headline_delete_all_btn">Eliminar todo de la cola de subida</string>
-  <string name="failed_upload_retry_text">Reintentar subida de imagen:</string>
-  <string name="failed_upload_load_more_images">Cargar mas imágenes</string>
-  <string name="failed_upload_retry_do_nothing_text">No hacer nada, no estás conectado para subida instantánea</string>
-  <string name="failed_upload_failure_text">Mensaje de error:</string>
-  <string name="failed_upload_quota_exceeded_text">Por favor, revisá la configuración de servidor, posiblemente tu cuota se haya excedido.</string>
+  <string name="preview_image_error_unknown_format">Esta imagen no puede ser mostrada</string>
+  <string name="activity_chooser_send_file_title">Mandar</string>
+  <string name="clipboard_text_copied">Copiado al portapapeles</string>
+  <string name="empty"></string>
+  <string name="prefs_category_accounts">Cuentas</string>
+  <string name="saml_authentication_required_text">Autentificación requerida</string>
+  <string name="saml_authentication_wrong_pass">Clave incorrecta</string>
+  <string name="move_choose_button_text">Elegir</string>
+  <string name="prefs_category_security">Seguridad</string>
 </resources>
diff --git a/res/values-es-rBO/strings.xml b/res/values-es-rBO/strings.xml
new file mode 100644 (file)
index 0000000..56e55a1
--- /dev/null
@@ -0,0 +1,4 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<resources>
+  <string name="empty"></string>
+</resources>
diff --git a/res/values-es-rCL/strings.xml b/res/values-es-rCL/strings.xml
new file mode 100644 (file)
index 0000000..c951072
--- /dev/null
@@ -0,0 +1,170 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<resources>
+  <string name="actionbar_sync">Refrescar cuenta</string>
+  <string name="actionbar_upload">Subir</string>
+  <string name="actionbar_upload_from_apps">contenido desde otras aplicaciones </string>
+  <string name="actionbar_upload_files">Archivos</string>
+  <string name="actionbar_mkdir">Nuevo directorio</string>
+  <string name="actionbar_settings">Configuración</string>
+  <string name="actionbar_see_details">detalles</string>
+  <string name="prefs_category_general">General</string>
+  <string name="prefs_accounts">Cuentas</string>
+  <string name="prefs_manage_accounts">Administrar Cuentas</string>
+  <string name="prefs_pincode">PIN de la aplicación</string>
+  <string name="prefs_pincode_summary">Proteger su cliente</string>
+  <string name="prefs_instant_upload">Subida instantánea de imagenes</string>
+  <string name="prefs_instant_upload_summary">Subida instantánea de imágenes tomadas con la cámara</string>
+  <string name="prefs_help">Ayuda</string>
+  <string name="auth_host_url">Dirección del servidor https://...</string>
+  <string name="auth_username">Usuario</string>
+  <string name="auth_password">Clave</string>
+  <string name="auth_register">¿Nuevo en %1$s?</string>
+  <string name="sync_string_files">Archivos</string>
+  <string name="setup_btn_connect">Conectar</string>
+  <string name="uploader_btn_upload_text">Subir</string>
+  <string name="uploader_top_message">Elija el directorio donde subir los archivos:</string>
+  <string name="uploader_wrn_no_account_title">No se encuentra la cuenta</string>
+  <string name="uploader_wrn_no_account_text">No existe la cuenta %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">ningun contenido para subir</string>
+  <string name="uploader_wrn_no_content_text">No se ha recibido ningún contenido. No hay nada para subir.</string>
+  <string name="uploader_error_forbidden_content">%1$s no esta autorizado para acceder al contenido compartido</string>
+  <string name="uploader_info_uploading">Subiendo</string>
+  <string name="filedetails_select_file">Seleccione un archivo para desplegar información adicional.</string>
+  <string name="filedetails_size">Tamaño:</string>
+  <string name="filedetails_type">Tipo:</string>
+  <string name="filedetails_created">Creado:</string>
+  <string name="filedetails_modified">Modificado:</string>
+  <string name="filedetails_download">Descargar</string>
+  <string name="filedetails_sync_file">refrescar archivo</string>
+  <string name="filedetails_renamed_in_upload_msg">El archivo fue renombrado a %1$s durante la subida</string>
+  <string name="common_yes">Si</string>
+  <string name="common_no">No</string>
+  <string name="common_ok">OK</string>
+  <string name="common_cancel_download">cancelar bajada</string>
+  <string name="common_cancel_upload">cancelar subida</string>
+  <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_error_unknown">Error desconocido</string>
+  <string name="about_title">Acerca de</string>
+  <string name="delete_account">Eliminar cuenta</string>
+  <string name="create_account">Crear cuenta</string>
+  <string name="upload_chooser_title">Subir desde...</string>
+  <string name="uploader_info_dirname">Nombre del directorio</string>
+  <string name="uploader_upload_in_progress_ticker">Subiendo</string>
+  <string name="uploader_upload_in_progress_content"> %1$d%% Subiendo %2$s</string>
+  <string name="uploader_upload_succeeded_ticker">Subida correcta</string>
+  <string name="uploader_upload_succeeded_content_single">%1$s fue subido correctamente</string>
+  <string name="uploader_upload_failed_ticker">Subida fallida</string>
+  <string name="uploader_upload_failed_content_single">La subida de %1$s no pudo ser completada</string>
+  <string name="downloader_download_in_progress_ticker">Descargando...</string>
+  <string name="downloader_download_in_progress_content">%1$d%% Descargando %2$s</string>
+  <string name="downloader_download_succeeded_ticker">Descarga completada</string>
+  <string name="downloader_download_succeeded_content">%1$s fue descargado correctamente</string>
+  <string name="downloader_download_failed_ticker">Descarga fallida</string>
+  <string name="downloader_download_failed_content">La descarga de %1$s no pudo ser completada</string>
+  <string name="downloader_not_downloaded_yet">Aun no se ha descargado</string>
+  <string name="common_choose_account">Elija una cuenta</string>
+  <string name="sync_fail_ticker">sincronización fallida</string>
+  <string name="sync_fail_content">La sincronización de %1$s no pudo ser completada</string>
+  <string name="sync_conflicts_in_favourites_ticker">conflictos encontrados</string>
+  <string name="sync_foreign_files_forgotten_ticker">Algunos archivos fueron olvidados</string>
+  <string name="sync_foreign_files_forgotten_content">%1$d archivos fuera de la carpeta %2$s no pudieron ser copiados dentro</string>
+  <string name="foreign_files_move">mover todo</string>
+  <string name="foreign_files_success">todos los archivos fueron transferidos</string>
+  <string name="foreign_files_fail">algunos archivos no pueden ser transferidos</string>
+  <string name="foreign_files_local_text">Local: %1$s</string>
+  <string name="foreign_files_remote_text">Remoto: %1$s</string>
+  <string name="pincode_enter_pin_code">Por favor, ingreses su PIN de aplicación</string>
+  <string name="pincode_configure_your_pin">Ingrese su PIN de aplicación</string>
+  <string name="pincode_configure_your_pin_explanation">El PIN será solicitado cada vez que la aplicación se inicie</string>
+  <string name="pincode_reenter_your_pincode">Por favor, reingrese su PIN de aplicación</string>
+  <string name="pincode_remove_your_pincode">Remover el PIN de su aplicación</string>
+  <string name="pincode_mismatch">Los PINs de su aplicación no coinciden</string>
+  <string name="pincode_wrong">PIN de aplicación incorrecto</string>
+  <string name="pincode_removed">PIN de aplicación removido</string>
+  <string name="pincode_stored">PIN de aplicación almacenada</string>
+  <string name="media_notif_ticker">Reproductor de música %1$s</string>
+  <string name="media_state_playing">(sonando) %1$s</string>
+  <string name="media_state_loading">(cargando) %1$s</string>
+  <string name="media_event_done">La reproducción de %1$s ha terminado</string>
+  <string name="media_err_nothing_to_play">ningun archivo multimedia encontrado</string>
+  <string name="media_err_no_account">ninguna cuenta provista</string>
+  <string name="media_err_not_in_owncloud">El archivo no es de una cuenta válida</string>
+  <string name="media_err_unsupported">Codificador de medios no soportado</string>
+  <string name="media_err_io">El archivo multi media no se pudo leer</string>
+  <string name="media_err_malformed">El archivo multimedia no está correctamente codificado</string>
+  <string name="media_err_timeout">Se excedió el tiempo al intentar reproducir</string>
+  <string name="auth_trying_to_login">Intentando entrar...</string>
+  <string name="auth_no_net_conn_title">Sin conexión de red</string>
+  <string name="auth_nossl_plain_ok_title">Conexión segura no disponible.</string>
+  <string name="auth_connection_established">Conexión establecida</string>
+  <string name="auth_testing_connection">Probando conexión...</string>
+  <string name="auth_not_configured_title">La configuración del servidor está mal formada</string>
+  <string name="auth_unknown_error_title">Ocurrió un error desconocido</string>
+  <string name="auth_unknown_host_title">No se puede encontrar el host</string>
+  <string name="auth_incorrect_path_title">Instancia del servidor no encontrada</string>
+  <string name="auth_timeout_title">El servidor se demoro mucho en contestar</string>
+  <string name="auth_incorrect_address_title">URL mal formada</string>
+  <string name="auth_ssl_general_error_title">Inicialización SSL fallida</string>
+  <string name="auth_ssl_unverified_server_title">No se pudo verificar la identidad SSL del servidor</string>
+  <string name="auth_bad_oc_version_title">Versión del servidor no reconocida</string>
+  <string name="auth_wrong_connection_title">No se pudo establecer la conexión</string>
+  <string name="auth_secure_connection">Conexión segura establecida</string>
+  <string name="auth_unauthorized">usuario o clave incorrecta</string>
+  <string name="fd_keep_in_sync">Mantener el archivo actualizado</string>
+  <string name="common_rename">Renombrar</string>
+  <string name="common_remove">Remover</string>
+  <string name="confirmation_remove_alert">¿Realmente desea eliminar %1$s?</string>
+  <string name="confirmation_remove_folder_alert">¿Realmente desea eliminar el archivo %1$s y su contenido?</string>
+  <string name="confirmation_remove_local">Solo local</string>
+  <string name="confirmation_remove_folder_local">solo contenidos locales </string>
+  <string name="confirmation_remove_remote">Eliminar desde el servidor</string>
+  <string name="confirmation_remove_remote_and_local">Remoto y local</string>
+  <string name="remove_success_msg">Removido correctamente</string>
+  <string name="remove_fail_msg">Fallo al remover</string>
+  <string name="rename_dialog_title">ingresar un nuevo nombre</string>
+  <string name="rename_local_fail_msg">La copia local no se pudo renombrar, pruebe un nombre diferente</string>
+  <string name="rename_server_fail_msg">Renombrar no pudo ser completado</string>
+  <string name="sync_file_fail_msg">El archivo remoto no se pudo chequear</string>
+  <string name="sync_file_nothing_to_do_msg">contenido de los archivos ya sincronizados</string>
+  <string name="create_dir_fail_msg">El directorio no pudo ser creado</string>
+  <string name="wait_a_moment">espera un momento</string>
+  <string name="filedisplay_unexpected_bad_get_content">Problema inesperado ; por favor seleccione el archivo desde una aplicación diferente</string>
+  <string name="filedisplay_no_file_selected">ningun archivo electo</string>
+  <string name="ssl_validator_header">La identidad del sitio no pudo ser verificada</string>
+  <string name="ssl_validator_reason_cert_not_trusted">-El certificado del servidor no es confiable</string>
+  <string name="ssl_validator_reason_cert_expired">-El certificado del servidor está expirado</string>
+  <string name="ssl_validator_reason_cert_not_yet_valid">-Las fechas validas para el certificado del servidor son futuras.</string>
+  <string name="ssl_validator_reason_hostname_not_verified">-  La URL no corresponde al nombre del servidor en el certificado</string>
+  <string name="ssl_validator_question">¿Desea confiar en el certificado de todas manera?</string>
+  <string name="ssl_validator_not_saved">El certificado no se pudo guardar</string>
+  <string name="ssl_validator_btn_details_see">detalles</string>
+  <string name="ssl_validator_btn_details_hide">esconder</string>
+  <string name="ssl_validator_label_subject">emitido para</string>
+  <string name="ssl_validator_label_issuer">emitido por </string>
+  <string name="ssl_validator_label_CN">nombre comun </string>
+  <string name="ssl_validator_label_O">organizacion </string>
+  <string name="ssl_validator_label_OU">unidad organizacional</string>
+  <string name="ssl_validator_label_C">pais</string>
+  <string name="ssl_validator_label_ST">estado</string>
+  <string name="ssl_validator_label_L">locacion</string>
+  <string name="ssl_validator_label_validity">Validez:</string>
+  <string name="ssl_validator_label_validity_from">desde</string>
+  <string name="ssl_validator_label_validity_to">para</string>
+  <string name="ssl_validator_label_signature">Firma:</string>
+  <string name="ssl_validator_label_signature_algorithm">algoritmo</string>
+  <string name="instant_upload_on_wifi">Solo subir fotos vía WiFi</string>
+  <string name="conflict_title">Conflicto al actualizar</string>
+  <string name="conflict_message">El archivo remoto %s no está sincronizado con la copia local. Si continua, se reemplazará el archivo en el servidor.</string>
+  <string name="conflict_keep_both">Mantener ambos</string>
+  <string name="conflict_overwrite">Sobre-escribir</string>
+  <string name="conflict_dont_upload">No subir</string>
+  <string name="error__upload__local_file_not_copied">%1$s no pudo ser copiado a la carpeta local %2$s</string>
+  <string name="empty"></string>
+  <string name="prefs_category_accounts">Cuentas</string>
+  <string name="move_choose_button_text">Choose</string>
+</resources>
diff --git a/res/values-es-rCO/strings.xml b/res/values-es-rCO/strings.xml
new file mode 100644 (file)
index 0000000..56e55a1
--- /dev/null
@@ -0,0 +1,4 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<resources>
+  <string name="empty"></string>
+</resources>
diff --git a/res/values-es-rCR/strings.xml b/res/values-es-rCR/strings.xml
new file mode 100644 (file)
index 0000000..56e55a1
--- /dev/null
@@ -0,0 +1,4 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<resources>
+  <string name="empty"></string>
+</resources>
diff --git a/res/values-es-rEC/strings.xml b/res/values-es-rEC/strings.xml
new file mode 100644 (file)
index 0000000..56e55a1
--- /dev/null
@@ -0,0 +1,4 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<resources>
+  <string name="empty"></string>
+</resources>
index c757504..ef91bc6 100644 (file)
@@ -1,2 +1,219 @@
 <?xml version='1.0' encoding='UTF-8'?>
-<resources/>
+<resources>
+  <string name="about_android">App Android %1$s</string>
+  <string name="about_version">versión %1$s</string>
+  <string name="actionbar_sync">Actualizar cuenta</string>
+  <string name="actionbar_upload">Subir archivo</string>
+  <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_settings">Ajustes</string>
+  <string name="actionbar_see_details">Detalles</string>
+  <string name="actionbar_send_file">Enviar</string>
+  <string name="prefs_category_general">General</string>
+  <string name="prefs_category_more">Más</string>
+  <string name="prefs_accounts">Cuentas</string>
+  <string name="prefs_manage_accounts">Gestionar cuentas</string>
+  <string name="prefs_pincode">PIN de aplicación </string>
+  <string name="prefs_pincode_summary">Proteja su cliente</string>
+  <string name="prefs_log_title">Habilitar registro</string>
+  <string name="prefs_log_summary">Esto es usado para registrar problemas</string>
+  <string name="prefs_log_title_history">Historia del Registro</string>
+  <string name="prefs_log_summary_history">Esto muestra los registros grabados</string>
+  <string name="prefs_log_delete_history_button">Eliminar Historial</string>
+  <string name="prefs_help">Ayuda</string>
+  <string name="prefs_recommend">Recomendar a un amigo</string>
+  <string name="prefs_feedback">Mensajes de retroalimentación</string>
+  <string name="prefs_imprint">Imprint</string>
+  <string name="recommend_subject">Prueba  %1$s en tu smarthphone!</string>
+  <string name="auth_check_server">Compruebe el servidor.</string>
+  <string name="auth_host_url">Dirección del servidor https://…</string>
+  <string name="auth_username">Nombre de usuario</string>
+  <string name="auth_password">Contraseña</string>
+  <string name="auth_register">New to %1$s?</string>
+  <string name="sync_string_files">Archivos</string>
+  <string name="setup_btn_connect">Conectar</string>
+  <string name="uploader_btn_upload_text">Subir</string>
+  <string name="uploader_wrn_no_account_title">No se encontraron cuentas</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_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>
+  <string name="uploader_wrn_no_content_text">Ningún contenido ha sido recibido. No hay nada que subir.</string>
+  <string name="uploader_error_forbidden_content">%1$s no está autorizado para acceder al contenido compartido</string>
+  <string name="uploader_info_uploading">Enviando</string>
+  <string name="file_list_empty">No hay nada aquí. ¡Suba algo!</string>
+  <string name="filedetails_select_file">Pulsa sobre un archivo para mostrar información adicional.</string>
+  <string name="filedetails_size">Tamaño:</string>
+  <string name="filedetails_type">Tipo:</string>
+  <string name="filedetails_created">Creado:</string>
+  <string name="filedetails_modified">Modificado:</string>
+  <string name="filedetails_download">Descargar</string>
+  <string name="filedetails_sync_file">Actualizar archivo</string>
+  <string name="filedetails_renamed_in_upload_msg">El archivo fue renombrado como %1$s durante la subida</string>
+  <string name="action_share_file">Enlace compartido</string>
+  <string name="common_yes">Sí</string>
+  <string name="common_no">No</string>
+  <string name="common_ok">Aceptar</string>
+  <string name="common_cancel_download">Cancelar descarga</string>
+  <string name="common_cancel_upload">Cancelar subida</string>
+  <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_error_unknown">Error desconocido</string>
+  <string name="about_title">Acerca de</string>
+  <string name="change_password">Cambiar contraseña</string>
+  <string name="delete_account">Eliminar cuenta</string>
+  <string name="create_account">Crear cuenta</string>
+  <string name="upload_chooser_title">Subir</string>
+  <string name="uploader_info_dirname">Nombre de la carpeta</string>
+  <string name="uploader_upload_in_progress_ticker">Subiendo...</string>
+  <string name="uploader_upload_in_progress_content">%1$d%% Subiendo %2$s</string>
+  <string name="uploader_upload_succeeded_ticker">Subido con éxito</string>
+  <string name="uploader_upload_succeeded_content_single">%1$s se ha subido con éxito</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="downloader_download_in_progress_ticker">Descargando ...</string>
+  <string name="downloader_download_in_progress_content">%1$s Descargada 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_ticker">Falló la descarga</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="common_choose_account">Elige una cuenta</string>
+  <string name="sync_fail_ticker">Falló la sincronización</string>
+  <string name="sync_fail_content">La sincronización de %1$s s no se pudo completar</string>
+  <string name="sync_fail_content_unauthorized">Contraseña no válida para %1$s</string>
+  <string name="sync_conflicts_in_favourites_ticker">Se encontraron conflictos</string>
+  <string name="sync_conflicts_in_favourites_content">Falló la sincronización de contenidos de %1$d archivos</string>
+  <string name="sync_fail_in_favourites_ticker">Fallos en la sincronización de contenidos</string>
+  <string name="sync_fail_in_favourites_content">Los contenidos de %1$d archivos no fueron sincronizados (%2$d conflictos)</string>
+  <string name="sync_foreign_files_forgotten_ticker">Algunos archivos locales se han perdido</string>
+  <string name="sync_current_folder_was_removed">La carpeta local %1$s no existe.</string>
+  <string name="foreign_files_move">Mover todo</string>
+  <string name="foreign_files_success">Todos los archivos fueron movidos</string>
+  <string name="foreign_files_fail">Algunos archivos no han podido ser movidos</string>
+  <string name="foreign_files_local_text">Local: %1$s</string>
+  <string name="foreign_files_remote_text">Remoto: %1$s</string>
+  <string name="pincode_enter_pin_code">Por favor, inserta tu 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="pincode_remove_your_pincode">Borre su PIN de aplicación</string>
+  <string name="pincode_mismatch">Los PIN introducidos no son iguales</string>
+  <string name="pincode_wrong">PIN de aplicación incorrecto</string>
+  <string name="pincode_removed">PIN de aplicación borrado</string>
+  <string name="pincode_stored">PIN de aplicación guardado</string>
+  <string name="media_notif_ticker">Reproductor de música %1$s</string>
+  <string name="media_state_playing">%1$s (reproduciendo)</string>
+  <string name="media_state_loading">%1$s (cargando)</string>
+  <string name="media_event_done">%1$s reproducción finalizada</string>
+  <string name="media_err_nothing_to_play">No se encuentra archivo de medio</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_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_invalid_progressive_playback">Archivo de medio no puede ser transmitido</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_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_trying_to_login">Intentado iniciar sesión...</string>
+  <string name="auth_no_net_conn_title">Sin conexión de red</string>
+  <string name="auth_nossl_plain_ok_title">Conexión segura no disponible.</string>
+  <string name="auth_connection_established">Conexión establecida</string>
+  <string name="auth_testing_connection">Probando conexión...</string>
+  <string name="auth_not_configured_title">Configuración de servidor en formato incorrecto</string>
+  <string name="auth_account_not_new">Una cuenta para el mismo usuario y servidor ya existen en el dispositivo</string>
+  <string name="auth_account_not_the_same">El usuario introducido no concuerda con el usuario de esta cuenta</string>
+  <string name="auth_unknown_error_title">Ocurrió un error desconocido</string>
+  <string name="auth_unknown_host_title">No se pudo encontrar la dirección</string>
+  <string name="auth_incorrect_path_title">Instancia de servidor no encontrada</string>
+  <string name="auth_timeout_title">El servidor ha tardado demasiado en responder</string>
+  <string name="auth_incorrect_address_title">URL no válida</string>
+  <string name="auth_ssl_general_error_title">Falló la inicialización SSL</string>
+  <string name="auth_ssl_unverified_server_title">No fue posible verificar la identidad del servidor SLL</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_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_expired_oauth_token_toast">Su autorización ha expirado. Por favor, autorice de nuevo</string>
+  <string name="auth_expired_basic_auth_toast">Por favor, introduzca la contraseña actual.</string>
+  <string name="auth_expired_saml_sso_token_toast">Su sesión ha expirado. Favor de conectarse de nuevo</string>
+  <string name="auth_connecting_auth_server">Conectando al servidor de autenticación...</string>
+  <string name="auth_unsupported_auth_method">El servidor no soporta este método de autenticación</string>
+  <string name="auth_unsupported_multiaccount">%1$s no soporta cuentas múltiples</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="confirmation_remove_local">Sólo local</string>
+  <string name="confirmation_remove_folder_local">Sólo archivos locales</string>
+  <string name="confirmation_remove_remote">Eliminar del servidor</string>
+  <string name="confirmation_remove_remote_and_local">Tanto remoto como local</string>
+  <string name="remove_success_msg">Borrado correctamente</string>
+  <string name="remove_fail_msg">El borrado no pudo ser completado</string>
+  <string name="rename_dialog_title">Introduzca un nombre nuevo</string>
+  <string name="rename_local_fail_msg">No se pudo cambiar el nombre de la copia local, trata con un nombre differente</string>
+  <string name="rename_server_fail_msg">No se pudo cambiar el nombre</string>
+  <string name="sync_file_fail_msg">No pudo comprobarse el archivo remoto</string>
+  <string name="sync_file_nothing_to_do_msg">Ya está sincronizado</string>
+  <string name="filename_forbidden_characters">Carácteres ilegales: / \\ &lt; &gt; : \" | ? *</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_no_file_selected">No fué seleccionado ningún archivo</string>
+  <string name="oauth_check_onoff">Ingresar con oAuth2</string>
+  <string name="oauth_login_connection">Conectando al servidor oAuth2...</string>
+  <string name="ssl_validator_header">La identidad del sitio no puede ser verificada</string>
+  <string name="ssl_validator_reason_cert_not_trusted">- El certificado del servidor no es de confianza</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 demasiado reciente</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_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="ssl_validator_label_subject">Emitido para:</string>
+  <string name="ssl_validator_label_issuer">Emitido por:</string>
+  <string name="ssl_validator_label_CN">Nombre común:</string>
+  <string name="ssl_validator_label_O">Organización:</string>
+  <string name="ssl_validator_label_OU">Unidad organizativa</string>
+  <string name="ssl_validator_label_C">Pais:</string>
+  <string name="ssl_validator_label_ST">Estado:</string>
+  <string name="ssl_validator_label_L">Ubicación:</string>
+  <string name="ssl_validator_label_validity">Validez:</string>
+  <string name="ssl_validator_label_validity_from">De:</string>
+  <string name="ssl_validator_label_validity_to">A:</string>
+  <string name="ssl_validator_label_signature">Firma:</string>
+  <string name="ssl_validator_label_signature_algorithm">Algoritmo:</string>
+  <string name="placeholder_sentence">Esto es un marcador de posición</string>
+  <string name="placeholder_filename">marcadordeposición.txt</string>
+  <string name="placeholder_filetype">Imagen PNG</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">Subir imágenes sólo via WiFi</string>
+  <string name="instant_upload_path">/SubidasInstantáneas</string>
+  <string name="conflict_title">Conflicto en la actualización</string>
+  <string name="conflict_message">El archivo remoto %s no está sincronizado con el archivo local. Si continúa, se reemplazará el contenido del archivo en el servidor.</string>
+  <string name="conflict_keep_both">Mantener ambas</string>
+  <string name="conflict_overwrite">Sobrescribir</string>
+  <string name="conflict_dont_upload">No subir</string>
+  <string name="preview_image_description">Previsualización de imagen</string>
+  <string name="activity_chooser_send_file_title">Enviar</string>
+  <string name="clipboard_text_copied">Copiado al portapapeles</string>
+  <string name="empty"></string>
+  <string name="prefs_category_accounts">Cuentas</string>
+  <string name="saml_authentication_wrong_pass">Contraseña incorrecta</string>
+  <string name="move_choose_button_text">Seleccionar</string>
+  <string name="prefs_category_security">Seguridad</string>
+</resources>
diff --git a/res/values-es-rPE/strings.xml b/res/values-es-rPE/strings.xml
new file mode 100644 (file)
index 0000000..56e55a1
--- /dev/null
@@ -0,0 +1,4 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<resources>
+  <string name="empty"></string>
+</resources>
diff --git a/res/values-es-rPY/strings.xml b/res/values-es-rPY/strings.xml
new file mode 100644 (file)
index 0000000..56fe666
--- /dev/null
@@ -0,0 +1,6 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<resources>
+  <string name="actionbar_upload_files">Archivos</string>
+  <string name="sync_string_files">Archivos</string>
+  <string name="empty"></string>
+</resources>
diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml
new file mode 100644 (file)
index 0000000..56e55a1
--- /dev/null
@@ -0,0 +1,4 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<resources>
+  <string name="empty"></string>
+</resources>
diff --git a/res/values-es-rUY/strings.xml b/res/values-es-rUY/strings.xml
new file mode 100644 (file)
index 0000000..56e55a1
--- /dev/null
@@ -0,0 +1,4 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<resources>
+  <string name="empty"></string>
+</resources>
index 4878480..7f66173 100644 (file)
@@ -1,23 +1,26 @@
 <?xml version='1.0' encoding='UTF-8'?>
 <resources>
-  <string name="about_android">App Android %1$s</string>
+  <string name="about_android">%1$s para Android</string>
   <string name="about_version">versión %1$s</string>
   <string name="actionbar_sync">Actualizar cuenta</string>
-  <string name="actionbar_upload">Subir archivo</string>
+  <string name="actionbar_upload">Subir</string>
   <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">Crear directorio</string>
-  <string name="actionbar_settings">Ajustes</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>
   <string name="prefs_category_general">General</string>
   <string name="prefs_category_more">Más</string>
   <string name="prefs_accounts">Cuentas</string>
   <string name="prefs_manage_accounts">Gestionar cuentas</string>
   <string name="prefs_pincode">PIN de aplicación </string>
   <string name="prefs_pincode_summary">Proteja su cliente</string>
-  <string name="prefs_instant_upload">Habilita la subida instantánea</string>
-  <string name="prefs_instant_upload_summary">Subir instantáneamente las fotos tomadas por la cámara</string>
+  <string name="prefs_instant_upload">Subida instantánea de imágenes</string>
+  <string name="prefs_instant_upload_summary">Sube instantáneamente las fotos tomadas con la cámara</string>
+  <string name="prefs_instant_video_upload">Subidas instantáneas de video</string>
+  <string name="prefs_instant_video_upload_summary">Sube instantáneamente los vídeos grabados con la cámara</string>
   <string name="prefs_log_title">Habilitar registro</string>
   <string name="prefs_log_summary">Esto es usado para registrar problemas</string>
   <string name="prefs_log_title_history">Historia del Registro</string>
   <string name="prefs_help">Ayuda</string>
   <string name="prefs_recommend">Recomendar a un amigo</string>
   <string name="prefs_feedback">Mensajes de retroalimentación</string>
-  <string name="prefs_imprint">Imprint</string>
+  <string name="prefs_imprint">pie de imprenta</string>
   <string name="recommend_subject">Prueba  %1$s en tu smarthphone!</string>
-  <string name="recommend_text">Quiero invitarte a usar %1$s en tu smarthphone!⏎\nDescargalo aquí: %2$s</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</string>
+  <string name="auth_host_url">Dirección del servidor https://…</string>
   <string name="auth_username">Nombre de usuario</string>
   <string name="auth_password">Contraseña</string>
-  <string name="auth_register">New to %1$s?</string>
+  <string name="auth_register">Nuevo para %1$s?</string>
   <string name="sync_string_files">Archivos</string>
   <string name="setup_btn_connect">Conectar</string>
   <string name="uploader_btn_upload_text">Subir</string>
-  <string name="uploader_top_message">Escoja el directorio de carga:</string>
-  <string name="uploader_wrn_no_account_title">No se encontraron cuentas</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_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>
   <string name="uploader_wrn_no_content_text">Ningún contenido ha sido recibido. No hay nada que subir.</string>
   <string name="uploader_error_forbidden_content">%1$s no está autorizado para acceder al contenido compartido</string>
-  <string name="uploader_info_uploading">Enviando</string>
-  <string name="file_list_empty">No hay archivos en esta carpeta.\nPuedes añadir nuevos archivos con la opción \"Subir\" del menú.</string>
+  <string name="uploader_info_uploading">Subiendo...</string>
+  <string name="file_list_empty">No hay nada aquí. ¡Suba algo!</string>
+  <string name="file_list_loading">Cargando...</string>
+  <string name="local_file_list_empty">No hay archivos en esta carpeta.</string>
   <string name="filedetails_select_file">Pulsa sobre un archivo para mostrar información adicional.</string>
   <string name="filedetails_size">Tamaño:</string>
   <string name="filedetails_type">Tipo:</string>
@@ -55,6 +60,8 @@
   <string name="filedetails_download">Descargar</string>
   <string name="filedetails_sync_file">Actualizar archivo</string>
   <string name="filedetails_renamed_in_upload_msg">El fichero fue renombrado como %1$s durante la subida</string>
+  <string name="action_share_file">Compartir con enlace</string>
+  <string name="action_unshare_file">Dejar de compartir</string>
   <string name="common_yes">Sí</string>
   <string name="common_no">No</string>
   <string name="common_ok">Aceptar</string>
   <string name="change_password">Cambiar contraseña</string>
   <string name="delete_account">Eliminar cuenta</string>
   <string name="create_account">Crear cuenta</string>
-  <string name="upload_chooser_title">Subir</string>
-  <string name="uploader_info_dirname">Nombre de directorio</string>
+  <string name="upload_chooser_title">Subir desde...</string>
+  <string name="uploader_info_dirname">Nombre de la carpeta</string>
   <string name="uploader_upload_in_progress_ticker">Subiendo...</string>
   <string name="uploader_upload_in_progress_content">%1$d%% Subiendo %2$s</string>
   <string name="uploader_upload_succeeded_ticker">Subido con éxito</string>
   <string name="uploader_upload_succeeded_content_single">%1$s se ha subido con éxito</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_content">%1$s Descargada de %2$s</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_ticker">Falló la descarga</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="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="sync_fail_content_unauthorized">Contraseña no válida para %1$s</string>
   <string name="sync_conflicts_in_favourites_ticker">Se encontraron conflictos</string>
   <string name="sync_conflicts_in_favourites_content">Falló la sincronización de contenidos de %1$d ficheros</string>
   <string name="sync_fail_in_favourites_ticker">Fallos en la sincronización de contenidos</string>
-  <string name="sync_fail_in_favourites_content">Los contenidos de %1$d ficheros no fueron sincronizados (%2$d conflictos)</string>
+  <string name="sync_fail_in_favourites_content">Los contenidos de %1$d archivos no pudieron sincronizarse (%2$d conflictos)</string>
   <string name="sync_foreign_files_forgotten_ticker">Algunos archivos locales se han perdido</string>
-  <string name="sync_foreign_files_forgotten_content">%1$d archivos de %2$s no han podido ser copiados</string>
-  <string name="sync_foreign_files_forgotten_explanation">Como versión 1.3.16, los archivos subidos desde este dispositivo son copiados a un archivo %1$s local para prevenir perdida de datos cuando un simple archivo es sincronizado con multiples cuentas.\n\nDebido a este cambio, todos los archivos subidos en versiones previas de esta aplicación han sido copiados a la carpeta %2$s. No obtante, un error previno el completado de esta operación durante la sincronización de cuenta. Debería dejar el o los archivos así y eliminar el enlace a %3$s o mover el o los archivos al %1$s directorio y conservar el enlace a %4$s.\n\nListado abajo tiene los enlaces a los archivos locales y archivos remotos en %5$s </string>
+  <string name="sync_foreign_files_forgotten_content">%1$d archivos en la carpeta %2$s no pudieron ser copiados a</string>
+  <string name="sync_foreign_files_forgotten_explanation">A partir de la versión 1.3.16, los ficheros subidos desde este dispositivo se copian en la carpeta local %1$s para evitar la pérdida de datos cuando se sincroniza un único archivo con varias cuentas.\n\nDebido a este cambio, todos los ficheros subidos con versiones anteriores de esta aplicación fueron copiados a la carpeta %2$s. Sin embargo, un error impidió que se completara esta operación durante la sincronización de la cuenta. Puede dejar los archivos tal y como están y eliminar el enlace a %3$s o mover los archivos a la carpeta %1$s y mantener el enlace a %4$s.\n\nDebajo se muestran los archivos locales y los archivos remotos en %5$s a los que fueron enlazados.</string>
   <string name="sync_current_folder_was_removed">La carpeta local %1$s no existe.</string>
   <string name="foreign_files_move">Mover todo</string>
   <string name="foreign_files_success">Todos los archivos fueron movidos</string>
-  <string name="foreign_files_fail">Algunos archivos no han podido ser movidos</string>
+  <string name="foreign_files_fail">No se han podido mover algunos archivos</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 en la carpeta %1$s. ¿Quiere moverlos en lugar de copiarlos?</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_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="media_state_playing">%1$s (reproduciendo)</string>
   <string name="media_state_loading">%1$s (cargando)</string>
   <string name="media_event_done">%1$s reproducción finalizada</string>
-  <string name="media_err_nothing_to_play">No se encuentra archivo de medio</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_rewind_description">Botón 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_trying_to_login">Intentado iniciar sesión...</string>
   <string name="auth_no_net_conn_title">Sin conexión de red</string>
   <string name="auth_nossl_plain_ok_title">Conexión segura no disponible.</string>
   <string name="auth_connection_established">Conexión establecida</string>
   <string name="auth_testing_connection">Probando conexión...</string>
   <string name="auth_not_configured_title">Configuración de servidor en formato incorrecto</string>
-  <string name="auth_account_not_new">Una cuenta para el mismo usuario y servidor ya existen en el dispositivo</string>
+  <string name="auth_account_not_new">Ya existe una cuenta en este dispositivo con los mismos datos de Usuario y Servidor</string>
   <string name="auth_account_not_the_same">El usuario introducido no concuerda con el usuario de esta cuenta</string>
   <string name="auth_unknown_error_title">Ocurrió un error desconocido</string>
-  <string name="auth_unknown_host_title">No se pudo encontrar la dirección</string>
+  <string name="auth_unknown_host_title">Error: no se pudo encontrar el host</string>
   <string name="auth_incorrect_path_title">Instancia de servidor no encontrada</string>
   <string name="auth_timeout_title">El servidor ha tardado demasiado en responder</string>
   <string name="auth_incorrect_address_title">URL no válida</string>
   <string name="auth_ssl_general_error_title">Falló la inicialización SSL</string>
-  <string name="auth_ssl_unverified_server_title">No fue posible verificar la identidad del servidor SLL</string>
+  <string name="auth_ssl_unverified_server_title">No fue posible verificar la identidad del servidor SSL</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_connecting_auth_server">Conectando al servidor de autenticación...</string>
   <string name="auth_unsupported_auth_method">El servidor no soporta este método de autenticación</string>
   <string name="auth_unsupported_multiaccount">%1$s no soporta cuentas múltiples</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="fd_keep_in_sync">Mantener el archivo actualizado</string>
   <string name="common_rename">Renombrar</string>
   <string name="common_remove">Borrar</string>
-  <string name="confirmation_remove_alert">¿Está seguro que desea borrar %1$s ?</string>
-  <string name="confirmation_remove_folder_alert">¿Desea elimiar %1$s y sus descendientes?</string>
+  <string name="confirmation_remove_alert">¿Realmente desea eliminar %1$s?</string>
+  <string name="confirmation_remove_folder_alert">¿Realmente desea eliminar %1$s y todo su contenido?</string>
   <string name="confirmation_remove_local">Sólo local</string>
   <string name="confirmation_remove_folder_local">Sólo ficheros locales</string>
   <string name="confirmation_remove_remote">Eliminar del servidor</string>
   <string name="rename_dialog_title">Introduzca un nombre nuevo</string>
   <string name="rename_local_fail_msg">No se pudo cambiar el nombre de la copia local, trata con un nombre differente</string>
   <string name="rename_server_fail_msg">No se pudo cambiar el nombre</string>
-  <string name="sync_file_fail_msg">No pudo comprobarse el fichero remoto</string>
+  <string name="sync_file_fail_msg">No se ha podido comprobar el fichero remoto</string>
   <string name="sync_file_nothing_to_do_msg">Ya está sincronizado</string>
-  <string name="create_dir_fail_msg">El directorio no pudo ser creado</string>
+  <string name="create_dir_fail_msg">No se pudo crear la carpeta</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_no_file_selected">No fué seleccionado ningún 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="oauth_login_connection">Conectando al servidor oAuth2...</string>
   <string name="ssl_validator_header">La identidad del sitio no puede ser verificada</string>
   <string name="ssl_validator_reason_cert_not_trusted">- El certificado del servidor no es de confianza</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 demasiado reciente</string>
+  <string name="ssl_validator_reason_cert_not_yet_valid">- El certificado del servidor es de una fecha que aún no llega</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_not_saved">El certificado no pudo ser guardado</string>
   <string name="ssl_validator_label_CN">Nombre común:</string>
   <string name="ssl_validator_label_O">Organización:</string>
   <string name="ssl_validator_label_OU">Unidad organizativa</string>
-  <string name="ssl_validator_label_C">Pais:</string>
+  <string name="ssl_validator_label_C">País:</string>
   <string name="ssl_validator_label_ST">Estado:</string>
   <string name="ssl_validator_label_L">Ubicación:</string>
   <string name="ssl_validator_label_validity">Validez:</string>
-  <string name="ssl_validator_label_validity_from">De:</string>
+  <string name="ssl_validator_label_validity_from">Desde</string>
   <string name="ssl_validator_label_validity_to">A:</string>
   <string name="ssl_validator_label_signature">Firma:</string>
   <string name="ssl_validator_label_signature_algorithm">Algoritmo:</string>
+  <string name="ssl_validator_null_cert">No se ha podido mostrar el certificado</string>
+  <string name="ssl_validator_no_info_about_error">- No hay información acerca del error</string>
   <string name="placeholder_sentence">Esto es un marcador de posición</string>
   <string name="placeholder_filename">marcadordeposición.txt</string>
   <string name="placeholder_filetype">Imagen PNG</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">Subir imágenes sólo via WiFi</string>
+  <string name="instant_upload_on_wifi">Subir imágenes sólo cuando hay WiFi</string>
+  <string name="instant_video_upload_on_wifi">Subir vídeos sólo por WiFi</string>
   <string name="instant_upload_path">/SubidasInstantáneas</string>
   <string name="conflict_title">Conflicto en la actualización</string>
   <string name="conflict_message">El archivo remoto %s no está sincronizado con el archivo local. Si continúa, se reemplazará el contenido del archivo en el servidor.</string>
-  <string name="conflict_keep_both">Mantener ambas</string>
+  <string name="conflict_keep_both">Mantener ambos</string>
   <string name="conflict_overwrite">Sobrescribir</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">No se puede mostrar la imagen</string>
-  <string name="error__upload__local_file_not_copied">%1$s no puede ser copiado al %2$s directorio local </string>
-  <string name="actionbar_failed_instant_upload">Carga instantánea fallida</string>
-  <string name="failed_upload_headline_text">Cargas instantáneas fallidas</string>
-  <string name="failed_upload_headline_hint">Resumen de todas las cargas instantáneas fallidas</string>
-  <string name="failed_upload_all_cb">Seleccionar todos</string>
-  <string name="failed_upload_headline_retryall_btn">Reintentar todos los seleccionados</string>
-  <string name="failed_upload_headline_delete_all_btn">Eliminar todo de la cola de subida</string>
-  <string name="failed_upload_retry_text">Reintentar subida de imagen:</string>
-  <string name="failed_upload_load_more_images">Cargar mas imágenes</string>
-  <string name="failed_upload_retry_do_nothing_text">No hacer nada no está conectado para subida instantánea</string>
-  <string name="failed_upload_failure_text">Mensaje de error:</string>
-  <string name="failed_upload_quota_exceeded_text">Por favor revise su configuración de servidor, posiblemente su cuota se haya excedido.</string>
+  <string name="error__upload__local_file_not_copied">%1$s se pudo copiar a la carpeta local %2$s</string>
+  <string name="prefs_instant_upload_path_title">Ruta de subida</string>
+  <string name="share_link_no_support_share_api">La función Compartir no está activada en su servidor. Contacte a su
+               administrador.</string>
+  <string name="share_link_file_no_exist">No se puede compartir. Revise si el archivo existe</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="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="error_cant_bind_to_operations_service">Error crítico: no es posible realizar operaciones</string>
+  <string name="network_error_socket_exception">Ocurrió un error al conectarse con el servidor.</string>
+  <string name="network_error_socket_timeout_exception">Ocurrió un error al esperar la respuesta del servidor, la operación no se pudo realizar</string>
+  <string name="network_error_connect_timeout_exception">Ocurrió un error al esperar la respuesta del servidor, la operación no se pudo realizar</string>
+  <string name="network_host_not_available">La operación no se pudo completar; el servidor no está disponible</string>
+  <string name="empty"></string>
+  <string name="forbidden_permissions">No tiene permiso %s</string>
+  <string name="forbidden_permissions_rename">para renombrar este archivo</string>
+  <string name="forbidden_permissions_delete">para eliminar 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 archivos a esta carpeta</string>
+  <string name="downloader_download_file_not_found">Este archivo ya no se encuentra en el servidor</string>
+  <string name="prefs_category_accounts">Cuentas</string>
+  <string name="prefs_add_account">Agregar cuenta</string>
+  <string name="auth_redirect_non_secure_connection_title">La conexión segura está siendo desviada por una ruta insegura.</string>
+  <string name="actionbar_logger">Logs</string>
+  <string name="log_send_history_button">Enviar historial</string>
+  <string name="log_mail_subject">Logs de las apps ownCloud Android</string>
+  <string name="log_progress_dialog_text">Cargando datos...</string>
+  <string name="saml_authentication_required_text">Se necesita autenticación</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="move_choose_button_text">Seleccionar</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="move_file_error">Hubo un error al tratar de mover este archivo o carpeta</string>
+  <string name="forbidden_permissions_move">para mover este archivo</string>
+  <string name="prefs_category_instant_uploading">Subidas instantáneas</string>
+  <string name="prefs_category_security">Seguridad</string>
 </resources>
index 4c55fb4..daba47f 100644 (file)
@@ -7,17 +7,20 @@
   <string name="actionbar_upload_from_apps">Sisu teistest rakendustest</string>
   <string name="actionbar_upload_files">Failid</string>
   <string name="actionbar_open_with">Ava rakendusega</string>
-  <string name="actionbar_mkdir">Loo kaust</string>
+  <string name="actionbar_mkdir">Uus kaust</string>
   <string name="actionbar_settings">Seaded</string>
   <string name="actionbar_see_details">Üksikasjad</string>
+  <string name="actionbar_send_file">Saada</string>
   <string name="prefs_category_general">Üldine</string>
   <string name="prefs_category_more">Rohkem</string>
   <string name="prefs_accounts">Kontod</string>
   <string name="prefs_manage_accounts">Halda kontosid</string>
   <string name="prefs_pincode">Rakenduse PIN</string>
   <string name="prefs_pincode_summary">Kaitse oma klienti</string>
-  <string name="prefs_instant_upload">Luba kohene üleslaadimine</string>
-  <string name="prefs_instant_upload_summary">Lae kaamera poolt tehtud fotod automaatselt üles</string>
+  <string name="prefs_instant_upload">Piltide kohene üleslaadimine</string>
+  <string name="prefs_instant_upload_summary">Laadi koheselt üles kaameraga tehtud pildid</string>
+  <string name="prefs_instant_video_upload">Videote kohene üleslaadimine</string>
+  <string name="prefs_instant_video_upload_summary">Laadi koheselt üles kaameraga tehtud videod</string>
   <string name="prefs_log_title">Luba logimine</string>
   <string name="prefs_log_summary">Kasutatakse probleemide logimiseks</string>
   <string name="prefs_log_title_history">Logi ajalugu</string>
@@ -28,9 +31,9 @@
   <string name="prefs_feedback">Tagasiside</string>
   <string name="prefs_imprint">Impressum</string>
   <string name="recommend_subject">Proovi oma nutitelefonil rakendust %1$s!</string>
-  <string name="recommend_text">Soovin sind kutsuda kasutama oma nutitelefonil rakendust %1$s!\nLae alla siit: %2$s</string>
+  <string name="recommend_text">Kutsun sind kasutama oma nutitelefonis rakendust %1$s!\nLaadi see alla siit: %2$s</string>
   <string name="auth_check_server">Kontrolli serverit</string>
-  <string name="auth_host_url">Serveri aadress</string>
+  <string name="auth_host_url">Serveri aadress https://...</string>
   <string name="auth_username">Kasutajanimi</string>
   <string name="auth_password">Parool</string>
   <string name="auth_register">Uus %1$s kasutaja?</string>
@@ -46,7 +49,9 @@
   <string name="uploader_wrn_no_content_text">Sisu ei saadud. Pole midagi üles laadida.</string>
   <string name="uploader_error_forbidden_content">%1$sile pole lubatud ligipääs jagatud sisule</string>
   <string name="uploader_info_uploading">Üleslaadimine</string>
-  <string name="file_list_empty">Selles kaustas pole ühtegi faili.\nUusi faile saab lisada kasutades menüü valikut \"Lae üles\".</string>
+  <string name="file_list_empty">Siin pole midagi. Lae midagi üles!</string>
+  <string name="file_list_loading">Laen ...</string>
+  <string name="local_file_list_empty">Kaustas pole faile.</string>
   <string name="filedetails_select_file">Lisainfo vaatamiseks vajuta failile.</string>
   <string name="filedetails_size">Suurus:</string>
   <string name="filedetails_type">Tüüp:</string>
@@ -55,6 +60,8 @@
   <string name="filedetails_download">Lae alla</string>
   <string name="filedetails_sync_file">Värskenda faili</string>
   <string name="filedetails_renamed_in_upload_msg">Fail nimetati üleslaadimise käigus ümber %1$ </string>
+  <string name="action_share_file">Jaga linki</string>
+  <string name="action_unshare_file">Tühista lingi jagamine</string>
   <string name="common_yes">Jah</string>
   <string name="common_no">Ei</string>
   <string name="common_ok">OK</string>
@@ -77,6 +84,7 @@
   <string name="uploader_upload_succeeded_content_single">%1$s laeti üles</string>
   <string name="uploader_upload_failed_ticker">Üleslaadimine ebaõnnestus</string>
   <string name="uploader_upload_failed_content_single">%1$s üleslaadimise lõpetamine ebaõnnestus</string>
+  <string name="uploader_upload_failed_credentials_error">Üleslaadimine ebaõnnestus, sa pead uuesti sisse logima</string>
   <string name="downloader_download_in_progress_ticker">Allalaadimine ...</string>
   <string name="downloader_download_in_progress_content">%1$d%% allalaadimine %2$s</string>
   <string name="downloader_download_succeeded_ticker">Allalaadimine oli edukas</string>
   <string name="downloader_download_failed_ticker">Allalaadimine ebaõnnestus</string>
   <string name="downloader_download_failed_content">%1$s allalaadimist ei õnnestunud lõpetada</string>
   <string name="downloader_not_downloaded_yet">Allalaadimata</string>
+  <string name="downloader_download_failed_credentials_error">Allaladimine ebaõnnestus, sa pead uuesti sisse logima</string>
   <string name="common_choose_account">Vali konto</string>
   <string name="sync_fail_ticker">Sünkroniseerimine ebaõnnestus</string>
+  <string name="sync_fail_ticker_unauthorized">Sünkroniseering katkes, pead uuesti sisse logima</string>
   <string name="sync_fail_content">%1$s sünkroniseerimise lõpetamine ebaõnnestus</string>
   <string name="sync_fail_content_unauthorized">Vigane parool %1$s jaoks</string>
   <string name="sync_conflicts_in_favourites_ticker">Leite konflikte</string>
   <string name="sync_fail_in_favourites_ticker">Sünkroniseeritavad failid ebaõnnestusid</string>
   <string name="sync_fail_in_favourites_content">Faili %1$d sisu ei suudeta sünkroniseerida (konflikt %2$d)</string>
   <string name="sync_foreign_files_forgotten_ticker">Osad kohalikud faili ununesid</string>
-  <string name="sync_foreign_files_forgotten_content">%1$d faili %2$s kataloogist ei suudeta kopeerida</string>
-  <string name="sync_foreign_files_forgotten_explanation">Alates versioonist 1.3.16 failid, mis on üles laetud kopeeritakse kohalikku kataloogi %1$s vältimaks andmete kadu, kui ühte faili sünkroniseeritakse mitmelt kontolt.\n\nSelle muudatusega seoses kõik failid, mis on üles laetud rakenduse vanemate versioonidega, kopeeriti kataloogi %2$s. Selle tegevuse peatas viga, mis tekkis konto sünkroniseerimise käigus. Sa saad jätta failid nagu nad on ning eemaldata viide %3$s või tõsta failid %1$s kataloogi ja säilitada viide %4$s.\n\nAllpool on loend kohalikest failidest ning serveris asuvatest failidest %5$s millele nad viitavad.</string>
+  <string name="sync_foreign_files_forgotten_content">%1$d faili %2$s kataloogis ei saa kopeerida</string>
+  <string name="sync_foreign_files_forgotten_explanation">Alates versioonist 1.3.16 failid, mis on üles laaditud kopeeritakse kohalikku kataloogi %1$s vältimaks andmete kadu vältimaks andmete kadu juhul, kui ühte faili sünkroniseeritakse mitmelt kontolt.
+
+Selle muudatusega seoses kõik failid, mis on üles laetud rakenduse vanemate versioonidega, kopeeriti kataloogi %2$s.  Selle tegevuse peatas viga, mis tekkis konto sünkroniseerimise käigus. Sa saad jätta faili(d) nagu nad on ning eemaldata viite %3$s või tõsta faili(d) %1$s kataloogi ja säilitada viite %4$s. 
+
+Allpool on loend kohalikest failidest ning serveris asuvatest failidest %5$s, millele nad viitavad.</string>
   <string name="sync_current_folder_was_removed">Kausta %1$s pole enam olemas</string>
   <string name="foreign_files_move">Tõsta kõik ümber</string>
   <string name="foreign_files_success">Kõik failid tõsteti ümber</string>
   <string name="foreign_files_fail">Mõningaid faile ei saa ümber tõsta</string>
   <string name="foreign_files_local_text">Kohalik: %1$s</string>
   <string name="foreign_files_remote_text">Serveris: %1$s</string>
-  <string name="upload_query_move_foreign_files">Pole piisavalt ruumi kopeerimaks valitud faile kataloogi %1$s. Soovid kopeerimise asemel neid ümber tõsta?</string>
+  <string name="upload_query_move_foreign_files">Pole piisavalt ruumi kopeerimaks valitud faile kataloogi %1$s. Kas soovid kopeerimise asemel neid ümber tõsta?</string>
   <string name="pincode_enter_pin_code">Palun sisesta oma rakenduse PIN</string>
   <string name="pincode_configure_your_pin">Sisesta oma rakenduse PIN</string>
   <string name="pincode_configure_your_pin_explanation">PIN-i nõutakse iga kord, kui rakendus käivitatakse</string>
   <string name="media_rewind_description">Tagasikerimise nupp</string>
   <string name="media_play_pause_description">Mängimise või pausi nupp</string>
   <string name="media_forward_description">Kiire kerimise nupp</string>
+  <string name="auth_getting_authorization">Autoriseerin...</string>
   <string name="auth_trying_to_login">Proovitakse sisse logida...</string>
   <string name="auth_no_net_conn_title">Võrguühendust pole</string>
   <string name="auth_nossl_plain_ok_title">Turvaline ühendus pole saadaval</string>
   <string name="auth_connecting_auth_server">Autentimisserveriga ühendumine ...</string>
   <string name="auth_unsupported_auth_method">See server ei toeta seda autentimise viisi</string>
   <string name="auth_unsupported_multiaccount">%1$s ei toeta mitme konto kasutamist</string>
+  <string name="auth_fail_get_user_name">Server ei tagasta korrektset kasutaja ID-d. Palun kontakteeru administraatoriga.
+⇥</string>
+  <string name="auth_can_not_auth_against_server">Ei suuda autoriseerida selle serveriga.</string>
   <string name="fd_keep_in_sync">Hoia faili ajakohasena</string>
   <string name="common_rename">Nimeta ümber</string>
   <string name="common_remove">Eemalda</string>
-  <string name="confirmation_remove_alert">Oled sa kindel, et soovid %1$s eemaldada ?</string>
-  <string name="confirmation_remove_folder_alert">Kas sa tõesti soovid eemaldada %1$s ja selle sisu ?</string>
+  <string name="confirmation_remove_alert">Oled sa kindel, et soovid %1$s eemaldada?</string>
+  <string name="confirmation_remove_folder_alert">Kas sa tõesti soovid eemaldada %1$s ja selle sisu?</string>
   <string name="confirmation_remove_local">Ainult kohalik</string>
   <string name="confirmation_remove_folder_local">Ainult kohalik sisu</string>
   <string name="confirmation_remove_remote">Eemalda serverist</string>
   <string name="rename_server_fail_msg">Ümbernimetamine ebaõnnestus</string>
   <string name="sync_file_fail_msg">Mujaloleva faili kontrollimine ebaõnnestus</string>
   <string name="sync_file_nothing_to_do_msg">Faili sisu on juba sünkroniseeritud</string>
-  <string name="create_dir_fail_msg">Kausta loomine ebaõnnestus</string>
+  <string name="create_dir_fail_msg">Kataloogi ei saa tekitada</string>
+  <string name="filename_forbidden_characters">Keelatud sümbolid:  / \\ &lt; &gt; : \" | ? *</string>
+  <string name="filename_empty">Faili nime lahter ei saa olla tühi</string>
   <string name="wait_a_moment">Oota hetk</string>
   <string name="filedisplay_unexpected_bad_get_content">Ootamatu tõrge ; palun kasuta faili valimiseks mõnda teist rakendust</string>
   <string name="filedisplay_no_file_selected">Ühtegi faili pole valitud</string>
+  <string name="activity_chooser_title">Saada link</string>
   <string name="oauth_check_onoff">Logi sisse oAuth2-ga</string>
   <string name="oauth_login_connection">oAuth2 serveriga ühendumine...</string>
   <string name="ssl_validator_header">Saidi identiteeti ei suudetud kinnitada</string>
   <string name="ssl_validator_label_validity_to">Saaja:</string>
   <string name="ssl_validator_label_signature">Allkiri:</string>
   <string name="ssl_validator_label_signature_algorithm">Algoritm:</string>
+  <string name="ssl_validator_null_cert">Ei suuda kuvada sertifikaati.</string>
+  <string name="ssl_validator_no_info_about_error">- Vea kohta puudub info</string>
   <string name="placeholder_sentence">See on kohahoidja</string>
   <string name="placeholder_filename">placeholder.txt</string>
   <string name="placeholder_filetype">PNG pilt</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">Lae pilte üles ainult läbi WiFi</string>
+  <string name="instant_video_upload_on_wifi">Laadi videod üles ainult WiFi-t kasutades</string>
   <string name="instant_upload_path">/InstantUpload</string>
   <string name="conflict_title">Uuenduse konflikt</string>
   <string name="conflict_message">Serveris asuvat faili ei sünkroniseeritud kohaliku failiga. Jätkates kirjutatakse serveris asuva faili sisu üle.</string>
   <string name="conflict_dont_upload">Ära uuenda</string>
   <string name="preview_image_description">Pildi eelvaade</string>
   <string name="preview_image_error_unknown_format">Seda pilti ei saa näidata</string>
-  <string name="error__upload__local_file_not_copied">%1$s ei suudetud kopeerida kohalikku kataloogi failina %2$s</string>
-  <string name="actionbar_failed_instant_upload">Ebaõnnestunud kohene üleslaadimine</string>
-  <string name="failed_upload_headline_text">Ebaõnnestunud kohesed üleslaadimised</string>
-  <string name="failed_upload_headline_hint">Kõikide ebaõnnestunud üleslaadimiste kokkuvõte</string>
-  <string name="failed_upload_all_cb">vali kõik</string>
-  <string name="failed_upload_headline_retryall_btn">proovi uuesti kõik valitud</string>
-  <string name="failed_upload_headline_delete_all_btn">eemalda kõik valitud üleslaadimise järjekorrast</string>
-  <string name="failed_upload_retry_text">proovi uuesti pilti üles laadida:</string>
-  <string name="failed_upload_load_more_images">Lae veel pilte</string>
-  <string name="failed_upload_retry_do_nothing_text">ära tee midagi, sa pole võrku ühendatud koheseks üleslaadimiseks</string>
-  <string name="failed_upload_failure_text">Veateade:</string>
-  <string name="failed_upload_quota_exceeded_text">Palun kontrolli oma serveri seadeid, võib-olla on mahulimiit ületatud.</string>
+  <string name="error__upload__local_file_not_copied">%1$s ei suudetud kopeerida kohalikku kataloogi %2$s</string>
+  <string name="prefs_instant_upload_path_title">Üleslaadimise rada</string>
+  <string name="share_link_no_support_share_api">Vabandust, server ei toeta jagamist. Palun kontakteeru 
+⇥⇥administraatoriga.</string>
+  <string name="share_link_file_no_exist">Jagamine ebaõnnestus. Palun kontrolli, kas fail on olemas</string>
+  <string name="share_link_file_error">Faili või kausta jagamisel esines viga</string>
+  <string name="unshare_link_file_no_exist">Liigutamise lõpetamine ebaõnnestus. Palun kontrolli, kas fail on olemas</string>
+  <string name="unshare_link_file_error">Faili või kausta jagamise tühistamisel esines viga</string>
+  <string name="activity_chooser_send_file_title">Saada</string>
+  <string name="copy_link">Kopeeri link</string>
+  <string name="clipboard_text_copied">Kopeeritud lõikepuhvrisse</string>
+  <string name="error_cant_bind_to_operations_service">Viga: ei suutnud operatsiooni lõpetada</string>
+  <string name="network_error_socket_exception">Serveriga ühendumisel tekkis tõrge.</string>
+  <string name="network_error_socket_timeout_exception">Serverilt vastuse ootamisel tekkis tõrge, toimingu sooritamine ebaõnnestus</string>
+  <string name="network_error_connect_timeout_exception">Serverilt vastuse ootamisel tekkis tõrge, toimingu sooritamine ebaõnnestus</string>
+  <string name="network_host_not_available">Toimingu lõpetamine ebaõnnestus, server pole saadaval</string>
+  <string name="empty"></string>
+  <string name="forbidden_permissions">Sul ei ole %s õigusi</string>
+  <string name="forbidden_permissions_rename">selle faili ümbernimetamiseks</string>
+  <string name="forbidden_permissions_delete">selle faili kustutamiseks</string>
+  <string name="share_link_forbidden_permissions">faili jagamiseks</string>
+  <string name="unshare_link_forbidden_permissions">faili jagamise lõpetamiseks</string>
+  <string name="forbidden_permissions_create">faili loomiseks</string>
+  <string name="uploader_upload_forbidden_permissions">sellesse kausta laadimiseks</string>
+  <string name="downloader_download_file_not_found">Fail ei ole serveris enam kättesaadav</string>
+  <string name="prefs_category_accounts">Kontod</string>
+  <string name="prefs_add_account">Lisa konto</string>
+  <string name="auth_redirect_non_secure_connection_title">Turvaline ühendus suunatakse läbi turvamata ühenduse.</string>
+  <string name="actionbar_logger">Logid</string>
+  <string name="log_send_history_button">Saada ajalugu</string>
+  <string name="log_mail_subject">ownCloud Android rakenduse logid</string>
+  <string name="log_progress_dialog_text">Andmete laadimine...</string>
+  <string name="saml_authentication_required_text">Autentimine on vajalik</string>
+  <string name="saml_authentication_wrong_pass">Vale parool</string>
+  <string name="actionbar_move">Tõsta ümber</string>
+  <string name="file_list_empty_moving">Siin pole midagi. Sa võid lisada kausta!</string>
+  <string name="move_choose_button_text">Vali</string>
+  <string name="move_file_not_found">Liigutamine ebaõnnestus. Palun kontrolli, kas fail on olemas</string>
+  <string name="move_file_invalid_into_descendent">Kausta ei saa liigutada selle alamkausta</string>
+  <string name="move_file_invalid_overwrite">See fail on juba sihtkaustas olemas</string>
+  <string name="move_file_error">Selle faili või kausta liigutamisel tekkis tõrge</string>
+  <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>
 </resources>
diff --git a/res/values-eu-rES/strings.xml b/res/values-eu-rES/strings.xml
new file mode 100644 (file)
index 0000000..a9461fc
--- /dev/null
@@ -0,0 +1,6 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<resources>
+  <string name="filedetails_download">Deskargatu</string>
+  <string name="common_cancel">Ezeztatu</string>
+  <string name="empty"></string>
+</resources>
index 03c5705..fec7404 100644 (file)
@@ -7,33 +7,39 @@
   <string name="actionbar_upload_from_apps">Beste app-en edukia</string>
   <string name="actionbar_upload_files">Fitxategiak</string>
   <string name="actionbar_open_with">Ireki honekin</string>
-  <string name="actionbar_mkdir">Sortu karpeta</string>
+  <string name="actionbar_mkdir">Karpeta berria</string>
   <string name="actionbar_settings">Ezarpenak</string>
   <string name="actionbar_see_details">Xehetasunak</string>
+  <string name="actionbar_send_file">Bidali</string>
   <string name="prefs_category_general">Orokorra</string>
   <string name="prefs_category_more">Gehiago</string>
   <string name="prefs_accounts">Kontuak</string>
   <string name="prefs_manage_accounts">Kontuak kudeatu</string>
   <string name="prefs_pincode">App PIN</string>
   <string name="prefs_pincode_summary">Babestu zure bezeroa</string>
-  <string name="prefs_instant_upload">Gaitu berehalako igoera</string>
+  <string name="prefs_instant_upload">Uneko irudi igoerak</string>
   <string name="prefs_instant_upload_summary">Igo berehala kamerak ateratako argazkiak</string>
+  <string name="prefs_instant_video_upload">Uneko bideo igoerak</string>
+  <string name="prefs_instant_video_upload_summary">Igo berehala kamerak filmatutako bideoak</string>
   <string name="prefs_log_title">Gaitu erregistroa</string>
   <string name="prefs_log_summary">Arazoen erregistroa gordetzeko erabiltzen da</string>
   <string name="prefs_log_title_history">Erregistro historia</string>
   <string name="prefs_log_summary_history">Honek gordetako erregistroak bistaratzen ditu.</string>
   <string name="prefs_log_delete_history_button">Ezabatu historia</string>
   <string name="prefs_help">Laguntza</string>
+  <string name="prefs_recommend">Lagun bati aholkatu</string>
+  <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="auth_check_server">Egiaztatu zerbitzaria</string>
-  <string name="auth_host_url">Zerbitzariaren helbidea</string>
+  <string name="auth_host_url">Zerbitzariaren helbidea https://</string>
   <string name="auth_username">Erabiltzaile izena</string>
   <string name="auth_password">Pasahitza</string>
   <string name="auth_register">Berria %1$s-n?</string>
   <string name="sync_string_files">Fitxategiak</string>
   <string name="setup_btn_connect">Konektatu</string>
   <string name="uploader_btn_upload_text">Igo</string>
-  <string name="uploader_top_message">Hautatu igoera direktorioa:</string>
+  <string name="uploader_top_message">Hautatu igoera karpeta:</string>
   <string name="uploader_wrn_no_account_title">Ez da konturik aurkitu</string>
   <string name="uploader_wrn_no_account_text">Zure gailuan ez dago %1$s konturik. Mesedez konfiguratu kontu bat lehenengo.</string>
   <string name="uploader_wrn_no_account_setup_btn_text">Konfiguratu</string>
@@ -42,7 +48,9 @@
   <string name="uploader_wrn_no_content_text">Ez da edukirik jaso. Ez dago ezer igotzeko.</string>
   <string name="uploader_error_forbidden_content">%1$s-(e)k ez du baimenik elkarbanatutako edukian sartzeko</string>
   <string name="uploader_info_uploading">Igotzen</string>
-  <string name="file_list_empty">Ez dago fitxategirik karpeta honetan.\nFitxategi berriak \"Igo\" menu aukerarekin gehi daitezke.</string>
+  <string name="file_list_empty">Ez dago ezer. Igo zerbait!</string>
+  <string name="file_list_loading">Kargatzen...</string>
+  <string name="local_file_list_empty">Ez dago fitxategirik karpeta honetan.</string>
   <string name="filedetails_select_file">Sakatu fitxategi baten gainean informazio gehiago lortzeko</string>
   <string name="filedetails_size">Tamaina:</string>
   <string name="filedetails_type">Mota:</string>
@@ -51,6 +59,8 @@
   <string name="filedetails_download">Deskargatu</string>
   <string name="filedetails_sync_file">Freskatu fitxaegia</string>
   <string name="filedetails_renamed_in_upload_msg">Fitxategiaren izena %1$sra aldatu da igotzean</string>
+  <string name="action_share_file">Elkarbanatu lotura</string>
+  <string name="action_unshare_file">Lotura partekatzeari utzi</string>
   <string name="common_yes">Bai</string>
   <string name="common_no">Ez</string>
   <string name="common_ok">Ados</string>
@@ -73,6 +83,7 @@
   <string name="uploader_upload_succeeded_content_single">%1$s ongi igo da</string>
   <string name="uploader_upload_failed_ticker">igotzeak huts egin du</string>
   <string name="uploader_upload_failed_content_single">%1$s fitxategiaren igoera ezin izan da burutu</string>
+  <string name="uploader_upload_failed_credentials_error">Huts egin du igotzen, berriro sartu behar duzu</string>
   <string name="downloader_download_in_progress_ticker">Deskargatzen ...</string>
   <string name="downloader_download_in_progress_content">%1$d%% Deskargatzen %2$s</string>
   <string name="downloader_download_succeeded_ticker">Deskarga ongi burutu da</string>
   <string name="downloader_download_failed_ticker">Deskargak huts egin du</string>
   <string name="downloader_download_failed_content">%1$s fitxategiaren deskarga ezin izan da burutu</string>
   <string name="downloader_not_downloaded_yet">Oraindik deskargatu gabe</string>
+  <string name="downloader_download_failed_credentials_error">Huts egin du deskargatzen, berriro sartu behar duzu</string>
   <string name="common_choose_account">Hautatu kontua</string>
   <string name="sync_fail_ticker">Sinkronizazioak huts egin du</string>
+  <string name="sync_fail_ticker_unauthorized">Huts egin du sinkronizatzen, berriro sartu behar duzu</string>
   <string name="sync_fail_content">%1$s fitxategiaren sinkronizazioa ezin da burutu</string>
   <string name="sync_fail_content_unauthorized">Okerreko pasahitza %1$s-rako</string>
   <string name="sync_conflicts_in_favourites_ticker">Gatazkak aurkituak </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_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>
   <string name="foreign_files_fail">Fitxategi batzuk ezin dira mugitu</string>
   <string name="media_err_unsupported">Onartzen ez de euskarri kodeka</string>
   <string name="media_err_io">Euskarri fitxategia ezin da bihurtu</string>
   <string name="media_err_malformed">Euskarri fitxategia ezin da kodetu</string>
+  <string name="media_err_timeout">Erreproduzitzen saiatzean denbora iraungitu da</string>
   <string name="media_err_invalid_progressive_playback">Euskarri fitxategia ezin da jariotu</string>
   <string name="media_err_unknown">Euskarri fitxategia ezin erreproduzitu stock euskarri erreproduzigailuarekin</string>
   <string name="media_err_security_ex">Segurtasun errorea %1$s erreproduzitzen saiatzean</string>
   <string name="media_rewind_description">Atzeratu botoia</string>
   <string name="media_play_pause_description">Erreproduzitu edo pausatu botoia</string>
   <string name="media_forward_description">Azkar aurreratu botoia</string>
+  <string name="auth_getting_authorization">Baimena eskuratzen...</string>
   <string name="auth_trying_to_login">Saioa hasten saiatzen...</string>
   <string name="auth_no_net_conn_title">Ez dago sare konexiorik</string>
   <string name="auth_nossl_plain_ok_title">Konexio segurua ez dago eskuragarri</string>
   <string name="auth_connection_established">Konexioa ezarri da</string>
   <string name="auth_testing_connection">Konexioa probatzen...</string>
   <string name="auth_not_configured_title">gaizki egindako server konfigurazioa</string>
+  <string name="auth_account_not_new">Erabiltzaile eta zerbitzari hauendako dagoeneko kontu bat  existitzen da gailu honetan</string>
+  <string name="auth_account_not_the_same">Sartutako erabiltzaileak ez du bat egiten kontu honetako erabiltzailearekin</string>
   <string name="auth_unknown_error_title">Errore ezezagun bat gertatu da</string>
   <string name="auth_unknown_host_title">Ezin izan da hostalaria aurkitu</string>
   <string name="auth_incorrect_path_title">ez da serveren instalaziorik aurkitu</string>
   <string name="auth_timeout_title">Zerbitzariak denbora asko hartu du erantzuteko</string>
   <string name="auth_incorrect_address_title">Gaizki sortutako URLa</string>
   <string name="auth_ssl_general_error_title">SSL abiaratzeak huts egin du</string>
+  <string name="auth_ssl_unverified_server_title">Ezin izan da SSL zerbitzariaren identitaea egiaztatu</string>
   <string name="auth_bad_oc_version_title">server zerbitzari bertsio ezezaguna</string>
   <string name="auth_wrong_connection_title">Ezin izan da konexioa egin</string>
   <string name="auth_secure_connection">Konexio segurua ezarri da</string>
   <string name="auth_oauth_error">Baimena ez da lortu</string>
   <string name="auth_oauth_error_access_denied">Sarrera autorizazio zerbitzariak ukatua</string>
   <string name="auth_wtf_reenter_URL">Egoera esperogabea, mesedez idatzi berriz zerbitzari URLa</string>
+  <string name="auth_expired_oauth_token_toast">Zure baimena iraungitu da.
+Mesedez, baimendu berriz</string>
   <string name="auth_expired_basic_auth_toast">Mesedez, sartu oraingo pasahitza</string>
+  <string name="auth_expired_saml_sso_token_toast">Zure saioa iraungitu da. Mesdez konektatu berriro</string>
+  <string name="auth_connecting_auth_server">Konektatzen autentikazio zerbitzarira...</string>
+  <string name="auth_unsupported_auth_method">Zerbitzariak ez du autentikazio metodo hau onartzen</string>
+  <string name="auth_unsupported_multiaccount">%1$s ez du kontu anitzak onartzen</string>
+  <string name="auth_fail_get_user_name">Zure zerbitzariak ez du bueltatzen erabiltzailearen id egokia, mesedez jarri harremanetan administratzailearekin.</string>
+  <string name="auth_can_not_auth_against_server">Ezin da autentikatu zerbitzarian.</string>
   <string name="fd_keep_in_sync">Mantendu fitxategia eguneratuta</string>
   <string name="common_rename">Berrizendatu</string>
   <string name="common_remove">Ezabatu</string>
-  <string name="confirmation_remove_alert">Nahi duzu %1$s ezabatu?</string>
-  <string name="confirmation_remove_folder_alert">Benetan %1$s eta bere eduki guztiak ezabatu nahi dituzu?</string>
+  <string name="confirmation_remove_alert">Ziur zaude %1$s ezabatu nahi duzula?</string>
+  <string name="confirmation_remove_folder_alert">Ziru zaude %1$s eta bere edukiak ezabatu nahi dituzula?</string>
   <string name="confirmation_remove_local">Bertakoa bakarrik</string>
   <string name="confirmation_remove_folder_local">Eduki lokalak bakarrik</string>
   <string name="confirmation_remove_remote">Zerbitzaritik ezabatu</string>
   <string name="rename_server_fail_msg">Izen aldaketa ezin izan da burutu</string>
   <string name="sync_file_fail_msg">Urruneko fitxategia ezin izan da arakatu</string>
   <string name="sync_file_nothing_to_do_msg">Fitxategi edukiak dagoeneko sinkronizaturik</string>
-  <string name="create_dir_fail_msg">Karpeta ezin da sortu</string>
+  <string name="create_dir_fail_msg">Ezin izan da karpeta sortu</string>
+  <string name="filename_forbidden_characters">Debekatutako karaktereak: / \\ &lt; &gt; : \" | ? *</string>
+  <string name="filename_empty">Fitxategi izena ezin da hutsa izan</string>
   <string name="wait_a_moment">Itxaron momentu bat</string>
   <string name="filedisplay_unexpected_bad_get_content">Ezusteko arazoa; mesedez, saiatu beste app batekin fitxategia hautatzeko</string>
   <string name="filedisplay_no_file_selected">Ez da fitxategirik hautatu</string>
+  <string name="activity_chooser_title">Bidali lotura honi...</string>
+  <string name="oauth_check_onoff">Saioa hasi oAuth2-rekin</string>
   <string name="oauth_login_connection">Konektatzen oAuth2 zerbitzarira...</string>
   <string name="ssl_validator_header">Lekuaren identitatea ezin da egiaztatu</string>
   <string name="ssl_validator_reason_cert_not_trusted">- Zerbitzariaren ziurtagiria ez da fidagarria</string>
   <string name="ssl_validator_label_validity_to">Noiz arte:</string>
   <string name="ssl_validator_label_signature">Sinadura:</string>
   <string name="ssl_validator_label_signature_algorithm">Algoritmoa:</string>
+  <string name="ssl_validator_null_cert">Ezin da ziurtagiria erakutsi.</string>
+  <string name="ssl_validator_no_info_about_error">- Ez dago errorearen gaineko informaziorik.</string>
   <string name="placeholder_sentence">Hau leku-marka da</string>
   <string name="placeholder_filename">kokalekua.txt</string>
   <string name="placeholder_filetype">PNG Irudia</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">Igo irudiak bakarrik WIFIren bidez</string>
+  <string name="instant_video_upload_on_wifi">Igo bideoak bakarrik WIFIren bidez</string>
   <string name="instant_upload_path">/BerehalakoIgoerak</string>
   <string name="conflict_title">Igoera konfliktoa</string>
   <string name="conflict_message">Urruneko %s fitxategia ez dago bertako fitxategiarekin sinkronizatuta. Jarraituz gero zerbitzariko fitxategiaren edukia ordeztuko da.</string>
   <string name="conflict_dont_upload">Ez igo</string>
   <string name="preview_image_description">Irudi aurreikuspena</string>
   <string name="preview_image_error_unknown_format">Ezin da irudi hau erakutsi</string>
-  <string name="error__upload__local_file_not_copied">%1$s ezin da %2$s bertako karpetara kopiatu</string>
-  <string name="actionbar_failed_instant_upload">UnekoIgoerak huts egin du\"</string>
-  <string name="failed_upload_headline_text">Uneko igoerek huts egin dute</string>
-  <string name="failed_upload_headline_hint">Huts egindako igoeren laburpena</string>
-  <string name="failed_upload_all_cb">Hautatu dena</string>
-  <string name="failed_upload_headline_retryall_btn">Berriz saiatu hautatutakoak</string>
-  <string name="failed_upload_headline_delete_all_btn">kendu hautatutakoak igoera-ilaratik</string>
-  <string name="failed_upload_retry_text">Berriz saiatu irudia igotzen:</string>
-  <string name="failed_upload_load_more_images">Kargatu irudi gehiago</string>
-  <string name="failed_upload_retry_do_nothing_text">ez egin ezer ez zaude on-line uneko igoerarentzat</string>
-  <string name="failed_upload_failure_text">Hutsegite mezua:</string>
-  <string name="failed_upload_quota_exceeded_text">Egiaztatu zure konfigurazioa, agian zure kuota muga gainditu  duzu.</string>
+  <string name="error__upload__local_file_not_copied">%1$s ezin da %2$s karpeta lokalera kopiatu</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_error">Errore bat egon da fitxategaia edo karpeta partekatzerakoan</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>
+  <string name="clipboard_text_copied">Arbelera kopiatua</string>
+  <string name="error_cant_bind_to_operations_service">Errore larria: ezin dira egin eragiketak</string>
+  <string name="network_error_socket_exception">Errore bat gertatu da zerbitzariarekin konektatzean.</string>
+  <string name="network_error_socket_timeout_exception">Errore bat gertatu da zerbitzariaren zain egon bitartean, ezin izan da eragiketa burutu</string>
+  <string name="network_error_connect_timeout_exception">Errore bat gertatu da zerbitzariaren zain egon bitartean, ezin izan da eragiketa burutu</string>
+  <string name="network_host_not_available">Eragiketa ezin izan da burutu, zerbitzaria ez dago erabilgarri</string>
+  <string name="empty"></string>
+  <string name="forbidden_permissions">Ez daukazu baimenik %s</string>
+  <string name="forbidden_permissions_rename">fitxategia berrizendatzeko</string>
+  <string name="forbidden_permissions_delete">fitxategia ezabatzeko</string>
+  <string name="share_link_forbidden_permissions">fitxategia konpartitzeko</string>
+  <string name="unshare_link_forbidden_permissions">fitxategiaren konpartitzea kentzeko</string>
+  <string name="forbidden_permissions_create">fitxategia sortzeko</string>
+  <string name="uploader_upload_forbidden_permissions">karpeta honetara igotzeko</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="saml_authentication_required_text">Autentikazioa beharrezkoa</string>
+  <string name="saml_authentication_wrong_pass">Pasahitz okerra</string>
+  <string name="move_choose_button_text">Aukeratu</string>
+  <string name="prefs_category_security">Segurtasuna</string>
 </resources>
index 82336bc..6a22f89 100644 (file)
@@ -7,32 +7,35 @@
   <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_mkdir">پوشه جدید</string>
   <string name="actionbar_settings">تنظیمات</string>
   <string name="actionbar_see_details">جزئیات</string>
+  <string name="actionbar_send_file">ارسال</string>
   <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">PIN برنامه</string>
   <string name="prefs_pincode_summary">حفاظت از مشتری</string>
-  <string name="prefs_instant_upload">فعال کردن بارگذاری فوری</string>
-  <string name="prefs_instant_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="auth_host_url">آدرس سرور</string>
+  <string name="recommend_subject">%1$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="uploader_btn_upload_text">بارگزاری</string>
-  <string name="uploader_top_message">اÙ\86تخاب Ù\85سÛ\8cر Ø¨Ø±Ø§Û\8c آپلود:</string>
+  <string name="uploader_top_message">اÙ\86تخاب Ù¾Ù\88Ø´Ù\87 آپلود:</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>
@@ -41,7 +44,9 @@
   <string name="uploader_wrn_no_content_text">هیچ مطلبی دریافت نشده است. هیچ‌‌چیزی بارگزاری نشده.</string>
   <string name="uploader_error_forbidden_content">%1$s اجازه ی دسترسی به محتوای مشترک را نمی دهد</string>
   <string name="uploader_info_uploading">در حال بارگزاری</string>
-  <string name="file_list_empty">هیچ فایل در این پوشه نیست.\nفایل های جدید می توانند بوسیله ی گزینه ی \"بارگزاری\" در لیست اضافه کنید.</string>
+  <string name="file_list_empty">اینجا هیچ چیز نیست.</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>
@@ -50,6 +55,8 @@
   <string name="filedetails_download">بارگیری</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_choose_account">حساب کاربری را انتخاب کنید</string>
   <string name="sync_fail_ticker">همگام سازی ناموفق</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_conflicts_in_favourites_content">%1$d پرونده ها نمیتوانند همگام سازی شوند.</string>
   <string name="sync_fail_in_favourites_ticker">همگام سازی پرونده ها ناموفق بود.</string>
   <string name="sync_fail_in_favourites_content">محتوای %1$d فایل ها نمی توانند همگام باشند(%2$d ناسازگاری)</string>
   <string name="sync_foreign_files_forgotten_ticker">بعضی از فایلهای محلی فراموش شده اند</string>
-  <string name="sync_foreign_files_forgotten_content">در اینجا %1$d تعداد فایل از لیست %2$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">لطفا PIN برنامه خودتان را وارد کنید</string>
   <string name="pincode_configure_your_pin">PIN برنامه را وارد کنید</string>
   <string name="pincode_configure_your_pin_explanation">هر زمان که برنامه آغاز شود PIN درخواست خواهد شد.</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">فایل رسانه با استفاده از پخش کننده stock media player قابل پخش نیست.</string>
   <string name="media_err_security_ex">خطای امنیتی، تلاش برای پخش %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_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_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_unverified_server_title">نمی‌توان اصالت SSL سرور را احراز نمود</string>
   <string name="auth_bad_oc_version_title">نسخه ی سرور ناشناخته</string>
   <string name="auth_wrong_connection_title">نمیتوان ارتباط برقرار نمود.</string>
   <string name="auth_secure_connection">ایجاد ارتباط ایمن</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">حالت غیرمنتظره؛ لطفا آدرس URL سرور را مجددا وارد نمایید.</string>
+  <string name="auth_expired_oauth_token_toast">احراز هویت شما منقضی شده است. لطفا، مجددا احراز هویت فرمایید.</string>
+  <string name="auth_expired_basic_auth_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="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="rename_server_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="wait_a_moment">لحظه‌ای صبر کنید</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">- گواهی سرور نامعتبر است</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">placeholder.txt</string>
   <string name="placeholder_filetype">تصویربا فرمت PNG </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">تصاویر را فقط از طریق wifi بارگذاری کن</string>
+  <string name="instant_video_upload_on_wifi">آپلود ویدیو فقط از طریق WiFi</string>
   <string name="instant_upload_path">آپلود فوری</string>
   <string name="conflict_title">بارگذاری ناسازگار</string>
   <string name="conflict_message">فایل های دور از دسترس %s با فایل های محلی همگام نشده اند. ادامه کار، محتوا را بر روی فایل در سرور جایگزین خواهد کرد.</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="actionbar_failed_instant_upload">آپلود فوری انجام نشد\"</string>
-  <string name="failed_upload_headline_text">آپلود های فوری انجام نشدند.</string>
-  <string name="failed_upload_headline_hint">خلاصه ای از تمام ارسال های فور ی ناموفق.</string>
-  <string name="failed_upload_all_cb">انتخاب همه</string>
-  <string name="failed_upload_headline_retryall_btn">تلاش مجدد بر روی همه موارد انتخاب شده</string>
-  <string name="failed_upload_headline_delete_all_btn">حذف تمام انتخاب شده ها از صف ارسال.</string>
-  <string name="failed_upload_retry_text">تلاش برای آپلود کردن تصویر:</string>
-  <string name="failed_upload_load_more_images">بارگذاری تصاویر بیشتر</string>
-  <string name="failed_upload_retry_do_nothing_text">هیچ کاری انجام ندهید، شما برای آپلود فوری آنلاین نیستید.</string>
-  <string name="failed_upload_failure_text">پیغام عدم موفقیت:</string>
-  <string name="failed_upload_quota_exceeded_text">لطفا پیکربندی سرورتان را بررسی کنید، شاید سهمیه شما بیش از حد شده باشد.</string>
+  <string name="preview_image_error_unknown_format">نمایش این عکس امکانپذیر نمی باشد</string>
+  <string name="share_link_file_error">در حین اشتراک گذاری این فایل یا پوشه خطایی رخ داده است</string>
+  <string name="unshare_link_file_error">در حین حذف اشتراک گذاری این فایل یا پوشه خطایی رخ داده است</string>
+  <string name="activity_chooser_send_file_title">ارسال</string>
+  <string name="clipboard_text_copied">کپی به کلیپ بورد</string>
+  <string name="network_host_not_available">تکمیل عملیات امکانپذیر نمی باشد، سرور در دسترس نمی باشد</string>
+  <string name="empty"></string>
+  <string name="forbidden_permissions_rename">برای تغییر نام این فایل</string>
+  <string name="forbidden_permissions_delete">برای حذف این فایل</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="saml_authentication_required_text">احراز هویت مورد نیاز است</string>
+  <string name="saml_authentication_wrong_pass">رمز عبور اشتباه است</string>
+  <string name="move_choose_button_text">انتخاب کردن</string>
+  <string name="prefs_category_security">امنیت</string>
 </resources>
index abed4d1..6f02e4b 100644 (file)
@@ -7,27 +7,32 @@
   <string name="actionbar_upload_from_apps">Sisältö toisista sovelluksista</string>
   <string name="actionbar_upload_files">Tiedostot</string>
   <string name="actionbar_open_with">Avaa sovelluksella</string>
-  <string name="actionbar_mkdir">Luo kansio</string>
+  <string name="actionbar_mkdir">Uusi kansio</string>
   <string name="actionbar_settings">Asetukset</string>
   <string name="actionbar_see_details">Tiedot</string>
+  <string name="actionbar_send_file">Lähetä</string>
   <string name="prefs_category_general">Yleiset</string>
   <string name="prefs_category_more">Enemmän</string>
   <string name="prefs_accounts">Tilit</string>
   <string name="prefs_manage_accounts">Tilien hallinta</string>
   <string name="prefs_pincode">Sovelluksen PIN-koodi</string>
-  <string name="prefs_pincode_summary">Suojaa Asiakasohjelmasi</string>
-  <string name="prefs_instant_upload">Käytä välitöntä lähetystä</string>
+  <string name="prefs_pincode_summary">Suojaa asiakasohjelmasi</string>
+  <string name="prefs_instant_upload">Kuvien välitön lähetys</string>
   <string name="prefs_instant_upload_summary">Lähetä kameralla otetut kuvat välittömästi</string>
+  <string name="prefs_instant_video_upload">Välittömät videolähetykset</string>
+  <string name="prefs_instant_video_upload_summary">Lähetä kameralla kuvatut videot välittömästi</string>
   <string name="prefs_log_title">Käytä lokitusta</string>
+  <string name="prefs_log_summary">Tätä käytetään ongelmien lokitukseen</string>
+  <string name="prefs_log_title_history">Lokihistoria</string>
   <string name="prefs_log_summary_history">Tämä näyttää tallennetut lokit</string>
   <string name="prefs_log_delete_history_button">Poista historia</string>
   <string name="prefs_help">Ohje</string>
   <string name="prefs_recommend">Suosittele kaverille</string>
   <string name="prefs_feedback">Palaute</string>
   <string name="recommend_subject">Kokeile %1$sia älypuhelimellasi!</string>
-  <string name="recommend_text">Ota %1$s käyttöösi älypuhelimessa!\nLataa tästä: %2$s</string>
+  <string name="recommend_text">Kutsun sinut käyttämään %1$sia älypuhelimellasi!\nLataa se tästä: %2$s</string>
   <string name="auth_check_server">Tarkista palvelin</string>
-  <string name="auth_host_url">Palvelimen osoite</string>
+  <string name="auth_host_url">Palvelinosoite https://…</string>
   <string name="auth_username">Käyttäjätunnus</string>
   <string name="auth_password">Salasana</string>
   <string name="auth_register">Onko %1$s uusi tuttavuus sinulle?</string>
@@ -43,7 +48,9 @@
   <string name="uploader_wrn_no_content_text">Sisältöä ei saatu. Ei lähetettävää palvelimelle.</string>
   <string name="uploader_error_forbidden_content">%1$silla ei ole oikeuksia jaettuun sisältöön</string>
   <string name="uploader_info_uploading">Lähetetään</string>
-  <string name="file_list_empty">Tässä kansiossa ei ole tiedostoja.\nUusia tiedostoja voi lisätä käyttäen valikon \"Lähetä\"-toimintoa.</string>
+  <string name="file_list_empty">Täällä ei ole mitään. Lähetä tänne jotakin!</string>
+  <string name="file_list_loading">Ladataan...</string>
+  <string name="local_file_list_empty">Tässä kansiossa ei ole tiedostoja</string>
   <string name="filedetails_select_file">Napauta tiedostoa nähdäksesi lisätietoja.</string>
   <string name="filedetails_size">Koko:</string>
   <string name="filedetails_type">Tyyppi:</string>
@@ -52,6 +59,7 @@
   <string name="filedetails_download">Lataa</string>
   <string name="filedetails_sync_file">Päivitä tiedosto</string>
   <string name="filedetails_renamed_in_upload_msg">Tiedoston nimeksi muutettiin %1$s siirron yhteydessä</string>
+  <string name="action_share_file">Jaa linkki</string>
   <string name="common_yes">Kyllä</string>
   <string name="common_no">Ei</string>
   <string name="common_ok">OK</string>
   <string name="uploader_upload_succeeded_content_single">%1$s lähetettiin onnistuneesti</string>
   <string name="uploader_upload_failed_ticker">Lähetys epäonnistui</string>
   <string name="uploader_upload_failed_content_single">%1$s :n lähetys palvelimelle jäi kesken</string>
+  <string name="uploader_upload_failed_credentials_error">Lähetys epäonnistui, kirjaudu uudelleen</string>
   <string name="downloader_download_in_progress_ticker">Ladataan...</string>
   <string name="downloader_download_in_progress_content">%1$d%% ladataan palvelimelta %2$s</string>
   <string name="downloader_download_succeeded_ticker">Lataus tänne onnistui</string>
   <string name="downloader_download_succeeded_content">%1$s ladattu palvelimelta onnistuneesti</string>
   <string name="downloader_download_failed_ticker">Lataus epäonnistui</string>
   <string name="downloader_download_failed_content">%1$s :n latausta ei pystytty suorittamaan loppuun asti</string>
+  <string name="downloader_not_downloaded_yet">Ei vielä ladattu</string>
+  <string name="downloader_download_failed_credentials_error">Lataus epäonnistui, kirjaudu uudelleen</string>
   <string name="common_choose_account">Valitse tili</string>
   <string name="sync_fail_ticker">Synkronointi epäonnistui</string>
+  <string name="sync_fail_ticker_unauthorized">Synkronointi epäonnistui, kirjaudu uudelleen</string>
   <string name="sync_fail_content">Kohteen %1$s synkronointia ei voitu suorittaa loppuun</string>
   <string name="sync_fail_content_unauthorized">Virheellinen salasana tilille %1$s</string>
   <string name="sync_conflicts_in_favourites_ticker">Ristiriitoja löytynyt</string>
   <string name="media_state_playing">%1$s (toistetaan)</string>
   <string name="media_state_loading">%1$s (ladataan)</string>
   <string name="media_err_nothing_to_play">Mediatiedostoa ei löytynyt</string>
+  <string name="media_err_no_account">Tiliä ei määritetty</string>
+  <string name="media_err_not_in_owncloud">Tiedosto ei ole kelvollisella tilillä</string>
   <string name="media_err_io">Mediatiedoston luku ei onnistunut</string>
+  <string name="media_err_timeout">Aikakatkaisu toistoa yrittäessä</string>
+  <string name="media_err_invalid_progressive_playback">Mediatiedostoa ei voi suoratoistaa</string>
+  <string name="media_err_security_ex">Turvallisuusvirhe yrittäessä toistaa kohdetta %1$s</string>
+  <string name="media_err_unexpected">Odottamaton virhe yrittäessä toistaa kohdetta %1$s</string>
   <string name="media_rewind_description">Taaksepäin kelaus -painike</string>
   <string name="media_play_pause_description">Toisto tai keskeytys -painike</string>
   <string name="media_forward_description">Eteenpäin kelaus -painike</string>
+  <string name="auth_getting_authorization">Noudetaan valtuutusta…</string>
   <string name="auth_trying_to_login">Yritetään kirjautua...</string>
   <string name="auth_no_net_conn_title">Ei verkkoyhteyttä</string>
   <string name="auth_nossl_plain_ok_title">Salattu yhteys ei ole käytettävissä.</string>
   <string name="auth_timeout_title">Palvelimen vastaus viipyy liian kauan</string>
   <string name="auth_incorrect_address_title">Väärin annettu osoite</string>
   <string name="auth_ssl_general_error_title">SSL:n alustus epäonnistui</string>
+  <string name="auth_ssl_unverified_server_title">SSL-palvelimen identiteettiä ei voitu varmistaa</string>
   <string name="auth_bad_oc_version_title">Tuntematon palvelimen versio</string>
   <string name="auth_wrong_connection_title">Yhteyden muodostus epäonnistui</string>
   <string name="auth_secure_connection">Salattu yhteys muodostettu</string>
   <string name="auth_expired_saml_sso_token_toast">Istunto vanhentui. Yhdistä uudelleen</string>
   <string name="auth_connecting_auth_server">Yhdistetään tunnistautumispalvelimeen…</string>
   <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="fd_keep_in_sync">Pidä tiedosto ajan tasalla</string>
   <string name="common_rename">Nimeä uudelleen</string>
   <string name="common_remove">Poista</string>
-  <string name="confirmation_remove_alert">Haluatko poistaa kohteen %1$s?</string>
-  <string name="confirmation_remove_folder_alert">Haluatko poistaa kohteen %1$s ja sen sisällön?</string>
+  <string name="confirmation_remove_alert">Haluatko varmasti poistaa kohteen %1$s?</string>
+  <string name="confirmation_remove_folder_alert">Haluatko varmasti poistaa kohteen %1$s ja sen sisällön?</string>
   <string name="confirmation_remove_local">Vain paikallinen</string>
   <string name="confirmation_remove_folder_local">Vain paikallinen sisältö</string>
   <string name="confirmation_remove_remote">Poista palvelimelta</string>
   <string name="rename_server_fail_msg">Nimen muutos epäonnistui</string>
   <string name="sync_file_fail_msg">Etäpään tiedostoa ei voitu tarkistaa</string>
   <string name="sync_file_nothing_to_do_msg">Tiedoston sisältö on jo synkronoitu</string>
-  <string name="create_dir_fail_msg">Kansion luonti epäonnistui</string>
+  <string name="create_dir_fail_msg">Kansion luominen epäonnistui</string>
+  <string name="filename_forbidden_characters">Kielletyt merkit: / \\ &lt; &gt; : \" | ? *</string>
+  <string name="filename_empty">Tiedoston nimi ei voi olla tyhjä</string>
   <string name="wait_a_moment">Odota hetki</string>
   <string name="filedisplay_unexpected_bad_get_content">Odottamaton ongelma; kokeile valita tiedosto toisella sovelluksella</string>
   <string name="filedisplay_no_file_selected">Tiedostoa ei valittu</string>
+  <string name="activity_chooser_title">Lähetä linkki…</string>
   <string name="oauth_check_onoff">Kirjaudu oAuth2:lla</string>
   <string name="oauth_login_connection">Yhdistetään oAuth2-palvelimeen…</string>
   <string name="ssl_validator_header">Sivuston identiteetin vahvistaminen ei onnistunut</string>
   <string name="ssl_validator_label_validity_to">Päättyen:</string>
   <string name="ssl_validator_label_signature">Allekirjoitus:</string>
   <string name="ssl_validator_label_signature_algorithm">Algoritmi:</string>
+  <string name="ssl_validator_null_cert">Varmennetta ei voi näyttää.</string>
+  <string name="ssl_validator_no_info_about_error">- Ei lisätietoja virheestä</string>
   <string name="placeholder_filetype">PNG-kuva</string>
   <string name="placeholder_filesize">389 kt</string>
   <string name="instant_upload_on_wifi">Lähetä kuvat vain WiFi-verkossa</string>
+  <string name="instant_video_upload_on_wifi">Lähetä videot vain wifi-yhteydellä</string>
   <string name="instant_upload_path">/InstantUpload</string>
   <string name="conflict_title">Päivitysristiriita</string>
   <string name="conflict_message">Etätiedostoa %s ei ole synkronoitu paikallisen tiedoston kanssa. Jatkaminen korvaa palvelimella olevan tiedoston sisällön.</string>
   <string name="conflict_keep_both">Säilytä molemmat</string>
   <string name="conflict_overwrite">Korvaa</string>
   <string name="conflict_dont_upload">Älä lähetä</string>
-  <string name="preview_image_error_unknown_format">Kuvaa ei voi näyttää</string>
-  <string name="failed_upload_all_cb">valitse kaikki</string>
-  <string name="failed_upload_headline_retryall_btn">yritä uudelleen kaikkia valittuja</string>
-  <string name="failed_upload_load_more_images">Lataa lisää kuvia</string>
-  <string name="failed_upload_failure_text">Virheviesti:</string>
+  <string name="preview_image_description">Kuvan esikatselu</string>
+  <string name="preview_image_error_unknown_format">Tätä kuvaa ei voi näyttää</string>
+  <string name="prefs_instant_upload_path_title">Lähetyspolku</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="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="error_cant_bind_to_operations_service">Kriittinen virhe: toimintoja ei voi suorittaa</string>
+  <string name="network_error_socket_exception">Virhe palvelimeen yhdistäessä</string>
+  <string name="network_error_socket_timeout_exception">Virhe palvelimen vastausta odottaessa, toimintoa ei voitu suorittaa</string>
+  <string name="network_error_connect_timeout_exception">Virhe palvelimen vastausta odottaessa, toimintoa ei voitu suorittaa</string>
+  <string name="network_host_not_available">Toimintoa ei voi suorittaa loppuun, palvelin ei ole käytettävissä</string>
+  <string name="empty"></string>
+  <string name="forbidden_permissions">Sinulla ei ole oikeutta %s</string>
+  <string name="forbidden_permissions_rename">nimetä tiedostoa uudelleen</string>
+  <string name="forbidden_permissions_delete">poistaa tiedostoa</string>
+  <string name="share_link_forbidden_permissions">jakaa tiedostoa</string>
+  <string name="unshare_link_forbidden_permissions">poistaa tiedoston jakamista</string>
+  <string name="forbidden_permissions_create">luoda tiedostoa</string>
+  <string name="uploader_upload_forbidden_permissions">lähettää tähän kansioon</string>
+  <string name="downloader_download_file_not_found">Tämä tiedosto ei ole enää palvelimella käytettävissä</string>
+  <string name="prefs_category_accounts">Tilit</string>
+  <string name="prefs_add_account">Lisää tili</string>
+  <string name="actionbar_logger">Lokit</string>
+  <string name="log_send_history_button">Lähetä historia</string>
+  <string name="log_mail_subject">ownCloudin Android-sovelluksen lokit</string>
+  <string name="log_progress_dialog_text">Ladataan tietoja...</string>
+  <string name="saml_authentication_required_text">Tunnistautuminen vaaditaan</string>
+  <string name="saml_authentication_wrong_pass">Väärä salasana</string>
+  <string name="actionbar_move">Siirrä</string>
+  <string name="file_list_empty_moving">Täällä ei ole mitään. Voit lisätä kansion!</string>
+  <string name="move_choose_button_text">Valitse</string>
+  <string name="move_file_not_found">Siirto ei onnistu. Tarkista, ettei tiedostoa ole jo olemassa</string>
+  <string name="move_file_invalid_overwrite">Tiedosto on jo olemassa kohdekansiossa</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>
 </resources>
diff --git a/res/values-fr-rCA/strings.xml b/res/values-fr-rCA/strings.xml
new file mode 100644 (file)
index 0000000..56e55a1
--- /dev/null
@@ -0,0 +1,4 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<resources>
+  <string name="empty"></string>
+</resources>
index c63bc4c..17da4a9 100644 (file)
@@ -7,17 +7,20 @@
   <string name="actionbar_upload_from_apps">Contenu d\'une autre application</string>
   <string name="actionbar_upload_files">Fichiers</string>
   <string name="actionbar_open_with">Ouvrir avec</string>
-  <string name="actionbar_mkdir">Créer un répertoire</string>
+  <string name="actionbar_mkdir">Nouveau dossier</string>
   <string name="actionbar_settings">Paramètres</string>
   <string name="actionbar_see_details">Détails</string>
+  <string name="actionbar_send_file">Envoyer</string>
   <string name="prefs_category_general">Général</string>
   <string name="prefs_category_more">Plus</string>
   <string name="prefs_accounts">Comptes</string>
   <string name="prefs_manage_accounts">Gestion des comptes utilisateur</string>
   <string name="prefs_pincode">Utilisation d\'un code de sécurité</string>
-  <string name="prefs_pincode_summary">Protéger l\'accès aux données maniplulées par le client</string>
-  <string name="prefs_instant_upload">Activer le téléversement instantané</string>
-  <string name="prefs_instant_upload_summary">Import instantané des photos prises par la caméra</string>
+  <string name="prefs_pincode_summary">Protéger l\'accès aux données manipulées par le client</string>
+  <string name="prefs_instant_upload">Téléchargements instantanés d\'images</string>
+  <string name="prefs_instant_upload_summary">Téléversement instantané des photos prises par la caméra</string>
+  <string name="prefs_instant_video_upload">Téléchargements instantanés de vidéos</string>
+  <string name="prefs_instant_video_upload_summary">Téléversement instantané des 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>
   <string name="prefs_log_title_history">Historique des logs</string>
   <string name="prefs_feedback">Commentaires</string>
   <string name="prefs_imprint">Empreinte</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 !\nTéléchargez-le ici : %2$s</string>
+  <string name="recommend_text">J\'aimerais vous inviter à utiliser %1$s sur votre smartphone !
+Téléchargez-le ici : %2$s</string>
   <string name="auth_check_server">Vérifier le serveur</string>
-  <string name="auth_host_url">Adresse du serveur</string>
+  <string name="auth_host_url">Adresse du serveur https://...</string>
   <string name="auth_username">Nom d\'utilisateur</string>
   <string name="auth_password">Mot de passe</string>
   <string name="auth_register">Nouveau dans %1$s ?</string>
   <string name="sync_string_files">Fichiers</string>
   <string name="setup_btn_connect">Connecter</string>
   <string name="uploader_btn_upload_text">Téléverser</string>
-  <string name="uploader_top_message">Choisissez le répertoire de destination:</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_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_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="file_list_empty">Ce répertoire ne contient aucun fichier.\nDe nouveaux fichiers peuvent être importés en cliquant sur le bouton « Téléverser un fichier » du menu des options</string>
+  <string name="file_list_empty">Il n\'y a rien ici ! Envoyez donc quelque chose :)</string>
+  <string name="file_list_loading">Chargement…</string>
+  <string name="local_file_list_empty">Aucun fichier n\'est présent dans ce dossier.</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>
@@ -55,6 +61,8 @@
   <string name="filedetails_download">Télécharger</string>
   <string name="filedetails_sync_file">Actualiser le fichier</string>
   <string name="filedetails_renamed_in_upload_msg">Le fichier a été renommé en %s pendant le téléversement</string>
+  <string name="action_share_file">Partager le lien</string>
+  <string name="action_unshare_file">Ne plus partager ce lien</string>
   <string name="common_yes">Oui</string>
   <string name="common_no">Non</string>
   <string name="common_ok">OK</string>
@@ -77,6 +85,7 @@
   <string name="uploader_upload_succeeded_content_single">Le fichier %1$s a été envoyé 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>
   <string name="downloader_download_in_progress_ticker">Téléchargement en cours…</string>
   <string name="downloader_download_in_progress_content">Téléchargement en cours de %2$s, %1$d%% effectués</string>
   <string name="downloader_download_succeeded_ticker">Téléchargement réussi</string>
   <string name="downloader_download_failed_ticker">Le téléchargement a échoué</string>
   <string name="downloader_download_failed_content">Le téléchargement de %1$s a échoué</string>
   <string name="downloader_not_downloaded_yet">Pas encore téléchargé</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_content">La synchronisation de %1$s ne peut pas être complétée</string>
   <string name="sync_fail_content_unauthorized">Mot de passe invalide pour %1$s</string>
   <string name="sync_conflicts_in_favourites_ticker">Des conflits ont été trouvés</string>
   <string name="sync_fail_in_favourites_content">Le contenu de %1$d fichiers n\'a put ê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 téléversés depuis cet équipement sont copiés dans le dossier local %1$s pour éviter toute perte de données lorsqu\'un fichier est synchronisé avec plusieurs comptes.\n\nEn raison de ce changement, tous les fichiers téléversés avec une version antérieure de cette application étaient copiés dans le dossier %2$s. Cependant, une erreur empêchait l\'achèvement de cette opération pendant la synchronisation. Vous pouvez soit laisser les fichiers tels quels et supprimer le lien à %3$s, soit déplacer les fichiers dans le dossier %1$s et garder le lien vers %4$s.\n\nCi-dessous la liste des fichiers locaux, et les fichiers distants de %5$s auxquels ils étaient liés.</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.
+
+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>
   <string name="foreign_files_move">Tout déplacer</string>
   <string name="foreign_files_success">Tous les fichiers ont été déplacés</string>
   <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 les déplacer à la place ?</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="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="media_rewind_description">Bouton de rem-bobinage</string>
   <string name="media_play_pause_description">Bouton de Lecture ou de Pause</string>
   <string name="media_forward_description">Bouton d\'avance rapide</string>
+  <string name="auth_getting_authorization">Demande d\'autorisation...</string>
   <string name="auth_trying_to_login">Tentative de connexion …</string>
   <string name="auth_no_net_conn_title">Pas de connexion réseau</string>
   <string name="auth_nossl_plain_ok_title">Connexion sécurisée non disponible</string>
   <string name="auth_bad_oc_version_title">La version du serveur n\'est pas reconnue</string>
   <string name="auth_wrong_connection_title">Impossible d\'établir la connexion</string>
   <string name="auth_secure_connection">Connexion sécurisée établie</string>
-  <string name="auth_unauthorized">Nom d\'utilisateur ou mot de passe invalide</string>
+  <string name="auth_unauthorized">Nom d\'utilisateur ou mot de passe incorrect</string>
   <string name="auth_oauth_error">Echec d\'autorisation</string>
   <string name="auth_oauth_error_access_denied">Accès refusé par le serveur d\'autorisation</string>
   <string name="auth_wtf_reenter_URL">État inattendu ; veuillez entrer à nouveau l\'URL du serveur</string>
   <string name="auth_connecting_auth_server">Connexion au serveur d\'authentification...</string>
   <string name="auth_unsupported_auth_method">Le serveur ne supporte pas cette méthode d\'authentification</string>
   <string name="auth_unsupported_multiaccount">%1$s ne supporte pas les comptes multiples</string>
+  <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="fd_keep_in_sync">Maintenir le fichier à jour</string>
   <string name="common_rename">Renommer</string>
   <string name="common_remove">Supprimer</string>
   <string name="rename_server_fail_msg">Renommage impossible</string>
   <string name="sync_file_fail_msg">Le fichier distant n\'a pu être vérifié</string>
   <string name="sync_file_nothing_to_do_msg">Le contenu des fichiers est déjà synchronisé</string>
-  <string name="create_dir_fail_msg">Création du répertoire impossible</string>
+  <string name="create_dir_fail_msg">Le dossier n\'a pas pu être créé</string>
+  <string name="filename_forbidden_characters">Caractères interdits : / \\ &lt; &gt; : \" | ? *</string>
+  <string name="filename_empty">Le nom du fichier ne peut pas être vide</string>
   <string name="wait_a_moment">Veuillez patienter</string>
   <string name="filedisplay_unexpected_bad_get_content">Problème inattendu ; veuillez essayer une autre app pour la sélection du fichier</string>
   <string name="filedisplay_no_file_selected">Aucun fichier sélectionné</string>
+  <string name="activity_chooser_title">Envoyer un lien à…</string>
   <string name="oauth_check_onoff">Connexion avec aAuth2.</string>
   <string name="oauth_login_connection">Connexion au serveur aAuth2...</string>
   <string name="ssl_validator_header">L\'identité du site ne peut être vérifiée</string>
   <string name="ssl_validator_label_validity_to">À :</string>
   <string name="ssl_validator_label_signature">Signature :</string>
   <string name="ssl_validator_label_signature_algorithm">Algorithme :</string>
+  <string name="ssl_validator_null_cert">Impossible d\'afficher le certificat.</string>
+  <string name="ssl_validator_no_info_about_error">- Aucune information sur l\'erreur</string>
   <string name="placeholder_sentence">Ceci est un espace réservé</string>
   <string name="placeholder_filename">placeholder.txt</string>
   <string name="placeholder_filetype">Image PNG</string>
   <string name="placeholder_filesize">389 Ko</string>
   <string name="placeholder_timestamp">18/05/2012 12:23</string>
   <string name="placeholder_media_time">12:23:45</string>
-  <string name="instant_upload_on_wifi">Ne téléverser les images que via une connexion WiFi</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">/TéléversementInstantané</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_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é vers le dossier local suivant %2$s</string>
-  <string name="actionbar_failed_instant_upload">Téléchargement instantané échoué</string>
-  <string name="failed_upload_headline_text">Téléchargements instantanés échoués</string>
-  <string name="failed_upload_headline_hint">Résumé de tous les téléchargements instantanés échoués</string>
-  <string name="failed_upload_all_cb">Tous sélectionner</string>
-  <string name="failed_upload_headline_retryall_btn">réessayer de tous sélectionner</string>
-  <string name="failed_upload_headline_delete_all_btn">Supprimez tous les sélectionnés de la file d\'attente de téléchargement</string>
-  <string name="failed_upload_retry_text">Ré-essayer de charger l\'image:</string>
-  <string name="failed_upload_load_more_images">Charger plus d\'images</string>
-  <string name="failed_upload_retry_do_nothing_text">Ne rien faire vous n\'êtes pas connecté pour le téléchargement instantané</string>
-  <string name="failed_upload_failure_text">Message d\'échec:</string>
-  <string name="failed_upload_quota_exceeded_text">Veuillez vérifier la configuration de votre serveur, peut-être que votre quota est dépassé.</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="share_link_no_support_share_api">Désolé, le partage n\'est pas disponible sur votre serveur. Contactez votre administrateur, s\'il vous plait.</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="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="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>
+  <string name="forbidden_permissions_delete">afin d’effacer ce fichier</string>
+  <string name="share_link_forbidden_permissions">afin de partager ce fichier</string>
+  <string name="unshare_link_forbidden_permissions">afin de ne plus partager ce fichier</string>
+  <string name="forbidden_permissions_create">afin de créer ce fichier</string>
+  <string name="uploader_upload_forbidden_permissions">afin d’importer dans ce répertoire</string>
+  <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="actionbar_logger">Journaux</string>
+  <string name="log_send_history_button">Envoyer l\'historique</string>
+  <string name="log_mail_subject">Journaux de l\'application Android ownCloud</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>
+  <string name="file_list_empty_moving">Il n\'y a rien ici. Vous pouvez ajouter un dossier !</string>
+  <string name="move_choose_button_text">Choisir</string>
+  <string name="move_file_not_found">Impossible de déplacer. Vérifiez que le fichier existe</string>
+  <string name="move_file_invalid_into_descendent">Il n\'est pas possible de déplacer un dossier vers un de ses descendants</string>
+  <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_security">Sécurité</string>
 </resources>
diff --git a/res/values-fy-rNL/strings.xml b/res/values-fy-rNL/strings.xml
new file mode 100644 (file)
index 0000000..56e55a1
--- /dev/null
@@ -0,0 +1,4 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<resources>
+  <string name="empty"></string>
+</resources>
index bd1b0d3..c169179 100644 (file)
@@ -1,23 +1,26 @@
 <?xml version='1.0' encoding='UTF-8'?>
 <resources>
-  <string name="about_android">Aplicativo Android %1$s</string>
+  <string name="about_android">Aplicación Android %1$s</string>
   <string name="about_version">versión %1$s</string>
   <string name="actionbar_sync">Actualizar a conta</string>
   <string name="actionbar_upload">Enviar</string>
-  <string name="actionbar_upload_from_apps">Contido doutros aplicativos</string>
+  <string name="actionbar_upload_from_apps">Contido doutras aplicacións</string>
   <string name="actionbar_upload_files">Ficheiros</string>
   <string name="actionbar_open_with">Abrir con</string>
-  <string name="actionbar_mkdir">Crear un directorio</string>
+  <string name="actionbar_mkdir">Novo cartafol</string>
   <string name="actionbar_settings">Preferencias</string>
   <string name="actionbar_see_details">Detalles</string>
+  <string name="actionbar_send_file">Enviar</string>
   <string name="prefs_category_general">Xeral</string>
   <string name="prefs_category_more">Máis</string>
   <string name="prefs_accounts">Contas</string>
   <string name="prefs_manage_accounts">Xestionar as contas</string>
-  <string name="prefs_pincode">PIN do aplicativo</string>
+  <string name="prefs_pincode">PIN da aplicación</string>
   <string name="prefs_pincode_summary">Protexe o seu cliente</string>
-  <string name="prefs_instant_upload">Activar o envío instantáneo</string>
+  <string name="prefs_instant_upload">Envío instantáneo de fotos</string>
   <string name="prefs_instant_upload_summary">Enviar instantaneamente as fotos tiradas coa cámara</string>
+  <string name="prefs_instant_video_upload">Envío instantáneo de vídeos</string>
+  <string name="prefs_instant_video_upload_summary">Enviar instantaneamente os vídeos gravados coa cámara</string>
   <string name="prefs_log_title">Activar o rexistro</string>
   <string name="prefs_log_summary">Isto empregase para rexistrar os problemas</string>
   <string name="prefs_log_title_history">Historial do rexistro</string>
   <string name="prefs_feedback">Comentarios</string>
   <string name="prefs_imprint">Impresión</string>
   <string name="recommend_subject">Tente %1$s no seu teléfono intelixente!</string>
-  <string name="recommend_text">Quero convidalo a empregar %1$s no seu teléfono intelixente!⏎\nDescárgueo de aquí:%2$s</string>
   <string name="auth_check_server">Comprobar o servidor</string>
-  <string name="auth_host_url">Enderezo do servidor</string>
+  <string name="auth_host_url">Enderezo do servidor https://…</string>
   <string name="auth_username">Nome de usuario</string>
   <string name="auth_password">Contrasinal</string>
   <string name="auth_register">Novo en %1$s?</string>
   <string name="sync_string_files">Ficheiros</string>
   <string name="setup_btn_connect">Conectar</string>
   <string name="uploader_btn_upload_text">Enviar</string>
-  <string name="uploader_top_message">Escolla o directorio para o envío:</string>
+  <string name="uploader_top_message">Escolla o cartafol de envío:</string>
   <string name="uploader_wrn_no_account_title">Non se atoparon contas</string>
   <string name="uploader_wrn_no_account_text">Non hai contas de %1$s no seu dispositivo. Cree unha nova conta primeiro.</string>
   <string name="uploader_wrn_no_account_setup_btn_text">Instalación</string>
@@ -46,7 +48,9 @@
   <string name="uploader_wrn_no_content_text">Non se recibiu contido. Non hai nada para enviar.</string>
   <string name="uploader_error_forbidden_content">%1$s non ten permiso para acceder ao contido compartido</string>
   <string name="uploader_info_uploading">Enviando</string>
-  <string name="file_list_empty">Non hai ficheiros neste cartafol.\nOs novos ficheiros pódense engadir ca opción do menú «Enviar».</string>
+  <string name="file_list_empty">Aquí non hai nada. Envíe algo!</string>
+  <string name="file_list_loading">Cargando...</string>
+  <string name="local_file_list_empty">Non hai ficheiros neste cartafol.</string>
   <string name="filedetails_select_file">Prema nun ficheiro para que amose a información adicional.</string>
   <string name="filedetails_size">Tamaño:</string>
   <string name="filedetails_type">Tipo:</string>
@@ -55,6 +59,8 @@
   <string name="filedetails_download">Descargar</string>
   <string name="filedetails_sync_file">Actualizar o ficheiro</string>
   <string name="filedetails_renamed_in_upload_msg">O ficheiro foi renomeado a %1$s durante o envío</string>
+  <string name="action_share_file">Ligazón para compartir</string>
+  <string name="action_unshare_file">Deixar de compartir a ligazón</string>
   <string name="common_yes">Si</string>
   <string name="common_no">Non</string>
   <string name="common_ok">Aceptar</string>
   <string name="delete_account">Eliminar a conta</string>
   <string name="create_account">Crear unha conta</string>
   <string name="upload_chooser_title">Enviar desde…</string>
-  <string name="uploader_info_dirname">Nome do directorio</string>
+  <string name="uploader_info_dirname">Nome do cartafol</string>
   <string name="uploader_upload_in_progress_ticker">Enviando…</string>
   <string name="uploader_upload_in_progress_content">%1$d%% enviando %2$s</string>
   <string name="uploader_upload_succeeded_ticker">Enviado correctamente</string>
   <string name="uploader_upload_succeeded_content_single">%1$s foi enviado correctamente</string>
   <string name="uploader_upload_failed_ticker">Produciuse un fallou no envío</string>
   <string name="uploader_upload_failed_content_single">Non foi posíbel completar o envío de %1$s</string>
+  <string name="uploader_upload_failed_credentials_error">Fallou o envío, necesita volver acceder</string>
   <string name="downloader_download_in_progress_ticker">Descargando…</string>
   <string name="downloader_download_in_progress_content">%1$d%% descargando %2$s</string>
   <string name="downloader_download_succeeded_ticker">Completouse a descarga</string>
   <string name="downloader_download_failed_ticker">Produciuse un fallo na descarga</string>
   <string name="downloader_download_failed_content">Non foi posíbel completar a descarga de %1$s</string>
   <string name="downloader_not_downloaded_yet">Non descargado aínda</string>
+  <string name="downloader_download_failed_credentials_error">Fallou a descarga, necesita volver acceder</string>
   <string name="common_choose_account">Escoller unha conta</string>
   <string name="sync_fail_ticker">Produciuse un fallo na sincronización</string>
+  <string name="sync_fail_ticker_unauthorized">Fallou a sincronización, necesita volver acceder</string>
   <string name="sync_fail_content">Non foi posíbel completar a sincronización de %1$s</string>
   <string name="sync_fail_content_unauthorized">Contrasinal incorrecto para %1$s</string>
   <string name="sync_conflicts_in_favourites_ticker">Atopáronse conflictos</string>
   <string name="sync_fail_in_favourites_ticker">Produciuse unha falla no mantemento sincronizado de ficheiros</string>
   <string name="sync_fail_in_favourites_content">Non foi posíbel sincronizar o contido de %1$d ficheiros (%2$d conflitos)</string>
   <string name="sync_foreign_files_forgotten_ticker">Algúns ficheiros locais foron esquecidos</string>
-  <string name="sync_foreign_files_forgotten_content">Non é posíbel copiar %1$d ficheiros do directorio %2$s en</string>
-  <string name="sync_foreign_files_forgotten_explanation">Desde a versión 1.3.16, os ficheiros enviados desde este dispositivo cópianse no cartafol local %1$s para evitar a perda de datos cando se sincroniza un ficheiro con varias contas.\n\nPor mor deste cambio, todos os ficheiros enviados nas versións anteriores deste aplicativo cópianse no cartafol %2$s. Porén, un erro impediu a finalización desta operación durante a sincronización da conta. É posíbel deixar o(s) ficheiro(s) como está(n) e retirar a ligazón a %3$s, ou mover o(s) ficheiro(s) ao directorio %1$s e manter a ligazón a %4$s.\n\nA seguir enuméranse o(s) fichero(s) local(is), e o(s) fichero(s) remoto(s) en %5$s co(s) que estaba(n) ligados.</string>
+  <string name="sync_foreign_files_forgotten_content">Non é posíbel copiar %1$d ficheiros do cartafol %2$s en</string>
   <string name="sync_current_folder_was_removed">O cartafol %1$s xa non existe</string>
   <string name="foreign_files_move">Mover todo</string>
   <string name="foreign_files_success">Foron movidos todos os ficheiros</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">Non hai espazo abondo para copiar os ficheiros seleccionados no cartafol %1$s. Quere movelos no canto de copialos?</string>
-  <string name="pincode_enter_pin_code">Insira o seu PIN do aplicativo</string>
-  <string name="pincode_configure_your_pin">Introduza o seu PIN do aplicativo</string>
-  <string name="pincode_configure_your_pin_explanation">Pediráselle o PIN cada vez que se inicie o aplicativo</string>
-  <string name="pincode_reenter_your_pincode">Volva a introducir o seu PIN do aplicativo</string>
-  <string name="pincode_remove_your_pincode">Retirar o seu PIN do aplicativo</string>
-  <string name="pincode_mismatch">Os PIN do aplicativo non son iguais</string>
-  <string name="pincode_wrong">PIN do aplicativo incorrecto</string>
-  <string name="pincode_removed">O PIN do aplicativo foi retirado</string>
-  <string name="pincode_stored">Almacenouse o PIN do aplicativo</string>
+  <string name="pincode_enter_pin_code">Insira o seu PIN da aplicación</string>
+  <string name="pincode_configure_your_pin">Introduza o seu PIN da aplicación</string>
+  <string name="pincode_configure_your_pin_explanation">Pediráselle o PIN cada vez que se inicie a aplicación</string>
+  <string name="pincode_reenter_your_pincode">Volva a introducir o seu PIN da aplicación</string>
+  <string name="pincode_remove_your_pincode">Retirar o seu PIN da aplicación</string>
+  <string name="pincode_mismatch">Os PIN da aplicación non son iguais</string>
+  <string name="pincode_wrong">O PIN da aplicación é incorrecto</string>
+  <string name="pincode_removed">O PIN da aplicación foi retirado</string>
+  <string name="pincode_stored">Almacenouse o PIN da aplicación</string>
   <string name="media_notif_ticker">%1$s reprodutor musical</string>
   <string name="media_state_playing">%1$s (reproducindo)</string>
   <string name="media_state_loading">%1$s (cargando)</string>
   <string name="media_rewind_description">Botón de retroceso</string>
   <string name="media_play_pause_description">Botón de reprodución/pausa</string>
   <string name="media_forward_description">Botón de avance rápido</string>
+  <string name="auth_getting_authorization">Obtendo a autorización...</string>
   <string name="auth_trying_to_login">Intentando acceder...</string>
   <string name="auth_no_net_conn_title">Sen conexión de rede</string>
   <string name="auth_nossl_plain_ok_title">Non hai conexión seguras dispoñíbeis.</string>
   <string name="auth_wtf_reenter_URL">Estado inesperado, introduza de novo o enderezo URL do servidor</string>
   <string name="auth_expired_oauth_token_toast">A súa autorización caducou. Autorícese de novo</string>
   <string name="auth_expired_basic_auth_toast">Introduza o contrasinal actual</string>
-  <string name="auth_expired_saml_sso_token_toast">A súa sesión caducou. Autorícese de novo</string>
+  <string name="auth_expired_saml_sso_token_toast">A súa sesión caducou. Acceda de novo</string>
   <string name="auth_connecting_auth_server">Conectando co servidor de autenticación…</string>
   <string name="auth_unsupported_auth_method">O servidor non admite este método de autenticación</string>
   <string name="auth_unsupported_multiaccount">%1$s non admite contas múltipes</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="fd_keep_in_sync">Manter actualizado o ficheiro</string>
   <string name="common_rename">Renomear</string>
   <string name="common_remove">Retirar</string>
-  <string name="confirmation_remove_alert">Confirma que quere retirar %1$s ?</string>
-  <string name="confirmation_remove_folder_alert">Confirma que quere retirar %1$s e o seu contido ?</string>
+  <string name="confirmation_remove_alert">Confirma que quere retirar %1$s?</string>
+  <string name="confirmation_remove_folder_alert">Confirma que quere retirar %1$s e o seu contido?</string>
   <string name="confirmation_remove_local">Só local</string>
   <string name="confirmation_remove_folder_local">Só contidos locais</string>
   <string name="confirmation_remove_remote">Retirar do servidor</string>
   <string name="rename_server_fail_msg">Non foi posíbel completar a operación de cambio de nome</string>
   <string name="sync_file_fail_msg">Non foi posíbel comprobar o ficheiro remoto</string>
   <string name="sync_file_nothing_to_do_msg">Os contidos do ficheiro xa están sincronizados</string>
-  <string name="create_dir_fail_msg">Non foi posíbel crear o directorio</string>
+  <string name="create_dir_fail_msg">Non foi posíbel crear o cartafol</string>
+  <string name="filename_forbidden_characters">Caracteres non permitidos: / \\ &lt; &gt; : \" | ? *</string>
+  <string name="filename_empty">O nome de ficheiro non pode estar baleiro</string>
   <string name="wait_a_moment">Agarde un chisco</string>
-  <string name="filedisplay_unexpected_bad_get_content">Produciuse un erro non agardado. Seleccione o ficheiro con outro aplicativo diferente</string>
+  <string name="filedisplay_unexpected_bad_get_content">Produciuse un erro non agardado. Seleccione o ficheiro con outra aplicación diferente</string>
   <string name="filedisplay_no_file_selected">Non se escolleu ningún ficheiro</string>
+  <string name="activity_chooser_title">Enviar a ligazón a ...</string>
   <string name="oauth_check_onoff">Acceder con oAuth2</string>
   <string name="oauth_login_connection">Conectando co servidor oAuth2…</string>
   <string name="ssl_validator_header">Non foi posíbel verificar a identidade do sitio</string>
   <string name="ssl_validator_label_validity_to">A:</string>
   <string name="ssl_validator_label_signature">Sinatura:</string>
   <string name="ssl_validator_label_signature_algorithm">Algoritmo:</string>
+  <string name="ssl_validator_null_cert">Non é posíbel amosar o certificado.</string>
+  <string name="ssl_validator_no_info_about_error">- Non hai información sobre este erro</string>
   <string name="placeholder_sentence">Isto é un marcador de posición</string>
-  <string name="placeholder_filename">marcador_de_posición.txt</string>
+  <string name="placeholder_filename">placeholder.txt</string>
   <string name="placeholder_filetype">Imaxe PNG</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">Enviar imaxes só medinte WiFi</string>
+  <string name="instant_video_upload_on_wifi">Enviar os vídeos só a través de WiFi</string>
   <string name="instant_upload_path">/EnvíoInstantáneo</string>
   <string name="conflict_title">Conflito de actualización</string>
   <string name="conflict_message">O ficheiro remoto %s non está sincronizado co ficheiro local. Continuando substituirase o contido do ficheiro no servidor.</string>
   <string name="conflict_dont_upload">Non enviar</string>
   <string name="preview_image_description">Vista previa da imaxe</string>
   <string name="preview_image_error_unknown_format">Esta imaxe non pode ser amosada</string>
-  <string name="error__upload__local_file_not_copied">Non foi posíbel copiar %1$s no directorio local %2$s</string>
-  <string name="actionbar_failed_instant_upload">produciuse un fallo de EnvíoInstantáneo»</string>
-  <string name="failed_upload_headline_text">Envíos instantáneos fallados</string>
-  <string name="failed_upload_headline_hint">Resumo de todos os envíos instantáneos fallados</string>
-  <string name="failed_upload_all_cb">seleccionar todo</string>
-  <string name="failed_upload_headline_retryall_btn">tentar de novo todo o seleccionado</string>
-  <string name="failed_upload_headline_delete_all_btn">eliminar todo o seleccionado da cola de envío</string>
-  <string name="failed_upload_retry_text">tentar de novo o envío da imaxe:</string>
-  <string name="failed_upload_load_more_images">Cargar máis imaxes</string>
-  <string name="failed_upload_retry_do_nothing_text">non facer nada que non estea en liña para o envío instantáneo</string>
-  <string name="failed_upload_failure_text">Mensaxe de fallo:</string>
-  <string name="failed_upload_quota_exceeded_text">Comprobe a configuración do seu servidor. é probábel que xa excedera a cota.</string>
+  <string name="error__upload__local_file_not_copied">Non foi posíbel copiar %1$s no cartafol local %2$s</string>
+  <string name="share_link_no_support_share_api">O seu servidor non ten activada a opción de compartir. Póñase en contacto co
+               administrador.</string>
+  <string name="share_link_file_error">Produciuse un erro ao tentar compartir este ficheiro ou cartafol.</string>
+  <string name="unshare_link_file_error">Produciuse un erro ao tentar deixar de compartir este ficheiro ou cartafol</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>
+  <string name="error_cant_bind_to_operations_service">Produciuse un erro crítico: non é posíbel realizar as operacións</string>
+  <string name="network_error_socket_exception">Produciuse un erro mentres conectaba co servidor.</string>
+  <string name="network_error_socket_timeout_exception">Produciuse un erro mentres agardaba polo servidor, a operación non se puido levar a fin</string>
+  <string name="network_error_connect_timeout_exception">Produciuse un erro mentres agardaba polo servidor, a operación non se puido levar a fin</string>
+  <string name="network_host_not_available">A operación non se completou, o servidor non está dispoñíbel</string>
+  <string name="empty"></string>
+  <string name="forbidden_permissions">Non ten permisos %s</string>
+  <string name="forbidden_permissions_rename">para renomear este ficheiro</string>
+  <string name="forbidden_permissions_delete">para eliminar este ficheiro</string>
+  <string name="share_link_forbidden_permissions">para compartir este ficheiro</string>
+  <string name="unshare_link_forbidden_permissions">para deixar de compartir este ficheiro</string>
+  <string name="forbidden_permissions_create">para crear o ficheiro</string>
+  <string name="uploader_upload_forbidden_permissions">para envialo a este cartafol</string>
+  <string name="downloader_download_file_not_found">O ficheiro xa non está dispoñíbel no servidor</string>
+  <string name="prefs_category_accounts">Contas</string>
+  <string name="prefs_add_account">Engadir unha conta</string>
+  <string name="saml_authentication_required_text">Requírese autenticación</string>
+  <string name="saml_authentication_wrong_pass">Contrasinal incorrecto</string>
+  <string name="actionbar_move">Mover</string>
+  <string name="move_choose_button_text">Escoller</string>
+  <string name="prefs_category_security">Seguranza</string>
 </resources>
diff --git a/res/values-gu/strings.xml b/res/values-gu/strings.xml
new file mode 100644 (file)
index 0000000..56e55a1
--- /dev/null
@@ -0,0 +1,4 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<resources>
+  <string name="empty"></string>
+</resources>
index 71c8b9d..4ae0072 100644 (file)
@@ -1,27 +1,45 @@
 <?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_mkdir">יצירת תיקייה</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="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_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="auth_host_url">כתובת שרת</string>
+  <string name="prefs_recommend">המלצה לחבר</string>
+  <string name="prefs_feedback">משוב</string>
+  <string name="prefs_imprint">חותמת</string>
+  <string name="recommend_subject">לבדיקה %1$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="uploader_btn_upload_text">העלאה</string>
-  <string name="uploader_top_message">× ×\90 ×\9c×\91×\97×\95ר ×\90ת ×ª×\99×§×\99×\99ת ×\94העלאה:</string>
+  <string name="uploader_top_message">×\91×\97×\99רת ×ª×\99×§×\99×\99ת העלאה:</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_content_text">לא התקבל תוכן. אין מה להעלות.</string>
   <string name="uploader_error_forbidden_content">ל־%1$s אין הרשאה לגשת לתוכן המשותף שלך</string>
   <string name="uploader_info_uploading">בהעלאה</string>
-  <string name="file_list_empty">אין קבצים בתיקייה זו.\nניתן להוסיף קבצים חדשים בעזרת האפשרות „העלאה“ מהתפריט.</string>
+  <string name="file_list_empty">אין כאן שום דבר. אולי ברצונך להעלות משהו?</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_download">הורדה</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="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_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">לא ניתן להשלים את ההורדה של </string>
+  <string name="downloader_not_downloaded_yet">לא הורד עדיין</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_ticker_unauthorized">סנכרון נכשל, יש להתחבר מחדש</string>
   <string name="sync_fail_content">לא ניתן להשלים את הסנכרון של </string>
+  <string name="sync_fail_content_unauthorized">סיסמא שגוייה עבור %1$s</string>
   <string name="sync_conflicts_in_favourites_ticker">נמצאו התנגשויות</string>
   <string name="sync_conflicts_in_favourites_content">לא ניתן לסנכרן %1$d קבצים שהוגדרו לסנכרון</string>
   <string name="sync_fail_in_favourites_ticker">קבצים שהוגדרו לסנכרון נכשלו</string>
   <string name="sync_fail_in_favourites_content">לא ניתן לסנכרם את תוכנם של %1$d מהקבצים (%2$d התנגשויות)</string>
   <string name="sync_foreign_files_forgotten_ticker">חלק מהקבצים המקומיים נשכחו</string>
+  <string name="sync_foreign_files_forgotten_content">קבצים %1$d מחוץ לתיקיית %2$s לא ניתן להעתיק אל</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="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_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_unverified_server_title">זהות ה- SSL של השרת לא ניתנת לאימות</string>
   <string name="auth_bad_oc_version_title">גרסה השרת אינה מזוהה</string>
   <string name="auth_wrong_connection_title">לא ניתן ליצור את החיבור</string>
   <string name="auth_secure_connection">נוצר חיבור מאובטח</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="fd_keep_in_sync">לשמור על קובץ עדכני</string>
   <string name="common_rename">שינוי שם</string>
   <string name="common_remove">הסרה</string>
-  <string name="confirmation_remove_alert">×\94×\90×\9d ×\90×\9b×\9f ×\9c×\94ס×\99ר ×\90ת </string>
-  <string name="confirmation_remove_folder_alert">×\94×\90×\9d ×\90×\9b×\9f ×\91רצ×\95× ×\9a ×\9c×\94ס×\99ר ×\90ת %1$s ×¢×\9c ×\9b×\9c ×ª×\95×\9b× ×\95 ?</string>
+  <string name="confirmation_remove_alert">×\94×\90×\9d ×\91×\90×\9eת ×\9c×\94ס×\99ר %1$s?</string>
+  <string name="confirmation_remove_folder_alert">×\94×\90×\9d ×\91×\90×\9eת ×\9c×\94ס×\99ר %1$s ×\95×\90ת ×\9b×\9c ×\94ת×\9b×\95×\9c×\94?</string>
   <string name="confirmation_remove_local">מקומי בלבד</string>
   <string name="confirmation_remove_folder_local">תכנים מקומיים בלבד</string>
   <string name="confirmation_remove_remote">הסרה מהשרת</string>
   <string name="rename_server_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="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_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">- תעודת השרת אינה מהימנה</string>
   <string name="ssl_validator_reason_cert_expired">- תוקף תעודת השרת פג</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">placeholder.txt</string>
   <string name="placeholder_filetype">תמונת PNG</string>
   <string name="placeholder_filesize">389 ק״ב</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_video_upload_on_wifi">העלאות קבצי וידאו על בסיס WiFi בלבד</string>
   <string name="instant_upload_path">/InstantUpload</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="failed_upload_headline_hint">הסיכום של כל ההעלאות המהירות שנכשלו</string>
-  <string name="failed_upload_all_cb">לבחור הכול</string>
-  <string name="failed_upload_headline_retryall_btn">לנסות שוב את כל הנבחרים</string>
-  <string name="failed_upload_headline_delete_all_btn">למחוק את כל הנבחרים מתור ההעלאה</string>
-  <string name="failed_upload_retry_text">לנסות להעלות את התמונה מחדש:</string>
-  <string name="failed_upload_load_more_images">טעינת תמונות נוספות</string>
-  <string name="failed_upload_failure_text">הודעת התקלה:</string>
-  <string name="failed_upload_quota_exceeded_text">נא לבדוק את תצורת שרת שלך, יתכן שחרגת מהמיכסה שלך.</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="share_link_no_support_share_api">מצטערים, שיתוף אינו מורשה על השרת שלך. יש ליצור קשר עם
+⇥⇥מנהל.</string>
+  <string name="share_link_file_error">שגיאה אירעה בזמן ניסיון לשתף קובץ זה או תיקייה זו</string>
+  <string name="unshare_link_file_error">שגיאה אירעה בזמן ניסיון לבטל שיתוף לקובץ זה או לתיקייה זו</string>
+  <string name="activity_chooser_send_file_title">שליחה</string>
+  <string name="copy_link">העתקת קישור</string>
+  <string name="clipboard_text_copied">הועתק ללוח הגזירים - clipboard</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="move_choose_button_text">בחירה</string>
+  <string name="prefs_category_security">אבטחה</string>
 </resources>
diff --git a/res/values-hi-rIN/strings.xml b/res/values-hi-rIN/strings.xml
new file mode 100644 (file)
index 0000000..56e55a1
--- /dev/null
@@ -0,0 +1,4 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<resources>
+  <string name="empty"></string>
+</resources>
index da6fb71..6d0355c 100644 (file)
@@ -1,11 +1,31 @@
 <?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_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="prefs_category_general">सामान्य </string>
-  <string name="prefs_help">सहयोग</string>
-  <string name="auth_username">प्रयोक्ता का नाम</string>
+  <string name="prefs_category_more">और अधिक</string>
+  <string name="prefs_accounts">खाते </string>
+  <string name="prefs_pincode">एप्प पिन </string>
+  <string name="prefs_pincode_summary">अपने उपभोक्ता की सुरक्षा करें </string>
+  <string name="prefs_help">सहायता </string>
+  <string name="auth_username">उपभोक्ता  का नाम</string>
   <string name="auth_password">पासवर्ड</string>
+  <string name="sync_string_files">फाइलें </string>
+  <string name="setup_btn_connect">जुड़ें </string>
   <string name="uploader_btn_upload_text">अपलोड </string>
+  <string name="common_cancel">रद्द करें </string>
   <string name="common_error">त्रुटि</string>
+  <string name="ssl_validator_btn_details_see">विवरण </string>
+  <string name="activity_chooser_send_file_title">भेजें</string>
+  <string name="empty"></string>
+  <string name="prefs_category_accounts">खाते </string>
 </resources>
index b55e3d9..b8dcfc5 100644 (file)
@@ -2,8 +2,9 @@
 <resources>
   <string name="actionbar_upload">Učitaj</string>
   <string name="actionbar_upload_files">Datoteke</string>
-  <string name="actionbar_mkdir">Kreiraj direktorij</string>
+  <string name="actionbar_mkdir">Nova mapa</string>
   <string name="actionbar_settings">Postavke</string>
+  <string name="actionbar_send_file">Pošaljite</string>
   <string name="prefs_category_general">Općenito</string>
   <string name="prefs_category_more">više</string>
   <string name="prefs_accounts">Korisnićki računi</string>
   <string name="setup_btn_connect">Poveži</string>
   <string name="uploader_btn_upload_text">Učitaj</string>
   <string name="uploader_wrn_no_account_quit_btn_text">Izlaz</string>
+  <string name="file_list_empty">Nema ničega u ovoj mapi. Pošalji nešto!</string>
   <string name="filedetails_download">Preuzimanje</string>
+  <string name="action_share_file">Podijelite vezu</string>
   <string name="common_yes">Da</string>
   <string name="common_no">Ne</string>
+  <string name="common_ok">U redu</string>
   <string name="common_cancel_upload">Prekini upload</string>
   <string name="common_cancel">Odustani</string>
   <string name="common_error">Greška</string>
+  <string name="common_error_unknown">Nepoznata pogreška</string>
   <string name="change_password">Izmjena lozinke</string>
+  <string name="uploader_info_dirname">Naziv mape</string>
   <string name="auth_trying_to_login">Trying to login…</string>
   <string name="common_rename">Promjeni ime</string>
   <string name="common_remove">Makni</string>
+  <string name="activity_chooser_send_file_title">Pošaljite</string>
+  <string name="empty"></string>
+  <string name="prefs_category_accounts">Korisnićki računi</string>
+  <string name="saml_authentication_required_text">Potrebna autentikacija</string>
+  <string name="saml_authentication_wrong_pass">Pogrešna lozinka</string>
+  <string name="move_choose_button_text">Izaberi</string>
+  <string name="prefs_category_security">Sigurnost</string>
 </resources>
index 88da10f..f590006 100644 (file)
@@ -7,33 +7,39 @@
   <string name="actionbar_upload_from_apps">Más alkalmazásokból származó tartalom</string>
   <string name="actionbar_upload_files">Fájlok</string>
   <string name="actionbar_open_with">Megnyitás a következővel</string>
-  <string name="actionbar_mkdir">Mappa létrehozása</string>
+  <string name="actionbar_mkdir">Új mappa</string>
   <string name="actionbar_settings">Beállítások</string>
   <string name="actionbar_see_details">Részletek</string>
+  <string name="actionbar_send_file">Küldjük el</string>
   <string name="prefs_category_general">Általános</string>
   <string name="prefs_category_more">Több</string>
   <string name="prefs_accounts">Fiókok</string>
   <string name="prefs_manage_accounts">Fiókok kezelése</string>
   <string name="prefs_pincode">Alkalmazás PIN</string>
   <string name="prefs_pincode_summary">Védje meg az alkalmazást</string>
-  <string name="prefs_instant_upload">Az azonnali feltöltés engedélyezése</string>
-  <string name="prefs_instant_upload_summary">Az eszköz által készített fényképek azonnali feltöltése</string>
+  <string name="prefs_instant_upload">Azonnali képfeltöltések</string>
+  <string name="prefs_instant_upload_summary">Kamera által készítette képek azonnali feltöltése</string>
+  <string name="prefs_instant_video_upload">Azonnali video feltöltések</string>
+  <string name="prefs_instant_video_upload_summary">Kamera által készített videó azonnali feltöltése</string>
   <string name="prefs_log_title">Naplózás engedélyezése</string>
   <string name="prefs_log_summary">Ez használható a problémák naplózásához</string>
   <string name="prefs_log_title_history">Naplózás előzménye</string>
   <string name="prefs_log_summary_history">Ez megjeleníti a rögzitett eseményeket</string>
   <string name="prefs_log_delete_history_button">Elözmények törlése</string>
   <string name="prefs_help">Súgó</string>
+  <string name="prefs_recommend">Ajánlja egy barátjának</string>
+  <string name="prefs_feedback">Visszajelzés</string>
   <string name="prefs_imprint">Impresszum</string>
+  <string name="recommend_subject">Próbálja ki %1$s-t az okostelefonján!</string>
   <string name="auth_check_server">Szerver állapot ellenörzés</string>
-  <string name="auth_host_url">A kiszolgáló címe</string>
+  <string name="auth_host_url">Kiszolgáló címe https://...</string>
   <string name="auth_username">Felhasználói név</string>
   <string name="auth_password">Jelszó</string>
   <string name="auth_register">Új vagy a %1$s területen?</string>
   <string name="sync_string_files">Fájlok</string>
   <string name="setup_btn_connect">Kapcsolódás</string>
   <string name="uploader_btn_upload_text">Feltöltés</string>
-  <string name="uploader_top_message">Feltöltési mappa választása:</string>
+  <string name="uploader_top_message">Válassz feltöltési mappát:</string>
   <string name="uploader_wrn_no_account_title">Nincs ilyen felhasználói fiók</string>
   <string name="uploader_wrn_no_account_text">Nem található %1$s fiók ezen a készüléken. Hozzon létre egy fiókot előbb.</string>
   <string name="uploader_wrn_no_account_setup_btn_text">Beállítás</string>
@@ -42,7 +48,9 @@
   <string name="uploader_wrn_no_content_text">Nem jött tartalom. Nincs mit feltölteni.</string>
   <string name="uploader_error_forbidden_content">%1$s nem jogosult a megosztott tartalom elérésére</string>
   <string name="uploader_info_uploading">Feltöltés</string>
-  <string name="file_list_empty">Ebben a mappában nincsenek állományok. A \"Feltöltés\" menüpont segítségével tölthet föl fájlokat.</string>
+  <string name="file_list_empty">Itt nincs semmi. Töltsön fel valamit!</string>
+  <string name="file_list_loading">Betöltés...</string>
+  <string name="local_file_list_empty">Nincs fájl ebben a mappában.</string>
   <string name="filedetails_select_file">Érintsen meg egy fájlt a további információkért.</string>
   <string name="filedetails_size">Méret:</string>
   <string name="filedetails_type">Tipus:</string>
@@ -51,6 +59,8 @@
   <string name="filedetails_download">Letöltés</string>
   <string name="filedetails_sync_file">File frissítése</string>
   <string name="filedetails_renamed_in_upload_msg">A feltöltés során az állmányt erre neveztük át: %1$s</string>
+  <string name="action_share_file">Megosztás hivatkozással</string>
+  <string name="action_unshare_file">Megosztás visszavonása</string>
   <string name="common_yes">Igen</string>
   <string name="common_no">Nem</string>
   <string name="common_ok">OK</string>
@@ -73,6 +83,7 @@
   <string name="uploader_upload_succeeded_content_single">%1$s sikeresen fel lett töltve</string>
   <string name="uploader_upload_failed_ticker">A feltöltés nem sikerült</string>
   <string name="uploader_upload_failed_content_single"> %1$s fájl feltöltése sikertelen</string>
+  <string name="uploader_upload_failed_credentials_error">Feltöltés sikertelen, jelentkezz be újra</string>
   <string name="downloader_download_in_progress_ticker">Letöltés ...</string>
   <string name="downloader_download_in_progress_content">%1$d%% Letöltés %2$s</string>
   <string name="downloader_download_succeeded_ticker">A letöltés sikeres</string>
   <string name="downloader_download_failed_ticker">A letöltés sikertelen</string>
   <string name="downloader_download_failed_content">A letöltésből %1$s nem lett befejezve</string>
   <string name="downloader_not_downloaded_yet">Még nem töltötte le</string>
+  <string name="downloader_download_failed_credentials_error">Letöltés sikertelen, jelentkezz be újra.</string>
   <string name="common_choose_account">Válasszon azonosítót</string>
   <string name="sync_fail_ticker">A szinkronizálás sikertelen</string>
+  <string name="sync_fail_ticker_unauthorized">Szinkronizálás sikertelen, jelentkezz be újra.</string>
   <string name="sync_fail_content">%1$s szinkronizációját nem sikerült befejezni</string>
   <string name="sync_fail_content_unauthorized">Érvénytelen jelszó a következőhöz %1$s</string>
   <string name="sync_conflicts_in_favourites_ticker">Ütközések vannak</string>
   <string name="sync_fail_in_favourites_ticker">A szinkronizálandó fájlokat nem sikerült szinkronizálni</string>
   <string name="sync_fail_in_favourites_content">%1$d fájl szinkronizálása nem sikerült (%2$d ütközés)</string>
   <string name="sync_foreign_files_forgotten_ticker">Néhány helyi fájlt figyelmen kívül hagytunk</string>
-  <string name="sync_foreign_files_forgotten_content">%1$d fájlt nem sikerült a %2$s mappából  bemásolni</string>
-  <string name="sync_foreign_files_forgotten_explanation">Az 1.3.16 verzió használatakor azok az állományok, amiket erről az eszközről töltenek fel, a helyi %1$s mappába másolódnak be, hogy elkerülhető legyen az adatveszteség, amikor ugyanazt az állományt több résztvevő is szinkronizál.\n\nEmiatt a változás miatt, az e program korábbi változataival feltöltött állományok a %2$s mappába másolódtak. Sajnos azonban egy a szinkronizáció közben fellépő hiba miatt ez a feladat csak részben valósult meg. Két lehetősége van: vagy úgy dönt, hogy maradjanak a fájl(ok) ahol vannak és akkor törölje a %3$s-re mutató linket, vagy pedig helyezze át az állomány(oka)t a %1$s mappába, és tartsa meg a %4$s-re mutató linket.\n\nAz alábbiakban látható a helyi fájl(ok) listája és a távoli fájl(ok) a %5$s mappában, amihez linkelve voltak.</string>
+  <string name="sync_current_folder_was_removed">A %1$s mappa már nem létezik</string>
   <string name="foreign_files_move">Helyezzük át mindet</string>
   <string name="foreign_files_success">Az összes fájlt áthelyeztük</string>
   <string name="foreign_files_fail">Egyes fájlokat nem sikerült áthelyezni</string>
   <string name="foreign_files_local_text">Helyi: %1$s</string>
   <string name="foreign_files_remote_text">Távoli: %1$s</string>
-  <string name="upload_query_move_foreign_files">Nincs elég hely ahhoz, hogy a kiválasztott fájlokat a %1$s mappába másoljuk. Akkor inkább helyezzük át őket oda?</string>
+  <string name="upload_query_move_foreign_files">Nincs elég hely a kiválasztott fájlok másolására a %1$s könyvtárban. Szeretnéd áthelyezni inkább?</string>
   <string name="pincode_enter_pin_code">Kérem adja meg az alkalmazás PIN-kódját</string>
   <string name="pincode_configure_your_pin">Az alkalmazás PIN-kódja</string>
   <string name="pincode_configure_your_pin_explanation">A PIN-t kötelező lesz megadni az alkalmazás minden indításakor</string>
   <string name="media_err_unsupported">Nem támogatott média kodek</string>
   <string name="media_err_io">Media fájl nem olvasható</string>
   <string name="media_err_malformed">Médiafájl kódolása nem megfelelő</string>
+  <string name="media_err_timeout">A lejátszás közben időtúllépés történt</string>
   <string name="media_err_invalid_progressive_playback">A média fájlt nem lehet streamelni.</string>
   <string name="media_err_unknown">A média fájlt nem tudja lejátszani a jelenlegi médialejátszó</string>
   <string name="media_err_security_ex">Biztonsági hiba amikor megpróbálja lejátszani a %1$s</string>
   <string name="auth_connection_established">A kapcsolat létrejött</string>
   <string name="auth_testing_connection">Kapcsolat tesztelése...</string>
   <string name="auth_not_configured_title">Hibás a kiszolgáló beállítása</string>
+  <string name="auth_account_not_new">Egy bejelentkezési beállítás már létezik ugyanehhez a kiszolgálóhoz és felhasználóhoz</string>
+  <string name="auth_account_not_the_same">A megadott felhasználó nem azonos ezzel a belépési jogosultsággal</string>
   <string name="auth_unknown_error_title">Ismeretlen hiba történt!</string>
   <string name="auth_unknown_host_title">A kiszolgáló nem található</string>
   <string name="auth_incorrect_path_title">Kiszolgáló nem található</string>
   <string name="auth_timeout_title">A kiszolgáló túl sokára válaszolt</string>
   <string name="auth_incorrect_address_title">Hibás URL</string>
   <string name="auth_ssl_general_error_title">Nem sikerült az SSL kapcsolat felépítése</string>
+  <string name="auth_ssl_unverified_server_title">Az SSL kiszolgáló tanúsítványát nem sikerült ellenőrizni</string>
   <string name="auth_bad_oc_version_title">Ismeretlen változat a kiszolgálón</string>
   <string name="auth_wrong_connection_title">A kapcsolat nem hozható létre</string>
   <string name="auth_secure_connection">Létrejött a titkosított kapcsolat</string>
   <string name="auth_oauth_error">Sikertelen azonosítás</string>
   <string name="auth_oauth_error_access_denied">Hozzáférés megtagadva az azonsítást végző szerver által</string>
   <string name="auth_wtf_reenter_URL">Nem várt állapot; kérlek, menj a szerver URL-jére újra.</string>
+  <string name="auth_expired_oauth_token_toast">A jogosultsága lejárt. Kérjük jelentkezzen be ismét!</string>
   <string name="auth_expired_basic_auth_toast">Kélek, írd be a jelenlegi jelszavadat</string>
+  <string name="auth_expired_saml_sso_token_toast">Lejárt a munkamenetének érvényessége. Kérjük jelentkezzen be ismét!</string>
+  <string name="auth_connecting_auth_server">Kapcsolódás a felhasználóazonosítást végző kiszolgálóhoz...</string>
+  <string name="auth_unsupported_auth_method">A kiszolgáló nem támogatja ezt a felhasználóazonosítási módszert</string>
+  <string name="auth_unsupported_multiaccount">%1$s nem támogat több bejelenkezési jogosultságot</string>
+  <string name="auth_can_not_auth_against_server">Nem tudod hitelesíteni magadat ezen a szerveren</string>
   <string name="fd_keep_in_sync">Automatikusan frissítse a fájlokat</string>
   <string name="common_rename">Átnevezés</string>
   <string name="common_remove">Eltávolítás</string>
-  <string name="confirmation_remove_alert">Tényleg szeretné törölni  ezt: %1$s ?</string>
-  <string name="confirmation_remove_folder_alert">Tényleg törölni akarja ezt a tartalmával együtt: %1$s?</string>
+  <string name="confirmation_remove_alert">Tényleg el akarod távolítani %1$s?</string>
+  <string name="confirmation_remove_folder_alert">Tényleg el akarod távolítani a %1$s és tartalmát?</string>
   <string name="confirmation_remove_local">Csak a helyi példány</string>
   <string name="confirmation_remove_folder_local">Csak a helyi tartalmat</string>
   <string name="confirmation_remove_remote">Törlés a szerverről</string>
   <string name="rename_server_fail_msg">Az átnevezés nem sikerült</string>
   <string name="sync_file_fail_msg">A távoli fájl nem volt ellenőrizhető</string>
   <string name="sync_file_nothing_to_do_msg">Az állományok már szinkonizálva vannak</string>
-  <string name="create_dir_fail_msg">A mappa nem hozható létre</string>
+  <string name="create_dir_fail_msg">A könyvtárt nem lehet létrehozni</string>
+  <string name="filename_forbidden_characters">Nem megendedett karakterek: / \\ &lt; &gt; : \" | ? *</string>
+  <string name="filename_empty">A fájl név nem lehet üres</string>
   <string name="wait_a_moment">Egy pillanat...</string>
   <string name="filedisplay_unexpected_bad_get_content">Váratlan hiba; válassza ki a fájlt más programból</string>
   <string name="filedisplay_no_file_selected">Egy fájl sincs kiválasztva</string>
+  <string name="activity_chooser_title">Hivatkozás küldése ...</string>
+  <string name="oauth_check_onoff">Bejelentkezés oAuth2-vel</string>
   <string name="oauth_login_connection">Kapcsolódás az oAuth2 szerverhez...</string>
   <string name="ssl_validator_header">A kiszolgálót nem sikerült azonosítani</string>
   <string name="ssl_validator_reason_cert_not_trusted">- A kiszolgáló tanúsítványa nem megbízható</string>
   <string name="ssl_validator_label_validity_to">Eddig a dátumig:</string>
   <string name="ssl_validator_label_signature">Aláírás:</string>
   <string name="ssl_validator_label_signature_algorithm">Algoritmus:</string>
+  <string name="ssl_validator_null_cert">A tanúsítvány nem megjeleníthető.</string>
+  <string name="ssl_validator_no_info_about_error">- Nincs információ a hibáról</string>
   <string name="placeholder_sentence">Ez egy helyőrző</string>
   <string name="placeholder_filename">helyörző.txt</string>
   <string name="placeholder_filetype">PNG kép</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">Képeket csak WiFi kapcsolaton keresztül töltsünk föl</string>
+  <string name="instant_video_upload_on_wifi">Videó feltöltés csak WIFI-vel</string>
   <string name="instant_upload_path">/InstantUpload</string>
   <string name="conflict_title">Frissítési ütközés</string>
   <string name="conflict_message">%s távoli állományt nem szinkronizáltuk a helyi példánnyal. Ha folytatja, akkor a távoli állományt felülírjuk.</string>
   <string name="conflict_overwrite">Felülírás</string>
   <string name="conflict_dont_upload">Ne töltsük föl</string>
   <string name="preview_image_description">Előnézeti kép</string>
-  <string name="preview_image_error_unknown_format">Ez a kép nem jelenik meg</string>
-  <string name="error__upload__local_file_not_copied">%1$s-t nem sikerült átmásolni ide: %2$s </string>
-  <string name="actionbar_failed_instant_upload">Sikertelen azonnali feltöltés\"</string>
-  <string name="failed_upload_headline_text">Sikertelen Azonnali feltöltés</string>
-  <string name="failed_upload_headline_hint">Összefoglaló az összes sikertelen instant feltöltésről</string>
-  <string name="failed_upload_all_cb">Összes kijelölése</string>
-  <string name="failed_upload_headline_retryall_btn">újra az összes kiválasztott</string>
-  <string name="failed_upload_headline_delete_all_btn">törölje az összes kiválasztottat a feltöltési sorból</string>
-  <string name="failed_upload_retry_text">újra feltölteni a képet:</string>
-  <string name="failed_upload_load_more_images">További képek betöltése</string>
-  <string name="failed_upload_retry_do_nothing_text">nem vagyunk online üzemmódban az azonnali feltöltéshez</string>
-  <string name="failed_upload_failure_text">Hibaüzenet</string>
-  <string name="failed_upload_quota_exceeded_text">Kérjük ellenőrizd a szerver konfigurációt, mert lehet, hogy a kvótát túllépted.</string>
+  <string name="preview_image_error_unknown_format">Ez a kép nem jeleníthető meg</string>
+  <string name="error__upload__local_file_not_copied">%1$s nem lehet másolni a %2$s helyi könyvtárba</string>
+  <string name="share_link_file_error">Hiba lépett fel a mappa megosztásakor</string>
+  <string name="unshare_link_file_error">Hiba lépett fel a mappa megosztásának visszavonásakor</string>
+  <string name="activity_chooser_send_file_title">Küldjük el</string>
+  <string name="copy_link">Link másolása</string>
+  <string name="clipboard_text_copied">Bemásolva a vágólapra</string>
+  <string name="empty"></string>
+  <string name="prefs_category_accounts">Fiókok</string>
+  <string name="saml_authentication_required_text">Felhasználóazonosítás szükséges</string>
+  <string name="saml_authentication_wrong_pass">Hibás jelszó</string>
+  <string name="move_choose_button_text">Válasszon</string>
+  <string name="prefs_category_security">Biztonság</string>
 </resources>
index 35864be..eeb78fe 100644 (file)
@@ -1,4 +1,5 @@
 <?xml version='1.0' encoding='UTF-8'?>
 <resources>
   <string name="filedetails_download">Բեռնել</string>
+  <string name="empty"></string>
 </resources>
index 5db09aa..0d79fbd 100644 (file)
@@ -2,7 +2,10 @@
 <resources>
   <string name="actionbar_upload">Incargar</string>
   <string name="actionbar_upload_files">Files</string>
+  <string name="actionbar_mkdir">Nove dossier</string>
   <string name="actionbar_settings">Configurationes</string>
+  <string name="actionbar_send_file">Invia</string>
+  <string name="prefs_category_general">General</string>
   <string name="prefs_category_more">Plus</string>
   <string name="prefs_help">Adjuta</string>
   <string name="auth_username">Nomine de usator</string>
   <string name="sync_string_files">Files</string>
   <string name="setup_btn_connect">Connecte</string>
   <string name="uploader_btn_upload_text">Incargar</string>
+  <string name="file_list_empty">Nihil hic. Incarga alcun cosa!</string>
   <string name="filedetails_download">Discargar</string>
+  <string name="action_share_file">Compartir ligamine</string>
+  <string name="common_yes">Si</string>
+  <string name="common_no">No</string>
+  <string name="common_ok">Ok</string>
   <string name="common_cancel">Cancellar</string>
   <string name="common_error">Error</string>
   <string name="common_error_unknown">Error Incognite</string>
   <string name="change_password">Cambiar contrasigno</string>
+  <string name="uploader_info_dirname">Nomine de dossier</string>
+  <string name="activity_chooser_send_file_title">Invia</string>
+  <string name="empty"></string>
+  <string name="move_choose_button_text">Seliger</string>
 </resources>
index 3eb4ccb..be93270 100644 (file)
 <?xml version='1.0' encoding='UTF-8'?>
 <resources>
+  <string name="about_android">%1$s Apl Android</string>
+  <string name="about_version">versi %1$s</string>
+  <string name="actionbar_sync">Segarkan akun</string>
   <string name="actionbar_upload">Unggah</string>
+  <string name="actionbar_upload_from_apps">Konten dari apl lain</string>
   <string name="actionbar_upload_files">Berkas</string>
-  <string name="actionbar_settings">pengaturan</string>
-  <string name="prefs_category_general">umum</string>
+  <string name="actionbar_open_with">Buka dengan</string>
+  <string name="actionbar_mkdir">Folder baru</string>
+  <string name="actionbar_settings">Pengaturan</string>
+  <string name="actionbar_see_details">Rincian</string>
+  <string name="actionbar_send_file">Kirim</string>
+  <string name="prefs_category_general">Umum</string>
   <string name="prefs_category_more">Lainnya</string>
+  <string name="prefs_accounts">Akun</string>
+  <string name="prefs_manage_accounts">Kelola Akun</string>
+  <string name="prefs_pincode">PIN Apl</string>
+  <string name="prefs_pincode_summary">Lindungi klien Anda</string>
+  <string name="prefs_instant_upload">Unggah gambar cepat</string>
+  <string name="prefs_instant_upload_summary">Unggah gambar yang diambil kamera dengan cepat</string>
+  <string name="prefs_instant_video_upload">Unggah video cepat</string>
+  <string name="prefs_instant_video_upload_summary">Unggah video yang direkam kamera dengan cepat</string>
+  <string name="prefs_log_title">Aktifkan Pencatatan</string>
+  <string name="prefs_log_summary">Ini digunakan untuk mencatat masalah</string>
+  <string name="prefs_log_title_history">Riwayat Catatan</string>
+  <string name="prefs_log_summary_history">Ini menampilkan catatan yang disimpan</string>
+  <string name="prefs_log_delete_history_button">Riwayat Hapus</string>
   <string name="prefs_help">Bantuan</string>
-  <string name="prefs_imprint">Imprint</string>
-  <string name="auth_host_url">alamat server</string>
-  <string name="auth_username">nama pengguna</string>
-  <string name="auth_password">kata kunci</string>
+  <string name="prefs_recommend">Rekomendasikan ke teman</string>
+  <string name="prefs_feedback">Umpan balik</string>
+  <string name="prefs_imprint">Jejak</string>
+  <string name="recommend_subject">Cobalah %1$s pada ponsel cerdas Anda!</string>
+  <string name="recommend_text">Saya ingin mengajak Anda untuk menggunakan %1$s di ponsel cerdas Anda!\nUnduh gratis disini: %2$s</string>
+  <string name="auth_check_server">Periksa Server</string>
+  <string name="auth_host_url">Alamat server https://…</string>
+  <string name="auth_username">Nama Pengguna</string>
+  <string name="auth_password">Sandi</string>
+  <string name="auth_register">Baru di %1$s?</string>
   <string name="sync_string_files">Berkas</string>
+  <string name="setup_btn_connect">Sambungkan</string>
   <string name="uploader_btn_upload_text">Unggah</string>
+  <string name="uploader_top_message">Pilih folder unggah:</string>
+  <string name="uploader_wrn_no_account_title">Tidak ada akun yang ditemukan</string>
+  <string name="uploader_wrn_no_account_text">Belum ada akun %1$s pada perangkat Anda. Silahkan buat akun terlebih dahulu.</string>
+  <string name="uploader_wrn_no_account_setup_btn_text">Pengaturan</string>
   <string name="uploader_wrn_no_account_quit_btn_text">Keluar</string>
-  <string name="filedetails_download">unduh</string>
+  <string name="uploader_wrn_no_content_title">Tidak ada konten untuk diunggah</string>
+  <string name="uploader_wrn_no_content_text">Tidak ada konten yang diterima. Tidak ada yang diunggah</string>
+  <string name="uploader_error_forbidden_content">%1$s tidak diizinkan mengakses konten berbagi</string>
+  <string name="uploader_info_uploading">Mengunggah</string>
+  <string name="file_list_empty">Tidak ada apa-apa di sini. Unggah sesuatu!</string>
+  <string name="file_list_loading">Memuat...</string>
+  <string name="local_file_list_empty">Tidak ada satupun berkas dalam folder ini.</string>
+  <string name="filedetails_select_file">Sentuh pada berkas untuk menampilkan informasi tambahan</string>
+  <string name="filedetails_size">Ukuran:</string>
+  <string name="filedetails_type">Tipe:</string>
+  <string name="filedetails_created">Dibuat:</string>
+  <string name="filedetails_modified">Diubah:</string>
+  <string name="filedetails_download">Unduh</string>
+  <string name="filedetails_sync_file">Segarkan berkas</string>
+  <string name="filedetails_renamed_in_upload_msg">Berkas diubah namanya menjadi %1$s saat pengunggahan</string>
+  <string name="action_share_file">Bagikan tautan</string>
+  <string name="action_unshare_file">Batal bagikan tautan</string>
   <string name="common_yes">Ya</string>
   <string name="common_no">Tidak</string>
   <string name="common_ok">Oke</string>
+  <string name="common_cancel_download">Batal mengunduh</string>
   <string name="common_cancel_upload">Batal mengunggah</string>
-  <string name="common_cancel">batal</string>
-  <string name="common_error">kesalahan</string>
+  <string name="common_cancel">Batal</string>
+  <string name="common_save_exit">Simpan &amp; Keluar</string>
+  <string name="common_error">Kesalahan</string>
+  <string name="common_loading">Memuat ...</string>
+  <string name="common_error_unknown">Galat tidak diketahui</string>
+  <string name="about_title">Tentang</string>
   <string name="change_password">Ubah sandi</string>
+  <string name="delete_account">Hapus akun</string>
+  <string name="create_account">Buat akun</string>
+  <string name="upload_chooser_title">Unggah dari...</string>
+  <string name="uploader_info_dirname">Nama folder</string>
+  <string name="uploader_upload_in_progress_ticker">Mengungggah...</string>
+  <string name="uploader_upload_in_progress_content">%1$d%% Mengunggah %2$s</string>
+  <string name="uploader_upload_succeeded_ticker">Berhasil mengunggah</string>
+  <string name="uploader_upload_succeeded_content_single">%1$s berhasil diunggah</string>
+  <string name="uploader_upload_failed_ticker">Gagal mengunggah</string>
+  <string name="uploader_upload_failed_content_single">Unggah %1$s tidak selesai</string>
+  <string name="downloader_download_in_progress_ticker">Mengunduh...</string>
+  <string name="downloader_download_in_progress_content">%1$d%% Mengunduh %2$s</string>
+  <string name="downloader_download_succeeded_ticker">Berhasil mengunduh</string>
+  <string name="downloader_download_succeeded_content">%1$s berhasil diunduh</string>
+  <string name="downloader_download_failed_ticker">Gagal Mengunduh</string>
+  <string name="downloader_download_failed_content">Mengunduh %1$s tidak selesai</string>
+  <string name="downloader_not_downloaded_yet">Belum diunduh</string>
+  <string name="downloader_download_failed_credentials_error">Gagal mengunduh, Anda perlu masuk kembali</string>
+  <string name="common_choose_account">Pilih akun</string>
+  <string name="sync_fail_ticker">Sinkronisasi gagal</string>
+  <string name="sync_fail_ticker_unauthorized">Sinkronisasi gagal, Anda perlu masuk kembali</string>
+  <string name="sync_fail_content">Sinkronisasi %1$s tidak selesai</string>
+  <string name="sync_fail_content_unauthorized">Sandi salah untuk %1$s</string>
+  <string name="sync_conflicts_in_favourites_ticker">Konflik ditemukan</string>
+  <string name="sync_conflicts_in_favourites_content">%1$d berkas kept-in-sync tidak dapat disinkronkan</string>
+  <string name="sync_fail_in_favourites_ticker">Berkas kept-in-sync gagal</string>
+  <string name="sync_fail_in_favourites_content">Konten berkas %1$d tidak dapat disinkronasikan (%2$d konflik)</string>
+  <string name="sync_foreign_files_forgotten_ticker">Beberapa berkas lokal terlupakan</string>
+  <string name="sync_foreign_files_forgotten_content">%1$d berkas diluar folder %2$s tidak dapat disalin kedalamnya</string>
+  <string name="sync_foreign_files_forgotten_explanation">Sejak versi  1.3.16, berkas-berkas yang diunggah dari piranti ini akan disalin kedalam folder %1$s lokal untuk mencagah kehilangan data ketika berkas tunggal disinkronkan dengan akun lebih dari satu.\n\nAkibat perubahan ini, semua berkas yang diunggah di versi aplikasi sebelumnya disalin kedalam folder %2$s. Namun, sebuah kesalahan mencegah penyelesaian operasi ini saat sinkronisasi berlangsung akun. Anda boleh meninggalkan berkas seperti ini dan menghapus tautan ke %3$s atau memindahkan berkas kedalam folder %1$s dan membiarkan tautan ke %4$s.\n\nYang tampak dibawah adalah berkas lokal, dan berkas remote didalam %5$s yang dihubungkan dengannya.</string>
+  <string name="sync_current_folder_was_removed">Folder %1$s tidak ada lagi</string>
+  <string name="foreign_files_move">Pindahkan semua</string>
+  <string name="foreign_files_success">Semua berkas sudah dipindahkan</string>
+  <string name="foreign_files_fail">Beberapa berkas tidak dapat dipindahkan</string>
+  <string name="foreign_files_local_text">Lokal: %1$s</string>
+  <string name="foreign_files_remote_text">Jauh: %1$s</string>
+  <string name="upload_query_move_foreign_files">Ruang tidak cukup untuk menyalin berkas terpilih kedalam folder %1$s. Apakah Anda ingin memindahkannya saja?</string>
+  <string name="pincode_enter_pin_code">Silakan masukkan PIN Apl</string>
+  <string name="pincode_configure_your_pin">Masukkan PIN Apl</string>
+  <string name="pincode_configure_your_pin_explanation">PIN akan selalu diminta setiap kali apl dijalankan</string>
+  <string name="pincode_reenter_your_pincode">Silakan masukkan ulang PIN Apl</string>
+  <string name="pincode_remove_your_pincode">Hapus PIN Apl</string>
+  <string name="pincode_mismatch">PIN Apl tidak sama</string>
+  <string name="pincode_wrong">PIN Apl salah</string>
+  <string name="pincode_removed">PIN Apl dihapus</string>
+  <string name="pincode_stored">PIN Apl disimpan</string>
+  <string name="media_notif_ticker">Pemutar musik %1$s</string>
+  <string name="media_state_playing">%1$s (dimainkan)</string>
+  <string name="media_state_loading">%1$s (sedang dimuat)</string>
+  <string name="media_event_done">%1$s pemutaran selesai</string>
+  <string name="media_err_nothing_to_play">Tidak ditemukan berkas media</string>
+  <string name="media_err_no_account">Tidak ada akun yang diberikan</string>
+  <string name="media_err_not_in_owncloud">Brkas tidak didalam akun yang sah</string>
+  <string name="media_err_unsupported">Kodek media tidak didukung</string>
+  <string name="media_err_io">Berkas media tidak dapat dibaca</string>
+  <string name="media_err_malformed">Berkas media tidak di enkode dengan benar</string>
+  <string name="media_err_timeout">Waktu habis saat mencoba untuk main</string>
+  <string name="media_err_invalid_progressive_playback">Berkas media tidak bisa dialirkan</string>
+  <string name="media_err_unknown">Berkas media tidak dapat dimainkan dengan pemutar media</string>
+  <string name="media_err_security_ex">Kesalahan keamanan saat mencoba memutar %1$s</string>
+  <string name="media_err_io_ex">Kesalahan masukkan saat mencoba memutar %1$s</string>
+  <string name="media_err_unexpected">Kesalahan tak terduga saat mencoba memutar %1$s</string>
+  <string name="media_rewind_description">Tombol mundur</string>
+  <string name="media_play_pause_description">Tombol main dan jeda</string>
+  <string name="media_forward_description">Tombol maju</string>
+  <string name="auth_getting_authorization">Mendapatkan otorisasi...</string>
+  <string name="auth_trying_to_login">Mencoba untuk masuk...</string>
+  <string name="auth_no_net_conn_title">Tidak ada koneksi internet</string>
+  <string name="auth_nossl_plain_ok_title">Sambungan aman tidak tersedia</string>
+  <string name="auth_connection_established">Sambungan dibuat</string>
+  <string name="auth_testing_connection">Pengetesan koneksi ...</string>
+  <string name="auth_not_configured_title">Konfigurasi server cacat</string>
+  <string name="auth_account_not_new">Akun untuk pengguna dan server yang sama sudah ada dalam perangkat</string>
+  <string name="auth_account_not_the_same">Pengguna yang dimasukkan tidak cocok dengan pengguna akun ini</string>
+  <string name="auth_unknown_error_title">Terjadi kesalahan yang tidak diketahui!</string>
+  <string name="auth_unknown_host_title">Tidak menemukan host</string>
+  <string name="auth_incorrect_path_title">Instansi server tidak ditemukan</string>
+  <string name="auth_timeout_title">Server terlalu lama merespon</string>
+  <string name="auth_incorrect_address_title">Format URL salah</string>
+  <string name="auth_ssl_general_error_title">Menginisiasi SSL gagal</string>
+  <string name="auth_ssl_unverified_server_title">Tidak dapat memverifikasi identitas server SSL</string>
+  <string name="auth_bad_oc_version_title">Versi server tidak dikenal</string>
+  <string name="auth_wrong_connection_title">Tidak dapat membuat koneksi</string>
+  <string name="auth_secure_connection">Sambungan aman dibuat</string>
+  <string name="auth_unauthorized">Nama pengguna dan sandi salah</string>
+  <string name="auth_oauth_error">Otorisasi tidak berhasil</string>
+  <string name="auth_oauth_error_access_denied">Akses ditolak oleh server otorisasi</string>
+  <string name="auth_wtf_reenter_URL">Keadaan tak terduga, silahkan masukkan URL server yang lagi</string>
+  <string name="auth_expired_oauth_token_toast">Otorisasi Anda telah berakhir. Silakan mengotorisasi lagi</string>
+  <string name="auth_expired_basic_auth_toast">Silakan mesukkan sandi saat ini</string>
+  <string name="auth_expired_saml_sso_token_toast">Sesi Anda telah berakhir. Silakan masuk kembali</string>
+  <string name="auth_connecting_auth_server">Menyambungkan ke server otentikasi...</string>
+  <string name="auth_unsupported_auth_method">Server tidak mendukung medote otentikasi ini</string>
+  <string name="auth_unsupported_multiaccount">%1$s tidak mendukung banyak akun </string>
+  <string name="auth_can_not_auth_against_server">Tidak dapat mengotentikasi pada server ini</string>
+  <string name="fd_keep_in_sync">Biarkan berkas tetap terbaru</string>
   <string name="common_rename">Ubah nama</string>
-  <string name="common_remove">hilangkan</string>
-  <string name="ssl_validator_btn_details_hide">sembunyikan</string>
+  <string name="common_remove">Hapus</string>
+  <string name="confirmation_remove_alert">Apakah Anda yakin ingin menghapus %1$s?</string>
+  <string name="confirmation_remove_folder_alert">Apakah Anda yakin ingin menghapus %1$s dan isinya?</string>
+  <string name="confirmation_remove_local">Lokal saja</string>
+  <string name="confirmation_remove_folder_local">Konten lokal saja</string>
+  <string name="confirmation_remove_remote">Hapus dari server</string>
+  <string name="confirmation_remove_remote_and_local">Jarak jauh dan lokal</string>
+  <string name="remove_success_msg">Penghapusan berhasil</string>
+  <string name="remove_fail_msg">Penghapusan gagal</string>
+  <string name="rename_dialog_title">Masukkan nama baru</string>
+  <string name="rename_local_fail_msg">Salinan lokal tidak dapat diubah nama, coba dengan nama yang berbeda</string>
+  <string name="rename_server_fail_msg">Mengubah nama tidak selesai</string>
+  <string name="sync_file_fail_msg">Berkas jauh tidak dapat diperiksa</string>
+  <string name="sync_file_nothing_to_do_msg">Isi berkas sudah diselaraskan</string>
+  <string name="create_dir_fail_msg">Folder tidak dapat dibuat</string>
+  <string name="filename_forbidden_characters">Karakter yang dilarang: / \\ &lt; &gt; : \" | ? *</string>
+  <string name="filename_empty">Nama berkas tidak boleh kosong</string>
+  <string name="wait_a_moment">Tunggu sebentar</string>
+  <string name="filedisplay_unexpected_bad_get_content">Masalah tidak terduga, silahkan pilih berkas dari apl yang berbeda</string>
+  <string name="filedisplay_no_file_selected">Tidak ada berkas yang terpilih</string>
+  <string name="activity_chooser_title">Kirim taukan ke</string>
+  <string name="oauth_check_onoff">Masuk dengan oAuth2</string>
+  <string name="oauth_login_connection">Menyambungkan ke server oAuth2...</string>
+  <string name="ssl_validator_header">Identitas situs tidak dapat diverfikasi</string>
+  <string name="ssl_validator_reason_cert_not_trusted">- Sertifikat server tidak terpercaya</string>
+  <string name="ssl_validator_reason_cert_expired">- Sertifikat server kadaluarsa</string>
+  <string name="ssl_validator_reason_cert_not_yet_valid">- Tanggal sertifikat server yang valid adalah di masa depan</string>
+  <string name="ssl_validator_reason_hostname_not_verified">- URL tidak cocok dengan nama host dalam sertifikat</string>
+  <string name="ssl_validator_question">Apakah Anda percaya dengan sertifikat ini?</string>
+  <string name="ssl_validator_not_saved">Sertifikat tidak dapat disimpan</string>
+  <string name="ssl_validator_btn_details_see">Rincian</string>
+  <string name="ssl_validator_btn_details_hide">Sembunyikan</string>
+  <string name="ssl_validator_label_subject">Diterbitkan untuk:</string>
+  <string name="ssl_validator_label_issuer">Diterbitkan oleh:</string>
+  <string name="ssl_validator_label_CN">Nama panggilan:</string>
+  <string name="ssl_validator_label_O">Organisasi:</string>
+  <string name="ssl_validator_label_OU">Unit Organisasi:</string>
+  <string name="ssl_validator_label_C">Negara:</string>
+  <string name="ssl_validator_label_ST">Negara bagian:</string>
+  <string name="ssl_validator_label_L">Lokasi:</string>
+  <string name="ssl_validator_label_validity">Masa berlaku:</string>
+  <string name="ssl_validator_label_validity_from">Dari:</string>
+  <string name="ssl_validator_label_validity_to">Untuk:</string>
+  <string name="ssl_validator_label_signature">Tanda tangan:</string>
+  <string name="ssl_validator_label_signature_algorithm">Algoritma:</string>
+  <string name="ssl_validator_null_cert">Sertifikat tidak dapat ditampilkan.</string>
+  <string name="ssl_validator_no_info_about_error">- Tidak ada informasi tantang terror</string>
+  <string name="placeholder_sentence">Ini adalah placeholder</string>
+  <string name="placeholder_filename">placeholder.txt</string>
+  <string name="placeholder_filetype">Gambar PNG</string>
+  <string name="placeholder_filesize">389 KB</string>
+  <string name="placeholder_timestamp">18/05/2012 12:23 PM</string>
+  <string name="placeholder_media_time">12:23:45</string>
+  <string name="instant_upload_on_wifi">Hanya unggah gambar via WiFi</string>
+  <string name="instant_video_upload_on_wifi">Hanya unggah video via WiFi</string>
+  <string name="instant_upload_path">/UnggahInstan</string>
+  <string name="conflict_title">Perbarui benturan</string>
+  <string name="conflict_message">Berkas jauh %s tidak sinkron dengan berkas lokal. Melanjutkan akan menggantikan konten berkas di server.</string>
+  <string name="conflict_keep_both">Biarkan keduannya</string>
+  <string name="conflict_overwrite">Timpa</string>
+  <string name="conflict_dont_upload">Jangan mengunggah</string>
+  <string name="preview_image_description">Pratilik gambar</string>
+  <string name="preview_image_error_unknown_format">Gambar ini tidak dapat ditampilkan</string>
+  <string name="activity_chooser_send_file_title">Kirim</string>
+  <string name="clipboard_text_copied">Disalin ke papan klip</string>
+  <string name="empty"></string>
+  <string name="prefs_category_accounts">Akun</string>
+  <string name="saml_authentication_required_text">Diperlukan otentikasi</string>
+  <string name="saml_authentication_wrong_pass">Sandi salah</string>
+  <string name="move_choose_button_text">Pilih</string>
+  <string name="prefs_category_security">Keamanan</string>
 </resources>
diff --git a/res/values-io/strings.xml b/res/values-io/strings.xml
new file mode 100644 (file)
index 0000000..56e55a1
--- /dev/null
@@ -0,0 +1,4 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<resources>
+  <string name="empty"></string>
+</resources>
index 6a2f987..d6eaeda 100644 (file)
@@ -3,20 +3,26 @@
   <string name="actionbar_upload">Senda inn</string>
   <string name="actionbar_upload_files">Skrár</string>
   <string name="actionbar_settings">Stillingar</string>
+  <string name="actionbar_send_file">Senda</string>
   <string name="prefs_category_more">Meira</string>
   <string name="prefs_help">Hjálp</string>
-  <string name="auth_host_url">Host nafn netþjóns</string>
   <string name="auth_username">Notendanafn</string>
   <string name="auth_password">Lykilorð</string>
   <string name="sync_string_files">Skrár</string>
   <string name="uploader_btn_upload_text">Senda inn</string>
+  <string name="file_list_empty">Ekkert hér. Settu eitthvað inn!</string>
   <string name="filedetails_download">Niðurhal</string>
   <string name="common_yes">Já</string>
   <string name="common_no">Nei</string>
+  <string name="common_ok">Í lagi</string>
   <string name="common_cancel_upload">Hætta við innsendingu</string>
   <string name="common_cancel">Hætta við</string>
   <string name="common_error"><strong>Villa</strong></string>
   <string name="change_password">Breyta lykilorði</string>
+  <string name="uploader_info_dirname">Nafn möppu</string>
   <string name="common_rename">Endurskýra</string>
   <string name="common_remove">Fjarlægja</string>
+  <string name="activity_chooser_send_file_title">Senda</string>
+  <string name="empty"></string>
+  <string name="move_choose_button_text">Veldu</string>
 </resources>
index 0bd8aa8..ffa01f3 100644 (file)
@@ -7,17 +7,20 @@
   <string name="actionbar_upload_from_apps">Contenuti da altre applicazioni</string>
   <string name="actionbar_upload_files">File</string>
   <string name="actionbar_open_with">Apri con</string>
-  <string name="actionbar_mkdir">Crea cartella</string>
+  <string name="actionbar_mkdir">Nuova cartella</string>
   <string name="actionbar_settings">Impostazioni</string>
   <string name="actionbar_see_details">Dettagli</string>
+  <string name="actionbar_send_file">Invia</string>
   <string name="prefs_category_general">Generale</string>
   <string name="prefs_category_more">Altro</string>
   <string name="prefs_accounts">Account</string>
   <string name="prefs_manage_accounts">Gestisci account</string>
   <string name="prefs_pincode">PIN App</string>
   <string name="prefs_pincode_summary">Proteggi il tuo client l\'applicazione</string>
-  <string name="prefs_instant_upload">Caricamento immediato</string>
+  <string name="prefs_instant_upload">Caricamenti istantanei delle foto</string>
   <string name="prefs_instant_upload_summary">Carica immediatamente le foto dalla fotocamera</string>
+  <string name="prefs_instant_video_upload">Caricamenti istantanei dei video</string>
+  <string name="prefs_instant_video_upload_summary">Carica immediatamente i video dalla fotocamera</string>
   <string name="prefs_log_title">Abilita registrazione log</string>
   <string name="prefs_log_summary">Usato per registrare i problemi nei log</string>
   <string name="prefs_log_title_history">Cronologia di registrazione log</string>
   <string name="prefs_feedback">Segnalazioni</string>
   <string name="prefs_imprint">Imprint</string>
   <string name="recommend_subject">Prova %1$s sul tuo smartphone!</string>
-  <string name="recommend_text">Vorrei invitarti ad usare %1$s sul tuo smartphone!⏎\nScarica qui: %2$s</string>
+  <string name="recommend_text">Vorrei invitarti a usare %1$s sul tuo smartphone!\nScarica qui: %2$s</string>
   <string name="auth_check_server">Verifica server</string>
-  <string name="auth_host_url">Indirizzo del server</string>
+  <string name="auth_host_url">Indirizzo server https://...</string>
   <string name="auth_username">Nome utente</string>
   <string name="auth_password">Password</string>
   <string name="auth_register">Prima volta su %1$s?</string>
   <string name="sync_string_files">File</string>
   <string name="setup_btn_connect">Connetti</string>
   <string name="uploader_btn_upload_text">Carica</string>
-  <string name="uploader_top_message">Scegli la cartella di caricamento:</string>
+  <string name="uploader_top_message">Scegli la cartella da caricare:</string>
   <string name="uploader_wrn_no_account_title">Nessun account trovato</string>
   <string name="uploader_wrn_no_account_text">Non ci sono account %1$s sul tuo dispositivo. Configura prima un account.</string>
   <string name="uploader_wrn_no_account_setup_btn_text">Configurazione</string>
@@ -46,7 +49,9 @@
   <string name="uploader_wrn_no_content_text">Non è stato ricevuto alcun contenuto. Niente da caricare.</string>
   <string name="uploader_error_forbidden_content">%1$s non è abilitato ad accedere al contenuto condiviso</string>
   <string name="uploader_info_uploading">Caricamento in corso</string>
-  <string name="file_list_empty">Non ci sono file in questa cartella.\nNuovi file possono essere aggiunti con l\'opzione di menu \"Carica\".</string>
+  <string name="file_list_empty">Non c\'è niente qui. Carica qualcosa!</string>
+  <string name="file_list_loading">Caricamento in corso...</string>
+  <string name="local_file_list_empty">Non ci sono file in questa cartella.</string>
   <string name="filedetails_select_file">Tocca un file per visualizzare informazioni aggiuntive.</string>
   <string name="filedetails_size">Dimensione:</string>
   <string name="filedetails_type">Tipo:</string>
@@ -55,6 +60,8 @@
   <string name="filedetails_download">Scarica</string>
   <string name="filedetails_sync_file">Aggiorna file</string>
   <string name="filedetails_renamed_in_upload_msg">Il file è stato rinominato in %1$s durante il caricamento</string>
+  <string name="action_share_file">Condividi collegamento</string>
+  <string name="action_unshare_file">Rimuovi condivisione collegamento</string>
   <string name="common_yes">Sì</string>
   <string name="common_no">No</string>
   <string name="common_ok">OK</string>
   <string name="delete_account">Elimina account</string>
   <string name="create_account">Crea account</string>
   <string name="upload_chooser_title">Carica file da...</string>
-  <string name="uploader_info_dirname">Nome cartella</string>
+  <string name="uploader_info_dirname">Nome della cartella</string>
   <string name="uploader_upload_in_progress_ticker">Caricamento in corso...</string>
   <string name="uploader_upload_in_progress_content">%1$d%% Caricamento di %2$s</string>
   <string name="uploader_upload_succeeded_ticker">Caricamento effettuato</string>
   <string name="uploader_upload_succeeded_content_single">%1$s è stato caricato correttamente</string>
   <string name="uploader_upload_failed_ticker">Caricamento non riuscito</string>
   <string name="uploader_upload_failed_content_single">Il caricamento di %1$s non può essere completato</string>
+  <string name="uploader_upload_failed_credentials_error">Caricamento non riuscito, devi ripetere l\'accesso</string>
   <string name="downloader_download_in_progress_ticker">Scaricamento in corso...</string>
   <string name="downloader_download_in_progress_content">%1$d%% Scaricamento di %2$s</string>
   <string name="downloader_download_succeeded_ticker">Scaricamento effettuato</string>
   <string name="downloader_download_failed_ticker">Scaricamento non riuscito</string>
   <string name="downloader_download_failed_content">Scaricamento di %1$s non è stato completato</string>
   <string name="downloader_not_downloaded_yet">Non ancora scaricato</string>
+  <string name="downloader_download_failed_credentials_error">Scaricamento non riuscito, devi ripetere l\'accesso</string>
   <string name="common_choose_account">Scegli account</string>
   <string name="sync_fail_ticker">Sincronizzazione non riuscita</string>
+  <string name="sync_fail_ticker_unauthorized">Sincronizzazione non riuscita, devi ripetere l\'accesso</string>
   <string name="sync_fail_content">La sincronizzazione di %1$s non può essere completata</string>
   <string name="sync_fail_content_unauthorized">Password non valida per %1$s</string>
   <string name="sync_conflicts_in_favourites_ticker">Conflitti rilevati</string>
   <string name="foreign_files_fail">Alcuni file non possono essere spostati</string>
   <string name="foreign_files_local_text">Locale: %1$s</string>
   <string name="foreign_files_remote_text">Remoto %1$s</string>
-  <string name="upload_query_move_foreign_files">Non c\'è spazio sufficiente per copiare i file selezionati nella cartella %1$s. Vuoi invece spostarli nella cartella?</string>
+  <string name="upload_query_move_foreign_files">Non c\'è spazio sufficiente per copiare i file selezionati nella cartella %1$s. Vuoi invece spostarli?</string>
   <string name="pincode_enter_pin_code">Inserisci il PIN dell\'applicazione</string>
   <string name="pincode_configure_your_pin">Inserisci il PIN di l\'applicazione</string>
   <string name="pincode_configure_your_pin_explanation">Il PIN sarà richiesto ad ogni avvio dell\'applicazione</string>
   <string name="media_rewind_description">Pulsante Riavvolgi</string>
   <string name="media_play_pause_description">Pulsante Riproduci o pausa</string>
   <string name="media_forward_description">Pulsante Avanti veloce</string>
+  <string name="auth_getting_authorization">Autorizzazione in corso...</string>
   <string name="auth_trying_to_login">Tentativo di accesso in corso...</string>
   <string name="auth_no_net_conn_title">Nessuna connessione di rete</string>
   <string name="auth_nossl_plain_ok_title">Connessione sicura disponibile.</string>
   <string name="auth_connecting_auth_server">Connessione al server di autenticazione in corso...</string>
   <string name="auth_unsupported_auth_method">Il server non supporta questo metodo di autenticazione</string>
   <string name="auth_unsupported_multiaccount">%1$s non supporta account multipli</string>
+  <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="fd_keep_in_sync">Tieni aggiornato il file</string>
   <string name="common_rename">Rinomina</string>
   <string name="common_remove">Rimuovi</string>
   <string name="confirmation_remove_alert">Vuoi davvero rimuovere %1$s?</string>
-  <string name="confirmation_remove_folder_alert">Vuoi davvero rimuovere %1$s ed i suoi contenuti?</string>
+  <string name="confirmation_remove_folder_alert">Vuoi davvero rimuovere %1$s e il suo contenuto?</string>
   <string name="confirmation_remove_local">Solo localmente</string>
   <string name="confirmation_remove_folder_local">Solo contenuti locali</string>
   <string name="confirmation_remove_remote">Rimuovi dal server</string>
   <string name="sync_file_fail_msg">Il file remoto non può essere controllato</string>
   <string name="sync_file_nothing_to_do_msg">Contenuti del file già sincronizzati</string>
   <string name="create_dir_fail_msg">La cartella non può essere creata</string>
+  <string name="filename_forbidden_characters">Caratteri proibiti: / \\ &lt; &gt; : \" | ? *</string>
+  <string name="filename_empty">Il nome del file non può essere vuoto</string>
   <string name="wait_a_moment">Attendi</string>
   <string name="filedisplay_unexpected_bad_get_content">Problema inatteso; prova un\'altra applicazione per selezionare il file</string>
   <string name="filedisplay_no_file_selected">Non è stato selezionato alcun file</string>
+  <string name="activity_chooser_title">Invia collegamento a...</string>
   <string name="oauth_check_onoff">Accesso con oAuth2.</string>
   <string name="oauth_login_connection">Connessione al server oAuth2 in corso...</string>
   <string name="ssl_validator_header">L\'identità del sito non può essere verificata</string>
   <string name="ssl_validator_label_validity_to">A:</string>
   <string name="ssl_validator_label_signature">Firma:</string>
   <string name="ssl_validator_label_signature_algorithm">Algoritmo:</string>
+  <string name="ssl_validator_null_cert">Il certificato non può essere mostrato.</string>
+  <string name="ssl_validator_no_info_about_error">- Nessuna informazione sull\'errore</string>
   <string name="placeholder_sentence">Questo è un segnaposto</string>
   <string name="placeholder_filename">segnaposto.txt</string>
   <string name="placeholder_filetype">Immagine PNG</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">Carica le immagini solo via WiFi</string>
+  <string name="instant_video_upload_on_wifi">Carica i video solo tramite WiFi</string>
   <string name="instant_upload_path">/InstantUpload</string>
   <string name="conflict_title">Conflitto di aggiornamento</string>
   <string name="conflict_message">Il file remoto %s non è sincronizzato con il file locale. Se continui, il contenuto del file sarà sostituito sul server.</string>
   <string name="preview_image_description">Anteprima dell\'immagine</string>
   <string name="preview_image_error_unknown_format">Questa immagine non può essere mostrata</string>
   <string name="error__upload__local_file_not_copied">%1$s non può essere copiato nella cartella locale %2$s</string>
-  <string name="actionbar_failed_instant_upload">Caricamento istantaneo non riuscito\"</string>
-  <string name="failed_upload_headline_text">Caricamenti istantanei non riusciti</string>
-  <string name="failed_upload_headline_hint">Riepilogo dei caricamenti istantanei non riusciti</string>
-  <string name="failed_upload_all_cb">seleziona tutto</string>
-  <string name="failed_upload_headline_retryall_btn">riprova tutti i selezionati</string>
-  <string name="failed_upload_headline_delete_all_btn">elimina tutti i selezionati dalla coda di caricamento</string>
-  <string name="failed_upload_retry_text">riprova a caricare l\'immagine:</string>
-  <string name="failed_upload_load_more_images">Carica altre immagini</string>
-  <string name="failed_upload_retry_do_nothing_text">non fare niente, non sei collegato per i caricamenti istantanei</string>
-  <string name="failed_upload_failure_text">Messaggio d\'errore:</string>
-  <string name="failed_upload_quota_exceeded_text">Controlla la configurazione del server, forse hai superato la tua quota.</string>
+  <string name="prefs_instant_upload_path_title">Percorso di caricamento</string>
+  <string name="share_link_no_support_share_api">Spiacenti, la condivisione non è abilitata sul tuo server. Contatta il tuo
+               amministratore.</string>
+  <string name="share_link_file_no_exist">Impossibile condividere. Assicurati che il file esista</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="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="error_cant_bind_to_operations_service">Errore grave: impossibile eseguire le operazioni</string>
+  <string name="network_error_socket_exception">Si è verificato un errore durante la connessione al server.</string>
+  <string name="network_error_socket_timeout_exception">Si è verificato un errore in attesa della risposta del server, l\'operazione non è stata completata</string>
+  <string name="network_error_connect_timeout_exception">Si è verificato un errore in attesa della risposta del server, l\'operazione non è stata completata</string>
+  <string name="network_host_not_available">L\'operazione non è stata completata, il server non è disponibile</string>
+  <string name="empty"></string>
+  <string name="forbidden_permissions">Non hai i permessi %s</string>
+  <string name="forbidden_permissions_rename">per rinominare questo file</string>
+  <string name="forbidden_permissions_delete">per eliminare questo file</string>
+  <string name="share_link_forbidden_permissions">per condividere questo file</string>
+  <string name="unshare_link_forbidden_permissions">per rimuovere la condivisione di questo file</string>
+  <string name="forbidden_permissions_create">per creare il file</string>
+  <string name="uploader_upload_forbidden_permissions">per caricare in questa cartella</string>
+  <string name="downloader_download_file_not_found">Il file non è più disponibile sul server</string>
+  <string name="prefs_category_accounts">Account</string>
+  <string name="prefs_add_account">Aggiungi account</string>
+  <string name="auth_redirect_non_secure_connection_title">La connessione sicura è rediretta su un percorso non sicuro.</string>
+  <string name="actionbar_logger">Registri</string>
+  <string name="log_send_history_button">Invia cronologia</string>
+  <string name="log_mail_subject">Registri applicazione ownCloud Android</string>
+  <string name="log_progress_dialog_text">Caricamento dati...</string>
+  <string name="saml_authentication_required_text">Autenticazione richiesta</string>
+  <string name="saml_authentication_wrong_pass">Password errata</string>
+  <string name="actionbar_move">Sposta</string>
+  <string name="file_list_empty_moving">Qui non c\'è niente. Puoi aggiungere una cartella.</string>
+  <string name="move_choose_button_text">Scegli</string>
+  <string name="move_file_not_found">Impossibile spostare. Assicurati che il file esista</string>
+  <string name="move_file_invalid_into_descendent">Impossibile spostare una cartella in una cartella inferiore</string>
+  <string name="move_file_invalid_overwrite">Il file esiste già nella cartella di destinazione</string>
+  <string name="move_file_error">Si è verificato un errore durante il tentativo di spostare il file o la cartella</string>
+  <string name="forbidden_permissions_move">per spostare questo file</string>
+  <string name="prefs_category_instant_uploading">Caricamenti istantanei</string>
+  <string name="prefs_category_security">Protezione</string>
 </resources>
index 04961ea..b6d8ffb 100644 (file)
@@ -1,26 +1,29 @@
 <?xml version='1.0' encoding='UTF-8'?>
 <resources>
-  <string name="about_android">%1$s アンドロイドアプリ</string>
+  <string name="about_android">%1$s Androidアプリ</string>
   <string name="about_version">バージョン %1$s</string>
   <string name="actionbar_sync">アカウントを同期</string>
-  <string name="actionbar_upload">ã\83\95ã\82¡ã\82¤ã\83«ã\82\92ã\82¢ã\83\83ã\83\97ã\83­ã\83¼ã\83\89</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="actionbar_mkdir">新しいフォルダー</string>
   <string name="actionbar_settings">設定</string>
   <string name="actionbar_see_details">詳細</string>
+  <string name="actionbar_send_file">送信</string>
   <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">自動画像アップロード</string>
   <string name="prefs_instant_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_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_feedback">フィードバック</string>
   <string name="prefs_imprint">インプリント</string>
   <string name="recommend_subject">スマートフォンで %1$s を試してください!</string>
-  <string name="recommend_text">スマートフォンで %1$s を利用してみませんか!\nここからダウンロードしてください: %2$s</string>
+  <string name="recommend_text">スマートフォンで %1$s を利用してみませんか!
+ここからダウンロードしてください: %2$s</string>
   <string name="auth_check_server">サーバーを確認する</string>
-  <string name="auth_host_url">ã\82µã\83¼ã\83\90ã\82¢ã\83\89ã\83¬ã\82¹</string>
+  <string name="auth_host_url">ã\82µã\83¼ã\83\90ã\83¼ã\82¢ã\83\89ã\83¬ã\82¹ https://â\80¦</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="uploader_btn_upload_text">アップロード</string>
-  <string name="uploader_top_message">ã\82¢ã\83\83ã\83\97ã\83­ã\83¼ã\83\89ã\83\87ã\82£ã\83¬ã\82¯ã\83\88ã\83ªを選択:</string>
+  <string name="uploader_top_message">ã\82¢ã\83\83ã\83\97ã\83­ã\83¼ã\83\89ã\81\99ã\82\8bã\83\95ã\82©ã\83«ã\83\80ã\83¼を選択:</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>
@@ -46,7 +50,9 @@
   <string name="uploader_wrn_no_content_text">コンテンツを受信しませんでした。アップロードするものはありません。</string>
   <string name="uploader_error_forbidden_content">%1$sで共有コンテンツへのアクセスが許可されていません。</string>
   <string name="uploader_info_uploading">アップロード中</string>
-  <string name="file_list_empty">このフォルダにはファイルがありません。\n\"アップロード\" メニューで新しいファイルを追加することができます。</string>
+  <string name="file_list_empty">ここには何もありません。何かアップロードしてください。</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>
@@ -55,6 +61,8 @@
   <string name="filedetails_download">ダウンロード</string>
   <string name="filedetails_sync_file">ファイルを同期</string>
   <string name="filedetails_renamed_in_upload_msg">アップロード中にファイル名を %1$s に変更しました</string>
+  <string name="action_share_file">URLで共有</string>
+  <string name="action_unshare_file">未共有のリンク</string>
   <string name="common_yes">はい</string>
   <string name="common_no">いいえ</string>
   <string name="common_ok">OK</string>
   <string name="delete_account">アカウントを削除</string>
   <string name="create_account">アカウントを作成</string>
   <string name="upload_chooser_title">アップロード …</string>
-  <string name="uploader_info_dirname">ã\83\87ã\82£ã\83¬ã\82¯ã\83\88ã\83ª名</string>
+  <string name="uploader_info_dirname">ã\83\95ã\82©ã\83«ã\83\80ã\83¼名</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_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_failed_ticker">ダウンロードに失敗</string>
   <string name="downloader_download_failed_content">%1$s のダウンロードは完了しませんでした</string>
   <string name="downloader_not_downloaded_yet">未ダウンロード</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_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_conflicts_in_favourites_content">%1$d 同期ファイルを同期できませんでした</string>
   <string name="sync_fail_in_favourites_ticker">ファイルの同期に失敗しました</string>
   <string name="sync_fail_in_favourites_content">%1$d ファイルのコンテンツを同期できませんでした(%2$d の競合)</string>
-  <string name="sync_foreign_files_forgotten_ticker">いくつかのローカルファイルが忘れられています</string>
-  <string name="sync_foreign_files_forgotten_content">%2$s ディレクトリ内の %1$d ファイルはコピーすることができませんでした</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="sync_foreign_files_forgotten_ticker">一部のローカルファイルが忘れられています</string>
+  <string name="sync_foreign_files_forgotten_content"> %2$s フォルダー内の %1$d ファイルはコピーできませんでした。</string>
+  <string name="sync_foreign_files_forgotten_explanation">バージョン 1.3.16以降、このデバイスからアップロードされたファイルは、単独のファイルが複数のアカウントと同期する際にデータの損失を防ぐため、ローカルの%1$sフォルダーにコピーされます。 この変更により、このアプリの以前のバージョンでアップロードされたすべてのファイルは%2$sフォルダーにコピーされます。しかしながら、アカウント同期中にはエラーが発生してこの操作が完了しないようになっています。ファイルをこのままにして%3$sへのリンクを削除するか、あるいは%1$sフォルダーにファイルを移動して%4$sへのリンクを維持することができます。 以下のリストにあるのは、ローカルのファイル及びそれらにリンクしている %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="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">アプリ開始時に毎回PINが要求されます。</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">メディアファイルをStock Media Playerでプレイ出来ません</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_err_unknown">メディアファイルをStock Media Playerで再生できません</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_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_testing_connection">接続をテスト中...</string>
-  <string name="auth_not_configured_title">サーバーの間違った設定</string>
-  <string name="auth_account_not_new">å\90\8cã\81\98ã\83¦ã\83¼ã\82¶ã\81¨ã\82µã\83¼ã\83\90のアカウントがデバイス上にすでに存在します</string>
-  <string name="auth_account_not_the_same">å\85¥å\8a\9bã\81\95ã\82\8cã\81\9fã\83¦ã\83¼ã\82¶ã\81¯ã\81\93ã\81®ã\82¢ã\82«ã\82¦ã\83³ã\83\88ã\81®ã\83¦ã\83¼ã\82と一致しません</string>
+  <string name="auth_not_configured_title">サーバー設定が間違っています</string>
+  <string name="auth_account_not_new">å\90\8cã\81\98ã\83¦ã\83¼ã\82¶ã\83¼ã\81¨ã\82µã\83¼ã\83\90ã\83¼のアカウントがデバイス上にすでに存在します</string>
+  <string name="auth_account_not_the_same">å\85¥å\8a\9bã\81\95ã\82\8cã\81\9fã\83¦ã\83¼ã\82¶ã\83¼ã\81¯ã\81\93ã\81®ã\82¢ã\82«ã\82¦ã\83³ã\83\88ã\81®ã\83¦ã\83¼ã\82¶ã\83¼と一致しません</string>
   <string name="auth_unknown_error_title">不明なエラーに発生しました</string>
   <string name="auth_unknown_host_title">ホストが見つかりませんでした</string>
-  <string name="auth_incorrect_path_title">ã\81®ã\82¤ã\83³ã\82¹ã\82¿ã\83³ã\82¹ã\81\8cè¦\8bã\81¤ã\81\8bã\82\8aã\81¾ã\81\9bã\82\93ã\81§ã\81\97ã\81\9f</string>
-  <string name="auth_timeout_title">サーバーからの反応がありません</string>
+  <string name="auth_incorrect_path_title">ã\82µã\83¼ã\83\90ã\83¼ã\81®ã\82¤ã\83³ã\82¹ã\82¿ã\83³ã\82¹ã\81\8cè¦\8bã\81¤ã\81\8bã\82\8aã\81¾ã\81\9bã\82\93</string>
+  <string name="auth_timeout_title">サーバーからの反応がありません</string>
   <string name="auth_incorrect_address_title">不明なURL形式</string>
   <string name="auth_ssl_general_error_title">SSLの初期化に失敗しました</string>
-  <string name="auth_ssl_unverified_server_title">SSL サーバ識別子を確認できませんでした</string>
-  <string name="auth_bad_oc_version_title">認識出来ないサーバのバージョンです</string>
+  <string name="auth_ssl_unverified_server_title">SSLサーバー識別子を確認できませんでした</string>
+  <string name="auth_bad_oc_version_title">認識できないサーバーのバージョンです</string>
   <string name="auth_wrong_connection_title">接続を確立できませんでした</string>
   <string name="auth_secure_connection">暗号化通信を確立しました</string>
   <string name="auth_unauthorized">間違ったユーザー名もしくはパスワード</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_connecting_auth_server">èª\8d証ã\82µã\83¼ã\83\90ã\83¼ã\81«æ\8e¥ç¶\9a中 ...</string>
+  <string name="auth_unsupported_auth_method">ã\82µã\83¼ã\83\90ã\83¼ã\81¯ã\81\93ã\81®èª\8d証æ\96¹å¼\8fã\82\92ã\82µã\83\9dã\83¼ã\83\88ã\81\97ã\81¦ã\81\84ã\81¾ã\81\9bã\82\93</string>
   <string name="auth_unsupported_multiaccount">%1$s は複数アカウントをサポートしていません</string>
+  <string name="auth_fail_get_user_name">サーバーが正しいユーザーIDを返しませんでした。管理者にご連絡ください。
+       </string>
+  <string name="auth_can_not_auth_against_server">このサーバーに対して認証できません</string>
   <string name="fd_keep_in_sync">ファイルを最新に保つ</string>
   <string name="common_rename">名前を変更</string>
   <string name="common_remove">削除</string>
-  <string name="confirmation_remove_alert">æ\9c¬å½\93ã\81« %1$s ã\82\92å\89\8aé\99¤ã\81\97ã\81¦ã\82\82ã\82\88ã\82\8dã\81\97ã\81\84ã\81§すか?</string>
+  <string name="confirmation_remove_alert">æ\9c¬å½\93ã\81« %1$s ã\82\92å\89\8aé\99¤ã\81\97ã\81¾すか?</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">ã\82µã\83¼ã\83\90ã\83¼ã\81\8bã\82\89å\89\8aé\99¤</string>
   <string name="confirmation_remove_remote_and_local">リモートとローカルの両方</string>
   <string name="remove_success_msg">削除に成功しました</string>
   <string name="remove_fail_msg">削除を完了できませんでした</string>
   <string name="rename_server_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="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_unexpected_bad_get_content">予期せぬ問題;他のアプリでファイルを選択してみてください。</string>
   <string name="filedisplay_no_file_selected">ファイルは選択されていません</string>
-  <string name="oauth_check_onoff">oAuth2 でログイン</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">- サーバ証明書は信頼されていません</string>
-  <string name="ssl_validator_reason_cert_expired">- サーバ証明書は有効期限切れです</string>
-  <string name="ssl_validator_reason_cert_not_yet_valid">- サーバ証明書は若すぎます</string>
+  <string name="ssl_validator_reason_cert_not_trusted">- サーバ証明書は信頼されていません</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">- URLは証明書内のホスト名と一致しません</string>
   <string name="ssl_validator_question">この証明書を信頼してもよろしいですか?</string>
   <string name="ssl_validator_not_saved">証明書は保存できませんでした</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">placeholder.txt</string>
   <string name="placeholder_filetype">PNG 画像</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_video_upload_on_wifi">WiFi経由でのみ動画をアップロード</string>
   <string name="instant_upload_path">/InstantUpload</string>
-  <string name="conflict_title">æ\9b´æ\96°ã\81®競合</string>
-  <string name="conflict_message">リモートファイル %s はローカルファイルと同期していません。続行すると、サーバ上のファイルを置き換えます。</string>
+  <string name="conflict_title">æ\9b´æ\96°ã\81\8c競合</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="actionbar_failed_instant_upload">インスタントアップロードに失敗」</string>
-  <string name="failed_upload_headline_text">インスタントアップロードに失敗</string>
-  <string name="failed_upload_headline_hint">全ての失敗したインスタントアップロードの要約</string>
-  <string name="failed_upload_all_cb">すべて選択</string>
-  <string name="failed_upload_headline_retryall_btn">すべての選択を再試行</string>
-  <string name="failed_upload_headline_delete_all_btn">アップロードキューからすべての選択を削除</string>
-  <string name="failed_upload_retry_text">画像のアップロードを再試行:</string>
-  <string name="failed_upload_load_more_images">更に画像を読み込む</string>
-  <string name="failed_upload_retry_do_nothing_text">オンラインでなく、インスタントアップロードのために何もしません</string>
-  <string name="failed_upload_failure_text">失敗メッセージ:</string>
-  <string name="failed_upload_quota_exceeded_text">サーバーの設定を確認してください。許容を超過している可能性があります。</string>
+  <string name="error__upload__local_file_not_copied">%1$s は、ローカルフォルダー %2$s  にコピーできませんでした。</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="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="actionbar_logger">ログ</string>
+  <string name="log_send_history_button">ログを送信</string>
+  <string name="log_mail_subject">ownCloud 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="file_list_empty_moving">ファイルが有りません。フォルダを追加してください。</string>
+  <string name="move_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_security">セキュリティ</string>
 </resources>
diff --git a/res/values-jv/strings.xml b/res/values-jv/strings.xml
new file mode 100644 (file)
index 0000000..084a4e3
--- /dev/null
@@ -0,0 +1,5 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<resources>
+  <string name="filedetails_download">Njipuk</string>
+  <string name="empty"></string>
+</resources>
index 56a17fa..43b1a45 100644 (file)
@@ -3,20 +3,18 @@
   <string name="actionbar_upload">ატვირთვა</string>
   <string name="actionbar_upload_from_apps">კონტენტი სხვა აპლიკაცისებიდან</string>
   <string name="actionbar_upload_files">ფაილები</string>
-  <string name="actionbar_mkdir">á\83\93á\83\98á\83 á\83\94á\83¥á\83¢á\83\9dá\83 á\83\98á\83\98á\83¡ á\83¨á\83\94á\83¥á\83\9bá\83\9cá\83\90</string>
+  <string name="actionbar_mkdir">á\83\90á\83®á\83\90á\83\9aá\83\98 á\83¤á\83\9dá\83\9aá\83\93á\83\94á\83 á\83\98</string>
   <string name="actionbar_settings">პარამეტრები</string>
+  <string name="actionbar_send_file">გაგზავნა</string>
   <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">აპლიკაციის PIN–ი</string>
   <string name="prefs_pincode_summary">თქვენი კლიენტის დაცვა</string>
-  <string name="prefs_instant_upload">ჩართე ეგრევე ატვირთვის ფუნქცია</string>
-  <string name="prefs_instant_upload_summary">კამერით გადაღებული ფოტოების ეგრევე ატვირთვა</string>
   <string name="prefs_help">დახმარება</string>
   <string name="prefs_feedback">უკუკავშირი</string>
   <string name="prefs_imprint">ბეჭედი</string>
-  <string name="auth_host_url">სერვერის მისამართი</string>
   <string name="auth_username">მომხმარებლის სახელი</string>
   <string name="auth_password">პაროლი</string>
   <string name="sync_string_files">ფაილები</string>
@@ -30,7 +28,7 @@
   <string name="uploader_wrn_no_content_text">კონტენტი არ იქნა მიღებული. არაფერია ასატვირთად.</string>
   <string name="uploader_error_forbidden_content">%1$s–ი არ დაიშვება გაზიარებული კონტენტის სანახავად</string>
   <string name="uploader_info_uploading">მიმდინარეობს ატვირთვა</string>
-  <string name="file_list_empty">á\83\90á\83\9b á\83¤á\83\9dá\83\9aá\83\93á\83\94á\83 á\83¨á\83\98 á\83¤á\83\90á\83\98á\83\9aá\83\94á\83\91á\83\98 á\83\90á\83  á\83\90á\83 á\83\98á\83¡.â\8f\8e\ná\83\90á\83®á\83\90á\83\9aá\83\98 á\83¤á\83\90á\83\98á\83\9aá\83\94á\83\91á\83\98 á\83¨á\83\94á\83\98á\83«á\83\9aá\83\94á\83\91á\83\90 á\83\93á\83\90á\83\94á\83\9bá\83\90á\83¢á\83\9dá\83¡ \"á\83\90á\83¢á\83\95á\83\98á\83 á\83\97á\83\95á\83\90\" á\83\9bá\83\94á\83\9cá\83\98á\83£á\83¡ á\83\9dá\83¤á\83ªá\83\98á\83\98á\83\97.</string>
+  <string name="file_list_empty">á\83\90á\83¥ á\83\90á\83 á\83\90á\83¤á\83\94á\83 á\83\98 á\83\90á\83  á\83\90á\83 á\83\98á\83¡. á\83\90á\83¢á\83\95á\83\98á\83 á\83\97á\83\94 á\83 á\83\90á\83\9bá\83\94!</string>
   <string name="filedetails_select_file">დააჭირეთ ფაილს დამატებითი ინფორმაციის გამოსაჩენად.</string>
   <string name="filedetails_size">ზომა:</string>
   <string name="filedetails_type">ტიპი:</string>
@@ -52,7 +50,7 @@
   <string name="delete_account">ანგარიშის წაშლა</string>
   <string name="create_account">ანგარიშის შექმნა</string>
   <string name="upload_chooser_title">ატვირთე აქედან...</string>
-  <string name="uploader_info_dirname">á\83\93á\83\98á\83 á\83\94á\83¥á\83¢á\83\9dá\83 á\83\98ის სახელი</string>
+  <string name="uploader_info_dirname">á\83¤á\83\9dá\83\9aá\83\93á\83\94á\83 ის სახელი</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="sync_fail_in_favourites_ticker">Kept-in-sync ფაილები ვერ მოხერხდა</string>
   <string name="sync_fail_in_favourites_content">%1$d ფაილების კონტენტის სინქრონიზაცია ვერ მოხერხდა  (%2$d კონფლიქტი)</string>
   <string name="sync_foreign_files_forgotten_ticker">რამოდენიმე ლოკალური ფაილი დაკარგულია</string>
-  <string name="sync_foreign_files_forgotten_content">%1$d ფაილები არ არის %2$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">გთხოვთ, ჩასვათ თქვენი აპლიკაციის PIN–ი</string>
   <string name="pincode_configure_your_pin">შეიყვანეთ თქვენი აპლიკაციის PIN–ი</string>
   <string name="pincode_configure_your_pin_explanation">PIN–ი მოთხოვნილი იქნება აპლიკაციის ყოველ ჩართვაზე</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="rename_server_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="wait_a_moment">გთხოვთ მოითმინოთ</string>
   <string name="filedisplay_unexpected_bad_get_content">მოულოდნელი პრობლემა: გთხოვთ აირჩიოთ ფაილი სხვადასხვა აპლიკაციიდან</string>
   <string name="filedisplay_no_file_selected">ფაილი არ ყოფილა მონიშნული</string>
   <string name="conflict_keep_both">დატოვე ორივე</string>
   <string name="conflict_overwrite">გადააწერე</string>
   <string name="conflict_dont_upload">არ ატვირთო</string>
-  <string name="error__upload__local_file_not_copied">%1$s–ის კოპირება ვერ მოხერხდა %2$s  ლოკალურ დირექტორიაში</string>
+  <string name="activity_chooser_send_file_title">გაგზავნა</string>
+  <string name="clipboard_text_copied">კოპირებულია კლიპბორდში</string>
+  <string name="empty"></string>
+  <string name="prefs_category_accounts">ანგარიში</string>
+  <string name="move_choose_button_text">არჩევა</string>
+  <string name="prefs_category_security">უსაფრთხოება</string>
 </resources>
index c757504..752985c 100644 (file)
@@ -1,2 +1,87 @@
 <?xml version='1.0' encoding='UTF-8'?>
-<resources/>
+<resources>
+  <string name="actionbar_upload">ផ្ទុក​ឡើង</string>
+  <string name="actionbar_upload_files">ឯកសារ</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="prefs_category_general">ទូទៅ</string>
+  <string name="prefs_category_more">ច្រើន​ទៀត</string>
+  <string name="prefs_accounts">គណនី</string>
+  <string name="prefs_manage_accounts">គ្រប់គ្រង​គណនី</string>
+  <string name="prefs_help">ជំនួយ</string>
+  <string name="auth_username">ឈ្មោះ​អ្នកប្រើ</string>
+  <string name="auth_password">ពាក្យសម្ងាត់</string>
+  <string name="sync_string_files">ឯកសារ</string>
+  <string name="setup_btn_connect">ភ្ជាប់</string>
+  <string name="uploader_btn_upload_text">ផ្ទុក​ឡើង</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">ចាក់ចេញ</string>
+  <string name="uploader_info_uploading">កំពុង​ផ្ទុក​ឡើង</string>
+  <string name="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_download">ទាញយក</string>
+  <string name="common_yes">ព្រម</string>
+  <string name="common_no">ទេ</string>
+  <string name="common_ok">OK</string>
+  <string name="common_cancel_download">បោះបង់ការទាញយក</string>
+  <string name="common_cancel_upload">បោះបង់​ការ​ផ្ទុកឡើង</string>
+  <string name="common_cancel">លើកលែង</string>
+  <string name="common_save_exit">រក្សាទុក &amp; ចាកចេញ</string>
+  <string name="common_error">កំហុស</string>
+  <string name="common_loading">កំពុងដំណើរការ</string>
+  <string name="common_error_unknown">មិន​ស្គាល់​កំហុស</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_succeeded_ticker">ការផ្ទុកឡើងបាន​ជោគជ័យ</string>
+  <string name="uploader_upload_failed_ticker">ការផ្ទុកឡើងបាន​បរាជ័យ</string>
+  <string name="downloader_download_in_progress_ticker">កំពុង​ធ្វើការទាញយក...</string>
+  <string name="downloader_download_succeeded_ticker">ការទាញយក​បានជោគជ័យ</string>
+  <string name="downloader_download_failed_ticker">ការទាញយក​បានបរាជ័យ</string>
+  <string name="common_choose_account">ជ្រើស​គណនី</string>
+  <string name="foreign_files_move">ផ្លាស់ទីទាំងអស់</string>
+  <string name="pincode_enter_pin_code">សូម ដាក់​បញ្ចូល App PIN របស់អ្នក</string>
+  <string name="pincode_configure_your_pin">បញ្ចូល App PIN របស់អ្នក</string>
+  <string name="pincode_reenter_your_pincode">សូម បញ្ចូល App PIN របស់អ្នក​ម្តង​ទៀត</string>
+  <string name="pincode_remove_your_pincode">លុប App PIN របស់​អ្នក</string>
+  <string name="pincode_mismatch">App PIN ទាំងនេះ​មិនដូចគ្នាទេ</string>
+  <string name="pincode_wrong">App PIN មិន​ត្រឹម​ត្រូវទេ</string>
+  <string name="pincode_removed">App PIN បាន​លុបចេញហើយ</string>
+  <string name="pincode_stored">App PIN បាន​យក​មកវិញ</string>
+  <string name="auth_trying_to_login">កំពុង​​តែ​ព្យាយាម​ដើម្បី​ចូល...</string>
+  <string name="auth_no_net_conn_title">គ្មានបណ្តាញ​តភ្ជាប់ទេ</string>
+  <string name="auth_testing_connection">ការតភ្ជាប់កំពុង​តែធ្វើតេស្ត...</string>
+  <string name="auth_unknown_error_title">មិនស្គាល់កំហុសបានកើតឡើង!</string>
+  <string name="fd_keep_in_sync">រក្សាឯកសាររហូតដល់កាលបរិច្ឆេទ</string>
+  <string name="common_rename">ប្ដូរ​ឈ្មោះ</string>
+  <string name="common_remove">ដកចេញ</string>
+  <string name="remove_success_msg">ការដកយកចេញបានជោគជ័យ</string>
+  <string name="remove_fail_msg">ការដកយកចេញបានបរាជ័យ</string>
+  <string name="rename_dialog_title">បញ្ចូលឈ្មោះថ្មី</string>
+  <string name="ssl_validator_btn_details_see">ព័ត៌មាន​លម្អិត</string>
+  <string name="ssl_validator_btn_details_hide">លាក់​បាំង</string>
+  <string name="ssl_validator_label_C">ប្រទេសៈ</string>
+  <string name="ssl_validator_label_ST">រដ្ឋៈ</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="activity_chooser_send_file_title">ផ្ញើ</string>
+  <string name="empty"></string>
+  <string name="prefs_category_accounts">គណនី</string>
+  <string name="saml_authentication_wrong_pass">ខុស​ពាក្យ​សម្ងាត់</string>
+  <string name="move_choose_button_text">ជ្រើស</string>
+  <string name="prefs_category_security">សុវត្ថិភាព</string>
+</resources>
index c757504..56e55a1 100644 (file)
@@ -1,2 +1,4 @@
 <?xml version='1.0' encoding='UTF-8'?>
-<resources/>
+<resources>
+  <string name="empty"></string>
+</resources>
index 8ac5cc9..4a0df83 100644 (file)
@@ -7,17 +7,16 @@
   <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_mkdir">새 폴더</string>
   <string name="actionbar_settings">설정</string>
   <string name="actionbar_see_details">세부내용</string>
+  <string name="actionbar_send_file">보내기</string>
   <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_log_title">로깅 허용</string>
   <string name="prefs_log_summary">이건 로그 문제에 사용됩니다</string>
   <string name="prefs_log_title_history">로그 기록</string>
   <string name="prefs_imprint">임프린트</string>
   <string name="recommend_subject">%1$s 을 스마트폰에서 사용해보세요!</string>
   <string name="auth_check_server">서버 확인</string>
-  <string name="auth_host_url">서버 주소</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="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>
@@ -45,7 +43,7 @@
   <string name="uploader_wrn_no_content_text">받은 콘텐츠가 없습니다. 업로드할 항목이 없습니다.</string>
   <string name="uploader_error_forbidden_content">%1$s에서 공유된 콘텐츠에 접근할 수 없습니다</string>
   <string name="uploader_info_uploading">업로드 중</string>
-  <string name="file_list_empty">이 폴더에 파일이 없습니다.\n메뉴 옵션의 \"업로드\" 항목을 사용하여 새 파일을 업로드할 수 있습니다.</string>
+  <string name="file_list_empty">내용이 없습니다. 업로드할 수 있습니다!</string>
   <string name="filedetails_select_file">파일을 누르면 추가 정보가 표시됩니다.</string>
   <string name="filedetails_size">크기:</string>
   <string name="filedetails_type">종류:</string>
@@ -54,6 +52,7 @@
   <string name="filedetails_download">다운로드</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="common_yes">예</string>
   <string name="common_no">아니요</string>
   <string name="common_ok">확인</string>
@@ -69,7 +68,7 @@
   <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_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="sync_fail_in_favourites_ticker">파일을 동기화할 수 없었습니다</string>
   <string name="sync_fail_in_favourites_content">파일 %1$d개의 내용을 동기화할 수 없었습니다 (충돌 %2$d개)</string>
   <string name="sync_foreign_files_forgotten_ticker">몇몇 로컬 파일이 사라졌습니다.</string>
-  <string name="sync_foreign_files_forgotten_content">%1$d 파일을 %2$s 디렉토리에 복사하지 못하였습니다.</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로 링크된 리모트 파일들의 목록이 있습니다.\n</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="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="auth_connection_established">연결됨</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="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="rename_server_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="wait_a_moment">잠시 기다려 주십시오</string>
   <string name="filedisplay_unexpected_bad_get_content">예상하지 못한 오류입니다. 다른 앱에서 파일을 선택하십시오</string>
   <string name="filedisplay_no_file_selected">선택한 파일 없음</string>
   <string name="ssl_validator_label_signature_algorithm">알고리즘:</string>
   <string name="placeholder_sentence">이것은 플레이스홀더입니다</string>
   <string name="placeholder_filename">placeholder.txt</string>
-  <string name="placeholder_filetype">PNG í\8c\8cì\9d¼</string>
+  <string name="placeholder_filetype">PNG ê·¸ë¦¼</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="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="actionbar_failed_instant_upload">자동 업로드가 실패했습니다\"</string>
-  <string name="failed_upload_headline_text">자동 업로드 실패함</string>
-  <string name="failed_upload_headline_hint">실패된 자동 업로드 전체 요약</string>
-  <string name="failed_upload_all_cb">전체 선택</string>
-  <string name="failed_upload_headline_retryall_btn">전체 선택 재시도</string>
-  <string name="failed_upload_headline_delete_all_btn">선택된 업로드 큐 전체 삭제</string>
-  <string name="failed_upload_retry_text">이미지 업로드 재시도:</string>
-  <string name="failed_upload_load_more_images">더 많은 사진 불러오기</string>
-  <string name="failed_upload_failure_text">실패 메시지:</string>
-  <string name="failed_upload_quota_exceeded_text">서버 설정을 확인해주세요, 아마 업로드 제한을 초과하셨을겁니다.</string>
+  <string name="activity_chooser_send_file_title">보내기</string>
+  <string name="copy_link">링크 복사</string>
+  <string name="clipboard_text_copied">클립보드로 복사됨</string>
+  <string name="empty"></string>
+  <string name="prefs_category_accounts">계정</string>
+  <string name="saml_authentication_required_text">인증 필요함</string>
+  <string name="saml_authentication_wrong_pass">잘못된 암호</string>
+  <string name="move_choose_button_text">선택</string>
+  <string name="prefs_category_security">보안</string>
 </resources>
index c40ddc5..2e843f2 100644 (file)
@@ -1,12 +1,32 @@
 <?xml version='1.0' encoding='UTF-8'?>
 <resources>
   <string name="actionbar_upload">بارکردن</string>
+  <string name="actionbar_upload_files">په‌ڕگەکان</string>
   <string name="actionbar_settings">ده‌ستكاری</string>
+  <string name="prefs_category_general">گشتی</string>
+  <string name="prefs_accounts">هەژمارەکان</string>
   <string name="prefs_help">یارمەتی</string>
-  <string name="auth_host_url">ناونیشانی ڕاژه</string>
   <string name="auth_username">ناوی به‌کارهێنه‌ر</string>
   <string name="auth_password">وشەی تێپەربو</string>
+  <string name="sync_string_files">په‌ڕگەکان</string>
+  <string name="setup_btn_connect">بەستنەوە</string>
   <string name="uploader_btn_upload_text">بارکردن</string>
+  <string name="uploader_wrn_no_account_title">هیچ هەژمارێک نه‌دۆزرایه‌وه‌</string>
+  <string name="uploader_wrn_no_account_setup_btn_text">جێگیرکردن</string>
+  <string name="uploader_wrn_no_account_quit_btn_text">دەرچوون</string>
+  <string name="uploader_info_uploading">بارکردن</string>
+  <string name="filedetails_size">قەبارە:</string>
+  <string name="filedetails_type">جۆر:</string>
+  <string name="filedetails_created">درووستبووە:</string>
+  <string name="filedetails_modified">گۆردراو:</string>
   <string name="filedetails_download">داگرتن</string>
+  <string name="common_yes">بەڵێ</string>
+  <string name="common_no">نەخێر</string>
+  <string name="common_ok">باشە</string>
+  <string name="common_cancel">لابردن</string>
+  <string name="common_save_exit">پاشکەوتکردن &amp; دەرچوون</string>
   <string name="common_error">هه‌ڵه</string>
+  <string name="uploader_info_dirname">ناوی بوخچه</string>
+  <string name="empty"></string>
+  <string name="prefs_category_accounts">هەژمارەکان</string>
 </resources>
index f7a0fe6..19b003e 100644 (file)
@@ -4,16 +4,15 @@
   <string name="actionbar_upload">Eroplueden</string>
   <string name="actionbar_upload_files">Dateien</string>
   <string name="actionbar_open_with">Opmaachen mat</string>
-  <string name="actionbar_mkdir">Dossier erstellen</string>
   <string name="actionbar_settings">Astellungen</string>
   <string name="actionbar_see_details">Detailer</string>
+  <string name="actionbar_send_file">Schécken</string>
   <string name="prefs_category_general">Allgemeng</string>
   <string name="prefs_category_more">Méi</string>
   <string name="prefs_accounts">Accounten</string>
   <string name="prefs_pincode">App PIN</string>
   <string name="prefs_help">Hëllef</string>
   <string name="prefs_feedback">Feedback</string>
-  <string name="auth_host_url">Server Adress</string>
   <string name="auth_username">Benotzernumm</string>
   <string name="auth_password">Passwuert</string>
   <string name="sync_string_files">Dateien</string>
   <string name="uploader_wrn_no_account_setup_btn_text">Setup</string>
   <string name="uploader_wrn_no_account_quit_btn_text">Erausgoen</string>
   <string name="uploader_info_uploading">Eroplueden</string>
+  <string name="file_list_empty">Hei ass näischt. Lued eppes rop!</string>
   <string name="filedetails_size">Gréisst:</string>
   <string name="filedetails_type">Typ:</string>
   <string name="filedetails_created">Erstallt:</string>
   <string name="filedetails_modified">Geännert:</string>
   <string name="filedetails_download">Download</string>
+  <string name="action_share_file">Link deelen</string>
   <string name="common_yes">Jo</string>
   <string name="common_no">Nee</string>
   <string name="common_ok">OK</string>
@@ -40,7 +41,7 @@
   <string name="change_password">Passwuert änneren</string>
   <string name="delete_account">Account läschen</string>
   <string name="create_account">Account erstellen</string>
-  <string name="uploader_info_dirname">Dossier\'s Numm</string>
+  <string name="uploader_info_dirname">Dossiers Numm:</string>
   <string name="uploader_upload_in_progress_ticker">Gett eropgelueden ...</string>
   <string name="uploader_upload_succeeded_ticker">Eroplueden färdeg</string>
   <string name="uploader_upload_failed_ticker">Eroplueden huet net geklappt</string>
@@ -80,6 +81,8 @@
   <string name="conflict_keep_both">Béid halen</string>
   <string name="conflict_overwrite">Iwwerschreiwen</string>
   <string name="conflict_dont_upload">Net eroplueden</string>
-  <string name="failed_upload_all_cb">all auswielen</string>
-  <string name="failed_upload_failure_text">Fehler Message:</string>
+  <string name="activity_chooser_send_file_title">Schécken</string>
+  <string name="empty"></string>
+  <string name="prefs_category_accounts">Accounten</string>
+  <string name="move_choose_button_text">Auswielen</string>
 </resources>
index ad28304..70bc85d 100644 (file)
@@ -7,17 +7,20 @@
   <string name="actionbar_upload_from_apps">Turinys iš kitų programų</string>
   <string name="actionbar_upload_files">Failai</string>
   <string name="actionbar_open_with">Atverti naudojant</string>
-  <string name="actionbar_mkdir">Kurti aplanką</string>
+  <string name="actionbar_mkdir">Naujas aplankas</string>
   <string name="actionbar_settings">Nustatymai</string>
   <string name="actionbar_see_details">Informacija</string>
+  <string name="actionbar_send_file">Siųsti</string>
   <string name="prefs_category_general">Bendras</string>
   <string name="prefs_category_more">Daugiau</string>
   <string name="prefs_accounts">Paskyros</string>
   <string name="prefs_manage_accounts">Tvarkyti paskyras</string>
   <string name="prefs_pincode">App programos PIN kodas</string>
   <string name="prefs_pincode_summary">Apsaugokite savo klientą</string>
-  <string name="prefs_instant_upload">Įjungti momentinius įkėlimus</string>
+  <string name="prefs_instant_upload">Momentiniai nuotraukų įkėlimai</string>
   <string name="prefs_instant_upload_summary">Iš karto nusiųsti nufotografuotas nuotraukas</string>
+  <string name="prefs_instant_video_upload">Momentiniai video įkėlimai</string>
+  <string name="prefs_instant_video_upload_summary">Iš karto nusiųsti sukurtus video failus</string>
   <string name="prefs_log_title">Įjungti žurnalo rašymą</string>
   <string name="prefs_log_summary">Tai naudojama problemų žurnalo vedimui</string>
   <string name="prefs_log_title_history">Žurnalų istorija</string>
   <string name="prefs_feedback">Atsiliepimai</string>
   <string name="prefs_imprint">Imprint</string>
   <string name="recommend_subject">Išbandykite %1$s savo išmaniajame telefone!</string>
-  <string name="recommend_text">Siūlau pabandyti %1$s savo išmaniajame telefone!\nParsisiųskite štai čia: %2$s</string>
   <string name="auth_check_server">Patikrinti Serverį</string>
-  <string name="auth_host_url">Serverio adresas</string>
+  <string name="auth_host_url">Serverio adresas </string>
   <string name="auth_username">Prisijungimo vardas</string>
   <string name="auth_password">Slaptažodis</string>
+  <string name="auth_register">Naujas į %1$s?</string>
   <string name="sync_string_files">Failai</string>
   <string name="setup_btn_connect">Prisijungti</string>
   <string name="uploader_btn_upload_text">Įkelti</string>
-  <string name="uploader_top_message">Nustatyti įkėlimų katalogą.</string>
+  <string name="uploader_top_message">Nustatyti įkėlimų aplanką:</string>
   <string name="uploader_wrn_no_account_title">Paskyrų nerasta</string>
   <string name="uploader_wrn_no_account_text">Jūsų įrenginyje nėra nė vienos %1$s paskyros. Prašome pirmiausia susikurti paskyrą.</string>
   <string name="uploader_wrn_no_account_setup_btn_text">Nustatymai</string>
@@ -45,7 +48,9 @@
   <string name="uploader_wrn_no_content_text">nebuvo gauta turinio. Nėra įkeltino turinio</string>
   <string name="uploader_error_forbidden_content">%1$s neleidžiama prieiti prie turinio, kuriuo dalijamasi</string>
   <string name="uploader_info_uploading">Išsiunčiama</string>
-  <string name="file_list_empty">Šiame aplanke failų nėra.\nNauji failai gali būti pridėti naudojant \"Įkelti\" funkciją meniu.</string>
+  <string name="file_list_empty">Čia tuščia. Įkelkite ką nors!</string>
+  <string name="file_list_loading">Įkeliama ...</string>
+  <string name="local_file_list_empty">Šiame aplanke nėra failų.</string>
   <string name="filedetails_select_file">Palieskite failą, kad parodyti papildomą informaciją.</string>
   <string name="filedetails_size">Dydis:</string>
   <string name="filedetails_type">Tipas:</string>
@@ -54,6 +59,8 @@
   <string name="filedetails_download">Atsisiųsti</string>
   <string name="filedetails_sync_file">Atnaujinti failą</string>
   <string name="filedetails_renamed_in_upload_msg">Įkėlimo metu failas buvo pervadintas į %1$s</string>
+  <string name="action_share_file">Dalintis nuoroda</string>
+  <string name="action_unshare_file">Nebesidalinti nuoroda</string>
   <string name="common_yes">Taip</string>
   <string name="common_no">Ne</string>
   <string name="common_ok">Gerai</string>
   <string name="delete_account">Ištrinti paskyrą</string>
   <string name="create_account">Sukurti paskyrą</string>
   <string name="upload_chooser_title">Įkelti iš ...</string>
-  <string name="uploader_info_dirname">Aplanko pavadinimas</string>
+  <string name="uploader_info_dirname">Katalogo pavadinimas</string>
   <string name="uploader_upload_in_progress_ticker">Įkeliama ...</string>
   <string name="uploader_upload_in_progress_content">%1$d%% Siunčiama %2$s</string>
   <string name="uploader_upload_succeeded_ticker">Nusiuntimas pavyko</string>
   <string name="uploader_upload_succeeded_content_single">%1$s buvo sėkmingai nusiųstas</string>
   <string name="uploader_upload_failed_ticker">Nusiuntimas nepavyko</string>
   <string name="uploader_upload_failed_content_single">Nepavyko baigti %1$s nusiuntimo</string>
+  <string name="uploader_upload_failed_credentials_error">Įkėlimas nepavyko, Jums reikia prisijungti pakartotinai</string>
   <string name="downloader_download_in_progress_ticker">Atsiunčiama...</string>
   <string name="downloader_download_in_progress_content">%1$d%% Atsiunčiama %2$s</string>
   <string name="downloader_download_succeeded_ticker">Atsiuntimas pavyko</string>
   <string name="downloader_download_failed_ticker">Atsiuntimas nepavyko</string>
   <string name="downloader_download_failed_content">Nepavyko baigti %1$s atsiuntimo</string>
   <string name="downloader_not_downloaded_yet">Dar neatsiųsta</string>
+  <string name="downloader_download_failed_credentials_error">Atsisiuntimas nepavyko, Jums reikia prisijungti pakartotinai</string>
   <string name="common_choose_account">Pasirinkite paskyrą</string>
   <string name="sync_fail_ticker">Sinchronizacija nepavyko</string>
+  <string name="sync_fail_ticker_unauthorized">Sinchronizacija nepavyko. Jums reikia prisijungti iš naujo</string>
   <string name="sync_fail_content">%1$s sinchronizacija nepavyko</string>
   <string name="sync_fail_content_unauthorized">Netinkamas slaptažodis %1$s</string>
   <string name="sync_conflicts_in_favourites_ticker">Rastas konfliktas</string>
   <string name="media_event_done">%1$s sąrašas baigtas</string>
   <string name="media_err_nothing_to_play">Nerasta medija failų</string>
   <string name="media_err_no_account">Nenurodyta paskyra</string>
+  <string name="media_err_not_in_owncloud">Failas yra netinkamoje sąskaitoje</string>
   <string name="media_err_unsupported">Nepalaikomas kodekas</string>
   <string name="media_err_io">Nenuskaitomas medijos failas</string>
   <string name="media_err_malformed">Netinkamai užkoduotas medijos failas</string>
   <string name="media_err_security_ex">Saugumo klaida bandant paleisti %1$s</string>
   <string name="media_err_io_ex">Įvesties klaida bandant paleisti %1$s</string>
   <string name="media_err_unexpected">Netikėta klaida bandant paleisti %1$s</string>
+  <string name="media_rewind_description">Atsukimo mygtukas</string>
   <string name="media_play_pause_description">Grojimo arba pauzės mygtukas</string>
+  <string name="media_forward_description">Prasukimo mygtukas</string>
+  <string name="auth_getting_authorization">Gaunama autorizaciją...</string>
   <string name="auth_trying_to_login">Bandoma prisijungti...</string>
   <string name="auth_no_net_conn_title">Nėra tinklo ryšio</string>
   <string name="auth_nossl_plain_ok_title">Saugus prisijungimas negalimas.</string>
   <string name="auth_connecting_auth_server">Jungiamasi prie autentikacijos serverio...</string>
   <string name="auth_unsupported_auth_method">Serveris nepalaiko šio autentikacijos metodo</string>
   <string name="auth_unsupported_multiaccount">%1$s nepalaiko kelių paskyrų iš karto</string>
+  <string name="auth_can_not_auth_against_server">Jungiamasi prie autentikacijos serverio...</string>
   <string name="fd_keep_in_sync">Laikyti failą naujinamą</string>
   <string name="common_rename">Pervadinti</string>
   <string name="common_remove">Pašalinti</string>
-  <string name="confirmation_remove_alert">Ar tikrai norite pašalinti %1$s ?</string>
+  <string name="confirmation_remove_alert">Ar tikrai norite pašalinti %1$s?</string>
   <string name="confirmation_remove_folder_alert">Ar tikrai norite pašalinti %1$s ir ten esantį turinį?</string>
   <string name="confirmation_remove_local">Tik vietiniai</string>
   <string name="confirmation_remove_folder_local">Tik vietinis turinys</string>
   <string name="sync_file_fail_msg">Nutolę failai negalėjo būti patikrinti</string>
   <string name="sync_file_nothing_to_do_msg">Failo turinys jau sunchronizuotas</string>
   <string name="create_dir_fail_msg">Aplanko sukurti nepavyko</string>
+  <string name="filename_forbidden_characters">Neleistini simboliai: / \\ &lt; &gt; : \" | ? *</string>
+  <string name="filename_empty">Failo pavadinimas negali būti tuščias</string>
   <string name="wait_a_moment">Truputį palaukite</string>
   <string name="filedisplay_unexpected_bad_get_content">Netikėta problema ; prašome pasirinkti failą iš kitos programėlės</string>
   <string name="filedisplay_no_file_selected">Joks failas nebuvo pasirinktas</string>
+  <string name="activity_chooser_title">Siųsti nuorodą asmeniui ...</string>
   <string name="oauth_check_onoff">Prisijungti naudojant oAuth2</string>
   <string name="oauth_login_connection">Jungiamasi prie oAuth2 serverio...</string>
   <string name="ssl_validator_header">Serverio tapatybė negali būti patikrinta</string>
   <string name="ssl_validator_label_validity_to">Iki:</string>
   <string name="ssl_validator_label_signature">Parašas:</string>
   <string name="ssl_validator_label_signature_algorithm">Algoritmas:</string>
+  <string name="ssl_validator_null_cert">Sertifikatas negali būti parodytas.</string>
+  <string name="ssl_validator_no_info_about_error">- Nėra informacijos apie klaidą</string>
   <string name="placeholder_filetype">PNG paveikslėlis</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">Įkelti nuotraukas tik kai prisijungiama per WiFi</string>
+  <string name="instant_video_upload_on_wifi">Įkelti video tik per WiFi</string>
   <string name="conflict_title">Atnaujinimo konfliktas</string>
   <string name="conflict_message">Nutolęs failas %s nėra sinchronizuotas su vietiniu failu. Jei tęsite, failas serveryje bus pakeistas.</string>
   <string name="conflict_keep_both">Palikti abu</string>
   <string name="conflict_overwrite">Perrašyti</string>
   <string name="conflict_dont_upload">Nebesiųsti</string>
   <string name="preview_image_description">Paveikslėlio peržiūra</string>
-  <string name="preview_image_error_unknown_format">Neįmanoma parodyti paveikslėlio</string>
-  <string name="failed_upload_all_cb">pažymėti viską</string>
-  <string name="failed_upload_retry_text">bandyti iš naujo nusiųsti paveikslėlį:</string>
-  <string name="failed_upload_load_more_images">Įkelti daugiau Nuotraukų</string>
-  <string name="failed_upload_failure_text">Klaidos pranešimas:</string>
-  <string name="failed_upload_quota_exceeded_text">Patikrinkite savo serverio nustatymus, tikėtina jog viršijote savo limitą.</string>
+  <string name="preview_image_error_unknown_format">Neįmanoma parodyti šio paveikslėlio</string>
+  <string name="share_link_file_error">Įvyko klaida bandant dalinti šį failą ar aplanką</string>
+  <string name="unshare_link_file_error">Įvyko klaida bandant nebedalinti šio failu ar aplanku</string>
+  <string name="activity_chooser_send_file_title">Siųsti</string>
+  <string name="copy_link">Kopijuoti nuorodą</string>
+  <string name="clipboard_text_copied">Nukopijuota į talpyklę</string>
+  <string name="empty"></string>
+  <string name="prefs_category_accounts">Paskyros</string>
+  <string name="saml_authentication_wrong_pass">Neteisingas slaptažodis</string>
+  <string name="move_choose_button_text">Pasirinkite</string>
+  <string name="prefs_category_security">Saugumas</string>
 </resources>
index 37eb6b9..88df829 100644 (file)
@@ -3,18 +3,16 @@
   <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_mkdir">Izveidot direktoriju</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="prefs_category_general">Vispārīgi</string>
   <string name="prefs_category_more">Vairāk</string>
   <string name="prefs_accounts">Konti</string>
   <string name="prefs_manage_accounts">Pārvaldīt kontus</string>
   <string name="prefs_pincode">Lietotnes PIN</string>
   <string name="prefs_pincode_summary">Aizsargā savu klientu</string>
-  <string name="prefs_instant_upload">Aktivēt tūlītējo augšupielādēšanu</string>
-  <string name="prefs_instant_upload_summary">Nekavējoties augšupielādēt kameras uzņemtos attēlus</string>
   <string name="prefs_help">Palīdzība</string>
-  <string name="auth_host_url">Servera adrese</string>
   <string name="auth_username">Lietotājvārds</string>
   <string name="auth_password">Parole</string>
   <string name="sync_string_files">Datnes</string>
@@ -28,7 +26,7 @@
   <string name="uploader_wrn_no_content_text">Nav saņemts nekāds saturs. Nav ko augšupielādēt.</string>
   <string name="uploader_error_forbidden_content">%1$s nedrīkst piekļūt koplietotajam saturam</string>
   <string name="uploader_info_uploading">Augšupielādē</string>
-  <string name="file_list_empty">Šajā mapē nav datņu.\nJaunas datnes var pievienot ar izvēlnes opciju “Augšupielādēt”</string>
+  <string name="file_list_empty">Te vēl nekas nav. Rīkojies, sāc augšupielādēt!</string>
   <string name="filedetails_select_file">Uzsitiet uz datnes, lai redzētu papildinformāciju.</string>
   <string name="filedetails_size">Izmērs:</string>
   <string name="filedetails_type">Tips:</string>
   <string name="common_cancel">Atcelt</string>
   <string name="common_save_exit">Saglabāt un iziet</string>
   <string name="common_error">Kļūda</string>
+  <string name="common_loading">Ielādē</string>
+  <string name="common_error_unknown">Nezināma kļūda</string>
   <string name="about_title">Par</string>
   <string name="change_password">Mainīt paroli</string>
   <string name="delete_account">Dzēst kontu</string>
   <string name="create_account">Izveidot kontu</string>
   <string name="upload_chooser_title">Augšupielādēt no...</string>
-  <string name="uploader_info_dirname">Direktorijas nosaukums</string>
+  <string name="uploader_info_dirname">Mapes nosaukums</string>
   <string name="uploader_upload_in_progress_ticker">Augšupielādē ...</string>
   <string name="uploader_upload_in_progress_content">%1$d%% augšupielādē %2$s</string>
   <string name="uploader_upload_succeeded_ticker">Augšupielāde ir veiksmīga</string>
   <string name="pincode_wrong">Nepareizs lietotnes PIN</string>
   <string name="pincode_removed">Lietotnes PIN ir izņemts</string>
   <string name="pincode_stored">Lietotnes PIN ir noglabāts</string>
+  <string name="auth_trying_to_login">Mēģina ierakstīties...</string>
   <string name="auth_no_net_conn_title">Nav tīkla savienojumu</string>
   <string name="auth_nossl_plain_ok_title">Nav pieejams drošs savienojums.</string>
   <string name="auth_connection_established">Savienojums ir izveidots</string>
+  <string name="auth_testing_connection">Testē savienojumu...</string>
   <string name="auth_not_configured_title">Slikti formatēta servera konfigurācija</string>
   <string name="auth_unknown_error_title">Gadījās nezināma kļūda!</string>
   <string name="auth_unknown_host_title">Nevarēja atrast datoru</string>
@@ -94,8 +96,6 @@
   <string name="fd_keep_in_sync">Uzturēt datni aktuālu</string>
   <string name="common_rename">Pārsaukt</string>
   <string name="common_remove">Izņemt</string>
-  <string name="confirmation_remove_alert">Vai tiešām vēlaties izņemt %1$s?</string>
-  <string name="confirmation_remove_folder_alert">Vai vēlaties izņemt %1$s un tā saturu?</string>
   <string name="confirmation_remove_local">Tikai lokālos</string>
   <string name="confirmation_remove_folder_local">Tikai lokālo saturu</string>
   <string name="confirmation_remove_remote">Izņemt no servera</string>
   <string name="rename_server_fail_msg">Nevarēja pabeigt pārsaukšanu</string>
   <string name="sync_file_fail_msg">Nevarēja atzīmēt attālinātas datnes</string>
   <string name="sync_file_nothing_to_do_msg">Datnes saturs jau ir sinhronizēts</string>
-  <string name="create_dir_fail_msg">Nevarēja izveidot direktoriju</string>
   <string name="wait_a_moment">Uzgaidīt brīdi</string>
   <string name="filedisplay_unexpected_bad_get_content">Negaidīta problēma; lūdzu, izvēlieties datni no citas lietotnes</string>
   <string name="filedisplay_no_file_selected">Netika izvēlēta neviena datne</string>
   <string name="conflict_keep_both">Paturēt abas</string>
   <string name="conflict_overwrite">Pārrakstīt</string>
   <string name="conflict_dont_upload">Neaugšupielādēt</string>
+  <string name="activity_chooser_send_file_title">Sūtīt</string>
+  <string name="empty"></string>
+  <string name="prefs_category_accounts">Konti</string>
+  <string name="move_choose_button_text">Izvēlieties</string>
+  <string name="prefs_category_security">Drošība</string>
 </resources>
diff --git a/res/values-mg/strings.xml b/res/values-mg/strings.xml
new file mode 100644 (file)
index 0000000..56e55a1
--- /dev/null
@@ -0,0 +1,4 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<resources>
+  <string name="empty"></string>
+</resources>
index 720e4da..e7b4906 100644 (file)
@@ -3,9 +3,10 @@
   <string name="actionbar_upload">Подигни</string>
   <string name="actionbar_upload_files">Датотеки</string>
   <string name="actionbar_open_with">Отвори со</string>
-  <string name="actionbar_mkdir">Создади папка</string>
+  <string name="actionbar_mkdir">Ð\9dова папка</string>
   <string name="actionbar_settings">Параметри</string>
   <string name="actionbar_see_details">Детали:</string>
+  <string name="actionbar_send_file">Прати</string>
   <string name="prefs_category_general">Општо</string>
   <string name="prefs_category_more">Повеќе</string>
   <string name="prefs_accounts">Сметки</string>
@@ -16,7 +17,7 @@
   <string name="prefs_help">Помош</string>
   <string name="prefs_recommend">Препорачај на пријател</string>
   <string name="prefs_feedback">Повратен одговор</string>
-  <string name="auth_host_url">Адреса на сервер</string>
+  <string name="auth_host_url">Адреса на серверот https://…</string>
   <string name="auth_username">Корисничко име</string>
   <string name="auth_password">Лозинка</string>
   <string name="sync_string_files">Датотеки</string>
   <string name="uploader_wrn_no_account_title">Не е пронајдена сметка</string>
   <string name="uploader_wrn_no_account_setup_btn_text">Нагодување</string>
   <string name="uploader_wrn_no_account_quit_btn_text">Прекини</string>
+  <string name="file_list_empty">Тука нема ништо. Снимете нешто!</string>
   <string name="filedetails_size">Големина:</string>
   <string name="filedetails_type">Тип:</string>
   <string name="filedetails_created">Создадено:</string>
   <string name="filedetails_modified">Изменето:</string>
   <string name="filedetails_download">Преземање</string>
+  <string name="action_share_file">Сподели ја врската</string>
   <string name="common_yes">Да</string>
   <string name="common_no">Не</string>
   <string name="common_ok">Во ред</string>
   <string name="change_password">Смени лозинка</string>
   <string name="delete_account">Избриши ја сметката</string>
   <string name="create_account">Креирај сметка</string>
-  <string name="uploader_info_dirname">Име на папката</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_succeeded_ticker">Подигањето беше успешно</string>
   <string name="downloader_download_in_progress_ticker">Преземање...</string>
   <string name="downloader_download_succeeded_ticker">Преземањето е успешно</string>
   <string name="downloader_download_failed_ticker">Преземањето не беше успешно</string>
   <string name="pincode_stored">Апликативниот ПИН е снимен</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_testing_connection">Ја тестирам врската...</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_ssl_general_error_title">Неуспешна SSL иницијализација</string>
+  <string name="auth_ssl_unverified_server_title">Не можев да го проверам SSL серверскиот идентитет</string>
   <string name="auth_bad_oc_version_title">Верзијата на серверот не е препознаена</string>
+  <string name="auth_wrong_connection_title">Не може да се воспостави конекција</string>
+  <string name="auth_secure_connection">Воспоставена е безбедна конекција</string>
   <string name="auth_unauthorized">Погрешно корисничко име или лозинка</string>
   <string name="auth_oauth_error">Неуспешна авторизација</string>
   <string name="auth_expired_basic_auth_toast">Внесете ја вашата тековна лозинка:</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_local">Само локално</string>
   <string name="confirmation_remove_remote">Отстрани од серверот</string>
   <string name="confirmation_remove_remote_and_local">Далечинско и локално</string>
   <string name="remove_success_msg">Одстранувањето е успешно</string>
   <string name="remove_fail_msg">Одстранувањето е неуспешно</string>
   <string name="rename_dialog_title">Внеси ново име</string>
-  <string name="create_dir_fail_msg">Не можам да креирам папка</string>
+  <string name="rename_server_fail_msg">Преименувањето не можеше да се комплетира</string>
+  <string name="create_dir_fail_msg">Папката не можеше да се креира</string>
   <string name="wait_a_moment">Почекајте малку</string>
   <string name="filedisplay_unexpected_bad_get_content">Неочекуван проблем ; ве молам одберете датотека од друга апликација</string>
   <string name="filedisplay_no_file_selected">Нема избрано датотека</string>
   <string name="conflict_title">Конфликт при надградбата</string>
   <string name="conflict_keep_both">Задржи ги и двете</string>
   <string name="conflict_overwrite">Препиши</string>
-  <string name="failed_upload_all_cb">избери се</string>
+  <string name="activity_chooser_send_file_title">Прати</string>
+  <string name="empty"></string>
+  <string name="prefs_category_accounts">Сметки</string>
+  <string name="saml_authentication_required_text">Потребна е автентификација</string>
+  <string name="saml_authentication_wrong_pass">Погрешна лозинка</string>
+  <string name="move_choose_button_text">Избери</string>
+  <string name="prefs_category_security">Безбедност</string>
 </resources>
index c757504..75c6f22 100644 (file)
@@ -1,2 +1,6 @@
 <?xml version='1.0' encoding='UTF-8'?>
-<resources/>
+<resources>
+  <string name="actionbar_upload_files">ഫയലുകൾ</string>
+  <string name="sync_string_files">ഫയലുകൾ</string>
+  <string name="empty"></string>
+</resources>
diff --git a/res/values-ml/strings.xml b/res/values-ml/strings.xml
new file mode 100644 (file)
index 0000000..56e55a1
--- /dev/null
@@ -0,0 +1,4 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<resources>
+  <string name="empty"></string>
+</resources>
diff --git a/res/values-mn/strings.xml b/res/values-mn/strings.xml
new file mode 100644 (file)
index 0000000..56e55a1
--- /dev/null
@@ -0,0 +1,4 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<resources>
+  <string name="empty"></string>
+</resources>
index b2b8fdf..af534d2 100644 (file)
@@ -2,14 +2,12 @@
 <resources>
   <string name="actionbar_upload">Muat naik</string>
   <string name="actionbar_upload_files">Fail-fail</string>
-  <string name="actionbar_mkdir">Bina direktori</string>
   <string name="actionbar_settings">Set</string>
   <string name="prefs_category_general">Umum</string>
   <string name="prefs_category_more">Lanjutan</string>
   <string name="prefs_accounts">Akaun</string>
   <string name="prefs_pincode">PIN App</string>
   <string name="prefs_help">Bantuan</string>
-  <string name="auth_host_url">Alamat pelayan</string>
   <string name="auth_username">Nama pengguna</string>
   <string name="auth_password">Kata laluan</string>
   <string name="sync_string_files">Fail-fail</string>
@@ -19,6 +17,7 @@
   <string name="uploader_wrn_no_account_text">Device anda tidak mempunyai sebarang akaun %1$s. Mohon bina akaun dahulu.</string>
   <string name="uploader_wrn_no_account_quit_btn_text">Berhenti</string>
   <string name="uploader_info_uploading">Memuatnaik</string>
+  <string name="file_list_empty">Tiada apa-apa di sini. Muat naik sesuatu!</string>
   <string name="filedetails_size">Saiz</string>
   <string name="filedetails_type">Jenis</string>
   <string name="filedetails_created">Telah dibina:</string>
@@ -34,7 +33,6 @@
   <string name="about_title">Mengenai</string>
   <string name="change_password">Ubah kata laluan</string>
   <string name="delete_account">Padam akaun</string>
-  <string name="uploader_info_dirname">Nama direktori</string>
   <string name="uploader_upload_succeeded_ticker">Muatnaik berjaya</string>
   <string name="uploader_upload_failed_ticker">Muatnaik gagal</string>
   <string name="downloader_download_in_progress_ticker">Muatturun....</string>
@@ -46,4 +44,6 @@
   <string name="common_rename">Namakan</string>
   <string name="common_remove">Buang</string>
   <string name="confirmation_remove_local">Lokal sahaja</string>
+  <string name="empty"></string>
+  <string name="prefs_category_accounts">Akaun</string>
 </resources>
diff --git a/res/values-mt-rMT/strings.xml b/res/values-mt-rMT/strings.xml
new file mode 100644 (file)
index 0000000..56e55a1
--- /dev/null
@@ -0,0 +1,4 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<resources>
+  <string name="empty"></string>
+</resources>
index 4318b6a..7f998bf 100644 (file)
@@ -8,5 +8,8 @@
   <string name="filedetails_download">ဒေါင်းလုတ်</string>
   <string name="common_yes">ဟုတ်</string>
   <string name="common_no">မဟုတ်ဘူး</string>
+  <string name="common_ok">အိုကေ</string>
   <string name="common_cancel">ပယ်ဖျက်မည်</string>
+  <string name="empty"></string>
+  <string name="move_choose_button_text">ရွေးချယ်</string>
 </resources>
index f7c70fd..55e2bb4 100644 (file)
@@ -1,33 +1,67 @@
 <?xml version='1.0' encoding='UTF-8'?>
 <resources>
+  <string name="about_android">%1$s Android app</string>
+  <string name="about_version">versjon %1$s</string>
+  <string name="actionbar_sync">Oppdater konto</string>
   <string name="actionbar_upload">Last opp</string>
   <string name="actionbar_upload_from_apps">Innhold fra andre applikasjoner</string>
   <string name="actionbar_upload_files">Filer</string>
-  <string name="actionbar_mkdir">Opprett katalog</string>
+  <string name="actionbar_open_with">Åpne med</string>
+  <string name="actionbar_mkdir">Ny mappe</string>
   <string name="actionbar_settings">Innstillinger</string>
+  <string name="actionbar_see_details">Detaljer</string>
+  <string name="actionbar_send_file">Send</string>
   <string name="prefs_category_general">Generelt</string>
   <string name="prefs_category_more">Mer</string>
   <string name="prefs_accounts">Kontoer</string>
-  <string name="prefs_instant_upload_summary">Last opp bilder tatt med kamera øyeblikkelig</string>
+  <string name="prefs_manage_accounts">Håndter kontoer</string>
+  <string name="prefs_pincode">PIN kode</string>
+  <string name="prefs_pincode_summary">Beskytt klienten din</string>
+  <string name="prefs_instant_upload">Umiddelbare bildeopplastninger</string>
+  <string name="prefs_instant_upload_summary">Last opp bilder tatt av kameraet umiddelbart</string>
+  <string name="prefs_instant_video_upload">Umiddelbare video-opplastninger</string>
+  <string name="prefs_instant_video_upload_summary">Last opp videoer tatt opp av kameraet umiddelbart</string>
+  <string name="prefs_log_title">Aktiver loggføring</string>
+  <string name="prefs_log_summary">Denne er brukt til å loggføre problemer</string>
+  <string name="prefs_log_title_history">Loggføringshistorikk</string>
+  <string name="prefs_log_summary_history">Denne viser de lagrede loggene</string>
+  <string name="prefs_log_delete_history_button">Slett historikk</string>
   <string name="prefs_help">Hjelp</string>
-  <string name="auth_host_url">Server-adresse</string>
+  <string name="prefs_recommend">Anbefal til en venn</string>
+  <string name="prefs_feedback">Tilbakemelding</string>
+  <string name="prefs_imprint">Avtrykk</string>
+  <string name="recommend_subject">Prøv %1$s på smarttelefonen din!</string>
+  <string name="recommend_text">Jeg ønsker å invitere deg til å bruke %1$s på smarttelefonen din!\nLast ned her: %2$s</string>
+  <string name="auth_check_server">Sjekk server</string>
+  <string name="auth_host_url">Serveradresse https://...</string>
   <string name="auth_username">Brukernavn</string>
   <string name="auth_password">Passord</string>
+  <string name="auth_register">Ny med %1$s?</string>
   <string name="sync_string_files">Filer</string>
   <string name="setup_btn_connect">Koble til</string>
   <string name="uploader_btn_upload_text">Last opp</string>
+  <string name="uploader_top_message">Velg opplastingsmappe:</string>
   <string name="uploader_wrn_no_account_title">Ingen konto funnet</string>
+  <string name="uploader_wrn_no_account_text">Det finnes ingen %1$s kontoer for din enhet. For å bruker denne appen må du først opprette en.</string>
   <string name="uploader_wrn_no_account_setup_btn_text">Oppsett</string>
   <string name="uploader_wrn_no_account_quit_btn_text">Avslutt</string>
   <string name="uploader_wrn_no_content_title">Intet innhold å laste opp</string>
   <string name="uploader_wrn_no_content_text">Intet innhold ble mottatt. Intet å laste opp.</string>
+  <string name="uploader_error_forbidden_content">%1$s har ikke tilgang til det delte innholdet</string>
   <string name="uploader_info_uploading">Laster opp</string>
+  <string name="file_list_empty">Ingenting her. Last opp noe!</string>
+  <string name="file_list_loading">Laster...</string>
+  <string name="local_file_list_empty">Det er ingen filer i denne mappen.</string>
   <string name="filedetails_select_file">Trykk på en fil for å vise ekstra informasjon.</string>
   <string name="filedetails_size">Størrelse:</string>
   <string name="filedetails_type">Type:</string>
   <string name="filedetails_created">Opprettet:</string>
   <string name="filedetails_modified">Endret:</string>
   <string name="filedetails_download">Last ned</string>
+  <string name="filedetails_sync_file">Oppdater fil</string>
+  <string name="filedetails_renamed_in_upload_msg">Filnavnet ble endret til  %1$s under opplasting</string>
+  <string name="action_share_file">Del lenke</string>
+  <string name="action_unshare_file">Avslutt deling av lenke</string>
   <string name="common_yes">Ja</string>
   <string name="common_no">Nei</string>
   <string name="common_ok">OK</string>
   <string name="common_cancel">Avbryt</string>
   <string name="common_save_exit">Lagre og avslutt</string>
   <string name="common_error">Feil</string>
+  <string name="common_loading">Laster...</string>
+  <string name="common_error_unknown">Ukjent feil</string>
   <string name="about_title">Om</string>
   <string name="change_password">Endre passord</string>
   <string name="delete_account">Slett konto</string>
   <string name="create_account">Opprett konto</string>
   <string name="upload_chooser_title">Last opp fra...</string>
-  <string name="uploader_info_dirname">Katalognavn</string>
+  <string name="uploader_info_dirname">Mappenavn</string>
   <string name="uploader_upload_in_progress_ticker">Laster opp...</string>
   <string name="uploader_upload_in_progress_content">%1$d%% Laster opp %2$s</string>
   <string name="uploader_upload_succeeded_ticker">Opplasting fullført</string>
+  <string name="uploader_upload_succeeded_content_single">%1$s ble lastet opp</string>
   <string name="uploader_upload_failed_ticker">Opplasting feilet</string>
   <string name="uploader_upload_failed_content_single">Opplasting av %1$s kunne ikke fullføres</string>
+  <string name="uploader_upload_failed_credentials_error">Opplasting feilet. Du må logge inn på nytt</string>
   <string name="downloader_download_in_progress_ticker">Laster ned...</string>
   <string name="downloader_download_in_progress_content">%1$d%% Laster ned %2$s</string>
   <string name="downloader_download_succeeded_ticker">Nedlasting fullført</string>
+  <string name="downloader_download_succeeded_content">%1$s ble lastet ned</string>
   <string name="downloader_download_failed_ticker">Nedlasting feilet</string>
   <string name="downloader_download_failed_content">Nedlasting av %1$s kunne ikke fullføres</string>
+  <string name="downloader_not_downloaded_yet">Ikke lastet ned enda</string>
+  <string name="downloader_download_failed_credentials_error">Nedlasting feilet. Du må logge inn på nytt</string>
   <string name="common_choose_account">Velg konto</string>
   <string name="sync_fail_ticker">Synkronisering feilet</string>
+  <string name="sync_fail_ticker_unauthorized">Synkronisering feilet, du må logge inn på nytt</string>
   <string name="sync_fail_content">Synkronisering av %1$s kunne ikke fullføres</string>
+  <string name="sync_fail_content_unauthorized">Ugyldig passord for %1$s</string>
   <string name="sync_conflicts_in_favourites_ticker">Konflikter funnet</string>
+  <string name="sync_conflicts_in_favourites_content">%1$d hold-i-synk filer kunne ikke synkroniseres</string>
+  <string name="sync_fail_in_favourites_ticker">Hold i synk filer mislyktes</string>
+  <string name="sync_fail_in_favourites_content">Innholdet av %1$d filer kunne ikke synkroniseres (%2$d konflikter)</string>
+  <string name="sync_foreign_files_forgotten_ticker">Noen lokale filer ble glemt</string>
+  <string name="sync_foreign_files_forgotten_content">%1$d filer fra %2$s mappen kunne ikke kopieres til</string>
+  <string name="sync_foreign_files_forgotten_explanation">Fra versjon 1.3.16 blir filer som lastes opp fra denne enheten kopiert inn i den lokale mappen %1$s for å forhindre tap av data når samme fil synkroniseres med flere kontoer.\n\nPga. denne endringen ble alle filer som er blitt lastet opp med tidligere versjoner av denne appen, kopiert til mappe %2$s. Imidlertid kunne ikke denne kopieringen fullføres under konto-synkroniseringen pga. en feil. Du kan enten la filen(e) ligge der de ligger og fjerne lenken til %3$s, eller flytte filene til mappe %1$s og beholde lenken til %4$s.\n\nNedenfor finner du en liste over de lokale filene og de eksterne filene i %5$s som de var lenket til.</string>
+  <string name="sync_current_folder_was_removed">Mappen %1$s finnes ikke lengere</string>
+  <string name="foreign_files_move">Flytt alle</string>
+  <string name="foreign_files_success">Alle filer ble flyttet</string>
+  <string name="foreign_files_fail">Noen filer kunne ikke fjernes</string>
+  <string name="foreign_files_local_text">Lokal: %1$s</string>
+  <string name="foreign_files_remote_text">Ekstern: %1$s</string>
+  <string name="upload_query_move_foreign_files">Det er ikke nok plass til å kopiere de valgte filene inn i mappen %1$s. Vil du flytte dem i stedet? </string>
   <string name="pincode_enter_pin_code">Vennligst tast inn din App-PIN</string>
+  <string name="pincode_configure_your_pin">Skriv inn din PIN kode</string>
+  <string name="pincode_configure_your_pin_explanation">PIN koden vil bli ettersourt hver gang appen starter</string>
+  <string name="pincode_reenter_your_pincode">Vennligst tast inn din PIN kode på nytt</string>
+  <string name="pincode_remove_your_pincode">Fjern din PIN kode</string>
+  <string name="pincode_mismatch">PIN kodene du tastet er ulike</string>
+  <string name="pincode_wrong">Feil PIN kode</string>
+  <string name="pincode_removed">PIN kode fjernet</string>
+  <string name="pincode_stored">PIN kode lagret</string>
+  <string name="media_notif_ticker">%1$s musikkspiller</string>
+  <string name="media_state_playing">%1$s (spiller)</string>
+  <string name="media_state_loading">%1$s (laster)</string>
+  <string name="media_event_done">%1$s avspilling avsluttet</string>
+  <string name="media_err_nothing_to_play">Ingen mediafil funnet</string>
+  <string name="media_err_no_account">Ingen konto angitt</string>
+  <string name="media_err_not_in_owncloud">Filen er ikke i en gyldig konto</string>
+  <string name="media_err_unsupported">Mediakodek er ikke støttet</string>
+  <string name="media_err_io">Mediafilen kunne ikke leses</string>
+  <string name="media_err_malformed">Mediafilen er ikke riktig kodet</string>
+  <string name="media_err_timeout">Tidsavbrudd under avspillingsforsøk</string>
+  <string name="media_err_invalid_progressive_playback">Mediafilen kan ikke strømmes</string>
+  <string name="media_err_unknown">Mediafilen kan ikke spilles med standard mediaspiller</string>
+  <string name="media_err_security_ex">Sikkerhetsfeil under avspilling av %1$s</string>
+  <string name="media_err_io_ex">Inputfeil under avspilling av %1$s</string>
+  <string name="media_err_unexpected">Uforventet feil under avspilling av %1$s</string>
+  <string name="media_rewind_description">Spol tilbake</string>
+  <string name="media_play_pause_description">Spill eller pause</string>
+  <string name="media_forward_description">Spol fremover</string>
+  <string name="auth_getting_authorization">Henter godkjenning...</string>
   <string name="auth_trying_to_login">Prøver å logge inn...</string>
   <string name="auth_no_net_conn_title">Ingen nettverkstilkobling</string>
   <string name="auth_nossl_plain_ok_title">Sikker tilkobling ikke tilgjengelig.</string>
   <string name="auth_connection_established">Tilkobling opprettet</string>
   <string name="auth_testing_connection">Tester tilgang...</string>
+  <string name="auth_not_configured_title">Feil i server konfigurasjon</string>
+  <string name="auth_account_not_new">En konto for samme bruker og server finnes allerede på enheten</string>
+  <string name="auth_account_not_the_same">Den innskrevne brukeren matcher ikke brukeren av denne kontoen</string>
   <string name="auth_unknown_error_title">Ukjent feil oppstod!</string>
   <string name="auth_unknown_host_title">Fant ikke tjener</string>
+  <string name="auth_incorrect_path_title">Finner ikke server instans</string>
   <string name="auth_timeout_title">Serveren brukte for lang tid på å svare</string>
   <string name="auth_incorrect_address_title">Feil formatert URL</string>
   <string name="auth_ssl_general_error_title">Oppstart av SSL feilet</string>
+  <string name="auth_ssl_unverified_server_title">Kunne ikke verifisere SSL-serverens identitet</string>
+  <string name="auth_bad_oc_version_title">Ukjent server versjon</string>
   <string name="auth_wrong_connection_title">Klarte ikke å opprette tilkobling</string>
   <string name="auth_secure_connection">Sikker tilkobling opprettet</string>
+  <string name="auth_unauthorized">Feil brukernavn eller passord</string>
+  <string name="auth_oauth_error">Mislykket autorisasjon</string>
+  <string name="auth_oauth_error_access_denied">Tilgang nektet av autorisasjonsserver</string>
+  <string name="auth_wtf_reenter_URL">Uforventet tilstand; vennligst skriv inn serveradressen en gang til</string>
+  <string name="auth_expired_oauth_token_toast">Autorisasjonen din har gått ut. Vennligt autoriser igjen</string>
+  <string name="auth_expired_basic_auth_toast">Vennligst skriv inn gjeldende passord</string>
+  <string name="auth_expired_saml_sso_token_toast">Sesjonen din har gått ut. Vennligst koble til igjen</string>
+  <string name="auth_connecting_auth_server">Kobler til autorisasjonsserver...</string>
+  <string name="auth_unsupported_auth_method">Serveren støtter ikke denne autorisasjonsmetoden</string>
+  <string name="auth_unsupported_multiaccount">%1$s støtter ikke flere kontoer</string>
+  <string name="auth_fail_get_user_name">Tjeneren din svarer ikke med korrekt bruker-ID, vennligst ta kontakt med en administrator
+       </string>
+  <string name="auth_can_not_auth_against_server">Kan ikke autentisere mot denne serveren</string>
   <string name="fd_keep_in_sync">Hold filen oppdatert</string>
   <string name="common_rename">Endre navn</string>
   <string name="common_remove">Fjern</string>
-  <string name="confirmation_remove_alert">Er du sikker på at du vil fjerne %1$s ?</string>
+  <string name="confirmation_remove_alert">Vil du virkelig fjerne %1$s?</string>
+  <string name="confirmation_remove_folder_alert">Vil du virkelig fjerne %1$s inkludert innholdet?</string>
   <string name="confirmation_remove_local">Kun lokalt</string>
+  <string name="confirmation_remove_folder_local">Kun lokalt innhold</string>
   <string name="confirmation_remove_remote">Fjern fra server</string>
+  <string name="confirmation_remove_remote_and_local">Ekstern og lokal</string>
+  <string name="remove_success_msg">Fjerning var vellykket</string>
+  <string name="remove_fail_msg">Fjerning mislyktes</string>
+  <string name="rename_dialog_title">Skriv inn et nytt navn</string>
+  <string name="rename_local_fail_msg">Lokal kopi kunne ikke endre navn; prøv et annet navn</string>
   <string name="rename_server_fail_msg">Klarte ikke å endre navn</string>
+  <string name="sync_file_fail_msg">Eksterne filer kunne ikke sjekkes</string>
+  <string name="sync_file_nothing_to_do_msg">filinnhold er allerede synkronisert</string>
   <string name="create_dir_fail_msg">Mappe kunne ikke opprettes</string>
+  <string name="filename_forbidden_characters">Forbudte tegn: / \\ &lt; &gt; : \" | ? *</string>
+  <string name="filename_empty">Filnavn kan ikke være tomt</string>
   <string name="wait_a_moment">Vent et øyeblikk</string>
+  <string name="filedisplay_unexpected_bad_get_content">Uforventet problem; vennligst velg filen fra en annen applikasjon</string>
   <string name="filedisplay_no_file_selected">Ingen fil ble valgt</string>
+  <string name="activity_chooser_title">Send lenke til ...</string>
+  <string name="oauth_check_onoff">Logg inn med oAuth2</string>
+  <string name="oauth_login_connection">Kobler til oAuth2 server...</string>
   <string name="ssl_validator_header">Identiteten til siden kunne ikke verifiseres</string>
   <string name="ssl_validator_reason_cert_not_trusted">- Serverens sertifikat er ikke til å stole på</string>
   <string name="ssl_validator_reason_cert_expired">- Serverens sertifikat er utløpt</string>
+  <string name="ssl_validator_reason_cert_not_yet_valid">- Server-sertifikatets gyldige datoer er i fremtiden</string>
+  <string name="ssl_validator_reason_hostname_not_verified">- Nettadressen samsvarer ikke med vertsnavnet i sertifikatet</string>
+  <string name="ssl_validator_question">Vil du stole på dette sertifikatet likevel?</string>
+  <string name="ssl_validator_not_saved">Sertifikatet kunne ikke lagres</string>
   <string name="ssl_validator_btn_details_see">Detaljer</string>
   <string name="ssl_validator_btn_details_hide">Skjul</string>
+  <string name="ssl_validator_label_subject">Utstedt til:</string>
+  <string name="ssl_validator_label_issuer">Utstedt av:</string>
+  <string name="ssl_validator_label_CN">Vanlig navn:</string>
+  <string name="ssl_validator_label_O">Organisasjon:</string>
+  <string name="ssl_validator_label_OU">Organisasjonsenhet:</string>
   <string name="ssl_validator_label_C">Land:</string>
+  <string name="ssl_validator_label_ST">Stat:</string>
+  <string name="ssl_validator_label_L">Sted:</string>
+  <string name="ssl_validator_label_validity">Gyldighet:</string>
   <string name="ssl_validator_label_validity_from">Fra:</string>
   <string name="ssl_validator_label_validity_to">Til:</string>
   <string name="ssl_validator_label_signature">Signatur:</string>
+  <string name="ssl_validator_label_signature_algorithm">Algoritme:</string>
+  <string name="ssl_validator_null_cert">Sertifikatet kunne ikke vises.</string>
+  <string name="ssl_validator_no_info_about_error">- Ingen informasjon om feilen</string>
+  <string name="placeholder_sentence">Dette er en plassholder</string>
+  <string name="placeholder_filename">placeholder.txt</string>
+  <string name="placeholder_filetype">PNG bilde</string>
+  <string name="placeholder_filesize">389 KB</string>
+  <string name="placeholder_timestamp">18.05.2012 12:23</string>
+  <string name="placeholder_media_time">12:23:45</string>
+  <string name="instant_upload_on_wifi">Kun last opp bilder via WiFi</string>
+  <string name="instant_video_upload_on_wifi">Last opp video kun via WiFi</string>
+  <string name="instant_upload_path">/Direkteopplasting</string>
+  <string name="conflict_title">Oppdateringskonflikt</string>
+  <string name="conflict_message">Ekstern fil %s er ikke synkronisert med lokal fil. Hvis du fortsetter vil det erstatte innhold på serveren.</string>
   <string name="conflict_keep_both">Behold begge</string>
+  <string name="conflict_overwrite">Overskriv</string>
+  <string name="conflict_dont_upload">Ikke last opp</string>
+  <string name="preview_image_description">Bildeforhåndsvisning</string>
+  <string name="preview_image_error_unknown_format">Dette bildet kan ikke vises</string>
+  <string name="error__upload__local_file_not_copied">%1$s kunne ikke kopieres til lokal mappe %2$s</string>
+  <string name="share_link_no_support_share_api">Beklager, deling er ikke skrudd på for din tjener. Ta kontakt med
+               administratoren.</string>
+  <string name="share_link_file_no_exist">Kan ikke dele. Sjekk om filen eksisterer.</string>
+  <string name="share_link_file_error">Det skjedde en feil under deling av denne filen eller mappen</string>
+  <string name="unshare_link_file_no_exist">Kan ikke fjerne deling. Sjekk om filen eksisterer.</string>
+  <string name="unshare_link_file_error">En feil oppstod ved avslutting av delingen av denne filen eller mappen</string>
+  <string name="activity_chooser_send_file_title">Send</string>
+  <string name="copy_link">Kopier lenke</string>
+  <string name="clipboard_text_copied">Kopiert til utklippstavlen</string>
+  <string name="error_cant_bind_to_operations_service">Kritisk feil: kan ikke utføre operasjonene</string>
+  <string name="network_error_socket_exception">En feil oppstod ved oppretting av forbindelse til serveren.</string>
+  <string name="network_error_socket_timeout_exception">En feil oppstod ved venting på svar fra serveren. Operasjonen kunne ikke utføres</string>
+  <string name="network_error_connect_timeout_exception">En feil oppstod ved venting på svar fra serveren. Operasjonen kunne ikke utføres</string>
+  <string name="network_host_not_available">Operasjonen kunne ikke fullføres. Server utilgjengelig</string>
+  <string name="empty"></string>
+  <string name="forbidden_permissions">Du har ikke tillatelse til %s</string>
+  <string name="forbidden_permissions_rename">å omdøpe denne filen</string>
+  <string name="forbidden_permissions_delete">å slette denne filen</string>
+  <string name="share_link_forbidden_permissions">å dele denne filen</string>
+  <string name="unshare_link_forbidden_permissions">å avslutte deling av denne filen</string>
+  <string name="forbidden_permissions_create">å opprette filen</string>
+  <string name="uploader_upload_forbidden_permissions">å laste opp i denne mappen</string>
+  <string name="downloader_download_file_not_found">Filen finnes ikke på serveren lenger</string>
+  <string name="prefs_category_accounts">Kontoer</string>
+  <string name="prefs_add_account">Legg til en konto</string>
+  <string name="actionbar_logger">Logger</string>
+  <string name="log_send_history_button">Send historikk</string>
+  <string name="log_mail_subject">logger for ownCloud Android app</string>
+  <string name="log_progress_dialog_text">Laster data...</string>
+  <string name="saml_authentication_required_text">Autentisering kreves</string>
+  <string name="saml_authentication_wrong_pass">Feil passord</string>
+  <string name="actionbar_move">Flytt</string>
+  <string name="file_list_empty_moving">Ingenting her. Du kan legge til en mappe!</string>
+  <string name="move_choose_button_text">Velg</string>
+  <string name="move_file_not_found">Kan ikke flytte. Sjekk om filen eksisterer.</string>
+  <string name="move_file_invalid_into_descendent">Det er ikke mulig å flytte en mappe inn i sin egen undermappe</string>
+  <string name="move_file_invalid_overwrite">Filen finnes allerede i målmappen</string>
+  <string name="move_file_error">En feil oppstod ved flytting av denne filen eller mappen</string>
+  <string name="forbidden_permissions_move">å flytte denne filen</string>
+  <string name="prefs_category_security">Sikkerhet</string>
 </resources>
index c757504..56e55a1 100644 (file)
@@ -1,2 +1,4 @@
 <?xml version='1.0' encoding='UTF-8'?>
-<resources/>
+<resources>
+  <string name="empty"></string>
+</resources>
index 16a7649..f79d933 100644 (file)
@@ -7,17 +7,20 @@
   <string name="actionbar_upload_from_apps">Inhoud van andere apps</string>
   <string name="actionbar_upload_files">Bestanden</string>
   <string name="actionbar_open_with">Open met</string>
-  <string name="actionbar_mkdir">Creëer map</string>
+  <string name="actionbar_mkdir">Nieuwe map</string>
   <string name="actionbar_settings">Instellingen</string>
   <string name="actionbar_see_details">Details</string>
+  <string name="actionbar_send_file">Versturen</string>
   <string name="prefs_category_general">Algemeen</string>
   <string name="prefs_category_more">Meer</string>
   <string name="prefs_accounts">Accounts</string>
   <string name="prefs_manage_accounts">Beheer accounts</string>
   <string name="prefs_pincode">App PIN</string>
   <string name="prefs_pincode_summary">Beveilig je client</string>
-  <string name="prefs_instant_upload">Schakel direct uploaden in</string>
-  <string name="prefs_instant_upload_summary">Upload afbeeldingen van camera automatisch</string>
+  <string name="prefs_instant_upload">Directe uploads van afbeeldingen</string>
+  <string name="prefs_instant_upload_summary">Direct uploaden van foto\'s genomen met de camera</string>
+  <string name="prefs_instant_video_upload">Direct uploaden van video\'s</string>
+  <string name="prefs_instant_video_upload_summary">Direct uploaden van video\'s vanaf de camera</string>
   <string name="prefs_log_title">Loggen aanzetten</string>
   <string name="prefs_log_summary">Dit wordt gebruikt om problemen te loggen.</string>
   <string name="prefs_log_title_history">Log-geschiedenis</string>
   <string name="prefs_feedback">Feedback</string>
   <string name="prefs_imprint">afdruk</string>
   <string name="recommend_subject">Probeer %1$s op uw smartphone!</string>
-  <string name="recommend_text">Uitnodiging om %1$s op uw smartphone uit te proberen!\nDownload hier: %2$s</string>
+  <string name="recommend_text">Uitnodiging om %1$s op uw smartphone uit te proberen!
+Download hier: %2$s</string>
   <string name="auth_check_server">Controleer server</string>
-  <string name="auth_host_url">Server adres</string>
+  <string name="auth_host_url">Serveradres https://…</string>
   <string name="auth_username">Gebruikersnaam</string>
   <string name="auth_password">Wachtwoord</string>
   <string name="auth_register">Nieuw bij %1$s?</string>
   <string name="sync_string_files">Bestanden</string>
   <string name="setup_btn_connect">Verbinden</string>
   <string name="uploader_btn_upload_text">Uploaden</string>
-  <string name="uploader_top_message">Selecteer upload map:</string>
+  <string name="uploader_top_message">Kies upload map:</string>
   <string name="uploader_wrn_no_account_title">Geen account gevonden</string>
   <string name="uploader_wrn_no_account_text">Er zijn nog geen %1$s accounts op je apparaat. Stel eerst een account in.</string>
   <string name="uploader_wrn_no_account_setup_btn_text">Configureren</string>
@@ -46,7 +50,9 @@
   <string name="uploader_wrn_no_content_text">Er werd geen inhoud ontvangen. Niets om te uploaden.</string>
   <string name="uploader_error_forbidden_content">%1$s is niet toegestaan om toegang te hebben tot de publieke inhoud</string>
   <string name="uploader_info_uploading">Uploaden</string>
-  <string name="file_list_empty">Er zitten geen bestanden in deze map.\nNieuwe bestanden kunnen worden toegevoegd via de \"Upload\" menukeuze.</string>
+  <string name="file_list_empty">Er bevindt zich hier niets. Upload een bestand!</string>
+  <string name="file_list_loading">Laden ...</string>
+  <string name="local_file_list_empty">Er staan geen bestanden in deze map.</string>
   <string name="filedetails_select_file">Druk op een bestand om extra informatie weer te geven</string>
   <string name="filedetails_size">Grootte:</string>
   <string name="filedetails_type">Type:</string>
@@ -55,6 +61,8 @@
   <string name="filedetails_download">Download</string>
   <string name="filedetails_sync_file">Bestand verversen</string>
   <string name="filedetails_renamed_in_upload_msg">Bestand was hernoemt naar %1$s tijdens het uploaden</string>
+  <string name="action_share_file">Deel link</string>
+  <string name="action_unshare_file">Link niet meer delen</string>
   <string name="common_yes">Ja</string>
   <string name="common_no">Nee</string>
   <string name="common_ok">OK</string>
   <string name="delete_account">Verwijder account</string>
   <string name="create_account">Maak account aan</string>
   <string name="upload_chooser_title">Upload van ...</string>
-  <string name="uploader_info_dirname">Map naam</string>
+  <string name="uploader_info_dirname">Mapnaam</string>
   <string name="uploader_upload_in_progress_ticker">Uploaden ...</string>
   <string name="uploader_upload_in_progress_content">%1$d%% Uploaden %2$s</string>
   <string name="uploader_upload_succeeded_ticker">Upload succesvol</string>
   <string name="uploader_upload_succeeded_content_single">%1$s is met succes ge-upload</string>
   <string name="uploader_upload_failed_ticker">Upload mislukt</string>
   <string name="uploader_upload_failed_content_single">Upload van %1$s kon niet voltooid worden</string>
+  <string name="uploader_upload_failed_credentials_error">Update mislukt, u moet opnieuw inloggen</string>
   <string name="downloader_download_in_progress_ticker">Downloaden ...</string>
   <string name="downloader_download_in_progress_content">%1$d%% Aan het downloaden %2$s</string>
   <string name="downloader_download_succeeded_ticker">Downloaden gelukt</string>
   <string name="downloader_download_failed_ticker">Downloaden mislukt</string>
   <string name="downloader_download_failed_content">Download van %1$s kon niet worden voltooid</string>
   <string name="downloader_not_downloaded_yet">Nog niet gedownload</string>
+  <string name="downloader_download_failed_credentials_error">Download mislukt, u moet opnieuw inloggen</string>
   <string name="common_choose_account">Kies account</string>
   <string name="sync_fail_ticker">Synchronisatie mislukt</string>
+  <string name="sync_fail_ticker_unauthorized">Synchronisatie mislukt, opnieuw inloggen</string>
   <string name="sync_fail_content">Synchronisatie van %1$s kon niet worden voltooid</string>
   <string name="sync_fail_content_unauthorized">Ongeldig wachtwoord voor %1$s</string>
   <string name="sync_conflicts_in_favourites_ticker">Conflicten gevonden</string>
   <string name="sync_fail_in_favourites_ticker">In-sync-houden bestanden mislukt</string>
   <string name="sync_fail_in_favourites_content">Inhoud van %1$d bestanden kon niet worden gesynchroniseerd (%2$d conflicten)</string>
   <string name="sync_foreign_files_forgotten_ticker">Een paar lokale bestanden werden vergeten</string>
-  <string name="sync_foreign_files_forgotten_content">%1$d bestanden uit de %2$s directory konden niet worden gekopieerd naar</string>
-  <string name="sync_foreign_files_forgotten_explanation">Vanaf versie 1.3.16 worden bestanden die geüpload zijn vanaf dit apparaat gekopieerd naar de lokale %1$s map om gegevensverlies te voorkomen wanneer een enkel bestand wordt gesynchroniseerd met meerdere accounts.\n\nDoor deze wijziging zijn alle bestanden die met een voorgaande versie van deze app zijn geüpload gekopieërd naar de %2$s map. Echter, door een fout kon deze bewerking niet volledig uitgevoerd worden tijdens het synchroniseren van het account. U kunt het bestand / de bestanden laten zoals ze zijn en de link naar %3$s verwijderen, of het bestand / de bestanden verplaatsen naar de %1$s map en de links naar %4$s behouden.\n\nHieronder staan de locale bestanden, en de externe bestanden in %5$s waarnaar ze doorverwezen.</string>
+  <string name="sync_foreign_files_forgotten_content">%1$d bestanden uit de %2$s map konden niet worden gekopieerd naar</string>
+  <string name="sync_foreign_files_forgotten_explanation">Vanaf versie 1.3.16, worden bestanden die vanaf dit apparaat worden ge-uploaded ook gekopieerd naar de lokale %1$s map om gegevensverlies te voorkomen als een enkel bestand wordt gesynchroniseerd met meerdere accounts.
+Door deze aanpassing werden alle bestanden die met een eerdere versie zijn ge-uploaded gekopieerd naar de %2$s map. Maar een fout voorkwam het succesvol afronden van deze actie tijdens het synchroniseren. U kunt de/het bestand(en) laten staan zoals ze nu zijn en de link naar %3$s verwijderen, of u kunt de bestanden verplaatsen naar de %1$s map en de link naar %4$s laten staan.
+Hieronder staan de lokale bestanden en de externe bestanden in %5$s waar ze naar verwezen.</string>
   <string name="sync_current_folder_was_removed">Map %1$s bestaat niet meer</string>
   <string name="foreign_files_move">Alle verplaatsen</string>
   <string name="foreign_files_success">Alle bestanden zijn verplaatst</string>
   <string name="foreign_files_fail">Een paar bestanden konden niet worden verplaatst</string>
   <string name="foreign_files_local_text">Lokaal: %1$s</string>
   <string name="foreign_files_remote_text">Extern: %1$s</string>
-  <string name="upload_query_move_foreign_files">Er is niet genoeg ruimte om de gekopieerde bestanden ook te plaatsen in map %1$s. Wilt u ze erheen verplaatsten? </string>
+  <string name="upload_query_move_foreign_files">Er is niet genoeg ruimte om de bestanden te gekopieëren in map %1$s. Wilt u ze erheen verplaatsten? </string>
   <string name="pincode_enter_pin_code">Voer App PIN in</string>
   <string name="pincode_configure_your_pin">Voer App PIN in</string>
   <string name="pincode_configure_your_pin_explanation">De PIN wordt steeds opnieuw gevraagd als de app wordt gestart</string>
   <string name="media_rewind_description">terugpoel knop</string>
   <string name="media_play_pause_description">Speel of pauze knop</string>
   <string name="media_forward_description">Doorspoel knop</string>
+  <string name="auth_getting_authorization">Ophalen autorisaties...</string>
   <string name="auth_trying_to_login">Proberen om in te loggen...</string>
   <string name="auth_no_net_conn_title">Geen netwerkverbinding</string>
   <string name="auth_nossl_plain_ok_title">Veilige verbinding niet beschikbaar.</string>
   <string name="auth_connecting_auth_server">Verbinden met authenticatieserver...</string>
   <string name="auth_unsupported_auth_method">De server ondersteunt deze authenticatiemethode niet</string>
   <string name="auth_unsupported_multiaccount">%1$s ondersteunt het gebruik van meerdere accounts niet</string>
+  <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="fd_keep_in_sync">Houd bestand actueel</string>
   <string name="common_rename">Hernoemen</string>
   <string name="common_remove">Verwijderen</string>
-  <string name="confirmation_remove_alert">Wilt je werkelijk %1$s verwijderen?</string>
-  <string name="confirmation_remove_folder_alert">Wil je echt %1$s ende inhoud daarvan verwijderen ?</string>
+  <string name="confirmation_remove_alert">Wilt u %1$s werkelijk verwijderen?</string>
+  <string name="confirmation_remove_folder_alert">Wilt u %1$s en de inhoud ervan werkelijk verwijderen?</string>
   <string name="confirmation_remove_local">Alleen lokaal</string>
   <string name="confirmation_remove_folder_local">Alleen lokale inhoud </string>
   <string name="confirmation_remove_remote">Verwijder van server</string>
   <string name="sync_file_fail_msg">Extern bestand kon niet worden gecontroleerd</string>
   <string name="sync_file_nothing_to_do_msg">Bestandsinhoud is al gesynchroniseerd</string>
   <string name="create_dir_fail_msg">Map kon niet worden aangemaakt</string>
+  <string name="filename_forbidden_characters">Verboden tekens: / \\ &lt; &gt; : \" | ? *</string>
+  <string name="filename_empty">Bestandsnaam mag niet leeg zijn</string>
   <string name="wait_a_moment">Even geduld</string>
   <string name="filedisplay_unexpected_bad_get_content">Onverwacht probleem; probeer een andere app om het bestand te selecteren</string>
   <string name="filedisplay_no_file_selected">Er werd geen bestand geselecteerd</string>
+  <string name="activity_chooser_title">Verstuur link naar ...</string>
   <string name="oauth_check_onoff">Inloggen met oAuth2</string>
   <string name="oauth_login_connection">Verbinden met oAuth2-server.</string>
   <string name="ssl_validator_header">De identiteit van de site kan niet worden gecontroleerd</string>
   <string name="ssl_validator_label_validity_to">Aan:</string>
   <string name="ssl_validator_label_signature">Handtekening:</string>
   <string name="ssl_validator_label_signature_algorithm">Algoritme:</string>
+  <string name="ssl_validator_null_cert">Het certificaat kon niet worden getoond.</string>
+  <string name="ssl_validator_no_info_about_error">- Geen informatie over de fout</string>
   <string name="placeholder_sentence">Dit is een plaatshouder</string>
   <string name="placeholder_filename">plaatshouder.txt</string>
   <string name="placeholder_filetype">PNG Afbeelding</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">Upload afbeeldingen alleen via WiFi</string>
+  <string name="instant_video_upload_on_wifi">Upload video\'s alleen over wifi</string>
   <string name="instant_upload_path">/InstantUpload</string>
   <string name="conflict_title">Update conflict</string>
   <string name="conflict_message">Het remote bestand %s is niet gesynchroniseerd met het lokale bestand. Als je doorgaat wordt de inhoud van het bestand op de server vervangen.</string>
   <string name="conflict_overwrite">Overschrijven</string>
   <string name="conflict_dont_upload">Niet uploaden</string>
   <string name="preview_image_description">Afbeelding voorbeeld</string>
-  <string name="preview_image_error_unknown_format">Deze afbeelding kan niet weergegeven worden</string>
+  <string name="preview_image_error_unknown_format">Deze afbeelding kan niet worden getoond</string>
   <string name="error__upload__local_file_not_copied">%1$s kon niet worden gekopieerd naar de %2$s lokale map</string>
-  <string name="actionbar_failed_instant_upload">Mislukte Directe Upload</string>
-  <string name="failed_upload_headline_text">Mislukte directe uploads</string>
-  <string name="failed_upload_headline_hint">Samenvatting van alle mislukte directe uploads</string>
-  <string name="failed_upload_all_cb">alles selecteren</string>
-  <string name="failed_upload_headline_retryall_btn">opnieuw proberen alles te selecteren</string>
-  <string name="failed_upload_headline_delete_all_btn">verwijderen alle geselecteerde van de upload wachtrij</string>
-  <string name="failed_upload_retry_text">probeer de afbeelding opnieuw te uploaden:</string>
-  <string name="failed_upload_load_more_images">Laadt meer Afbeeldingen</string>
-  <string name="failed_upload_retry_do_nothing_text">doe niks, u bent niet online voor directe upload</string>
-  <string name="failed_upload_failure_text">Mislukkings Bericht:</string>
-  <string name="failed_upload_quota_exceeded_text">Controleer uw server instellingen, misschien is uw quota overschreden.</string>
+  <string name="prefs_instant_upload_path_title">Upload pad</string>
+  <string name="share_link_no_support_share_api">Sorry, delen is niet mogelijk op uw server. Neem contact op met uw
+               beheerder.</string>
+  <string name="share_link_file_no_exist">Kan dit niet delen. Controleer of dit bestand wel bestaat.</string>
+  <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="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>
+  <string name="error_cant_bind_to_operations_service">Kritieke fout: kan de acties niet uitvoeren</string>
+  <string name="network_error_socket_exception">Er trad een fout op bij het verbinden met de server.</string>
+  <string name="network_error_socket_timeout_exception">Er trad een fout op bij het wachten op de server, de verwerking kon niet plaatsvinden</string>
+  <string name="network_error_connect_timeout_exception">Er trad een fout op bij het wachten op de server, de verwerking kon niet plaatsvinden</string>
+  <string name="network_host_not_available">De verwerking kon niet plaatsvinden, de server is niet beschikbaar</string>
+  <string name="empty"></string>
+  <string name="forbidden_permissions">U mist autorisatie %s</string>
+  <string name="forbidden_permissions_rename">om dit bestand te hernoemen</string>
+  <string name="forbidden_permissions_delete">om dit bestand te verwijderen</string>
+  <string name="share_link_forbidden_permissions">om dit bestand te delen</string>
+  <string name="unshare_link_forbidden_permissions">om dit bestand niet meer te delen</string>
+  <string name="forbidden_permissions_create">om dit bestand te creëren</string>
+  <string name="uploader_upload_forbidden_permissions">om dit bestand in deze map te uploaden</string>
+  <string name="downloader_download_file_not_found">Dit bestand is niet langer beschikbaar op de server</string>
+  <string name="prefs_category_accounts">Accounts</string>
+  <string name="prefs_add_account">Toevoegen account</string>
+  <string name="auth_redirect_non_secure_connection_title">De beveiligde verbinding is omgeleid naar een onveilige route.</string>
+  <string name="actionbar_logger">Logs</string>
+  <string name="log_send_history_button">Verstuur geschiedenis</string>
+  <string name="log_mail_subject">ownCloud Android app logs</string>
+  <string name="log_progress_dialog_text">Laden data...</string>
+  <string name="saml_authentication_required_text">Authenticatie vereist</string>
+  <string name="saml_authentication_wrong_pass">Onjuist wachtwoord</string>
+  <string name="actionbar_move">verplaatsen</string>
+  <string name="file_list_empty_moving">Niets hier. U kunt een map toevoegen!</string>
+  <string name="move_choose_button_text">Kies</string>
+  <string name="move_file_not_found">Kan niet verplaatsen. Ga na of het bestand wel bestaat</string>
+  <string name="move_file_invalid_into_descendent">De map kan niet naar een onderliggende map worden verplaatst</string>
+  <string name="move_file_invalid_overwrite">Het bestand bestaat al in de doelmap</string>
+  <string name="move_file_error">Er trad een fout op bij uw poging dit bestand of deze map te verplaatsen</string>
+  <string name="forbidden_permissions_move">om dit bestand te verplaatsen</string>
+  <string name="prefs_category_instant_uploading">Directe uploads</string>
+  <string name="prefs_category_security">Beveiliging</string>
 </resources>
index 12eba28..528bff4 100644 (file)
@@ -1,34 +1,57 @@
 <?xml version='1.0' encoding='UTF-8'?>
 <resources>
+  <string name="about_android">%1$s Android-program</string>
+  <string name="about_version">utgåve %1$s</string>
+  <string name="actionbar_sync">Oppdater konto</string>
   <string name="actionbar_upload">Last opp</string>
   <string name="actionbar_upload_from_apps">Innhald frå andre program</string>
   <string name="actionbar_upload_files">Filer</string>
-  <string name="actionbar_mkdir">Opprett mappe</string>
+  <string name="actionbar_open_with">Opna med</string>
+  <string name="actionbar_mkdir">Ny mappe</string>
   <string name="actionbar_settings">Innstillingar</string>
+  <string name="actionbar_see_details">Detaljar</string>
+  <string name="actionbar_send_file">Send</string>
   <string name="prefs_category_general">Generelt</string>
   <string name="prefs_category_more">Meir</string>
   <string name="prefs_accounts">Kontoar</string>
-  <string name="prefs_instant_upload_summary">Last opp kamerabilete med ein gong du tek dei</string>
+  <string name="prefs_manage_accounts">Behandle kontoar</string>
+  <string name="prefs_pincode">Programpinkode</string>
+  <string name="prefs_pincode_summary">Beskytt klienten din</string>
+  <string name="prefs_instant_upload">Last opp bilete omgåande</string>
+  <string name="prefs_instant_upload_summary">Last opp bilete når du tek dei med kameraet</string>
+  <string name="prefs_instant_video_upload">Last opp film</string>
+  <string name="prefs_instant_video_upload_summary">Last opp film med ein gong du tar dei med kameraet</string>
+  <string name="prefs_log_title">Skru på logging</string>
+  <string name="prefs_log_summary">Brukt til å logga problem</string>
+  <string name="prefs_log_title_history">Logghistorikk</string>
+  <string name="prefs_log_summary_history">Dette viser loggane som er ført</string>
+  <string name="prefs_log_delete_history_button">Slett historikk</string>
   <string name="prefs_help">Hjelp</string>
+  <string name="prefs_recommend">Anbefal til ein ven</string>
+  <string name="prefs_feedback">Tilbakemelding</string>
   <string name="prefs_imprint">Impressum</string>
-  <string name="auth_host_url">Tenaradresse</string>
+  <string name="recommend_subject">Prøv %1$s på smarttelefonen din!</string>
+  <string name="auth_host_url">Tenaradresse https://</string>
   <string name="auth_username">Brukarnamn</string>
   <string name="auth_password">Passord</string>
   <string name="sync_string_files">Filer</string>
   <string name="setup_btn_connect">Kopla til</string>
   <string name="uploader_btn_upload_text">Last opp</string>
   <string name="uploader_wrn_no_account_title">Fann ingen konto</string>
+  <string name="uploader_wrn_no_account_text">Det er ingen %1$s kontoar på eininga di. Gjer vel å konfigurer ein konto først.</string>
   <string name="uploader_wrn_no_account_setup_btn_text">Oppsett</string>
   <string name="uploader_wrn_no_account_quit_btn_text">Avslutt</string>
   <string name="uploader_wrn_no_content_title">Inga innhald å lasta opp</string>
   <string name="uploader_wrn_no_content_text">Mottok ikkje noko innhald. Ingenting å lasta opp.</string>
   <string name="uploader_info_uploading">Lastar opp</string>
+  <string name="file_list_empty">Ingenting her. Last noko opp!</string>
   <string name="filedetails_select_file">Trykk på ei fil for å visa meir informasjon.</string>
   <string name="filedetails_size">Storleik:</string>
   <string name="filedetails_type">Type:</string>
   <string name="filedetails_created">Oppretta:</string>
   <string name="filedetails_modified">Endra:</string>
   <string name="filedetails_download">Last ned</string>
+  <string name="action_share_file">Del lenkje</string>
   <string name="common_yes">Ja</string>
   <string name="common_no">Nei</string>
   <string name="common_ok">Greitt</string>
@@ -37,6 +60,7 @@
   <string name="common_cancel">Avbryt</string>
   <string name="common_save_exit">Lagra &amp; avslutt</string>
   <string name="common_error">Feil</string>
+  <string name="common_error_unknown">Ukjend feil</string>
   <string name="about_title">Om</string>
   <string name="change_password">Endra passord</string>
   <string name="delete_account">Slett konto</string>
   <string name="uploader_upload_in_progress_ticker">Lastar opp …</string>
   <string name="uploader_upload_in_progress_content">%1$d%% lastar opp %2$s</string>
   <string name="uploader_upload_succeeded_ticker">Opplasting fullført</string>
+  <string name="uploader_upload_succeeded_content_single">%1$s vart lasta opp vellukka</string>
   <string name="uploader_upload_failed_ticker">Feil ved opplasting</string>
   <string name="uploader_upload_failed_content_single">Klarte ikkje å lasta %1$s ferdig opp</string>
   <string name="downloader_download_in_progress_ticker">Lastar ned …</string>
   <string name="downloader_download_in_progress_content">%1$d%% lastar ned %2$s</string>
+  <string name="downloader_download_succeeded_ticker">Nedlasting vellukka</string>
+  <string name="downloader_download_succeeded_content">%1$s vart lasta ned vellukka</string>
   <string name="downloader_download_failed_ticker">Feil ved nedlasting</string>
   <string name="downloader_download_failed_content">Klarte ikkje å lasta %1$s ferdig ned</string>
   <string name="common_choose_account">Vel konto</string>
   <string name="sync_fail_ticker">Feil ved synkronisering</string>
   <string name="sync_fail_content">Klarte ikkje å synkronisera ferdig %1$s</string>
   <string name="pincode_enter_pin_code">Ver venleg og skriv inn programpinkoden</string>
+  <string name="pincode_configure_your_pin">Skriv inn programpinkoden</string>
+  <string name="pincode_reenter_your_pincode">Ver venleg å skriv inn programpinkoden på nytt</string>
+  <string name="pincode_remove_your_pincode">Fjern programpinkoden</string>
+  <string name="pincode_mismatch">Programpinkodane er ikkje like</string>
+  <string name="pincode_wrong">Feil programpinkode</string>
+  <string name="pincode_removed">Programpinkode er fjerna</string>
+  <string name="pincode_stored">Programpinkode er lagra</string>
+  <string name="auth_trying_to_login">Prøvar å logge på...</string>
   <string name="auth_no_net_conn_title">Inga nettilkopling</string>
   <string name="auth_nossl_plain_ok_title">Trygg tilkopling ikkje tilgjengeleg.</string>
   <string name="auth_connection_established">Tilkopling oppretta</string>
+  <string name="auth_testing_connection">Testar tilkopling...</string>
+  <string name="auth_not_configured_title">Ugyldig tenarkonfigurasjon</string>
   <string name="auth_unknown_error_title">Ein ukjend feil oppstod!</string>
   <string name="auth_unknown_host_title">Klarte ikkje å finna tenaren</string>
+  <string name="auth_incorrect_path_title">Tenarinstans vart ikkje funnen</string>
   <string name="auth_timeout_title">Tenaren brukte for lang tid på å svara</string>
   <string name="auth_incorrect_address_title">Ugyldig URL</string>
   <string name="auth_ssl_general_error_title">Feil ved SSL-oppstart</string>
   <string name="fd_keep_in_sync">Hald fila oppdatert</string>
   <string name="common_rename">Endra namn</string>
   <string name="common_remove">Fjern</string>
-  <string name="confirmation_remove_alert">Vil du verkeleg fjerna %1$s?</string>
   <string name="confirmation_remove_local">Berre lokalt</string>
   <string name="confirmation_remove_remote">Fjern frå tenaren</string>
+  <string name="confirmation_remove_remote_and_local">Ekstern og lokal</string>
+  <string name="remove_success_msg">Fjerning vellukka</string>
+  <string name="remove_fail_msg">Fjerning mislukka</string>
   <string name="rename_server_fail_msg">Klarte ikkje å fullføra omdøyping</string>
-  <string name="create_dir_fail_msg">Klarte ikkje å oppretta mappa</string>
   <string name="wait_a_moment">Vent litt</string>
+  <string name="filedisplay_unexpected_bad_get_content">Uventa problem ; ver venleg å vel fila frå ein annan app</string>
   <string name="filedisplay_no_file_selected">Inga fil valt</string>
   <string name="ssl_validator_header">Klarte ikkje å stadfesta identiteten til nettstaden</string>
   <string name="ssl_validator_reason_cert_not_trusted">– Tenarsertifikatet er ikkje klarert</string>
   <string name="ssl_validator_reason_hostname_not_verified">– URL-en stemmer ikkje med tenarnamnet i sertifikatet</string>
   <string name="ssl_validator_question">Vil du stola på dette sertifikatet uansett?</string>
   <string name="ssl_validator_not_saved">Klarte ikkje å lagra sertifikatet</string>
+  <string name="ssl_validator_btn_details_see">Detaljar</string>
   <string name="instant_upload_on_wifi">Berre last opp bilete over WiFi</string>
+  <string name="activity_chooser_send_file_title">Send</string>
+  <string name="empty"></string>
+  <string name="prefs_category_accounts">Kontoar</string>
+  <string name="saml_authentication_wrong_pass">Feil passord</string>
+  <string name="move_choose_button_text">Vel</string>
+  <string name="prefs_category_security">Tryggleik</string>
 </resources>
index 9bdc969..84ca498 100644 (file)
@@ -2,7 +2,6 @@
 <resources>
   <string name="actionbar_upload">Amontcarga</string>
   <string name="actionbar_upload_files">Fichièrs</string>
-  <string name="actionbar_mkdir">Crea un repertòri</string>
   <string name="actionbar_settings">Configuracion</string>
   <string name="prefs_category_general">General</string>
   <string name="prefs_category_more">Mai d\'aquò</string>
@@ -18,6 +17,7 @@
   <string name="uploader_wrn_no_account_setup_btn_text">Configuracion</string>
   <string name="uploader_wrn_no_account_quit_btn_text">Quita</string>
   <string name="uploader_info_uploading">Al amontcargar</string>
+  <string name="file_list_empty">Pas res dedins. Amontcarga qualquaren</string>
   <string name="filedetails_size">Talha :</string>
   <string name="filedetails_type">Tipe :</string>
   <string name="filedetails_created">Creat :</string>
   <string name="delete_account">Escafa lo compte</string>
   <string name="create_account">Crea un compte</string>
   <string name="upload_chooser_title">Avalcarga dempuèi ...</string>
-  <string name="uploader_info_dirname">Nom de repertòri</string>
   <string name="uploader_upload_in_progress_ticker">Al avalcargar ...</string>
   <string name="uploader_upload_succeeded_ticker">Capitada d\'avalcargar</string>
   <string name="common_choose_account">Causís lo compte</string>
   <string name="pincode_enter_pin_code">Dintras ton PIN d\'App, se te plai</string>
   <string name="common_rename">Torna nomenar</string>
+  <string name="empty"></string>
+  <string name="prefs_category_accounts">Comptes</string>
+  <string name="move_choose_button_text">Causís</string>
 </resources>
diff --git a/res/values-or-rIN/strings.xml b/res/values-or-rIN/strings.xml
new file mode 100644 (file)
index 0000000..56e55a1
--- /dev/null
@@ -0,0 +1,4 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<resources>
+  <string name="empty"></string>
+</resources>
index 7d9f60a..dc0b9e7 100644 (file)
@@ -7,22 +7,20 @@
   <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="prefs_category_general">ਆਮ</string>
   <string name="prefs_accounts">ਅਕਾਊਂਟ</string>
   <string name="prefs_log_title">ਲਾਗ ਰੱਖਣਾ ਚਾਲੂ</string>
   <string name="prefs_log_title_history">ਲਾਗ ਰੱਖਣ ਅਤੀਤ</string>
   <string name="prefs_log_delete_history_button">ਅਤੀਤ ਹਟਆਓ</string>
-  <string name="auth_host_url">ਸਰਵਰ ਐਡਰੈਸ</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="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_setup_btn_text">ਸੈਟਅੱਪ</string>
   <string name="uploader_wrn_no_account_quit_btn_text">ਬਾਹਰ</string>
@@ -51,7 +49,6 @@
   <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="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_local">ਕੇਵਲ ਲੋਕਲ</string>
   <string name="confirmation_remove_remote">ਸਰਵਰ ਤੋਂ ਹਟਾਓ</string>
   <string name="confirmation_remove_remote_and_local">ਰਿਮੋਟ ਤੇ ਲੋਕਲ</string>
-  <string name="create_dir_fail_msg">ਡਾਇਰੈਕਟਰੀ ਬਣਾਈ ਨਹੀਂ ਜਾ ਸਕੀ</string>
   <string name="wait_a_moment">ਪਲ਼ ਭਰ ਲਈ ਉਡੀਕੋ</string>
   <string name="filedisplay_no_file_selected">ਕੋਈ ਫਾਇਲ ਨਹੀਂ ਚੁਣੀ ਗਈ</string>
   <string name="ssl_validator_header">ਇਹ ਸਾਈਟ ਦੀ ਪਛਾਣ ਦੀ ਜਾਂਚ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕੀ ਹੈ</string>
   <string name="conflict_overwrite">ਉੱਤੇ ਲਿਖੋ</string>
   <string name="conflict_dont_upload">ਅੱਪਲੋਡ ਨਾ ਕਰੋ</string>
   <string name="preview_image_description">ਚਿੱਤਰ ਝਲਕ</string>
-  <string name="failed_upload_all_cb">ਸਭ ਚੁਣੋ</string>
+  <string name="activity_chooser_send_file_title">ਭੇਜੋ</string>
+  <string name="empty"></string>
+  <string name="prefs_category_accounts">ਅਕਾਊਂਟ</string>
+  <string name="move_choose_button_text">ਚੁਣੋ</string>
 </resources>
index e4b5ce8..8c0a987 100644 (file)
@@ -4,22 +4,25 @@
   <string name="about_version">wersja %1$s</string>
   <string name="actionbar_sync">Odśwież konto</string>
   <string name="actionbar_upload">Wyślij plik</string>
-  <string name="actionbar_upload_from_apps">Zasoby innych aplikacji</string>
+  <string name="actionbar_upload_from_apps">Zawartość z innych aplikacji</string>
   <string name="actionbar_upload_files">Pliki</string>
   <string name="actionbar_open_with">Otwórz za pomocą</string>
-  <string name="actionbar_mkdir">Nowy katalog</string>
+  <string name="actionbar_mkdir">Nowy folder</string>
   <string name="actionbar_settings">Ustawienia</string>
   <string name="actionbar_see_details">Szczegóły</string>
+  <string name="actionbar_send_file">Wyślij</string>
   <string name="prefs_category_general">Ogólne</string>
   <string name="prefs_category_more">Więcej</string>
   <string name="prefs_accounts">Konta</string>
   <string name="prefs_manage_accounts">Zarządzaj kontami</string>
   <string name="prefs_pincode">PIN aplikacji</string>
-  <string name="prefs_pincode_summary">Chroń klienta</string>
-  <string name="prefs_instant_upload">Włącz natychmiastowe wysyłanie</string>
-  <string name="prefs_instant_upload_summary">Natychmiast wysyłaj zdjęcia zrobione aparatem</string>
+  <string name="prefs_pincode_summary">Chroń swojego klienta</string>
+  <string name="prefs_instant_upload">natychmiastowa wysyłka obrazków</string>
+  <string name="prefs_instant_upload_summary">Wysyłaj od razu zdjęcia zrobione aparatem</string>
+  <string name="prefs_instant_video_upload">Natychmiastowa wysyłka wideo</string>
+  <string name="prefs_instant_video_upload_summary">Wysyłaj od razu filmy nakręcone aparatem</string>
   <string name="prefs_log_title">Włączone Logi</string>
-  <string name="prefs_log_summary">To jest używane do logów problemów</string>
+  <string name="prefs_log_summary">To jest używane do logowania problemów</string>
   <string name="prefs_log_title_history">Zapisuj historię</string>
   <string name="prefs_log_summary_history">To pokazuje zapisane logi</string>
   <string name="prefs_log_delete_history_button">Usuń histrorię</string>
@@ -28,9 +31,9 @@
   <string name="prefs_feedback">Wsparcie</string>
   <string name="prefs_imprint">Stopka</string>
   <string name="recommend_subject">Wypróbuj %1$s na swoim smartphonie!</string>
-  <string name="recommend_text">Chcę was zaprosić do korzystania z %1$ s na twoim smartfonie!\nPobierz tutaj: %2$s</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_host_url">Adres Serwera</string>
+  <string name="auth_host_url">Adres serwera https://...</string>
   <string name="auth_username">Nazwa użytkownika</string>
   <string name="auth_password">Hasło</string>
   <string name="auth_register">Nowe %1$s?</string>
@@ -46,7 +49,9 @@
   <string name="uploader_wrn_no_content_text">Nie otrzymano danych. Nie ma nic do wysłania.</string>
   <string name="uploader_error_forbidden_content">%1$s nie ma dostępu do udostępnionych treści</string>
   <string name="uploader_info_uploading">Wysyłanie</string>
-  <string name="file_list_empty">Nie ma plików w tym katalogu.⏎ Nowe pliki można dodać wybierając w menu Wyślij.</string>
+  <string name="file_list_empty">Pusto. Wyślij coś!</string>
+  <string name="file_list_loading">Ładowanie...</string>
+  <string name="local_file_list_empty">Nie ma plików w tym folderze.</string>
   <string name="filedetails_select_file">Dotknij plik aby wyświetlić dodatkowe informacje</string>
   <string name="filedetails_size">Rozmiar:</string>
   <string name="filedetails_type">Typ:</string>
@@ -55,6 +60,8 @@
   <string name="filedetails_download">Pobierz</string>
   <string name="filedetails_sync_file">Odśwież plik</string>
   <string name="filedetails_renamed_in_upload_msg">Podczas wysyłania nazwa pliku została zmieniona na %1$s</string>
+  <string name="action_share_file">Udostępnij link</string>
+  <string name="action_unshare_file">Anuluj udostępnianie</string>
   <string name="common_yes">Tak</string>
   <string name="common_no">Nie</string>
   <string name="common_ok">OK</string>
   <string name="delete_account">Usuń konto</string>
   <string name="create_account">Utwórz konto</string>
   <string name="upload_chooser_title">Wyślij plik z …</string>
-  <string name="uploader_info_dirname">Nazwa katalogu</string>
+  <string name="uploader_info_dirname">Nazwa folderu</string>
   <string name="uploader_upload_in_progress_ticker">Wysyłam…</string>
   <string name="uploader_upload_in_progress_content">%1$d%% Wysyłanie %2$s</string>
   <string name="uploader_upload_succeeded_ticker">Wysyłanie zakończone powodzeniem</string>
   <string name="uploader_upload_succeeded_content_single">Wysyłanie %1$s zakończone sukcesem</string>
   <string name="uploader_upload_failed_ticker">Wysyłanie nie powiodło się</string>
   <string name="uploader_upload_failed_content_single">Wysyłanie %1$s nie powiodło się</string>
+  <string name="uploader_upload_failed_credentials_error">Przesyłanie nie powiodło się, musisz się ponownie zalogować</string>
   <string name="downloader_download_in_progress_ticker">Pobieranie …</string>
   <string name="downloader_download_in_progress_content">%1$d%% Pobieranie %2$s</string>
   <string name="downloader_download_succeeded_ticker">Pobieranie zakończone</string>
   <string name="downloader_download_succeeded_content">Pobrano %1$s plików</string>
   <string name="downloader_download_failed_ticker">Pobieranie nieudane</string>
   <string name="downloader_download_failed_content">Pobieranie %1$s nie powiodło się</string>
-  <string name="downloader_not_downloaded_yet">Nie poprane jeszcze</string>
+  <string name="downloader_not_downloaded_yet">Jeszcze nie pobrane</string>
+  <string name="downloader_download_failed_credentials_error">Ściganie nie powiodło się, musisz się ponownie zalogować</string>
   <string name="common_choose_account">Wybierz konto</string>
   <string name="sync_fail_ticker">Błąd synchronizacji</string>
-  <string name="sync_fail_content">Nie można było ukończyć synchronizacji %1$s </string>
+  <string name="sync_fail_ticker_unauthorized">Synchronizacja nie powiodła się, musisz się zalogować ponownie</string>
+  <string name="sync_fail_content">Nie można było dokończyć synchronizacji %1$s </string>
   <string name="sync_fail_content_unauthorized">Niepoprawne hasło dla %1$s</string>
   <string name="sync_conflicts_in_favourites_ticker">Znaleziono konflikty</string>
   <string name="sync_conflicts_in_favourites_content">%1$d synchronizowanych plików nie może zostać zsynchronizowanych</string>
   <string name="sync_fail_in_favourites_ticker">Synchronizacja plików nie powiodła się</string>
   <string name="sync_fail_in_favourites_content">Zawartość %1$d plików nie może zostać synchronizowana (%2$d konfliktów)</string>
   <string name="sync_foreign_files_forgotten_ticker">Niektóre lokalne pliki zostały zgubione.</string>
-  <string name="sync_foreign_files_forgotten_content">%1$d plików z %2$s katalogu nie może zostać skopiowana do niego</string>
-  <string name="sync_foreign_files_forgotten_explanation">\"W wersji 1.3.16, pliki załadowane z tego urządzenia są skopiowane do lokalnego folderu %1$s aby zapobiec utracie danych, gdy pojedynczy plik jest synchronizowany z kilku kont.⏎ ⏎ Ze zwględu na tą zmianę, wszystkie pliki załadowane w poprzedniej wersji tej aplikacji były kopiowane do folderu %2$s. Jednakże błąd podczas synchronizacji spowodował przerwanie procesu. Możesz zostawić plik(i) i usunąć link do %3$s, lub przenieść plik(i) to katalogu %1$s i zostawić link do %4$s.⏎ ⏎ Lista poniżej zawiera lokalne i zdalne pliki, które są podlinkowane do %5$s.</string>
+  <string name="sync_foreign_files_forgotten_content">%1$d plików z folderu %2$s nie udało się się przekopiować</string>
+  <string name="sync_foreign_files_forgotten_explanation">Od wersji 1.3.16, pliki wysyłane z tego urządzenia są kopiowane do lokalnego folderu %1$s aby zapobiec utracie danych gdy pojedynczy plik jest synchronizowany z wieloma kontami.\n\nZ powodu tej zmiany, wszystkie pliki wysłane za pomocą poprzedniej wersji tej aplikacji były kopiowane do folderu %2$s. Jednakże, błąd uniemożliwiał dokończenie tej operacji podczas synchronizacji konta. Możesz albo pozostawić plik(i) tak jak jest i usunąć link do %3$s lub przenieść plik(i) do folderu %1$s i pozostawić link do %4$s.\n\nPoniżej plik(i) lokalny i plik(i) zdalny w %5$s, do którego zostały zlinkowane.</string>
   <string name="sync_current_folder_was_removed">Folder  %1$s nie istnieje.</string>
   <string name="foreign_files_move">Przenieś wszystko</string>
   <string name="foreign_files_success">Wszystkie pliki zostały przeniesione</string>
   <string name="foreign_files_fail">Niektóre pliki nie mogły być przeniesione</string>
-  <string name="foreign_files_local_text">Lokalna ścieżka: %1$s</string>
-  <string name="foreign_files_remote_text">Zdalna ścieżka: %1$s</string>
+  <string name="foreign_files_local_text">Lokalnie: %1$s</string>
+  <string name="foreign_files_remote_text">Zdalnie: %1$s</string>
   <string name="upload_query_move_foreign_files">Nie ma wystarczająco miejśca, aby skopiować zaznaczone pliki do folderu %1$s. Chciałbyś je przenieść?</string>
   <string name="pincode_enter_pin_code">Podaj PIN aplikacji</string>
   <string name="pincode_configure_your_pin">Wpisz PIN aplikacji</string>
   <string name="pincode_removed">Usunięto PIN aplikacji</string>
   <string name="pincode_stored">Zapisano PIN aplikacji</string>
   <string name="media_notif_ticker">%1$s odtwarzacz muzyki</string>
-  <string name="media_state_playing">%1$s (odtwarzane)</string>
-  <string name="media_state_loading">%1$s (wczytywane)</string>
+  <string name="media_state_playing">%1$s (odtwarzany)</string>
+  <string name="media_state_loading">%1$s (wczytywany)</string>
   <string name="media_event_done">%1$s odtwarzanie zakończone</string>
   <string name="media_err_nothing_to_play">Nie znaleziono plików multimedialnych</string>
   <string name="media_err_no_account">Nie znaleziono konta</string>
   <string name="media_err_io">Błąd odczytu pliku multimedialnego</string>
   <string name="media_err_malformed">Błąd kodowania pliku multimedialnego</string>
   <string name="media_err_timeout">Upłynął limit czasu podczas próby odtwarzania</string>
-  <string name="media_err_invalid_progressive_playback">Ni udało się przesłać pliku multimedialnego</string>
+  <string name="media_err_invalid_progressive_playback">Plik mediów nie może być przesyłany strumieniowo</string>
   <string name="media_err_unknown">Plik multimediów nie może być odtworzony we wbudowanym odtwarzaczu</string>
   <string name="media_err_security_ex">Błąd zabezpieczeń podczas próby odtworzenia %1$s</string>
   <string name="media_err_io_ex">Błąd wprowadzania podczas próby odtworzenia %1$s</string>
   <string name="media_rewind_description">Przycisk przewijania</string>
   <string name="media_play_pause_description">Przycisk odtwarzania / pauzowania</string>
   <string name="media_forward_description">Przycisk przewijania do przodu</string>
+  <string name="auth_getting_authorization">Pobieram autoryzację...</string>
   <string name="auth_trying_to_login">Próbuję się zalogować...</string>
   <string name="auth_no_net_conn_title">Brak połączenia sieciowego</string>
   <string name="auth_nossl_plain_ok_title">Nie można nawiązać bezpiecznego połączenia.</string>
   <string name="auth_expired_saml_sso_token_toast">Twoja sesja wygasła. Proszę zaloguj się ponownie</string>
   <string name="auth_connecting_auth_server">Łączenie z serwerem autoryzacji...</string>
   <string name="auth_unsupported_auth_method">Serwer nie obsługuje tej metody autoryzacji</string>
-  <string name="auth_unsupported_multiaccount">%1$s nie wspiera multikont</string>
+  <string name="auth_unsupported_multiaccount">%1$s nie wspiera wielu kont</string>
+  <string name="auth_fail_get_user_name">Twój serwer nie zwraca prawidłowego id użytkownika, proszę skontaktuj się z administratorem
+       </string>
+  <string name="auth_can_not_auth_against_server">Nie można autoryzować przy użyciu tego serwera</string>
   <string name="fd_keep_in_sync">Automatyczne aktualizuj plik</string>
   <string name="common_rename">Zmień nazwę</string>
   <string name="common_remove">Usuń</string>
-  <string name="confirmation_remove_alert">Czy na pewno chcesz usunąć %1$s ?</string>
-  <string name="confirmation_remove_folder_alert">Czy usunąć %1$s oraz jego zawartość?</string>
+  <string name="confirmation_remove_alert">Czy naprawdę chcesz usunąć %1$s?</string>
+  <string name="confirmation_remove_folder_alert">Czy naprawdę chcesz usunąć %1$s i jego zawartość?</string>
   <string name="confirmation_remove_local">Tylko lokalnie</string>
   <string name="confirmation_remove_folder_local">Tylko zasoby lokalne</string>
   <string name="confirmation_remove_remote">Usuń z serwera</string>
   <string name="rename_server_fail_msg">Zmiana nazwy nie powiodła się</string>
   <string name="sync_file_fail_msg">Nie można sprawdzić zdalnego pliku</string>
   <string name="sync_file_nothing_to_do_msg">Zawartość pliku została już synchronizowana</string>
-  <string name="create_dir_fail_msg">Nie można utworzyć katalogu</string>
+  <string name="create_dir_fail_msg">Folder nie może zostać utworzony</string>
+  <string name="filename_forbidden_characters">Znaki zabronione: / \\ &lt; &gt; : \" | ? *</string>
+  <string name="filename_empty">Nazwa pliku nie może być pusta.</string>
   <string name="wait_a_moment">Poczekaj chwilę</string>
   <string name="filedisplay_unexpected_bad_get_content">Nieoczekiwany problem; spróbuj wybrać plik z innej aplikacji</string>
   <string name="filedisplay_no_file_selected">Nie wybrano żadnych plików</string>
+  <string name="activity_chooser_title">Wyślij link do ...</string>
   <string name="oauth_check_onoff">Loguj przez oAuth2</string>
   <string name="oauth_login_connection">Łączenie z serwerem oAuth2...</string>
   <string name="ssl_validator_header">Nie można zweryfikować tożsamości strony</string>
   <string name="ssl_validator_label_validity_to">Do:</string>
   <string name="ssl_validator_label_signature">Sygnatura:</string>
   <string name="ssl_validator_label_signature_algorithm">Algorytm:</string>
+  <string name="ssl_validator_null_cert">Nie można wyświetlić certyfikatu.</string>
+  <string name="ssl_validator_no_info_about_error">- Brak informacji o błędzie</string>
   <string name="placeholder_sentence">Tekst zastępczy</string>
   <string name="placeholder_filename">placeholder.txt</string>
   <string name="placeholder_filetype">Obraz PNG</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">Wysyłaj zdjęcia tylko przez WiFi</string>
+  <string name="instant_video_upload_on_wifi">Aktualizuj filmy tylko przez WiFi</string>
   <string name="instant_upload_path">/InstantUpload</string>
   <string name="conflict_title">Konflikt aktualizacji</string>
   <string name="conflict_message">Zdalny plik %s nie jest zsynchronizowany z plikiem lokalnym. Kontynuując zastąpisz zawartość pliku na serwerze.</string>
   <string name="conflict_overwrite">Zastąp</string>
   <string name="conflict_dont_upload">Nie wysyłaj</string>
   <string name="preview_image_description">Podgląd</string>
-  <string name="preview_image_error_unknown_format">Obraz nie może zostać wyświetlony</string>
-  <string name="error__upload__local_file_not_copied">%1$s nie może zostać skopiowany do lokalnego %2$s katalogu</string>
-  <string name="actionbar_failed_instant_upload">Autoprzesyłanie nieudane\"</string>
-  <string name="failed_upload_headline_text">Błąd automatycznego przesyłania</string>
-  <string name="failed_upload_headline_hint">Podsumowanie wszystkich nieudanych transferów</string>
-  <string name="failed_upload_all_cb">zaznacz wszystkie</string>
-  <string name="failed_upload_headline_retryall_btn">spróbuj zaznaczyć wszystkie</string>
-  <string name="failed_upload_headline_delete_all_btn">usuń wszystko z kolejki wysyłania</string>
-  <string name="failed_upload_retry_text">ponów wysyłanie obrazu:</string>
-  <string name="failed_upload_load_more_images">Wczytaj więcej obrazów</string>
-  <string name="failed_upload_retry_do_nothing_text">nic nie rób, ponieważ nie jesteś online, nie możesz przesyłać plików</string>
-  <string name="failed_upload_failure_text">Komunikat błędu:</string>
-  <string name="failed_upload_quota_exceeded_text">Proszę sprawdź ustawienia serwera, możliwe że przekroczyłes limit wielkości pliku</string>
+  <string name="preview_image_error_unknown_format">Ten obrazek nie może zostać wyświetlony</string>
+  <string name="error__upload__local_file_not_copied">%1$s nie może zostać skopiowany do lokalnego folderu %2$s</string>
+  <string name="share_link_no_support_share_api">Przepraszamy, ale współdzielenie nie jest włączone na Twoim serwerze. Proszę skontaktuj się z
+               administratorem.</string>
+  <string name="share_link_file_no_exist">Nie można udostępnić. Proszę sprawdzić, czy plik istnieje</string>
+  <string name="share_link_file_error">Wystąpił błąd podczas udostępniania tego pliku lub folderu.</string>
+  <string name="unshare_link_file_no_exist">Nie można wyłączyć udostępniania. Proszę sprawdzić, czy plik istnieje</string>
+  <string name="unshare_link_file_error">Wystąpił błąd podczas anulowania udostępniania tego pliku lub folderu.</string>
+  <string name="activity_chooser_send_file_title">Wyślij</string>
+  <string name="copy_link">Skopiuj link</string>
+  <string name="clipboard_text_copied">Skopiuj do schowka</string>
+  <string name="error_cant_bind_to_operations_service">Błąd krytyczny: nie można wykonać operacji</string>
+  <string name="network_error_socket_exception">Pojawił się błąd podczas łączenia z serwerem.</string>
+  <string name="network_error_socket_timeout_exception">Pojawił się błąd podczas oczekiwania na serwer, operacja nie mogła zostać wykonana</string>
+  <string name="network_error_connect_timeout_exception">Pojawił się błąd podczas oczekiwania na serwer, operacja nie mogła zostać wykonana</string>
+  <string name="network_host_not_available">Nie można dokończyć operacji, serwer jest niedostępny</string>
+  <string name="empty"></string>
+  <string name="forbidden_permissions">Nie masz uprawnień %s</string>
+  <string name="forbidden_permissions_rename">do zmiany nazwy tego pliku</string>
+  <string name="forbidden_permissions_delete">do usuwania tego pliku</string>
+  <string name="share_link_forbidden_permissions">do współdzielenia tego pliku</string>
+  <string name="unshare_link_forbidden_permissions">do zniesienia współdzielenia tego pliku</string>
+  <string name="forbidden_permissions_create">do utworzenia tego pliku</string>
+  <string name="uploader_upload_forbidden_permissions">do wgrania tego folderu</string>
+  <string name="downloader_download_file_not_found">Ten plik nie jest już dostępny na serwerze</string>
+  <string name="prefs_category_accounts">Konta</string>
+  <string name="prefs_add_account">Dodaj konto</string>
+  <string name="actionbar_logger">Logi</string>
+  <string name="log_send_history_button">Wyślij historię</string>
+  <string name="log_progress_dialog_text">Ładuję dane...</string>
+  <string name="saml_authentication_required_text">Wymagana autoryzacja</string>
+  <string name="saml_authentication_wrong_pass">Złe hasło</string>
+  <string name="actionbar_move">Przenieś</string>
+  <string name="file_list_empty_moving">Nic tu nie ma. Możesz dodać folder!</string>
+  <string name="move_choose_button_text">Wybierz</string>
+  <string name="move_file_not_found">Nie można przenieść. Proszę sprawdzić, czy plik istnieje</string>
+  <string name="move_file_invalid_into_descendent">Nie jest możliwe przeniesienie folderu do potomka</string>
+  <string name="move_file_invalid_overwrite">Plik istnieje już w folderze docelowym</string>
+  <string name="move_file_error">Pojawił się błąd podczas próby przeniesienia tego pliku lub folderu</string>
+  <string name="forbidden_permissions_move">aby przenieść ten plik</string>
+  <string name="prefs_category_security">Bezpieczeństwo</string>
 </resources>
index ed892d7..3ffb84b 100644 (file)
@@ -3,24 +3,27 @@
   <string name="about_android">%1$s Android App</string>
   <string name="about_version">versão %1$s</string>
   <string name="actionbar_sync">Atualização de conta</string>
-  <string name="actionbar_upload">Upload</string>
+  <string name="actionbar_upload">Enviar</string>
   <string name="actionbar_upload_from_apps">Conteúdo de outros apps</string>
   <string name="actionbar_upload_files">Arquivos</string>
   <string name="actionbar_open_with">Abrir com</string>
-  <string name="actionbar_mkdir">Criar pasta</string>
-  <string name="actionbar_settings">Ajustes</string>
+  <string name="actionbar_mkdir">Nova pasta</string>
+  <string name="actionbar_settings">Configurações</string>
   <string name="actionbar_see_details">Detalhes</string>
+  <string name="actionbar_send_file">Enviar</string>
   <string name="prefs_category_general">Geral</string>
   <string name="prefs_category_more">Mais</string>
   <string name="prefs_accounts">Contas</string>
-  <string name="prefs_manage_accounts">Gerenciar contas</string>
+  <string name="prefs_manage_accounts">Gerenciar Contas</string>
   <string name="prefs_pincode">PIN App</string>
   <string name="prefs_pincode_summary">Proteja seu cliente</string>
-  <string name="prefs_instant_upload">Habilitar upload instantâneo</string>
-  <string name="prefs_instant_upload_summary">Instantaneamente faça upload das fotos tiradas pela câmera</string>
-  <string name="prefs_log_title">Habilitar conexão</string>
-  <string name="prefs_log_summary">Isto é usado para registrar os problemas</string>
-  <string name="prefs_log_title_history">História de Registro</string>
+  <string name="prefs_instant_upload">Envio instantâneo de imagem</string>
+  <string name="prefs_instant_upload_summary">Enviar instantaneamente fotos tiradas com a camera</string>
+  <string name="prefs_instant_video_upload">Envio instantâneo de vídeos</string>
+  <string name="prefs_instant_video_upload_summary">Enviar instantaneamente vídeos feitos com a camera</string>
+  <string name="prefs_log_title">Habilitar Conexão</string>
+  <string name="prefs_log_summary">Isto é usado para registrar(log) os problemas</string>
+  <string name="prefs_log_title_history">História de Registro(log)</string>
   <string name="prefs_log_summary_history">Isso mostra os registros gravados</string>
   <string name="prefs_log_delete_history_button">Excluir Histórico</string>
   <string name="prefs_help">Ajuda</string>
   <string name="prefs_feedback">Feedback</string>
   <string name="prefs_imprint">Imprint</string>
   <string name="recommend_subject">Tentar %1$s em seu smartfone!</string>
-  <string name="recommend_text">Gostaria de lhe convidar para usar %1$s em seu smartfone!\nBaixe aqui: %2$s</string>
+  <string name="recommend_text">Gostaria de convida-lo a usar %1$s em seu smartphone!\nBaixe aqui: %2$s</string>
   <string name="auth_check_server">Verificar Servidor</string>
-  <string name="auth_host_url">Endereço do servidor</string>
+  <string name="auth_host_url">Endereço do servidor https://...</string>
   <string name="auth_username">Nome de usuário</string>
   <string name="auth_password">Senha</string>
   <string name="auth_register">Novo para %1$s?</string>
   <string name="sync_string_files">Arquivos</string>
   <string name="setup_btn_connect">Conectar</string>
-  <string name="uploader_btn_upload_text">Upload</string>
+  <string name="uploader_btn_upload_text">Enviar</string>
   <string name="uploader_top_message">Escolher pasta para enviar:</string>
   <string name="uploader_wrn_no_account_title">Nenhuma conta encontrada</string>
   <string name="uploader_wrn_no_account_text">Não existem contas %1$s no seu dispositivo. Por favor, configure uma conta primeiro.</string>
   <string name="uploader_wrn_no_account_setup_btn_text">Instalação</string>
   <string name="uploader_wrn_no_account_quit_btn_text">Sair</string>
-  <string name="uploader_wrn_no_content_title">Sem conteúdo para enviar</string>
-  <string name="uploader_wrn_no_content_text">Nenhum foi recebido. Nada para enviar.</string>
-  <string name="uploader_error_forbidden_content">%1$s não é permitido a acessar o conteúdo compartilhado</string>
+  <string name="uploader_wrn_no_content_title">Nenhum conteúdo para enviar</string>
+  <string name="uploader_wrn_no_content_text">Nenhum conteúdo foi recebido. Nada para enviar.</string>
+  <string name="uploader_error_forbidden_content">%1$s não é permitido acessar o conteúdo compartilhado</string>
   <string name="uploader_info_uploading">Enviando</string>
-  <string name="file_list_empty">Não existe arquivos nesta pasta\nNovos arquivos podem ser adicionados com a opção do menu \"Enviar\"</string>
+  <string name="file_list_empty">Nada aqui. Envie alguma coisa!</string>
+  <string name="file_list_loading">Carregando...</string>
+  <string name="local_file_list_empty">Não existe nenhum arquivo nesta pasta.</string>
   <string name="filedetails_select_file">Toque em um arquivo para mostrar informações adicionais.</string>
   <string name="filedetails_size">Tamanho:</string>
   <string name="filedetails_type">Tipo:</string>
   <string name="filedetails_created">Criado:</string>
   <string name="filedetails_modified">Modificado:</string>
-  <string name="filedetails_download">Download</string>
+  <string name="filedetails_download">Baixar</string>
   <string name="filedetails_sync_file">Atualizar arquivo</string>
-  <string name="filedetails_renamed_in_upload_msg">Arquivo foi renomeado para %1$s durante o upload</string>
+  <string name="filedetails_renamed_in_upload_msg">Arquivo foi renomeado para %1$s durante o envio</string>
+  <string name="action_share_file">Compartilhar link</string>
+  <string name="action_unshare_file">Descompartilhar o link</string>
   <string name="common_yes">Sim</string>
   <string name="common_no">Não</string>
   <string name="common_ok">OK</string>
-  <string name="common_cancel_download">Cancelar download</string>
-  <string name="common_cancel_upload">Cancelar upload</string>
+  <string name="common_cancel_download">Cancelar download</string>
+  <string name="common_cancel_upload">Cancelar envio</string>
   <string name="common_cancel">Cancelar</string>
   <string name="common_save_exit">Salvar &amp; Sair</string>
   <string name="common_error">Erro</string>
   <string name="delete_account">Remover conta</string>
   <string name="create_account">Criar conta</string>
   <string name="upload_chooser_title">Enviar de …</string>
-  <string name="uploader_info_dirname">Nome do diretório</string>
+  <string name="uploader_info_dirname">Nome da pasta</string>
   <string name="uploader_upload_in_progress_ticker">Enviando …</string>
   <string name="uploader_upload_in_progress_content">%1$d%% Enviando %2$s</string>
   <string name="uploader_upload_succeeded_ticker">Envio bem sucedido</string>
   <string name="uploader_upload_succeeded_content_single">%1$s foi enviado com sucesso</string>
   <string name="uploader_upload_failed_ticker">Falha no envio</string>
-  <string name="uploader_upload_failed_content_single">Envio de %1$s não pôde ser completado</string>
+  <string name="uploader_upload_failed_content_single">Envio de %1$s não pôde ser finalizado</string>
+  <string name="uploader_upload_failed_credentials_error">O envio falhou, você precisa reconectar</string>
   <string name="downloader_download_in_progress_ticker">Baixando …</string>
   <string name="downloader_download_in_progress_content">%1$d%% Baixando %2$s</string>
   <string name="downloader_download_succeeded_ticker">Download bem sucedido</string>
   <string name="downloader_download_failed_ticker">Download falhou</string>
   <string name="downloader_download_failed_content">Download de %1$s não pôde ser concluído</string>
   <string name="downloader_not_downloaded_yet">Não baixado ainda</string>
+  <string name="downloader_download_failed_credentials_error">O download falhou, você precisa reconectar</string>
   <string name="common_choose_account">Escolha a conta</string>
   <string name="sync_fail_ticker">Sincronização falhou</string>
+  <string name="sync_fail_ticker_unauthorized">A sincronização falhou, você necessita se reconectar</string>
   <string name="sync_fail_content">Sincronização de %1$s não pôde ser completada</string>
   <string name="sync_fail_content_unauthorized">Senha inválida para %1$s</string>
   <string name="sync_conflicts_in_favourites_ticker">Conflitos encontrados</string>
   <string name="sync_fail_in_favourites_ticker">Falha ao manter arquivos sincronizados</string>
   <string name="sync_fail_in_favourites_content">O conteúdo de %1$d arquivos não puderam ser sincronizados (%2$d conflitos)</string>
   <string name="sync_foreign_files_forgotten_ticker">Alguns arquivos locais foram esquecidos</string>
-  <string name="sync_foreign_files_forgotten_content">%1$d arquivos da pasta %2$s não foram copiados</string>
-  <string name="sync_foreign_files_forgotten_explanation">A partir da versão 1.3.16, os arquivos enviados a partir deste dispositivo são copiados para a pasta local %1$s para evitar a perda de dados quando um único arquivo é sincronizado com várias contas. \n\nDevido a essa mudança, todos os arquivos carregados em versões anteriores deste aplicativo foram copiados para a pasta %2$s. No entanto, um erro evita a conclusão desta operação durante a conta de sincronização. Você pode tanto deixar os arquivos como é e remover o link para %3$s, ou mover o arquivos para o diretório %1$s e manter o link para %4$s. \n\nListados abaixo estão os arquivos locais, e os arquivos remotos em %5$s que estavam vinculados.</string>
+  <string name="sync_foreign_files_forgotten_content">%1$d arquivos de %2$s não puderam ser copiados para a pasta</string>
+  <string name="sync_foreign_files_forgotten_explanation">A partir da versão 1.3.16, os arquivos enviados a partir deste dispositivo são copiados para a pasta local %1$s para evitar a perda de dados quando um único arquivo é sincronizado com várias contas. \n\nDevido a esta mudança, todos os arquivos enviados em versões anteriores deste aplicativo foram copiados para a pasta %2$s . No entanto, um erro impediu a conclusão desta operação durante a sincronização de conta. Você pode tanto deixar os arquivos como são e remover o link para %3$s, ou mover os arquivo(s) para a pasta %1$s e manter o link para %4$s. \n\nListadas abaixo são os arquivo(s) locais, e os arquivo(s) remoto(s) em %5$s que estavam vinculados.</string>
   <string name="sync_current_folder_was_removed">Pasta %1s não existe mais</string>
   <string name="foreign_files_move">Mover todos</string>
   <string name="foreign_files_success">Todos os arquivos foram movidos</string>
   <string name="foreign_files_fail">Alguns arquivos não puderam ser movidos</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">Não há espaço suficiente para copiar os arquivos selecionados para a pasta %1$s. Ao invés disso, gostaria de movê-los?</string>
+  <string name="upload_query_move_foreign_files">Não existe espaço suficiente para copiar os arquivos selecionados para a pasta %1$s. Você gostaria de ao invés de copiar movê-los? </string>
   <string name="pincode_enter_pin_code">Por favor, insira o seu PIN de Aplicativo</string>
   <string name="pincode_configure_your_pin">Insira seu PIN de Aplicativo</string>
   <string name="pincode_configure_your_pin_explanation">O PIN (senha) será solicitado toda vez que o aplicativo for iniciado</string>
   <string name="media_err_malformed">Arquivo de mídia não corretamente codificado</string>
   <string name="media_err_timeout">Expirou o tempo durante a tentativa</string>
   <string name="media_err_invalid_progressive_playback">Arquivo de mídia não pode ser transmitido</string>
-  <string name="media_err_unknown">Arquivo de mídia não pode ser reproduzido com o estoque media player</string>
+  <string name="media_err_unknown">Arquivo de mídia não pode ser reproduzido com o stock media player</string>
   <string name="media_err_security_ex">Erro de segurança tentando reproduzir %1$s</string>
   <string name="media_err_io_ex">Erro de entrada tentando reproduzir %1$s</string>
   <string name="media_err_unexpected">Erro inesperado tentando reproduzir %1$s</string>
   <string name="media_rewind_description">Botão rebobinar</string>
   <string name="media_play_pause_description">Botão reproduzir parar</string>
   <string name="media_forward_description">Botão de adiantamento rápido</string>
+  <string name="auth_getting_authorization">Obtendo autorização...</string>
   <string name="auth_trying_to_login">Tentando fazer login...</string>
   <string name="auth_no_net_conn_title">Sem conexão de rede</string>
   <string name="auth_nossl_plain_ok_title">Conexão segura indisponível.</string>
   <string name="auth_testing_connection">Testando conexão...</string>
   <string name="auth_not_configured_title">Configuração do servidor mal formada</string>
   <string name="auth_account_not_new">Uma conta para o mesmo usuário e servidor já existe no dispositivo</string>
-  <string name="auth_account_not_the_same">As informações que o usuário digitou não corresponde ao usuário da conta</string>
+  <string name="auth_account_not_the_same">As informações que o usuário digitou não correspondem ao usuário da conta</string>
   <string name="auth_unknown_error_title">Ocorreu um erro desconhecido!</string>
   <string name="auth_unknown_host_title">Não pôde encontrar host</string>
   <string name="auth_incorrect_path_title">Instância de servidor não encontrada</string>
   <string name="auth_incorrect_address_title">URL mal formada</string>
   <string name="auth_ssl_general_error_title">Inicialização SSL falhou</string>
   <string name="auth_ssl_unverified_server_title">Não foi possível verificar a identidade do servidor SSL</string>
-  <string name="auth_bad_oc_version_title">Versão do servidor é irreconhecível</string>
+  <string name="auth_bad_oc_version_title">Versão do servidor desconhecida</string>
   <string name="auth_wrong_connection_title">Não foi possível estabelecer conexão</string>
   <string name="auth_secure_connection">Conexão segura estabelecida</string>
   <string name="auth_unauthorized">Nome de usuário e/ou senha está errada!</string>
   <string name="auth_connecting_auth_server">Conectando ao servidor de autenticação ...</string>
   <string name="auth_unsupported_auth_method">O servidor não suporta este método de autenticação</string>
   <string name="auth_unsupported_multiaccount">%1$s não suporta múltiplas contas</string>
+  <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="fd_keep_in_sync">Manter arquivo atualizado</string>
   <string name="common_rename">Renomear</string>
   <string name="common_remove">Remover</string>
-  <string name="confirmation_remove_alert">Você realmente quer remover %1$s ?</string>
-  <string name="confirmation_remove_folder_alert">Você deseja realmente apagar %1$s e seu conteúdo?</string>
+  <string name="confirmation_remove_alert">Você realmente deseja remover %1$s?</string>
+  <string name="confirmation_remove_folder_alert">Você realmente deseja remover %1$s e seus conteúdos?</string>
   <string name="confirmation_remove_local">Somente local</string>
   <string name="confirmation_remove_folder_local">Somente conteúdo local</string>
   <string name="confirmation_remove_remote">Remover do servidor</string>
   <string name="remove_success_msg">Removido com sucesso</string>
   <string name="remove_fail_msg">Erro ao remover</string>
   <string name="rename_dialog_title">Digite um novo nome</string>
-  <string name="rename_local_fail_msg">Cópia local não pôde ser renomeada, tente outro nome</string>
-  <string name="rename_server_fail_msg">Renomeação não pôde ser completada</string>
+  <string name="rename_local_fail_msg">Cópia local não pôde ser renomeada; tente outro nome</string>
+  <string name="rename_server_fail_msg">Renomeação não pôde ser finalizada</string>
   <string name="sync_file_fail_msg">Arquivo remoto não pode ser verificado</string>
   <string name="sync_file_nothing_to_do_msg">Conteúdo do arquivo já foi sincronizado</string>
-  <string name="create_dir_fail_msg">Diretório não pôde ser criado</string>
+  <string name="create_dir_fail_msg">A pasta não pode ser criada</string>
+  <string name="filename_forbidden_characters">Caracteres proibidos: / \\ &lt; &gt; : \" | ? *</string>
+  <string name="filename_empty">O nome do arquivo não pode estar vazio</string>
   <string name="wait_a_moment">Aguarde um momento</string>
   <string name="filedisplay_unexpected_bad_get_content">Problema inesperado; por favor, tente selecionar o arquivo com outro app</string>
   <string name="filedisplay_no_file_selected">Nenhum arquivo foi selecionado</string>
+  <string name="activity_chooser_title">Enviar o link para</string>
   <string name="oauth_check_onoff">Login com oAuth2</string>
   <string name="oauth_login_connection">Conectando-se a oAuth2 servidor ...</string>
   <string name="ssl_validator_header">A identidade do site não pode ser verificada</string>
   <string name="ssl_validator_reason_cert_not_trusted">- O certificado do servidor não é confiável</string>
   <string name="ssl_validator_reason_cert_expired">- O certificado do servidor expirou</string>
-  <string name="ssl_validator_reason_cert_not_yet_valid">- O certificado do servidor é muito recente</string>
+  <string name="ssl_validator_reason_cert_not_yet_valid">- O datas de validade do certificado do servidor estão no futuro</string>
   <string name="ssl_validator_reason_hostname_not_verified">- O URL do host não confere com o host do certificado</string>
-  <string name="ssl_validator_question">Você confia nesse certificado mesmo assim?</string>
+  <string name="ssl_validator_question">Você mesmo assim confia nesse certificado?</string>
   <string name="ssl_validator_not_saved">O certificado não pode ser salvo</string>
   <string name="ssl_validator_btn_details_see">Detalhes</string>
   <string name="ssl_validator_btn_details_hide">Ocultar</string>
   <string name="ssl_validator_label_validity_to">Para:</string>
   <string name="ssl_validator_label_signature">Assinatura:</string>
   <string name="ssl_validator_label_signature_algorithm">Algoritmo:</string>
+  <string name="ssl_validator_null_cert">O certificado não pode ser mostrado.</string>
+  <string name="ssl_validator_no_info_about_error">- Nenhuma informação sobre o erro</string>
   <string name="placeholder_sentence">Este é um espaço reservado</string>
   <string name="placeholder_filename">espaçoreservado.txt</string>
   <string name="placeholder_filetype">Imagem PNG</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">Fazer upload de fotos somente via WiFi</string>
+  <string name="instant_upload_on_wifi">Fazer envio de fotos somente via WiFi</string>
+  <string name="instant_video_upload_on_wifi">Enviar vídeos somente via WiFi</string>
   <string name="instant_upload_path">/Upload instantâneo</string>
   <string name="conflict_title">Conflito de atualização</string>
-  <string name="conflict_message">O arquivo remoto %s não está soncronizado com o arquivo local. Prosseguir irá substituir o arquivo no servidor.</string>
+  <string name="conflict_message">O arquivo remoto %s não está sincronizado com o arquivo local. Prosseguir irá substituir o arquivo no servidor.</string>
   <string name="conflict_keep_both">Manter ambos</string>
   <string name="conflict_overwrite">Sobrescrever</string>
-  <string name="conflict_dont_upload">Não fazer upload</string>
+  <string name="conflict_dont_upload">Não enviar</string>
   <string name="preview_image_description">Pré-visualização da imagem</string>
   <string name="preview_image_error_unknown_format">Esta imagem não pode ser mostrada</string>
-  <string name="error__upload__local_file_not_copied">%1$s não pode ser copiado a pasta local %2$s</string>
-  <string name="actionbar_failed_instant_upload">Falha no envio imediato</string>
-  <string name="failed_upload_headline_text">Falhas nos envios imediatos</string>
-  <string name="failed_upload_headline_hint">Sumario de todas as falhas nos envios imediatos</string>
-  <string name="failed_upload_all_cb">selecionar tudo</string>
-  <string name="failed_upload_headline_retryall_btn">tentar novamente todos os selecionados</string>
-  <string name="failed_upload_headline_delete_all_btn">excluir todos os selecionados da lista de envio</string>
-  <string name="failed_upload_retry_text">tentar novamente envio da imagem:</string>
-  <string name="failed_upload_load_more_images">Carregar mais Imagens</string>
-  <string name="failed_upload_retry_do_nothing_text">não fazer nada voce não está conectado para envio instantâneo </string>
-  <string name="failed_upload_failure_text">Mensagem de Falha:</string>
-  <string name="failed_upload_quota_exceeded_text">Por favor verifique a configuração do servidor, talvez a sua cota esteja vencida.</string>
+  <string name="error__upload__local_file_not_copied">%1$s não pôde ser copiado para pasta local %2$s</string>
+  <string name="prefs_instant_upload_path_title">Enviar Caminho</string>
+  <string name="share_link_no_support_share_api">Desculpe, o compartilhamento não está habilitado em seu servidor. Entre em contato com seu 
+⇥⇥ administrador.</string>
+  <string name="share_link_file_no_exist">Não é possível compartilhar. Por favor verifique se o arquivo existe</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="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="error_cant_bind_to_operations_service">Erro crítico: não pode executar operações</string>
+  <string name="network_error_socket_exception">Ocorreu um erro durante a conexão com o servidor.</string>
+  <string name="network_error_socket_timeout_exception">Ocorreu um erro enquanto se espera pelo servidor, a operação não poderia ter sido executada</string>
+  <string name="network_error_connect_timeout_exception">Ocorreu um erro enquanto se espera pelo servidor, a operação não poderia ter sido executada</string>
+  <string name="network_host_not_available">A operação não pôde ser concluída, o servidor está indisponível</string>
+  <string name="empty"></string>
+  <string name="forbidden_permissions">Você não tem premissão %s</string>
+  <string name="forbidden_permissions_rename">para renomear este arquivo</string>
+  <string name="forbidden_permissions_delete">para excluir este arquivo</string>
+  <string name="share_link_forbidden_permissions">para compartilhar este arquivo</string>
+  <string name="unshare_link_forbidden_permissions">para descompartilhar este arquivo</string>
+  <string name="forbidden_permissions_create">para criar este arquivo</string>
+  <string name="uploader_upload_forbidden_permissions">para enviar para esta pasta</string>
+  <string name="downloader_download_file_not_found">Este arquivo não mais está disponível neste servidor</string>
+  <string name="prefs_category_accounts">Contas</string>
+  <string name="prefs_add_account">Adicionar uma conta</string>
+  <string name="auth_redirect_non_secure_connection_title">Conexão segura esta redirecionada para uma rota não segura.</string>
+  <string name="actionbar_logger">Logs</string>
+  <string name="log_send_history_button">Enviar Histórico</string>
+  <string name="log_mail_subject">Logs do aplicativo ownCloud Android</string>
+  <string name="log_progress_dialog_text">Carregamento de dados...</string>
+  <string name="saml_authentication_required_text">Autenticação é requerida</string>
+  <string name="saml_authentication_wrong_pass">Senha incorreta</string>
+  <string name="actionbar_move">Mover</string>
+  <string name="file_list_empty_moving">Nada aqui. Você pode adicionar uma pasta!</string>
+  <string name="move_choose_button_text">Escolher</string>
+  <string name="move_file_not_found">Não é possível mover. Por favor verifique se o arquivo existe</string>
+  <string name="move_file_invalid_into_descendent">Não é possível mover a pasta para uma descendente</string>
+  <string name="move_file_invalid_overwrite">O arquivo já existe na pasta de destino</string>
+  <string name="move_file_error">Ocorreu um erro ao tentar mover este arquivo ou pasta</string>
+  <string name="forbidden_permissions_move">mover este arquivo</string>
+  <string name="prefs_category_instant_uploading">Envios Instantâneos</string>
+  <string name="prefs_category_security">Segurança</string>
 </resources>
index 514e60c..6c4aab1 100644 (file)
@@ -2,39 +2,45 @@
 <resources>
   <string name="about_android">%1$s Aplicação(ões) Android</string>
   <string name="about_version">versão %1$s</string>
-  <string name="actionbar_sync">Recarregar a conta</string>
+  <string name="actionbar_sync">Actualizar</string>
   <string name="actionbar_upload">Enviar</string>
   <string name="actionbar_upload_from_apps">Conteúdo das outras apps</string>
   <string name="actionbar_upload_files">Ficheiros</string>
   <string name="actionbar_open_with">Abrir com</string>
-  <string name="actionbar_mkdir">Criar pasta</string>
+  <string name="actionbar_mkdir">Nova Pasta</string>
   <string name="actionbar_settings">Definições</string>
   <string name="actionbar_see_details">Detalhes</string>
+  <string name="actionbar_send_file">Enviar</string>
   <string name="prefs_category_general">Geral</string>
   <string name="prefs_category_more">Mais</string>
   <string name="prefs_accounts">Contas</string>
   <string name="prefs_manage_accounts">Gerir contas</string>
   <string name="prefs_pincode">App PIN</string>
   <string name="prefs_pincode_summary">Proteja o seu cliente</string>
-  <string name="prefs_instant_upload">Activar envio instantâneo</string>
-  <string name="prefs_instant_upload_summary">Enviar automaticamente as fotografias tiradas pela camera</string>
+  <string name="prefs_instant_upload">Transferência instantânea de imagens</string>
+  <string name="prefs_instant_upload_summary">Transferência instantânea de imagens tiradas com câmara</string>
+  <string name="prefs_instant_video_upload">Envios instantâneos dos vídeos</string>
+  <string name="prefs_instant_video_upload_summary">Carregamento instantâneo de vídeos registados com a camera  </string>
   <string name="prefs_log_title">Ativar Rastreio</string>
   <string name="prefs_log_summary">Isto é usado para registar problemas</string>
   <string name="prefs_log_title_history">Historico do rastreio</string>
   <string name="prefs_log_summary_history">Isto mostra os registos guardados</string>
   <string name="prefs_log_delete_history_button">Eliminar Histórico</string>
   <string name="prefs_help">Ajuda</string>
+  <string name="prefs_recommend">Recomendar a um amigo</string>
   <string name="prefs_feedback">Resposta</string>
   <string name="prefs_imprint">Imprint</string>
+  <string name="recommend_subject">Experimente %1$s no seu smartphone!</string>
+  <string name="recommend_text">Quero convidar-te a usares %1$s no teu smartphone!\nFaz download aqui: %2$s</string>
   <string name="auth_check_server">Verificar Servidor</string>
-  <string name="auth_host_url">Endereço do servidor</string>
+  <string name="auth_host_url">Endereço do servidor https://..</string>
   <string name="auth_username">Nome de Utilizador</string>
   <string name="auth_password">Palavra-passe</string>
   <string name="auth_register">Novo em %1$s?</string>
   <string name="sync_string_files">Ficheiros</string>
   <string name="setup_btn_connect">Ligar</string>
   <string name="uploader_btn_upload_text">Enviar</string>
-  <string name="uploader_top_message">Escolha a directoria do upload:</string>
+  <string name="uploader_top_message">Escolha a pasta de envio:</string>
   <string name="uploader_wrn_no_account_title">Nenhuma conta encontrada</string>
   <string name="uploader_wrn_no_account_text">Não tem nenhuma conta  %1$s no seu dispositivo. Configure uma conta.</string>
   <string name="uploader_wrn_no_account_setup_btn_text">Configurar</string>
@@ -43,7 +49,9 @@
   <string name="uploader_wrn_no_content_text">Não foi recebido nenhum conteúdo. Nada para enviar.</string>
   <string name="uploader_error_forbidden_content">O  %1$s não está autorizado a aceder aos ficheiro partilhados.</string>
   <string name="uploader_info_uploading">A enviar</string>
-  <string name="file_list_empty">Não existem ficheiros nesta pasta.\nPode adicionar ficheiros com a opção \"Enviar\" no menu.</string>
+  <string name="file_list_empty">Vazio. Envie alguma coisa!</string>
+  <string name="file_list_loading">A carregar...</string>
+  <string name="local_file_list_empty">Não existem ficheiros nesta pasta.</string>
   <string name="filedetails_select_file">Clique no ficheiro para visualizar informação adicional.</string>
   <string name="filedetails_size">Tamanho:</string>
   <string name="filedetails_type">Tipo:</string>
@@ -52,6 +60,8 @@
   <string name="filedetails_download">Descarregar</string>
   <string name="filedetails_sync_file">Atualizar ficheiro</string>
   <string name="filedetails_renamed_in_upload_msg">O nome do ficheiro foi alterado para %1$s durante o envio.</string>
+  <string name="action_share_file">Partilhar o link</string>
+  <string name="action_unshare_file">Deixar de partilhar a ligação</string>
   <string name="common_yes">Sim</string>
   <string name="common_no">Não</string>
   <string name="common_ok">OK</string>
   <string name="delete_account">Apagar conta</string>
   <string name="create_account">Criar conta</string>
   <string name="upload_chooser_title">Carregar de...</string>
-  <string name="uploader_info_dirname">Nome da directoria</string>
+  <string name="uploader_info_dirname">Nome da pasta</string>
   <string name="uploader_upload_in_progress_ticker">A carregar...</string>
   <string name="uploader_upload_in_progress_content">A enviar %1$d%% , %2$s completo.</string>
   <string name="uploader_upload_succeeded_ticker">Carregado com sucesso</string>
   <string name="uploader_upload_succeeded_content_single">%1$s foi carregado com sucesso</string>
   <string name="uploader_upload_failed_ticker">Carregamento falhou</string>
   <string name="uploader_upload_failed_content_single">O envio do ficheiro %1$s não foi concluído.</string>
+  <string name="uploader_upload_failed_credentials_error">Falha no carregamento, é necessário fazer novo login</string>
   <string name="downloader_download_in_progress_ticker">A descarregar...</string>
   <string name="downloader_download_in_progress_content">%1$d%% A decarregar %2$s</string>
   <string name="downloader_download_succeeded_ticker">Descarga com sucesso</string>
   <string name="downloader_download_failed_ticker">Descarga falhou</string>
   <string name="downloader_download_failed_content">O descarregamento %1$s não foi possível descarregar</string>
   <string name="downloader_not_downloaded_yet">Não transferido</string>
+  <string name="downloader_download_failed_credentials_error">Falha no download, é necessário fazer login </string>
   <string name="common_choose_account">Escolha a conta</string>
   <string name="sync_fail_ticker">Falhou a sincronização</string>
+  <string name="sync_fail_ticker_unauthorized">Falhou a sincronização, necessita fazer um novo login</string>
   <string name="sync_fail_content">Não foi possível sincronizar %1$s</string>
   <string name="sync_fail_content_unauthorized">Password inválida para %1$s</string>
   <string name="sync_conflicts_in_favourites_ticker">Foram encontrados conflitos</string>
   <string name="sync_fail_in_favourites_ticker">Falhou a operação de manter os ficheiros sincronizados</string>
   <string name="sync_fail_in_favourites_content">Não foi possível sincronizar  o conteúdo de %1$d ficheiros  (%2$d conflictos)</string>
   <string name="sync_foreign_files_forgotten_ticker">Alguns ficheiros locais ficaram esquecidos</string>
-  <string name="sync_foreign_files_forgotten_content">%1$d ficheiros da directoria %2$s não foram copiados</string>
-  <string name="sync_foreign_files_forgotten_explanation">Com a versão 1.3.16, os ficheiros que foram enviados deste dispositivo foram copiados para a pasta local %1$s para prevenir perda de dados quando um ficheiro está partilhado com várias contas.\nDevido a esta alteração, todos os ficheiros e as suas versões foram copiados para a pasta %2$s. Contudo, um erro não deixou concluír este processo durante a sincronização da conta. Pode deixar o ficheiro(s) como está(ão) e remover o link para %3$s, ou mover o(s) ficheiro(s)  para a pasta %1$s e guardar o link para %4$s.\n\nEm baixo está(ão) listados o(s) ficheiro(s) locais e remotos em %5$s que foram ligados.</string>
+  <string name="sync_foreign_files_forgotten_content">Nao foi possivel copiar os ficheiros %1$d da pasta %2$s para</string>
+  <string name="sync_foreign_files_forgotten_explanation">Tal como na versão 1.3.16, os ficheiros que foram enviados deste dispositivo são copiados para a pasta local %1$s para prevenir perda de dados quando um ficheiro é partilhado com várias contas.\n\nDevido a esta alteração, todos os ficheiros das versões anteriores foram copiados para a pasta %2$s. No entanto, um erro impediu a conclusão deste processo durante a sincronização da conta. Pode deixar o ficheiro(s) como estão e remover o link para %3$s, ou mover o(s) ficheiro(s) para a pasta %1$s e guardar o link para %4$s. \n\nEm baixo estão listados ficheiro(s) locais e remotos em %5$s que foram ligados.</string>
+  <string name="sync_current_folder_was_removed">A pasta %1$s já não existe</string>
   <string name="foreign_files_move">Mover Todos</string>
   <string name="foreign_files_success">Todos os ficheiros foram movidos</string>
   <string name="foreign_files_fail">Não foi possível mover alguns ficheiros</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">Não existe espaço suficiente para copiar os ficheiros seleccionados para a pasta %1$s . Deseja move-los?</string>
+  <string name="upload_query_move_foreign_files">Não existe espaço disponível para copiar o ficheiro seleccionado para a pasta %1$s . Em vez disso deseja mover o ficheiro?</string>
   <string name="pincode_enter_pin_code">Por favor escreva o PIN da Aplicação</string>
   <string name="pincode_configure_your_pin">Escreva o PIN da Aplicação</string>
   <string name="pincode_configure_your_pin_explanation">O PIN vai ser pedido todas as vezes que iniciar a aplicação.</string>
   <string name="media_err_unsupported">Codec de média não suportado</string>
   <string name="media_err_io">Não foi possível reproduzir o ficheiro</string>
   <string name="media_err_malformed">Ficheiro erradamente codificado (codec)</string>
+  <string name="media_err_timeout">O tempo de espera para jogar expirou</string>
   <string name="media_err_invalid_progressive_playback">O ficheiro não pode ser reproduzido (streaming)</string>
   <string name="media_err_unknown">O ficheiro não pode ser reproduzido com o leitor de média de origem</string>
   <string name="media_err_security_ex">Erro de segurança a tentar reproduzir o ficheiro %1$s</string>
   <string name="media_rewind_description">Botão de rebobinar</string>
   <string name="media_play_pause_description">Botão Tocar/Pausa</string>
   <string name="media_forward_description">Botão de avanço rápido</string>
+  <string name="auth_getting_authorization">A obter autorização...</string>
   <string name="auth_trying_to_login">A tentar entrar...</string>
   <string name="auth_no_net_conn_title">Sem ligação à rede</string>
   <string name="auth_nossl_plain_ok_title">Ligação segura indisponível</string>
   <string name="auth_connection_established">Ligação estabelecida</string>
   <string name="auth_testing_connection">A testar a ligação...</string>
   <string name="auth_not_configured_title">Configuração do servidor incorrecta.</string>
+  <string name="auth_account_not_new">Uma conta para este utilizador e servidor já existe no dispositivo</string>
+  <string name="auth_account_not_the_same">O utilizador que escreveu não coincide com o nome de utilizador desta conta</string>
   <string name="auth_unknown_error_title">Ocorreu um erro desconhecido!</string>
   <string name="auth_unknown_host_title">Não é possível encontrar o servidor</string>
   <string name="auth_incorrect_path_title">Instância servidor não encontrada</string>
   <string name="auth_timeout_title">O servidor levou demasiado tempo a responder</string>
   <string name="auth_incorrect_address_title">URL errado</string>
   <string name="auth_ssl_general_error_title">Inicialização de SSL falhou</string>
+  <string name="auth_ssl_unverified_server_title">Não foi possível verificar a identidade SSL do servidor</string>
   <string name="auth_bad_oc_version_title">Versão do servidor não reconhecida</string>
   <string name="auth_wrong_connection_title">Não consegue estabelecer ligação</string>
   <string name="auth_secure_connection">Ligação segura estabelecida</string>
   <string name="auth_oauth_error">autorização mal sucedida</string>
   <string name="auth_oauth_error_access_denied">Acesso negado pelo servidor</string>
   <string name="auth_wtf_reenter_URL">Estado inesperado, por favor, digite a URL do servidor novamente</string>
+  <string name="auth_expired_oauth_token_toast">O prazo da sua autorização expirou. Por favor renove-a</string>
   <string name="auth_expired_basic_auth_toast">Por favor, introduza a password actual</string>
+  <string name="auth_expired_saml_sso_token_toast">A sua sessão expirou. Por favor autentique-se de novo</string>
+  <string name="auth_connecting_auth_server">A verificar a sua autenticação no servidor...</string>
+  <string name="auth_unsupported_auth_method">O servidor não suporta este método de autenticação</string>
+  <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="fd_keep_in_sync">manter ficheiro actualizado</string>
   <string name="common_rename">Renomear</string>
   <string name="common_remove">Remover</string>
   <string name="rename_server_fail_msg">Não foi possível renomear</string>
   <string name="sync_file_fail_msg">Não foi possível verificar o ficheiro remoto</string>
   <string name="sync_file_nothing_to_do_msg">O conteúdo do ficheiro já foi sincronizado</string>
-  <string name="create_dir_fail_msg">Não foi possível criar a pasta</string>
+  <string name="create_dir_fail_msg">Não foi possivel criar a pasta</string>
+  <string name="filename_forbidden_characters">Caracteres não permitidos: / \\ &lt; &gt; : \" | ? *</string>
+  <string name="filename_empty">O nome do ficheiro não pode ser vazio.</string>
   <string name="wait_a_moment">Aguarde um momento</string>
   <string name="filedisplay_unexpected_bad_get_content">Erro inesperado. Por favor tente outra aplicação para seleccionar o ficheiro.</string>
   <string name="filedisplay_no_file_selected">Não selecionou nenhum ficheiro</string>
+  <string name="activity_chooser_title">Enviar a ligação para ...</string>
+  <string name="oauth_check_onoff">Autenticar-se com oAuth2</string>
   <string name="oauth_login_connection">A ligar ao servidor oAuth2</string>
   <string name="ssl_validator_header">Não foi possível verificar a identidade do site.</string>
   <string name="ssl_validator_reason_cert_not_trusted">- O certificado do servidor não é de confiança</string>
   <string name="ssl_validator_label_validity_to">Para:</string>
   <string name="ssl_validator_label_signature">Assinatura:</string>
   <string name="ssl_validator_label_signature_algorithm">Algoritmo</string>
+  <string name="ssl_validator_null_cert">O certificado não pôde ser mostrado.</string>
+  <string name="ssl_validator_no_info_about_error">- Nenhuma informação acerca do erro</string>
   <string name="placeholder_sentence">Isto é uma variável.</string>
   <string name="placeholder_filename">placeholder.txt</string>
   <string name="placeholder_filetype">Imagem PNG</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">Enviar fotografias apenas via WiFi</string>
+  <string name="instant_video_upload_on_wifi">Enviar videos apenas por WiFi</string>
   <string name="instant_upload_path">/Upload-Instantâneo </string>
   <string name="conflict_title">Conflito na actualização</string>
   <string name="conflict_message">O ficheiro remoto %s não está sincronizado com o ficheiro local. Se continuar ira substituir o ficheiro no servidor.</string>
   <string name="preview_image_description">Pré-Visualização da imagem</string>
   <string name="preview_image_error_unknown_format">Esta imagem não pode ser mostrada</string>
   <string name="error__upload__local_file_not_copied">Não foi possível copiar %1$s para a pasta local %2$s</string>
-  <string name="actionbar_failed_instant_upload">Falhou o Upload-Instantâneo\"</string>
-  <string name="failed_upload_headline_text">Falharam os Uploads-Instantâneos</string>
-  <string name="failed_upload_headline_hint">Sumário dos Uploads-Instantâneos falhados</string>
-  <string name="failed_upload_all_cb">Seleccionar Todos</string>
-  <string name="failed_upload_headline_retryall_btn">Tentar todos os seleccionados</string>
-  <string name="failed_upload_headline_delete_all_btn">Eliminar todos os seleccionados da lista de envio</string>
-  <string name="failed_upload_retry_text">Tentar envio da imagem:</string>
-  <string name="failed_upload_load_more_images">Carregar mais imagens</string>
-  <string name="failed_upload_retry_do_nothing_text">não fazer nada, nao está online para o Upload-Instantâneo</string>
-  <string name="failed_upload_failure_text">Mensagem de erro:</string>
-  <string name="failed_upload_quota_exceeded_text">Por favor verifique a configuração do servidor, talvez tenha excedido a sua quota</string>
+  <string name="prefs_instant_upload_path_title">Caminho de Upload</string>
+  <string name="share_link_no_support_share_api">Lamentamos mas não é possível partilhar através do seu servidor. Por favor contacte o seu administrador.</string>
+  <string name="share_link_file_no_exist">Não é possivel partilhar. Por favor verifique se o ficheiro existe</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="activity_chooser_send_file_title">Enviar</string>
+  <string name="copy_link">Copiar ligação</string>
+  <string name="clipboard_text_copied">Copiado para a área de transferência</string>
+  <string name="error_cant_bind_to_operations_service">Erro crítico: não é possível executar as operações</string>
+  <string name="network_error_socket_exception">Ocorreu um erro durante a ligação ao servidos.</string>
+  <string name="network_error_socket_timeout_exception">Ocorreu um erro durante a ligação ao servidor, não foi possível realizar a operação.</string>
+  <string name="network_error_connect_timeout_exception">Ocorreu um erro durante a ligação ao servidor, não foi possível realizar a operação.</string>
+  <string name="network_host_not_available">A operação não foi concluída, o servidor está inacessível.</string>
+  <string name="empty"></string>
+  <string name="forbidden_permissions">Você não tem permissão %s</string>
+  <string name="forbidden_permissions_rename">para renomear este ficheiro</string>
+  <string name="forbidden_permissions_delete">para eliminar este ficheiro</string>
+  <string name="share_link_forbidden_permissions">para partilhar este ficheiro</string>
+  <string name="unshare_link_forbidden_permissions">para eliminar a partilha deste ficheiro</string>
+  <string name="forbidden_permissions_create">para criar o ficheiro</string>
+  <string name="uploader_upload_forbidden_permissions">para carregar dentro desta pasta</string>
+  <string name="downloader_download_file_not_found">O ficheiro não está mais disponível no servidor</string>
+  <string name="prefs_category_accounts">Contas</string>
+  <string name="prefs_add_account">Adicionar conta</string>
+  <string name="auth_redirect_non_secure_connection_title">Ligação segura é redireccionada para um caminho inseguro.</string>
+  <string name="actionbar_logger">Logs</string>
+  <string name="log_send_history_button">Enviar Histórico</string>
+  <string name="log_mail_subject">Logs da app ownCloud Android</string>
+  <string name="log_progress_dialog_text">A carregar os dados...</string>
+  <string name="saml_authentication_required_text">Autenticação necessária</string>
+  <string name="saml_authentication_wrong_pass">Password errada</string>
+  <string name="actionbar_move">Mover</string>
+  <string name="file_list_empty_moving">Não está aqui nada. Pode adicionar uma pasta!</string>
+  <string name="move_choose_button_text">Escolha</string>
+  <string name="move_file_not_found">Não é possível mover. Verifique se o ficheiro existe</string>
+  <string name="move_file_invalid_into_descendent">Não é possível mover esta pasta deste modo</string>
+  <string name="move_file_invalid_overwrite">O ficheiro já existe na pasta de destino</string>
+  <string name="move_file_error">Um erro ocorreu ao tentar mover este ficheiro ou pasta</string>
+  <string name="forbidden_permissions_move">para mover este ficheiro</string>
+  <string name="prefs_category_instant_uploading">Uploads Instantâneos</string>
+  <string name="prefs_category_security">Segurança</string>
 </resources>
index a35bbdc..b3ea725 100644 (file)
 <?xml version='1.0' encoding='UTF-8'?>
 <resources>
+  <string name="about_android">%1$s Aplicație Android</string>
+  <string name="about_version">versiunea %1$s</string>
+  <string name="actionbar_sync">Refresh cont</string>
   <string name="actionbar_upload">Încarcă</string>
   <string name="actionbar_upload_from_apps">Conținut de la alte aplicații</string>
   <string name="actionbar_upload_files">Fișiere</string>
-  <string name="actionbar_mkdir">Creare director</string>
+  <string name="actionbar_open_with">Deschideţi cu </string>
+  <string name="actionbar_mkdir">Un nou dosar</string>
   <string name="actionbar_settings">Setări</string>
+  <string name="actionbar_see_details">Detalii</string>
+  <string name="actionbar_send_file">Expediază</string>
   <string name="prefs_category_general">General</string>
   <string name="prefs_category_more">Mai mult</string>
   <string name="prefs_accounts">Conturi</string>
   <string name="prefs_manage_accounts">Administrare conturi</string>
-  <string name="prefs_instant_upload">Activează încărcarea instant</string>
+  <string name="prefs_pincode">PIN-ul aplicaţiei</string>
+  <string name="prefs_pincode_summary">Protejaţi-vă clientul</string>
+  <string name="prefs_instant_upload">Încărcare instanta de imagine</string>
+  <string name="prefs_instant_upload_summary">Încărca instantaneu imagini luate de camera</string>
+  <string name="prefs_instant_video_upload">Încărcare instantă de videoclipuri.</string>
+  <string name="prefs_instant_video_upload_summary">Încarcă videoclipuri instant, filmate cu camera.</string>
+  <string name="prefs_log_title">Permite logarea</string>
+  <string name="prefs_log_summary">Acesta este folosit pentru a înregistra problemele</string>
+  <string name="prefs_log_title_history">Istoria logarilor</string>
+  <string name="prefs_log_summary_history">Asta arata înregistrările salvate</string>
+  <string name="prefs_log_delete_history_button">Ştergeţi istoric</string>
   <string name="prefs_help">Ajutor</string>
-  <string name="auth_host_url">Adresa server-ului</string>
+  <string name="prefs_recommend">Recomandati unui prieten</string>
+  <string name="prefs_feedback">Feedback</string>
+  <string name="prefs_imprint">Imprint</string>
+  <string name="recommend_subject">Încearcă %1$s pe smartphone-ul tău!</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="auth_password">Parolă</string>
+  <string name="auth_register">Nou la %1$s?</string>
   <string name="sync_string_files">Fișiere</string>
   <string name="setup_btn_connect">Conectare</string>
   <string name="uploader_btn_upload_text">Încărcare</string>
+  <string name="uploader_top_message">Alegeţi fişierul pentru încărcare</string>
   <string name="uploader_wrn_no_account_title">Nici un cont găsit</string>
   <string name="uploader_wrn_no_account_text">Nu există conturi %1$s pe dispozitivul tău. Te rugăm să configurezi un cont mai întâi.</string>
   <string name="uploader_wrn_no_account_setup_btn_text">Configurare</string>
   <string name="uploader_wrn_no_account_quit_btn_text">Anulare</string>
+  <string name="uploader_wrn_no_content_title">Nu exista conţinut pentru încărcare</string>
+  <string name="uploader_wrn_no_content_text">Nu a fost primit nici un conţinut .Nu exista nimic de încărcat .</string>
+  <string name="uploader_error_forbidden_content">%1$s nu este permis sa acceseze conținutul shared</string>
   <string name="uploader_info_uploading">Încărcare</string>
+  <string name="file_list_empty">Nimic aici. Încarcă ceva!</string>
+  <string name="file_list_loading">Se incarca</string>
+  <string name="local_file_list_empty">In acest folder nu sunt fisiere.</string>
+  <string name="filedetails_select_file">Selectati un fisier pentru a afisa informatia aditionala</string>
   <string name="filedetails_size">Mărime:</string>
   <string name="filedetails_type">Tip:</string>
   <string name="filedetails_created">Creat:</string>
   <string name="filedetails_modified">Modificat:</string>
   <string name="filedetails_download">Descarcă</string>
+  <string name="filedetails_sync_file">Împrospătare fişier</string>
+  <string name="filedetails_renamed_in_upload_msg">Fișierul a fost redenumit %1$s în timpul încărcării</string>
+  <string name="action_share_file">Share link</string>
+  <string name="action_unshare_file">Unshare link</string>
   <string name="common_yes">Da</string>
   <string name="common_no">Nu</string>
   <string name="common_ok">OK</string>
+  <string name="common_cancel_download">Anulează descărcarea</string>
   <string name="common_cancel_upload">Anulează încărcarea</string>
   <string name="common_cancel">Anulare</string>
   <string name="common_save_exit">Salvare &amp; Ieșire</string>
   <string name="common_error">Eroare</string>
+  <string name="common_loading">Se încarcă...</string>
+  <string name="common_error_unknown">Eroare necunoscută</string>
   <string name="about_title">Despre</string>
   <string name="change_password">Schimbă parola</string>
   <string name="delete_account">Șterge cont</string>
   <string name="create_account">Crează cont</string>
   <string name="upload_chooser_title">Încarcă din...</string>
-  <string name="uploader_info_dirname">Nume director</string>
+  <string name="uploader_info_dirname">Denumire director</string>
   <string name="uploader_upload_in_progress_ticker">În curs de încărcare...</string>
   <string name="uploader_upload_in_progress_content">%1$d%% Se încarcă %2$s</string>
   <string name="uploader_upload_succeeded_ticker">Încărcat cu succes</string>
   <string name="uploader_upload_succeeded_content_single">%1$s a fost încărcat cu succes</string>
   <string name="uploader_upload_failed_ticker">Încărcarea a eșuat</string>
   <string name="uploader_upload_failed_content_single">Încărcarea fișierului %1$s nu a putut fi încheiată</string>
+  <string name="uploader_upload_failed_credentials_error">Incărcarea a eşuat, trebuie să te logezi din nou</string>
   <string name="downloader_download_in_progress_ticker">Se descarcă...</string>
   <string name="downloader_download_in_progress_content">%1$d%% Se descarcă %2$s</string>
   <string name="downloader_download_succeeded_ticker">Descărcarea a reușit</string>
   <string name="downloader_download_succeeded_content">%1$s a fost descărcat cu succes</string>
   <string name="downloader_download_failed_ticker">Descărcarea a eșuat</string>
+  <string name="downloader_download_failed_content">Nu s-a putut face downloadarea completa a %1$s</string>
+  <string name="downloader_not_downloaded_yet">Nu s-a  descărcat încă</string>
+  <string name="downloader_download_failed_credentials_error">Descărcarea a eşuat, trebuie să te logezi din nou</string>
   <string name="common_choose_account">Alege cont</string>
   <string name="sync_fail_ticker">Sincronizarea a eșuat</string>
+  <string name="sync_fail_ticker_unauthorized">Sincronizare date a eşuat, trebuie să te logezi din nou</string>
+  <string name="sync_fail_content">Sincronizarea %1$s nu a putut fi completata</string>
+  <string name="sync_fail_content_unauthorized">Parolă greșită pentru %1$s</string>
+  <string name="sync_conflicts_in_favourites_ticker">S-au gasit conflicte</string>
+  <string name="sync_conflicts_in_favourites_content">%1$d file pastrate-in-sync files nu au putut fi sincronizate</string>
+  <string name="sync_fail_in_favourites_ticker">Pastrarea fisierelor in sync nu a reușit</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_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="foreign_files_fail">Unele fişiere nu au putut fi mutate</string>
+  <string name="foreign_files_local_text">Local: %1$s</string>
+  <string name="foreign_files_remote_text">La distanta: %1$s</string>
+  <string name="upload_query_move_foreign_files">Nu este suficient spațiu pentru a copia fișierele selectate în dosarul %1$s . Dorești să le muți în loc?
+</string>
   <string name="pincode_enter_pin_code">Te rugăm să specifici PIN-ul aplicației</string>
+  <string name="pincode_configure_your_pin">Introduceti PIN-ul aplicatiei</string>
+  <string name="pincode_configure_your_pin_explanation">PIN-ul va fi solicitat ori de cate ori aplicaţia este pornita</string>
+  <string name="pincode_reenter_your_pincode">Va rugam , reintroduceti PIN-ul aplicatiei</string>
   <string name="pincode_remove_your_pincode">Elimină PIN-ul aplicației</string>
   <string name="pincode_mismatch">Cele două PIN-uri ale aplicației nu sunt similare</string>
   <string name="pincode_wrong">PIN-ul aplicației este incorect</string>
   <string name="pincode_removed">PIN-ul aplicației a fost eliminat</string>
   <string name="pincode_stored">PIN-ul aplicației a fost memorat</string>
+  <string name="media_notif_ticker">%1$s  player de muzică</string>
+  <string name="media_state_playing">%1$s (cântă)</string>
+  <string name="media_state_loading">%1$s (încarcă)</string>
+  <string name="media_event_done">%1$s redare terminată</string>
+  <string name="media_err_nothing_to_play">Nu a fost găsit nici un fişier media</string>
+  <string name="media_err_no_account">Nu a fost dat nici un cont</string>
+  <string name="media_err_not_in_owncloud">Fişierul nu este într-un cont valid</string>
+  <string name="media_err_unsupported">Codec media fără suport</string>
+  <string name="media_err_io">Fişierul media nu a putut fi citit</string>
+  <string name="media_err_malformed">Fişierul media nu a fost codat corect</string>
+  <string name="media_err_timeout">Timpul a expirat în  ce încerca să execute</string>
+  <string name="media_err_invalid_progressive_playback">Fișierul media nu poate fi transmis</string>
+  <string name="media_err_unknown">Fișierul media nu poate fi executat cu stock media player</string>
+  <string name="media_err_security_ex">Eroare de securitate în timp ce încerca să execute %1$s</string>
+  <string name="media_err_io_ex">Eroare de input în timp ce încerca să execute %1$s</string>
+  <string name="media_err_unexpected">Eroare neprevăzută în timp ce încerca să execute %1$s</string>
+  <string name="media_rewind_description">Butonul rewind</string>
+  <string name="media_play_pause_description">Buton de play sau pauză </string>
+  <string name="media_forward_description">Butonul pentru repede înainte</string>
+  <string name="auth_getting_authorization">Obținerea autorizației...</string>
   <string name="auth_trying_to_login">În curs de autentificare...</string>
+  <string name="auth_no_net_conn_title">Nu exista conexiune</string>
   <string name="auth_nossl_plain_ok_title">Conexiune securizată indisponibilă</string>
   <string name="auth_connection_established">Conexiune stabilită</string>
   <string name="auth_testing_connection">Se testează conexiunea...</string>
   <string name="auth_not_configured_title">Configurație serverului incorectă</string>
+  <string name="auth_account_not_new">Un cont pentru același utilizator și server există deja în dispozitiv</string>
+  <string name="auth_account_not_the_same">Utilizatorul introdus nu se potrivește cu utilizatorul acestui cont</string>
   <string name="auth_unknown_error_title">A apărut o eroare necunoscută!</string>
+  <string name="auth_unknown_host_title">Nu a putut gasi host-ul</string>
   <string name="auth_incorrect_path_title">Instanța serverului nu a fost găsită</string>
+  <string name="auth_timeout_title">Server-ului i-a luat prea mult timp sa raspunda</string>
+  <string name="auth_incorrect_address_title">URL  scris gresit</string>
   <string name="auth_ssl_general_error_title">Inițializarea SSL a eșuat</string>
+  <string name="auth_ssl_unverified_server_title">Nu s-a putut verifica identitatea serverului SSL</string>
+  <string name="auth_bad_oc_version_title">Versiune necunoscuta a serverului </string>
   <string name="auth_wrong_connection_title">Nu s-a putut stabili conexiunea</string>
   <string name="auth_secure_connection">Conexiune sigură stabilită</string>
+  <string name="auth_unauthorized">Utilizator sau parola greşită </string>
+  <string name="auth_oauth_error">Autorizare nereușită</string>
+  <string name="auth_oauth_error_access_denied">Acces refuzat de serverul de autorizare</string>
+  <string name="auth_wtf_reenter_URL">Situație neașteptată, vă rugăm, introduceți din nou URL-ul serverului</string>
+  <string name="auth_expired_oauth_token_toast">Autorizarea dvs. a expirat. Vă rugăm să autorizați din nou.</string>
+  <string name="auth_expired_basic_auth_toast">Va rugam introduceţi parola curenta</string>
+  <string name="auth_expired_saml_sso_token_toast">Sesiunea a expirat .Va rugam conectati-va din nou </string>
+  <string name="auth_connecting_auth_server">Se conectează la serverul de autentificare...</string>
+  <string name="auth_unsupported_auth_method">Serverul nu soporta aceasta metoda de autentificare </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="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="confirmation_remove_alert">Sigur dorești să elimini %1$s ?</string>
+  <string name="confirmation_remove_alert">Doriti sigur sa stergeti %1$s?</string>
+  <string name="confirmation_remove_folder_alert">Sigur vrei să elimini %1$s și conținutul său?</string>
   <string name="confirmation_remove_local">Doar local</string>
+  <string name="confirmation_remove_folder_local">Doar continut local</string>
   <string name="confirmation_remove_remote">Elimină de pe server</string>
+  <string name="confirmation_remove_remote_and_local">De la distanță și local</string>
   <string name="remove_success_msg">Eliminat cu succes</string>
   <string name="remove_fail_msg">Eliminarea nu a reușit</string>
-  <string name="create_dir_fail_msg">Directorul nu a putut fi creat</string>
+  <string name="rename_dialog_title">Introduceţi un nou nume</string>
+  <string name="rename_local_fail_msg">Copia locala nu a putut fi renumita; incearca un nume diferit</string>
+  <string name="rename_server_fail_msg">Redenumirea nu s-a putut realiza</string>
+  <string name="sync_file_fail_msg">Fisierul de la distanta nu a putut fi verificat</string>
+  <string name="sync_file_nothing_to_do_msg">Continutul fisierului este deja sincronizat</string>
+  <string name="create_dir_fail_msg">Nu a putut fi creat directorul</string>
+  <string name="filename_forbidden_characters">Caractere interzise: / \\ &lt; &gt; : \" | ? *</string>
+  <string name="filename_empty">Numele fișierului nu poate fi gol.</string>
   <string name="wait_a_moment">Așteaptă un moment</string>
+  <string name="filedisplay_unexpected_bad_get_content">Problema neasteptata ; selectati fisierul dintr-o aplicatie diferita </string>
   <string name="filedisplay_no_file_selected">Nu a fost selectat nici un fișier</string>
+  <string name="activity_chooser_title">Trimite link la ...</string>
+  <string name="oauth_check_onoff">Întră în cont cu oAuth2</string>
+  <string name="oauth_login_connection">Se conectează la serverul oAuth2...</string>
+  <string name="ssl_validator_header">Nu s-a putut verifica identitatea site-ului</string>
+  <string name="ssl_validator_reason_cert_not_trusted">Certificatul serverului nu este de incredere </string>
+  <string name="ssl_validator_reason_cert_expired">Certificatul serverului a expirat</string>
+  <string name="ssl_validator_reason_cert_not_yet_valid">- Perioada de valabilitate a certificatului serverului este în viitor</string>
+  <string name="ssl_validator_reason_hostname_not_verified">URL nu se potriveste cu numele gazda in certificat</string>
+  <string name="ssl_validator_question">Vrei să ai încredere în acest certificat, oricum?</string>
+  <string name="ssl_validator_not_saved">Certificatul nu a putut fi salvat.</string>
+  <string name="ssl_validator_btn_details_see">Detalii</string>
+  <string name="ssl_validator_btn_details_hide">Ascunde</string>
+  <string name="ssl_validator_label_subject">A emis:</string>
+  <string name="ssl_validator_label_issuer">Emis de:</string>
+  <string name="ssl_validator_label_CN">Nume comun</string>
+  <string name="ssl_validator_label_O">Organizaţie</string>
+  <string name="ssl_validator_label_OU">Unitate organizationala</string>
+  <string name="ssl_validator_label_C">Tara :</string>
+  <string name="ssl_validator_label_ST">Stat:</string>
+  <string name="ssl_validator_label_L">Locaţie:</string>
+  <string name="ssl_validator_label_validity">Validitate:</string>
+  <string name="ssl_validator_label_validity_from">De la :</string>
+  <string name="ssl_validator_label_validity_to">Catre:</string>
+  <string name="ssl_validator_label_signature">Semnatura:</string>
+  <string name="ssl_validator_label_signature_algorithm">Algoritm:</string>
+  <string name="ssl_validator_null_cert">Certificatul nu a putut fi aratat.</string>
+  <string name="ssl_validator_no_info_about_error">- Nu exista nici o informaţie pentru aceasta eroare</string>
+  <string name="placeholder_sentence">Acesta este un substituent</string>
+  <string name="placeholder_filename">placeholder.txt</string>
+  <string name="placeholder_filetype">Imagine PNG</string>
+  <string name="placeholder_filesize">389 KO</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">Incarca poze doar via WiFi</string>
+  <string name="instant_video_upload_on_wifi">Încarcă videoclipuri doar via WiFi</string>
+  <string name="instant_upload_path">/Încărcare instanta</string>
+  <string name="conflict_title">Actualizați conflictul</string>
+  <string name="conflict_message">Fișierul de la distanță %s nu este sincronizat cu fișierul local. Continuand, se va înlocui conținutul fișierului de pe server.</string>
+  <string name="conflict_keep_both">Pastreaza amandoua</string>
+  <string name="conflict_overwrite">Scrie peste</string>
+  <string name="conflict_dont_upload">Nu încarcă</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="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="activity_chooser_send_file_title">Expediază</string>
+  <string name="copy_link">Link copiat</string>
+  <string name="clipboard_text_copied">Copiat în clipboard</string>
+  <string name="error_cant_bind_to_operations_service">Eroare critică: nu se pot executa operațiunile</string>
+  <string name="network_error_socket_exception">A apărut o eroare în timp ce se conecta la server</string>
+  <string name="network_error_socket_timeout_exception">A apărut o eroare în timp ce se aștepta pentru server, operațiunea nu s-a executat</string>
+  <string name="network_error_connect_timeout_exception">A apărut o eroare în timp ce se aștepta pentru server, operațiunea nu s-a executat</string>
+  <string name="network_host_not_available">Operațiunea nu a putut fi finalizată, serverul este indisponibil</string>
+  <string name="empty"></string>
+  <string name="forbidden_permissions">Nu aveți permisiune %s</string>
+  <string name="forbidden_permissions_rename">pentru a redenumi acest fișier</string>
+  <string name="forbidden_permissions_delete">pentru a șterge acest fișier</string>
+  <string name="share_link_forbidden_permissions">de a share acest fișier</string>
+  <string name="unshare_link_forbidden_permissions">de a nu permite accesul la acest fisier</string>
+  <string name="forbidden_permissions_create">pentru a crea fisierul</string>
+  <string name="uploader_upload_forbidden_permissions">pentru a încărca în acest 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="saml_authentication_wrong_pass">Parolă greșită</string>
+  <string name="move_choose_button_text">Alege</string>
+  <string name="prefs_category_security">Securitate</string>
 </resources>
index b7d3c62..6675918 100644 (file)
@@ -16,7 +16,6 @@
   <string name="prefs_instant_upload">Включить немедленную загрузку</string>
   <string name="prefs_instant_upload_summary">Мгновенно загрузить фотографии, сделанные камерой</string>
   <string name="prefs_help">Помощь</string>
-  <string name="auth_host_url">URL</string>
   <string name="auth_username">Имя пользователя</string>
   <string name="auth_password">Пароль</string>
   <string name="auth_register">Я новичок в %1$s</string>
index b575553..66ad7ad 100644 (file)
@@ -1,52 +1,58 @@
 <?xml version='1.0' encoding='UTF-8'?>
 <resources>
-  <string name="about_android">%1$s Ð\9fÑ\80иложение Ð\90ндÑ\80оид</string>
+  <string name="about_android">%1$s Ð\9fÑ\80иложение Ð´Ð»Ñ\8f Ð\90ндÑ\80оида</string>
   <string name="about_version">Версия %1$s</string>
   <string name="actionbar_sync">Обновить учетную запись</string>
-  <string name="actionbar_upload">Ð\97агÑ\80Ñ\83зка</string>
-  <string name="actionbar_upload_from_apps">СодеÑ\80жимое Ð¾Ñ\82 других приложений</string>
+  <string name="actionbar_upload">Ð\97агÑ\80Ñ\83зиÑ\82Ñ\8c</string>
+  <string name="actionbar_upload_from_apps">СодеÑ\80жимое Ð¸Ð· других приложений</string>
   <string name="actionbar_upload_files">Файлы</string>
   <string name="actionbar_open_with">Открыть с помощью</string>
-  <string name="actionbar_mkdir">СоздаÑ\82Ñ\8c Ð´Ð¸Ñ\80екÑ\82оÑ\80иÑ\8e</string>
+  <string name="actionbar_mkdir">Ð\9dоваÑ\8f Ð¿Ð°Ð¿ÐºÐ°</string>
   <string name="actionbar_settings">Настройки</string>
-  <string name="actionbar_see_details">Детали</string>
-  <string name="prefs_category_general">Главные</string>
+  <string name="actionbar_see_details">Подробно</string>
+  <string name="actionbar_send_file">Отправить</string>
+  <string name="prefs_category_general">Основные</string>
   <string name="prefs_category_more">Больше</string>
-  <string name="prefs_accounts">Ð\90ккаÑ\83нÑ\82Ñ\8b</string>
-  <string name="prefs_manage_accounts">Управление аккаунтами</string>
+  <string name="prefs_accounts">УÑ\87Ñ\91Ñ\82нÑ\8bе Ð·Ð°Ð¿Ð¸Ñ\81и</string>
+  <string name="prefs_manage_accounts">Управление учётными записями</string>
   <string name="prefs_pincode">App PIN</string>
-  <string name="prefs_pincode_summary">Защитить ваш клиент применение</string>
-  <string name="prefs_instant_upload">Включить моментальную загрузку</string>
-  <string name="prefs_instant_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_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="recommend_subject">Попробуйте %1$s на вашем смартфоне!</string>
-  <string name="recommend_text">Хочу предложить вам пользоваться %1$s на вашем смартфоне!\nДля загрузки: %2$s</string>
+  <string name="recommend_text">Хочу предложить вам использовать %1$s на смартфоне!\nЗагрузить можно здесь: %2$s
+       </string>
   <string name="auth_check_server">Проверить сервер</string>
-  <string name="auth_host_url">Адрес сервера</string>
-  <string name="auth_username">Ð\9fолÑ\8cзоваÑ\82елÑ\8c</string>
+  <string name="auth_host_url">Адрес сервера https://...</string>
+  <string name="auth_username">Ð\98мÑ\8f Ð¿Ð¾Ð»Ñ\8cзоваÑ\82елÑ\8f</string>
   <string name="auth_password">Пароль</string>
-  <string name="auth_register">Ð\92пеÑ\80вÑ\8bе с %1$s?</string>
+  <string name="auth_register">Ð\9dезнакомÑ\8b с %1$s?</string>
   <string name="sync_string_files">Файлы</string>
-  <string name="setup_btn_connect">СоединиÑ\82Ñ\8c</string>
-  <string name="uploader_btn_upload_text">Ð\97агÑ\80Ñ\83зка</string>
-  <string name="uploader_top_message">Выбрать место для загрузки:</string>
-  <string name="uploader_wrn_no_account_title">Ð\90ккаÑ\83нÑ\82Ñ\8b Ð½Ðµ Ð½Ð°Ð¹Ð´ÐµÐ½Ñ\8b</string>
-  <string name="uploader_wrn_no_account_text">На вашем устройстве нет аккаунтов %1$s. Настройте сначала аккаунт.</string>
+  <string name="setup_btn_connect">Ð\9fодклÑ\8eÑ\87иÑ\82Ñ\8cÑ\81Ñ\8f</string>
+  <string name="uploader_btn_upload_text">Ð\97агÑ\80Ñ\83зиÑ\82Ñ\8c</string>
+  <string name="uploader_top_message">Выберете папку для загрузки</string>
+  <string name="uploader_wrn_no_account_title">УÑ\87Ñ\91Ñ\82наÑ\8f Ð·Ð°Ð¿Ð¸Ñ\81Ñ\8c Ð½Ðµ Ð½Ð°Ð¹Ð´ÐµÐ½Ð°</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="uploader_wrn_no_content_text">Ð\9aонÑ\82енÑ\82 Ð½Ðµ Ð¿Ð¾Ð»Ñ\83Ñ\87ен. Нечего загружать.</string>
+  <string name="uploader_wrn_no_content_text">СодеÑ\80жимое Ð½Ðµ Ð¿Ð¾Ð»Ñ\83Ñ\87ено. Нечего загружать.</string>
   <string name="uploader_error_forbidden_content">%1$s не имеет доступа к опубликованным данным</string>
   <string name="uploader_info_uploading">Загрузка</string>
-  <string name="file_list_empty">В этой папке нет файлов.\nНовые файлы могут быть добавлены с помощью пункта меню \"Загрузить\".</string>
+  <string name="file_list_empty">Здесь ничего нет. Загрузите что-нибудь!</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_download">Скачать</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">Ð\9eÑ\82мена Ð·Ð°Ð³Ñ\80Ñ\83зки</string>
+  <string name="common_cancel_upload">Ð\9eÑ\82мениÑ\82Ñ\8c Ð·Ð°Ð³Ñ\80Ñ\83зкÑ\83</string>
   <string name="common_cancel">Отмена</string>
-  <string name="common_save_exit">Сохранить &amp; Выйти</string>
+  <string name="common_save_exit">Сохранить и выйти</string>
   <string name="common_error">Ошибка</string>
-  <string name="common_loading">Ð\97агÑ\80Ñ\83жаеÑ\82Ñ\81Ñ\8f...</string>
+  <string name="common_loading">Ð\98дÑ\91Ñ\82 Ð·Ð°Ð³Ñ\80Ñ\83зка...</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="delete_account">Удалить учётную запись</string>
+  <string name="create_account">Создать учётную запись</string>
   <string name="upload_chooser_title">Загрузить из...</string>
-  <string name="uploader_info_dirname">Ð\98мÑ\8f Ð´Ð¸Ñ\80екÑ\82оÑ\80ии</string>
+  <string name="uploader_info_dirname">Ð\98мÑ\8f Ð¿Ð°Ð¿Ðºи</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">Ð\97агÑ\80Ñ\83зка Ð¿Ñ\80оÑ\88ла Ñ\83Ñ\81пеÑ\88но</string>
+  <string name="uploader_upload_succeeded_ticker">Ð\97агÑ\80Ñ\83зка Ð·Ð°Ð²ÐµÑ\80Ñ\88ена</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_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">СкаÑ\87ивание Ð¿Ñ\80оÑ\88ло Ñ\83Ñ\81пеÑ\88но</string>
+  <string name="downloader_download_succeeded_ticker">СкаÑ\87ивание Ð·Ð°Ð²ÐµÑ\80Ñ\88ено</string>
   <string name="downloader_download_succeeded_content">%1$s успешно скачан</string>
-  <string name="downloader_download_failed_ticker">СкаÑ\87ивание Ð½Ðµ Ñ\83далась</string>
+  <string name="downloader_download_failed_ticker">СкаÑ\87ивание Ð½Ðµ Ñ\83далось</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_not_downloaded_yet">Ещё не скачано</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_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_conflicts_in_favourites_content">%1$d файлы, которые должны быть синхронизированными не могут синхронизироваться</string>
+  <string name="sync_conflicts_in_favourites_content">%1$d файлы не могут быть синхронизированы</string>
   <string name="sync_fail_in_favourites_ticker">Не удалось синхронизировать файлы</string>
-  <string name="sync_fail_in_favourites_content">СодеÑ\80жание %1$d Ñ\84айла(ов) Ð½Ðµ Ð¼Ð¾Ð¶ÐµÑ\82 Ð±Ñ\8bÑ\82Ñ\8c Ñ\81инÑ\85Ñ\80онизиÑ\80овано (%2$d ÐºÐ¾Ð½Ñ\84ликÑ\82а(ов))</string>
+  <string name="sync_fail_in_favourites_content">СодеÑ\80жимое %1$d Ñ\84айлов Ð½Ðµ Ð¼Ð¾Ð¶ÐµÑ\82 Ð±Ñ\8bÑ\82Ñ\8c Ñ\81инÑ\85Ñ\80онизиÑ\80овано (конÑ\84ликÑ\82ов: %2$d)</string>
   <string name="sync_foreign_files_forgotten_ticker">Несколько локальных файлов были забыты</string>
-  <string name="sync_foreign_files_forgotten_content">%1$d файлы из %2$s папки не могут быть скопированы в</string>
-  <string name="sync_foreign_files_forgotten_explanation">файлы, загруженные с этого устройства, скопированы в локальную папку %1$s для предотвращения потери данных, когда отдельный файл синхронизируется с нескольких учётных записей. По причине этого изменения, все файлы, загруженные в предыдущих версиях этого приложения, были скопированы в папку %2$s. Однако, ошибка помешала завершению этой операции при синхронизации учётной записи. Вы можете либо оставить файлы как есть, или переместить их в папку %1$s и сохранить ссылку в %4$s. \nВ списке указаны локальные файлы, привязанные к файлам на сервере в папке %5$s.</string>
+  <string name="sync_foreign_files_forgotten_content"> Не возможно скопировать %1$d файлы из %2$s папки</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">Ð\9eÑ\82Ñ\81Ñ\83Ñ\82Ñ\81Ñ\82вÑ\83еÑ\82 Ð´Ð¾Ñ\81Ñ\82аÑ\82оÑ\87ное ÐºÐ¾Ð»Ð¸Ñ\87еÑ\81Ñ\82во Ð¼ÐµÑ\81Ñ\82а Ð´Ð»Ñ\8f ÐºÐ¾Ð¿Ð¸Ñ\80ованиÑ\8f Ð²Ñ\8bделеннÑ\8bÑ\85 Ñ\84айлов Ð² Ð¿Ð°Ð¿ÐºÑ\83 %1$s. Ð¥Ð¾Ñ\82иÑ\82е Ð»Ð¸ Ð\92Ñ\8b Ð¿ÐµÑ\80емеÑ\81Ñ\82иÑ\82Ñ\8c Ð¸Ñ\85 в другое место?</string>
-  <string name="pincode_enter_pin_code">Вставьте PIN вашего приложения</string>
-  <string name="pincode_configure_your_pin">Введите  App PIN</string>
-  <string name="pincode_configure_your_pin_explanation">ПИН-код будет запрашиваться каждый раз, когда вы запускаете приложение.</string>
-  <string name="pincode_reenter_your_pincode">Повторите App PIN</string>
+  <string name="upload_query_move_foreign_files">Ð\94лÑ\8f ÐºÐ¾Ð¿Ð¸Ñ\80ованиÑ\8f Ð²Ñ\8bбÑ\80аннÑ\8bÑ\85 Ñ\84айлов Ð² Ð¿Ð°Ð¿ÐºÑ\83 %1$s Ð½ÐµÐ´Ð¾Ñ\81Ñ\82аÑ\82оÑ\87но Ñ\81вободного Ð¼ÐµÑ\81Ñ\82а. Ð¡ÐºÐ¾Ð¿Ð¸Ñ\80оваÑ\82Ñ\8c в другое место?</string>
+  <string name="pincode_enter_pin_code">Вставьте  App PIN</string>
+  <string name="pincode_configure_your_pin">Введите App PIN</string>
+  <string name="pincode_configure_your_pin_explanation">PIN-код будет запрашиваться при каждом запуске приложения.</string>
+  <string name="pincode_reenter_your_pincode">Повторите ввод App PIN</string>
   <string name="pincode_remove_your_pincode">Удалить App PIN</string>
-  <string name="pincode_mismatch">Ð\94ва App PIN не совпадают</string>
+  <string name="pincode_mismatch">Ð\92ведÑ\91ннÑ\8bе App PIN не совпадают</string>
   <string name="pincode_wrong">Неверный App PIN</string>
   <string name="pincode_removed">App PIN удалён</string>
   <string name="pincode_stored">App PIN сохранён</string>
-  <string name="media_notif_ticker">%1$s Ð¼Ñ\83зÑ\8bкалÑ\8cнÑ\8bй Ð¿Ñ\80оигÑ\80Ñ\8bваÑ\82елÑ\8c</string>
+  <string name="media_notif_ticker">%1$s Ð°Ñ\83диоплееÑ\80</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">Ð\9dе Ð½Ð°Ð¹Ð´ÐµÐ½ Ð¼ÐµÐ´Ð¸Ð°-Ñ\84айл</string>
-  <string name="media_err_no_account">Ð\9dе Ð½Ð°Ñ\81Ñ\82Ñ\80оена Ñ\83Ñ\87Ñ\91Ñ\82наÑ\8f Ð·Ð°Ð¿Ð¸Ñ\81Ñ\8c</string>
+  <string name="media_err_nothing_to_play">Ð\9cедиаÑ\84айлов Ð½Ðµ Ð½Ð°Ð¹Ð´ÐµÐ½Ð¾</string>
+  <string name="media_err_no_account">УÑ\87Ñ\91Ñ\82наÑ\8f Ð·Ð°Ð¿Ð¸Ñ\81Ñ\8c Ð½Ðµ Ð½Ð°Ñ\81Ñ\82Ñ\80оена</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">Тайм Ð°Ñ\83Ñ\82 Ð¿Ñ\80и Ð²Ð¾Ñ\81пÑ\80оизведении</string>
-  <string name="media_err_invalid_progressive_playback">Ð\9dевозможно Ð²Ð¾Ñ\81пÑ\80оизвеÑ\81Ñ\82и Ñ\84айл ÐºÐ°Ðº Ð¿Ð¾Ñ\82ок</string>
-  <string name="media_err_unknown">Файл Ð½Ðµ Ð¼Ð¾Ð¶ÐµÑ\82 Ð±Ñ\8bÑ\82Ñ\8c Ð¿Ñ\80оигÑ\80ан  стандартным плеером</string>
+  <string name="media_err_io">Ð\9cедиаÑ\84айл не может быть прочитан</string>
+  <string name="media_err_malformed">Ð\9cедиаÑ\84айл Ð½ÐµÐºÐ¾Ñ\80Ñ\80екÑ\82но Ð·Ð°ÐºÐ¾Ð´Ð¸Ñ\80ован</string>
+  <string name="media_err_timeout">Ð\92Ñ\80емÑ\8f Ð¿Ð¾Ð¿Ñ\8bÑ\82ок Ð²Ð¾Ñ\81пÑ\80оизведениÑ\8f Ð²Ñ\8bÑ\88ло</string>
+  <string name="media_err_invalid_progressive_playback">Ð\9dевозможно Ð¾Ñ\80ганизоваÑ\82Ñ\8c Ð¿Ð¾Ñ\82оковÑ\83Ñ\8e Ð¿ÐµÑ\80едаÑ\87Ñ\83 Ð¼ÐµÐ´Ð¸Ð°Ñ\84айла</string>
+  <string name="media_err_unknown">Ð\9cедиаÑ\84айл Ð½Ðµ Ð¼Ð¾Ð¶ÐµÑ\82 Ð±Ñ\8bÑ\82Ñ\8c Ð¿Ñ\80оигÑ\80ан стандартным плеером</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_no_net_conn_title">Нет подключения к сети</string>
   <string name="auth_nossl_plain_ok_title">Защищённое соединение недоступно.</string>
   <string name="auth_connection_established">Соединение установлено</string>
   <string name="auth_testing_connection">Тестирование соединения...</string>
-  <string name="auth_not_configured_title">Ð\9dевеÑ\80наÑ\8f ÐºÐ¾Ð½Ñ\84игÑ\83Ñ\80аÑ\86иÑ\8f Ñ\81еÑ\80веÑ\80</string>
-  <string name="auth_account_not_new">Учётная запись для такого пользователя и сервера уже существует на устройстве</string>
-  <string name="auth_account_not_the_same">Введённый пользователь не соответсвует пользователю учётной записи</string>
+  <string name="auth_not_configured_title">Ð\9aонÑ\84игÑ\83Ñ\80аÑ\86иÑ\8f Ñ\81еÑ\80веÑ\80а Ð·Ð°Ð´Ð°Ð½Ð° Ð½ÐµÐ²ÐµÑ\80но</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">ЭкземплÑ\8fÑ\80 Ñ\81ервер не найден</string>
+  <string name="auth_incorrect_path_title">Сервер не найден</string>
   <string name="auth_timeout_title">Сервер слишком долго не отвечает</string>
   <string name="auth_incorrect_address_title">Неверный URL</string>
   <string name="auth_ssl_general_error_title">Ошибка инициализации SSL</string>
-  <string name="auth_ssl_unverified_server_title">Невозможно проверить сертификат SSL сервера</string>
+  <string name="auth_ssl_unverified_server_title">Невозможно проверить SSL-сертификат сервера</string>
   <string name="auth_bad_oc_version_title">Неизвестная версия сервера</string>
   <string name="auth_wrong_connection_title">Невозможно установить соединение</string>
   <string name="auth_secure_connection">Защищённое соединение установлено</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">Ð\9dеожиданнÑ\8bй Ð¾Ñ\82веÑ\82; Ð¿Ð¾Ð¶Ð°Ð»Ñ\83йÑ\81Ñ\82а, Ð²Ð²ÐµÐ´Ð¸Ñ\82е Ð°Ð´Ñ\80еÑ\81 Ñ\81еÑ\80веÑ\80а ÐµÑ\89Ñ\91 Ñ\80аз</string>
-  <string name="auth_expired_oauth_token_toast">Ваша авторизация истекла. Пожалуйста, авторизуйтесь снова</string>
+  <string name="auth_oauth_error_access_denied">СеÑ\80веÑ\80 Ð°Ð²Ñ\82оÑ\80изаÑ\86ии Ð¾Ñ\82казал Ð² Ð´Ð¾Ñ\81Ñ\82Ñ\83пе</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_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_unsupported_multiaccount">%1$s не поддерживает сразу несколько учётных записей</string>
+  <string name="auth_fail_get_user_name">Ваш сервер не возвращает корректный пользовательский идентификатор, пожалуйста свяжитесь с администратором
+⇥</string>
+  <string name="auth_can_not_auth_against_server">Невозможно аутентифицироваться на этом сервере</string>
   <string name="fd_keep_in_sync">Обновлять файл</string>
   <string name="common_rename">Переименовать</string>
   <string name="common_remove">Удалить</string>
-  <string name="confirmation_remove_alert">Ð\92Ñ\8b Ð² Ñ\81амом Ð´ÐµÐ»Ðµ Ñ\85оÑ\82иÑ\82е Ñ\83далиÑ\82Ñ\8c %1$s ?</string>
-  <string name="confirmation_remove_folder_alert">Вы действительно хотите удалить %1$s  и его содержимое ?</string>
+  <string name="confirmation_remove_alert">Ð\92Ñ\8b Ð´ÐµÐ¹Ñ\81Ñ\82виÑ\82елÑ\8cно Ñ\85оÑ\82иÑ\82е Ñ\83далиÑ\82Ñ\8c %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">Ð\98 Ñ\83далённо и локально</string>
-  <string name="remove_success_msg">Успешное удаление</string>
-  <string name="remove_fail_msg">Удаление Ð½Ðµ Ð¼Ð¾Ð¶ÐµÑ\82 Ð±Ñ\8bÑ\82Ñ\8c Ð·Ð°Ð²ÐµÑ\80Ñ\88ено</string>
+  <string name="confirmation_remove_remote_and_local">Удалённо и локально</string>
+  <string name="remove_success_msg">Удаление завершено</string>
+  <string name="remove_fail_msg">Ð\9eÑ\88ибка Ñ\83далениÑ\8f</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_nothing_to_do_msg">Содержимое файла уже синхронизировано</string>
-  <string name="create_dir_fail_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_unexpected_bad_get_content">Ð\9dеизвеÑ\81Ñ\82наÑ\8f Ð¾Ñ\88ибка; Ð¿Ð¾Ð¿Ñ\80обÑ\83йÑ\82е Ð´Ñ\80Ñ\83гое Ð¿Ñ\80иложение Ð´Ð»Ñ\8f Ð²Ñ\8bбоÑ\80а Ñ\84айла</string>
+  <string name="filedisplay_unexpected_bad_get_content">Ð\9dеизвеÑ\81Ñ\82наÑ\8f Ð¾Ñ\88ибка; Ð²Ñ\8bбеÑ\80иÑ\82е Ñ\8dÑ\82оÑ\82 Ñ\84айл Ð¸Ð· Ð´Ñ\80Ñ\83гого Ð¿Ñ\80иложениÑ\8f</string>
   <string name="filedisplay_no_file_selected">Файлы не выбраны</string>
-  <string name="oauth_check_onoff">Подключать через oAuth2</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">- Сертификат сервера не является доверенным</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">Ð\92Ñ\81е-Ñ\80авно Ð´Ð¾Ð²ÐµÑ\80Ñ\8fÑ\82Ñ\8c Ð´Ð°Ð½Ð½Ð¾Ð¼Ñ\83 Ñ\81еÑ\80Ñ\82иÑ\84икаÑ\82Ñ\83?</string>
+  <string name="ssl_validator_reason_cert_not_yet_valid">- Срок действия сертификата сервера ещё не начался</string>
+  <string name="ssl_validator_reason_hostname_not_verified">- URL не совпадает с именем сервера в сертификате</string>
+  <string name="ssl_validator_question">Ð\92Ñ\8b Ñ\85оÑ\82иÑ\82е Ð´Ð¾Ð²ÐµÑ\80Ñ\8fÑ\82Ñ\8c Ð´Ð°Ð½Ð½Ð¾Ð¼Ñ\83 Ñ\81еÑ\80Ñ\82иÑ\84икаÑ\82Ñ\83 Ð² Ð»Ñ\8eбом Ñ\81лÑ\83Ñ\87ае?</string>
   <string name="ssl_validator_not_saved">Сертификат не может быть сохранён</string>
-  <string name="ssl_validator_btn_details_see">Ð\94еÑ\82али</string>
-  <string name="ssl_validator_btn_details_hide">СпÑ\80Ñ\8fÑ\82ать</string>
-  <string name="ssl_validator_label_subject">Ð\92Ñ\8bдано Ð´Ð»Ñ\8f:</string>
-  <string name="ssl_validator_label_issuer">Ð\92Ñ\8bдан:</string>
+  <string name="ssl_validator_btn_details_see">Ð\9fодÑ\80обно</string>
+  <string name="ssl_validator_btn_details_hide">СкÑ\80Ñ\8bть</string>
+  <string name="ssl_validator_label_subject">Ð\9aомÑ\83 Ð²Ñ\8bдано:</string>
+  <string name="ssl_validator_label_issuer">Ð\9aем Ð²Ñ\8bдано:</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">Страна:</string>
-  <string name="ssl_validator_label_ST">СÑ\82аÑ\82Ñ\83Ñ\81:</string>
+  <string name="ssl_validator_label_ST">ШÑ\82аÑ\82:</string>
   <string name="ssl_validator_label_L">Местонахождение:</string>
   <string name="ssl_validator_label_validity">Срок действия:</string>
-  <string name="ssl_validator_label_validity_from">Ð\9eÑ\82:</string>
-  <string name="ssl_validator_label_validity_to">Ð\94о:</string>
+  <string name="ssl_validator_label_validity_from">Ð\98з:</string>
+  <string name="ssl_validator_label_validity_to">Ð\92:</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">placeholder.txt</string>
   <string name="placeholder_filetype">Изображение PNG</string>
-  <string name="placeholder_filesize">389 KB</string>
+  <string name="placeholder_filesize">389 КБ</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">Загружать изображения только через Wi-Fi</string>
+  <string name="instant_video_upload_on_wifi">Загрузка видео только через WiFi</string>
   <string name="instant_upload_path">/InstantUpload</string>
   <string name="conflict_title">Конфликт обновления</string>
-  <string name="conflict_message">УдаленнÑ\8bй Ñ\84айл %s Ð½Ðµ Ñ\81инÑ\85Ñ\80онизиÑ\80ован Ñ\81 Ð»Ð¾ÐºÐ°Ð»Ñ\8cнÑ\8bм. Ð\97авеÑ\80Ñ\88ение Ð¿Ñ\80иведеÑ\82 Ðº Ð·Ð°Ð¼ÐµÐ½Ðµ Ñ\81одеÑ\80жаниÑ\8f файла на сервере.</string>
-  <string name="conflict_keep_both">Ð\9eÑ\81Ñ\82авить оба</string>
+  <string name="conflict_message">УдаленнÑ\8bй Ñ\84айл %s Ð½Ðµ Ñ\81инÑ\85Ñ\80онизиÑ\80ован Ñ\81 Ð»Ð¾ÐºÐ°Ð»Ñ\8cнÑ\8bм. Ð\9fÑ\80одолжение Ð¿Ñ\80иведеÑ\82 Ðº Ð·Ð°Ð¼ÐµÐ½Ðµ Ñ\81одеÑ\80жимого файла на сервере.</string>
+  <string name="conflict_keep_both">СоÑ\85Ñ\80анить оба</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="actionbar_failed_instant_upload">Быстрая загрузка не удалась</string>
-  <string name="failed_upload_headline_text">Быстрые загрузки не удались</string>
-  <string name="failed_upload_headline_hint">Список всех неудачных загрузок</string>
-  <string name="failed_upload_all_cb">Выбрать всё</string>
-  <string name="failed_upload_headline_retryall_btn">Ещё раз попробовать всё выделенное</string>
-  <string name="failed_upload_headline_delete_all_btn">Удалить всё| выбранное из очереди загрузки</string>
-  <string name="failed_upload_retry_text">Попробовать ещё раз загрузить изображение</string>
-  <string name="failed_upload_load_more_images">Загрузить больше картинок</string>
-  <string name="failed_upload_retry_do_nothing_text">Ничего не делать, если не в сети</string>
-  <string name="failed_upload_failure_text">Сообщение об ошибке</string>
-  <string name="failed_upload_quota_exceeded_text">Проверьте настройки сервера, возможно ваш лимит превышен</string>
+  <string name="error__upload__local_file_not_copied">%1$s не возможно скопировать в локальною папку %2$s </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="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="actionbar_logger">Журналы</string>
+  <string name="log_send_history_button">История Отправлений</string>
+  <string name="log_mail_subject">Журналы Андроид-приложения ownCloud</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="move_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_security">Безопасность</string>
 </resources>
index 59a8531..e64f577 100644 (file)
@@ -2,17 +2,13 @@
 <resources>
   <string name="actionbar_upload">උඩුගත කිරීම</string>
   <string name="actionbar_upload_files">ගොනු</string>
-  <string name="actionbar_mkdir">ඩිරෙක්ටරිය සාදන්න</string>
   <string name="actionbar_settings">සිටුවම්</string>
   <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_summary">ඔබේ සේවාලාභියා සුරකින්න</string>
-  <string name="prefs_instant_upload">ක්‍ෂණික උඩුගත කිරීම් සක්‍රිය කරන්න</string>
-  <string name="prefs_instant_upload_summary">කැමරාවෙන් ගත් රූප ක්‍ෂණිකව උඩුගත කරන්න</string>
   <string name="prefs_help">උදව්</string>
-  <string name="auth_host_url">සේවාදායකයේ ලිපිනය</string>
   <string name="auth_username">පරිශීලක නම</string>
   <string name="auth_password">මුර පදය</string>
   <string name="sync_string_files">ගොනු</string>
@@ -23,6 +19,7 @@
   <string name="uploader_wrn_no_account_setup_btn_text">ස්ථාපනය</string>
   <string name="uploader_wrn_no_account_quit_btn_text">නික්මෙන්න</string>
   <string name="uploader_info_uploading">උඩුගතවේ</string>
+  <string name="file_list_empty">මෙහි කිසිවක් නොමැත. යමක් උඩුගත කරන්න</string>
   <string name="filedetails_select_file">වැඩි විස්තර සඳහා ගොනුවක් ස්පර්ෂ කරන්න</string>
   <string name="filedetails_size">විශාලත්වය:</string>
   <string name="filedetails_type">ගණය:</string>
@@ -40,7 +37,7 @@
   <string name="change_password">මුරපදය වෙනස් කිරීම</string>
   <string name="delete_account">ගිණුම මකන්න</string>
   <string name="create_account">ගිණුම සාදන්න</string>
-  <string name="uploader_info_dirname">à¶©à·\92à¶»à·\99à¶\9aà·\8aà¶§à¶»à·\92 නම</string>
+  <string name="uploader_info_dirname">à·\86à·\9cà¶½à·\8aඩරයà·\9a නම</string>
   <string name="uploader_upload_succeeded_ticker">උඩුගත කිරීම සාර්ථකයි</string>
   <string name="uploader_upload_failed_ticker">උඩුගත කිරීම අසාර්ථකයි</string>
   <string name="downloader_download_in_progress_ticker">බාගතවේ...</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_local">පෙදෙසි පමණක්</string>
   <string name="confirmation_remove_remote">සේවාදායකයාගෙන් ඉවත් කරන්න</string>
   <string name="confirmation_remove_remote_and_local">දුරස්ථ හා පෙදෙසි </string>
   <string name="remove_success_msg">සාර්ථක ඉවත්කිරීමක්</string>
   <string name="remove_fail_msg">ඉවත් කිරීම සම්පූර්ණ කළ නොහැක</string>
   <string name="rename_server_fail_msg">නැවත නම් කිරීම සම්පුර්ණ කළ නොහැකි විය</string>
-  <string name="create_dir_fail_msg">ඩිරෙක්ටරිය සෑදීමට නොහැකි විය</string>
   <string name="wait_a_moment">ස්වල්ප මොහොතක් සිටින්න</string>
   <string name="filedisplay_unexpected_bad_get_content">නොසිතු ප්‍රශ්ණයක්; කරුණාකර වෙනත් යෙදුමක් භාවිතා කර ගොනුව තෝරන්න</string>
   <string name="filedisplay_no_file_selected">ගොනුවක් තෝරා නැත</string>
   <string name="ssl_validator_btn_details_hide">සඟවන්න</string>
+  <string name="empty"></string>
+  <string name="prefs_category_accounts">ගිණුම්</string>
+  <string name="move_choose_button_text">තෝරන්න</string>
 </resources>
index 16b7778..7686043 100644 (file)
@@ -7,17 +7,20 @@
   <string name="actionbar_upload_from_apps">Obsah z inej aplikácie</string>
   <string name="actionbar_upload_files">Súbory</string>
   <string name="actionbar_open_with">Otvoriť v</string>
-  <string name="actionbar_mkdir">Vytvor priečinok</string>
+  <string name="actionbar_mkdir">Nový priečinok</string>
   <string name="actionbar_settings">Nastavenia</string>
   <string name="actionbar_see_details">Podrobnosti</string>
+  <string name="actionbar_send_file">Odoslať</string>
   <string name="prefs_category_general">Všeobecné</string>
   <string name="prefs_category_more">Viac</string>
   <string name="prefs_accounts">Účty</string>
   <string name="prefs_manage_accounts">Správa účtov</string>
   <string name="prefs_pincode">PIN aplikácie</string>
   <string name="prefs_pincode_summary">Chrániť klienta aplikácie</string>
-  <string name="prefs_instant_upload">Zapnúť okamžité odosielanie</string>
-  <string name="prefs_instant_upload_summary">Okamžite odosielať fotky z fotoaparátu</string>
+  <string name="prefs_instant_upload">Okamžité nahratie obrázka</string>
+  <string name="prefs_instant_upload_summary">Okamžite nahrať obrázok zaznamenaný fotoaparátom</string>
+  <string name="prefs_instant_video_upload">Okamžité nahranie videa</string>
+  <string name="prefs_instant_video_upload_summary">Okamžite nahrať video zaznamenané fotoaparátom</string>
   <string name="prefs_log_title">Povoliť logovanie</string>
   <string name="prefs_log_summary">Toto je použité pre logovanie problémov</string>
   <string name="prefs_log_title_history">História logovania</string>
   <string name="prefs_imprint">Podmienky používania</string>
   <string name="recommend_subject">Skúste %1$s na vašom telefóne!</string>
   <string name="auth_check_server">Skontrolovať Server</string>
-  <string name="auth_host_url">Adresa servera</string>
+  <string name="auth_host_url">Adresa servera https://...</string>
   <string name="auth_username">Používateľské meno</string>
   <string name="auth_password">Heslo</string>
   <string name="auth_register">Ste nový v %1$s?</string>
   <string name="sync_string_files">Súbory</string>
-  <string name="setup_btn_connect">Pripoj</string>
+  <string name="setup_btn_connect">Pripoj</string>
   <string name="uploader_btn_upload_text">Nahrať</string>
-  <string name="uploader_top_message">Vyberte priečinok pre nahrané súbory:</string>
+  <string name="uploader_top_message">Vyberte priečinok pre nahrávanie:</string>
   <string name="uploader_wrn_no_account_title">Účet sa nenašiel</string>
   <string name="uploader_wrn_no_account_text">Na tomto zariadení nie je zadaný žiadny %1$s účet. Zadajte ho prosím.</string>
   <string name="uploader_wrn_no_account_setup_btn_text">Nastavenie</string>
@@ -45,7 +48,9 @@
   <string name="uploader_wrn_no_content_text">Nedodaný žiaden obsah. Nič na odoslanie.</string>
   <string name="uploader_error_forbidden_content">%1$s nemá práva pre prístup k zdieľanému obsahu</string>
   <string name="uploader_info_uploading">Nahrávanie</string>
-  <string name="file_list_empty">Priečinok neobsahuje súbory.\nNové súbory môžete pridať cez \"Upload\".</string>
+  <string name="file_list_empty">Žiadny súbor. Nahrajte niečo!</string>
+  <string name="file_list_loading">Nahráva sa...</string>
+  <string name="local_file_list_empty">V tomto priečinku nie sú žiadne súbory.</string>
   <string name="filedetails_select_file">Viac informácií získate kliknutím na súbor.</string>
   <string name="filedetails_size">Veľkosť:</string>
   <string name="filedetails_type">Typ:</string>
@@ -54,6 +59,8 @@
   <string name="filedetails_download">Stiahnuť</string>
   <string name="filedetails_sync_file">Obnoviť súbor</string>
   <string name="filedetails_renamed_in_upload_msg">Súbor bol premenovaný na %1$s počas nahrávania</string>
+  <string name="action_share_file">Zdieľať linku</string>
+  <string name="action_unshare_file">Zrušiť zdieľanie odkazu</string>
   <string name="common_yes">Áno</string>
   <string name="common_no">Nie</string>
   <string name="common_ok">OK</string>
@@ -76,6 +83,7 @@
   <string name="uploader_upload_succeeded_content_single">%1$s úspešne odoslaný</string>
   <string name="uploader_upload_failed_ticker">Odoslanie bolo neúspešné</string>
   <string name="uploader_upload_failed_content_single">Odoslanie %1$s nemohlo byť dokončené</string>
+  <string name="uploader_upload_failed_credentials_error">Nahrávanie zlyhalo. Prihláste sa znovu</string>
   <string name="downloader_download_in_progress_ticker">Sťahujem ...</string>
   <string name="downloader_download_in_progress_content">%1$d%% Sťahovanie %2$s</string>
   <string name="downloader_download_succeeded_ticker">Sťahovanie bolo úspešné</string>
   <string name="downloader_download_failed_ticker">Stiahnutie zlyhalo</string>
   <string name="downloader_download_failed_content">Sťahovanie %1$s nebolo dokončené</string>
   <string name="downloader_not_downloaded_yet">Ešte nie je stiahnuté</string>
+  <string name="downloader_download_failed_credentials_error">Sťahovanie zlyhalo. Prihláste sa znovu</string>
   <string name="common_choose_account">Zvoliť účet</string>
   <string name="sync_fail_ticker">Synchronizácia zlyhala</string>
+  <string name="sync_fail_ticker_unauthorized">Synchronizácia zlyhala. Prihláste sa znovu</string>
   <string name="sync_fail_content">Synchronizáciu %1$s nemožno dokončiť</string>
   <string name="sync_fail_content_unauthorized">Nesprávne heslo pre %1$s</string>
   <string name="sync_conflicts_in_favourites_ticker">Objavené konflikty</string>
   <string name="sync_fail_in_favourites_ticker">Automatická synchronizácia súborov zlyhala</string>
   <string name="sync_fail_in_favourites_content">Obsah %1$d súborov nemohol byť synchronizovaný (%2$d konfliktov)</string>
   <string name="sync_foreign_files_forgotten_ticker">Niektoré lokálne súbory boli zabudnuté</string>
-  <string name="sync_foreign_files_forgotten_content">%1$d súborov z priečinka %2$s nemožno skopírovať do</string>
-  <string name="sync_foreign_files_forgotten_explanation">Od verzie 1.3.16 sú súbory nahrané z tohoto zariadenia, skopírovné do lokálneho priečinka %1$s, aby sa zabránilo strate dát, keď je jeden súbor synchronizovný s viacerými účtami.\n\nPre túto zmenu, všetky súbory nahraté v predchádzajúcich verziách tejto aplikácie boli skopírované do priečinka %2$s. Je nám to ľúto, chyba zabránila dokončeniu tejto operácie počas synchronizácie účtu. Súbor(y) môžete ponechať v súčasnom stave a zmazať odkaz na %3$s, alebo presunúť súbor(y) do priečinka %1$s a zachovať odkaz na %4$s.\n\nĎalej lokálny súbor(y) a vzdialený súbor(y) sú spojené v priečinku %5$s.</string>
+  <string name="sync_foreign_files_forgotten_content">%1$d súborov z %2$s priečinkov sa nepodarilo skopírovať do</string>
+  <string name="sync_current_folder_was_removed">Priečinok %1$s už existuje</string>
   <string name="foreign_files_move">Premiestniť všetko</string>
   <string name="foreign_files_success">Všetky súbory boli premiestnené</string>
   <string name="foreign_files_fail">Niektoré súbory nebolo možné premiestniť</string>
   <string name="foreign_files_local_text">Lokálne: %1$s</string>
   <string name="foreign_files_remote_text">Vzdialené: %1$s</string>
-  <string name="upload_query_move_foreign_files">Nie je dostatok miesta na kopírovanie vybraných súborov do priečinka %1$s. Želáte si miesto kopírovania zmeniť?</string>
+  <string name="upload_query_move_foreign_files">Nie je dostatok miesta na skopírovanie vybraných súborov do priečinka %1$s. Želáte si ich namiesto toho presunúť?</string>
   <string name="pincode_enter_pin_code">Zadajte PIN aplikácie</string>
   <string name="pincode_configure_your_pin">Zadajte PIN aplikácie</string>
   <string name="pincode_configure_your_pin_explanation">Pri každom spustení aplikácie bude vyžadovaný PIN</string>
   <string name="pincode_reenter_your_pincode">Zadajte znovu PIN aplikácie</string>
   <string name="pincode_remove_your_pincode">Zrušiť PIN pre aplikáciu</string>
-  <string name="pincode_mismatch">PIN sa neshodujú</string>
+  <string name="pincode_mismatch">PINy sa neshodujú</string>
   <string name="pincode_wrong">Nesprávny PIN aplikácie</string>
   <string name="pincode_removed">PIN aplikácie bol odstránený</string>
   <string name="pincode_stored">PIN aplikácie bol uložený</string>
   <string name="media_rewind_description">Tlačidlo pretáčania</string>
   <string name="media_play_pause_description">Tlačidlo prehrávania / pauzy</string>
   <string name="media_forward_description">Tlačidlo \"rýchlo vpred\"</string>
+  <string name="auth_getting_authorization">Kontrolujem poverenia...</string>
   <string name="auth_trying_to_login">Pokus o pripojenie...</string>
   <string name="auth_no_net_conn_title">Bez sieťového pripojenia</string>
   <string name="auth_nossl_plain_ok_title">Nie je k dispozícii bezpečné pripojenie</string>
   <string name="auth_account_not_the_same">Zadané prihlasovacie údaje používateľa sú nesprávne</string>
   <string name="auth_unknown_error_title">Nastala neznáma chyba!</string>
   <string name="auth_unknown_host_title">Nemožno nájsť hosta</string>
-  <string name="auth_incorrect_path_title">Servera inštancia nebola nájdená</string>
+  <string name="auth_incorrect_path_title">Inštancia servera nebola nájdená</string>
   <string name="auth_timeout_title">Serveru trvá odpoveď príliš dlho</string>
   <string name="auth_incorrect_address_title">Poškodená URL</string>
   <string name="auth_ssl_general_error_title">Inicializácia SSL zlyhala</string>
   <string name="auth_oauth_error">Neúspešná autorizácia</string>
   <string name="auth_oauth_error_access_denied">Prístup odmietnutý autorizačným serverom</string>
   <string name="auth_wtf_reenter_URL">Nečakaný stav; prosím, opätovne vložte URL adresu servera</string>
-  <string name="auth_expired_oauth_token_toast">Vaša autorizácia expirovala. Prosím autorizujte sa znovu prosím</string>
+  <string name="auth_expired_oauth_token_toast">Vaša autorizácia vypršala. Prosím, autorizujte sa znovu</string>
   <string name="auth_expired_basic_auth_toast">Prosím, zadajte aktuálne heslo</string>
-  <string name="auth_expired_saml_sso_token_toast">Vaše pripojenie expirovalo. Pripojte sa znovu prosím</string>
+  <string name="auth_expired_saml_sso_token_toast">Vaše pripojenie vypršalo. Pripojte sa znovu prosím</string>
   <string name="auth_connecting_auth_server">Pripájam sa na autentifikačný server...</string>
   <string name="auth_unsupported_auth_method">Server nepodporuje túto autentifikačnú metódu</string>
   <string name="auth_unsupported_multiaccount">%1$s nepodporuje viacero účtov</string>
+  <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="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="confirmation_remove_alert">Naozaj odstrániť %1$s ?</string>
-  <string name="confirmation_remove_folder_alert">Chcete odstrániť %1$s a jeho obsah?</string>
+  <string name="confirmation_remove_alert">Naozaj chcete odstrániť %1$s?</string>
+  <string name="confirmation_remove_folder_alert">Naozaj chcete odstrániť %1$s a jeho obsah?</string>
   <string name="confirmation_remove_local">Iba lokálne</string>
   <string name="confirmation_remove_folder_local">Len lokálny obsah</string>
   <string name="confirmation_remove_remote">Zmazať zo servera</string>
   <string name="sync_file_fail_msg">Vzdialený súbor nemohol byť prekontrolovaný</string>
   <string name="sync_file_nothing_to_do_msg">Obsah súboru je zosynchronizovaný</string>
   <string name="create_dir_fail_msg">Priečinok nie je možné vytvoriť</string>
+  <string name="filename_forbidden_characters">Zakázané znaky: / \\ &lt; &gt; : \" | ? *</string>
+  <string name="filename_empty">Názov súboru nemôže byť prázdny</string>
   <string name="wait_a_moment">Počkať chvíľu</string>
   <string name="filedisplay_unexpected_bad_get_content">Neočakávaný problém; skúste vybrať súbor inou aplikáciou</string>
   <string name="filedisplay_no_file_selected">Nebol vybraný súbor</string>
+  <string name="activity_chooser_title">Odošli link do ...</string>
+  <string name="oauth_check_onoff">Prihlásiť sa z oAuth2</string>
   <string name="oauth_login_connection">Pripájam sa na oAuth2 server…</string>
   <string name="ssl_validator_header">Identitu stránky nemožno overiť</string>
   <string name="ssl_validator_reason_cert_not_trusted">- Certifikát servera nie je overený</string>
   <string name="ssl_validator_label_validity_to">Do: </string>
   <string name="ssl_validator_label_signature">Podpis:</string>
   <string name="ssl_validator_label_signature_algorithm">Algoritmus:</string>
+  <string name="ssl_validator_null_cert">Certifikát nemohol byť zobrazený.</string>
+  <string name="ssl_validator_no_info_about_error">- Žiadne informácie o tejto chybe</string>
   <string name="placeholder_sentence">Toto je \"placeholder\"</string>
   <string name="placeholder_filename">placeholder.txt</string>
   <string name="placeholder_filetype">PNG obrázok</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">Odoslať fotografie iba cez WiFi</string>
+  <string name="instant_video_upload_on_wifi">Nahrávať videá len cez WiFi</string>
   <string name="instant_upload_path">/InstantUpload</string>
   <string name="conflict_title">Konflikt pri aktualizácii</string>
   <string name="conflict_message">Vzdialený súbor %s nie je zosynchronizovaný s lokálnym. Pokračovanie prepíše obsah súboru na serveri.</string>
   <string name="conflict_overwrite">Prepísať</string>
   <string name="conflict_dont_upload">Nenahrávajte</string>
   <string name="preview_image_description">Ukážka obrazu</string>
-  <string name="preview_image_error_unknown_format">Obraz nemôže byť zobrazený</string>
+  <string name="preview_image_error_unknown_format">Obrázok nemožno zobraziť</string>
   <string name="error__upload__local_file_not_copied">%1$s nemožno skopírovať do lokálneho priečinka %2$s</string>
-  <string name="actionbar_failed_instant_upload">Zlyhaný InstantnýUpload\"</string>
-  <string name="failed_upload_headline_text">Zlyhané instantné nahratia</string>
-  <string name="failed_upload_headline_hint">Zhrnutie všetkých zlyhaných nahratí</string>
-  <string name="failed_upload_all_cb">vybrať všetko</string>
-  <string name="failed_upload_headline_retryall_btn">opakovať všetky vybrané</string>
-  <string name="failed_upload_headline_delete_all_btn">zmazať všetky vybrané z radu pre nahratie</string>
-  <string name="failed_upload_retry_text">opakovať nahratie obrazu:</string>
-  <string name="failed_upload_load_more_images">Načítať viac Obrázkov</string>
-  <string name="failed_upload_retry_do_nothing_text">nevykonať nič, nie ste online pre instantné nahratie</string>
-  <string name="failed_upload_failure_text">Chybová správa:</string>
-  <string name="failed_upload_quota_exceeded_text">Prosím skontrolujte nastavenie vášho servera, možno bola prekročená disková kvóta.</string>
+  <string name="share_link_no_support_share_api">Je nám to ľúto, ale zdieľanie nie je na vašom serveri povolené. Prosím kontaktujte vášho
+               administrátora.</string>
+  <string name="share_link_file_error">Pri pokuse o zdieľanie tohto súboru alebo priečinka došlo k chybe</string>
+  <string name="unshare_link_file_error">Pri pokuse zrušiť zdieľanie tohto súboru alebo priečinka došlo k chybe</string>
+  <string name="activity_chooser_send_file_title">Odoslať</string>
+  <string name="copy_link">Kopíruj odkaz</string>
+  <string name="clipboard_text_copied">Skopírované do schránky</string>
+  <string name="error_cant_bind_to_operations_service">Kritická chyba: operáciu nemožno vykonať</string>
+  <string name="network_error_socket_exception">Pri pokuse o pripojenie na server nastala chyba.</string>
+  <string name="network_error_socket_timeout_exception">Pri čakaní na odpoveď servera nastala chyba, operácia nemohla byť dokončená</string>
+  <string name="network_error_connect_timeout_exception">Pri čakaní na odpoveď servera nastala chyba, operácia nemohla byť dokončená</string>
+  <string name="network_host_not_available">Operácia nemohla byť dokončená, server je nedostupný</string>
+  <string name="empty"></string>
+  <string name="forbidden_permissions">Nemáte oprávnenie %s</string>
+  <string name="forbidden_permissions_rename">premenovať tento súbor</string>
+  <string name="forbidden_permissions_delete">zmazať tento súbor</string>
+  <string name="share_link_forbidden_permissions">zdieľať tento súbor</string>
+  <string name="unshare_link_forbidden_permissions">zrušiť zdieľanie tohto súboru</string>
+  <string name="forbidden_permissions_create">vytvoriť súbor</string>
+  <string name="uploader_upload_forbidden_permissions">nahrávať do tohto priečinka</string>
+  <string name="downloader_download_file_not_found">Súbor už na serveri nie je dostupný</string>
+  <string name="prefs_category_accounts">Účty</string>
+  <string name="prefs_add_account">Pridať účet</string>
+  <string name="saml_authentication_required_text">Vyžaduje sa overenie</string>
+  <string name="saml_authentication_wrong_pass">Nesprávne heslo</string>
+  <string name="actionbar_move">Presunúť</string>
+  <string name="move_choose_button_text">Vybrať</string>
+  <string name="prefs_category_security">Zabezpečenie</string>
 </resources>
index c757504..63fbabf 100644 (file)
@@ -1,2 +1,8 @@
 <?xml version='1.0' encoding='UTF-8'?>
-<resources/>
+<resources>
+  <string name="actionbar_settings">Nastavenia</string>
+  <string name="prefs_category_general">Všeobecné</string>
+  <string name="filedetails_download">Stiahnuť</string>
+  <string name="common_cancel">Zrušiť</string>
+  <string name="empty"></string>
+</resources>
index a54c11c..dcdf603 100644 (file)
@@ -1,49 +1,67 @@
 <?xml version='1.0' encoding='UTF-8'?>
 <resources>
+  <string name="about_android">Program za Android %1$s</string>
+  <string name="about_version">različica %1$s</string>
+  <string name="actionbar_sync">Osveži račun</string>
   <string name="actionbar_upload">Pošlji datoteko</string>
   <string name="actionbar_upload_from_apps">Vsebina iz drugih programov</string>
   <string name="actionbar_upload_files">Datoteke</string>
-  <string name="actionbar_open_with">Odpri z:</string>
-  <string name="actionbar_mkdir">Ustvari mapo</string>
+  <string name="actionbar_open_with">Odpri z</string>
+  <string name="actionbar_mkdir">Nova mapa</string>
   <string name="actionbar_settings">Nastavitve</string>
   <string name="actionbar_see_details">Podrobnosti</string>
+  <string name="actionbar_send_file">Pošlji</string>
   <string name="prefs_category_general">Splošno</string>
   <string name="prefs_category_more">Več</string>
   <string name="prefs_accounts">Računi</string>
   <string name="prefs_manage_accounts">Upravljanje z računi</string>
   <string name="prefs_pincode">Koda PIN programa</string>
   <string name="prefs_pincode_summary">Zaščitite odjemalec</string>
-  <string name="prefs_instant_upload">Omogoči takojšnje pošiljanje</string>
-  <string name="prefs_instant_upload_summary">Takojšnje pošiljanje posnetih fotografij</string>
-  <string name="prefs_log_title">Omogoči zapisovanje v dnevnik</string>
-  <string name="prefs_log_title_history">Zgodovina</string>
+  <string name="prefs_instant_upload">Takojšnje pošiljanje slik</string>
+  <string name="prefs_instant_upload_summary">Takojšnje pošiljanje slik, zajetih s fotoaparatom, na strežnik</string>
+  <string name="prefs_instant_video_upload">Takojšnje pošiljanje posnetkov</string>
+  <string name="prefs_instant_video_upload_summary">Takojšnje pošiljanje posnetkov, zajetih s fotoaparatom, na strežnik</string>
+  <string name="prefs_log_title">Omogoči zapisovanje dnevnika</string>
+  <string name="prefs_log_summary">Uporablja se za beleženje težav in napak</string>
+  <string name="prefs_log_title_history">Zgodovina beleženja dnevnika</string>
+  <string name="prefs_log_summary_history">Pokaže shranjene dnevnike</string>
   <string name="prefs_log_delete_history_button">Izbriši zgodovino</string>
   <string name="prefs_help">Pomoč</string>
+  <string name="prefs_recommend">Priporoči prijateljem</string>
   <string name="prefs_feedback">Odziv</string>
   <string name="prefs_imprint">Natis</string>
-  <string name="auth_host_url">Naslov strežnika</string>
+  <string name="recommend_subject">Preizkusi %1$s na pametnem telefonu!</string>
+  <string name="recommend_text">Želim ti predstaviti %1$s na pametnem telefonu!\nPrejmeš ga lahko na: %2$s</string>
+  <string name="auth_check_server">Preveri strežnik</string>
+  <string name="auth_host_url">Naslov strežnika https://…</string>
   <string name="auth_username">Uporabniško ime</string>
   <string name="auth_password">Geslo</string>
+  <string name="auth_register">Ali ste novi uporabnik sistema %1$s?</string>
   <string name="sync_string_files">Datoteke</string>
   <string name="setup_btn_connect">Poveži</string>
   <string name="uploader_btn_upload_text">Pošlji</string>
-  <string name="uploader_top_message">Izberite mapo, v katero boste prenesli dokumente:</string>
+  <string name="uploader_top_message">Izbor mape za pošiljanje:</string>
   <string name="uploader_wrn_no_account_title">Uporabniškega računa ni mogoče najti</string>
   <string name="uploader_wrn_no_account_text">Na napravi ni računov %1$s. Nastaviti je treba vsaj en račun.</string>
   <string name="uploader_wrn_no_account_setup_btn_text">Nastavi</string>
   <string name="uploader_wrn_no_account_quit_btn_text">Končaj</string>
   <string name="uploader_wrn_no_content_title">Ni vsebine za pošiljanje</string>
   <string name="uploader_wrn_no_content_text">Ni prejete vsebine. Ni datotek za pošiljanje.</string>
-  <string name="uploader_error_forbidden_content">Oblak %1$s nima dovoljenj za dostop do vsebine v souporabi</string>
+  <string name="uploader_error_forbidden_content">Oblak %1$s nima nastavljenih dovoljenj za dostop do vsebine v souporabi</string>
   <string name="uploader_info_uploading">Pošiljanje</string>
-  <string name="file_list_empty">V tej mapi ni datotek.\nNove datoteke je mogoče dodati preko možnosti menija \"Pošlji\".</string>
+  <string name="file_list_empty">Tukaj še ni ničesar. Najprej je treba datoteke poslati v oblak!</string>
+  <string name="file_list_loading">Poteka nalaganje ...</string>
+  <string name="local_file_list_empty">V tej mapi ni datotek.</string>
   <string name="filedetails_select_file">Pritisnite na datoteko za prikaz dodatnih podrobnosti.</string>
   <string name="filedetails_size">Velikost:</string>
   <string name="filedetails_type">Vrsta:</string>
   <string name="filedetails_created">Ustvarjeno:</string>
   <string name="filedetails_modified">Spremenjeno:</string>
   <string name="filedetails_download">Prejmi</string>
+  <string name="filedetails_sync_file">Osveži datoteko</string>
   <string name="filedetails_renamed_in_upload_msg">Datoteka je bila med nalaganjem preimenovana v %1$s</string>
+  <string name="action_share_file">Povezava za souporabo</string>
+  <string name="action_unshare_file">Odstrani možnost souporabe</string>
   <string name="common_yes">Da</string>
   <string name="common_no">Ne</string>
   <string name="common_ok">V redu</string>
@@ -52,7 +70,7 @@
   <string name="common_cancel">Prekliči</string>
   <string name="common_save_exit">Shrani in končaj</string>
   <string name="common_error">Napaka</string>
-  <string name="common_loading">Nalaganje...</string>
+  <string name="common_loading">Nalaganje ...</string>
   <string name="common_error_unknown">Neznana napaka</string>
   <string name="about_title">O oblaku %1$s</string>
   <string name="change_password">Spremeni geslo</string>
   <string name="uploader_upload_succeeded_content_single">%1$s je uspešno poslan</string>
   <string name="uploader_upload_failed_ticker">Pošiljanje je spodletelo</string>
   <string name="uploader_upload_failed_content_single">Pošiljanja %1$s ni mogoče dokončati</string>
+  <string name="uploader_upload_failed_credentials_error">Pošiljanje je spodletelo. Pred nadaljevanjem se je treba prijaviti.</string>
   <string name="downloader_download_in_progress_ticker">Prejemanje …</string>
   <string name="downloader_download_in_progress_content">%1$d%% Prejemanje %2$s</string>
   <string name="downloader_download_succeeded_ticker">Prejemanje je uspešno končano</string>
   <string name="downloader_download_succeeded_content">%1$s je uspešno prejet</string>
   <string name="downloader_download_failed_ticker">Prejemanje je spodletelo</string>
   <string name="downloader_download_failed_content">Prejemanja %1$s ni mogoče dokončati</string>
-  <string name="downloader_not_downloaded_yet">Prenos še ni zaključen</string>
+  <string name="downloader_not_downloaded_yet">Prejem še ni zaključen</string>
+  <string name="downloader_download_failed_credentials_error">Prejemanje je spodletelo. Pred nadaljevanjem se je treba prijaviti.</string>
   <string name="common_choose_account">Izbor računa</string>
   <string name="sync_fail_ticker">Usklajevanje je spodletelo</string>
+  <string name="sync_fail_ticker_unauthorized">Usklajevanje je spodletelo. Znova se je treba prijaviti.</string>
   <string name="sync_fail_content">Usklajevanja %1$s ni mogoče dokončati</string>
+  <string name="sync_fail_content_unauthorized">Neveljavno geslo za %1$s</string>
   <string name="sync_conflicts_in_favourites_ticker">Zaznani spori</string>
-  <string name="sync_conflicts_in_favourites_content">%1$d vedno-ažurnih datotek ni bilo mogoče uskladiti</string>
-  <string name="sync_fail_in_favourites_ticker">Usklajevanje vedno-ažurnih datotek je spodletelo</string>
-  <string name="sync_fail_in_favourites_content">Vsebino %1$d datotek ni bilo mogoče uskladiti (%2$d sporov)</string>
+  <string name="sync_conflicts_in_favourites_content">%1$d stalno usklajenih datotek ni bilo mogoče uskladiti</string>
+  <string name="sync_fail_in_favourites_ticker">Posodobitev stalno usklajenih datotek je spodletelo</string>
+  <string name="sync_fail_in_favourites_content">Vsebine %1$d datotek ni bilo mogoče uskladiti (zaznanih je %2$d sporov)</string>
   <string name="sync_foreign_files_forgotten_ticker">Nekatere krajevne datoteke so spregledane</string>
   <string name="sync_foreign_files_forgotten_content">Skupno %1$d datotek iz mape %2$s ni mogoče kopirati v</string>
+  <string name="sync_foreign_files_forgotten_explanation">Od različice 1.3.16 so datoteke, poslane iz te naprave, varnostno kopirane v krajevno mapo %1$s. S tem je preprečena možnost izgube podatkov, ko se ena datoteka usklajuje z več računi.\n\nZaradi te spremembe so vse datoteke, ki so bile kopirane v prejšnjih različicah, kopirane v mapo %2$s. Zaradi napake ni mogoče končati usklajevanja. Datoteke lahko ali pustite kjer so, in odstranite povezavo na %3$s, ali pa premaknete datoteke v mapo %1$s in ohranite povezavo do %4$s.\n\nSpodaj so izpisane krajevne datoteke in oddaljene povezane datoteke v mapi %5$s.</string>
+  <string name="sync_current_folder_was_removed">Mapa %1$s ne obstaja več</string>
   <string name="foreign_files_move">Premakni vse</string>
   <string name="foreign_files_success">Vse datoteke so uspešno premaknjene na novo mesto</string>
   <string name="foreign_files_fail">Nekaterih datotek ni mogoče premakniti</string>
   <string name="foreign_files_local_text">Krajevno: %1$s</string>
   <string name="foreign_files_remote_text">Oddaljeno: %1$s</string>
-  <string name="upload_query_move_foreign_files">Na strežniku ni dovolj prostora za kopiranje izbranih datotek v mapo %1$s. Ali želite datoteke raje premakniti na novo mesto? </string>
+  <string name="upload_query_move_foreign_files">Ni dovolj prostora za kopiranje izbranih datotek v mapo %1$s. Ali jih želite premakniti?</string>
   <string name="pincode_enter_pin_code">Vnesite kodo PIN programa</string>
   <string name="pincode_configure_your_pin">Vnesite kodo PIN programa</string>
   <string name="pincode_configure_your_pin_explanation">Koda PIN bo zahtevana vsakič pred zagonom programa.</string>
   <string name="pincode_reenter_your_pincode">Ponovno vnesite kodo PIN programa</string>
   <string name="pincode_remove_your_pincode">Odstrani kodo PIN programa</string>
-  <string name="pincode_mismatch">Vrednosti kodo PIN programa nista enaki</string>
-  <string name="pincode_wrong">Nepravilen kodo PIN programa</string>
+  <string name="pincode_mismatch">Vrednosti kod PIN programa nista enaki</string>
+  <string name="pincode_wrong">Nepravilna koda PIN programa</string>
   <string name="pincode_removed">Koda PIN programa je odstranjena</string>
   <string name="pincode_stored">Koda PIN programa je shranjena</string>
-  <string name="media_state_playing">%1$s (predvajanja)</string>
-  <string name="media_state_loading">%1$s (nalaganja)</string>
-  <string name="media_err_nothing_to_play">Medijskih datotek ni bilo mogoče najti</string>
-  <string name="media_err_no_account">Niste navedli uporabniškega računa</string>
-  <string name="media_err_not_in_owncloud">Dokument ni shranjen pod veljaven račun.</string>
-  <string name="media_err_unsupported">Medijski kodek ni podprt</string>
-  <string name="media_err_io">Medijske datoteke ni bilo mogoče prebrati.</string>
-  <string name="media_err_malformed">Medijska datoteka ni pravilno kodirana.</string>
-  <string name="media_err_invalid_progressive_playback">Medijske datoteke ni mogoče predvajati</string>
-  <string name="media_err_unknown">Medijske datoteke ni mogoče predvajati s predvajalnikom Stock media player</string>
+  <string name="media_notif_ticker">Predvajalnik glasbe %1$s</string>
+  <string name="media_state_playing">%1$s (se predvaja)</string>
+  <string name="media_state_loading">%1$s (se nalaga)</string>
+  <string name="media_event_done">Predvajanje %1$s je končano</string>
+  <string name="media_err_nothing_to_play">Predstavnih datotek ni mogoče najti</string>
+  <string name="media_err_no_account">Ni navedenega računa</string>
+  <string name="media_err_not_in_owncloud">Dokument ni shranjen v veljavnem računu.</string>
+  <string name="media_err_unsupported">Nepodprt predstavni kodek</string>
+  <string name="media_err_io">Predstavne datoteke ni mogoče prebrati.</string>
+  <string name="media_err_malformed">Predstavna datoteka ni pravilno kodirana.</string>
+  <string name="media_err_timeout">Poskus predvajanja je časovno potekel</string>
+  <string name="media_err_invalid_progressive_playback">Predstavne datoteke ni mogoče prikazati v pretoku</string>
+  <string name="media_err_unknown">Predstavne datoteke ni mogoče predvajati s sistemsko privzetim predvajalnikom</string>
+  <string name="media_err_security_ex">Prišlo je do varnostne napake med predvajanjem %1$s</string>
+  <string name="media_err_io_ex">Prišlo je do napake vhoda med predvajanjem %1$s</string>
+  <string name="media_err_unexpected">Prišlo je do nepričakovane napake med predvajanjem %1$s</string>
+  <string name="media_rewind_description">Vrni nazaj</string>
+  <string name="media_play_pause_description">Gumb za predvajanje in premor</string>
+  <string name="media_forward_description">Gumb za hitro predvajanje naprej</string>
+  <string name="auth_getting_authorization">Pridobivanje overitve ...</string>
   <string name="auth_trying_to_login">Poskus prijave …</string>
   <string name="auth_no_net_conn_title">Ni omrežne povezave</string>
   <string name="auth_nossl_plain_ok_title">Varna povezava ni na voljo.</string>
   <string name="auth_connection_established">Povezava je vzpostavljena</string>
   <string name="auth_testing_connection">Preizkušanje povezave ...</string>
-  <string name="auth_not_configured_title">Nastavitve servera so napačno oblikovane</string>
-  <string name="auth_unknown_error_title">Prišlo je do neznane napake</string>
+  <string name="auth_not_configured_title">Napačno oblikovane nastavitve strežnika</string>
+  <string name="auth_account_not_new">Na napravi račun za istega uporabnika in strežnik že obstaja</string>
+  <string name="auth_account_not_the_same">Vpisan uporabnik ni lastnik tega računa</string>
+  <string name="auth_unknown_error_title">Prišlo je do neznane napake!</string>
   <string name="auth_unknown_host_title">Gostitelja ni mogoče najti</string>
-  <string name="auth_incorrect_path_title">Namestitve servera ni mogoče najti</string>
-  <string name="auth_timeout_title">Strežnik je potreboval preveč časa za odgovor</string>
+  <string name="auth_incorrect_path_title">Primerka strežnika ni mogoče najti</string>
+  <string name="auth_timeout_title">Odziv s strežnika je časovno pretekel</string>
   <string name="auth_incorrect_address_title">Napačno oblikovan naslov URL</string>
   <string name="auth_ssl_general_error_title">Začenjanje SSL je spodletelo</string>
-  <string name="auth_bad_oc_version_title">Neprepoznana različica strežnika servera</string>
-  <string name="auth_wrong_connection_title">Povezave ni mogoče vzpostaviti</string>
+  <string name="auth_ssl_unverified_server_title">Ni mogoče overiti istovetnosti strežnika SSL</string>
+  <string name="auth_bad_oc_version_title">Nepoznana različica strežnika</string>
+  <string name="auth_wrong_connection_title">Ni mogoče vzpostaviti povezave</string>
   <string name="auth_secure_connection">Varna povezava je vzpostavljena</string>
+  <string name="auth_unauthorized">Napačno uporabniško ime ali geslo</string>
+  <string name="auth_oauth_error">Overitev ni uspešno končana</string>
+  <string name="auth_oauth_error_access_denied">Dostop je zavrnjen s strani overitvenega strežnika</string>
+  <string name="auth_wtf_reenter_URL">Nepričakovano stanje; ponovno je treba vpisati naslov URL strežnika</string>
+  <string name="auth_expired_oauth_token_toast">Overitev računa je potekla. Pred nadaljevanjem je treba prijavo ponovno overiti.</string>
+  <string name="auth_expired_basic_auth_toast">Vnesite trenutno geslo</string>
+  <string name="auth_expired_saml_sso_token_toast">Seja je potekla. Ponovno je treba vzpostaviti povezavo.</string>
+  <string name="auth_connecting_auth_server">Poteka povezovanje z overitvenim strežnikom ...</string>
+  <string name="auth_unsupported_auth_method">Strežnik ne podpira tega načina overitve</string>
+  <string name="auth_unsupported_multiaccount">%1$s ne omogoča podpore več računom</string>
+  <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="fd_keep_in_sync">Datoteka naj bo posodobljena</string>
   <string name="common_rename">Preimenuj</string>
   <string name="common_remove">Odstrani</string>
-  <string name="confirmation_remove_alert">Ali res želite odstraniti %1$s ?</string>
-  <string name="confirmation_remove_folder_alert">Ali ste prepričani, da želite odstraniti %1$s in njeno vsebino?</string>
+  <string name="confirmation_remove_alert">Ali res želite odstraniti %1$s?</string>
+  <string name="confirmation_remove_folder_alert">Ali res želite odstraniti %1$s skupaj s celotno vsebino?</string>
   <string name="confirmation_remove_local">Le krajevno</string>
-  <string name="confirmation_remove_folder_local">Samo lokalne vsebine</string>
+  <string name="confirmation_remove_folder_local">Le krajevno vsebino</string>
   <string name="confirmation_remove_remote">Odstrani s strežnika</string>
   <string name="confirmation_remove_remote_and_local">Oddaljeno in krajevno</string>
   <string name="remove_success_msg">Odstranitev je uspešno končana</string>
-  <string name="remove_fail_msg">Odstranjevanje ni dokončano</string>
+  <string name="remove_fail_msg">Odstranjevanje je spodletelo</string>
   <string name="rename_dialog_title">Vnesite novo ime</string>
   <string name="rename_local_fail_msg">Krajevne datoteke ni mogoče preimenovati; poskusite z drugačnim novim imenom</string>
   <string name="rename_server_fail_msg">Preimenovanja ni možno dokončati</string>
-  <string name="sync_file_fail_msg">Oddaljene datoteke ni bilo mogoče preveriti</string>
-  <string name="sync_file_nothing_to_do_msg">Vsebina datoteke je ažurna</string>
+  <string name="sync_file_fail_msg">Oddaljene datoteke ni mogoče preveriti</string>
+  <string name="sync_file_nothing_to_do_msg">Vsebina datoteke je že usklajena</string>
   <string name="create_dir_fail_msg">Mape ni mogoče ustvariti</string>
+  <string name="filename_forbidden_characters">Nedovoljeni znaki: characters: / \\ &lt; &gt; : \" | ? *</string>
+  <string name="filename_empty">Ime datoteke ne sme biti prazno</string>
   <string name="wait_a_moment">Počakajte trenutek ...</string>
   <string name="filedisplay_unexpected_bad_get_content">Prišlo je do nepričakovane napake. Poskusite datoteko izbrati z drugim programom.</string>
   <string name="filedisplay_no_file_selected">Ni izbranih datotek</string>
+  <string name="activity_chooser_title">Pošlji povezavo ...</string>
+  <string name="oauth_check_onoff">Prijava  z oAuth2</string>
+  <string name="oauth_login_connection">Poteka povezovanje s strežnikom oAuth2 ...</string>
   <string name="ssl_validator_header">Istovetnosti strani ni mogoče preveriti</string>
   <string name="ssl_validator_reason_cert_not_trusted">- potrdilo strežnika ni vredno zaupanja</string>
   <string name="ssl_validator_reason_cert_expired">- potrdilo strežnika je poteklo</string>
   <string name="ssl_validator_label_subject">Izdano za:</string>
   <string name="ssl_validator_label_issuer">Izdajatelj:</string>
   <string name="ssl_validator_label_CN">Splošno ime:</string>
-  <string name="ssl_validator_label_O">Organizacija:</string>
+  <string name="ssl_validator_label_O">Ustanova:</string>
   <string name="ssl_validator_label_OU">Organizacijska enota:</string>
   <string name="ssl_validator_label_C">Država:</string>
   <string name="ssl_validator_label_ST">Regija:</string>
   <string name="ssl_validator_label_validity_to">Do:</string>
   <string name="ssl_validator_label_signature">Podpis:</string>
   <string name="ssl_validator_label_signature_algorithm">Algoritem:</string>
-  <string name="placeholder_sentence">To je vsebnik predmetov.</string>
+  <string name="ssl_validator_null_cert">Potrdila ni mogoče pokazati.</string>
+  <string name="ssl_validator_no_info_about_error">– Ni podatkov o napaki</string>
+  <string name="placeholder_sentence">To je vsebnik predmetov</string>
+  <string name="placeholder_filename">vsebnik.txt</string>
+  <string name="placeholder_filetype">Slika PNG</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">Pošiljaj slike le preko povezav Wi-Fi</string>
-  <string name="instant_upload_path">/NeposrednoNalaganje</string>
+  <string name="instant_video_upload_on_wifi">Pošlji posnetke le preko povezave Wi-Fi</string>
+  <string name="instant_upload_path">/TakojšnjePošiljanje</string>
   <string name="conflict_title">Posodobi podatke spora</string>
   <string name="conflict_message">Oddaljena datoteka %s ni usklajena s krajevno. Z nadaljevanem bo datoteka na strežniku zamenjana s krajevno.</string>
   <string name="conflict_keep_both">Ohrani obe</string>
   <string name="conflict_dont_upload">Ne pošlji</string>
   <string name="preview_image_description">Predogled slike</string>
   <string name="preview_image_error_unknown_format">Te slike ni mogoče prikazati</string>
-  <string name="error__upload__local_file_not_copied">Datoteke %1$s ni mogoče kopirati v krajevno mapo %2$s.</string>
-  <string name="failed_upload_all_cb">izberi vse</string>
-  <string name="failed_upload_load_more_images">Naloži več slik</string>
-  <string name="failed_upload_failure_text">Sporočilo o napaki:</string>
+  <string name="error__upload__local_file_not_copied">Datoteke %1$s ni mogoče kopirati v krajevno mapo %2$s</string>
+  <string name="share_link_no_support_share_api">Souporaba je na strežniku onemogočena. Možnost lahko spreminjajo le
+               uporabniki s skrbniškimi dovoljenji.</string>
+  <string name="share_link_file_no_exist">Souporaba ni mogoča. Preverite, ali datoteka obstaja.</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="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="error_cant_bind_to_operations_service">Kritična napaka: dejanj ni možno izvesti</string>
+  <string name="network_error_socket_exception">Med povezovanjem s strežnikom je prišlo do napake.</string>
+  <string name="network_error_socket_timeout_exception">Med čakanjem na vzpostavitev povezave s strežnikom je prišlo do napake. Zahtevanega dejanja ni mogoče izvesti.</string>
+  <string name="network_error_connect_timeout_exception">Med čakanjem na vzpostavitev povezave s strežnikom je prišlo do napake. Zahtevanega dejanja ni bilo mogoče končati.</string>
+  <string name="network_host_not_available">Zahtevanega dejanja ni bilo mogoče končati. Strežnik ni dosegljiv.</string>
+  <string name="empty"></string>
+  <string name="forbidden_permissions">Ni ustreznega dovoljenja %s</string>
+  <string name="forbidden_permissions_rename">za preimenovanje datoteke.</string>
+  <string name="forbidden_permissions_delete">za izbris datoteke.</string>
+  <string name="share_link_forbidden_permissions">za omogočanje souporabe datoteke.</string>
+  <string name="unshare_link_forbidden_permissions">za preklic souporabe datoteke.</string>
+  <string name="forbidden_permissions_create">za ustvarjanje datoteke.</string>
+  <string name="uploader_upload_forbidden_permissions">za pošiljanje datoteke v oblak.</string>
+  <string name="downloader_download_file_not_found">Datoteka na strežniku ni več na voljo.</string>
+  <string name="prefs_category_accounts">Računi</string>
+  <string name="prefs_add_account">Dodaj račun</string>
+  <string name="actionbar_logger">Dnevnik</string>
+  <string name="log_send_history_button">Pošlji zgodovino</string>
+  <string name="log_mail_subject">Dnevnik programa ownCloud</string>
+  <string name="log_progress_dialog_text">Poteka nalaganje podatkov ...</string>
+  <string name="saml_authentication_required_text">Zahtevana je overitev</string>
+  <string name="saml_authentication_wrong_pass">Napačno geslo</string>
+  <string name="actionbar_move">Premakni</string>
+  <string name="file_list_empty_moving">Ni vsebine in datotek. Lahko ustvarite na primer mapo.</string>
+  <string name="move_choose_button_text">Izbor</string>
+  <string name="move_file_not_found">Ni mogoče premakniti datoteke. Preverite, ali obstaja.</string>
+  <string name="move_file_invalid_into_descendent">Ni mogoče premakniti mape v podrejeno mapo.</string>
+  <string name="move_file_invalid_overwrite">Datoteka v ciljni mapi že obstaja.</string>
+  <string name="move_file_error">Prišlo je do napake med premikanjem datoteke v mapo</string>
+  <string name="forbidden_permissions_move">med premikanjem datoteke</string>
+  <string name="prefs_category_security">Varnost</string>
 </resources>
index 03b08ac..adeb3e9 100644 (file)
@@ -2,21 +2,75 @@
 <resources>
   <string name="actionbar_upload">Ngarko</string>
   <string name="actionbar_upload_files">Skedarët</string>
+  <string name="actionbar_mkdir">Dosje e\'re</string>
   <string name="actionbar_settings">Parametrat</string>
+  <string name="actionbar_send_file">Dërgo</string>
   <string name="prefs_category_general">Përgjithshme</string>
   <string name="prefs_category_more">Më tepër</string>
+  <string name="prefs_accounts">Llogarit</string>
+  <string name="prefs_pincode">PIN-i Aplikacionit</string>
+  <string name="prefs_pincode_summary">Ruani klientin tuaj</string>
   <string name="prefs_help">Ndihmë</string>
+  <string name="prefs_imprint">Stampoj</string>
   <string name="auth_username">Përdoruesi</string>
   <string name="auth_password">Kodi</string>
   <string name="sync_string_files">Skedarët</string>
+  <string name="setup_btn_connect">Lidhu</string>
   <string name="uploader_btn_upload_text">Ngarko</string>
+  <string name="uploader_wrn_no_account_title">Nuk u gjend asnjë llogari</string>
+  <string name="uploader_wrn_no_account_text">Nuk ka %1$s llogari në pajisjen tuaj. Ju lutemi të krijojnë një llogari të parë.</string>
+  <string name="uploader_wrn_no_account_setup_btn_text">Ndërto</string>
+  <string name="uploader_wrn_no_account_quit_btn_text">Dil</string>
+  <string name="uploader_info_uploading">Ngarko</string>
+  <string name="file_list_empty">Këtu nuk ka asgje. Ngarko dicka</string>
+  <string name="filedetails_select_file">Trokitje e lehtë në një dokument për të shfaqur informacion shtesë.</string>
+  <string name="filedetails_size">Dimensioni:</string>
+  <string name="filedetails_type">Tipi:</string>
+  <string name="filedetails_created">Krijuar:</string>
+  <string name="filedetails_modified">Modifikuar:</string>
   <string name="filedetails_download">Shkarko</string>
   <string name="common_yes">Po</string>
   <string name="common_no">Jo</string>
+  <string name="common_ok">Ok</string>
   <string name="common_cancel_upload">Anulo ngarkimin</string>
   <string name="common_cancel">Anulo</string>
   <string name="common_error">Veprim i gabuar</string>
+  <string name="common_error_unknown">Gabim panjohur</string>
+  <string name="about_title">Rreth</string>
   <string name="change_password">Ndrysho fjalëkalimin</string>
+  <string name="delete_account">Fshi llogarin</string>
+  <string name="create_account">Krijo llogari</string>
+  <string name="upload_chooser_title">Ngarko nga...</string>
+  <string name="uploader_info_dirname">Emri i Skedarit</string>
+  <string name="uploader_upload_in_progress_ticker">Ngarkim...</string>
+  <string name="uploader_upload_in_progress_content">%1$d%% Ngarkim %2$s</string>
+  <string name="uploader_upload_succeeded_ticker">Ngarkimi me sukses.</string>
+  <string name="uploader_upload_succeeded_content_single">%1$s u ngarkua me sukses</string>
   <string name="uploader_upload_failed_ticker">Ngarkimi dështoi</string>
+  <string name="uploader_upload_failed_content_single">Ngarkimi i %1$s nuk mund te behej</string>
+  <string name="downloader_download_in_progress_ticker">Shkarkimi...</string>
+  <string name="downloader_download_in_progress_content">%1$d%% Shkarkimi %2$s</string>
+  <string name="downloader_download_succeeded_ticker">Shkarkimi me sukses</string>
+  <string name="downloader_download_succeeded_content">%1$s u shkarkua me sukses</string>
+  <string name="downloader_download_failed_ticker">Shkarkimi dështoj</string>
+  <string name="common_choose_account">Zgjidhni Llogarine</string>
+  <string name="pincode_enter_pin_code">Lutemi, vendosni PIN tuaj</string>
+  <string name="pincode_reenter_your_pincode">Lutemi, rivendosni PIN tuaj</string>
+  <string name="pincode_remove_your_pincode">Hiqni PIN in tuaj</string>
+  <string name="pincode_mismatch">PIN-et nuk jane te njejte</string>
+  <string name="pincode_wrong">PIN i gabuar</string>
+  <string name="pincode_removed">PIN-i u hoq</string>
+  <string name="pincode_stored">PIN-i u ruajt</string>
+  <string name="auth_no_net_conn_title">Nuk ka lidhje ne Rrjet</string>
+  <string name="auth_connection_established">Lidhja u vendos</string>
+  <string name="auth_testing_connection">Duke testuar lidhjen</string>
+  <string name="auth_secure_connection">Lidhja e Sigurt vendos</string>
   <string name="common_rename">Riemërto</string>
+  <string name="common_remove">Hiq</string>
+  <string name="activity_chooser_send_file_title">Dërgo</string>
+  <string name="empty"></string>
+  <string name="prefs_category_accounts">Llogarit</string>
+  <string name="saml_authentication_wrong_pass">Fjalëkalim i gabuar</string>
+  <string name="move_choose_button_text">Zgjidh</string>
+  <string name="prefs_category_security">Siguria</string>
 </resources>
index 663c462..973a548 100644 (file)
@@ -3,15 +3,56 @@
   <string name="actionbar_upload">Pošalji</string>
   <string name="actionbar_upload_files">Fajlovi</string>
   <string name="actionbar_settings">Podešavanja</string>
+  <string name="actionbar_see_details">Detaljnije</string>
+  <string name="actionbar_send_file">Pošalji</string>
+  <string name="prefs_category_general">Opšte</string>
+  <string name="prefs_accounts">Nalozi</string>
+  <string name="prefs_manage_accounts">Upravljaj nalozima</string>
   <string name="prefs_help">Pomoć</string>
   <string name="auth_username">Korisničko ime</string>
   <string name="auth_password">Lozinka</string>
   <string name="sync_string_files">Fajlovi</string>
   <string name="uploader_btn_upload_text">Pošalji</string>
+  <string name="uploader_wrn_no_account_title">Nalog nije nađen</string>
+  <string name="uploader_info_uploading">Šalje se</string>
+  <string name="file_list_empty">Ovde nema ničeg. Pošaljite nešto!</string>
+  <string name="filedetails_size">Veličina:</string>
+  <string name="filedetails_type">Tip:</string>
   <string name="filedetails_download">Preuzmi</string>
   <string name="common_yes">Da</string>
   <string name="common_no">Ne</string>
+  <string name="common_ok">Ok</string>
   <string name="common_cancel">Otkaži</string>
   <string name="common_error">Greška</string>
   <string name="change_password">Izmeni lozinku</string>
+  <string name="delete_account">Ukloni nalog</string>
+  <string name="create_account">Novi nalog</string>
+  <string name="uploader_upload_in_progress_ticker">Otpremanje...</string>
+  <string name="uploader_upload_succeeded_ticker">Uspešno otpremljeno</string>
+  <string name="uploader_upload_failed_ticker">Otpremanje nije uspelo</string>
+  <string name="downloader_download_in_progress_ticker">Preuzimanje...</string>
+  <string name="downloader_download_succeeded_ticker">Uspešno preuzeto</string>
+  <string name="downloader_download_failed_ticker">Preuzimanje nije uspelo</string>
+  <string name="common_choose_account">Odaberite nalog</string>
+  <string name="auth_no_net_conn_title">Nema konekcije</string>
+  <string name="auth_nossl_plain_ok_title">Sigurna konekcija nije dostupna.</string>
+  <string name="auth_connection_established">Konekcija uspostavljena</string>
+  <string name="common_rename">Preimenij</string>
+  <string name="common_remove">Ukloni</string>
+  <string name="remove_success_msg">Uklanjanje je uspelo</string>
+  <string name="remove_fail_msg">Uklanjanje nije uspelo</string>
+  <string name="wait_a_moment">Molim pričekajte</string>
+  <string name="ssl_validator_btn_details_see">Detaljnije</string>
+  <string name="ssl_validator_btn_details_hide">Sakrij</string>
+  <string name="ssl_validator_label_O">Organizacija:</string>
+  <string name="ssl_validator_label_C">Država:</string>
+  <string name="ssl_validator_label_L">Lokacija:</string>
+  <string name="ssl_validator_label_validity_from">Od:</string>
+  <string name="ssl_validator_label_validity_to">Za:</string>
+  <string name="ssl_validator_label_signature">Potpis:</string>
+  <string name="conflict_keep_both">Zadrži oboje</string>
+  <string name="activity_chooser_send_file_title">Pošalji</string>
+  <string name="empty"></string>
+  <string name="prefs_category_accounts">Nalozi</string>
+  <string name="move_choose_button_text">Izaberi</string>
 </resources>
index 446a6ee..2ef1373 100644 (file)
@@ -3,14 +3,12 @@
   <string name="actionbar_upload">Отпреми</string>
   <string name="actionbar_upload_from_apps">Садржај са других апликација</string>
   <string name="actionbar_upload_files">Датотеке</string>
-  <string name="actionbar_mkdir">Направи фасциклу</string>
   <string name="actionbar_settings">Поставке</string>
+  <string name="actionbar_send_file">Пошаљи</string>
   <string name="prefs_category_general">Опште</string>
   <string name="prefs_category_more">Више</string>
   <string name="prefs_accounts">Налози</string>
-  <string name="prefs_instant_upload_summary">Тренутно отпремај фотографије сликане камером</string>
   <string name="prefs_help">Помоћ</string>
-  <string name="auth_host_url">Адреса сервера</string>
   <string name="auth_username">Корисничко име</string>
   <string name="auth_password">Лозинка</string>
   <string name="sync_string_files">Фајлови</string>
@@ -22,7 +20,7 @@
   <string name="uploader_wrn_no_content_title">Нема садржаја за отпремање</string>
   <string name="uploader_wrn_no_content_text">Садржај није примљен. Нема ништа да се отпреми.</string>
   <string name="uploader_info_uploading">Отпремање</string>
-  <string name="file_list_empty">Ð\9dема Ð´Ð°Ñ\82оÑ\82ека Ñ\83 Ð¾Ð²Ð¾Ñ\98 Ñ\84аÑ\81Ñ\86икли.\nÐ\9dове Ð´Ð°Ñ\82оÑ\82еке Ð¼Ð¾Ð¶ÐµÑ\82е Ð´Ð° Ð´Ð¾Ð´Ð°Ñ\82е Ð¿Ñ\83Ñ\82ем Ð¾Ð¿Ñ\86иÑ\98е â\80\9eÐ\9eÑ\82пÑ\80емиâ\80\9c.</string>
+  <string name="file_list_empty">Ð\9eвде Ð½ÐµÐ¼Ð° Ð½Ð¸Ñ\87ег. Ð\9eÑ\82пÑ\80емиÑ\82е Ð½ÐµÑ\88Ñ\82о!</string>
   <string name="filedetails_select_file">Додирните датотеку ради приказа додатних информација.</string>
   <string name="filedetails_size">Величина:</string>
   <string name="filedetails_type">Врста:</string>
@@ -43,7 +41,6 @@
   <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="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_local">Само локално</string>
   <string name="confirmation_remove_remote">Уклони са сервера</string>
   <string name="confirmation_remove_remote_and_local">Удаљено и локално</string>
   <string name="rename_dialog_title">Унесите ново име</string>
   <string name="rename_server_fail_msg">Не могу да довршим преименовање</string>
   <string name="sync_file_fail_msg">Удаљена датотека се не може проверити</string>
-  <string name="create_dir_fail_msg">Не могу да направим фасциклу</string>
   <string name="wait_a_moment">Сачекајте тренутак</string>
   <string name="filedisplay_no_file_selected">Нисте изабрали датотеку</string>
   <string name="ssl_validator_header">Не могу да проверим идентитет сајта</string>
   <string name="ssl_validator_label_signature_algorithm">Алгоритам:</string>
   <string name="instant_upload_on_wifi">Отпремај слике само путем бежичне мреже</string>
   <string name="conflict_title">Ажурирај сукоб</string>
+  <string name="activity_chooser_send_file_title">Пошаљи</string>
+  <string name="empty"></string>
+  <string name="prefs_category_accounts">Налози</string>
+  <string name="move_choose_button_text">Одабери</string>
+  <string name="prefs_category_security">Безбедност</string>
 </resources>
diff --git a/res/values-su/strings.xml b/res/values-su/strings.xml
new file mode 100644 (file)
index 0000000..56e55a1
--- /dev/null
@@ -0,0 +1,4 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<resources>
+  <string name="empty"></string>
+</resources>
index 57794a9..c077786 100644 (file)
@@ -7,17 +7,20 @@
   <string name="actionbar_upload_from_apps">Innehåll från andra program</string>
   <string name="actionbar_upload_files">Filer</string>
   <string name="actionbar_open_with">Öppna med</string>
-  <string name="actionbar_mkdir">Skapa mapp</string>
+  <string name="actionbar_mkdir">Ny mapp</string>
   <string name="actionbar_settings">Inställningar</string>
   <string name="actionbar_see_details">Detaljer</string>
+  <string name="actionbar_send_file">Skicka</string>
   <string name="prefs_category_general">Allmänt</string>
   <string name="prefs_category_more">Mer</string>
   <string name="prefs_accounts">Konton</string>
   <string name="prefs_manage_accounts">Hantera konton</string>
   <string name="prefs_pincode">applikation PIN</string>
   <string name="prefs_pincode_summary">Skydda applikation-klienten</string>
-  <string name="prefs_instant_upload">Aktivera direktuppladdning</string>
-  <string name="prefs_instant_upload_summary">Direktuppladdning av kamerabilder</string>
+  <string name="prefs_instant_upload">Direktuppladdning av kamerabilder</string>
+  <string name="prefs_instant_upload_summary">Direktuppladning av bilder tagna med kameran</string>
+  <string name="prefs_instant_video_upload">Direktuppladning av video</string>
+  <string name="prefs_instant_video_upload_summary">Direktuppladdning av video inspelade med kameran</string>
   <string name="prefs_log_title">Aktivera loggning</string>
   <string name="prefs_log_summary">Används för att logga problem</string>
   <string name="prefs_log_title_history">Logghistorik</string>
   <string name="prefs_log_delete_history_button">Radera historik</string>
   <string name="prefs_help">Hjälp</string>
   <string name="prefs_recommend">Rekommendera till en vän</string>
-  <string name="prefs_feedback">Återkoppling</string>
+  <string name="prefs_feedback">Feedback</string>
   <string name="prefs_imprint">Imprint</string>
-  <string name="recommend_subject">Försök %1$s på din smarttelefon!</string>
-  <string name="recommend_text">Jag vill bjuda in dig till att anända %1$s på din smarttelefon!\nLadda ner här: %2$s</string>
+  <string name="recommend_subject">Prova %1$s på din smartphone!</string>
+  <string name="recommend_text">Jag skullje vilja bjuda in dig till att prova %1$s på din smartphone!\nLadda ner appen från Google Play här: %2$s</string>
   <string name="auth_check_server">Kontrollera Server</string>
-  <string name="auth_host_url">Serveradress</string>
+  <string name="auth_host_url">Serveradress https://...</string>
   <string name="auth_username">Användarnamn</string>
   <string name="auth_password">Lösenord</string>
   <string name="auth_register">Ny på %1$s?</string>
@@ -46,7 +49,9 @@
   <string name="uploader_wrn_no_content_text">Inget innehåll mottaget. Inget att ladda upp.</string>
   <string name="uploader_error_forbidden_content">%1$s har inte rättighet till det delade innehållet</string>
   <string name="uploader_info_uploading">Laddar upp</string>
-  <string name="file_list_empty">Det finns inga filer i denna mapp.\nNya filer kan läggas till med \"Ladda upp\" i menyn.</string>
+  <string name="file_list_empty">Ingenting här. Ladda upp något!</string>
+  <string name="file_list_loading">Laddar...</string>
+  <string name="local_file_list_empty">Det finns inga filer i den här mappen.</string>
   <string name="filedetails_select_file">Peka på en fil för att visa mer information.</string>
   <string name="filedetails_size">Storlek:</string>
   <string name="filedetails_type">Typ:</string>
@@ -55,6 +60,8 @@
   <string name="filedetails_download">Ladda ner</string>
   <string name="filedetails_sync_file">Ladda om fil</string>
   <string name="filedetails_renamed_in_upload_msg">Filen bytte namn till %1$s under uppladdningen</string>
+  <string name="action_share_file">Dela länk</string>
+  <string name="action_unshare_file">Sluta dela länk</string>
   <string name="common_yes">Ja</string>
   <string name="common_no">Nej</string>
   <string name="common_ok">OK</string>
@@ -77,6 +84,7 @@
   <string name="uploader_upload_succeeded_content_single">%1$s laddades upp</string>
   <string name="uploader_upload_failed_ticker">Misslyckad uppladdning</string>
   <string name="uploader_upload_failed_content_single">Uppladdning av %1$s kunde inte slutföras</string>
+  <string name="uploader_upload_failed_credentials_error">Uppladdning misslyckades, måste du logga in igen</string>
   <string name="downloader_download_in_progress_ticker">Laddar ner ...</string>
   <string name="downloader_download_in_progress_content">%1$d%% Laddar ner %2$s</string>
   <string name="downloader_download_succeeded_ticker">Nedladdning klar</string>
   <string name="downloader_download_failed_ticker">Misslyckad nedladdning</string>
   <string name="downloader_download_failed_content">Nedladdning av %1$s kunde inte slutföras</string>
   <string name="downloader_not_downloaded_yet">Ännu inte nedladdade</string>
+  <string name="downloader_download_failed_credentials_error">Nerladda misslyckades, måste du logga in igen</string>
   <string name="common_choose_account">Välj konto</string>
   <string name="sync_fail_ticker">Synkroniseringen misslyckades</string>
+  <string name="sync_fail_ticker_unauthorized">Synkroniseringen misslyckades, du måste logga in på nytt.</string>
   <string name="sync_fail_content">Synkronisering av %1$s kunde inte slutföras</string>
   <string name="sync_fail_content_unauthorized">Felaktigt lösenord för %1$s</string>
   <string name="sync_conflicts_in_favourites_ticker">Konflikter uppstod</string>
   <string name="sync_fail_in_favourites_content">Innehållet i %1$d filer kunde inte synkas (%2$d konflikter)</string>
   <string name="sync_foreign_files_forgotten_ticker">Vissa lokala filer glömdes</string>
   <string name="sync_foreign_files_forgotten_content">%1$d filer från %2$s mappar kunde inte kopieras till</string>
-  <string name="sync_foreign_files_forgotten_explanation">Från och med version 1.3.16 kopieras uppladdade filer från den här enheten till den lokala %1$s mappen för att förhindra förlust av data när en enda fil synkroniseras med flera konton.\n\nPå grund av denna förändring har alla filer som laddats upp i tidigare versioner av denna app kopierats till %2$s mappen. Men ett fel förhindrade slutförande av denna operation under synkronisering. Du kan antingen lämna fil(er) som det är och ta bort länken till %3$s, eller flytta fil(er) till %1$s mappen och behålla länken till %4$s.\n\nNedan listas dom lokala fil(er) och fjärrfil(er) i %5$s dom var länkade till.</string>
   <string name="sync_current_folder_was_removed">Mappen %1$s existerar inte längre</string>
   <string name="foreign_files_move">Flytta allt</string>
   <string name="foreign_files_success">Alla filer flyttades</string>
   <string name="foreign_files_fail">Vissa filer kunde inte flyttas</string>
   <string name="foreign_files_local_text">Lokal: %1$s</string>
   <string name="foreign_files_remote_text">Fjärr: %1$s</string>
-  <string name="upload_query_move_foreign_files">Det finns inte tillräckligt med utrymme för att kopiera valda filer till mappen %1$s. Vill du flytta filerna istället? </string>
+  <string name="upload_query_move_foreign_files">Det finns inte tillräckligt med ledigt utrymme för att kopiera de valda filerna till %1$s mappen. Skulle du vilja flytta dem istället?</string>
   <string name="pincode_enter_pin_code">Ange din PIN</string>
   <string name="pincode_configure_your_pin">Ange applikation PIN</string>
   <string name="pincode_configure_your_pin_explanation">Din PIN måste anges varje gång du startar programmet.</string>
   <string name="media_rewind_description">Bakåtspolningsknapp</string>
   <string name="media_play_pause_description">Spela- / Pausknapp</string>
   <string name="media_forward_description">Snappspolningsknapp</string>
+  <string name="auth_getting_authorization">Får tillstånd...</string>
   <string name="auth_trying_to_login">Försöker logga in...</string>
   <string name="auth_no_net_conn_title">Ingen nätverksanslutning</string>
   <string name="auth_nossl_plain_ok_title">Säker anslutning inte tillgänglig.</string>
   <string name="auth_connecting_auth_server">Ansluter till autentiseringsservern...</string>
   <string name="auth_unsupported_auth_method">Servern har inte stöd för denna autentiseringsmetod</string>
   <string name="auth_unsupported_multiaccount">%1$s har inte stöd för multipla konton</string>
+  <string name="auth_fail_get_user_name">Din server returnerar inte ett korrekt användare id, vänligen kontakta en administratör
+       </string>
+  <string name="auth_can_not_auth_against_server">Kan inte autentisera mot servern</string>
   <string name="fd_keep_in_sync">Håll filen uppdaterad</string>
   <string name="common_rename">Byt namn</string>
   <string name="common_remove">Radera</string>
-  <string name="confirmation_remove_alert">Vill du verkligen radera: %1$s ?</string>
-  <string name="confirmation_remove_folder_alert">Vill du verkligen radera %1$s och dess innehåll?</string>
+  <string name="confirmation_remove_alert">Vill du verkligen ta bort %1$s?</string>
+  <string name="confirmation_remove_folder_alert">Vill du verkligen ta bort %1$s och dess innehåll?</string>
   <string name="confirmation_remove_local">Endast lokalt</string>
   <string name="confirmation_remove_folder_local">Endast lokalt innehåll</string>
   <string name="confirmation_remove_remote">Radera från server</string>
   <string name="sync_file_fail_msg">Fjärrfilen kunde inte kontrolleras</string>
   <string name="sync_file_nothing_to_do_msg">Filinnehåll redan synkroniserat</string>
   <string name="create_dir_fail_msg">Mapp kunde inte skapas</string>
+  <string name="filename_forbidden_characters">Förbjudna tecken är: / \\ &lt; &gt; : \" | ? *</string>
+  <string name="filename_empty">Filnamnet får inte lämnas blankt</string>
   <string name="wait_a_moment">Var god vänta</string>
   <string name="filedisplay_unexpected_bad_get_content">Oväntat problem; prova annat program för aktuell fil</string>
   <string name="filedisplay_no_file_selected">Ingen fil vald</string>
+  <string name="activity_chooser_title">Sänd länk till ...</string>
   <string name="oauth_check_onoff">Logga in med oAuth2.</string>
   <string name="oauth_login_connection">Ansluter till oAuth2 servern…</string>
   <string name="ssl_validator_header">Webbplatsens identitet kunde inte verifieras</string>
   <string name="ssl_validator_label_validity_to">Till:</string>
   <string name="ssl_validator_label_signature">Signatur:</string>
   <string name="ssl_validator_label_signature_algorithm">Algoritm:</string>
+  <string name="ssl_validator_null_cert">Certifikatet kunde inte visas.</string>
+  <string name="ssl_validator_no_info_about_error">- Ingen information om felet</string>
   <string name="placeholder_sentence">Detta är en platshållare</string>
   <string name="placeholder_filename">placeholder.txt</string>
   <string name="placeholder_filetype">PNG Bild</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">Ladda upp bilder endast via WiFi</string>
+  <string name="instant_video_upload_on_wifi">Ladda upp videos endast via WIFI</string>
   <string name="instant_upload_path">/DirektUppladdning</string>
   <string name="conflict_title">Uppdateringskonflikt</string>
   <string name="conflict_message">Serverns fil %s är inte synkroniserad med den lokala filen. Fortsätt för att skriva över filen på servern.</string>
   <string name="preview_image_description">Förhandsvisa bild</string>
   <string name="preview_image_error_unknown_format">Denna bild kan inte visas</string>
   <string name="error__upload__local_file_not_copied">%1$s kunde inte kopieras till %2$s lokal mapp</string>
-  <string name="actionbar_failed_instant_upload">Fel vid direktuppladdning\"</string>
-  <string name="failed_upload_headline_text">Misslyckades vid direktuppladdning</string>
-  <string name="failed_upload_headline_hint">Sammanfattning av alla misslyckade uppladdningar</string>
-  <string name="failed_upload_all_cb">välj alla</string>
-  <string name="failed_upload_headline_retryall_btn">försökt igen med alla valda</string>
-  <string name="failed_upload_headline_delete_all_btn">radera alla valda från uppladdningskön</string>
-  <string name="failed_upload_retry_text">försök igen att ladda upp bilden:</string>
-  <string name="failed_upload_load_more_images">Ladda fler bilder</string>
-  <string name="failed_upload_retry_do_nothing_text">Du är inte ansluten, direktuppladdning ej möjligt</string>
-  <string name="failed_upload_failure_text">Felmeddelande:</string>
-  <string name="failed_upload_quota_exceeded_text">Vänligen kontrollera dina serverkonfiguration. Din kvot kan ha överskridits.</string>
+  <string name="share_link_no_support_share_api">Ledsen, delning är inte aktiverat på din server. Vänligen kontakta din
+               administratör.</string>
+  <string name="share_link_file_error">Ett fel uppstod vid försök att dela denna fil eller mapp</string>
+  <string name="unshare_link_file_error">Ett fel uppstod vid försök att sluta dela denna fil eller mapp</string>
+  <string name="activity_chooser_send_file_title">Skicka</string>
+  <string name="copy_link">Kopiera länk</string>
+  <string name="clipboard_text_copied">Kopierat till urklipp</string>
+  <string name="error_cant_bind_to_operations_service">Kritiskt fel: kan inte utföra åtgärden</string>
+  <string name="network_error_socket_exception">Ett fel uppstod vid anslutning till servern.</string>
+  <string name="network_error_socket_timeout_exception">Ett fel uppstod i väntan på servern, operationen kunde inte ha gjorts</string>
+  <string name="network_error_connect_timeout_exception">Ett fel uppstod i väntan på servern, operationen kunde inte ha gjorts</string>
+  <string name="network_host_not_available">Åtgärden kunte inte slutföras, servern är ej tillgänglig</string>
+  <string name="empty"></string>
+  <string name="forbidden_permissions">Du har inga rättigheter %s</string>
+  <string name="forbidden_permissions_rename">att döpa om denna fil</string>
+  <string name="forbidden_permissions_delete">att radera denna fil</string>
+  <string name="share_link_forbidden_permissions">att dela denna fil</string>
+  <string name="unshare_link_forbidden_permissions">att avbryta delningen utav denna fil</string>
+  <string name="forbidden_permissions_create">att skapa filen</string>
+  <string name="uploader_upload_forbidden_permissions">att ladda upp i den här mappen</string>
+  <string name="downloader_download_file_not_found">Filen är inte längre tillgänglig på servern</string>
+  <string name="prefs_category_accounts">Konton</string>
+  <string name="prefs_add_account">Lägg till konto</string>
+  <string name="log_progress_dialog_text">Laddar data...</string>
+  <string name="saml_authentication_required_text">Autentisering krävs</string>
+  <string name="saml_authentication_wrong_pass">Fel lösenord</string>
+  <string name="actionbar_move">Flytta</string>
+  <string name="file_list_empty_moving">Ingenting här. Du kan skapa en mapp!</string>
+  <string name="move_choose_button_text">Välj</string>
+  <string name="move_file_not_found">Gick inte att flytta. Vänligen kontrollera att filen existerar</string>
+  <string name="forbidden_permissions_move">att flytta den här filen</string>
+  <string name="prefs_category_security">Säkerhet</string>
 </resources>
index c757504..56e55a1 100644 (file)
@@ -1,2 +1,4 @@
 <?xml version='1.0' encoding='UTF-8'?>
-<resources/>
+<resources>
+  <string name="empty"></string>
+</resources>
diff --git a/res/values-ta-rIN/strings.xml b/res/values-ta-rIN/strings.xml
new file mode 100644 (file)
index 0000000..9cce7ae
--- /dev/null
@@ -0,0 +1,34 @@
+<?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_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="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="sync_string_files">கோப்புகள்</string>
+  <string name="uploader_btn_upload_text">பதிவேற்று</string>
+  <string name="ssl_validator_btn_details_see">விவரங்கள்</string>
+  <string name="activity_chooser_send_file_title">அனுப்பவும்</string>
+  <string name="empty"></string>
+  <string name="prefs_category_accounts">கணக்குகள்</string>
+</resources>
index 9b888c4..8dd0c78 100644 (file)
@@ -3,7 +3,6 @@
   <string name="actionbar_upload">பதிவேற்றுக</string>
   <string name="actionbar_upload_from_apps">மற்ற செயலிகளிலிருந்து உள்ளடக்கம்</string>
   <string name="actionbar_upload_files">கோப்புகள்</string>
-  <string name="actionbar_mkdir">அடைவை உருவாக்குக</string>
   <string name="actionbar_settings">அமைப்புகள்</string>
   <string name="actionbar_see_details">விவரங்கள்</string>
   <string name="prefs_category_general">பொதுவான</string>
   <string name="prefs_manage_accounts">கணக்குகளை நிர்வகிக்க</string>
   <string name="prefs_pincode">App PIN</string>
   <string name="prefs_pincode_summary">உங்களுடைய சேவைப் பயனரை பாதுகாக்க</string>
-  <string name="prefs_instant_upload">உடனடி பதிவேற்றலை இயலுமைப்படுத்துக</string>
-  <string name="prefs_instant_upload_summary">கமராவினால் எடுக்கப்பட்ட படங்கள் உடனடியாக பதிவேற்றப்பட்டன</string>
   <string name="prefs_help">உதவி</string>
-  <string name="auth_host_url">சேவையக முகவரி</string>
   <string name="auth_username">பயனாளர் பெயர்</string>
   <string name="auth_password">கடவுச்சொல்</string>
   <string name="sync_string_files">கோப்புகள்</string>
@@ -29,7 +25,7 @@
   <string name="uploader_wrn_no_content_text">ஒரு உள்ளடக்கமும் பெறப்படவில்லை. பதிவேற்றுவதற்கு ஒன்றும் இல்லை</string>
   <string name="uploader_error_forbidden_content">பகிரப்பட்ட உள்ளடக்ககங்களை அணுகுவதற்கு %1$s  அனுமதிக்கமாட்டாது</string>
   <string name="uploader_info_uploading">பதிவேற்றல்</string>
-  <string name="file_list_empty">à®\87நà¯\8dத à®\95à¯\8bபà¯\8dபà¯\81à®±à¯\88யிலà¯\8d à®\8eநà¯\8dத à®\95à¯\8bபà¯\8dபà¯\81à®®à¯\8d à®\87லà¯\8dலà¯\88. \"பதிவà¯\87à®±à¯\8dறலà¯\8d\" à®ªà®\9fà¯\8dà®\9fி à®¤à¯\86ரிவà¯\81 à®®à¯\82லமà¯\8d à®ªà¯\81திய à®\95à¯\8bபà¯\8dபà¯\81à®\95ளà¯\88 à®ªà®¤à®¿à®µà¯\87à®±à¯\8dறமà¯\81à®\9fியà¯\81à®®à¯\8d.</string>
+  <string name="file_list_empty">à®\87à®\99à¯\8dà®\95à¯\81 à®\92னà¯\8dà®±à¯\81à®®à¯\8d à®\87லà¯\8dலà¯\88. à®\8fதாவதà¯\81 à®ªà®¤à®¿à®µà¯\87à®±à¯\8dà®±à¯\81à®\95!</string>
   <string name="filedetails_select_file">மேலதிக தகவல்களை காட்சிப்படுத்துவதற்கு கோப்பின் மேல் தட்டுக.</string>
   <string name="filedetails_size">அளவு:</string>
   <string name="filedetails_type">வகை:</string>
@@ -50,7 +46,7 @@
   <string name="delete_account">கணக்கை நீக்குக</string>
   <string name="create_account">கணக்கை உருவாக்குக</string>
   <string name="upload_chooser_title">பதிவேற்றல் படிவம்</string>
-  <string name="uploader_info_dirname">à®\85à®\9fà¯\88வà¯\81 பெயர்</string>
+  <string name="uploader_info_dirname">à®\95à¯\8bபà¯\8dபà¯\81à®±à¯\88 பெயர்</string>
   <string name="uploader_upload_in_progress_ticker">பதிவேற்றல்...</string>
   <string name="uploader_upload_in_progress_content">%1$d%% பதிவேற்றல்g %2$s</string>
   <string name="uploader_upload_succeeded_ticker">வெற்றிகரமாக பதிவேற்றப்பட்டது</string>
@@ -95,8 +91,6 @@
   <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="rename_server_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="wait_a_moment">சிறிது நேரம் காத்திருங்கள்</string>
   <string name="filedisplay_unexpected_bad_get_content">எதிர்பாராத பிரச்சினை ; தயவுசெய்து கோப்பை தெரிவுசெய்ய மற்ற செயலியை பயன்படுத்தவும்</string>
   <string name="filedisplay_no_file_selected">ஒரு கோப்பும் தெரிவுசெய்யப்படவில்லை</string>
   <string name="conflict_keep_both">இரண்டையும் வைக்க </string>
   <string name="conflict_overwrite">மேலெழுதல்</string>
   <string name="conflict_dont_upload">பதிவேற்ற வேண்டாம்</string>
+  <string name="empty"></string>
+  <string name="prefs_category_accounts">கணக்குகள்</string>
+  <string name="move_choose_button_text">தெரிவுசெய்க </string>
 </resources>
index b827eda..ac04982 100644 (file)
@@ -1,13 +1,18 @@
 <?xml version='1.0' encoding='UTF-8'?>
 <resources>
+  <string name="actionbar_mkdir">కొత్త సంచయం</string>
   <string name="actionbar_settings">అమరికలు</string>
+  <string name="actionbar_send_file">పంపించు</string>
   <string name="prefs_category_more">మరిన్ని</string>
   <string name="prefs_help">సహాయం</string>
-  <string name="auth_host_url">సేవకి చిరునామా</string>
   <string name="auth_username">వాడుకరి పేరు</string>
   <string name="auth_password">సంకేతపదం</string>
   <string name="common_yes">అవును</string>
   <string name="common_no">కాదు</string>
+  <string name="common_ok">సరే</string>
   <string name="common_cancel">రద్దుచేయి</string>
   <string name="common_error">పొరపాటు</string>
+  <string name="uploader_info_dirname">సంచయం పేరు</string>
+  <string name="activity_chooser_send_file_title">పంపించు</string>
+  <string name="empty"></string>
 </resources>
diff --git a/res/values-tg-rTJ/strings.xml b/res/values-tg-rTJ/strings.xml
new file mode 100644 (file)
index 0000000..56e55a1
--- /dev/null
@@ -0,0 +1,4 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<resources>
+  <string name="empty"></string>
+</resources>
index 521ad4a..0b141a1 100644 (file)
@@ -3,19 +3,17 @@
   <string name="actionbar_upload">อัพโหลดไฟล์</string>
   <string name="actionbar_upload_from_apps">เนื้อหาจากแอปฯอื่นๆ</string>
   <string name="actionbar_upload_files">ไฟล์</string>
-  <string name="actionbar_mkdir">สรà¹\89าà¸\87à¹\84à¸\94à¹\80รà¹\87à¸\81à¸\97อรี่</string>
+  <string name="actionbar_mkdir">à¹\82à¸\9fลà¹\80à¸\94อรà¹\8cà¹\83หม่</string>
   <string name="actionbar_settings">ตั้งค่า</string>
   <string name="actionbar_see_details">รายละเอียด</string>
+  <string name="actionbar_send_file">ส่ง</string>
   <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">App PIN</string>
   <string name="prefs_pincode_summary">ป้องกันโปรแกรมไคลเอนต์ ของคุณ</string>
-  <string name="prefs_instant_upload">เปิดใช้งานระบบอัพโหลดได้ทันที</string>
-  <string name="prefs_instant_upload_summary">อัพโหลดรูปภาพจากกล้องขึ้นไปทันที</string>
   <string name="prefs_help">ช่วยเหลือ</string>
-  <string name="auth_host_url">ที่อยู่เซิร์ฟเวอร์</string>
   <string name="auth_username">ชื่อผู้ใช้</string>
   <string name="auth_password">รหัสผ่าน</string>
   <string name="sync_string_files">ไฟล์</string>
@@ -29,7 +27,7 @@
   <string name="uploader_wrn_no_content_text">ยังไม่ได้รับเนื้อหา ไม่มีอะไรให้ต้องอัพโหลด</string>
   <string name="uploader_error_forbidden_content">%1$s ไม่อนุญาตให้เข้าถึงเนื้อหาที่ถูกแชร์ไว้</string>
   <string name="uploader_info_uploading">กำลังอัพโหลด</string>
-  <string name="file_list_empty">ยัà¸\87à¹\84มà¹\88มีà¹\84à¸\9fลà¹\8cอยูà¹\88à¹\83à¸\99à¹\82à¸\9fลà¹\80à¸\94อรà¹\8cà¸\99ีà¹\89.\nสามารà¸\96à¹\80à¸\9eิà¹\88มà¹\84à¸\9fลà¹\8cà¹\83หมà¹\88à¹\84à¸\94à¹\89à¸\88าà¸\81à¸\95ัวà¹\80ลือà¸\81à¹\83à¸\99à¹\80มà¸\99ู \"อัà¸\9eà¹\82หลà¸\94\".</string>
+  <string name="file_list_empty">ยัà¸\87à¹\84มà¹\88มีà¹\84à¸\9fลà¹\8cà¹\83à¸\94à¹\86อยูà¹\88à¸\97ีà¹\88à¸\99ีà¹\88 à¸\81รุà¸\93าอัà¸\9eà¹\82หลà¸\94à¹\84à¸\9fลà¹\8c!</string>
   <string name="filedetails_select_file">แตะที่ไฟล์ เพื่อแสดงข้อมูลเพิ่มเติม</string>
   <string name="filedetails_size">ขนาด:</string>
   <string name="filedetails_type">ชนิด:</string>
   <string name="common_cancel">ยกเลิก</string>
   <string name="common_save_exit">บันทึก &amp; ออก</string>
   <string name="common_error">ข้อผิดพลาด</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">à¸\8aืà¹\88อà¹\84à¸\94à¹\80รà¹\87à¸\81à¸\97อรีà¹\88</string>
+  <string name="uploader_info_dirname">à¸\8aืà¹\88อà¹\82à¸\9fลà¹\80à¸\94อรà¹\8c</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>
@@ -76,7 +75,6 @@
   <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">กรุณาใส่ PIN แอปของคุณ</string>
   <string name="pincode_configure_your_pin">กรอกรหัส PIN ของ  App</string>
   <string name="pincode_configure_your_pin_explanation">หมายเลข PIN ดังกล่าวจะถูกร้องขอทุกครั้งที่เริ่มใช้งานแอปฯ</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="rename_server_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="wait_a_moment">กรุณารอสักครู่</string>
   <string name="filedisplay_unexpected_bad_get_content">เกิดปัญหาที่ไม่คาดคิด ; กรุณาลองใช้งานแอปฯอื่นๆ เพื่อเลือกไฟล์</string>
   <string name="filedisplay_no_file_selected">ไม่มีไฟล์ที่ถูกเลือก</string>
   <string name="conflict_keep_both">เก็บไว้ทั้งสองอย่าง</string>
   <string name="conflict_overwrite">เขียนทับ</string>
   <string name="conflict_dont_upload">ไม่ต้องอัพโหลด</string>
-  <string name="error__upload__local_file_not_copied">%1$s ไม่สามารถถูกคัดลอกไปที่ %2$s ไดเรกทอรีท้องถิ่น</string>
+  <string name="activity_chooser_send_file_title">ส่ง</string>
+  <string name="empty"></string>
+  <string name="prefs_category_accounts">บัญชี</string>
+  <string name="move_choose_button_text">เลือก</string>
 </resources>
index b6c88bd..e5bfe93 100644 (file)
@@ -3,24 +3,27 @@
   <string name="about_android">%1$s Android Uygulaması</string>
   <string name="about_version">sürüm %1$s</string>
   <string name="actionbar_sync">Hesabı yenile</string>
-  <string name="actionbar_upload">Dosya yükle</string>
+  <string name="actionbar_upload">Yükle</string>
   <string name="actionbar_upload_from_apps">Diğer uygulamalardan içerik</string>
   <string name="actionbar_upload_files">Dosyalar</string>
-  <string name="actionbar_open_with">ile aç</string>
-  <string name="actionbar_mkdir">Klasör oluştur</string>
+  <string name="actionbar_open_with">Birlikte aç</string>
+  <string name="actionbar_mkdir">Yeni klasör</string>
   <string name="actionbar_settings">Ayarlar</string>
-  <string name="actionbar_see_details">Detaylar</string>
+  <string name="actionbar_see_details">Ayrıntılar</string>
+  <string name="actionbar_send_file">Gönder</string>
   <string name="prefs_category_general">Genel</string>
   <string name="prefs_category_more">Daha fazla</string>
   <string name="prefs_accounts">Hesaplar</string>
-  <string name="prefs_manage_accounts">Hesapları yönet</string>
-  <string name="prefs_pincode">App PIN</string>
+  <string name="prefs_manage_accounts">Hesapları Yönet</string>
+  <string name="prefs_pincode">Uygulama PIN\'i</string>
   <string name="prefs_pincode_summary">İstemcinizi koruyun</string>
-  <string name="prefs_instant_upload">Anında yükleme etkinleştir</string>
-  <string name="prefs_instant_upload_summary">Anında çekilen fotoğrafları yükle</string>
-  <string name="prefs_log_title">Günlük tutmayı etkinleştir</string>
+  <string name="prefs_instant_upload">Anında fotoğraf yüklemeleri</string>
+  <string name="prefs_instant_upload_summary">Kamera ile çekilen fotoğrafları anında yükle</string>
+  <string name="prefs_instant_video_upload">Anında video yüklemeleri</string>
+  <string name="prefs_instant_video_upload_summary">Kamera ile çekilen videoları anında yükle</string>
+  <string name="prefs_log_title">Günlük Tutmayı Etkinleştir</string>
   <string name="prefs_log_summary">Bu, sorunları günlük dosyasına kaydetmek için kullanılır</string>
-  <string name="prefs_log_title_history">Günlük geçmişi</string>
+  <string name="prefs_log_title_history">Günlük Geçmişi</string>
   <string name="prefs_log_summary_history">Bu, kayıtlı günlük dosyalarını görüntüler</string>
   <string name="prefs_log_delete_history_button">Geçmişi Sil</string>
   <string name="prefs_help">Yardım</string>
   <string name="prefs_feedback">Geribildirim</string>
   <string name="prefs_imprint">İzlenim</string>
   <string name="recommend_subject">%1$s uygulamasını akıllı telefonunda dene!</string>
-  <string name="recommend_text">Sana, akıllı telefonunda kullanmak üzere %1$s daveti yapıyorum!\nBuradan indirebilirsin: %2$s</string>
-  <string name="auth_check_server">Sunucuyu kontrol et</string>
-  <string name="auth_host_url">Sunucu Adresi</string>
-  <string name="auth_username">Kullanıcı Adi:</string>
-  <string name="auth_password">Şifre:</string>
-  <string name="auth_register">%1$s senin için yeni mi?</string>
+  <string name="recommend_text">Seni, akıllı telefonunda %1$s kullanmaya davet ediyorum!\nBuradan indirebilirsin: %2$s</string>
+  <string name="auth_check_server">Sunucuyu Denetle</string>
+  <string name="auth_host_url">Sunucu adresi https://…</string>
+  <string name="auth_username">Kullanıcı Adı</string>
+  <string name="auth_password">Parola</string>
+  <string name="auth_register">%1$s sizin için yeni mi?</string>
   <string name="sync_string_files">Dosyalar</string>
   <string name="setup_btn_connect">Bağlan</string>
   <string name="uploader_btn_upload_text">Yükle</string>
-  <string name="uploader_top_message">Yükleme dizinini seçiniz:</string>
-  <string name="uploader_wrn_no_account_title">Hesap bulunamadi</string>
-  <string name="uploader_wrn_no_account_text">Cihazınızda %1$s hesabı bulunmamaktadır. Lütfen öncelikle bir hesap ayarı giriniz.</string>
+  <string name="uploader_top_message">Yükleme klasörünü seçin:</string>
+  <string name="uploader_wrn_no_account_title">Hesap bulunamadı</string>
+  <string name="uploader_wrn_no_account_text">Cihazınızda %1$s hesabı bulunmamaktadır. Lütfen öncelikle bir hesap ayarlayın.</string>
   <string name="uploader_wrn_no_account_setup_btn_text">Kurulum</string>
   <string name="uploader_wrn_no_account_quit_btn_text">Çıkış</string>
   <string name="uploader_wrn_no_content_title">Yüklenecek içerik yok</string>
-  <string name="uploader_wrn_no_content_text">Yüklenecek içerik yok. Yüklenecek dosya yok.</string>
-  <string name="uploader_error_forbidden_content">%1$s, paylaşılan içeriğe erişim izni vermiyor</string>
+  <string name="uploader_wrn_no_content_text">Hiç içerik alınmadı. Yüklenecek hiçbir şey yok.</string>
+  <string name="uploader_error_forbidden_content">%1$s için paylaşılan içeriğe erişim izni yok</string>
   <string name="uploader_info_uploading">Yükleniyor</string>
-  <string name="file_list_empty">Klasörde dosya yok. Yeni dosyalar yükle\'ye tıklayarak eklenebilir.</string>
-  <string name="filedetails_select_file">Ek bilgileri görmek için dosyaya tıklayınız.</string>
+  <string name="file_list_empty">Burada hiçbir şey yok. Bir şeyler yükleyin!</string>
+  <string name="file_list_loading">Yükleniyor...</string>
+  <string name="local_file_list_empty">Bu klasörde dosya yok.</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="filedetails_created">Oluşturulma:</string>
-  <string name="filedetails_modified">Değiştirme:</string>
+  <string name="filedetails_modified">Değiştirilme:</string>
   <string name="filedetails_download">İndir</string>
   <string name="filedetails_sync_file">Dosyayı yenile</string>
   <string name="filedetails_renamed_in_upload_msg">Dosya adı, yükleme sırasında %1$s olarak değiştirildi</string>
+  <string name="action_share_file">Paylaşma bağlantısı</string>
+  <string name="action_unshare_file">Bağlantı paylaşımını kaldır</string>
   <string name="common_yes">Evet</string>
   <string name="common_no">Hayır</string>
-  <string name="common_ok">OK</string>
+  <string name="common_ok">Tamam</string>
   <string name="common_cancel_download">İndirmeyi iptal et</string>
   <string name="common_cancel_upload">Yüklemeyi iptal et</string>
   <string name="common_cancel">İptal</string>
-  <string name="common_save_exit">Kaydet %amp; Kapat</string>
+  <string name="common_save_exit">Kaydet ve Çık</string>
   <string name="common_error">Hata</string>
   <string name="common_loading">Yükleniyor...</string>
   <string name="common_error_unknown">Bilinmeyen hata</string>
   <string name="change_password">Parola değiştir</string>
   <string name="delete_account">Hesabı sil</string>
   <string name="create_account">Hesap oluştur</string>
-  <string name="upload_chooser_title">... dan dosya yükle</string>
-  <string name="uploader_info_dirname">Dizin ismi</string>
-  <string name="uploader_upload_in_progress_ticker">Yüklüyor ...</string>
-  <string name="uploader_upload_in_progress_content">%1$d%% Yükleniyor %2$s</string>
+  <string name="upload_chooser_title">Şuradan yükle...</string>
+  <string name="uploader_info_dirname">Klasör adı</string>
+  <string name="uploader_upload_in_progress_ticker">Yükleniyor...</string>
+  <string name="uploader_upload_in_progress_content">%%%1$d Yüklenen: %2$s</string>
   <string name="uploader_upload_succeeded_ticker">Yükleme başarılı</string>
-  <string name="uploader_upload_succeeded_content_single">%1$s kadarı başarıyla yüklendi.</string>
+  <string name="uploader_upload_succeeded_content_single">%1$s başarıyla yüklendi</string>
   <string name="uploader_upload_failed_ticker">Yükleme başarısız</string>
-  <string name="uploader_upload_failed_content_single">%1$s yüklenmedi tamamlanamadı</string>
-  <string name="downloader_download_in_progress_ticker">İndiriyor ...</string>
-  <string name="downloader_download_in_progress_content">%1$d%% İndiriliyor %2$s</string>
+  <string name="uploader_upload_failed_content_single">%1$s yüklenmesi tamamlanamadı</string>
+  <string name="uploader_upload_failed_credentials_error">Yükleme başarısız, yeniden oturum açmalısınız</string>
+  <string name="downloader_download_in_progress_ticker">İndiriliyor...</string>
+  <string name="downloader_download_in_progress_content">%%%1$d İndirilen: %2$s</string>
   <string name="downloader_download_succeeded_ticker">İndirme başarılı</string>
   <string name="downloader_download_succeeded_content">%1$s başarıyla indirildi</string>
-  <string name="downloader_download_failed_ticker">İndirilme başarısız</string>
-  <string name="downloader_download_failed_content">%1$s indirilmesi tamamlanamadı</string>
+  <string name="downloader_download_failed_ticker">İndirme başarısız</string>
+  <string name="downloader_download_failed_content">%1$s indirmesi tamamlanamadı</string>
   <string name="downloader_not_downloaded_yet">Henüz indirilemedi</string>
-  <string name="common_choose_account">Hesap seçiniz</string>
+  <string name="downloader_download_failed_credentials_error">İndirme başarısız, yeniden oturum açmalısınız</string>
+  <string name="common_choose_account">Hesap seçin</string>
   <string name="sync_fail_ticker">Eşitleme başarısız</string>
-  <string name="sync_fail_content">%1$s Senkronizasyonu tamamlanamadı</string>
+  <string name="sync_fail_ticker_unauthorized">Eşitleme başarısız, yeniden oturum açmalısınız</string>
+  <string name="sync_fail_content">%1$s eşitlemesi tamamlanamadı</string>
   <string name="sync_fail_content_unauthorized">%1$s için geçersiz parola</string>
   <string name="sync_conflicts_in_favourites_ticker">Çakışma bulundu</string>
-  <string name="sync_conflicts_in_favourites_content">%1$d korumalı senkronizasyon dosyası, senkronize edilemedi</string>
-  <string name="sync_fail_in_favourites_ticker">Korunan dosya senkronizasyonu başarısız</string>
-  <string name="sync_fail_in_favourites_content">%1$d dosya  senkronize edilemedi  (%2$d hata)</string>
+  <string name="sync_conflicts_in_favourites_content">%1$d eşit tut dosyası, eşitlenemedi</string>
+  <string name="sync_fail_in_favourites_ticker">Dosyaları eşit tut işlemi başarısız</string>
+  <string name="sync_fail_in_favourites_content">%1$d dosya eşitlenemedi (%2$d çakışma)</string>
   <string name="sync_foreign_files_forgotten_ticker">Bazı yerel dosyalar unutuldu</string>
-  <string name="sync_foreign_files_forgotten_content">%1$d dosyalar  %2$s dizinine kopyalanamadı</string>
+  <string name="sync_foreign_files_forgotten_content">%2$s klasöründeki %1$d dosya şuraya kopyalanamadı</string>
   <string name="sync_foreign_files_forgotten_explanation">1.3.16 sürümünden sonra, bu aygıttan yüklenen dosyalar bir dosya birden fazla hesapla eşitlendiğinde veri kaybının önlenebilmesi için %1$s yerel klasörüne kopyalanır.\n\nBu değişiklikten dolayı, bu uygulamanın yüklenmiş tüm önceki sürümündeki dosyalar %2$s klasörüne kopyalandı. Ancak hesap eşitlenmesi sırasında bu işlemin tamamlanmasını engelleyen bir hata oluştu. Dosyayı/dosyaları olduğu gibi bırakabilir ve %3$s bağlantısını kaldırabilirsiniz veya dosyayı/dosyaları %1$s dizinine taşıyıp %4$s bağlantılarını koruyabilirsiniz.\n\nAşağıda listelenenler yerel dosyalar ve bağlı oldukları %5$s içerisindeki uzak dosyalardır.</string>
   <string name="sync_current_folder_was_removed">%1$s klasörü artık mevcut değil.</string>
   <string name="foreign_files_move">Tümünü taşı</string>
   <string name="foreign_files_fail">Bazı dosyalar taşınamadı</string>
   <string name="foreign_files_local_text">Yerel: %1$s</string>
   <string name="foreign_files_remote_text">Uzak: %1$s</string>
-  <string name="upload_query_move_foreign_files">Seçilen dosyaları %1$s dizinine kopyalamak için yeterli alan yok. Bunun yerine dosyayı taşımak ister misiniz?</string>
-  <string name="pincode_enter_pin_code">Lütfen uygulama PIN\'ınızı giriniz</string>
-  <string name="pincode_configure_your_pin">App PIN giriniz</string>
+  <string name="upload_query_move_foreign_files">Seçilen dosyaları %1$s dizinine kopyalamak için yeterli alan yok. Bunun yerine dosyayı içine taşımak ister misiniz?</string>
+  <string name="pincode_enter_pin_code">Lütfen uygulama PIN\'inizi girin</string>
+  <string name="pincode_configure_your_pin">Uygulama PIN\'inizi girin</string>
   <string name="pincode_configure_your_pin_explanation">PIN uygulama yeniden başladığında tekrar sorulacak</string>
-  <string name="pincode_reenter_your_pincode">Lütfen, App PIN ni tekrar giriniz</string>
-  <string name="pincode_remove_your_pincode">App PIN\'nizi kaldırınız.</string>
-  <string name="pincode_mismatch">Her iki App PIN aynı değil.</string>
-  <string name="pincode_wrong">Yanlış App PIN</string>
-  <string name="pincode_removed">App PIN kaldırıldı</string>
-  <string name="pincode_stored">App PIN saklandı</string>
+  <string name="pincode_reenter_your_pincode">Lütfen, uygulama PIN\'inizi tekrar girin</string>
+  <string name="pincode_remove_your_pincode">Uygulama PIN\'inizi kaldırın</string>
+  <string name="pincode_mismatch">Her iki Uygulama PIN\'i aynı değil</string>
+  <string name="pincode_wrong">Yanlış Uygulama PIN\'i</string>
+  <string name="pincode_removed">Uygulama PIN\'i kaldırıldı</string>
+  <string name="pincode_stored">Uygulama PIN\'i saklandı</string>
   <string name="media_notif_ticker">%1$s müzik çalar</string>
   <string name="media_state_playing">%1$s (oynatılıyor)</string>
   <string name="media_state_loading">%1$s (yükleniyor)</string>
-  <string name="media_event_done">%1$s yeniden oynatım sonlandırıldı</string>
-  <string name="media_err_nothing_to_play">Herhangi bir medya öğesi bulunamadı</string>
+  <string name="media_event_done">%1$s oynatma tamamlandı</string>
+  <string name="media_err_nothing_to_play">Herhangi bir ortam ögesi bulunamadı</string>
   <string name="media_err_no_account">Tanımlı hesap yok</string>
-  <string name="media_err_not_in_owncloud">Dosya doğru bir hesapta değil</string>
-  <string name="media_err_unsupported">Codec desteklenmiyor</string>
-  <string name="media_err_io">Medya öğesi okunamadı</string>
-  <string name="media_err_malformed">Medya öğesi doğru bir şekilde kodlanmadı</string>
-  <string name="media_err_timeout">Oynatmaya çalışırken zaman aşımına uğradı</string>
-  <string name="media_err_invalid_progressive_playback">Medya öğesi aktarılamadı</string>
+  <string name="media_err_not_in_owncloud">Dosya geçerli bir hesapta değil</string>
+  <string name="media_err_unsupported">Ortam kod çözücü desteklenmiyor</string>
+  <string name="media_err_io">Ortam ögesi okunamadı</string>
+  <string name="media_err_malformed">Ortam ögesi doğru bir şekilde kodlanmamış</string>
+  <string name="media_err_timeout">Oynatmaya çalışırken zaman aşımına uğradı</string>
+  <string name="media_err_invalid_progressive_playback">Ortam ögesi akışı yapılamıyor</string>
   <string name="media_err_unknown">Ortam dosyası mevcut ortam oynatıcı ile çalınamaz</string>
   <string name="media_err_security_ex">%1$s oynatılmaya çalışılırken güvenlik hatası oluştu</string>
   <string name="media_err_io_ex">%1$s oynatılmaya çalışılırken girdi hatası oluştu</string>
   <string name="media_err_unexpected">%1$s oynatılmaya çalışılırken beklenmeyen bir hata oluştu</string>
-  <string name="media_rewind_description">Başa sar butonu</string>
-  <string name="media_play_pause_description">Oynat veya duraklat butonu</string>
-  <string name="media_forward_description">Hızlı ileri butonu</string>
-  <string name="auth_trying_to_login">Giriş için deneniyor</string>
+  <string name="media_rewind_description">Başa sar düğmesi</string>
+  <string name="media_play_pause_description">Oynat veya duraklat düğmesi</string>
+  <string name="media_forward_description">Hızlı ileri düğmesi</string>
+  <string name="auth_getting_authorization">Kimlik doğrulama alınıyor...</string>
+  <string name="auth_trying_to_login">Oturum açma deneniyor...</string>
   <string name="auth_no_net_conn_title">Ağ bağlantısı yok</string>
-  <string name="auth_nossl_plain_ok_title">Günvenli bağlantı mevcut değil.</string>
+  <string name="auth_nossl_plain_ok_title">Güvenli bağlantı mevcut değil.</string>
   <string name="auth_connection_established">Bağlantı kuruldu</string>
-  <string name="auth_testing_connection">Bağlantı kontrol ediliyor ...</string>
-  <string name="auth_not_configured_title">Hatalı sunucu ayarı.</string>
+  <string name="auth_testing_connection">Bağlantı kontrol ediliyor...</string>
+  <string name="auth_not_configured_title">Hatalı sunucu yapılandırması</string>
   <string name="auth_account_not_new">Cihazda aynı kullanıcı adı ve sunucu için bir hesap zaten mevcut</string>
   <string name="auth_account_not_the_same">Girilen kullanıcı bu hesabın kullanıcısı ile eşleşmiyor</string>
-  <string name="auth_unknown_error_title">Bilinmeyen hata oluştu.</string>
-  <string name="auth_unknown_host_title">Anabilgisayar bulunamadı</string>
-  <string name="auth_incorrect_path_title">sunucu servisi bulunamadı.</string>
+  <string name="auth_unknown_error_title">Bilinmeyen hata oluştu!</string>
+  <string name="auth_unknown_host_title">Ana makine bulunamadı</string>
+  <string name="auth_incorrect_path_title">Sunucu örneği bulunamadı</string>
   <string name="auth_timeout_title">Sunucu çok geç cevap veriyor</string>
   <string name="auth_incorrect_address_title">Hatalı biçimlendirilmiş URL</string>
-  <string name="auth_ssl_general_error_title">SSL başlatılmasında hata</string>
+  <string name="auth_ssl_general_error_title">SSL başlatma başarısız</string>
   <string name="auth_ssl_unverified_server_title">SSL sunucu kimliği doğrulanamadı</string>
   <string name="auth_bad_oc_version_title">Bilinmeyen sunucu sürümü</string>
   <string name="auth_wrong_connection_title">Bağlantı kurulamadı</string>
-  <string name="auth_secure_connection">Güvenli bağlantı sağlandı.</string>
+  <string name="auth_secure_connection">Güvenli bağlantı sağlandı</string>
   <string name="auth_unauthorized">Hatalı kullanıcı adı veya parola</string>
   <string name="auth_oauth_error">Kimlik doğrulama başarısız oldu</string>
   <string name="auth_oauth_error_access_denied">Erişim, kimlik doğrulama sunucusu tarafından reddedildi</string>
   <string name="auth_connecting_auth_server">Kimlik doğrulama sunucusuna bağlanılıyor...</string>
   <string name="auth_unsupported_auth_method">Sunucu bu kimlik doğrulama yöntemini desteklemiyor</string>
   <string name="auth_unsupported_multiaccount">%1$s çoklu hesapları desteklemiyor</string>
-  <string name="fd_keep_in_sync">Dosyayı güncel tut </string>
-  <string name="common_rename">İsim değiştir.</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="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="confirmation_remove_alert"> %1$s ları gerçekten kaldırmak istiyor musunuz ?</string>
-  <string name="confirmation_remove_folder_alert">Gerçekten %1s ve içeriğini silmek istediğinizden emin misiniz?</string>
+  <string name="confirmation_remove_alert">Gerçekten %1$s dosyasını kaldırmak istiyor musunuz?</string>
+  <string name="confirmation_remove_folder_alert">Gerçekten %1$s ve içeriğini kaldırmak istediğinizden emin misiniz?</string>
   <string name="confirmation_remove_local">Sadece yerel</string>
   <string name="confirmation_remove_folder_local">Sadece yerel içerik</string>
   <string name="confirmation_remove_remote">Sunucudan kaldır</string>
-  <string name="confirmation_remove_remote_and_local">Uzaktaki ve yereldeki</string>
+  <string name="confirmation_remove_remote_and_local">Uzak ve yerel</string>
   <string name="remove_success_msg">Kaldırma başarılı</string>
-  <string name="remove_fail_msg">Kaldırma tamamlanamıyor</string>
+  <string name="remove_fail_msg">Kaldırma başarısız</string>
   <string name="rename_dialog_title">Yeni bir isim girin</string>
-  <string name="rename_local_fail_msg">Yerel kopya adlandırılamaz; farklı bir ad deneyin</string>
-  <string name="rename_server_fail_msg">Yeniden  adlandırılma tamamlanmadı</string>
-  <string name="sync_file_fail_msg">Dosya teslim edilemedi</string>
-  <string name="sync_file_nothing_to_do_msg">Dosyalar başarıyla senkronize edildi</string>
-  <string name="create_dir_fail_msg">Dizin oluşturulamadı</string>
+  <string name="rename_local_fail_msg">Yerel kopya adlandırılamadı; farklı bir ad deneyin</string>
+  <string name="rename_server_fail_msg">Yeniden  adlandırılma tamamlanamadı</string>
+  <string name="sync_file_fail_msg">Uzak dosya denetlenemedi</string>
+  <string name="sync_file_nothing_to_do_msg">Dosya içerikleri zaten eşitlenmiş</string>
+  <string name="create_dir_fail_msg">Klasör oluşturulamadı</string>
+  <string name="filename_forbidden_characters">Yasaklı karakterler: / \\ &lt; &gt; : \" | ? *</string>
+  <string name="filename_empty">Dosya adı boş olamaz</string>
   <string name="wait_a_moment">Bir süre bekleyin</string>
-  <string name="filedisplay_unexpected_bad_get_content">Beklenmeyen problem ; lütfen, dosya seçmek için diğer uygulamayı deneyin</string>
+  <string name="filedisplay_unexpected_bad_get_content">Beklenmedik sorun; lütfen dosya seçmek için farklı bir uygulama kullanın</string>
   <string name="filedisplay_no_file_selected">Hiçbir dosya seçilmedi</string>
+  <string name="activity_chooser_title">Bağlantıyı gönder ...</string>
   <string name="oauth_check_onoff">oAuth2 ile oturum aç</string>
   <string name="oauth_login_connection">oAuth2 sunucusuna bağlanılıyor…</string>
   <string name="ssl_validator_header">Bu sitenin sertifikası doğrulanamadı</string>
-  <string name="ssl_validator_reason_cert_not_trusted">- Sunucu sertifikası güvenilmez</string>
-  <string name="ssl_validator_reason_cert_expired">- Sunucu sertifikasının süresi geçmiş</string>
-  <string name="ssl_validator_reason_cert_not_yet_valid">Sunucu sertifikasının geçerli olacağı tarih</string>
-  <string name="ssl_validator_reason_hostname_not_verified">- URL adresi sunucu isminin sertifikası ile uyuşmuyor</string>
+  <string name="ssl_validator_reason_cert_not_trusted">- Sunucu sertifikasına güvenilmiyor</string>
+  <string name="ssl_validator_reason_cert_expired">- Sunucu sertifikasının süresi dolmuş</string>
+  <string name="ssl_validator_reason_cert_not_yet_valid">- Sunucu sertifikasının geçerlilik tarihi ileride</string>
+  <string name="ssl_validator_reason_hostname_not_verified">- Adres, sertifikadaki sunucu adı ile eşleşmiyor</string>
   <string name="ssl_validator_question">Sertifikaya yine de güvenmek istiyor musunuz?</string>
   <string name="ssl_validator_not_saved">Sertifika kaydedilemedi</string>
   <string name="ssl_validator_btn_details_see">Ayrıntılar</string>
   <string name="ssl_validator_label_subject">Verilen:</string>
   <string name="ssl_validator_label_issuer">Veren:</string>
   <string name="ssl_validator_label_CN">Ortak ad:</string>
-  <string name="ssl_validator_label_O">Organizasyon:</string>
-  <string name="ssl_validator_label_OU">Organizasyon birimi:</string>
+  <string name="ssl_validator_label_O">Kurum:</string>
+  <string name="ssl_validator_label_OU">Kuruluş birimi:</string>
   <string name="ssl_validator_label_C">Ülke:</string>
   <string name="ssl_validator_label_ST">Eyalet:</string>
   <string name="ssl_validator_label_L">Konum:</string>
   <string name="ssl_validator_label_validity">Geçerlilik:</string>
-  <string name="ssl_validator_label_validity_from">Kimden:</string>
-  <string name="ssl_validator_label_validity_to">Kime:</string>
+  <string name="ssl_validator_label_validity_from">Başlangıç:</string>
+  <string name="ssl_validator_label_validity_to">Bitiş:</string>
   <string name="ssl_validator_label_signature">İmza:</string>
   <string name="ssl_validator_label_signature_algorithm">Algoritma:</string>
+  <string name="ssl_validator_null_cert">Sertifika gösterilemedi.</string>
+  <string name="ssl_validator_no_info_about_error">- Hata hakkında bilgi yok</string>
   <string name="placeholder_sentence">Bu bir yer tutucudur</string>
   <string name="placeholder_filename">yertutucu.txt</string>
   <string name="placeholder_filetype">PNG Resmi</string>
   <string name="placeholder_filesize">389 KB</string>
   <string name="placeholder_timestamp">2012/05/18 12:23 ÖS</string>
   <string name="placeholder_media_time">12:23:45</string>
-  <string name="instant_upload_on_wifi">Resimleri sadece WiFi bağlantısında yükle</string>
+  <string name="instant_upload_on_wifi">Fotoğrafları sadece kablosuzda (WiFi) yükle</string>
+  <string name="instant_video_upload_on_wifi">Videoları sadece kablosuzda (WiFi) yükle</string>
   <string name="instant_upload_path">/AnındaYükle</string>
   <string name="conflict_title">Çakışmayı güncelle</string>
-  <string name="conflict_message">Uzaktaki %s dosyası, yerel dosya ile senkronize edilemedi.  işleme devam etmek sunucudaki dosyanın içeriğini değiştirecektir.</string>
+  <string name="conflict_message">Uzaktaki %s dosyası, yerel dosya ile eşitlenemedi. İşleme devam etmek sunucudaki dosyanın içeriğini değiştirecektir.</string>
   <string name="conflict_keep_both">İkisini de koru</string>
   <string name="conflict_overwrite">Üzerine yaz</string>
   <string name="conflict_dont_upload">Yükleme</string>
-  <string name="preview_image_description">Görüntü önizleme</string>
-  <string name="preview_image_error_unknown_format">Bu resim gösterilemez</string>
-  <string name="error__upload__local_file_not_copied">%1$s, %2$s yerel dizine kopyalanamadı</string>
-  <string name="actionbar_failed_instant_upload">AnındaYükleme\" başarısız</string>
-  <string name="failed_upload_headline_text">Anında yüklemeler başarısız</string>
-  <string name="failed_upload_headline_hint">Başarısız olan tüm anında yüklemelerin özeti</string>
-  <string name="failed_upload_all_cb">hepsini seç</string>
-  <string name="failed_upload_headline_retryall_btn">tüm seçili olanları tekrar dene</string>
-  <string name="failed_upload_headline_delete_all_btn">yükleme kuyruğundaki tüm seçili olanları sil</string>
-  <string name="failed_upload_retry_text">Resmi yeniden yüklemeyi dene:</string>
-  <string name="failed_upload_load_more_images">Daha fazla Görsel yükle</string>
-  <string name="failed_upload_retry_do_nothing_text">anında yükleme için çevrimiçi değilsiniz, bir şey yapma</string>
-  <string name="failed_upload_failure_text">Hata Mesajı:</string>
-  <string name="failed_upload_quota_exceeded_text">Sunucu yapılandırmanızı kontrol edin. Kotanızı aşmış olabilirsiniz.</string>
+  <string name="preview_image_description">Resim önizleme</string>
+  <string name="preview_image_error_unknown_format">Bu resim gösterilemiyor</string>
+  <string name="error__upload__local_file_not_copied">%1$s, %2$s yerel klasörüne kopyalanamadı</string>
+  <string name="prefs_instant_upload_path_title">Yükleme Yolu</string>
+  <string name="share_link_no_support_share_api">Üzgünüz, paylaşım sunucunuzda etkin değil. Lütfen yöneticinizle
+                iletişime geçin.</string>
+  <string name="share_link_file_no_exist">Paylaşma başarısız. Lütfen dosyanın mevcut olup olmadığını denetleyin</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="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="error_cant_bind_to_operations_service">Ciddi hata: işlem gerçekleştirilemiyor</string>
+  <string name="network_error_socket_exception">Sunucuya bağlanılırken bir hata oluştu.</string>
+  <string name="network_error_socket_timeout_exception">Sunucu beklenirken bir hata oluştu, işlem yapılamadı</string>
+  <string name="network_error_connect_timeout_exception">Sunucu beklenirken bir hata oluştu, işlem yapılamadı</string>
+  <string name="network_host_not_available">İşlem tamamlanamadı, sunucu kullanılamıyor</string>
+  <string name="empty"></string>
+  <string name="forbidden_permissions">%s izniniz yok</string>
+  <string name="forbidden_permissions_rename">Bu dosyayı adlandırma</string>
+  <string name="forbidden_permissions_delete">Bu dosyayı silme</string>
+  <string name="share_link_forbidden_permissions">Bu dosyayı paylaşma</string>
+  <string name="unshare_link_forbidden_permissions">Bu dosya paylaşımını kaldırma</string>
+  <string name="forbidden_permissions_create">Dosya oluşturma</string>
+  <string name="uploader_upload_forbidden_permissions">Bu klasöre yükleme</string>
+  <string name="downloader_download_file_not_found">Bu dosya artık sunucuda mevcut değil</string>
+  <string name="prefs_category_accounts">Hesaplar</string>
+  <string name="prefs_add_account">Hesap ekle</string>
+  <string name="auth_redirect_non_secure_connection_title">Güvenli bağlantı, güvenli olmayan bir rotaya yönlendirildi.</string>
+  <string name="actionbar_logger">Günlükler</string>
+  <string name="log_send_history_button">Geçmişi Gönder</string>
+  <string name="log_mail_subject">ownCloud Android uygulama kayıtları</string>
+  <string name="log_progress_dialog_text">Veri yükleniyor...</string>
+  <string name="saml_authentication_required_text">Kimlik doğrulama gerekli</string>
+  <string name="saml_authentication_wrong_pass">Hatalı parola</string>
+  <string name="actionbar_move">Taşı</string>
+  <string name="file_list_empty_moving">Burada bir şey yok. Bir klasör ekleyebilirsiniz!</string>
+  <string name="move_choose_button_text">Seç</string>
+  <string name="move_file_not_found">Taşıma başarısız. Lütfen dosyanın mevcut olup olmadığını denetleyin</string>
+  <string name="move_file_invalid_into_descendent">Klasörü, kendi alt klasörüne taşımak mümkün değil</string>
+  <string name="move_file_invalid_overwrite">Dosya zaten hedef klasörde mevcut</string>
+  <string name="move_file_error">Bu dosya veya klasörü taşımaya çalışılırken bir hata oluştu</string>
+  <string name="forbidden_permissions_move">bu dosyayı taşımak için</string>
+  <string name="prefs_category_instant_uploading">Anında Yüklemeler</string>
+  <string name="prefs_category_security">Güvenlik</string>
 </resources>
index 41798ce..e1140f8 100644 (file)
@@ -2,14 +2,14 @@
 <resources>
   <string name="actionbar_upload">يۈكلە</string>
   <string name="actionbar_upload_files">ھۆججەتلەر</string>
-  <string name="actionbar_mkdir">Ù\85Û\87Ù\86دÛ\95رÙ\89جÛ\95 Ù\82Û\87ر</string>
+  <string name="actionbar_mkdir">Ù\8aÛ\90Ú­Ù\89 Ù\82Ù\89سÙ\82Û\87Ú\86</string>
   <string name="actionbar_settings">تەڭشەكلەر</string>
+  <string name="actionbar_send_file">يوللا</string>
   <string name="prefs_category_general">ئادەتتىكى</string>
   <string name="prefs_category_more">تېخىمۇ كۆپ</string>
   <string name="prefs_accounts">ھېساباتلار</string>
   <string name="prefs_help">ياردەم</string>
   <string name="prefs_feedback">قايتۇرما ئىنكاس</string>
-  <string name="auth_host_url">مۇلازىمېتىر ئادرىسى</string>
   <string name="auth_username">ئىشلەتكۈچى ئاتى</string>
   <string name="auth_password">ئىم</string>
   <string name="sync_string_files">ھۆججەتلەر</string>
@@ -19,6 +19,7 @@
   <string name="uploader_wrn_no_account_setup_btn_text">تەڭشەك</string>
   <string name="uploader_wrn_no_account_quit_btn_text">چېكىن</string>
   <string name="uploader_info_uploading">يۈكلەۋاتىدۇ</string>
+  <string name="file_list_empty">بۇ جايدا ھېچنېمە يوق. Upload something!</string>
   <string name="filedetails_size">چوڭلۇقى:</string>
   <string name="filedetails_type">تىپى:</string>
   <string name="filedetails_created">قۇرۇلغان ۋاقتى:</string>
   <string name="common_error">خاتالىق</string>
   <string name="common_error_unknown">يوچۇن خاتالىق</string>
   <string name="change_password">ئىم ئۆزگەرت</string>
-  <string name="uploader_info_dirname">Ù\85Û\87Ù\86دÛ\95رÙ\89جÛ\95 Ø¦Ù\89سÙ\85ى</string>
+  <string name="uploader_info_dirname">Ù\82Ù\89سÙ\82Û\87Ú\86 Ø¦Ø§Øªى</string>
   <string name="common_choose_account">ھېسابات تاللاڭ</string>
   <string name="common_rename">ئات ئۆزگەرت</string>
   <string name="common_remove">چىقىرىۋەت</string>
+  <string name="activity_chooser_send_file_title">يوللا</string>
+  <string name="empty"></string>
+  <string name="prefs_category_accounts">ھېساباتلار</string>
+  <string name="prefs_category_security">بىخەتەرلىك</string>
 </resources>
index 749321e..d927e39 100644 (file)
@@ -1,28 +1,46 @@
 <?xml version='1.0' encoding='UTF-8'?>
 <resources>
+  <string name="about_android">%1$s Android App</string>
+  <string name="about_version">версія %1$s</string>
+  <string name="actionbar_sync">Оновити account</string>
   <string name="actionbar_upload">Відвантажити</string>
   <string name="actionbar_upload_from_apps">Вміст із інших програм</string>
   <string name="actionbar_upload_files">Файли</string>
-  <string name="actionbar_mkdir">Створити теку</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="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">App програмний PIN</string>
   <string name="prefs_pincode_summary">Захист Вашог App клієнта</string>
-  <string name="prefs_instant_upload">Включити негайне завантаження</string>
-  <string name="prefs_instant_upload_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="auth_host_url">Адреса сервера</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="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_content_text">Не отримано даних. Нічого завантажувати.</string>
   <string name="uploader_error_forbidden_content">%1$s не може отримати доступ до спільного контенту</string>
   <string name="uploader_info_uploading">Завантаження</string>
-  <string name="file_list_empty">В цьому каталозі відсутні файли.\nНові файли можна додати через опцію меню \"Завантаження\".</string>
+  <string name="file_list_empty">Тут нічого немає. Відвантажте що-небудь!</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_download">Завантажити</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">OK</string>
@@ -47,6 +70,7 @@
   <string name="common_cancel">Відмінити</string>
   <string name="common_save_exit">Зберегти &amp; Вихід</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="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_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_not_downloaded_yet">Ще не завантажене</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_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_conflicts_in_favourites_content">%1$d файли, які мають бути синхронізованими не можуть синхронізуватися</string>
   <string name="sync_fail_in_favourites_ticker">Синхронізувати файли не вдалося</string>
   <string name="sync_fail_in_favourites_content">Зміст %1$d файлів не може бути синхронізований (%2$d конфліктів)</string>
   <string name="sync_foreign_files_forgotten_ticker">Деякі локальні файли були забуті</string>
-  <string name="sync_foreign_files_forgotten_content">%1$d файлів з каталогу %2$s не можуть бути в нього скопійовані</string>
+  <string name="sync_foreign_files_forgotten_content">Неможливо скопіювати %1$d файли з теки %2$s</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="pincode_wrong">Не вірний App програмний PIN</string>
   <string name="pincode_removed">App програмний PIN видалено</string>
   <string name="pincode_stored">App програмний PIN збережено</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_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">Пошкоджений URL</string>
   <string name="auth_ssl_general_error_title">Помилка SSL ініціалізації</string>
+  <string name="auth_ssl_unverified_server_title">Неможливо перевірити SSL-сертифікат сервера</string>
   <string name="auth_bad_oc_version_title">Не вдалося визначити версію сервер серверу</string>
   <string name="auth_wrong_connection_title">Не вдалося встановити з\'єднання</string>
   <string name="auth_secure_connection">Встановлено захищене з\'єднання</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="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">Ð\92и Ð´Ñ\96йÑ\81но Ð±Ð°Ð¶Ð°Ñ\94Ñ\82е Ð²Ð¸Ð´Ð°Ð»Ð¸Ñ\82и %1$s Ñ\96 Ð¹Ð¾Ð³Ð¾ Ð·Ð¼Ñ\96Ñ\81Ñ\82 ?</string>
+  <string name="confirmation_remove_alert">Ви дійсно бажаєте видалити %1$s?</string>
+  <string name="confirmation_remove_folder_alert">Ð\92и Ð´Ñ\96йÑ\81но Ð±Ð°Ð¶Ð°Ñ\94Ñ\82е Ð²Ð¸Ð´Ð°Ð»Ð¸Ñ\82и %1$s Ñ\82а Ð²ÐµÑ\81Ñ\8c Ð²Ð¼Ñ\96Ñ\81Ñ\82?</string>
   <string name="confirmation_remove_local">Лише локально</string>
   <string name="confirmation_remove_folder_local">Лише локальний зміст</string>
   <string name="confirmation_remove_remote">Видалити із серверу</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_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">- Не довірений сертифікат серверу</string>
   <string name="ssl_validator_reason_cert_expired">- Сертифікат серверу втратив чинність</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">placeholder.txt</string>
+  <string name="placeholder_filetype">PNG зображення</string>
+  <string name="placeholder_filesize">389 КБ</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_video_upload_on_wifi">Завантажувати відео тільки через WiFi</string>
   <string name="instant_upload_path">/InstantUpload</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="error__upload__local_file_not_copied">%1$s неможливо скопіювати в локальний каталог %2$s</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="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_mail_subject">Журнали Android-додатка ownCloud</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="move_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>
 </resources>
index a96fe56..1532b7a 100644 (file)
@@ -1,11 +1,21 @@
 <?xml version='1.0' encoding='UTF-8'?>
 <resources>
   <string name="actionbar_settings">سیٹینگز</string>
+  <string name="actionbar_send_file">بھجیں</string>
+  <string name="prefs_category_more">مزید</string>
   <string name="prefs_help">مدد</string>
   <string name="auth_username">یوزر نیم</string>
   <string name="auth_password">پاسورڈ</string>
+  <string name="setup_btn_connect">منسلک</string>
+  <string name="filedetails_download">ڈاؤن لوڈ،</string>
+  <string name="action_share_file">اشتراک لنک</string>
   <string name="common_yes">ہاں</string>
   <string name="common_no">نہیں</string>
+  <string name="common_ok">اوکے</string>
   <string name="common_cancel">منسوخ کریں</string>
   <string name="common_error">ایرر</string>
+  <string name="common_error_unknown">غیر معروف خرابی</string>
+  <string name="activity_chooser_send_file_title">بھجیں</string>
+  <string name="empty"></string>
+  <string name="move_choose_button_text">منتخب کریں</string>
 </resources>
diff --git a/res/values-ur/strings.xml b/res/values-ur/strings.xml
new file mode 100644 (file)
index 0000000..63dbc49
--- /dev/null
@@ -0,0 +1,5 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<resources>
+  <string name="common_error">خرابی</string>
+  <string name="empty"></string>
+</resources>
index c757504..56e55a1 100644 (file)
@@ -1,2 +1,4 @@
 <?xml version='1.0' encoding='UTF-8'?>
-<resources/>
+<resources>
+  <string name="empty"></string>
+</resources>
index 75cfb9b..ab237e8 100644 (file)
@@ -6,4 +6,17 @@
                <item name="android:textColor">@color/button_text_color</item>
        </style>
 
+       <!-- Notifications -->
+       <!-- Notifications -->
+       <style  name="Theme.ownCloud.NotificationText.Title" 
+               parent="@android:style/TextAppearance.StatusBar.EventContent.Title" > 
+               <item name="android:textSize">18sp</item>
+        <item name="android:textStyle">bold</item>
+       </style>
+
+       <style  name="Theme.ownCloud.NotificationText.Content" 
+               parent="@android:style/TextAppearance.StatusBar.EventContent"   >
+        <item name="android:textSize">16sp</item>
+       </style>
+       
 </resources>
diff --git a/res/values-v9/versioned_styles.xml b/res/values-v9/versioned_styles.xml
new file mode 100644 (file)
index 0000000..57bb396
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android">
+       
+       <!-- Notifications -->
+       <style name="Theme.ownCloud.NotificationText.Title" 
+           parent="@android:style/TextAppearance.StatusBar.EventContent.Title" 
+           />
+       <style name="Theme.ownCloud.NotificationText.Content" 
+           parent="@android:style/TextAppearance.StatusBar.EventContent" 
+           />
+       
+</resources>
index 859c483..122092d 100644 (file)
   <string name="actionbar_mkdir">Tạo thư mục</string>
   <string name="actionbar_settings">Cài đặt</string>
   <string name="actionbar_see_details">Chi tiết</string>
+  <string name="actionbar_send_file">Gởi</string>
   <string name="prefs_category_general">Tổng hợp</string>
   <string name="prefs_category_more">hơn</string>
   <string name="prefs_accounts">Tài khoản</string>
   <string name="prefs_manage_accounts">Quản lý tài khoản</string>
   <string name="prefs_pincode">Mã PIN ứng dụng App</string>
   <string name="prefs_pincode_summary">Bảo vệ App client của bạn</string>
-  <string name="prefs_instant_upload">Kích hoạt tính năng tải lên ngay lập tức</string>
-  <string name="prefs_instant_upload_summary">Ngay lập tức tải lên các hình ảnh được chụp bởi camera</string>
   <string name="prefs_log_title">Bật chế độ nhật trình</string>
   <string name="prefs_log_summary">Được sử dụng cho các vấn đề liên quan đến nhật trình</string>
   <string name="prefs_log_title_history">Nhật trình dữ kiện</string>
   <string name="prefs_log_summary_history">Hiển thị các nhật trình đã được ghi nhận lại</string>
   <string name="prefs_log_delete_history_button">Xóa lịch sử</string>
   <string name="prefs_help">Giúp đỡ</string>
+  <string name="prefs_recommend">Giới thiệu đến bạn bè</string>
+  <string name="prefs_feedback">Phản hồi</string>
+  <string name="prefs_imprint">Đánh dấu</string>
+  <string name="recommend_subject">Thử %1$s trên smartphone của bạn!</string>
   <string name="auth_check_server">Kiểm tra máy chủ</string>
-  <string name="auth_host_url">Địa chỉ máy chủ</string>
+  <string name="auth_host_url">Địa chỉ máy chủ https://…</string>
   <string name="auth_username">Tên người dùng</string>
   <string name="auth_password">Mật khẩu</string>
   <string name="auth_register">Lần đầu mới đến %1$s?</string>
   <string name="sync_string_files">Tập tin</string>
   <string name="setup_btn_connect">Kết nối</string>
   <string name="uploader_btn_upload_text">Tải lên</string>
-  <string name="uploader_top_message">Chọn thư mục tải lên:</string>
   <string name="uploader_wrn_no_account_title">Không tìm thấy tài khoản</string>
   <string name="uploader_wrn_no_account_text">Trên thiết bị của bạn không có tài khoản %1$s. Bước đầu tiên hãy thiết lập một tài khoản.</string>
   <string name="uploader_wrn_no_account_setup_btn_text">Cài đặt</string>
@@ -41,7 +43,7 @@
   <string name="uploader_wrn_no_content_text">Không có nội dung được nhận. Không có gì để tải lên.</string>
   <string name="uploader_error_forbidden_content">%1$s không cho phép truy cập vào các nội dung chia sẻ</string>
   <string name="uploader_info_uploading">Đang tải lên</string>
-  <string name="file_list_empty">Không có các tập tin trong thư mục này ⏎ tập tin mới có thể được thêm vào với tùy chọn trình đơn \"Tải lên\".</string>
+  <string name="file_list_empty">Không có gì ở đây .Hãy tải lên một cái gì đó !</string>
   <string name="filedetails_select_file">Tap vào một tập tin để hiển thị thêm thông tin</string>
   <string name="filedetails_size">Kích thước:</string>
   <string name="filedetails_type">Loại:</string>
@@ -50,6 +52,8 @@
   <string name="filedetails_download">Tải về</string>
   <string name="filedetails_sync_file">Cập nhật lại tập tin</string>
   <string name="filedetails_renamed_in_upload_msg">Tập tin đã bị đổi tên thành %1$s trong quá trình tải lên</string>
+  <string name="action_share_file">Chia sẻ liên kết</string>
+  <string name="action_unshare_file">Liên kết không chia sẻ</string>
   <string name="common_yes">Yes</string>
   <string name="common_no">Không</string>
   <string name="common_ok">Chấp nhận</string>
   <string name="sync_fail_in_favourites_ticker">Các file trong hàng đợi đồng bộ không thành công</string>
   <string name="sync_fail_in_favourites_content">Nội dung tập tin %1$d không thể đồng bộ (%2$d xung đột)</string>
   <string name="sync_foreign_files_forgotten_ticker">Một số tập tin cục bộ bị quên</string>
-  <string name="sync_foreign_files_forgotten_content">Các tập tin %1$d ở ngoài thư mục %2$s không thể được chép vào</string>
+  <string name="sync_current_folder_was_removed">Thư mục %1$s không còn tồn tại</string>
   <string name="foreign_files_move">Di chuyển tất cả</string>
   <string name="foreign_files_success">Tất cả tập tin đã được chuyển đi</string>
   <string name="foreign_files_fail">Một vài tập tin không thể chuyển đi</string>
   <string name="foreign_files_local_text">Cục bộ: %1$s</string>
   <string name="foreign_files_remote_text">Từ xa: %1$s</string>
-  <string name="upload_query_move_foreign_files">Không đủ chỗ trống để chép các tập tin đã chọn vào thư mục %1$s. Bạn có muốn di chuyển chúng thay vì sao chép?</string>
   <string name="pincode_enter_pin_code">Vui lòng, nhập mã PIN ứng dụng của bạn</string>
   <string name="pincode_configure_your_pin">Nhập mã PIN ứng dụng App</string>
   <string name="pincode_configure_your_pin_explanation">Mã PIN sẽ được yêu cầu mỗi khi ứng dụng được bật </string>
   <string name="media_err_unsupported">Codec của media không được hỗ trợ</string>
   <string name="media_err_io">Không thể đọc dữ liệu từ tập tin media</string>
   <string name="media_err_malformed">Tập tin media không được mã hóa đúng quy định</string>
+  <string name="media_err_timeout">Tạm ngừng trong khi đang cố gắng chạy</string>
   <string name="media_err_invalid_progressive_playback">Không thể phân luồng dữ liệu tập tin media</string>
   <string name="media_err_unknown">Tập tin media không thể được phát với trình phát media của stock</string>
   <string name="media_err_security_ex">Lỗi bảo mật khi cố phát %1$s</string>
   <string name="auth_connection_established">Kết nối đã thiết lập</string>
   <string name="auth_testing_connection">Đang kiểm tra kết nối...</string>
   <string name="auth_not_configured_title">Thay đổi cấu hình máy chủ </string>
+  <string name="auth_account_not_new">Một tài khoản với cùng tên người dùng và máy chủ đã tồn tại trong thiết bị</string>
+  <string name="auth_account_not_the_same">Tên người dùng đã nhập không đúng với tên người dùng của tài khoản này</string>
   <string name="auth_unknown_error_title">Không xác định được lỗi!</string>
   <string name="auth_unknown_host_title">Không thể tìm thấy máy chủ</string>
   <string name="auth_incorrect_path_title">Phiên bản máy chủ không tìm thấy</string>
   <string name="auth_timeout_title">Máy chủ đã quá dài để đáp ứng</string>
   <string name="auth_incorrect_address_title">Thay đổi URL</string>
   <string name="auth_ssl_general_error_title">SSL khởi tạo thất bại</string>
+  <string name="auth_ssl_unverified_server_title">không thể xác minh danh tính của máy chủ SSL</string>
   <string name="auth_bad_oc_version_title">Không chấp nhận phiên bản máy chủ</string>
   <string name="auth_wrong_connection_title">Không thể thiết lập kết nối</string>
   <string name="auth_secure_connection">Kết nối an toàn đã được thiết lập</string>
   <string name="auth_oauth_error">Xác nhận không thành công</string>
   <string name="auth_oauth_error_access_denied">Từ chối truy cập vì xác nhận từ phía máy chủ</string>
   <string name="auth_wtf_reenter_URL">Trạng thái không rõ, vui lòng điền lại đường dẫn liên kết một lần nữa</string>
+  <string name="auth_expired_oauth_token_toast">Hạn xác nhận của bạn đã hết. Vui lòng, xác nhận lại</string>
   <string name="auth_expired_basic_auth_toast">Vui lòng điền vào mật khẩu hiện tại của bạn</string>
+  <string name="auth_expired_saml_sso_token_toast">Phiên làm việc của bạn đã kết thúc. Vui lòng kết nối lại</string>
+  <string name="auth_connecting_auth_server">Đang kết nối đến máy chủ xác thực...</string>
+  <string name="auth_unsupported_auth_method">Máy chủ không hổ trợ phương thức xác thực này</string>
+  <string name="auth_unsupported_multiaccount">%1$s  không hỗ trợ nhiều tài khoản</string>
   <string name="fd_keep_in_sync">Giữ tập tin cập nhật</string>
   <string name="common_rename">Sửa tên</string>
   <string name="common_remove">Xóa</string>
-  <string name="confirmation_remove_alert">Bạn có thực sự muốn xóa %1$s ?</string>
-  <string name="confirmation_remove_folder_alert">Bạn có thật sự muốn xóa %1$s và nội dung của nó ?</string>
   <string name="confirmation_remove_local">Chỉ cục bộ</string>
   <string name="confirmation_remove_folder_local">Chỉ nội dung trên máy</string>
   <string name="confirmation_remove_remote">Xóa từ máy chủ</string>
   <string name="rename_server_fail_msg">Đổi tên không thể hoàn thành</string>
   <string name="sync_file_fail_msg">Tập tin từ xa không được kiểm tra</string>
   <string name="sync_file_nothing_to_do_msg">Nội dung tập tin đã đồng bộ</string>
-  <string name="create_dir_fail_msg">Thư mục không thể được tạo</string>
+  <string name="filename_forbidden_characters">Những kí tự không được dùng: / \\ &lt; &gt; : \" | ? *</string>
   <string name="wait_a_moment">Chờ một lúc</string>
   <string name="filedisplay_unexpected_bad_get_content">Vấn đề bất ngờ ; hãy thử ứng dụng khác để chọn tập tin</string>
   <string name="filedisplay_no_file_selected">Không có tập tin nào được chọn</string>
+  <string name="activity_chooser_title">Gửi liên kết đến...</string>
+  <string name="oauth_check_onoff">Đăng nhập bằng oAuth2.</string>
   <string name="oauth_login_connection">Đang kết nối đến máy chủ oAuth2...</string>
   <string name="ssl_validator_header">Không thể xác minh danh tính của site</string>
   <string name="ssl_validator_reason_cert_not_trusted">Chứng chỉ này không đáng tin cậy</string>
   <string name="conflict_overwrite">Ghi đè lên</string>
   <string name="conflict_dont_upload">Không tải lên</string>
   <string name="preview_image_description">Xem trước hình ảnh</string>
-  <string name="preview_image_error_unknown_format">Không thể hiển thị hình ảnh</string>
-  <string name="error__upload__local_file_not_copied">%1$s không thể sao chép vào %2$s thư mục cục bộ</string>
-  <string name="actionbar_failed_instant_upload">Tải lên nhanh bị lỗi\"</string>
-  <string name="failed_upload_headline_text">Tải lên nhanh bị lỗi</string>
-  <string name="failed_upload_headline_hint">Tóm tắt tất cả các tải lên nhanh bị lỗi</string>
-  <string name="failed_upload_all_cb">chọn tất cả</string>
-  <string name="failed_upload_headline_retryall_btn">thử lại với tất cả các đối tượng được chọn</string>
-  <string name="failed_upload_headline_delete_all_btn">xóa tất cả khỏi các đối tượng được chọn trong hàng đợi chờ tải lên</string>
-  <string name="failed_upload_retry_text">thử lại việc tải lên hình ảnh:</string>
-  <string name="failed_upload_load_more_images">Tải thêm nhiều hình ảnh</string>
-  <string name="failed_upload_retry_do_nothing_text">không thực hiện thao tác gì nêu bạn không có kết nối mạng dành cho tải lên nhanh</string>
-  <string name="failed_upload_failure_text">Thông điệp lỗi:</string>
-  <string name="failed_upload_quota_exceeded_text">Vui lòng kiểm tra cấu hình máy chủ của bạn, có thể hạn ngạch dữ liệu đã quá hạn.</string>
+  <string name="share_link_file_error">Một lỗi đã xảy ra khi thử chia sẻ file hoặc thư mục này</string>
+  <string name="unshare_link_file_error">Một lỗi đã xảy ra khi thử gỡ chia sẻ file hoặc thư mục này</string>
+  <string name="activity_chooser_send_file_title">Gởi</string>
+  <string name="empty"></string>
+  <string name="prefs_category_accounts">Tài khoản</string>
+  <string name="move_choose_button_text">Chọn</string>
 </resources>
index 67a69e1..79255f8 100644 (file)
@@ -1,36 +1,47 @@
 <?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">来自其它app的内容</string>
   <string name="actionbar_upload_files">文件</string>
   <string name="actionbar_open_with">打开</string>
-  <string name="actionbar_mkdir">å\88\9b建ç\9b®å½\95</string>
+  <string name="actionbar_mkdir">å¢\9eå\8a æ\96\87件夹</string>
   <string name="actionbar_settings">设置</string>
   <string name="actionbar_see_details">详细信息</string>
+  <string name="actionbar_send_file">发送</string>
   <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">App PIN</string>
   <string name="prefs_pincode_summary">保护您的App客户端</string>
-  <string name="prefs_instant_upload">开启即时上传</string>
-  <string name="prefs_instant_upload_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="recommend_subject">在您的智能手机上试用一下 %1$s!</string>
+  <string name="recommend_text">“我邀请你使用在你的智能手机上使用 %1$s,在这下载:%2$s”
+       </string>
   <string name="auth_check_server">检查服务器</string>
-  <string name="auth_host_url">服务器地址</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="uploader_btn_upload_text">上传</string>
-  <string name="uploader_top_message">选择上传目录:</string>
+  <string name="uploader_top_message">选择上传文件夹:</string>
   <string name="uploader_wrn_no_account_title">未找到账号</string>
   <string name="uploader_wrn_no_account_text">设备上未找到账号,请先创建账号。</string>
   <string name="uploader_wrn_no_account_setup_btn_text">设置</string>
   <string name="uploader_wrn_no_content_text">没有接收到内容,无可上传。</string>
   <string name="uploader_error_forbidden_content">%1$s未被允许访问共享内容。</string>
   <string name="uploader_info_uploading">上传</string>
-  <string name="file_list_empty">文件夹为空\n可以使用上传按钮来增加文件</string>
+  <string name="file_list_empty">这里还什么都没有。上传些东西吧!</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_download">下载</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">OK</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_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$上传未能完成</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_failed_ticker">下载失败</string>
   <string name="downloader_download_failed_content">下载1$s 未能完成</string>
   <string name="downloader_not_downloaded_yet">未下载完毕</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_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_fail_in_favourites_ticker">文件同步失败</string>
   <string name="sync_fail_in_favourites_content">无法同步 %1$d 文件内容(与 %2$d 冲突)</string>
   <string name="sync_foreign_files_forgotten_ticker">某些本地文件已被遗忘</string>
-  <string name="sync_foreign_files_forgotten_content">%2$s目录中的%1$d个文件不能被复制到</string>
-  <string name="sync_foreign_files_forgotten_explanation">\"从 1.3.16 版起,从此设备上传的文件将被复制到本地的 %1$s 文件夹来防止当某个单一文件在多个账户间同步造成的数据损失。由于此项变化,此应用之前的版本上传的全部文件都已被复制到了 %2$s 文件夹。然而,账户同步期间有一个错误阻止了此操作的完成。您或许可以保持文件不动,并移除指向 %3$s 的链接,或将文件移动到 %1$s 文件夹中并将保持到 %4$s 的链接。下面列出的是本地文件,以及它们被链接到的 %5$s 中的远程文件。</string>
+  <string name="sync_foreign_files_forgotten_content">%2$s 目录中的 %1$d 个文件不能被复制到</string>
+  <string name="sync_foreign_files_forgotten_explanation">从 1.3.16 版起,从此设备上传的文件将被复制到本地的 %1$s 文件夹,以防止某个单一文件在多个账户间同步而造成的数据损失。\n\n 由于此项变化,此应用之前的版本上传的全部文件都已被复制到了 %2$s 文件夹。然而,账户同步期间有一个错误阻止了此操作的完成。您可能想保持文件不动,并移除指向 %3$s 的链接,或将文件移动到 %1$s 文件夹中并保持其到 %4$s 的链接。下面列出的是本地文件,以及它们被链接到的 %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="upload_query_move_foreign_files">没有足够的空间以复制选定的文件到 %1$s 文件夹,您想移动文件到此文件夹吗?</string>
   <string name="pincode_enter_pin_code">请输入您的App PIN码</string>
   <string name="pincode_configure_your_pin">输入 App PIN码</string>
   <string name="pincode_configure_your_pin_explanation">每次应用启动时都会请求PIN码</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_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_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_unverified_server_title">无法验证 SSL 服务器的身份</string>
   <string name="auth_bad_oc_version_title">不可辨识的服务器服务器版本</string>
   <string name="auth_wrong_connection_title">无法建立连接</string>
   <string name="auth_secure_connection">加密连接已建立</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">您的服务器没有返回一个正确的用户 id,请联系管理员
+       </string>
+  <string name="auth_can_not_auth_against_server">无法通过此服务器认证</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_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="rename_server_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="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_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">不受信任的服务器证书</string>
   <string name="ssl_validator_reason_cert_expired">服务器证书过期</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">PNG图像格式</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">仅通过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="conflict_message">远程文件 %s 未与本地文件同步。继续将替换服务器上的文件内容。</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="actionbar_failed_instant_upload">限时上传失败</string>
-  <string name="failed_upload_headline_text">限时上传失败</string>
-  <string name="failed_upload_headline_hint">限时上传失败汇总</string>
-  <string name="failed_upload_all_cb">全选</string>
-  <string name="failed_upload_headline_retryall_btn">重试全选</string>
-  <string name="failed_upload_headline_delete_all_btn">从上传列表删除所有选定项</string>
-  <string name="failed_upload_retry_text">重试上传图片</string>
-  <string name="failed_upload_load_more_images">载入更多图片</string>
-  <string name="failed_upload_retry_do_nothing_text">不在线时不开启即时上传</string>
-  <string name="failed_upload_failure_text">失败消息</string>
-  <string name="failed_upload_quota_exceeded_text">请检查服务器设置。可能走出配额。</string>
+  <string name="error__upload__local_file_not_copied">无法复制 %1$s 到本地目录 %2$s</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="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="actionbar_logger">日志</string>
+  <string name="log_send_history_button">发送历史</string>
+  <string name="log_mail_subject">ownCloud安卓客户端日志</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="move_choose_button_text">选择(&amp;C)...</string>
+  <string name="move_file_not_found">无法移动。请检查文件是否存在</string>
+  <string name="move_file_invalid_into_descendent">b不能够把一个目录移动到它的下级</string>
+  <string name="move_file_invalid_overwrite">该文件已经存在在目标文件夹</string>
+  <string name="move_file_error">尝试移动该文件或文件夹时发生错误</string>
+  <string name="forbidden_permissions_move">移动该文件</string>
+  <string name="prefs_category_security">安全</string>
 </resources>
index c119564..bd5f2e1 100644 (file)
@@ -1,31 +1,71 @@
 <?xml version='1.0' encoding='UTF-8'?>
 <resources>
-  <string name="actionbar_upload">上傳</string>
+  <string name="about_android">%1$s Android App</string>
+  <string name="about_version">版本 %1$s</string>
+  <string name="actionbar_upload">上戴</string>
   <string name="actionbar_upload_files">文件</string>
-  <string name="actionbar_mkdir">建立目錄</string>
+  <string name="actionbar_mkdir">新資料夾</string>
   <string name="actionbar_settings">設定</string>
+  <string name="actionbar_send_file">傳送</string>
   <string name="prefs_category_general">一般</string>
+  <string name="prefs_category_more">更多</string>
   <string name="prefs_accounts">帳號</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>
   <string name="setup_btn_connect">連線</string>
-  <string name="uploader_btn_upload_text">上</string>
+  <string name="uploader_btn_upload_text">上</string>
   <string name="uploader_wrn_no_account_title">找不到帳戶</string>
   <string name="uploader_wrn_no_account_setup_btn_text">設定</string>
   <string name="uploader_wrn_no_account_quit_btn_text">退出</string>
-  <string name="uploader_info_uploading">正在上傳</string>
-  <string name="filedetails_size">大小</string>
-  <string name="filedetails_type">類別</string>
-  <string name="filedetails_created">建立於:</string>
-  <string name="filedetails_modified">修改於:</string>
+  <string name="uploader_info_uploading">正在上戴</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_download">下載</string>
-  <string name="common_yes">Yes</string>
-  <string name="common_no">No</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">取消上戴</string>
   <string name="common_cancel">取消</string>
+  <string name="common_save_exit">儲存並離開</string>
   <string name="common_error">錯誤</string>
-  <string name="uploader_info_dirname">目錄名稱</string>
-  <string name="common_choose_account">選擇帳戶</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_succeeded_ticker">上載成功</string>
+  <string name="uploader_upload_failed_ticker">上載失敗</string>
+  <string name="downloader_download_in_progress_ticker">下載中</string>
+  <string name="downloader_download_succeeded_ticker">下載成功</string>
+  <string name="downloader_download_failed_ticker">下載失敗</string>
+  <string name="common_choose_account">選擇帳號</string>
+  <string name="foreign_files_move">移動所有</string>
+  <string name="auth_no_net_conn_title">無網絡連線</string>
+  <string name="common_rename">重新命名</string>
+  <string name="common_remove">刪除</string>
+  <string name="ssl_validator_btn_details_hide">隱藏</string>
+  <string name="ssl_validator_label_C">國家:</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="activity_chooser_send_file_title">傳送</string>
+  <string name="copy_link">複製連結</string>
+  <string name="empty"></string>
+  <string name="prefs_category_accounts">帳號</string>
+  <string name="saml_authentication_wrong_pass">密碼錯誤</string>
 </resources>
index 4f3299c..9104138 100644 (file)
@@ -7,27 +7,33 @@
   <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_mkdir">新資料夾</string>
   <string name="actionbar_settings">設定</string>
   <string name="actionbar_see_details">詳細資料</string>
+  <string name="actionbar_send_file">寄出</string>
   <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">App 密碼</string>
   <string name="prefs_pincode_summary">保護您的 App 用戶端</string>
-  <string name="prefs_instant_upload">啟用即時上傳</string>
-  <string name="prefs_instant_upload_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="recommend_subject">在您的手機中試用%1$s!</string>
+  <string name="recommend_text">我想邀請您在您的手機上使用 %1$s ! 可以由這兒下載: %2$s</string>
   <string name="auth_check_server">檢查伺服器</string>
-  <string name="auth_host_url">伺服器位址</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>
@@ -43,7 +49,9 @@
   <string name="uploader_wrn_no_content_text">沒接到任何內容。沒有什麼可上載。</string>
   <string name="uploader_error_forbidden_content">%1$s 並沒有被允許存取分享的內容</string>
   <string name="uploader_info_uploading">上傳中</string>
-  <string name="file_list_empty">這個目錄目前是空的</string>
+  <string name="file_list_empty">這裡還沒有東西,上傳一些吧!</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>
@@ -52,6 +60,8 @@
   <string name="filedetails_download">下載</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="delete_account">刪除帳號</string>
   <string name="create_account">建立帳號</string>
   <string name="upload_chooser_title">更新自 ...</string>
-  <string name="uploader_info_dirname">目錄名稱</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_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_failed_ticker">下載失敗</string>
   <string name="downloader_download_failed_content">下載 %1$s 未完成</string>
   <string name="downloader_not_downloaded_yet">尚未下載</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_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_fail_in_favourites_ticker">同步檔案失敗</string>
   <string name="sync_fail_in_favourites_content">%1$d 未被同步 (%2$d 衝突)</string>
   <string name="sync_foreign_files_forgotten_ticker">有些本地端的檔案已遺失</string>
-  <string name="sync_foreign_files_forgotten_content">%1$d 檔案於 %2$s 目錄未被複製</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_foreign_files_forgotten_content">%1$d 檔案超過 %2$s 資料夾可能不能複製進去</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="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_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_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">URL 不正確</string>
   <string name="auth_ssl_general_error_title">SSL 初始化失敗</string>
+  <string name="auth_ssl_unverified_server_title">無法驗證 SSL 伺服器身份</string>
   <string name="auth_bad_oc_version_title">無法辨識的伺服器版本</string>
   <string name="auth_wrong_connection_title">無法建立連線</string>
   <string name="auth_secure_connection">安全連線已建立</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">你的伺服器並沒有傳回正確的使用者 ID, 請聯絡伺服器的管理員
+       </string>
+  <string name="auth_can_not_auth_against_server">無法在這個伺服器上取得認證</string>
   <string name="fd_keep_in_sync">讓檔案保持最新的</string>
   <string name="common_rename">重新命名</string>
   <string name="common_remove">移除</string>
   <string name="rename_server_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="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_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">- 這個伺服器使用未被信任的憑證</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">placeholder.txt</string>
   <string name="placeholder_filetype">PNG 圖檔</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_video_upload_on_wifi">只透過無線網路來執行即時影像上傳的功能</string>
   <string name="instant_upload_path">/InstantUpload</string>
   <string name="conflict_title">更新衝突</string>
   <string name="conflict_message">遠端檔案 %s 未同步到本地. 繼續將取代伺服器上的文件.</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="actionbar_failed_instant_upload">即時上傳失敗</string>
-  <string name="failed_upload_headline_text">即時上傳失敗</string>
-  <string name="failed_upload_headline_hint">所有即時上傳失敗的記錄</string>
-  <string name="failed_upload_all_cb">全部選取</string>
-  <string name="failed_upload_headline_retryall_btn">重新上傳選取的檔案</string>
-  <string name="failed_upload_headline_delete_all_btn">刪除所有被選取的檔案</string>
-  <string name="failed_upload_retry_text">重新上傳這個檔案: </string>
-  <string name="failed_upload_load_more_images">載入更多的檔案</string>
-  <string name="failed_upload_retry_do_nothing_text">未連線, 所以無法使用上傳功能</string>
-  <string name="failed_upload_failure_text">失敗訊息: </string>
-  <string name="failed_upload_quota_exceeded_text">請檢查你的伺服器設定, 可能你的額度已超過.</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="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_mail_subject">ownCloud 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="file_list_empty_moving">找不到任何檔案. 你可以新增一個目錄!</string>
+  <string name="move_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>
 </resources>
index ce9b2d1..2b1fec9 100644 (file)
@@ -21,5 +21,6 @@
     
     <color name="filelist_icon_backgorund">#DDDDDD</color>
     <color name="owncloud_blue_bright">#00ddff</color>
+    <color name="list_item_lastmod_and_filesize_text">#989898</color>
     
 </resources>
\ No newline at end of file
index 226b618..6c1a67a 100644 (file)
@@ -8,17 +8,23 @@
     <string name ="db_name">ownCloud</string>
     <string name ="data_folder">owncloud</string>
     <string name ="log_name">Owncloud_</string>
+    <string name ="default_display_name_for_root_folder">ownCloud</string>
     
     <!-- URLs and flags related -->
     <string name="server_url"></string>
     <bool name="show_server_url_input">true</bool>
     <bool name="show_welcome_link">true</bool>
        <string name="welcome_link_url">"https://owncloud.com/mobile/new"</string>
+       <string name="share_api_link"></string>
     
     <!-- Flags to setup the authentication methods available in the app -->
     <string name="auth_method_oauth2">off</string>
     <string name="auth_method_saml_web_sso">off</string>
     
+    <!-- Flags to enable/disable some features -->
+    <string name = "send_files_to_other_apps">on</string>
+    
+    
     <!-- Colors -->
     <color name="login_background_color">#FFFFFF</color>
     <color name="login_logo_background_color">#FFFFFF</color>
     <bool name="multiaccount_support">true</bool>
     
     <!-- Help, imprint and feedback -->
-    <bool name="help_enabled">false</bool>
+    <bool name="help_enabled">true</bool>
     <bool name="imprint_enabled">false</bool> 
-    <bool name="recommend_enabled">false</bool>
-    <bool name="feedback_enabled">false</bool>
-    <string name="url_help">https://owncloud.com/mobile/help</string>
+    <bool name="recommend_enabled">true</bool>
+    <bool name="feedback_enabled">true</bool>
+    <string name="url_help">http://owncloud.com/mobile/help</string>
     <string name="url_imprint"></string>
     <string name="mail_recommend">"mailto:"</string>
     <string name="mail_feedback">"mailto:apps@owncloud.com"</string>
     <string name="url_app_download">"https://play.google.com/store/apps/details?id=com.owncloud.android"</string>
 
+    <!--Destination mail for sending log files -->
+    <string name="mail_logger"></string>
+
 </resources>
 
 
index 4f75db1..af5a684 100644 (file)
@@ -8,18 +8,28 @@
     <string name="actionbar_upload_from_apps">Content from other apps</string>
     <string name="actionbar_upload_files">Files</string>
     <string name="actionbar_open_with">Open with</string>
-    <string name="actionbar_mkdir">Create directory</string>
+    <string name="actionbar_mkdir">New folder</string>
     <string name="actionbar_settings">Settings</string>
     <string name="actionbar_see_details">Details</string>
-    
+    <string name="actionbar_send_file">Send</string>
+    <string name="actionbar_sort">Sort</string>
+    <string name="actionbar_sort_title">Sort by</string>
+    <string-array name="actionbar_sortby">
+       <item>A-Z</item>
+       <item>Newest - Oldest</item>
+       <!-- TODO re-enable when server-side folder size calculation is available   
+       <item>Biggest - Smallest</item>  -->
+    </string-array>
     <string name="prefs_category_general">General</string>
     <string name="prefs_category_more">More</string>
     <string name="prefs_accounts">Accounts</string>
     <string name="prefs_manage_accounts">Manage Accounts</string>
     <string name="prefs_pincode">App PIN</string>
     <string name="prefs_pincode_summary">Protect your client</string>
-    <string name="prefs_instant_upload">Enable instant uploads</string>
-    <string name="prefs_instant_upload_summary">Instantly upload photos taken by camera</string>
+    <string name="prefs_instant_upload">Instant picture uploads</string>
+    <string name="prefs_instant_upload_summary">Instantly upload pictures taken by camera</string>
+    <string name="prefs_instant_video_upload">Instant video uploads</string>
+    <string name="prefs_instant_video_upload_summary">Instantly upload videos recorded by camera</string>
     <string name="prefs_log_title">Enable Logging</string>
     <string name="prefs_log_summary">This is used to log problems</string>
     <string name="prefs_log_title_history">Logging History</string>
     <string name="prefs_imprint">Imprint</string>
     
        <string name="recommend_subject">"Try %1$s on your smartphone!"</string>
-       <string name="recommend_text">"I want to invite you to use %1$s on your smartphone!\nDownload here: %2$s"</string>  
+       <string name="recommend_text">"I want to invite you to use %1$s on your smartphone!\nDownload here: %2$s"</string>
 
     <string name="auth_check_server">Check Server</string>
-    <string name="auth_host_url">Server address</string>
+    <string name="auth_host_url">Server address https://…</string>
     <string name="auth_username">Username</string>
     <string name="auth_password">Password</string>
     <string name="auth_register">New to %1$s?</string>
     <string name="sync_string_files">Files</string>
     <string name="setup_btn_connect">Connect</string>
     <string name="uploader_btn_upload_text">Upload</string>
-    <string name="uploader_top_message">Choose upload directory:</string>
+    <string name="uploader_top_message">Choose upload folder:</string>
     <string name="uploader_wrn_no_account_title">No account found</string>
     <string name="uploader_wrn_no_account_text">There are no %1$s accounts on your device. Please setup an account first.</string>
     <string name="uploader_wrn_no_account_setup_btn_text">Setup</string>
@@ -50,7 +60,9 @@
     <string name="uploader_wrn_no_content_text">No content was received. Nothing to upload.</string>
     <string name="uploader_error_forbidden_content">%1$s is not allowed to access the shared content</string>
     <string name="uploader_info_uploading">Uploading</string>
-    <string name="file_list_empty">There are no files in this folder.\nNew files can be added with the \"Upload\" menu option.</string>
+    <string name="file_list_empty">Nothing in here. Upload something!</string>
+    <string name="file_list_loading">Loading...</string>
+    <string name="local_file_list_empty">There are no files in this folder.</string>
     <string name="filedetails_select_file">Tap on a file to display additional information.</string>
     <string name="filedetails_size">Size:</string>
     <string name="filedetails_type">Type:</string>
@@ -59,6 +71,8 @@
     <string name="filedetails_download">Download</string>
     <string name="filedetails_sync_file">Refresh file</string>
     <string name="filedetails_renamed_in_upload_msg">File was renamed to %1$s during upload</string>
+    <string name="action_share_file">Share link</string>
+    <string name="action_unshare_file">Unshare link</string>
     <string name="common_yes">Yes</string>
     <string name="common_no">No</string>
     <string name="common_ok">OK</string>
     <string name="delete_account">Delete account</string>
     <string name="create_account">Create account</string>
     <string name="upload_chooser_title">Upload from &#8230;</string>
-    <string name="uploader_info_dirname">Directory name</string>
+    <string name="uploader_info_dirname">Folder name</string>
     <string name="uploader_upload_in_progress_ticker">Uploading &#8230;</string>
     <string name="uploader_upload_in_progress_content">%1$d%% Uploading %2$s</string>
     <string name="uploader_upload_succeeded_ticker">Upload succeeded</string>
     <string name="uploader_upload_succeeded_content_single">%1$s was successfully uploaded</string>
     <string name="uploader_upload_failed_ticker">Upload failed</string>
     <string name="uploader_upload_failed_content_single">Upload of %1$s could not be completed</string>
+    <string name="uploader_upload_failed_credentials_error">Upload failed, you need to relogin</string>
     <string name="downloader_download_in_progress_ticker">Downloading &#8230;</string>
     <string name="downloader_download_in_progress_content">%1$d%% Downloading %2$s</string>
     <string name="downloader_download_succeeded_ticker">Download succeeded</string>
     <string name="downloader_download_failed_ticker">Download failed</string>
     <string name="downloader_download_failed_content">Download of %1$s could not be completed</string>
     <string name="downloader_not_downloaded_yet">Not downloaded yet</string>
+    <string name="downloader_download_failed_credentials_error">Download failed, you need to relogin</string>
     <string name="common_choose_account">Choose account</string>
     <string name="sync_fail_ticker">Synchronization failed</string>
+    <string name="sync_fail_ticker_unauthorized">Synchronization failed, you need to relogin</string>
     <string name="sync_fail_content">Synchronization of %1$s could not be completed</string>
     <string name="sync_fail_content_unauthorized">Invalid password for %1$s</string>
        <string name="sync_conflicts_in_favourites_ticker">Conflicts found</string>
     <string name="sync_fail_in_favourites_ticker">Kept-in-sync files failed</string>
     <string name="sync_fail_in_favourites_content">Contents of %1$d files could not be sync\'ed (%2$d conflicts)</string>
     <string name="sync_foreign_files_forgotten_ticker">Some local files were forgotten</string>
-    <string name="sync_foreign_files_forgotten_content">%1$d files out of the %2$s directory could not be copied into</string>
-    <string name="sync_foreign_files_forgotten_explanation">As of version 1.3.16, files uploaded from this device are copied into the local %1$s folder to prevent data loss when a single file is synced with multiple accounts.\n\nDue to this change, all files uploaded in previous versions of this app were copied into the %2$s folder. However, an error prevented the completion of this operation during account synchronization. You may either leave the file(s) as is and remove the link to %3$s, or move the file(s) into the %1$s directory and retain the link to %4$s.\n\nListed below are the local file(s), and the the remote file(s) in %5$s they were linked to.</string>
+    <string name="sync_foreign_files_forgotten_content">%1$d files out of the %2$s folder could not be copied into</string>
+    <string name="sync_foreign_files_forgotten_explanation">As of version 1.3.16, files uploaded from this device are copied into the local %1$s folder to prevent data loss when a single file is synced with multiple accounts.\n\nDue to this change, all files uploaded in previous versions of this app were copied into the %2$s folder. However, an error prevented the completion of this operation during account synchronization. You may either leave the file(s) as is and remove the link to %3$s, or move the file(s) into the %1$s folder and retain the link to %4$s.\n\nListed below are the local file(s), and the remote file(s) in %5$s they were linked to.</string>
        <string name="sync_current_folder_was_removed">Folder %1$s does not exist anymore</string>    
     <string name="foreign_files_move">"Move all"</string>
     <string name="foreign_files_success">"All files were moved"</string>
     <string name="foreign_files_fail">"Some files could not be moved"</string>
     <string name="foreign_files_local_text">"Local: %1$s"</string>
     <string name="foreign_files_remote_text">"Remote: %1$s"</string>
-    <string name="upload_query_move_foreign_files">There is not space enough to copy the selected files into the %1$s folder. Would like to move them into instead? </string>
+    <string name="upload_query_move_foreign_files">There is not space enough to copy the selected files into the %1$s folder. Would you like to move them instead? </string>
     <string name="pincode_enter_pin_code">Please, insert your App PIN</string>
+    
     <string name="pincode_configure_your_pin">Enter your App PIN</string>
     <string name="pincode_configure_your_pin_explanation">The PIN will be requested every time the app is started</string>
     <string name="pincode_reenter_your_pincode">Please, reenter your App PIN</string>
     <string name="media_event_done">"%1$s playback finished"</string>
     <string name="media_err_nothing_to_play">No media file found</string>
        <string name="media_err_no_account">No account provided</string>
-    <string name="media_err_not_in_owncloud">File not in a valid account</string>
-    <string name="media_err_unsupported">Unsupported media codec</string>
-    <string name="media_err_io">Media file could not be read</string>
-    <string name="media_err_malformed">Media file not correctly encoded</string>
-    <string name="media_err_timeout">Timed out while trying to play</string>
-    <string name="media_err_invalid_progressive_playback">Media file cannot be streamed</string>
-    <string name="media_err_unknown">Media file cannot be played with the stock media player</string>
-    <string name="media_err_security_ex">Security error trying to play %1$s</string>
+       <string name="media_err_not_in_owncloud">File not in a valid account</string>
+       <string name="media_err_unsupported">Unsupported media codec</string>
+       <string name="media_err_io">Media file could not be read</string>
+       <string name="media_err_malformed">Media file not correctly encoded</string>
+       <string name="media_err_timeout">Timed out while trying to play</string>
+       <string name="media_err_invalid_progressive_playback">Media file cannot be streamed</string>
+       <string name="media_err_unknown">Media file cannot be played with the stock media player</string>
+       <string name="media_err_security_ex">Security error trying to play %1$s</string>
        <string name="media_err_io_ex">Input error trying to play %1$s</string>
        <string name="media_err_unexpected">Unexpected error trying to play %1$s</string>
        <string name="media_rewind_description">Rewind button</string>
        <string name="media_play_pause_description">Play or pause button</string>
        <string name="media_forward_description">Fast forward button</string>
 
-    <string name="auth_trying_to_login">Trying to login&#8230;</string>
-    <string name="auth_no_net_conn_title">No network connection</string>
-    <string name="auth_nossl_plain_ok_title">Secure connection unavailable.</string>
-    <string name="auth_connection_established">Connection established</string>
-    <string name="auth_testing_connection">Testing connection&#8230;</string>
-    <string name="auth_not_configured_title">Malformed server configuration</string>
-    <string name="auth_account_not_new">An account for the same user and server already exists in the device</string>
-    <string name="auth_account_not_the_same">The entered user does not match the user of this account</string>
-    <string name="auth_unknown_error_title">Unknown error occurred!</string>
-    <string name="auth_unknown_host_title">Couldn\'t find host</string>
-    <string name="auth_incorrect_path_title">Server instance not found</string>
-    <string name="auth_timeout_title">The server took too long to respond</string>
-    <string name="auth_incorrect_address_title">Malformed URL</string>
-    <string name="auth_ssl_general_error_title">SSL initialization failed</string>
-    <string name="auth_ssl_unverified_server_title">Couldn\'t verify SSL server\'s identity</string>
-    <string name="auth_bad_oc_version_title">Unrecognized server version</string>
-    <string name="auth_wrong_connection_title">Couldn\'t establish connection</string>
-    <string name="auth_secure_connection">Secure connection established</string>
-    <string name="auth_unauthorized">Wrong username or password</string>
+       <string name="auth_getting_authorization">Getting authorization&#8230;</string>
+       <string name="auth_trying_to_login">Trying to login&#8230;</string>
+       <string name="auth_no_net_conn_title">No network connection</string>
+       <string name="auth_nossl_plain_ok_title">Secure connection unavailable.</string>
+       <string name="auth_connection_established">Connection established</string>
+       <string name="auth_testing_connection">Testing connection&#8230;</string>
+       <string name="auth_not_configured_title">Malformed server configuration</string>
+       <string name="auth_account_not_new">An account for the same user and server already exists in the device</string>
+       <string name="auth_account_not_the_same">The entered user does not match the user of this account</string>
+       <string name="auth_unknown_error_title">Unknown error occurred!</string>
+       <string name="auth_unknown_host_title">Couldn\'t find host</string>
+       <string name="auth_incorrect_path_title">Server instance not found</string>
+       <string name="auth_timeout_title">The server took too long to respond</string>
+       <string name="auth_incorrect_address_title">Malformed URL</string>
+       <string name="auth_ssl_general_error_title">SSL initialization failed</string>
+       <string name="auth_ssl_unverified_server_title">Couldn\'t verify SSL server\'s identity</string>
+       <string name="auth_bad_oc_version_title">Unrecognized server version</string>
+       <string name="auth_wrong_connection_title">Couldn\'t establish connection</string>
+       <string name="auth_secure_connection">Secure connection established</string>
+       <string name="auth_unauthorized">Wrong username or password</string>
        <string name="auth_oauth_error">Unsuccessful authorization</string>
        <string name="auth_oauth_error_access_denied">Access denied by authorization server</string>
-    <string name="auth_wtf_reenter_URL">Unexpected state; please, enter the server URL again</string>
-    <string name="auth_expired_oauth_token_toast">Your authorization expired. Please, authorize again</string>
-    <string name="auth_expired_basic_auth_toast">Please, enter the current password</string>
-    <string name="auth_expired_saml_sso_token_toast">Your session expired. Please connect again</string>
+       <string name="auth_wtf_reenter_URL">Unexpected state; please, enter the server URL again</string>
+       <string name="auth_expired_oauth_token_toast">Your authorization expired. Please, authorize again</string>
+       <string name="auth_expired_basic_auth_toast">Please, enter the current password</string>
+       <string name="auth_expired_saml_sso_token_toast">Your session expired. Please connect again</string>
        <string name="auth_connecting_auth_server">Connecting to authentication server…</string>
-       <string name="auth_unsupported_auth_method">The server does not support this authentication method</string>    
+       <string name="auth_unsupported_auth_method">The server does not support this authentication method</string>
        <string name="auth_unsupported_multiaccount">%1$s does not support multiple accounts</string>
+       <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="fd_keep_in_sync">Keep file up to date</string>
     <string name="common_rename">Rename</string>
     <string name="common_remove">Remove</string>
-    <string name="confirmation_remove_alert">"Do you really want to remove %1$s ?"</string>
-    <string name="confirmation_remove_folder_alert">"Do you really want to remove %1$s and its contents ?"</string>
+    <string name="confirmation_remove_alert">"Do you really want to remove %1$s?"</string>
+    <string name="confirmation_remove_folder_alert">"Do you really want to remove %1$s and its contents?"</string>
     <string name="confirmation_remove_local">Local only</string>
     <string name="confirmation_remove_folder_local">Local contents only</string>
     <string name="confirmation_remove_remote">Remove from server</string>
     <string name="rename_server_fail_msg">"Rename could not be completed"</string>
     <string name="sync_file_fail_msg">Remote file could not be checked</string>
     <string name="sync_file_nothing_to_do_msg">File contents already synchronized</string>
-    <string name="create_dir_fail_msg">Directory could not be created</string>
+    <string name="create_dir_fail_msg">Folder could not be created</string>
+    <string name="filename_forbidden_characters">Forbidden characters: / \\ &lt; &gt; : " | ? *</string>
+    <string name="filename_empty">File name cannot be empty</string>
     <string name="wait_a_moment">Wait a moment</string>
     <string name="filedisplay_unexpected_bad_get_content">"Unexpected problem ; please select the file from a different app"</string>
     <string name="filedisplay_no_file_selected">No file was selected</string>
+    <string name="activity_chooser_title">Send link to &#8230;</string>
     
     <string name="oauth_check_onoff">Login with oAuth2</string> 
     <string name="oauth_login_connection">Connecting to oAuth2 server…</string>    
        <string name="ssl_validator_label_validity_to">To:</string>
        <string name="ssl_validator_label_signature">Signature:</string>
        <string name="ssl_validator_label_signature_algorithm">Algorithm:</string>
+       <string name="ssl_validator_null_cert">The certificate could not be shown.</string>
+       <string name="ssl_validator_no_info_about_error">- No information about the error</string>
                        
     <string name="placeholder_sentence">This is a placeholder</string>
     <string name="placeholder_filename">placeholder.txt</string>
     <string name="placeholder_media_time">12:23:45</string>
     
     <string name="instant_upload_on_wifi">Upload pictures via WiFi only</string>
+    <string name="instant_video_upload_on_wifi">Upload videos via WiFi only</string>
     <string name="instant_upload_path">/InstantUpload</string>
     <string name="conflict_title">Update conflict</string>
     <string name="conflict_message">Remote file %s is not synchronized with local file. Continuing will replace content of file on server.</string>
     <string name="conflict_dont_upload">Don\'t upload</string>
     
     <string name="preview_image_description">Image preview</string>
-    <string name="preview_image_error_unknown_format">This image can not be shown</string>
+    <string name="preview_image_error_unknown_format">This image cannot be shown</string>
     
-    <string name="error__upload__local_file_not_copied">%1$s could not be copied to %2$s local directory</string>
-    <string name="actionbar_failed_instant_upload">Failed InstantUpload"</string>
-    <string name="failed_upload_headline_text">Failed instant uploads</string>
-    <string name="failed_upload_headline_hint">Summary of all failed instant uploads</string>
-    <string name="failed_upload_all_cb">select all</string>
-    <string name="failed_upload_headline_retryall_btn">retry all selected</string>
-    <string name="failed_upload_headline_delete_all_btn">delete all  selected from uploadqueue</string>
-    <string name="failed_upload_retry_text">retry to upload the image: </string>
-    <string name="failed_upload_load_more_images">Load more Picrures</string>
-    <string name="failed_upload_retry_do_nothing_text">do nothing you are not online for instant upload</string>
-       <string name="failed_upload_failure_text">Failure Message: </string>
-       <string name="failed_upload_quota_exceeded_text">Please check your server configuration,maybe your quota is exceeded.</string>
+    <string name="error__upload__local_file_not_copied">%1$s could not be copied to %2$s local folder</string>
+    <string name="prefs_instant_upload_path_title">Upload Path</string>
+
+       <string name="share_link_no_support_share_api">Sorry, sharing is not enabled on your server. Please contact your
+               administrator.</string>
+       <string name="share_link_file_no_exist">Unable to share. Please check whether the file exists</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="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="error_cant_bind_to_operations_service">Critical error: cannot perform operations</string>
+       
+       <string name="network_error_socket_exception">An error occurred while connecting with the server.</string>
+       <string name="network_error_socket_timeout_exception">An error occurred while waiting for the server, the operation couldn\'t have been done</string>
+       <string name="network_error_connect_timeout_exception">An error occurred while waiting for the server, the operation couldn\'t have been done</string>
+       <string name="network_host_not_available">The operation couldn\'t be completed, server is unavailable</string>
+       <string name="empty"></string>
+       
+       <string name="forbidden_permissions">You do not have permission %s</string>
+       <string name="forbidden_permissions_rename">to rename this file</string>
+       <string name="forbidden_permissions_delete">to delete this file</string>
+       <string name="share_link_forbidden_permissions">to share this file</string>
+       <string name="unshare_link_forbidden_permissions">to unshare this file</string>
+       <string name="forbidden_permissions_create">to create the file</string>
+       <string name="uploader_upload_forbidden_permissions">to upload in this folder</string>
+       <string name="downloader_download_file_not_found">The file is no longer available on the server</string>
+
+       <string name="prefs_category_accounts">Accounts</string>
+       <string name="prefs_add_account">Add account</string>
+       <string name="auth_redirect_non_secure_connection_title">Secure connection is redirected to an unsecured route.</string>
+
+       <string name="actionbar_logger">Logs</string>
+       <string name="log_send_history_button">Send History</string>
+       <string name="log_mail_subject">ownCloud Android app logs</string>
+       <string name="log_progress_dialog_text">Loading data...</string>
+
+       <string name="saml_authentication_required_text">Authentication required</string>
+       <string name="saml_authentication_wrong_pass">Wrong password</string>
+       <string name="actionbar_move">Move</string>
+       <string name="file_list_empty_moving">Nothing in here. You can add a folder!</string>
+       <string name="move_choose_button_text">Choose</string>
+
+       <string name="move_file_not_found">Unable to move. Please check whether the file exists</string>
+       <string name="move_file_invalid_into_descendent">It is not possible to move a folder into a descendant</string>
+       <string name="move_file_invalid_overwrite">The file exists already in the destination folder</string>
+       <string name="move_file_error">An error occurred while trying to move this file or folder</string>
+       <string name="forbidden_permissions_move">to move this file</string>
+
+       <string name="prefs_category_instant_uploading">Instant Uploads</string>
+       <string name="prefs_category_security">Security</string>
+
 </resources>
index 034ca5c..c65cbad 100644 (file)
@@ -59,7 +59,7 @@
        </style>
 
        <!-- Dialogs -->
-       <style name="Theme.ownCloud.Dialog" parent="style/Theme.Sherlock.Light.Dialog">
+       <style name="Theme.ownCloud.Dialog" parent="@android:style/Theme.Dialog">
        </style>
        
        <!-- PopDownMenu -->
index cd6c1f5..5faa6b2 100644 (file)
            <item name="android:indeterminateDrawable">@drawable/abs__progress_medium_holo</item>
        </style>
 
+       <!-- Notifications -->
+       <style  name="Theme.ownCloud.NotificationText.Title" 
+               parent="@android:style/TextAppearance">
+        <item name="android:textColor">#ff000000</item>
+               <item name="android:textSize">18sp</item>
+        <item name="android:textStyle">bold</item>
+       </style>
+       <style  name="Theme.ownCloud.NotificationText.Content" 
+               parent="@android:style/TextAppearance">
+        <item name="android:textColor">#ff000000</item>
+               <item name="android:textSize">14sp</item>
+       </style>
 </resources>
index a7f76f5..3b8b3e8 100644 (file)
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 -->
 <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >
-       <PreferenceCategory android:title="@string/prefs_category_general">
+    <PreferenceCategory android:title="@string/prefs_category_accounts" android:key="accounts_category">
+    </PreferenceCategory>
     
-    <!-- ListPreference
-        android:key="select_oc_account"
-        android:title="@string/prefs_select_oc_account"
-        android:summary="@string/prefs_summary_select_oc_account" 
-        / -->
-    <Preference android:title="@string/prefs_manage_accounts" android:key="manage_account" />
-    <CheckBoxPreference android:title="@string/prefs_pincode" android:key="set_pincode" 
+       <PreferenceCategory android:title="@string/prefs_category_security">
+           <!-- ListPreference
+               android:key="select_oc_account"
+               android:title="@string/prefs_select_oc_account"
+               android:summary="@string/prefs_summary_select_oc_account"
+               / -->
+           <com.owncloud.android.ui.CheckBoxPreferenceWithLongTitle android:title="@string/prefs_pincode" android:key="set_pincode" 
                         android:summary="@string/prefs_pincode_summary"/>
-    <CheckBoxPreference android:key="instant_uploading" 
-                        android:title="@string/prefs_instant_upload"  
-                        android:summary="@string/prefs_instant_upload_summary"/>
-    <CheckBoxPreference android:dependency="instant_uploading" 
-                                       android:disableDependentsState="true" 
-                                       android:title="@string/instant_upload_on_wifi" 
-                                       android:key="instant_upload_on_wifi"/>
-    <!-- DISABLED FOR RELEASE UNTIL FIXED 
-    CheckBoxPreference android:key="log_to_file" 
-                        android:title="@string/prefs_log_title"  
-                        android:summary="@string/prefs_log_summary"/>
-       <Preference             android:key="log_history" 
-                        android:title="@string/prefs_log_title_history"  
-                        android:summary="@string/prefs_log_summary_history"/ -->
+       </PreferenceCategory>
+
+    <PreferenceCategory android:title="@string/prefs_category_instant_uploading">
+           <EditTextPreference android:title="@string/prefs_instant_upload_path_title"
+                                               android:defaultValue="@string/instant_upload_path"
+                                               android:key="instant_upload_path"/>
+           <com.owncloud.android.ui.CheckBoxPreferenceWithLongTitle android:key="instant_uploading"
+                               android:title="@string/prefs_instant_upload"
+                               android:summary="@string/prefs_instant_upload_summary"/>
+           <com.owncloud.android.ui.CheckBoxPreferenceWithLongTitle android:dependency="instant_uploading"
+                                               android:disableDependentsState="true"
+                                               android:title="@string/instant_upload_on_wifi"
+                                               android:key="instant_upload_on_wifi"/>
+           <com.owncloud.android.ui.CheckBoxPreferenceWithLongTitle android:key="instant_video_uploading"
+                               android:title="@string/prefs_instant_video_upload"
+                               android:summary="@string/prefs_instant_video_upload_summary"/>
+           <com.owncloud.android.ui.CheckBoxPreferenceWithLongTitle android:dependency="instant_video_uploading"
+                                               android:disableDependentsState="true"
+                                               android:title="@string/instant_video_upload_on_wifi"
+                                               android:key="instant_video_upload_on_wifi"/>
+           <!-- DISABLED FOR RELEASE UNTIL FIXED
+           CheckBoxPreference android:key="log_to_file"
+                               android:title="@string/prefs_log_title"
+                               android:summary="@string/prefs_log_summary"/>
+               <Preference             android:key="log_history"
+                               android:title="@string/prefs_log_title_history"
+                               android:summary="@string/prefs_log_summary_history"/ -->
                         
     </PreferenceCategory>
        
@@ -57,4 +71,4 @@
        </PreferenceCategory>
     
 
-</PreferenceScreen>
\ No newline at end of file
+</PreferenceScreen>
index 265ff59..dc44a12 100644 (file)
@@ -1,6 +1,7 @@
 call git submodule init
 call git submodule update
 call android.bat update project -p actionbarsherlock\library -n ActionBarSherlock
+call android.bat update lib-project -p owncloud-android-library
 call android.bat update project -p .
 call android.bat update project -p oc_jb_workaround
 copy /Y third_party\android-support-library\android-support-v4.jar actionbarsherlock\library\libs\android-support-v4.jar
index d18ce22..ae42142 100755 (executable)
@@ -1,8 +1,9 @@
-#!/bin/bash
+#!/bin/bash -e
 
 git submodule init
 git submodule update
 android update project -p actionbarsherlock/library -n ActionBarSherlock
+android update lib-project -p owncloud-android-library
 android update project -p .
 android update project -p oc_jb_workaround
 cp third_party/android-support-library/android-support-v4.jar actionbarsherlock/library/libs/android-support-v4.jar 
diff --git a/src/com/owncloud/android/DisplayUtils.java b/src/com/owncloud/android/DisplayUtils.java
deleted file mode 100644 (file)
index 1ee898b..0000000
+++ /dev/null
@@ -1,190 +0,0 @@
-/* ownCloud Android client application\r
- *   Copyright (C) 2011  Bartek Przybylski\r
- *   Copyright (C) 2012-2013 ownCloud Inc.\r
- *\r
- *   This program is free software: you can redistribute it and/or modify\r
- *   it under the terms of the GNU General Public License version 2,\r
- *   as published by the Free Software Foundation.\r
- *\r
- *   This program is distributed in the hope that it will be useful,\r
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
- *   GNU General Public License for more details.\r
- *\r
- *   You should have received a copy of the GNU General Public License\r
- *   along with this program.  If not, see <http://www.gnu.org/licenses/>.\r
- *\r
- */\r
-\r
-package com.owncloud.android;\r
-\r
-import java.util.Arrays;\r
-import java.util.Date;\r
-import java.util.HashMap;\r
-import java.util.HashSet;\r
-import java.util.Set;\r
-\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
-    //private static String TAG = DisplayUtils.class.getSimpleName(); \r
-    \r
-    private static final String[] sizeSuffixes = { "B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" };\r
-\r
-    private static HashMap<String, String> mimeType2HUmanReadable;\r
-    static {\r
-        mimeType2HUmanReadable = new HashMap<String, String>();\r
-        // images\r
-        mimeType2HUmanReadable.put("image/jpeg", "JPEG image");\r
-        mimeType2HUmanReadable.put("image/jpg", "JPEG image");\r
-        mimeType2HUmanReadable.put("image/png", "PNG image");\r
-        mimeType2HUmanReadable.put("image/bmp", "Bitmap image");\r
-        mimeType2HUmanReadable.put("image/gif", "GIF image");\r
-        mimeType2HUmanReadable.put("image/svg+xml", "JPEG image");\r
-        mimeType2HUmanReadable.put("image/tiff", "TIFF image");\r
-        // music\r
-        mimeType2HUmanReadable.put("audio/mpeg", "MP3 music file");\r
-        mimeType2HUmanReadable.put("application/ogg", "OGG music file");\r
-\r
-    }\r
-\r
-    private static final String TYPE_APPLICATION = "application";\r
-    private static final String TYPE_AUDIO = "audio";\r
-    private static final String TYPE_IMAGE = "image";\r
-    private static final String TYPE_TXT = "text";\r
-    private static final String TYPE_VIDEO = "video";\r
-    \r
-    private static final String SUBTYPE_PDF = "pdf";\r
-    private static final String[] SUBTYPES_DOCUMENT = { "msword", "mspowerpoint", "msexcel", \r
-                                                        "vnd.oasis.opendocument.presentation",\r
-                                                        "vnd.oasis.opendocument.spreadsheet",\r
-                                                        "vnd.oasis.opendocument.text"\r
-                                                        };\r
-    private static Set<String> SUBTYPES_DOCUMENT_SET = new HashSet<String>(Arrays.asList(SUBTYPES_DOCUMENT));\r
-    private static final String[] SUBTYPES_COMPRESSED = {"x-tar", "x-gzip", "zip"};\r
-    private static final Set<String> SUBTYPES_COMPRESSED_SET = new HashSet<String>(Arrays.asList(SUBTYPES_COMPRESSED));\r
-    \r
-    /**\r
-     * Converts the file size in bytes to human readable output.\r
-     * \r
-     * @param bytes Input file size\r
-     * @return Like something readable like "12 MB"\r
-     */\r
-    public static String bytesToHumanReadable(long bytes) {\r
-        double result = bytes;\r
-        int attachedsuff = 0;\r
-        while (result > 1024 && attachedsuff < sizeSuffixes.length) {\r
-            result /= 1024.;\r
-            attachedsuff++;\r
-        }\r
-        result = ((int) (result * 100)) / 100.;\r
-        return result + " " + sizeSuffixes[attachedsuff];\r
-    }\r
-\r
-    /**\r
-     * Removes special HTML entities from a string\r
-     * \r
-     * @param s Input string\r
-     * @return A cleaned version of the string\r
-     */\r
-    public static String HtmlDecode(String s) {\r
-        /*\r
-         * TODO: Perhaps we should use something more proven like:\r
-         * http://commons.apache.org/lang/api-2.6/org/apache/commons/lang/StringEscapeUtils.html#unescapeHtml%28java.lang.String%29\r
-         */\r
-\r
-        String ret = "";\r
-        for (int i = 0; i < s.length(); ++i) {\r
-            if (s.charAt(i) == '%') {\r
-                ret += (char) Integer.parseInt(s.substring(i + 1, i + 3), 16);\r
-                i += 2;\r
-            } else {\r
-                ret += s.charAt(i);\r
-            }\r
-        }\r
-        return ret;\r
-    }\r
-\r
-    /**\r
-     * Converts MIME types like "image/jpg" to more end user friendly output\r
-     * like "JPG image".\r
-     * \r
-     * @param mimetype MIME type to convert\r
-     * @return A human friendly version of the MIME type\r
-     */\r
-    public static String convertMIMEtoPrettyPrint(String mimetype) {\r
-        if (mimeType2HUmanReadable.containsKey(mimetype)) {\r
-            return mimeType2HUmanReadable.get(mimetype);\r
-        }\r
-        if (mimetype.split("/").length >= 2)\r
-            return mimetype.split("/")[1].toUpperCase() + " file";\r
-        return "Unknown type";\r
-    }\r
-    \r
-    \r
-    /**\r
-     * Returns the resource identifier of an image resource to use as icon associated to a \r
-     * known MIME type.\r
-     * \r
-     * @param mimetype      MIME type string.\r
-     * @return              Resource identifier of an image resource.\r
-     */\r
-    public static int getResourceId(String mimetype) {\r
-\r
-        if (mimetype == null || "DIR".equals(mimetype)) {\r
-            return R.drawable.ic_menu_archive;\r
-            \r
-        } else {\r
-            String [] parts = mimetype.split("/");\r
-            String type = parts[0];\r
-            String subtype = (parts.length > 1) ? parts[1] : "";\r
-            \r
-            if(TYPE_TXT.equals(type)) {\r
-                return R.drawable.file_doc;\r
-    \r
-            } else if(TYPE_IMAGE.equals(type)) {\r
-                return R.drawable.file_image;\r
-                \r
-            } else if(TYPE_VIDEO.equals(type)) {\r
-                return R.drawable.file_movie;\r
-                \r
-            } else if(TYPE_AUDIO.equals(type)) {  \r
-                return R.drawable.file_sound;\r
-                \r
-            } else if(TYPE_APPLICATION.equals(type)) {\r
-                \r
-                if (SUBTYPE_PDF.equals(subtype)) {\r
-                    return R.drawable.file_pdf;\r
-                    \r
-                } else if (SUBTYPES_DOCUMENT_SET.contains(subtype)) {\r
-                    return R.drawable.file_doc;\r
-\r
-                } else if (SUBTYPES_COMPRESSED_SET.contains(subtype)) {\r
-                    return R.drawable.file_zip;\r
-                }\r
-    \r
-            }\r
-            // problems: RAR, RTF, 3GP are send as application/octet-stream from the server ; extension in the filename should be explicitly reviewed\r
-        }\r
-\r
-        // default icon\r
-        return R.drawable.file;\r
-    }\r
-\r
-    \r
-\r
-    /**\r
-     * Converts Unix time to human readable format\r
-     * @param miliseconds 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
-        Date date = new Date(milliseconds);\r
-        return date.toLocaleString();\r
-    }\r
-}\r
diff --git a/src/com/owncloud/android/Log_OC.java b/src/com/owncloud/android/Log_OC.java
deleted file mode 100644 (file)
index 5a1be29..0000000
+++ /dev/null
@@ -1,127 +0,0 @@
-package com.owncloud.android;
-
-import java.io.BufferedWriter;
-import java.io.File;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.Locale;
-
-import android.util.Log;
-
-
-
-public class Log_OC {
-    
-
-    private static boolean isEnabled = false;
-    private static File logFile;
-    private static File folder;
-    private static BufferedWriter buf;  
-    
-    public static void i(String TAG, String message){
-        // Printing the message to LogCat console
-        Log.i(TAG, message);
-        // Write the log message to the file
-        appendLog(TAG+" : "+message);
-    }
-
-    public static void d(String TAG, String message){
-        Log.d(TAG, message);
-        appendLog(TAG + " : " + message);
-    }
-    public static void d(String TAG, String message, Exception e) {
-        Log.d(TAG, message, e);
-        appendLog(TAG + " : " + message + " Exception : "+ e.getStackTrace());
-    }
-    public static void e(String TAG, String message){
-        Log.e(TAG, message);
-        appendLog(TAG + " : " + message);
-    }
-    
-    public static void e(String TAG, String message, Throwable e) {
-        Log.e(TAG, message, e);
-        appendLog(TAG+" : " + message +" Exception : " + e.getStackTrace());
-    }
-    
-    public static void v(String TAG, String message){
-        Log.v(TAG, message);
-        appendLog(TAG+" : "+ message);
-    }
-    
-    public static void w(String TAG, String message) {
-        Log.w(TAG,message); 
-        appendLog(TAG+" : "+ message);
-    }
-    
-    public static void wtf(String TAG, String message) {
-        Log.wtf(TAG,message); 
-        appendLog(TAG+" : "+ message);
-    }
-    
-    public static void startLogging(String logPath) {
-        folder = new File(logPath);
-        logFile = new File(folder + File.separator + "log.txt");
-        
-        if (!folder.exists()) {
-            folder.mkdirs();
-        }
-        if (logFile.exists()) {
-            logFile.delete();
-        }
-        try { 
-            logFile.createNewFile();
-            buf = new BufferedWriter(new FileWriter(logFile, true));
-            isEnabled = true;
-            appendPhoneInfo();
-        }catch (IOException e){ 
-            e.printStackTrace(); 
-        } 
-    }
-    
-    public static void stopLogging() {
-        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault());
-        String currentDateandTime = sdf.format(new Date());
-        if (logFile != null) {
-            logFile.renameTo(new File(folder + File.separator + MainApp.getLogName() + currentDateandTime+".log"));
-          
-            isEnabled = false;
-            try {
-                buf.close();
-            } catch (IOException e) {
-                e.printStackTrace();
-            } 
-        
-        }
-        
-    }
-    
-    private static void appendPhoneInfo() {
-        appendLog("Model : " + android.os.Build.MODEL);
-        appendLog("Brand : " + android.os.Build.BRAND);
-        appendLog("Product : " + android.os.Build.PRODUCT);
-        appendLog("Device : " + android.os.Build.DEVICE);
-        appendLog("Version-Codename : " + android.os.Build.VERSION.CODENAME);
-        appendLog("Version-Release : " + android.os.Build.VERSION.RELEASE);
-    }
-    
-    private static void appendLog(String text) { 
-        if (isEnabled) {
-           try { 
-               buf.append(text); 
-               buf.newLine(); 
-           } catch (IOException e) { 
-               e.printStackTrace(); 
-        } 
-    }
-}
-
-    
-   
-
-  
-
-   
-   
-}
index 6cd88fe..e04239d 100644 (file)
@@ -18,20 +18,57 @@ package com.owncloud.android;
 
 import android.app.Application;
 import android.content.Context;
+
+import com.owncloud.android.datamodel.ThumbnailsCacheManager;
+import com.owncloud.android.lib.common.OwnCloudClientManagerFactory;
+import com.owncloud.android.lib.common.OwnCloudClientManagerFactory.Policy;
+import com.owncloud.android.lib.common.utils.Log_OC;
 /**
  * Main Application of the project
  * 
- * Contains methods to build the "static" strings. These strings were before constants in different classes
+ * 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 {
+    
+    private static final String AUTH_ON = "on";
+    
+    @SuppressWarnings("unused")
+    private static final String POLICY_SINGLE_SESSION_PER_ACCOUNT = "single session per account";
+    @SuppressWarnings("unused")
+    private static final String POLICY_ALWAYS_NEW_CLIENT = "always new client";
 
     private static Context mContext;
-
+    
     public void onCreate(){
         super.onCreate();
         MainApp.mContext = getApplicationContext();
+        
+        boolean isSamlAuth = AUTH_ON.equals(getString(R.string.auth_method_saml_web_sso));
+        
+        if (isSamlAuth) {   
+            OwnCloudClientManagerFactory.setDefaultPolicy(Policy.SINGLE_SESSION_PER_ACCOUNT);
+            
+        } else {
+            OwnCloudClientManagerFactory.setDefaultPolicy(Policy.ALWAYS_NEW_CLIENT);
+        }
+        
+        // initialise thumbnails cache on background thread
+        new ThumbnailsCacheManager.InitDiskCacheTask().execute();
+        
+        if (BuildConfig.DEBUG) {
+
+            String dataFolder = getDataFolder();
+
+            // Set folder for store logs
+            Log_OC.setLogDataFolder(dataFolder);
+
+            Log_OC.startLogging();
+            Log_OC.d("Debug", "start logging");
+        }
     }
 
     public static Context getAppContext() {
@@ -44,7 +81,7 @@ public class MainApp extends Application {
     public static String getAccountType() {
         return getAppContext().getResources().getString(R.string.account_type);
     }
-    
+
     //  From AccountAuthenticator 
     //  public static final String AUTHORITY = "org.owncloud";
     public static String getAuthority() {
@@ -57,30 +94,6 @@ public class MainApp extends Application {
         return getAppContext().getResources().getString(R.string.authority);
     }
     
-    //  From AccountAuthenticator
-    //  public static final String AUTH_TOKEN_TYPE_PASSWORD = "owncloud.password";
-    public static String getAuthTokenTypePass() {
-        return getAppContext().getResources().getString(R.string.account_type) + ".password";
-    }
-    
-    //  From AccountAuthenticator
-    //  public static final String AUTH_TOKEN_TYPE_ACCESS_TOKEN = "owncloud.oauth2.access_token";
-    public static String getAuthTokenTypeAccessToken() {
-        return getAppContext().getResources().getString(R.string.account_type) + ".oauth2.access_token";
-    }
-    
-    //  From AccountAuthenticator
-    //  public static final String AUTH_TOKEN_TYPE_REFRESH_TOKEN = "owncloud.oauth2.refresh_token";
-    public static String getAuthTokenTypeRefreshToken() {
-        return getAppContext().getResources().getString(R.string.account_type) + ".oauth2.refresh_token";
-    }
-    
-    //  From AccountAuthenticator
-    //  public static final String AUTH_TOKEN_TYPE_SAML_WEB_SSO_SESSION_COOKIE = "owncloud.saml.web_sso.session_cookie";
-    public static String getAuthTokenTypeSamlSessionCookie() {
-        return getAppContext().getResources().getString(R.string.account_type) +  ".saml.web_sso.session_cookie";
-    }
-    
     //  From ProviderMeta 
     //  public static final String DB_FILE = "owncloud.db";
     public static String getDBFile() {
@@ -102,4 +115,5 @@ public class MainApp extends Application {
     public static String getLogName() {
         return getAppContext().getResources().getString(R.string.log_name);
     }
+
 }
diff --git a/src/com/owncloud/android/OwnCloudSession.java b/src/com/owncloud/android/OwnCloudSession.java
deleted file mode 100644 (file)
index d7bb609..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-/* ownCloud Android client application\r
- *   Copyright (C) 2011  Bartek Przybylski\r
- *   Copyright (C) 2012-2013 ownCloud Inc.\r
- *\r
- *   This program is free software: you can redistribute it and/or modify\r
- *   it under the terms of the GNU General Public License version 2,\r
- *   as published by the Free Software Foundation.\r
- *\r
- *   This program is distributed in the hope that it will be useful,\r
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
- *   GNU General Public License for more details.\r
- *\r
- *   You should have received a copy of the GNU General Public License\r
- *   along with this program.  If not, see <http://www.gnu.org/licenses/>.\r
- *\r
- */\r
-package com.owncloud.android;\r
-\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
-    private String mSessionUrl;\r
-    private int mEntryId;\r
-\r
-    public OwnCloudSession(String name, String url, int entryId) {\r
-        mSessionName = name;\r
-        mSessionUrl = url;\r
-        mEntryId = entryId;\r
-    }\r
-\r
-    public void setName(String name) {\r
-        mSessionName = name;\r
-    }\r
-\r
-    public String getName() {\r
-        return mSessionName;\r
-    }\r
-\r
-    public void setUrl(String url) {\r
-        mSessionUrl = url;\r
-    }\r
-\r
-    public String getUrl() {\r
-        return mSessionUrl;\r
-    }\r
-\r
-    public int getEntryId() {\r
-        return mEntryId;\r
-    }\r
-}\r
diff --git a/src/com/owncloud/android/Uploader.java b/src/com/owncloud/android/Uploader.java
deleted file mode 100644 (file)
index 29a4d6a..0000000
+++ /dev/null
@@ -1,427 +0,0 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012  Bartek Przybylski
- *   Copyright (C) 2012-2013 ownCloud Inc.
- *
- *   This program is free software: you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License version 2,
- *   as published by the Free Software Foundation.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-package com.owncloud.android;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Stack;
-import java.util.Vector;
-
-import com.owncloud.android.R;
-import com.owncloud.android.authentication.AccountAuthenticator;
-import com.owncloud.android.datamodel.FileDataStorageManager;
-import com.owncloud.android.datamodel.OCFile;
-import com.owncloud.android.files.services.FileUploader;
-
-import android.accounts.Account;
-import android.accounts.AccountManager;
-import android.app.AlertDialog;
-import android.app.AlertDialog.Builder;
-import android.app.Dialog;
-import android.app.ListActivity;
-import android.app.ProgressDialog;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.DialogInterface.OnCancelListener;
-import android.content.DialogInterface.OnClickListener;
-import android.content.Intent;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.Parcelable;
-import android.provider.MediaStore.Audio;
-import android.provider.MediaStore.Images;
-import android.provider.MediaStore.Video;
-import android.view.View;
-import android.view.Window;
-import android.widget.AdapterView;
-import android.widget.AdapterView.OnItemClickListener;
-import android.widget.Button;
-import android.widget.EditText;
-import android.widget.SimpleAdapter;
-import android.widget.Toast;
-
-
-/**
- * This can be used to upload things to an ownCloud instance.
- * 
- * @author Bartek Przybylski
- * 
- */
-public class Uploader extends ListActivity implements OnItemClickListener, android.view.View.OnClickListener {
-    private static final String TAG = "ownCloudUploader";
-
-    private Account mAccount;
-    private AccountManager mAccountManager;
-    private Stack<String> mParents;
-    private ArrayList<Parcelable> mStreamsToUpload;
-    private boolean mCreateDir;
-    private String mUploadPath;
-    private FileDataStorageManager mStorageManager;
-    private OCFile mFile;
-
-    private final static int DIALOG_NO_ACCOUNT = 0;
-    private final static int DIALOG_WAITING = 1;
-    private final static int DIALOG_NO_STREAM = 2;
-    private final static int DIALOG_MULTIPLE_ACCOUNT = 3;
-
-    private final static int REQUEST_CODE_SETUP_ACCOUNT = 0;
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        getWindow().requestFeature(Window.FEATURE_NO_TITLE);
-        mParents = new Stack<String>();
-        mParents.add("");
-        if (prepareStreamsToUpload()) {
-            mAccountManager = (AccountManager) getSystemService(Context.ACCOUNT_SERVICE);
-            Account[] accounts = mAccountManager.getAccountsByType(MainApp.getAccountType());
-            if (accounts.length == 0) {
-                Log_OC.i(TAG, "No ownCloud account is available");
-                showDialog(DIALOG_NO_ACCOUNT);
-            } else if (accounts.length > 1) {
-                Log_OC.i(TAG, "More then one ownCloud is available");
-                showDialog(DIALOG_MULTIPLE_ACCOUNT);
-            } else {
-                mAccount = accounts[0];
-                mStorageManager = new FileDataStorageManager(mAccount, getContentResolver());
-                populateDirectoryList();
-            }
-        } else {
-            showDialog(DIALOG_NO_STREAM);
-        }
-    }
-    
-    @Override
-    protected Dialog onCreateDialog(final int id) {
-        final AlertDialog.Builder builder = new Builder(this);
-        switch (id) {
-        case DIALOG_WAITING:
-            ProgressDialog pDialog = new ProgressDialog(this);
-            pDialog.setIndeterminate(false);
-            pDialog.setCancelable(false);
-            pDialog.setMessage(getResources().getString(R.string.uploader_info_uploading));
-            return pDialog;
-        case DIALOG_NO_ACCOUNT:
-            builder.setIcon(android.R.drawable.ic_dialog_alert);
-            builder.setTitle(R.string.uploader_wrn_no_account_title);
-            builder.setMessage(String.format(getString(R.string.uploader_wrn_no_account_text), getString(R.string.app_name)));
-            builder.setCancelable(false);
-            builder.setPositiveButton(R.string.uploader_wrn_no_account_setup_btn_text, new OnClickListener() {
-                @Override
-                public void onClick(DialogInterface dialog, int which) {
-                    if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.ECLAIR_MR1) {
-                        // using string value since in API7 this
-                        // constatn is not defined
-                        // in API7 < this constatant is defined in
-                        // Settings.ADD_ACCOUNT_SETTINGS
-                        // and Settings.EXTRA_AUTHORITIES
-                        Intent intent = new Intent(android.provider.Settings.ACTION_ADD_ACCOUNT);
-                        intent.putExtra("authorities", new String[] { MainApp.getAuthTokenType() });
-                        startActivityForResult(intent, REQUEST_CODE_SETUP_ACCOUNT);
-                    } else {
-                        // since in API7 there is no direct call for
-                        // account setup, so we need to
-                        // show our own AccountSetupAcricity, get
-                        // desired results and setup
-                        // everything for ourself
-                        Intent intent = new Intent(getBaseContext(), AccountAuthenticator.class);
-                        startActivityForResult(intent, REQUEST_CODE_SETUP_ACCOUNT);
-                    }
-                }
-            });
-            builder.setNegativeButton(R.string.uploader_wrn_no_account_quit_btn_text, new OnClickListener() {
-                @Override
-                public void onClick(DialogInterface dialog, int which) {
-                    finish();
-                }
-            });
-            return builder.create();
-        case DIALOG_MULTIPLE_ACCOUNT:
-            CharSequence ac[] = new CharSequence[mAccountManager.getAccountsByType(MainApp.getAccountType()).length];
-            for (int i = 0; i < ac.length; ++i) {
-                ac[i] = mAccountManager.getAccountsByType(MainApp.getAccountType())[i].name;
-            }
-            builder.setTitle(R.string.common_choose_account);
-            builder.setItems(ac, new OnClickListener() {
-                @Override
-                public void onClick(DialogInterface dialog, int which) {
-                    mAccount = mAccountManager.getAccountsByType(MainApp.getAccountType())[which];
-                    mStorageManager = new FileDataStorageManager(mAccount, getContentResolver());
-                    populateDirectoryList();
-                }
-            });
-            builder.setCancelable(true);
-            builder.setOnCancelListener(new OnCancelListener() {
-                @Override
-                public void onCancel(DialogInterface dialog) {
-                    dialog.cancel();
-                    finish();
-                }
-            });
-            return builder.create();
-        case DIALOG_NO_STREAM:
-            builder.setIcon(android.R.drawable.ic_dialog_alert);
-            builder.setTitle(R.string.uploader_wrn_no_content_title);
-            builder.setMessage(R.string.uploader_wrn_no_content_text);
-            builder.setCancelable(false);
-            builder.setNegativeButton(R.string.common_cancel, new OnClickListener() {
-                @Override
-                public void onClick(DialogInterface dialog, int which) {
-                    finish();
-                }
-            });
-            return builder.create();
-        default:
-            throw new IllegalArgumentException("Unknown dialog id: " + id);
-        }
-    }
-
-    class a implements OnClickListener {
-        String mPath;
-        EditText mDirname;
-
-        public a(String path, EditText dirname) {
-            mPath = path; 
-            mDirname = dirname;
-        }
-
-        @Override
-        public void onClick(DialogInterface dialog, int which) {
-            Uploader.this.mUploadPath = mPath + mDirname.getText().toString();
-            Uploader.this.mCreateDir = true;
-            uploadFiles();
-        }
-    }
-
-    @Override
-    public void onBackPressed() {
-
-        if (mParents.size() <= 1) {
-            super.onBackPressed();
-            return;
-        } else {
-            mParents.pop();
-            populateDirectoryList();
-        }
-    }
-
-    @Override
-    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
-        // click on folder in the list
-        Log_OC.d(TAG, "on item click");
-        Vector<OCFile> tmpfiles = mStorageManager.getFolderContent(mFile);
-        if (tmpfiles.size() <= 0) return;
-        // filter on dirtype
-        Vector<OCFile> files = new Vector<OCFile>();
-        for (OCFile f : tmpfiles)
-            if (f.isFolder())
-                files.add(f);
-        if (files.size() < position) {
-            throw new IndexOutOfBoundsException("Incorrect item selected");
-        }
-        mParents.push(files.get(position).getFileName());
-        populateDirectoryList();
-    }
-
-    @Override
-    public void onClick(View v) {
-        // click on button
-        switch (v.getId()) {
-        case R.id.uploader_choose_folder:
-            mUploadPath = "";   // first element in mParents is root dir, represented by ""; init mUploadPath with "/" results in a "//" prefix
-            for (String p : mParents)
-                mUploadPath += p + OCFile.PATH_SEPARATOR;
-            Log_OC.d(TAG, "Uploading file to dir " + mUploadPath);
-
-            uploadFiles();
-
-            break;
-        default:
-            throw new IllegalArgumentException("Wrong element clicked");
-        }
-    }
-
-    @Override
-    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
-        super.onActivityResult(requestCode, resultCode, data);
-        Log_OC.i(TAG, "result received. req: " + requestCode + " res: " + resultCode);
-        if (requestCode == REQUEST_CODE_SETUP_ACCOUNT) {
-            dismissDialog(DIALOG_NO_ACCOUNT);
-            if (resultCode == RESULT_CANCELED) {
-                finish();
-            }
-            Account[] accounts = mAccountManager.getAccountsByType(MainApp.getAuthTokenType());
-            if (accounts.length == 0) {
-                showDialog(DIALOG_NO_ACCOUNT);
-            } else {
-                // there is no need for checking for is there more then one
-                // account at this point
-                // since account setup can set only one account at time
-                mAccount = accounts[0];
-                populateDirectoryList();
-            }
-        }
-    }
-
-    private void populateDirectoryList() {
-        setContentView(R.layout.uploader_layout);
-
-        String full_path = "";
-        for (String a : mParents)
-            full_path += a + "/";
-        
-        Log_OC.d(TAG, "Populating view with content of : " + full_path);
-        
-        mFile = mStorageManager.getFileByPath(full_path);
-        if (mFile != null) {
-            Vector<OCFile> files = mStorageManager.getFolderContent(mFile);
-            List<HashMap<String, Object>> data = new LinkedList<HashMap<String,Object>>();
-            for (OCFile f : files) {
-                HashMap<String, Object> h = new HashMap<String, Object>();
-                if (f.isFolder()) {
-                    h.put("dirname", f.getFileName());
-                    data.add(h);
-                }
-            }
-            SimpleAdapter sa = new SimpleAdapter(this,
-                                                data,
-                                                R.layout.uploader_list_item_layout,
-                                                new String[] {"dirname"},
-                                                new int[] {R.id.textView1});
-            setListAdapter(sa);
-            Button btn = (Button) findViewById(R.id.uploader_choose_folder);
-            btn.setOnClickListener(this);
-            getListView().setOnItemClickListener(this);
-        }
-    }
-
-    private boolean prepareStreamsToUpload() {
-        if (getIntent().getAction().equals(Intent.ACTION_SEND)) {
-            mStreamsToUpload = new ArrayList<Parcelable>();
-            mStreamsToUpload.add(getIntent().getParcelableExtra(Intent.EXTRA_STREAM));
-        } else if (getIntent().getAction().equals(Intent.ACTION_SEND_MULTIPLE)) {
-            mStreamsToUpload = getIntent().getParcelableArrayListExtra(Intent.EXTRA_STREAM);
-        }
-        return (mStreamsToUpload != null && mStreamsToUpload.get(0) != null);
-    }
-
-    public void uploadFiles() {
-        try {
-            //WebdavClient webdav = OwnCloudClientUtils.createOwnCloudClient(mAccount, getApplicationContext());
-
-            ArrayList<String> local = new ArrayList<String>();
-            ArrayList<String> remote = new ArrayList<String>();
-            
-            /* TODO - mCreateDir can never be true at this moment; we will replace wdc.createDirectory by CreateFolderOperation when that is fixed 
-            WebdavClient wdc = OwnCloudClientUtils.createOwnCloudClient(mAccount, getApplicationContext());
-            // create last directory in path if necessary
-            if (mCreateDir) {
-                wdc.createDirectory(mUploadPath);
-            }
-            */
-            
-            // this checks the mimeType 
-            for (Parcelable mStream : mStreamsToUpload) {
-                
-                Uri uri = (Uri) mStream;
-                if (uri !=null) {
-                    if (uri.getScheme().equals("content")) {
-                        
-                       String mimeType = getContentResolver().getType(uri);
-                       
-                       if (mimeType.contains("image")) {
-                           String[] CONTENT_PROJECTION = { Images.Media.DATA, Images.Media.DISPLAY_NAME, Images.Media.MIME_TYPE, Images.Media.SIZE};
-                           Cursor c = getContentResolver().query(uri, CONTENT_PROJECTION, null, null, null);
-                           c.moveToFirst();
-                           int index = c.getColumnIndex(Images.Media.DATA);
-                           String data = c.getString(index);
-                           local.add(data);
-                           remote.add(mUploadPath + c.getString(c.getColumnIndex(Images.Media.DISPLAY_NAME)));
-                       
-                       }
-                       else if (mimeType.contains("video")) {
-                           String[] CONTENT_PROJECTION = { Video.Media.DATA, Video.Media.DISPLAY_NAME, Video.Media.MIME_TYPE, Video.Media.SIZE, Video.Media.DATE_MODIFIED };
-                           Cursor c = getContentResolver().query(uri, CONTENT_PROJECTION, null, null, null);
-                           c.moveToFirst();
-                           int index = c.getColumnIndex(Video.Media.DATA);
-                           String data = c.getString(index);
-                           local.add(data);
-                           remote.add(mUploadPath + c.getString(c.getColumnIndex(Video.Media.DISPLAY_NAME)));
-                          
-                       }
-                       else if (mimeType.contains("audio")) {
-                           String[] CONTENT_PROJECTION = { Audio.Media.DATA, Audio.Media.DISPLAY_NAME, Audio.Media.MIME_TYPE, Audio.Media.SIZE };
-                           Cursor c = getContentResolver().query(uri, CONTENT_PROJECTION, null, null, null);
-                           c.moveToFirst();
-                           int index = c.getColumnIndex(Audio.Media.DATA);
-                           String data = c.getString(index);
-                           local.add(data);
-                           remote.add(mUploadPath + c.getString(c.getColumnIndex(Audio.Media.DISPLAY_NAME)));
-                        
-                       }
-                       else {
-                           String filePath = Uri.decode(uri.toString()).replace(uri.getScheme() + "://", "");
-                           // cut everything whats before mnt. It occured to me that sometimes apps send their name into the URI
-                           if (filePath.contains("mnt")) {
-                              String splitedFilePath[] = filePath.split("/mnt");
-                              filePath = splitedFilePath[1];
-                           }
-                           final File file = new File(filePath);
-                           local.add(file.getAbsolutePath());
-                           remote.add(mUploadPath + file.getName());
-                       }
-                        
-                    } else if (uri.getScheme().equals("file")) {
-                        String filePath = Uri.decode(uri.toString()).replace(uri.getScheme() + "://", "");
-                        if (filePath.contains("mnt")) {
-                           String splitedFilePath[] = filePath.split("/mnt");
-                           filePath = splitedFilePath[1];
-                        }
-                        final File file = new File(filePath);
-                        local.add(file.getAbsolutePath());
-                        remote.add(mUploadPath + file.getName());
-                    }
-                    else {
-                        throw new SecurityException();
-                    }
-                }
-                else {
-                    throw new SecurityException();
-                }
-           
-            Intent intent = new Intent(getApplicationContext(), FileUploader.class);
-            intent.putExtra(FileUploader.KEY_UPLOAD_TYPE, FileUploader.UPLOAD_MULTIPLE_FILES);
-            intent.putExtra(FileUploader.KEY_LOCAL_FILE, local.toArray(new String[local.size()]));
-            intent.putExtra(FileUploader.KEY_REMOTE_FILE, remote.toArray(new String[remote.size()]));
-            intent.putExtra(FileUploader.KEY_ACCOUNT, mAccount);
-            startService(intent);
-            finish();
-            }
-            
-        } catch (SecurityException e) {
-            String message = String.format(getString(R.string.uploader_error_forbidden_content), getString(R.string.app_name));
-            Toast.makeText(this, message, Toast.LENGTH_LONG).show();            
-        }
-    }
-
-}
index ff0782d..1d52fd0 100644 (file)
@@ -18,7 +18,6 @@
 
 package com.owncloud.android.authentication;
 
-import com.owncloud.android.Log_OC;
 import com.owncloud.android.MainApp;
 import com.owncloud.android.R;
 
@@ -29,7 +28,8 @@ import android.os.Bundle;
 import android.os.Handler;
 import android.widget.Toast;
 
-
+import com.owncloud.android.lib.common.accounts.AccountTypeUtils;
+import com.owncloud.android.lib.common.utils.Log_OC;
 
 
 /**
@@ -53,34 +53,6 @@ public class AccountAuthenticator extends AbstractAccountAuthenticator {
     public static final String KEY_LOGIN_OPTIONS = "loginOptions";
     public static final String KEY_ACCOUNT = "account";
     
-    /**
-     * Value under this key should handle path to webdav php script. Will be
-     * removed and usage should be replaced by combining
-     * {@link com.owncloud.android.authentication.AuthenticatorActivity.KEY_OC_BASE_URL} and
-     * {@link com.owncloud.android.utils.OwnCloudVersion}
-     * 
-     * @deprecated
-     */
-    public static final String KEY_OC_URL = "oc_url";
-    /**
-     * Version should be 3 numbers separated by dot so it can be parsed by
-     * {@link com.owncloud.android.utils.OwnCloudVersion}
-     */
-    public static final String KEY_OC_VERSION = "oc_version";
-    /**
-     * Base url should point to owncloud installation without trailing / ie:
-     * http://server/path or https://owncloud.server
-     */
-    public static final String KEY_OC_BASE_URL = "oc_base_url";
-    /**
-     * Flag signaling if the ownCloud server can be accessed with OAuth2 access tokens.
-     */
-    public static final String KEY_SUPPORTS_OAUTH2 = "oc_supports_oauth2";
-    /**
-     * Flag signaling if the ownCloud server can be accessed with session cookies from SAML-based web single-sign-on.
-     */
-    public static final String KEY_SUPPORTS_SAML_WEB_SSO = "oc_supports_saml_web_sso";
-    
     private static final String TAG = AccountAuthenticator.class.getSimpleName();
     
     private Context mContext;
@@ -204,7 +176,7 @@ public class AccountAuthenticator extends AbstractAccountAuthenticator {
         /// check if required token is stored
         final AccountManager am = AccountManager.get(mContext);
         String accessToken;
-        if (authTokenType.equals(MainApp.getAuthTokenTypePass())) {
+        if (authTokenType.equals(AccountTypeUtils.getAuthTokenTypePass(MainApp.getAccountType()))) {
             accessToken = am.getPassword(account);
         } else {
             accessToken = am.peekAuthToken(account, authTokenType);
@@ -223,8 +195,7 @@ public class AccountAuthenticator extends AbstractAccountAuthenticator {
         intent.putExtra(KEY_AUTH_TOKEN_TYPE, authTokenType);
         intent.putExtra(KEY_LOGIN_OPTIONS, options);
         intent.putExtra(AuthenticatorActivity.EXTRA_ACCOUNT, account);
-        intent.putExtra(AuthenticatorActivity.EXTRA_ENFORCED_UPDATE, true);
-        intent.putExtra(AuthenticatorActivity.EXTRA_ACTION, AuthenticatorActivity.ACTION_UPDATE_TOKEN);
+        intent.putExtra(AuthenticatorActivity.EXTRA_ACTION, AuthenticatorActivity.ACTION_UPDATE_EXPIRED_TOKEN);
         
 
         final Bundle bundle = new Bundle();
@@ -285,10 +256,10 @@ public class AccountAuthenticator extends AbstractAccountAuthenticator {
     private void validateAuthTokenType(String authTokenType)\r
             throws UnsupportedAuthTokenTypeException {\r
         if (!authTokenType.equals(MainApp.getAuthTokenType()) &&\r
-            !authTokenType.equals(MainApp.getAuthTokenTypePass()) &&\r
-            !authTokenType.equals(MainApp.getAuthTokenTypeAccessToken()) &&\r
-            !authTokenType.equals(MainApp.getAuthTokenTypeRefreshToken()) &&
-            !authTokenType.equals(MainApp.getAuthTokenTypeSamlSessionCookie())) {\r
+            !authTokenType.equals(AccountTypeUtils.getAuthTokenTypePass(MainApp.getAccountType())) &&\r
+            !authTokenType.equals(AccountTypeUtils.getAuthTokenTypeAccessToken(MainApp.getAccountType())) &&\r
+            !authTokenType.equals(AccountTypeUtils.getAuthTokenTypeRefreshToken(MainApp.getAccountType())) &&
+            !authTokenType.equals(AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(MainApp.getAccountType()))) {\r
             throw new UnsupportedAuthTokenTypeException();\r
         }\r
     }\r
index 3b79c39..dc02344 100644 (file)
 \r
 package com.owncloud.android.authentication;\r
 \r
+import java.util.Locale;\r
+\r
 import com.owncloud.android.MainApp;\r
-import com.owncloud.android.utils.OwnCloudVersion;\r
+import com.owncloud.android.lib.common.accounts.AccountTypeUtils;\r
+import com.owncloud.android.lib.resources.status.OwnCloudVersion;\r
 \r
 import android.accounts.Account;\r
 import android.accounts.AccountManager;\r
-import android.accounts.AccountsException;\r
 import android.content.Context;\r
 import android.content.SharedPreferences;\r
 import android.preference.PreferenceManager;\r
@@ -81,8 +83,18 @@ public class AccountUtils {
                 MainApp.getAccountType());\r
 \r
         if (account != null && account.name != null) {\r
-            for (Account ac : ocAccounts) {\r
-                if (ac.name.equals(account.name)) {\r
+            int lastAtPos = account.name.lastIndexOf("@");\r
+            String hostAndPort = account.name.substring(lastAtPos + 1);\r
+            String username = account.name.substring(0, lastAtPos);\r
+            String otherHostAndPort, otherUsername;\r
+            Locale currentLocale = context.getResources().getConfiguration().locale;\r
+            for (Account otherAccount : ocAccounts) {\r
+                lastAtPos = otherAccount.name.lastIndexOf("@");\r
+                otherHostAndPort = otherAccount.name.substring(lastAtPos + 1);\r
+                otherUsername = otherAccount.name.substring(0, lastAtPos);\r
+                if (otherHostAndPort.equals(hostAndPort) &&\r
+                        otherUsername.toLowerCase(currentLocale).\r
+                            equals(username.toLowerCase(currentLocale))) {\r
                     return true;\r
                 }\r
             }\r
@@ -127,30 +139,6 @@ public class AccountUtils {
     }\r
 \r
     /**\r
-     * \r
-     * @param version version of owncloud\r
-     * @return webdav path for given OC version, null if OC version unknown\r
-     */\r
-    public static String getWebdavPath(OwnCloudVersion version, boolean supportsOAuth, boolean supportsSamlSso) {\r
-        if (version != null) {\r
-            if (supportsOAuth) {\r
-                return ODAV_PATH;\r
-            }\r
-            if (supportsSamlSso) {\r
-                return SAML_SSO_PATH;\r
-            }\r
-            if (version.compareTo(OwnCloudVersion.owncloud_v4) >= 0)\r
-                return WEBDAV_PATH_4_0;\r
-            if (version.compareTo(OwnCloudVersion.owncloud_v3) >= 0\r
-                    || version.compareTo(OwnCloudVersion.owncloud_v2) >= 0)\r
-                return WEBDAV_PATH_2_0;\r
-            if (version.compareTo(OwnCloudVersion.owncloud_v1) >= 0)\r
-                return WEBDAV_PATH_1_2;\r
-        }\r
-        return null;\r
-    }\r
-    \r
-    /**\r
      * Returns the proper URL path to access the WebDAV interface of an ownCloud server,\r
      * according to its version and the authorization method used.\r
      * \r
@@ -160,10 +148,10 @@ public class AccountUtils {
      */\r
     public static String getWebdavPath(OwnCloudVersion version, String authTokenType) {\r
         if (version != null) {\r
-            if (MainApp.getAuthTokenTypeAccessToken().equals(authTokenType)) {\r
+            if (AccountTypeUtils.getAuthTokenTypeAccessToken(MainApp.getAccountType()).equals(authTokenType)) {\r
                 return ODAV_PATH;\r
             }\r
-            if (MainApp.getAuthTokenTypeSamlSessionCookie().equals(authTokenType)) {\r
+            if (AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(MainApp.getAccountType()).equals(authTokenType)) {\r
                 return SAML_SSO_PATH;\r
             }\r
             if (version.compareTo(OwnCloudVersion.owncloud_v4) >= 0)\r
@@ -177,44 +165,4 @@ public class AccountUtils {
         return null;\r
     }\r
     \r
-    /**\r
-     * Constructs full url to host and webdav resource basing on host version\r
-     * @param context\r
-     * @param account\r
-     * @return url or null on failure\r
-     * @throws AccountNotFoundException     When 'account' is unknown for the AccountManager\r
-     */\r
-    public static String constructFullURLForAccount(Context context, Account account) throws AccountNotFoundException {\r
-        AccountManager ama = AccountManager.get(context);\r
-        String baseurl = ama.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL);\r
-        String strver  = ama.getUserData(account, AccountAuthenticator.KEY_OC_VERSION);\r
-        boolean supportsOAuth = (ama.getUserData(account, AccountAuthenticator.KEY_SUPPORTS_OAUTH2) != null);\r
-        boolean supportsSamlSso = (ama.getUserData(account, AccountAuthenticator.KEY_SUPPORTS_SAML_WEB_SSO) != null);\r
-        OwnCloudVersion ver = new OwnCloudVersion(strver);\r
-        String webdavpath = getWebdavPath(ver, supportsOAuth, supportsSamlSso);\r
-\r
-        if (baseurl == null || webdavpath == null) \r
-            throw new AccountNotFoundException(account, "Account not found", null);\r
-        \r
-        return baseurl + webdavpath;\r
-    }\r
-    \r
-    \r
-    public static class AccountNotFoundException extends AccountsException {\r
-        \r
-        /** Generated - should be refreshed every time the class changes!! */\r
-        private static final long serialVersionUID = -9013287181793186830L;\r
-        \r
-        private Account mFailedAccount; \r
-                \r
-        public AccountNotFoundException(Account failedAccount, String message, Throwable cause) {\r
-            super(message, cause);\r
-            mFailedAccount = failedAccount;\r
-        }\r
-        \r
-        public Account getFailedAccount() {\r
-            return mFailedAccount;\r
-        }\r
-    }\r
-\r
 }\r
index faeffd5..97dcfde 100644 (file)
@@ -1,6 +1,6 @@
 /* ownCloud Android client application\r
  *   Copyright (C) 2012  Bartek Przybylski\r
- *   Copyright (C) 2012-2013 ownCloud Inc.\r
+ *   Copyright (C) 2012-2014 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
 package com.owncloud.android.authentication;\r
 \r
+import java.security.cert.X509Certificate;\r
+import java.util.Map;\r
+\r
 import android.accounts.Account;\r
 import android.accounts.AccountManager;\r
-import android.app.AlertDialog;\r
 import android.app.Dialog;\r
-import android.app.ProgressDialog;\r
-import android.content.ContentResolver;\r
-import android.content.DialogInterface;\r
+import android.content.ComponentName;\r
+import android.content.Context;\r
 import android.content.Intent;\r
+import android.content.ServiceConnection;\r
 import android.content.SharedPreferences;\r
 import android.graphics.Rect;\r
 import android.graphics.drawable.Drawable;\r
 import android.net.Uri;\r
+import android.net.http.SslError;\r
 import android.os.Bundle;\r
 import android.os.Handler;\r
+import android.os.IBinder;\r
 import android.preference.PreferenceManager;\r
 import android.support.v4.app.Fragment;\r
+import android.support.v4.app.FragmentManager;\r
+import android.support.v4.app.FragmentTransaction;\r
 import android.text.Editable;\r
 import android.text.InputType;\r
 import android.text.TextWatcher;\r
@@ -44,129 +50,138 @@ import android.view.View.OnFocusChangeListener;
 import android.view.View.OnTouchListener;\r
 import android.view.Window;\r
 import android.view.inputmethod.EditorInfo;\r
+import android.webkit.HttpAuthHandler;\r
+import android.webkit.SslErrorHandler;\r
+import android.webkit.WebView;\r
 import android.widget.Button;\r
 import android.widget.CheckBox;\r
 import android.widget.EditText;\r
 import android.widget.TextView;\r
 import android.widget.TextView.OnEditorActionListener;\r
+import android.widget.Toast;\r
 \r
 import com.actionbarsherlock.app.SherlockDialogFragment;\r
-import com.owncloud.android.Log_OC;\r
 import com.owncloud.android.MainApp;\r
 import com.owncloud.android.R;\r
 import com.owncloud.android.authentication.SsoWebViewClient.SsoWebViewClientListener;\r
-import com.owncloud.android.network.OwnCloudClientUtils;\r
-import com.owncloud.android.operations.ExistenceCheckOperation;\r
+import com.owncloud.android.lib.common.accounts.AccountTypeUtils;\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
+import com.owncloud.android.lib.common.operations.RemoteOperation;\r
+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
+import com.owncloud.android.operations.GetServerInfoOperation;\r
 import com.owncloud.android.operations.OAuth2GetAccessToken;\r
-import com.owncloud.android.operations.OnRemoteOperationListener;\r
-import com.owncloud.android.operations.OwnCloudServerCheckOperation;\r
-import com.owncloud.android.operations.RemoteOperation;\r
-import com.owncloud.android.operations.RemoteOperationResult;\r
-import com.owncloud.android.operations.RemoteOperationResult.ResultCode;\r
+import com.owncloud.android.services.OperationsService;\r
+import com.owncloud.android.services.OperationsService.OperationsServiceBinder;\r
+import com.owncloud.android.ui.dialog.CredentialsDialogFragment;\r
+import com.owncloud.android.ui.dialog.IndeterminateProgressDialog;\r
 import com.owncloud.android.ui.dialog.SamlWebViewDialog;\r
-import com.owncloud.android.ui.dialog.SslValidatorDialog;\r
-import com.owncloud.android.ui.dialog.SslValidatorDialog.OnSslValidatorListener;\r
-import com.owncloud.android.utils.OwnCloudVersion;\r
-\r
-\r
-import eu.alefzero.webdav.WebdavClient;\r
+import com.owncloud.android.ui.dialog.SslUntrustedCertDialog;\r
+import com.owncloud.android.ui.dialog.SslUntrustedCertDialog.OnSslUntrustedCertListener;\r
 \r
 /**\r
  * This Activity is used to add an ownCloud account to the App\r
  * \r
  * @author Bartek Przybylski\r
  * @author David A. Velasco\r
+ * @author masensio\r
  */\r
 public class AuthenticatorActivity extends AccountAuthenticatorActivity\r
-implements  OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeListener, OnEditorActionListener, SsoWebViewClientListener{\r
+implements  OnRemoteOperationListener, OnFocusChangeListener, OnEditorActionListener, \r
+SsoWebViewClientListener, OnSslUntrustedCertListener {\r
 \r
     private static final String TAG = AuthenticatorActivity.class.getSimpleName();\r
 \r
-    public static final String EXTRA_ACCOUNT = "ACCOUNT";\r
-    public static final String EXTRA_USER_NAME = "USER_NAME";\r
-    public static final String EXTRA_HOST_NAME = "HOST_NAME";\r
     public static final String EXTRA_ACTION = "ACTION";\r
-    public static final String EXTRA_ENFORCED_UPDATE = "ENFORCE_UPDATE";\r
+    public static final String EXTRA_ACCOUNT = "ACCOUNT";\r
+\r
+    private static final String KEY_AUTH_TOKEN_TYPE = "AUTH_TOKEN_TYPE";\r
 \r
-    private static final String KEY_AUTH_MESSAGE_VISIBILITY = "AUTH_MESSAGE_VISIBILITY";\r
-    private static final String KEY_AUTH_MESSAGE_TEXT = "AUTH_MESSAGE_TEXT";\r
     private static final String KEY_HOST_URL_TEXT = "HOST_URL_TEXT";\r
     private static final String KEY_OC_VERSION = "OC_VERSION";\r
-    private static final String KEY_ACCOUNT = "ACCOUNT";\r
     private static final String KEY_SERVER_VALID = "SERVER_VALID";\r
     private static final String KEY_SERVER_CHECKED = "SERVER_CHECKED";\r
-    private static final String KEY_SERVER_CHECK_IN_PROGRESS = "SERVER_CHECK_IN_PROGRESS"; \r
     private static final String KEY_SERVER_STATUS_TEXT = "SERVER_STATUS_TEXT";\r
     private static final String KEY_SERVER_STATUS_ICON = "SERVER_STATUS_ICON";\r
     private static final String KEY_IS_SSL_CONN = "IS_SSL_CONN";\r
-    private static final String KEY_PASSWORD_VISIBLE = "PASSWORD_VISIBLE";\r
+    private static final String KEY_PASSWORD_EXPOSED = "PASSWORD_VISIBLE";\r
     private static final String KEY_AUTH_STATUS_TEXT = "AUTH_STATUS_TEXT";\r
     private static final String KEY_AUTH_STATUS_ICON = "AUTH_STATUS_ICON";\r
-    private static final String KEY_REFRESH_BUTTON_ENABLED = "KEY_REFRESH_BUTTON_ENABLED";\r
-    \r
-    private static final String KEY_OC_USERNAME_EQUALS = "oc_username=";\r
+    private static final String KEY_SERVER_AUTH_METHOD = "SERVER_AUTH_METHOD";\r
+    private static final String KEY_WAITING_FOR_OP_ID = "WAITING_FOR_OP_ID";\r
+    private static final String KEY_AUTH_TOKEN = "AUTH_TOKEN";\r
 \r
     private static final String AUTH_ON = "on";\r
-    private static final String AUTH_OFF = "off";\r
     private static final String AUTH_OPTIONAL = "optional";\r
-    \r
-    private static final int DIALOG_LOGIN_PROGRESS = 0;\r
-    private static final int DIALOG_SSL_VALIDATOR = 1;\r
-    private static final int DIALOG_CERT_NOT_SAVED = 2;\r
-    private static final int DIALOG_OAUTH2_LOGIN_PROGRESS = 3;\r
 \r
     public static final byte ACTION_CREATE = 0;\r
-    public static final byte ACTION_UPDATE_TOKEN = 1;\r
+    public static final byte ACTION_UPDATE_TOKEN = 1;               // requested by the user\r
+    public static final byte ACTION_UPDATE_EXPIRED_TOKEN = 2;       // detected by the app\r
+\r
+    private static final String UNTRUSTED_CERT_DIALOG_TAG = "UNTRUSTED_CERT_DIALOG";\r
+    private static final String SAML_DIALOG_TAG = "SAML_DIALOG";\r
+    private static final String WAIT_DIALOG_TAG = "WAIT_DIALOG";\r
+    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 TAG_SAML_DIALOG = "samlWebViewDialog";\r
     \r
-    private String mHostBaseUrl;\r
-    private OwnCloudVersion mDiscoveredVersion;\r
+    /// parameters from EXTRAs in starter Intent\r
+    private byte mAction;\r
+    private Account mAccount;\r
+    private String mAuthTokenType;\r
 \r
-    private String mAuthMessageText;\r
-    private int mAuthMessageVisibility, mServerStatusText, mServerStatusIcon;\r
-    private boolean mServerIsChecked, mServerIsValid, mIsSslConn;\r
-    private int mAuthStatusText, mAuthStatusIcon;    \r
-    private TextView mAuthStatusLayout;\r
 \r
+    /// activity-level references / state\r
     private final Handler mHandler = new Handler();\r
-    private Thread mOperationThread;\r
-    private OwnCloudServerCheckOperation mOcServerChkOperation;\r
-    private ExistenceCheckOperation mAuthCheckOperation;\r
-    private RemoteOperationResult mLastSslUntrustedServerResult;\r
-\r
+    private ServiceConnection mOperationsServiceConnection = null;\r
+    private OperationsServiceBinder mOperationsServiceBinder = null;\r
+    private AccountManager mAccountMgr;\r
     private Uri mNewCapturedUriFromOAuth2Redirection;\r
 \r
-    private AccountManager mAccountMgr;\r
-    private boolean mJustCreated;\r
-    private byte mAction;\r
-    private Account mAccount;\r
 \r
-    private TextView mAuthMessage;\r
-    \r
+    /// Server PRE-Fragment elements \r
     private EditText mHostUrlInput;\r
-    private boolean mHostUrlInputEnabled;\r
     private View mRefreshButton;\r
+    private TextView mServerStatusView;\r
+    \r
+    private TextWatcher mHostUrlInputWatcher;\r
+    private int mServerStatusText = 0, mServerStatusIcon = 0;\r
+    \r
+    private boolean mServerIsChecked = false;\r
+    private boolean mServerIsValid = false;\r
+    private boolean mPendingAutoCheck = false;\r
 \r
-    private String mAuthTokenType;\r
+    private GetServerInfoOperation.ServerInfo mServerInfo = \r
+            new GetServerInfoOperation.ServerInfo();\r
     \r
-    private EditText mUsernameInput;\r
-    private EditText mPasswordInput;\r
     \r
+    /// Authentication PRE-Fragment elements \r
     private CheckBox mOAuth2Check;\r
-    \r
     private TextView mOAuthAuthEndpointText;\r
     private TextView mOAuthTokenEndpointText;\r
-    \r
-    private SamlWebViewDialog mSamlDialog;\r
-    \r
+    private EditText mUsernameInput;\r
+    private EditText mPasswordInput;\r
     private View mOkButton;\r
+    private TextView mAuthStatusView;\r
+\r
+    private int mAuthStatusText = 0, mAuthStatusIcon = 0;\r
     \r
-    private String mAuthToken;\r
-    \r
-    private boolean mResumed; // Control if activity is resumed\r
+    private String mAuthToken = "";\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
     /**\r
      * {@inheritDoc}\r
      * \r
@@ -174,165 +189,202 @@ implements  OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList
      */\r
     @Override\r
     protected void onCreate(Bundle savedInstanceState) {\r
+        //Log_OC.wtf(TAG,  "onCreate init");\r
         super.onCreate(savedInstanceState);\r
         getWindow().requestFeature(Window.FEATURE_NO_TITLE);\r
 \r
-        /// set view and get references to view elements\r
+        mIsFirstAuthAttempt = true;\r
+\r
+        // bind to Operations Service\r
+        mOperationsServiceConnection = new OperationsServiceConnection();\r
+        if (!bindService(new Intent(this, OperationsService.class), \r
+                mOperationsServiceConnection, \r
+                Context.BIND_AUTO_CREATE)) {\r
+            Toast.makeText(this, \r
+                    R.string.error_cant_bind_to_operations_service, \r
+                    Toast.LENGTH_LONG)\r
+                        .show();\r
+            finish();\r
+        }\r
+\r
+        /// init activity state\r
+        mAccountMgr = AccountManager.get(this);\r
+        mNewCapturedUriFromOAuth2Redirection = null;\r
+        \r
+        /// get input values\r
+        mAction = getIntent().getByteExtra(EXTRA_ACTION, ACTION_CREATE); \r
+        mAccount = getIntent().getExtras().getParcelable(EXTRA_ACCOUNT);\r
+        if (savedInstanceState == null) {\r
+            initAuthTokenType();\r
+        } else {\r
+            mAuthTokenType = savedInstanceState.getString(KEY_AUTH_TOKEN_TYPE);\r
+            mWaitingForOpId = savedInstanceState.getLong(KEY_WAITING_FOR_OP_ID);\r
+            mIsFirstAuthAttempt = savedInstanceState.getBoolean(KEY_AUTH_IS_FIRST_ATTEMPT_TAG);\r
+        }\r
+        \r
+        /// load user interface\r
         setContentView(R.layout.account_setup);\r
-        mAuthMessage = (TextView) findViewById(R.id.auth_message);\r
-        mHostUrlInput = (EditText) findViewById(R.id.hostUrlInput);\r
-        mHostUrlInput.setText(getString(R.string.server_url));  // valid although R.string.server_url is an empty string\r
-        mUsernameInput = (EditText) findViewById(R.id.account_username);\r
-        mPasswordInput = (EditText) findViewById(R.id.account_password);\r
-        mOAuthAuthEndpointText = (TextView)findViewById(R.id.oAuthEntryPoint_1);\r
-        mOAuthTokenEndpointText = (TextView)findViewById(R.id.oAuthEntryPoint_2);\r
-        mOAuth2Check = (CheckBox) findViewById(R.id.oauth_onOff_check);\r
-        mOkButton = findViewById(R.id.buttonOK);\r
-        mAuthStatusLayout = (TextView) findViewById(R.id.auth_status_text); \r
         \r
-        /// set Host Url Input Enabled\r
-        mHostUrlInputEnabled = getResources().getBoolean(R.bool.show_server_url_input);\r
+        /// initialize general UI elements\r
+        initOverallUi(savedInstanceState);\r
         \r
-        /// set visibility of link for new users\r
-        boolean accountRegisterVisibility = getResources().getBoolean(R.bool.show_welcome_link);\r
-        Button welcomeLink = (Button) findViewById(R.id.welcome_link);\r
-        if (welcomeLink != null) {\r
-            if (accountRegisterVisibility) {\r
-                welcomeLink.setVisibility(View.VISIBLE);\r
-                welcomeLink.setText(String.format(getString(R.string.auth_register), getString(R.string.app_name)));            \r
+        mOkButton = findViewById(R.id.buttonOK);\r
+\r
+        /// initialize block to be moved to single Fragment to check server and get info about it \r
+        initServerPreFragment(savedInstanceState);\r
+        \r
+        /// initialize block to be moved to single Fragment to retrieve and validate credentials \r
+        initAuthorizationPreFragment(savedInstanceState);\r
+\r
+        //Log_OC.wtf(TAG,  "onCreate end");\r
+    }\r
+\r
+    private void initAuthTokenType() {\r
+        mAuthTokenType = \r
+                getIntent().getExtras().getString(AccountAuthenticator.KEY_AUTH_TOKEN_TYPE);\r
+        if (mAuthTokenType == null) {\r
+            if (mAccount != null) {\r
+                boolean oAuthRequired = \r
+                    (mAccountMgr.getUserData(mAccount, Constants.KEY_SUPPORTS_OAUTH2) != null);\r
+                boolean samlWebSsoRequired = ( \r
+                    mAccountMgr.getUserData(\r
+                        mAccount, Constants.KEY_SUPPORTS_SAML_WEB_SSO\r
+                    ) != null\r
+                );\r
+                mAuthTokenType = chooseAuthTokenType(oAuthRequired, samlWebSsoRequired);\r
+                \r
             } else {\r
-                findViewById(R.id.welcome_link).setVisibility(View.GONE);\r
+                boolean oAuthSupported = AUTH_ON.equals(getString(R.string.auth_method_oauth2));\r
+                boolean samlWebSsoSupported = \r
+                        AUTH_ON.equals(getString(R.string.auth_method_saml_web_sso));\r
+                mAuthTokenType = chooseAuthTokenType(oAuthSupported, samlWebSsoSupported);\r
             }\r
         }\r
+    }\r
 \r
-        /// initialization\r
-        mAccountMgr = AccountManager.get(this);\r
-        mNewCapturedUriFromOAuth2Redirection = null;\r
-        mAction = getIntent().getByteExtra(EXTRA_ACTION, ACTION_CREATE); \r
-        mAccount = null;\r
-        mHostBaseUrl = "";\r
-        boolean refreshButtonEnabled = false;\r
-        \r
-        // URL input configuration applied\r
-        if (!mHostUrlInputEnabled)\r
-        {\r
-            findViewById(R.id.hostUrlFrame).setVisibility(View.GONE);\r
-            mRefreshButton = findViewById(R.id.centeredRefreshButton);\r
+    private String chooseAuthTokenType(boolean oauth, boolean saml) {\r
+        if (saml) {\r
+            return AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(MainApp.getAccountType());\r
+        } else if (oauth) {\r
+             return AccountTypeUtils.getAuthTokenTypeAccessToken(MainApp.getAccountType());\r
+        } else {\r
+            return AccountTypeUtils.getAuthTokenTypePass(MainApp.getAccountType());\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
+        \r
+        /// step 1 - load and process relevant inputs (resources, intent, savedInstanceState)\r
+        boolean isWelcomeLinkVisible = getResources().getBoolean(R.bool.show_welcome_link);\r
+        \r
+        String instructionsMessageText = null; \r
+        if (mAction == ACTION_UPDATE_EXPIRED_TOKEN) {\r
+            if (AccountTypeUtils.getAuthTokenTypeAccessToken(MainApp.getAccountType())\r
+                    .equals(mAuthTokenType)) {\r
+                instructionsMessageText = getString(R.string.auth_expired_oauth_token_toast);\r
+                \r
+            } else if (AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(MainApp.getAccountType())\r
+                    .equals(mAuthTokenType)) {\r
+                instructionsMessageText = getString(R.string.auth_expired_saml_sso_token_toast);\r
+                \r
+            } else {\r
+                instructionsMessageText = getString(R.string.auth_expired_basic_auth_toast);\r
+            }\r
+        }\r
+        \r
+        /// step 2 - set properties of UI elements (text, visibility, enabled...)\r
+        Button welcomeLink = (Button) findViewById(R.id.welcome_link);\r
+        welcomeLink.setVisibility(isWelcomeLinkVisible ? View.VISIBLE : View.GONE);\r
+        welcomeLink.setText(\r
+                String.format(getString(R.string.auth_register), getString(R.string.app_name)));\r
+        \r
+        TextView instructionsView = (TextView) findViewById(R.id.instructions_message);\r
+        if (instructionsMessageText != null) {\r
+            instructionsView.setVisibility(View.VISIBLE);\r
+            instructionsView.setText(instructionsMessageText);\r
         } else {\r
-            mRefreshButton = findViewById(R.id.embeddedRefreshButton);\r
+            instructionsView.setVisibility(View.GONE);\r
         }\r
+    }\r
 \r
-        if (savedInstanceState == null) {\r
-            mResumed = false;\r
-            /// connection state and info\r
-            mAuthMessageVisibility = View.GONE;\r
-            mServerStatusText = mServerStatusIcon = 0;\r
-            mServerIsValid = false;\r
-            mServerIsChecked = false;\r
-            mIsSslConn = false;\r
-            mAuthStatusText = mAuthStatusIcon = 0;\r
 \r
-            /// retrieve extras from intent\r
-            mAccount = getIntent().getExtras().getParcelable(EXTRA_ACCOUNT);\r
+    /**\r
+     * \r
+     * @param savedInstanceState        Saved activity state, as in {{@link #onCreate(Bundle)}\r
+     */\r
+    private void initServerPreFragment(Bundle savedInstanceState) {\r
+\r
+        /// step 1 - load and process relevant inputs (resources, intent, savedInstanceState)\r
+        boolean isUrlInputAllowed = getResources().getBoolean(R.bool.show_server_url_input); \r
+        if (savedInstanceState == null) {\r
             if (mAccount != null) {\r
-                String ocVersion = mAccountMgr.getUserData(mAccount, AccountAuthenticator.KEY_OC_VERSION);\r
+                mServerInfo.mBaseUrl = mAccountMgr.getUserData(mAccount, Constants.KEY_OC_BASE_URL);\r
+                // TODO do next in a setter for mBaseUrl\r
+                mServerInfo.mIsSslConn = mServerInfo.mBaseUrl.startsWith("https://");   \r
+                String ocVersion = mAccountMgr.getUserData(mAccount, Constants.KEY_OC_VERSION);\r
                 if (ocVersion != null) {\r
-                    mDiscoveredVersion = new OwnCloudVersion(ocVersion);\r
+                    mServerInfo.mVersion = new OwnCloudVersion(ocVersion);\r
                 }\r
-                mHostBaseUrl = normalizeUrl(mAccountMgr.getUserData(mAccount, AccountAuthenticator.KEY_OC_BASE_URL));\r
-                mHostUrlInput.setText(mHostBaseUrl);\r
-                String userName = mAccount.name.substring(0, mAccount.name.lastIndexOf('@'));\r
-                mUsernameInput.setText(userName);\r
-            }\r
-            initAuthorizationMethod();  // checks intent and setup.xml to determine mCurrentAuthorizationMethod\r
-            mJustCreated = true;\r
-            \r
-            if (mAction == ACTION_UPDATE_TOKEN || !mHostUrlInputEnabled) {\r
-                checkOcServer(); \r
+            } else {\r
+                mServerInfo.mBaseUrl = getString(R.string.server_url).trim();\r
+                mServerInfo.mIsSslConn = mServerInfo.mBaseUrl.startsWith("https://");\r
             }\r
-            \r
         } else {\r
-            mResumed = true;\r
-            /// connection state and info\r
-            mAuthMessageVisibility = savedInstanceState.getInt(KEY_AUTH_MESSAGE_VISIBILITY);\r
-            mAuthMessageText = savedInstanceState.getString(KEY_AUTH_MESSAGE_TEXT);\r
-            mServerIsValid = savedInstanceState.getBoolean(KEY_SERVER_VALID);\r
-            mServerIsChecked = savedInstanceState.getBoolean(KEY_SERVER_CHECKED);\r
             mServerStatusText = savedInstanceState.getInt(KEY_SERVER_STATUS_TEXT);\r
             mServerStatusIcon = savedInstanceState.getInt(KEY_SERVER_STATUS_ICON);\r
-            mIsSslConn = savedInstanceState.getBoolean(KEY_IS_SSL_CONN);\r
-            mAuthStatusText = savedInstanceState.getInt(KEY_AUTH_STATUS_TEXT);\r
-            mAuthStatusIcon = savedInstanceState.getInt(KEY_AUTH_STATUS_ICON);\r
-            if (savedInstanceState.getBoolean(KEY_PASSWORD_VISIBLE, false)) {\r
-                showPassword();\r
-            }\r
             \r
-            /// server data\r
+            mServerIsValid = savedInstanceState.getBoolean(KEY_SERVER_VALID);\r
+            mServerIsChecked = savedInstanceState.getBoolean(KEY_SERVER_CHECKED);\r
+            \r
+            // TODO parcelable\r
+            mServerInfo.mIsSslConn = savedInstanceState.getBoolean(KEY_IS_SSL_CONN);\r
+            mServerInfo.mBaseUrl = savedInstanceState.getString(KEY_HOST_URL_TEXT);\r
             String ocVersion = savedInstanceState.getString(KEY_OC_VERSION);\r
             if (ocVersion != null) {\r
-                mDiscoveredVersion = new OwnCloudVersion(ocVersion);\r
+                mServerInfo.mVersion = new OwnCloudVersion(ocVersion);\r
             }\r
-            mHostBaseUrl = savedInstanceState.getString(KEY_HOST_URL_TEXT);\r
-\r
-            // account data, if updating\r
-            mAccount = savedInstanceState.getParcelable(KEY_ACCOUNT);\r
-            mAuthTokenType = savedInstanceState.getString(AccountAuthenticator.KEY_AUTH_TOKEN_TYPE);\r
-            if (mAuthTokenType == null) {\r
-                mAuthTokenType =  MainApp.getAuthTokenTypePass();\r
-                \r
-            }\r
-\r
-            // check if server check was interrupted by a configuration change\r
-            if (savedInstanceState.getBoolean(KEY_SERVER_CHECK_IN_PROGRESS, false)) {\r
-                checkOcServer();\r
-            }            \r
-            \r
-            // refresh button enabled\r
-            refreshButtonEnabled = savedInstanceState.getBoolean(KEY_REFRESH_BUTTON_ENABLED);\r
+            mServerInfo.mAuthMethod = AuthenticationMethod.valueOf(\r
+                    savedInstanceState.getString(KEY_SERVER_AUTH_METHOD));\r
             \r
-\r
-        }\r
-\r
-        if (mAuthMessageVisibility== View.VISIBLE) {\r
-            showAuthMessage(mAuthMessageText);\r
         }\r
-        else {\r
-            hideAuthMessage();\r
-        }\r
-        adaptViewAccordingToAuthenticationMethod();\r
-        showServerStatus();\r
-        showAuthStatus();\r
         \r
-        if (mAction == ACTION_UPDATE_TOKEN) {\r
+        /// step 2 - set properties of UI elements (text, visibility, enabled...)\r
+        mHostUrlInput = (EditText) findViewById(R.id.hostUrlInput);\r
+        mHostUrlInput.setText(mServerInfo.mBaseUrl);\r
+        if (mAction != ACTION_CREATE) {\r
             /// lock things that should not change\r
             mHostUrlInput.setEnabled(false);\r
             mHostUrlInput.setFocusable(false);\r
-            mUsernameInput.setEnabled(false);\r
-            mUsernameInput.setFocusable(false);\r
-            mOAuth2Check.setVisibility(View.GONE);\r
         }\r
-        \r
-        //if (mServerIsChecked && !mServerIsValid && mRefreshButtonEnabled) showRefreshButton();\r
-        if (mServerIsChecked && !mServerIsValid && refreshButtonEnabled) showRefreshButton();\r
-        mOkButton.setEnabled(mServerIsValid); // state not automatically recovered in configuration changes\r
-\r
-        if (MainApp.getAuthTokenTypeSamlSessionCookie().equals(mAuthTokenType) || \r
-                !AUTH_OPTIONAL.equals(getString(R.string.auth_method_oauth2))) {\r
-            mOAuth2Check.setVisibility(View.GONE);\r
+        if (isUrlInputAllowed) {\r
+            mRefreshButton = findViewById(R.id.embeddedRefreshButton);\r
+        } else {\r
+            findViewById(R.id.hostUrlFrame).setVisibility(View.GONE);\r
+            mRefreshButton = findViewById(R.id.centeredRefreshButton);\r
         }\r
-\r
-        mPasswordInput.setText("");     // clean password to avoid social hacking (disadvantage: password in removed if the device is turned aside)\r
-\r
-        /// bind view elements to listeners and other friends\r
-        mHostUrlInput.setOnFocusChangeListener(this);\r
+        showRefreshButton(mServerIsChecked && !mServerIsValid && \r
+                mWaitingForOpId > Integer.MAX_VALUE);\r
+        mServerStatusView = (TextView) findViewById(R.id.server_status_text);\r
+        showServerStatus();\r
+        \r
+        /// step 3 - bind some listeners and options\r
         mHostUrlInput.setImeOptions(EditorInfo.IME_ACTION_NEXT);\r
         mHostUrlInput.setOnEditorActionListener(this);\r
-        mHostUrlInput.addTextChangedListener(new TextWatcher() {\r
-\r
+        \r
+        /// step 4 - create listeners that will be bound at onResume\r
+        mHostUrlInputWatcher = new TextWatcher() {\r
+            \r
             @Override\r
             public void afterTextChanged(Editable s) {\r
-                if (!mHostBaseUrl.equals(normalizeUrl(mHostUrlInput.getText().toString()))) {\r
+                if (mOkButton.isEnabled() &&\r
+                        !mServerInfo.mBaseUrl.equals(\r
+                                normalizeUrl(s.toString(), mServerInfo.mIsSslConn))) {\r
                     mOkButton.setEnabled(false);\r
                 }\r
             }\r
@@ -343,18 +395,95 @@ implements  OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList
 \r
             @Override\r
             public void onTextChanged(CharSequence s, int start, int before, int count) {\r
-                if (!mResumed) {\r
+                if (mAuthStatusIcon != 0) {\r
+                    Log_OC.d(TAG, "onTextChanged: hiding authentication status");\r
                     mAuthStatusIcon = 0;\r
                     mAuthStatusText = 0;\r
-                    showAuthStatus();                    \r
+                    showAuthStatus();\r
                 }\r
-                mResumed = false;\r
+            }\r
+        };\r
+\r
+\r
+        // TODO find out if this is really necessary, or if it can done in a different way\r
+        findViewById(R.id.scroll).setOnTouchListener(new OnTouchListener() {\r
+            @Override\r
+            public boolean onTouch(View view, MotionEvent event) {\r
+                if (event.getAction() == MotionEvent.ACTION_DOWN) {\r
+                    if (\r
+                            AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(\r
+                                    MainApp.getAccountType()\r
+                                    ).equals(mAuthTokenType) &&\r
+                            mHostUrlInput.hasFocus()\r
+                    ) {\r
+                        checkOcServer();\r
+                    }\r
+                }\r
+                return false;\r
             }\r
         });\r
+     \r
+        \r
+        /// step 4 - mark automatic check to be started when OperationsService is ready\r
+        mPendingAutoCheck = (savedInstanceState == null && \r
+                (mAction != ACTION_CREATE || !isUrlInputAllowed));\r
+    }\r
+    \r
+    \r
+    /**\r
+     * \r
+     * @param savedInstanceState        Saved activity state, as in {{@link #onCreate(Bundle)}\r
+     */\r
+    private void initAuthorizationPreFragment(Bundle savedInstanceState) {\r
+        \r
+        /// step 0 - get UI elements in layout\r
+        mOAuth2Check = (CheckBox) findViewById(R.id.oauth_onOff_check);\r
+        mOAuthAuthEndpointText = (TextView)findViewById(R.id.oAuthEntryPoint_1);\r
+        mOAuthTokenEndpointText = (TextView)findViewById(R.id.oAuthEntryPoint_2);\r
+        mUsernameInput = (EditText) findViewById(R.id.account_username);\r
+        mPasswordInput = (EditText) findViewById(R.id.account_password);\r
+        mAuthStatusView = (TextView) findViewById(R.id.auth_status_text); \r
+        \r
+        /// step 1 - load and process relevant inputs (resources, intent, savedInstanceState)\r
+        String presetUserName = null;\r
+        boolean isPasswordExposed = false;\r
+        if (savedInstanceState == null) {\r
+            if (mAccount != null) {\r
+                presetUserName = mAccount.name.substring(0, mAccount.name.lastIndexOf('@'));\r
+            }\r
+            \r
+        } else {\r
+            isPasswordExposed = savedInstanceState.getBoolean(KEY_PASSWORD_EXPOSED, false);\r
+            mAuthStatusText = savedInstanceState.getInt(KEY_AUTH_STATUS_TEXT);\r
+            mAuthStatusIcon = savedInstanceState.getInt(KEY_AUTH_STATUS_ICON);\r
+            mAuthToken = savedInstanceState.getString(KEY_AUTH_TOKEN);\r
+        }\r
+        \r
+        /// step 2 - set properties of UI elements (text, visibility, enabled...)\r
+        mOAuth2Check.setChecked(\r
+                AccountTypeUtils.getAuthTokenTypeAccessToken(MainApp.getAccountType())\r
+                    .equals(mAuthTokenType));\r
+        if (presetUserName != null) {\r
+            mUsernameInput.setText(presetUserName);\r
+        }\r
+        if (mAction != ACTION_CREATE) {\r
+            mUsernameInput.setEnabled(false);\r
+            mUsernameInput.setFocusable(false);\r
+        }\r
+        mPasswordInput.setText(""); // clean password to avoid social hacking\r
+        if (isPasswordExposed) {\r
+            showPassword();\r
+        }\r
+        updateAuthenticationPreFragmentVisibility();\r
+        showAuthStatus();\r
+        mOkButton.setEnabled(mServerIsValid);\r
+\r
         \r
+        /// step 3 - bind listeners\r
+        // bindings for password input field\r
         mPasswordInput.setOnFocusChangeListener(this);\r
         mPasswordInput.setImeOptions(EditorInfo.IME_ACTION_DONE);\r
-        mPasswordInput.setOnEditorActionListener(this);
+        mPasswordInput.setOnEditorActionListener(this);\r
         mPasswordInput.setOnTouchListener(new RightDrawableOnTouchListener() {\r
             @Override\r
             public boolean onDrawableTouch(final MotionEvent event) {\r
@@ -365,110 +494,101 @@ implements  OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList
             }\r
         });\r
         \r
-        findViewById(R.id.scroll).setOnTouchListener(new OnTouchListener() {\r
-            @Override\r
-            public boolean onTouch(View view, MotionEvent event) {\r
-                if (event.getAction() == MotionEvent.ACTION_DOWN) {\r
-                    if (MainApp.getAuthTokenTypeSamlSessionCookie().equals(mAuthTokenType) &&\r
-                            mHostUrlInput.hasFocus()) {\r
-                        checkOcServer();\r
-                    }\r
-                }\r
-                return false;\r
-            }\r
-        });\r
     }\r
-    \r
-   \r
 \r
-    private void initAuthorizationMethod() {\r
-        boolean oAuthRequired = false;\r
-        boolean samlWebSsoRequired = false;\r
 \r
-        mAuthTokenType = getIntent().getExtras().getString(AccountAuthenticator.KEY_AUTH_TOKEN_TYPE);\r
-        mAccount = getIntent().getExtras().getParcelable(EXTRA_ACCOUNT);\r
-        \r
-        // TODO could be a good moment to validate the received token type, if not null\r
-        \r
-        if (mAuthTokenType == null) {    \r
-            if (mAccount != null) {\r
-                /// same authentication method than the one used to create the account to update\r
-                oAuthRequired = (mAccountMgr.getUserData(mAccount, AccountAuthenticator.KEY_SUPPORTS_OAUTH2) != null);\r
-                samlWebSsoRequired = (mAccountMgr.getUserData(mAccount, AccountAuthenticator.KEY_SUPPORTS_SAML_WEB_SSO) != null);\r
+    /**\r
+     * Changes the visibility of input elements depending on\r
+     * the current authorization method.\r
+     */\r
+    private void updateAuthenticationPreFragmentVisibility () {\r
+        if (AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(MainApp.getAccountType()).\r
+                equals(mAuthTokenType)) {\r
+            // SAML-based web Single Sign On\r
+            mOAuth2Check.setVisibility(View.GONE);\r
+            mOAuthAuthEndpointText.setVisibility(View.GONE);\r
+            mOAuthTokenEndpointText.setVisibility(View.GONE);\r
+            mUsernameInput.setVisibility(View.GONE);\r
+            mPasswordInput.setVisibility(View.GONE);\r
             \r
+        } else {\r
+            if (mAction == ACTION_CREATE && \r
+                    AUTH_OPTIONAL.equals(getString(R.string.auth_method_oauth2))) {\r
+                mOAuth2Check.setVisibility(View.VISIBLE);\r
             } else {\r
-                /// use the one set in setup.xml\r
-                oAuthRequired = AUTH_ON.equals(getString(R.string.auth_method_oauth2));\r
-                samlWebSsoRequired = AUTH_ON.equals(getString(R.string.auth_method_saml_web_sso));            \r
+                mOAuth2Check.setVisibility(View.GONE);\r
             }\r
-            if (oAuthRequired) {\r
-                mAuthTokenType = MainApp.getAuthTokenTypeAccessToken();\r
-            } else if (samlWebSsoRequired) {\r
-                mAuthTokenType = MainApp.getAuthTokenTypeSamlSessionCookie();\r
+            \r
+            if (AccountTypeUtils.getAuthTokenTypeAccessToken(MainApp.getAccountType()).\r
+                    equals(mAuthTokenType)) {\r
+                // OAuth 2 authorization\r
+                \r
+                mOAuthAuthEndpointText.setVisibility(View.VISIBLE);\r
+                mOAuthTokenEndpointText.setVisibility(View.VISIBLE);\r
+                mUsernameInput.setVisibility(View.GONE);\r
+                mPasswordInput.setVisibility(View.GONE);\r
+    \r
             } else {\r
-                mAuthTokenType = MainApp.getAuthTokenTypePass();\r
+                // basic HTTP authorization\r
+                mOAuthAuthEndpointText.setVisibility(View.GONE);\r
+                mOAuthTokenEndpointText.setVisibility(View.GONE);\r
+                mUsernameInput.setVisibility(View.VISIBLE);\r
+                mPasswordInput.setVisibility(View.VISIBLE);\r
             }\r
         }\r
-    \r
-        if (mAccount != null) {\r
-            String userName = mAccount.name.substring(0, mAccount.name.lastIndexOf('@'));\r
-            mUsernameInput.setText(userName);\r
-        }\r
-        \r
-        mOAuth2Check.setChecked(MainApp.getAuthTokenTypeAccessToken().equals(mAuthTokenType));\r
-        \r
     }\r
 \r
+\r
+\r
     /**\r
      * Saves relevant state before {@link #onPause()}\r
      * \r
-     * Do NOT save {@link #mNewCapturedUriFromOAuth2Redirection}; it keeps a temporal flag, intended to defer the \r
-     * processing of the redirection caught in {@link #onNewIntent(Intent)} until {@link #onResume()} \r
+     * Do NOT save {@link #mNewCapturedUriFromOAuth2Redirection}; it keeps a temporal flag, \r
+     * intended to defer the processing of the redirection caught in \r
+     * {@link #onNewIntent(Intent)} until {@link #onResume()} \r
      * \r
      * See {@link #loadSavedInstanceState(Bundle)}\r
      */\r
     @Override\r
     protected void onSaveInstanceState(Bundle outState) {\r
+        //Log_OC.wtf(TAG, "onSaveInstanceState init" );\r
         super.onSaveInstanceState(outState);\r
 \r
-        /// connection state and info\r
-        outState.putInt(KEY_AUTH_MESSAGE_VISIBILITY, mAuthMessage.getVisibility());\r
-        outState.putString(KEY_AUTH_MESSAGE_TEXT, mAuthMessage.getText().toString());\r
+        /// global state\r
+        outState.putString(KEY_AUTH_TOKEN_TYPE, mAuthTokenType);\r
+        outState.putLong(KEY_WAITING_FOR_OP_ID, mWaitingForOpId);\r
+\r
+        /// Server PRE-fragment state\r
         outState.putInt(KEY_SERVER_STATUS_TEXT, mServerStatusText);\r
         outState.putInt(KEY_SERVER_STATUS_ICON, mServerStatusIcon);\r
-        outState.putBoolean(KEY_SERVER_VALID, mServerIsValid);\r
         outState.putBoolean(KEY_SERVER_CHECKED, mServerIsChecked);\r
-        outState.putBoolean(KEY_SERVER_CHECK_IN_PROGRESS, (!mServerIsValid && mOcServerChkOperation != null));\r
-        outState.putBoolean(KEY_IS_SSL_CONN, mIsSslConn);\r
-        outState.putBoolean(KEY_PASSWORD_VISIBLE, isPasswordVisible());\r
+        outState.putBoolean(KEY_SERVER_VALID, mServerIsValid);\r
+        outState.putBoolean(KEY_IS_SSL_CONN, mServerInfo.mIsSslConn);\r
+        outState.putString(KEY_HOST_URL_TEXT, mServerInfo.mBaseUrl);\r
+        if (mServerInfo.mVersion != null) {\r
+            outState.putString(KEY_OC_VERSION, mServerInfo.mVersion.getVersion());\r
+        }\r
+        outState.putString(KEY_SERVER_AUTH_METHOD, mServerInfo.mAuthMethod.name());\r
+\r
+        /// Authentication PRE-fragment state\r
+        outState.putBoolean(KEY_PASSWORD_EXPOSED, isPasswordVisible());\r
         outState.putInt(KEY_AUTH_STATUS_ICON, mAuthStatusIcon);\r
         outState.putInt(KEY_AUTH_STATUS_TEXT, mAuthStatusText);\r
+        outState.putString(KEY_AUTH_TOKEN, mAuthToken);\r
 \r
-        /// server data\r
-        if (mDiscoveredVersion != null) {\r
-            outState.putString(KEY_OC_VERSION, mDiscoveredVersion.toString());\r
-        }\r
-        outState.putString(KEY_HOST_URL_TEXT, mHostBaseUrl);\r
-\r
-        /// account data, if updating\r
-        if (mAccount != null) {\r
-            outState.putParcelable(KEY_ACCOUNT, mAccount);\r
-        }\r
-        outState.putString(AccountAuthenticator.KEY_AUTH_TOKEN_TYPE, mAuthTokenType);\r
-        \r
-        // refresh button enabled\r
-        outState.putBoolean(KEY_REFRESH_BUTTON_ENABLED, (mRefreshButton.getVisibility() == View.VISIBLE));\r
-        \r
+        /// authentication\r
+        outState.putBoolean(KEY_AUTH_IS_FIRST_ATTEMPT_TAG, mIsFirstAuthAttempt);\r
 \r
+        //Log_OC.wtf(TAG, "onSaveInstanceState end" );\r
     }\r
 \r
 \r
     /**\r
-     * The redirection triggered by the OAuth authentication server as response to the GET AUTHORIZATION request\r
-     * is caught here.\r
+     * The redirection triggered by the OAuth authentication server as response to the \r
+     * GET AUTHORIZATION request is caught here.\r
      * \r
-     * To make this possible, this activity needs to be qualified with android:launchMode = "singleTask" in the\r
-     * AndroidManifest.xml file.\r
+     * To make this possible, this activity needs to be qualified with android:launchMode = \r
+     * "singleTask" in the AndroidManifest.xml file.\r
      */\r
     @Override\r
     protected void onNewIntent (Intent intent) {\r
@@ -481,31 +601,55 @@ implements  OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList
 \r
 \r
     /**\r
-     * The redirection triggered by the OAuth authentication server as response to the GET AUTHORIZATION, and \r
-     * deferred in {@link #onNewIntent(Intent)}, is processed here.\r
+     * The redirection triggered by the OAuth authentication server as response to the \r
+     * GET AUTHORIZATION, and deferred in {@link #onNewIntent(Intent)}, is processed here.\r
      */\r
     @Override\r
     protected void onResume() {\r
+        //Log_OC.wtf(TAG, "onResume init" );\r
         super.onResume();\r
-        if (mAction == ACTION_UPDATE_TOKEN && mJustCreated && getIntent().getBooleanExtra(EXTRA_ENFORCED_UPDATE, false)) {\r
-            if (MainApp.getAuthTokenTypeAccessToken().equals(mAuthTokenType)) {\r
-                //Toast.makeText(this, R.string.auth_expired_oauth_token_toast, Toast.LENGTH_LONG).show();\r
-                showAuthMessage(getString(R.string.auth_expired_oauth_token_toast));\r
-            } else if (MainApp.getAuthTokenTypeSamlSessionCookie().equals(mAuthTokenType)) {\r
-                //Toast.makeText(this, R.string.auth_expired_saml_sso_token_toast, Toast.LENGTH_LONG).show();\r
-                showAuthMessage(getString(R.string.auth_expired_saml_sso_token_toast));\r
-            } else {\r
-                //Toast.makeText(this, R.string.auth_expired_basic_auth_toast, Toast.LENGTH_LONG).show();\r
-                showAuthMessage(getString(R.string.auth_expired_basic_auth_toast));\r
-            }\r
-        }\r
-\r
+        \r
+        // bound here to avoid spurious changes triggered by Android on device rotations\r
+        mHostUrlInput.setOnFocusChangeListener(this);\r
+        mHostUrlInput.addTextChangedListener(mHostUrlInputWatcher);\r
+        \r
         if (mNewCapturedUriFromOAuth2Redirection != null) {\r
             getOAuth2AccessTokenFromCapturedRedirection();            \r
         }\r
+        \r
+        if (mOperationsServiceBinder != null) {\r
+            doOnResumeAndBound();\r
+        }\r
+        \r
+        //Log_OC.wtf(TAG, "onResume end" );\r
+    }\r
 \r
-        mJustCreated = false;\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
+        mHostUrlInput.removeTextChangedListener(mHostUrlInputWatcher);\r
+        mHostUrlInput.setOnFocusChangeListener(null);\r
+        \r
+        super.onPause();\r
+        //Log_OC.wtf(TAG, "onPause end" );\r
+    }\r
+    \r
+    @Override\r
+    protected void onDestroy() {\r
+\r
+        mHostUrlInputWatcher = null;\r
         \r
+        if (mOperationsServiceConnection != null) {\r
+            unbindService(mOperationsServiceConnection);\r
+            mOperationsServiceBinder = null;\r
+        }\r
+        super.onDestroy();\r
     }\r
 \r
 \r
@@ -519,16 +663,26 @@ implements  OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList
         mNewCapturedUriFromOAuth2Redirection = null;\r
 \r
         /// Showing the dialog with instructions for the user.\r
-        showDialog(DIALOG_OAUTH2_LOGIN_PROGRESS);\r
+        IndeterminateProgressDialog dialog = \r
+                IndeterminateProgressDialog.newInstance(R.string.auth_getting_authorization, true);\r
+        dialog.show(getSupportFragmentManager(), WAIT_DIALOG_TAG);\r
 \r
-        /// GET ACCESS TOKEN to the oAuth server \r
-        RemoteOperation operation = new OAuth2GetAccessToken(   getString(R.string.oauth2_client_id), \r
-                getString(R.string.oauth2_redirect_uri),       \r
-                getString(R.string.oauth2_grant_type),\r
+        /// GET ACCESS TOKEN to the oAuth server\r
+        Intent getServerInfoIntent = new Intent();\r
+        getServerInfoIntent.setAction(OperationsService.ACTION_OAUTH2_GET_ACCESS_TOKEN);\r
+        \r
+        getServerInfoIntent.putExtra(\r
+                OperationsService.EXTRA_SERVER_URL, \r
+                mOAuthTokenEndpointText.getText().toString().trim());\r
+        \r
+        getServerInfoIntent.putExtra(\r
+                OperationsService.EXTRA_OAUTH2_QUERY_PARAMETERS, \r
                 queryParameters);\r
-        //WebdavClient client = OwnCloudClientUtils.createOwnCloudClient(Uri.parse(getString(R.string.oauth2_url_endpoint_access)), getApplicationContext());\r
-        WebdavClient client = OwnCloudClientUtils.createOwnCloudClient(Uri.parse(mOAuthTokenEndpointText.getText().toString().trim()), getApplicationContext(), true);\r
-        operation.execute(client, this, mHandler);\r
+        \r
+        if (mOperationsServiceBinder != null) {\r
+            //Log_OC.wtf(TAG, "getting access token..." );\r
+            mWaitingForOpId = mOperationsServiceBinder.newOperation(getServerInfoIntent);\r
+        }\r
     }\r
 \r
 \r
@@ -542,7 +696,7 @@ implements  OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList
                 onUrlInputFocusLost((TextView) view);\r
             }\r
             else {\r
-                hideRefreshButton();\r
+                showRefreshButton(false);\r
             }\r
 \r
         } else if (view.getId() == R.id.account_password) {\r
@@ -563,36 +717,42 @@ implements  OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList
      * @param hostInput     TextView with the URL input field receiving the change of focus.\r
      */\r
     private void onUrlInputFocusLost(TextView hostInput) {\r
-        if (!mHostBaseUrl.equals(normalizeUrl(mHostUrlInput.getText().toString()))) {\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
             checkOcServer();\r
         } else {\r
             mOkButton.setEnabled(mServerIsValid);\r
-            if (!mServerIsValid) {\r
-                showRefreshButton();\r
-            }\r
+            showRefreshButton(!mServerIsValid);\r
         }\r
     }\r
 \r
 \r
     private void checkOcServer() {\r
-        String uri = trimUrlWebdav(mHostUrlInput.getText().toString().trim());\r
-        \r
-        if (!mHostUrlInputEnabled){\r
-            uri = getString(R.string.server_url);\r
-        }\r
-        \r
+        String uri = mHostUrlInput.getText().toString().trim();\r
         mServerIsValid = false;\r
         mServerIsChecked = false;\r
         mOkButton.setEnabled(false);\r
-        mDiscoveredVersion = null;\r
-        hideRefreshButton();\r
+        mServerInfo = new GetServerInfoOperation.ServerInfo();\r
+        showRefreshButton(false);\r
+        \r
         if (uri.length() != 0) {\r
             mServerStatusText = R.string.auth_testing_connection;\r
             mServerStatusIcon = R.drawable.progress_small;\r
             showServerStatus();\r
-            mOcServerChkOperation = new  OwnCloudServerCheckOperation(uri, this);\r
-            WebdavClient client = OwnCloudClientUtils.createOwnCloudClient(Uri.parse(uri), this, true);\r
-            mOperationThread = mOcServerChkOperation.execute(client, this, mHandler);\r
+            \r
+            Intent getServerInfoIntent = new Intent();\r
+            getServerInfoIntent.setAction(OperationsService.ACTION_GET_SERVER_INFO);\r
+            getServerInfoIntent.putExtra(\r
+                OperationsService.EXTRA_SERVER_URL, \r
+                normalizeUrlSuffix(uri)\r
+            );\r
+            if (mOperationsServiceBinder != null) {\r
+                mWaitingForOpId = mOperationsServiceBinder.newOperation(getServerInfoIntent);\r
+            } else {\r
+              Log_OC.wtf(TAG, "Server check tried with OperationService unbound!" );\r
+            }\r
+            \r
         } else {\r
             mServerStatusText = 0;\r
             mServerStatusIcon = 0;\r
@@ -622,49 +782,35 @@ implements  OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList
 \r
 \r
     private void showViewPasswordButton() {\r
-        //int drawable = android.R.drawable.ic_menu_view;\r
         int drawable = R.drawable.ic_view;\r
         if (isPasswordVisible()) {\r
-            //drawable = android.R.drawable.ic_secure;\r
             drawable = R.drawable.ic_hide;\r
         }\r
         mPasswordInput.setCompoundDrawablesWithIntrinsicBounds(0, 0, drawable, 0);\r
     }\r
 \r
     private boolean isPasswordVisible() {\r
-        return ((mPasswordInput.getInputType() & InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD) == InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD);\r
+        return ((mPasswordInput.getInputType() & InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD) == \r
+                InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD);\r
     }\r
-    \r
+\r
     private void hidePasswordButton() {\r
         mPasswordInput.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);\r
     }\r
 \r
     private void showPassword() {\r
-        mPasswordInput.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD);\r
+        mPasswordInput.setInputType(\r
+                InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD\r
+        );\r
         showViewPasswordButton();\r
     }\r
-    \r
+\r
     private void hidePassword() {\r
-        mPasswordInput.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);\r
+        mPasswordInput.setInputType(\r
+                InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD\r
+        );\r
         showViewPasswordButton();\r
     }\r
-    \r
-    \r
-    /**\r
-     * Cancels the authenticator activity\r
-     * \r
-     * IMPORTANT ENTRY POINT 3: Never underestimate the importance of cancellation\r
-     * \r
-     * This method is bound in the layout/acceoun_setup.xml resource file.\r
-     * \r
-     * @param view      Cancel button\r
-     */\r
-    public void onCancelClick(View view) {\r
-        setResult(RESULT_CANCELED);     // TODO review how is this related to AccountAuthenticator (debugging)\r
-        finish();\r
-    }\r
-\r
-\r
 \r
     /**\r
      * Checks the credentials of the user in the root of the ownCloud server\r
@@ -682,18 +828,25 @@ implements  OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList
      */\r
     public void onOkClick(View view) {\r
         // this check should be unnecessary\r
-        if (mDiscoveredVersion == null || !mDiscoveredVersion.isVersionValid()  || mHostBaseUrl == null || mHostBaseUrl.length() == 0) {\r
+        if (mServerInfo.mVersion == null || \r
+                !mServerInfo.mVersion.isVersionValid()  || \r
+                mServerInfo.mBaseUrl == null || \r
+                mServerInfo.mBaseUrl.length() == 0) {\r
             mServerStatusIcon = R.drawable.common_error;\r
             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
+            //Log_OC.wtf(TAG,  "The user was allowed to click 'connect' to an unchecked server!!");\r
             return;\r
         }\r
 \r
-        if (MainApp.getAuthTokenTypeAccessToken().equals(mAuthTokenType)) {\r
+        if (AccountTypeUtils.getAuthTokenTypeAccessToken(MainApp.getAccountType()).\r
+                equals(mAuthTokenType)) {\r
+            \r
             startOauthorization();\r
-        } else if (MainApp.getAuthTokenTypeSamlSessionCookie().equals(mAuthTokenType)) { \r
+        } else if (AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(MainApp.getAccountType()).\r
+                equals(mAuthTokenType)) {\r
+            \r
             startSamlBasedFederatedSingleSignOnAuthorization();\r
         } else {\r
             checkBasicAuthorization();\r
@@ -706,23 +859,34 @@ implements  OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList
      * the root folder of the ownCloud server.\r
      */\r
     private void checkBasicAuthorization() {\r
-        /// get the path to the root folder through WebDAV from the version server\r
-        String webdav_path = AccountUtils.getWebdavPath(mDiscoveredVersion, mAuthTokenType);\r
-\r
         /// get basic credentials entered by user\r
         String username = mUsernameInput.getText().toString();\r
         String password = mPasswordInput.getText().toString();\r
 \r
         /// be gentle with the user\r
-        showDialog(DIALOG_LOGIN_PROGRESS);\r
+        IndeterminateProgressDialog dialog = \r
+                IndeterminateProgressDialog.newInstance(R.string.auth_trying_to_login, true);\r
+        dialog.show(getSupportFragmentManager(), WAIT_DIALOG_TAG);\r
 \r
-        /// test credentials accessing the root folder\r
-        mAuthCheckOperation = new  ExistenceCheckOperation("", this, false);\r
-        WebdavClient client = OwnCloudClientUtils.createOwnCloudClient(Uri.parse(mHostBaseUrl + webdav_path), this, true);\r
-        client.setBasicCredentials(username, password);\r
-        mOperationThread = mAuthCheckOperation.execute(client, this, mHandler);\r
+        /// validate credentials accessing the root folder\r
+        accessRootFolderRemoteOperation(username, password);\r
+        \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.newOperation(existenceCheckIntent);\r
+        }\r
+    }\r
 \r
     /**\r
      * Starts the OAuth 'grant type' flow to get an access token, with \r
@@ -733,17 +897,22 @@ implements  OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList
         mAuthStatusIcon = R.drawable.progress_small;\r
         mAuthStatusText = R.string.oauth_login_connection;\r
         showAuthStatus();\r
-        \r
 \r
         // GET AUTHORIZATION request\r
-        //Uri uri = Uri.parse(getString(R.string.oauth2_url_endpoint_auth));\r
         Uri uri = Uri.parse(mOAuthAuthEndpointText.getText().toString().trim());\r
         Uri.Builder uriBuilder = uri.buildUpon();\r
-        uriBuilder.appendQueryParameter(OAuth2Constants.KEY_RESPONSE_TYPE, getString(R.string.oauth2_response_type));\r
-        uriBuilder.appendQueryParameter(OAuth2Constants.KEY_REDIRECT_URI, getString(R.string.oauth2_redirect_uri));   \r
-        uriBuilder.appendQueryParameter(OAuth2Constants.KEY_CLIENT_ID, getString(R.string.oauth2_client_id));\r
-        uriBuilder.appendQueryParameter(OAuth2Constants.KEY_SCOPE, getString(R.string.oauth2_scope));\r
-        //uriBuilder.appendQueryParameter(OAuth2Constants.KEY_STATE, whateverwewant);\r
+        uriBuilder.appendQueryParameter(\r
+                OAuth2Constants.KEY_RESPONSE_TYPE, getString(R.string.oauth2_response_type)\r
+        );\r
+        uriBuilder.appendQueryParameter(\r
+                OAuth2Constants.KEY_REDIRECT_URI, getString(R.string.oauth2_redirect_uri)\r
+        );   \r
+        uriBuilder.appendQueryParameter(\r
+                OAuth2Constants.KEY_CLIENT_ID, getString(R.string.oauth2_client_id)\r
+        );\r
+        uriBuilder.appendQueryParameter(\r
+                OAuth2Constants.KEY_SCOPE, getString(R.string.oauth2_scope)\r
+        );\r
         uri = uriBuilder.build();\r
         Log_OC.d(TAG, "Starting browser to view " + uri.toString());\r
         Intent i = new Intent(Intent.ACTION_VIEW, uri);\r
@@ -760,16 +929,13 @@ implements  OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList
         mAuthStatusIcon = R.drawable.progress_small;\r
         mAuthStatusText = R.string.auth_connecting_auth_server;\r
         showAuthStatus();\r
-        showDialog(DIALOG_LOGIN_PROGRESS);\r
-        \r
-        /// get the path to the root folder through WebDAV from the version server\r
-        String webdav_path = AccountUtils.getWebdavPath(mDiscoveredVersion, mAuthTokenType);\r
-\r
-        /// test credentials accessing the root folder\r
-        mAuthCheckOperation = new  ExistenceCheckOperation("", this, false);\r
-        WebdavClient client = OwnCloudClientUtils.createOwnCloudClient(Uri.parse(mHostBaseUrl + webdav_path), this, false);\r
-        mOperationThread = mAuthCheckOperation.execute(client, this, mHandler);\r
-      \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
     }\r
 \r
     /**\r
@@ -780,46 +946,91 @@ implements  OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList
     @Override\r
     public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationResult result) {\r
 \r
-        if (operation instanceof OwnCloudServerCheckOperation) {\r
-            onOcServerCheckFinish((OwnCloudServerCheckOperation) operation, result);\r
+        if (operation instanceof GetServerInfoOperation) {\r
+            if (operation.hashCode() == mWaitingForOpId) {\r
+                onGetServerInfoFinish(result);\r
+            }   // else nothing ; only the last check operation is considered; \r
+                // multiple can be started if the user amends a URL quickly\r
 \r
         } else if (operation instanceof OAuth2GetAccessToken) {\r
-            onGetOAuthAccessTokenFinish((OAuth2GetAccessToken)operation, result);\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 if (operation instanceof ExistenceCheckOperation)  {\r
-            if (MainApp.getAuthTokenTypeSamlSessionCookie().equals(mAuthTokenType)) {\r
-                onSamlBasedFederatedSingleSignOnAuthorizationStart(operation, result);\r
-                \r
             } else {\r
-                onAuthorizationCheckFinish((ExistenceCheckOperation)operation, result);\r
+                onAuthorizationCheckFinish(result);\r
             }\r
+        } else if (operation instanceof GetRemoteUserNameOperation) {\r
+            onGetUserNameFinish(result);\r
         }\r
+\r
     }\r
-    \r
-    \r
-    private void onSamlBasedFederatedSingleSignOnAuthorizationStart(RemoteOperation operation, RemoteOperationResult result) {\r
-        try {\r
-            dismissDialog(DIALOG_LOGIN_PROGRESS);\r
-        } catch (IllegalArgumentException e) {\r
-            // NOTHING TO DO ; can't find out what situation that leads to the exception in this code, but user logs signal that it happens\r
+\r
+    private void onGetUserNameFinish(RemoteOperationResult result) {\r
+        mWaitingForOpId = Long.MAX_VALUE;\r
+        if (result.isSuccess()) {\r
+            boolean success = false;\r
+            String username = (String) result.getData().get(0);\r
+\r
+            if ( mAction == ACTION_CREATE) {\r
+                mUsernameInput.setText(username);\r
+                success = createAccount();\r
+            } else {\r
+\r
+                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
+                }\r
+            }\r
+\r
+            if (success)\r
+                finish();\r
+        } else {\r
+            updateStatusIconFailUserName();\r
+            showAuthStatus();\r
+            Log_OC.e(TAG, "Access to user name failed: " + result.getLogMessage());\r
         }\r
-        
-        //if (result.isTemporalRedirection() && result.isIdPRedirection()) {\r
+\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 = mHostBaseUrl + AccountUtils.getWebdavPath(mDiscoveredVersion, mAuthTokenType);\r
-            \r
+            String targetUrl = mServerInfo.mBaseUrl \r
+                    + AccountUtils.getWebdavPath(mServerInfo.mVersion, mAuthTokenType);\r
+\r
             // Show dialog\r
-            mSamlDialog = SamlWebViewDialog.newInstance(url, targetUrl);            \r
-            mSamlDialog.show(getSupportFragmentManager(), TAG_SAML_DIALOG);\r
-            \r
+            SamlWebViewDialog dialog = SamlWebViewDialog.newInstance(url, targetUrl);            \r
+            dialog.show(getSupportFragmentManager(), SAML_DIALOG_TAG);\r
+\r
             mAuthStatusIcon = 0;\r
             mAuthStatusText = 0;\r
-            \r
+\r
         } else {\r
             mAuthStatusIcon = R.drawable.common_error;\r
             mAuthStatusText = R.string.auth_unsupported_auth_method;\r
-            \r
+\r
         }\r
         showAuthStatus();\r
     }\r
@@ -832,65 +1043,91 @@ implements  OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList
      * @param operation     Server check performed.\r
      * @param result        Result of the check.\r
      */\r
-    private void onOcServerCheckFinish(OwnCloudServerCheckOperation operation, RemoteOperationResult result) {\r
-        if (operation.equals(mOcServerChkOperation)) {\r
-            /// save result state\r
-            mServerIsChecked = true;\r
-            mServerIsValid = result.isSuccess();\r
-            mIsSslConn = (result.getCode() == ResultCode.OK_SSL);\r
-            mOcServerChkOperation = null;\r
+    private void onGetServerInfoFinish(RemoteOperationResult result) {\r
+        /// update activity state\r
+        mServerIsChecked = true;\r
+        mWaitingForOpId = Long.MAX_VALUE;\r
+        \r
+        // update server status, but don't show it yet\r
+        updateServerStatusIconAndText(result);\r
 \r
-            /// update status icon and text\r
-            if (mServerIsValid) {\r
-                hideRefreshButton();\r
-            } else {\r
-                showRefreshButton();\r
-            }\r
-            updateServerStatusIconAndText(result);\r
-            showServerStatus();\r
+        if (result.isSuccess()) {\r
+            /// SUCCESS means:\r
+            //      1. connection succeeded, and we know if it's SSL or not\r
+            //      2. server is installed\r
+            //      3. we got the server version\r
+            //      4. we got the authentication method required by the server \r
+            mServerInfo = (GetServerInfoOperation.ServerInfo) (result.getData().get(0));\r
+            \r
+            if (!authSupported(mServerInfo.mAuthMethod)) {\r
+                \r
+                updateServerStatusIconNoRegularAuth();  // overrides updateServerStatusIconAndText()  \r
+                mServerIsValid = false;\r
 \r
-            /// very special case (TODO: move to a common place for all the remote operations)\r
-            if (result.getCode() == ResultCode.SSL_RECOVERABLE_PEER_UNVERIFIED) {\r
-                mLastSslUntrustedServerResult = result;\r
-                showDialog(DIALOG_SSL_VALIDATOR); \r
+            } else {\r
+                mServerIsValid = true;\r
             }\r
+            \r
+        } else {\r
+            mServerIsValid = false;\r
+        }\r
 \r
-            /// retrieve discovered version and normalize server URL\r
-            mDiscoveredVersion = operation.getDiscoveredVersion();\r
-            mHostBaseUrl = normalizeUrl(mHostUrlInput.getText().toString());\r
+        // refresh UI\r
+        showRefreshButton(!mServerIsValid);\r
+        showServerStatus();\r
+        mOkButton.setEnabled(mServerIsValid);\r
+        \r
+        /// very special case (TODO: move to a common place for all the remote operations)\r
+        if (result.getCode() == ResultCode.SSL_RECOVERABLE_PEER_UNVERIFIED) {\r
+            showUntrustedCertDialog(result);\r
+        }\r
+    }\r
 \r
-            /// allow or not the user try to access the server\r
-            mOkButton.setEnabled(mServerIsValid);\r
 \r
-        }   // else nothing ; only the last check operation is considered; \r
-        // multiple can be triggered if the user amends a URL before a previous check can be triggered\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
+        );\r
     }\r
 \r
 \r
-    private String normalizeUrl(String url) {\r
+    // TODO remove, if possible\r
+    private String normalizeUrl(String url, boolean sslWhenUnprefixed) {\r
         if (url != null && url.length() > 0) {\r
             url = url.trim();\r
             if (!url.toLowerCase().startsWith("http://") &&\r
                     !url.toLowerCase().startsWith("https://")) {\r
-                if (mIsSslConn) {\r
+                if (sslWhenUnprefixed) {\r
                     url = "https://" + url;\r
                 } else {\r
                     url = "http://" + url;\r
                 }\r
             }\r
-\r
-            // OC-208: Add suffix remote.php/webdav to normalize (OC-34)            \r
-            url = trimUrlWebdav(url);\r
-\r
-            if (url.endsWith("/")) {\r
-                url = url.substring(0, url.length() - 1);\r
-            }\r
-\r
+        \r
+            url = normalizeUrlSuffix(url);\r
         }\r
         return (url != null ? url : "");\r
     }\r
+    \r
+    \r
+    private String normalizeUrlSuffix(String url) {\r
+        if (url.endsWith("/")) {\r
+            url = url.substring(0, url.length() - 1);\r
+        }\r
+        url = trimUrlWebdav(url);\r
+        return url;\r
+    }\r
 \r
 \r
+    // TODO remove, if possible\r
     private String trimUrlWebdav(String url){       \r
         if(url.toLowerCase().endsWith(AccountUtils.WEBDAV_PATH_4_0)){\r
             url = url.substring(0, url.length() - AccountUtils.WEBDAV_PATH_4_0.length());             \r
@@ -901,8 +1138,8 @@ implements  OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList
         } \r
         return (url != null ? url : "");\r
     }\r
-    \r
-    \r
+\r
+\r
     /**\r
      * Chooses the right icon and text to show to the user for the received operation result.\r
      * \r
@@ -973,6 +1210,10 @@ implements  OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList
         case UNKNOWN_ERROR:\r
             mServerStatusText = R.string.auth_unknown_error_title;\r
             break;\r
+        case OK_REDIRECT_TO_NON_SECURE_CONNECTION:\r
+            mServerStatusIcon = android.R.drawable.ic_partial_secure;\r
+            mServerStatusText = R.string.auth_redirect_non_secure_connection_title;\r
+            break;\r
         default:\r
             mServerStatusText = 0;\r
             mServerStatusIcon = 0;\r
@@ -1063,32 +1304,39 @@ implements  OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList
     }\r
 \r
 \r
+    private void updateStatusIconFailUserName(){\r
+        mAuthStatusIcon = R.drawable.common_error;\r
+        mAuthStatusText = R.string.auth_fail_get_user_name;\r
+    }\r
+\r
+    private void updateServerStatusIconNoRegularAuth(){\r
+        mServerStatusIcon = R.drawable.common_error;\r
+        mServerStatusText = R.string.auth_can_not_auth_against_server;\r
+    }\r
+\r
     /**\r
      * Processes the result of the request for and access token send \r
      * to an OAuth authorization server.\r
      * \r
-     * @param operation     Operation performed requesting the access token.\r
      * @param result        Result of the operation.\r
      */\r
-    private void onGetOAuthAccessTokenFinish(OAuth2GetAccessToken operation, RemoteOperationResult result) {\r
-        try {\r
-            dismissDialog(DIALOG_OAUTH2_LOGIN_PROGRESS);\r
-        } catch (IllegalArgumentException e) {\r
-            // NOTHING TO DO ; can't find out what situation that leads to the exception in this code, but user logs signal that it happens\r
-        }\r
+    private void onGetOAuthAccessTokenFinish(RemoteOperationResult result) {\r
+        mWaitingForOpId = Long.MAX_VALUE;\r
+        dismissDialog(WAIT_DIALOG_TAG);\r
 \r
-        String webdav_path = AccountUtils.getWebdavPath(mDiscoveredVersion, mAuthTokenType);\r
-        if (result.isSuccess() && webdav_path != null) {\r
+        if (result.isSuccess()) {\r
             /// be gentle with the user\r
-            showDialog(DIALOG_LOGIN_PROGRESS);\r
+            IndeterminateProgressDialog dialog = \r
+                    IndeterminateProgressDialog.newInstance(R.string.auth_trying_to_login, true);\r
+            dialog.show(getSupportFragmentManager(), WAIT_DIALOG_TAG);\r
 \r
             /// time to test the retrieved access token on the ownCloud server\r
-            mAuthToken = ((OAuth2GetAccessToken)operation).getResultTokenMap().get(OAuth2Constants.KEY_ACCESS_TOKEN);\r
+            @SuppressWarnings("unchecked")\r
+            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
-            mAuthCheckOperation = new ExistenceCheckOperation("", this, false);\r
-            WebdavClient client = OwnCloudClientUtils.createOwnCloudClient(Uri.parse(mHostBaseUrl + webdav_path), this, true);\r
-            client.setBearerCredentials(mAuthToken);\r
-            mAuthCheckOperation.execute(client, this, mHandler);\r
+            \r
+            accessRootFolderRemoteOperation("", "");\r
 \r
         } else {\r
             updateAuthStatusIconAndText(result);\r
@@ -1106,12 +1354,9 @@ implements  OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList
      * @param operation     Access check performed.\r
      * @param result        Result of the operation.\r
      */\r
-    private void onAuthorizationCheckFinish(ExistenceCheckOperation operation, RemoteOperationResult result) {\r
-        try {\r
-            dismissDialog(DIALOG_LOGIN_PROGRESS);\r
-        } catch (IllegalArgumentException e) {\r
-            // NOTHING TO DO ; can't find out what situation that leads to the exception in this code, but user logs signal that it happens\r
-        }\r
+    private void onAuthorizationCheckFinish(RemoteOperationResult result) {\r
+        mWaitingForOpId = Long.MAX_VALUE;\r
+        dismissDialog(WAIT_DIALOG_TAG);\r
 \r
         if (result.isSuccess()) {\r
             Log_OC.d(TAG, "Successful access - time to save the account");\r
@@ -1121,21 +1366,20 @@ implements  OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList
                 success = createAccount();\r
 \r
             } else {\r
-                success = updateToken();\r
+                updateToken();\r
+                success = true;\r
             }\r
 \r
             if (success) {\r
                 finish();\r
             }\r
-\r
-        } else if (result.isServerFail() || result.isException()) {\r
-            /// if server fail or exception in authorization, the UI is updated as when a server check failed\r
+            \r
+        } else if (result.isServerFail() || result.isException()) {
+            /// server errors or exceptions in authorization take to requiring a new check of \r
+            /// the server\r
             mServerIsChecked = true;\r
             mServerIsValid = false;\r
-            mIsSslConn = false;\r
-            mOcServerChkOperation = null;\r
-            mDiscoveredVersion = null;\r
-            mHostBaseUrl = normalizeUrl(mHostUrlInput.getText().toString());\r
+            mServerInfo = new GetServerInfoOperation.ServerInfo();  \r
 \r
             // update status icon and text\r
             updateServerStatusIconAndText(result);\r
@@ -1143,15 +1387,14 @@ implements  OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList
             mAuthStatusIcon = 0;\r
             mAuthStatusText = 0;\r
             showAuthStatus();\r
-            \r
+\r
             // update input controls state\r
-            showRefreshButton();\r
+            showRefreshButton(true);\r
             mOkButton.setEnabled(false);\r
 \r
-            // very special case (TODO: move to a common place for all the remote operations) (dangerous here?)\r
+            // very special case (TODO: move to a common place for all the remote operations)\r
             if (result.getCode() == ResultCode.SSL_RECOVERABLE_PEER_UNVERIFIED) {\r
-                mLastSslUntrustedServerResult = result;\r
-                showDialog(DIALOG_SSL_VALIDATOR); \r
+                showUntrustedCertDialog(result);\r
             }\r
 \r
         } else {    // authorization fail due to client side - probably wrong credentials\r
@@ -1159,47 +1402,41 @@ implements  OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList
             showAuthStatus();\r
             Log_OC.d(TAG, "Access failed: " + result.getLogMessage());\r
         }\r
-\r
     }\r
 \r
 \r
+\r
+\r
     /**\r
-     * Sets the proper response to get that the Account Authenticator that started this activity saves \r
-     * a new authorization token for mAccount.\r
+     * Sets the proper response to get that the Account Authenticator that started this activity \r
+     * saves a new authorization token for mAccount.\r
      */\r
-    private boolean updateToken() {\r
+    private void updateToken() {\r
         Bundle response = new Bundle();\r
         response.putString(AccountManager.KEY_ACCOUNT_NAME, mAccount.name);\r
         response.putString(AccountManager.KEY_ACCOUNT_TYPE, mAccount.type);\r
-        \r
-        if (MainApp.getAuthTokenTypeAccessToken().equals(mAuthTokenType)) { \r
+\r
+        if (AccountTypeUtils.getAuthTokenTypeAccessToken(MainApp.getAccountType()).\r
+                equals(mAuthTokenType)) { \r
             response.putString(AccountManager.KEY_AUTHTOKEN, mAuthToken);\r
-            // the next line is necessary; by now, notifications are calling directly to the AuthenticatorActivity to update, without AccountManager intervention\r
+            // the next line is necessary, notifications are calling directly to the \r
+            // AuthenticatorActivity to update, without AccountManager intervention\r
             mAccountMgr.setAuthToken(mAccount, mAuthTokenType, mAuthToken);\r
-            \r
-        } else if (MainApp.getAuthTokenTypeSamlSessionCookie().equals(mAuthTokenType)) {\r
-            String username = getUserNameForSamlSso();\r
-            if (!mUsernameInput.getText().toString().equals(username)) {\r
-                // fail - not a new account, but an existing one; disallow\r
-                RemoteOperationResult result = new RemoteOperationResult(ResultCode.ACCOUNT_NOT_THE_SAME); \r
-                updateAuthStatusIconAndText(result);\r
-                showAuthStatus();\r
-                Log_OC.d(TAG, result.getLogMessage());\r
-                \r
-                return false;\r
-            }\r
-            \r
+\r
+        } else if (AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(MainApp.getAccountType()).\r
+                equals(mAuthTokenType)) {\r
+\r
             response.putString(AccountManager.KEY_AUTHTOKEN, mAuthToken);\r
-            // the next line is necessary; by now, notifications are calling directly to the AuthenticatorActivity to update, without AccountManager intervention\r
+            // the next line is necessary; by now, notifications are calling directly to the \r
+            // AuthenticatorActivity to update, without AccountManager intervention\r
             mAccountMgr.setAuthToken(mAccount, mAuthTokenType, mAuthToken);\r
-            \r
+\r
         } else {\r
             response.putString(AccountManager.KEY_AUTHTOKEN, mPasswordInput.getText().toString());\r
             mAccountMgr.setPassword(mAccount, mPasswordInput.getText().toString());\r
         }\r
         setAccountAuthenticatorResult(response);\r
-        \r
-        return true;\r
+\r
     }\r
 \r
 \r
@@ -1212,38 +1449,39 @@ implements  OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList
      */\r
     private boolean createAccount() {\r
         /// create and save new ownCloud account\r
-        boolean isOAuth = MainApp.getAuthTokenTypeAccessToken().equals(mAuthTokenType);\r
-        boolean isSaml =  MainApp.getAuthTokenTypeSamlSessionCookie().equals(mAuthTokenType);\r
+        boolean isOAuth = AccountTypeUtils.\r
+                getAuthTokenTypeAccessToken(MainApp.getAccountType()).equals(mAuthTokenType);\r
+        boolean isSaml =  AccountTypeUtils.\r
+                getAuthTokenTypeSamlSessionCookie(MainApp.getAccountType()).equals(mAuthTokenType);\r
 \r
-        Uri uri = Uri.parse(mHostBaseUrl);\r
+        Uri uri = Uri.parse(mServerInfo.mBaseUrl);\r
         String username = mUsernameInput.getText().toString().trim();\r
-        if (isSaml) {\r
-            username = getUserNameForSamlSso();\r
-            \r
-        } else if (isOAuth) {\r
+        if (isOAuth) {\r
             username = "OAuth_user" + (new java.util.Random(System.currentTimeMillis())).nextLong();\r
-        }            \r
-        String accountName = username + "@" + uri.getHost();\r
-        if (uri.getPort() >= 0) {\r
-            accountName += ":" + uri.getPort();\r
         }\r
-        mAccount = new Account(accountName, MainApp.getAccountType());\r
-        if (AccountUtils.exists(mAccount, getApplicationContext())) {\r
+        String accountName = com.owncloud.android.lib.common.accounts.AccountUtils.\r
+                buildAccountName(uri, username);\r
+        Account newAccount = new Account(accountName, MainApp.getAccountType());\r
+        if (AccountUtils.exists(newAccount, getApplicationContext())) {\r
             // fail - not a new account, but an existing one; disallow\r
             RemoteOperationResult result = new RemoteOperationResult(ResultCode.ACCOUNT_NOT_NEW); \r
             updateAuthStatusIconAndText(result);\r
             showAuthStatus();\r
             Log_OC.d(TAG, result.getLogMessage());\r
             return false;\r
-            \r
+\r
         } else {\r
-        \r
+            mAccount = newAccount;\r
+            \r
             if (isOAuth || isSaml) {\r
-                mAccountMgr.addAccountExplicitly(mAccount, "", null);  // with external authorizations, the password is never input in the app\r
+                // with external authorizations, the password is never input in the app\r
+                mAccountMgr.addAccountExplicitly(mAccount, "", null);  \r
             } else {\r
-                mAccountMgr.addAccountExplicitly(mAccount, mPasswordInput.getText().toString(), null);\r
+                mAccountMgr.addAccountExplicitly(\r
+                        mAccount, mPasswordInput.getText().toString(), null\r
+                );\r
             }\r
-    \r
+\r
             /// add the new account as default in preferences, if there is none already\r
             Account defaultAccount = AccountUtils.getCurrentOwnCloudAccount(this);\r
             if (defaultAccount == null) {\r
@@ -1252,9 +1490,10 @@ implements  OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList
                 editor.putString("select_oc_account", accountName);\r
                 editor.commit();\r
             }\r
-    \r
+\r
             /// prepare result to return to the Authenticator\r
-            //  TODO check again what the Authenticator makes with it; probably has the same effect as addAccountExplicitly, but it's not well done\r
+            //  TODO check again what the Authenticator makes with it; probably has the same \r
+            //  effect as addAccountExplicitly, but it's not well done\r
             final Intent intent = new Intent();       \r
             intent.putExtra(AccountManager.KEY_ACCOUNT_TYPE,    MainApp.getAccountType());\r
             intent.putExtra(AccountManager.KEY_ACCOUNT_NAME,    mAccount.name);\r
@@ -1264,127 +1503,26 @@ implements  OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList
             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 addAccountExplicitly, or in KEY_USERDATA\r
-            mAccountMgr.setUserData(mAccount, AccountAuthenticator.KEY_OC_VERSION,    mDiscoveredVersion.toString());\r
-            mAccountMgr.setUserData(mAccount, AccountAuthenticator.KEY_OC_BASE_URL,   mHostBaseUrl);\r
+            /// add user data to the new account; TODO probably can be done in the last parameter \r
+            //      addAccountExplicitly, or in KEY_USERDATA
+            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
+
             if (isSaml) {\r
-                mAccountMgr.setUserData(mAccount, AccountAuthenticator.KEY_SUPPORTS_SAML_WEB_SSO, "TRUE"); \r
+                mAccountMgr.setUserData(mAccount, Constants.KEY_SUPPORTS_SAML_WEB_SSO, "TRUE"); \r
             } else if (isOAuth) {\r
-                mAccountMgr.setUserData(mAccount, AccountAuthenticator.KEY_SUPPORTS_OAUTH2, "TRUE");  \r
+                mAccountMgr.setUserData(mAccount, Constants.KEY_SUPPORTS_OAUTH2, "TRUE");  \r
             }\r
-    \r
+\r
             setAccountAuthenticatorResult(intent.getExtras());\r
             setResult(RESULT_OK, intent);\r
-    \r
-            return true;\r
-        }\r
-    }\r
-\r
-    \r
-    private String getUserNameForSamlSso() {\r
-        if (mAuthToken != null) {\r
-            String [] cookies = mAuthToken.split(";");\r
-            for (int i=0; i<cookies.length; i++) {\r
-                if (cookies[i].startsWith(KEY_OC_USERNAME_EQUALS )) {\r
-                    String value = Uri.decode(cookies[i].substring(KEY_OC_USERNAME_EQUALS.length()));\r
-                    return value;\r
-                }\r
-            }\r
-        }\r
-        return "";\r
-    }\r
-\r
-\r
-    /**\r
-     * {@inheritDoc}\r
-     * \r
-     * Necessary to update the contents of the SSL Dialog\r
-     * \r
-     * TODO move to some common place for all possible untrusted SSL failures\r
-     */\r
-    @Override\r
-    protected void onPrepareDialog(int id, Dialog dialog, Bundle args) {\r
-        switch (id) {\r
-        case DIALOG_LOGIN_PROGRESS:\r
-        case DIALOG_CERT_NOT_SAVED:\r
-        case DIALOG_OAUTH2_LOGIN_PROGRESS:\r
-            break;\r
-        case DIALOG_SSL_VALIDATOR: {\r
-            ((SslValidatorDialog)dialog).updateResult(mLastSslUntrustedServerResult);\r
-            break;\r
-        }\r
-        default:\r
-            Log_OC.e(TAG, "Incorrect dialog called with id = " + id);\r
-        }\r
-    }\r
 \r
-\r
-    /**\r
-     * {@inheritDoc}\r
-     */\r
-    @Override\r
-    protected Dialog onCreateDialog(int id) {\r
-        Dialog dialog = null;\r
-        switch (id) {\r
-        case DIALOG_LOGIN_PROGRESS: {\r
-            /// simple progress dialog\r
-            ProgressDialog working_dialog = new ProgressDialog(this);\r
-            working_dialog.setMessage(getResources().getString(R.string.auth_trying_to_login));\r
-            working_dialog.setIndeterminate(true);\r
-            working_dialog.setCancelable(true);\r
-            working_dialog\r
-            .setOnCancelListener(new DialogInterface.OnCancelListener() {\r
-                @Override\r
-                public void onCancel(DialogInterface dialog) {\r
-                    /// TODO study if this is enough\r
-                    Log_OC.i(TAG, "Login canceled");\r
-                    if (mOperationThread != null) {\r
-                        mOperationThread.interrupt();\r
-                        finish();\r
-                    }\r
-                }\r
-            });\r
-            dialog = working_dialog;\r
-            break;\r
-        }\r
-        case DIALOG_OAUTH2_LOGIN_PROGRESS: {\r
-            ProgressDialog working_dialog = new ProgressDialog(this);\r
-            working_dialog.setMessage(String.format("Getting authorization")); \r
-            working_dialog.setIndeterminate(true);\r
-            working_dialog.setCancelable(true);\r
-            working_dialog\r
-            .setOnCancelListener(new DialogInterface.OnCancelListener() {\r
-                @Override\r
-                public void onCancel(DialogInterface dialog) {\r
-                    Log_OC.i(TAG, "Login canceled");\r
-                    finish();\r
-                }\r
-            });\r
-            dialog = working_dialog;\r
-            break;\r
-        }\r
-        case DIALOG_SSL_VALIDATOR: {\r
-            /// TODO start to use new dialog interface, at least for this (it is a FragmentDialog already)\r
-            dialog = SslValidatorDialog.newInstance(this, mLastSslUntrustedServerResult, this);\r
-            break;\r
-        }\r
-        case DIALOG_CERT_NOT_SAVED: {\r
-            AlertDialog.Builder builder = new AlertDialog.Builder(this);\r
-            builder.setMessage(getResources().getString(R.string.ssl_validator_not_saved));\r
-            builder.setCancelable(false);\r
-            builder.setPositiveButton(R.string.common_ok, new DialogInterface.OnClickListener() {\r
-                @Override\r
-                public void onClick(DialogInterface dialog, int which) {\r
-                    dialog.dismiss();\r
-                };\r
-            });\r
-            dialog = builder.create();\r
-            break;\r
-        }\r
-        default:\r
-            Log_OC.e(TAG, "Incorrect dialog called with id = " + id);\r
+            return true;\r
         }\r
-        return dialog;\r
     }\r
 \r
 \r
@@ -1394,7 +1532,9 @@ implements  OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList
      * @param view      'Account register' button\r
      */\r
     public void onRegisterClick(View view) {\r
-        Intent register = new Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.welcome_link_url)));\r
+        Intent register = new Intent(\r
+                Intent.ACTION_VIEW, Uri.parse(getString(R.string.welcome_link_url))\r
+        );\r
         setResult(RESULT_CANCELED);\r
         startActivity(register);\r
     }\r
@@ -1403,17 +1543,18 @@ implements  OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList
     /**\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
     private void showServerStatus() {\r
-        TextView tv = (TextView) findViewById(R.id.server_status_text);\r
-\r
         if (mServerStatusIcon == 0 && mServerStatusText == 0) {\r
-            tv.setVisibility(View.INVISIBLE);\r
+            mServerStatusView.setVisibility(View.INVISIBLE);\r
 \r
         } else {\r
-            tv.setText(mServerStatusText);\r
-            tv.setCompoundDrawablesWithIntrinsicBounds(mServerStatusIcon, 0, 0, 0);\r
-            tv.setVisibility(View.VISIBLE);\r
+            mServerStatusView.setText(mServerStatusText);\r
+            mServerStatusView.setCompoundDrawablesWithIntrinsicBounds(mServerStatusIcon, 0, 0, 0);\r
+            mServerStatusView.setVisibility(View.VISIBLE);\r
         }\r
 \r
     }\r
@@ -1425,22 +1566,22 @@ implements  OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList
      */\r
     private void showAuthStatus() {\r
         if (mAuthStatusIcon == 0 && mAuthStatusText == 0) {\r
-            mAuthStatusLayout.setVisibility(View.INVISIBLE);\r
+            mAuthStatusView.setVisibility(View.INVISIBLE);\r
 \r
         } else {\r
-            mAuthStatusLayout.setText(mAuthStatusText);\r
-            mAuthStatusLayout.setCompoundDrawablesWithIntrinsicBounds(mAuthStatusIcon, 0, 0, 0);\r
-            mAuthStatusLayout.setVisibility(View.VISIBLE);\r
+            mAuthStatusView.setText(mAuthStatusText);\r
+            mAuthStatusView.setCompoundDrawablesWithIntrinsicBounds(mAuthStatusIcon, 0, 0, 0);\r
+            mAuthStatusView.setVisibility(View.VISIBLE);\r
         }\r
     }     \r
 \r
 \r
-    private void showRefreshButton() {\r
-        mRefreshButton.setVisibility(View.VISIBLE);\r
-    }\r
-\r
-    private void hideRefreshButton() {\r
-        mRefreshButton.setVisibility(View.GONE);\r
+    private void showRefreshButton (boolean show) {\r
+        if (show)  {\r
+            mRefreshButton.setVisibility(View.VISIBLE);\r
+        } else {\r
+            mRefreshButton.setVisibility(View.GONE);\r
+        }\r
     }\r
 \r
     /**\r
@@ -1453,8 +1594,8 @@ implements  OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList
     public void onRefreshClick(View view) {\r
         checkOcServer();\r
     }\r
-    \r
-    \r
+\r
+\r
     /**\r
      * Called when the eye icon in the password field is clicked.\r
      * \r
@@ -1482,73 +1623,32 @@ implements  OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList
     public void onCheckClick(View view) {\r
         CheckBox oAuth2Check = (CheckBox)view;\r
         if (oAuth2Check.isChecked()) {\r
-            mAuthTokenType = MainApp.getAuthTokenTypeAccessToken();\r
-        } else {\r
-            mAuthTokenType = MainApp.getAuthTokenTypePass();\r
-        }\r
-        adaptViewAccordingToAuthenticationMethod();\r
-    }\r
-\r
-    \r
-    /**\r
-     * Changes the visibility of input elements depending on\r
-     * the current authorization method.\r
-     */\r
-    private void adaptViewAccordingToAuthenticationMethod () {\r
-        if (MainApp.getAuthTokenTypeAccessToken().equals(mAuthTokenType)) {\r
-            // OAuth 2 authorization\r
-            mOAuthAuthEndpointText.setVisibility(View.VISIBLE);\r
-            mOAuthTokenEndpointText.setVisibility(View.VISIBLE);\r
-            mUsernameInput.setVisibility(View.GONE);\r
-            mPasswordInput.setVisibility(View.GONE);\r
-            \r
-        } else if (MainApp.getAuthTokenTypeSamlSessionCookie().equals(mAuthTokenType)) {\r
-            // SAML-based web Single Sign On\r
-            mOAuthAuthEndpointText.setVisibility(View.GONE);\r
-            mOAuthTokenEndpointText.setVisibility(View.GONE);\r
-            mUsernameInput.setVisibility(View.GONE);\r
-            mPasswordInput.setVisibility(View.GONE);\r
+            mAuthTokenType = AccountTypeUtils.getAuthTokenTypeAccessToken(MainApp.getAccountType());\r
         } else {\r
-            // basic HTTP authorization\r
-            mOAuthAuthEndpointText.setVisibility(View.GONE);\r
-            mOAuthTokenEndpointText.setVisibility(View.GONE);\r
-            mUsernameInput.setVisibility(View.VISIBLE);\r
-            mPasswordInput.setVisibility(View.VISIBLE);\r
+            mAuthTokenType = AccountTypeUtils.getAuthTokenTypePass(MainApp.getAccountType());\r
         }\r
-    }\r
-    \r
-    /**\r
-     * Called from SslValidatorDialog when a new server certificate was correctly saved.\r
-     */\r
-    public void onSavedCertificate() {\r
-        checkOcServer();\r
-    }\r
-\r
-    /**\r
-     * Called from SslValidatorDialog when a new server certificate could not be saved \r
-     * when the user requested it.\r
-     */\r
-    @Override\r
-    public void onFailedSavingCertificate() {\r
-        showDialog(DIALOG_CERT_NOT_SAVED);\r
+        updateAuthenticationPreFragmentVisibility();\r
     }\r
 \r
 \r
     /**\r
      *  Called when the 'action' button in an IME is pressed ('enter' in software keyboard).\r
      * \r
-     *  Used to trigger the authentication check when the user presses 'enter' after writing the password, \r
-     *  or to throw the server test when the only field on screen is the URL input field.\r
+     *  Used to trigger the authentication check when the user presses 'enter' after writing the \r
+     *  password, or to throw the server test when the only field on screen is the URL input field.\r
      */\r
     @Override\r
     public boolean onEditorAction(TextView inputField, int actionId, KeyEvent event) {\r
-        if (actionId == EditorInfo.IME_ACTION_DONE && inputField != null && inputField.equals(mPasswordInput)) {\r
+        if (actionId == EditorInfo.IME_ACTION_DONE && inputField != null && \r
+                inputField.equals(mPasswordInput)) {\r
             if (mOkButton.isEnabled()) {\r
                 mOkButton.performClick();\r
             }\r
-            \r
-        } else if (actionId == EditorInfo.IME_ACTION_NEXT && inputField != null && inputField.equals(mHostUrlInput)) {\r
-            if (MainApp.getAuthTokenTypeSamlSessionCookie().equals(mAuthTokenType)) {\r
+\r
+        } else if (actionId == EditorInfo.IME_ACTION_NEXT && inputField != null && \r
+                inputField.equals(mHostUrlInput)) {\r
+            if (AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(MainApp.getAccountType()).\r
+                    equals(mAuthTokenType)) {\r
                 checkOcServer();\r
             }\r
         }\r
@@ -1559,7 +1659,7 @@ implements  OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList
     private abstract static class RightDrawableOnTouchListener implements OnTouchListener  {\r
 \r
         private int fuzz = 75;\r
-        \r
+\r
         /**\r
          * {@inheritDoc}\r
          */\r
@@ -1576,9 +1676,11 @@ implements  OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList
                 final int x = (int) event.getX();\r
                 final int y = (int) event.getY();\r
                 final Rect bounds = rightDrawable.getBounds();\r
-                if (x >= (view.getRight() - bounds.width() - fuzz) && x <= (view.getRight() - view.getPaddingRight() + fuzz)\r
-                    && y >= (view.getPaddingTop() - fuzz) && y <= (view.getHeight() - view.getPaddingBottom()) + fuzz) {\r
-                    \r
+                if (    x >= (view.getRight() - bounds.width() - fuzz) && \r
+                        x <= (view.getRight() - view.getPaddingRight() + fuzz) && \r
+                        y >= (view.getPaddingTop() - fuzz) &&\r
+                        y <= (view.getHeight() - view.getPaddingBottom()) + fuzz) {\r
+\r
                     return onDrawableTouch(event);\r
                 }\r
             }\r
@@ -1589,35 +1691,27 @@ implements  OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList
     }\r
 \r
 \r
-    public void onSamlDialogSuccess(String sessionCookie){\r
-        mAuthToken = sessionCookie;\r
+    private void getRemoteUserNameOperation(String sessionCookie, boolean followRedirects) {\r
         \r
-        if (sessionCookie != null && sessionCookie.length() > 0) {\r
-            mAuthToken = sessionCookie;\r
-            boolean success = false;\r
-            if (mAction == ACTION_CREATE) {\r
-                success = createAccount();\r
+        Intent getUserNameIntent = new Intent();\r
+        getUserNameIntent.setAction(OperationsService.ACTION_GET_USER_NAME);\r
+        getUserNameIntent.putExtra(OperationsService.EXTRA_SERVER_URL, mServerInfo.mBaseUrl);\r
+        getUserNameIntent.putExtra(OperationsService.EXTRA_COOKIE, sessionCookie);\r
         \r
-            } else {\r
-                success = updateToken();\r
-            }\r
-            if (success) {\r
-                finish();\r
-            }\r
+        if (mOperationsServiceBinder != null) {\r
+            //Log_OC.wtf(TAG, "starting getRemoteUserNameOperation..." );\r
+            mWaitingForOpId = mOperationsServiceBinder.newOperation(getUserNameIntent);\r
         }\r
-\r
-            \r
     }\r
 \r
 \r
     @Override\r
-    public void onSsoFinished(String sessionCookies) {\r
-        //Toast.makeText(this, "got cookies: " + sessionCookie, Toast.LENGTH_LONG).show();\r
-\r
-        if (sessionCookies != null && sessionCookies.length() > 0) {\r
+    public void onSsoFinished(String sessionCookie) {\r
+        if (sessionCookie != null && sessionCookie.length() > 0) {\r
             Log_OC.d(TAG, "Successful SSO - time to save the account");\r
-            onSamlDialogSuccess(sessionCookies);\r
-            Fragment fd = getSupportFragmentManager().findFragmentByTag(TAG_SAML_DIALOG);\r
+            mAuthToken = sessionCookie;\r
+            getRemoteUserNameOperation(sessionCookie, true);\r
+            Fragment fd = getSupportFragmentManager().findFragmentByTag(SAML_DIALOG_TAG);\r
             if (fd != null && fd instanceof SherlockDialogFragment) {\r
                 Dialog d = ((SherlockDialogFragment)fd).getDialog();\r
                 if (d != null && d.isShowing()) {\r
@@ -1629,28 +1723,169 @@ implements  OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList
             // TODO - show fail\r
             Log_OC.d(TAG, "SSO failed");\r
         }\r
-    \r
-    }\r
-    \r
-    /** Show auth_message \r
-     * \r
-     * @param message\r
-     */\r
-    private void showAuthMessage(String message) {\r
-       mAuthMessage.setVisibility(View.VISIBLE);\r
-       mAuthMessage.setText(message);\r
-    }\r
-    \r
-    private void hideAuthMessage() {\r
-        mAuthMessage.setVisibility(View.GONE);\r
+\r
     }\r
 \r
     @Override\r
     public boolean onTouchEvent(MotionEvent event) {\r
-        if (MainApp.getAuthTokenTypeSamlSessionCookie().equals(mAuthTokenType) &&\r
+        if (AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(MainApp.getAccountType()).\r
+                equals(mAuthTokenType) &&\r
                 mHostUrlInput.hasFocus() && event.getAction() == MotionEvent.ACTION_DOWN) {\r
             checkOcServer();\r
         }\r
         return super.onTouchEvent(event);\r
     }\r
+\r
+\r
+    /**\r
+     * Show untrusted cert dialog \r
+     */\r
+    public void showUntrustedCertDialog(\r
+            X509Certificate x509Certificate, SslError error, SslErrorHandler handler\r
+        ) {\r
+        // Show a dialog with the certificate info\r
+        SslUntrustedCertDialog dialog = null;\r
+        if (x509Certificate == null) {\r
+            dialog = SslUntrustedCertDialog.newInstanceForEmptySslError(error, handler);\r
+        } else {\r
+            dialog = SslUntrustedCertDialog.\r
+                    newInstanceForFullSslError(x509Certificate, error, handler);\r
+        }\r
+        FragmentManager fm = getSupportFragmentManager();\r
+        FragmentTransaction ft = fm.beginTransaction();\r
+        ft.addToBackStack(null);\r
+        dialog.show(ft, UNTRUSTED_CERT_DIALOG_TAG);\r
+    }\r
+\r
+\r
+    /**\r
+     * Show untrusted cert dialog \r
+     */\r
+    private void showUntrustedCertDialog(RemoteOperationResult result) {\r
+        // Show a dialog with the certificate info\r
+        SslUntrustedCertDialog dialog = SslUntrustedCertDialog.\r
+                newInstanceForFullSslError((CertificateCombinedException)result.getException());\r
+        FragmentManager fm = getSupportFragmentManager();\r
+        FragmentTransaction ft = fm.beginTransaction();\r
+        ft.addToBackStack(null);\r
+        dialog.show(ft, UNTRUSTED_CERT_DIALOG_TAG);\r
+\r
+    }\r
+\r
+    /**\r
+     * Called from SslValidatorDialog when a new server certificate was correctly saved.\r
+     */\r
+    public void onSavedCertificate() {\r
+        Fragment fd = getSupportFragmentManager().findFragmentByTag(SAML_DIALOG_TAG);\r
+        if (fd == null) {\r
+            // if SAML dialog is not shown, \r
+            // the SslDialog was shown due to an SSL error in the server check\r
+            checkOcServer();\r
+        }\r
+    }\r
+\r
+    /**\r
+     * Called from SslValidatorDialog when a new server certificate could not be saved \r
+     * when the user requested it.\r
+     */\r
+    @Override\r
+    public void onFailedSavingCertificate() {\r
+        dismissDialog(SAML_DIALOG_TAG);\r
+        Toast.makeText(this, R.string.ssl_validator_not_saved, Toast.LENGTH_LONG).show();\r
+    }\r
+\r
+    @Override\r
+    public void onCancelCertificate() {\r
+        dismissDialog(SAML_DIALOG_TAG);\r
+    }\r
+\r
+\r
+    private void doOnResumeAndBound() {\r
+        //Log_OC.wtf(TAG, "registering to listen for operation callbacks" );\r
+        mOperationsServiceBinder.addOperationListener(AuthenticatorActivity.this, mHandler);\r
+        if (mWaitingForOpId <= Integer.MAX_VALUE) {\r
+            mOperationsServiceBinder.dispatchResultIfFinished((int)mWaitingForOpId, this);\r
+        }\r
+        \r
+        if (mPendingAutoCheck) {\r
+            checkOcServer();\r
+        }\r
+    }\r
+\r
+    \r
+    private void dismissDialog(String dialogTag){\r
+        Fragment frag = getSupportFragmentManager().findFragmentByTag(dialogTag);\r
+        if (frag != null && frag instanceof SherlockDialogFragment) {\r
+            SherlockDialogFragment dialog = (SherlockDialogFragment) frag;\r
+            dialog.dismiss();\r
+        }\r
+    }\r
+    \r
+    \r
+    /** \r
+     * Implements callback methods for service binding. \r
+     */\r
+    private class OperationsServiceConnection implements ServiceConnection {\r
+\r
+        @Override\r
+        public void onServiceConnected(ComponentName component, IBinder service) {\r
+            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
+                \r
+            } else {\r
+                return;\r
+            }\r
+            \r
+        }\r
+\r
+        @Override\r
+        public void onServiceDisconnected(ComponentName component) {\r
+            if (component.equals(\r
+                    new ComponentName(AuthenticatorActivity.this, OperationsService.class)\r
+                )) {\r
+                Log_OC.e(TAG, "Operations service crashed");\r
+                mOperationsServiceBinder = null;\r
+            }\r
+        }\r
+    \r
+    }\r
+\r
+    /**\r
+     * Create and show dialog for request authentication to the user\r
+     * @param webView\r
+     * @param handler\r
+     */\r
+    public void createAuthenticationDialog(WebView webView, HttpAuthHandler handler) {\r
+\r
+        // Show a dialog with the certificate info\r
+        CredentialsDialogFragment dialog = \r
+                CredentialsDialogFragment.newInstanceForCredentials(webView, handler);\r
+        FragmentManager fm = getSupportFragmentManager();\r
+        FragmentTransaction ft = fm.beginTransaction();\r
+        ft.addToBackStack(null);\r
+        dialog.setCancelable(false);\r
+        dialog.show(ft, CREDENTIALS_DIALOG_TAG);\r
+\r
+        if (!mIsFirstAuthAttempt) {\r
+            Toast.makeText(\r
+                    getApplicationContext(), \r
+                    getText(R.string.saml_authentication_wrong_pass), \r
+                    Toast.LENGTH_LONG\r
+            ).show();\r
+        } else {\r
+            mIsFirstAuthAttempt = false;\r
+        }\r
+    }\r
+\r
+    /**\r
+     * For retrieving the clicking on authentication cancel button\r
+     */\r
+    public void doNegativeAuthenticatioDialogClick(){\r
+        mIsFirstAuthAttempt = true;\r
+    }\r
 }\r
index 5c97931..b90ab85 100644 (file)
 
 package com.owncloud.android.authentication;
 
+import java.io.ByteArrayInputStream;
 import java.lang.ref.WeakReference;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
 
-import com.owncloud.android.Log_OC;
-
+import com.owncloud.android.lib.common.network.NetworkUtils;
+import com.owncloud.android.lib.common.utils.Log_OC;
 
+import android.content.Context;
 import android.graphics.Bitmap;
+import android.net.http.SslCertificate;
+import android.net.http.SslError;
+import android.os.Bundle;
 import android.os.Handler;
 import android.os.Message;
+import android.view.KeyEvent;
 import android.view.View;
 import android.webkit.CookieManager;
+import android.webkit.HttpAuthHandler;
+import android.webkit.SslErrorHandler;
+import android.webkit.WebResourceResponse;
 import android.webkit.WebView;
 import android.webkit.WebViewClient;
 
@@ -48,12 +61,15 @@ public class SsoWebViewClient extends WebViewClient {
         public void onSsoFinished(String sessionCookie);
     }
     
+    private Context mContext;
     private Handler mListenerHandler;
     private WeakReference<SsoWebViewClientListener> mListenerRef;
     private String mTargetUrl;
     private String mLastReloadedUrlAtError;
+
     
-    public SsoWebViewClient (Handler listenerHandler, SsoWebViewClientListener listener) {
+    public SsoWebViewClient (Context context, Handler listenerHandler, SsoWebViewClientListener listener) {
+        mContext = context;
         mListenerHandler = listenerHandler;
         mListenerRef = new WeakReference<SsoWebViewClient.SsoWebViewClientListener>(listener);
         mTargetUrl = "fake://url.to.be.set";
@@ -71,6 +87,7 @@ public class SsoWebViewClient extends WebViewClient {
     @Override
     public void onPageStarted (WebView view, String url, Bitmap favicon) {
         Log_OC.d(TAG, "onPageStarted : " + url);
+        view.clearCache(true);
         super.onPageStarted(view, url, favicon);
     }
     
@@ -107,7 +124,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() {
@@ -115,29 +132,73 @@ public class SsoWebViewClient extends WebViewClient {
                     public void run() {
                         SsoWebViewClientListener listener = mListenerRef.get();
                         if (listener != null) {
+                               // Send Cookies to the listener
                             listener.onSsoFinished(cookies);
                         }
                     }
                 });
             }
-        }
-
+        } 
     }
     
-    /*
+    
     @Override
     public void doUpdateVisitedHistory (WebView view, String url, boolean isReload) {
         Log_OC.d(TAG, "doUpdateVisitedHistory : " + url);
     }
     
     @Override
-    public void onReceivedSslError (WebView view, SslErrorHandler handler, SslError error) {
+    public void onReceivedSslError (final WebView view, final SslErrorHandler handler, SslError error) {
         Log_OC.d(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) {
+                Log_OC.e(TAG, "Exception: " + e.getMessage());
+            }
+        }
+        
+         if (isKnownServer) {
+             handler.proceed();
+         } else {
+             ((AuthenticatorActivity)mContext).showUntrustedCertDialog(x509Certificate, error, handler);
+         }
+    }
+    
+    /**
+     * Obtain the X509Certificate from SslError
+     * @param   error     SslError
+     * @return  X509Certificate from error
+     */
+    public X509Certificate getX509CertificateFromError (SslError error) {
+        Bundle bundle = SslCertificate.saveState(error.getCertificate());
+        X509Certificate x509Certificate;
+        byte[] bytes = bundle.getByteArray("x509-certificate");
+        if (bytes == null) {
+            x509Certificate = null;
+        } else {
+            try {
+                CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
+                Certificate cert = certFactory.generateCertificate(new ByteArrayInputStream(bytes));
+                x509Certificate = (X509Certificate) cert;
+            } catch (CertificateException e) {
+                x509Certificate = null;
+            }
+        }        
+        return x509Certificate;
     }
     
     @Override
     public void onReceivedHttpAuthRequest (WebView view, HttpAuthHandler handler, String host, String realm) {
         Log_OC.d(TAG, "onReceivedHttpAuthRequest : " + host);
+
+        ((AuthenticatorActivity)mContext).createAuthenticationDialog(view, handler);
     }
 
     @Override
@@ -172,5 +233,4 @@ public class SsoWebViewClient extends WebViewClient {
         Log_OC.d(TAG, "shouldOverrideKeyEvent : " + event);
         return false;
     }
-    */
 }
index 0ad985e..5b1bef1 100644 (file)
@@ -1,6 +1,6 @@
 /* ownCloud Android client application
  *   Copyright (C) 2012  Bartek Przybylski
- *   Copyright (C) 2012-2013 ownCloud Inc.
+ *   Copyright (C) 2012-2014 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 +25,12 @@ import java.util.Collections;
 import java.util.Iterator;
 import java.util.Vector;
 
-import com.owncloud.android.Log_OC;
 import com.owncloud.android.MainApp;
 import com.owncloud.android.db.ProviderMeta.ProviderTableMeta;
+import com.owncloud.android.lib.common.utils.Log_OC;
+import com.owncloud.android.lib.resources.shares.OCShare;
+import com.owncloud.android.lib.resources.shares.ShareType;
+import com.owncloud.android.lib.resources.files.FileUtils;
 import com.owncloud.android.utils.FileStorageUtils;
 
 
@@ -148,7 +151,7 @@ public class FileDataStorageManager {
     public Vector<OCFile> getFolderImages(OCFile folder) {
         Vector<OCFile> ret = new Vector<OCFile>(); 
         if (folder != null) {
-            // TODO better implementation, filtering in the access to database (if possible) instead of here 
+            // TODO better implementation, filtering in the access to database instead of here 
             Vector<OCFile> tmp = getFolderContent(folder);
             OCFile current = null; 
             for (int i=0; i<tmp.size(); i++) {
@@ -166,7 +169,10 @@ public class FileDataStorageManager {
         boolean overriden = false;
         ContentValues cv = new ContentValues();
         cv.put(ProviderTableMeta.FILE_MODIFIED, file.getModificationTimestamp());
-        cv.put(ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA, file.getModificationTimestampAtLastSyncForData());
+        cv.put( 
+            ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA, 
+            file.getModificationTimestampAtLastSyncForData()
+        );
         cv.put(ProviderTableMeta.FILE_CREATION, file.getCreationTimestamp());
         cv.put(ProviderTableMeta.FILE_CONTENT_LENGTH, file.getFileLength());
         cv.put(ProviderTableMeta.FILE_CONTENT_TYPE, file.getMimetype());
@@ -181,10 +187,15 @@ public class FileDataStorageManager {
         cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA, file.getLastSyncDateForData());
         cv.put(ProviderTableMeta.FILE_KEEP_IN_SYNC, file.keepInSync() ? 1 : 0);
         cv.put(ProviderTableMeta.FILE_ETAG, file.getEtag());
-
+        cv.put(ProviderTableMeta.FILE_SHARE_BY_LINK, file.isShareByLink() ? 1 : 0);
+        cv.put(ProviderTableMeta.FILE_PUBLIC_LINK, file.getPublicLink());
+        cv.put(ProviderTableMeta.FILE_PERMISSIONS, file.getPermissions());
+        cv.put(ProviderTableMeta.FILE_REMOTE_ID, file.getRemoteId());
+        cv.put(ProviderTableMeta.FILE_UPDATE_THUMBNAIL, file.needsUpdateThumbnail());
+        
         boolean sameRemotePath = fileExists(file.getRemotePath());
         if (sameRemotePath ||
-                fileExists(file.getFileId())        ) {           // for renamed files; no more delete and create
+                fileExists(file.getFileId())        ) {  // for renamed files
 
             OCFile oldFile = null;
             if (sameRemotePath) {
@@ -232,11 +243,11 @@ public class FileDataStorageManager {
             }            
         }
 
-        if (file.isFolder()) {
-            updateFolderSize(file.getFileId());
-        } else {
-            updateFolderSize(file.getParentId());
-        }
+//        if (file.isFolder()) {
+//            updateFolderSize(file.getFileId());
+//        } else {
+//            updateFolderSize(file.getParentId());
+//        }
         
         return overriden;
     }
@@ -252,17 +263,24 @@ public class FileDataStorageManager {
      * @param files
      * @param removeNotUpdated
      */
-    public void saveFolder(OCFile folder, Collection<OCFile> updatedFiles, Collection<OCFile> filesToRemove) {
+    public void saveFolder(
+            OCFile folder, Collection<OCFile> updatedFiles, Collection<OCFile> filesToRemove
+        ) {
         
-        Log_OC.d(TAG,  "Saving folder " + folder.getRemotePath() + " with " + updatedFiles.size() + " children and " + filesToRemove.size() + " files to remove");
+        Log_OC.d(TAG,  "Saving folder " + folder.getRemotePath() + " with " + updatedFiles.size() 
+                + " children and " + filesToRemove.size() + " files to remove");
 
-        ArrayList<ContentProviderOperation> operations = new ArrayList<ContentProviderOperation>(updatedFiles.size());
+        ArrayList<ContentProviderOperation> operations = 
+                new ArrayList<ContentProviderOperation>(updatedFiles.size());
 
         // prepare operations to insert or update files to save in the given folder
         for (OCFile file : updatedFiles) {
             ContentValues cv = new ContentValues();
             cv.put(ProviderTableMeta.FILE_MODIFIED, file.getModificationTimestamp());
-            cv.put(ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA, file.getModificationTimestampAtLastSyncForData());
+            cv.put(
+                ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA, 
+                file.getModificationTimestampAtLastSyncForData()
+            );
             cv.put(ProviderTableMeta.FILE_CREATION, file.getCreationTimestamp());
             cv.put(ProviderTableMeta.FILE_CONTENT_LENGTH, file.getFileLength());
             cv.put(ProviderTableMeta.FILE_CONTENT_TYPE, file.getMimetype());
@@ -278,6 +296,10 @@ public class FileDataStorageManager {
             cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA, file.getLastSyncDateForData());
             cv.put(ProviderTableMeta.FILE_KEEP_IN_SYNC, file.keepInSync() ? 1 : 0);
             cv.put(ProviderTableMeta.FILE_ETAG, file.getEtag());
+            cv.put(ProviderTableMeta.FILE_SHARE_BY_LINK, file.isShareByLink() ? 1 : 0);
+            cv.put(ProviderTableMeta.FILE_PUBLIC_LINK, file.getPublicLink());
+            cv.put(ProviderTableMeta.FILE_PERMISSIONS, file.getPermissions());
+            cv.put(ProviderTableMeta.FILE_REMOTE_ID, file.getRemoteId());
 
             boolean existsByPath = fileExists(file.getRemotePath());
             if (existsByPath || fileExists(file.getFileId())) {
@@ -290,29 +312,40 @@ public class FileDataStorageManager {
 
             } else {
                 // adding a new file
-                operations.add(ContentProviderOperation.newInsert(ProviderTableMeta.CONTENT_URI).withValues(cv).build());
+                operations.add(ContentProviderOperation.newInsert(ProviderTableMeta.CONTENT_URI).
+                        withValues(cv).build());
             }
         }
         
         // prepare operations to remove files in the given folder
-        String where = ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?" + " AND " + ProviderTableMeta.FILE_PATH + "=?";
+        String where = ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?" + " AND " + 
+                ProviderTableMeta.FILE_PATH + "=?";
         String [] whereArgs = null;
         for (OCFile file : filesToRemove) {
             if (file.getParentId() == folder.getFileId()) {
                 whereArgs = new String[]{mAccount.name, file.getRemotePath()};
                 //Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_FILE, "" + file.getFileId());
                 if (file.isFolder()) {
-                    operations.add(ContentProviderOperation
-                                    .newDelete(ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_DIR, file.getFileId())).withSelection(where, whereArgs)
-                                        .build());
-                    // TODO remove local folder
+                    operations.add(ContentProviderOperation.newDelete(
+                            ContentUris.withAppendedId(
+                                    ProviderTableMeta.CONTENT_URI_DIR, file.getFileId()
+                            )
+                    ).withSelection(where, whereArgs).build());
+                    
+                    File localFolder = 
+                            new File(FileStorageUtils.getDefaultSavePathFor(mAccount.name, file));
+                    if (localFolder.exists()) {
+                        removeLocalFolder(localFolder);
+                    }
                 } else {
-                    operations.add(ContentProviderOperation
-                                    .newDelete(ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_FILE, file.getFileId())).withSelection(where, whereArgs)
-                                        .build());
+                    operations.add(ContentProviderOperation.newDelete(
+                            ContentUris.withAppendedId(
+                                    ProviderTableMeta.CONTENT_URI_FILE, file.getFileId()
+                            )
+                    ).withSelection(where, whereArgs).build());
+                    
                     if (file.isDown()) {
                         new File(file.getStoragePath()).delete();
-                        // TODO move the deletion of local contents after success of deletions
                     }
                 }
             }
@@ -321,9 +354,12 @@ public class FileDataStorageManager {
         // update metadata of folder
         ContentValues cv = new ContentValues();
         cv.put(ProviderTableMeta.FILE_MODIFIED, folder.getModificationTimestamp());
-        cv.put(ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA, folder.getModificationTimestampAtLastSyncForData());
+        cv.put(
+            ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA, 
+            folder.getModificationTimestampAtLastSyncForData()
+        );
         cv.put(ProviderTableMeta.FILE_CREATION, folder.getCreationTimestamp());
-        cv.put(ProviderTableMeta.FILE_CONTENT_LENGTH, 0);   // FileContentProvider calculates the right size
+        cv.put(ProviderTableMeta.FILE_CONTENT_LENGTH, 0);
         cv.put(ProviderTableMeta.FILE_CONTENT_TYPE, folder.getMimetype());
         cv.put(ProviderTableMeta.FILE_NAME, folder.getFileName());
         cv.put(ProviderTableMeta.FILE_PARENT, folder.getParentId());
@@ -333,6 +369,11 @@ public class FileDataStorageManager {
         cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA, folder.getLastSyncDateForData());
         cv.put(ProviderTableMeta.FILE_KEEP_IN_SYNC, folder.keepInSync() ? 1 : 0);
         cv.put(ProviderTableMeta.FILE_ETAG, folder.getEtag());
+        cv.put(ProviderTableMeta.FILE_SHARE_BY_LINK, folder.isShareByLink() ? 1 : 0);
+        cv.put(ProviderTableMeta.FILE_PUBLIC_LINK, folder.getPublicLink());
+        cv.put(ProviderTableMeta.FILE_PERMISSIONS, folder.getPermissions());
+        cv.put(ProviderTableMeta.FILE_REMOTE_ID, folder.getRemoteId());
+        
         operations.add(ContentProviderOperation.newUpdate(ProviderTableMeta.CONTENT_URI).
                 withValues(cv).
                 withSelection(  ProviderTableMeta._ID + "=?", 
@@ -378,64 +419,72 @@ public class FileDataStorageManager {
             }
         }
         
-        updateFolderSize(folder.getFileId());
+        //updateFolderSize(folder.getFileId());
         
     }
 
 
-    /**
-     * 
-     * @param id
-     */
-    private void updateFolderSize(long id) {
-        if (id > FileDataStorageManager.ROOT_PARENT_ID) {
-            Log_OC.d(TAG, "Updating size of " + id);
-            if (getContentResolver() != null) {
-                getContentResolver().update(ProviderTableMeta.CONTENT_URI_DIR, 
-                        new ContentValues(),    // won't be used, but cannot be null; crashes in KLP
-                        ProviderTableMeta._ID + "=?",
-                        new String[] { String.valueOf(id) });
-            } else {
-                try {
-                    getContentProviderClient().update(ProviderTableMeta.CONTENT_URI_DIR, 
-                            new ContentValues(),    // won't be used, but cannot be null; crashes in KLP
-                            ProviderTableMeta._ID + "=?",
-                            new String[] { String.valueOf(id) });
-                    
-                } catch (RemoteException e) {
-                    Log_OC.e(TAG, "Exception in update of folder size through compatibility patch " + e.getMessage());
-                }
-            }
-        } else {
-            Log_OC.e(TAG,  "not updating size for folder " + id);
-        }
-    }
+//    /**
+//     * 
+//     * @param id
+//     */
+//    private void updateFolderSize(long id) {
+//        if (id > FileDataStorageManager.ROOT_PARENT_ID) {
+//            Log_OC.d(TAG, "Updating size of " + id);
+//            if (getContentResolver() != null) {
+//                getContentResolver().update(ProviderTableMeta.CONTENT_URI_DIR, 
+//                        new ContentValues(),    
+                            // won't be used, but cannot be null; crashes in KLP
+//                        ProviderTableMeta._ID + "=?",
+//                        new String[] { String.valueOf(id) });
+//            } else {
+//                try {
+//                    getContentProviderClient().update(ProviderTableMeta.CONTENT_URI_DIR, 
+//                            new ContentValues(),    
+                                // won't be used, but cannot be null; crashes in KLP
+//                            ProviderTableMeta._ID + "=?",
+//                            new String[] { String.valueOf(id) });
+//                    
+//                } catch (RemoteException e) {
+//                    Log_OC.e(
+//    TAG, "Exception in update of folder size through compatibility patch " + e.getMessage());
+//                }
+//            }
+//        } else {
+//            Log_OC.e(TAG,  "not updating size for folder " + id);
+//        }
+//    }
     
 
-    public void removeFile(OCFile file, boolean removeDBData, boolean removeLocalCopy) {
+    public boolean removeFile(OCFile file, boolean removeDBData, boolean removeLocalCopy) {
+        boolean success = true;
         if (file != null) {
             if (file.isFolder()) {
-                removeFolder(file, removeDBData, removeLocalCopy);
+                success = removeFolder(file, removeDBData, removeLocalCopy);
                 
             } else {
                 if (removeDBData) {
-                    //Uri file_uri = Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_FILE, ""+file.getFileId());
-                    Uri file_uri = ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_FILE, file.getFileId());
-                    String where = ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?" + " AND " + ProviderTableMeta.FILE_PATH + "=?";
+                    Uri file_uri = ContentUris.withAppendedId(
+                        ProviderTableMeta.CONTENT_URI_FILE, 
+                        file.getFileId()
+                    );
+                    String where = ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?" + " AND " + 
+                            ProviderTableMeta.FILE_PATH + "=?";
                     String [] whereArgs = new String[]{mAccount.name, file.getRemotePath()};
+                    int deleted = 0;
                     if (getContentProviderClient() != null) {
                         try {
-                            getContentProviderClient().delete(file_uri, where, whereArgs);
+                            deleted = getContentProviderClient().delete(file_uri, where, whereArgs);
                         } catch (RemoteException e) {
                             e.printStackTrace();
                         }
                     } else {
-                        getContentResolver().delete(file_uri, where, whereArgs);
+                        deleted = getContentResolver().delete(file_uri, where, whereArgs);
                     }
-                    updateFolderSize(file.getParentId());
+                    success &= (deleted > 0); 
                 }
-                if (removeLocalCopy && file.isDown()) {
-                    boolean success = new File(file.getStoragePath()).delete();
+                if (removeLocalCopy && file.isDown() && file.getStoragePath() != null && success) {
+                    success = new File(file.getStoragePath()).delete();
                     if (!removeDBData && success) {
                         // maybe unnecessary, but should be checked TODO remove if unnecessary
                         file.setStoragePath(null);
@@ -444,51 +493,86 @@ public class FileDataStorageManager {
                 }
             }
         }
+        return success;
     }
     
 
-    public void removeFolder(OCFile folder, boolean removeDBData, boolean removeLocalContent) {
+    public boolean removeFolder(OCFile folder, boolean removeDBData, boolean removeLocalContent) {
+        boolean success = true;
         if (folder != null && folder.isFolder()) {
             if (removeDBData &&  folder.getFileId() != -1) {
-                removeFolderInDb(folder);
+                success = removeFolderInDb(folder);
             }
-            if (removeLocalContent) {
-                File localFolder = new File(FileStorageUtils.getDefaultSavePathFor(mAccount.name, folder));
-                removeLocalFolder(localFolder);
+            if (removeLocalContent && success) {
+                success = removeLocalFolder(folder);
             }
         }
+        return success;
     }
 
-    private void removeFolderInDb(OCFile folder) {
-        Uri folder_uri = Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_DIR, ""+ folder.getFileId());   // URI for recursive deletion
-        String where = ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?" + " AND " + ProviderTableMeta.FILE_PATH + "=?";
+    private boolean removeFolderInDb(OCFile folder) {
+        Uri folder_uri = Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_DIR, "" + 
+                folder.getFileId());   // URI for recursive deletion
+        String where = ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?" + " AND " + 
+                ProviderTableMeta.FILE_PATH + "=?";
         String [] whereArgs = new String[]{mAccount.name, folder.getRemotePath()};
+        int deleted = 0;
         if (getContentProviderClient() != null) {
             try {
-                getContentProviderClient().delete(folder_uri, where, whereArgs);
+                deleted = getContentProviderClient().delete(folder_uri, where, whereArgs);
             } catch (RemoteException e) {
                 e.printStackTrace();
             }
         } else {
-            getContentResolver().delete(folder_uri, where, whereArgs); 
+            deleted = getContentResolver().delete(folder_uri, where, whereArgs); 
         }
-        updateFolderSize(folder.getParentId());
+        return deleted > 0;
     }
 
-    private void removeLocalFolder(File folder) {
-        if (folder.exists()) {
-            File[] files = folder.listFiles();
+    private boolean removeLocalFolder(OCFile folder) {
+        boolean success = true;
+        File localFolder = new File(FileStorageUtils.getDefaultSavePathFor(mAccount.name, folder));
+        if (localFolder.exists()) {
+            // stage 1: remove the local files already registered in the files database
+            Vector<OCFile> files = getFolderContent(folder.getFileId());
             if (files != null) {
-                for (File file : files) {
-                    if (file.isDirectory()) {
-                        removeLocalFolder(file);
+                for (OCFile file : files) {
+                    if (file.isFolder()) {
+                        success &= removeLocalFolder(file);
                     } else {
-                        file.delete();
+                        if (file.isDown()) {
+                            File localFile = new File(file.getStoragePath());
+                            success &= localFile.delete();
+                            if (success) {
+                                file.setStoragePath(null);
+                                saveFile(file);
+                            }
+                        }
                     }
                 }
             }
-            folder.delete();
+
+            // stage 2: remove the folder itself and any local file inside out of sync; 
+            //          for instance, after clearing the app cache or reinstalling
+            success &= removeLocalFolder(localFolder);
+        }
+        return success;
+    }
+
+    private boolean removeLocalFolder(File localFolder) {
+        boolean success = true;
+        File[] localFiles = localFolder.listFiles();
+        if (localFiles != null) {
+            for (File localFile : localFiles) {
+                if (localFile.isDirectory()) {
+                    success &= removeLocalFolder(localFile);
+                } else {
+                    success &= localFile.delete();
+                }
+            }
         }
+        success &= localFolder.delete();
+        return success;
     }
 
     /**
@@ -500,43 +584,67 @@ public class FileDataStorageManager {
     public void moveFolder(OCFile folder, String newPath) {
         // TODO check newPath
 
-        if (folder != null && folder.isFolder() && folder.fileExists() && !OCFile.ROOT_PATH.equals(folder.getFileName())) {
+        if (    folder != null && folder.isFolder() && 
+                folder.fileExists() && !OCFile.ROOT_PATH.equals(folder.getFileName())
+            ) {
             /// 1. get all the descendants of 'dir' in a single QUERY (including 'dir')
             Cursor c = null;
             if (getContentProviderClient() != null) {
                 try {
-                    c = getContentProviderClient().query(ProviderTableMeta.CONTENT_URI, 
-                            null,
-                            ProviderTableMeta.FILE_ACCOUNT_OWNER + "=? AND " + ProviderTableMeta.FILE_PATH + " LIKE ? ",
-                            new String[] { mAccount.name, folder.getRemotePath() + "%"  }, ProviderTableMeta.FILE_PATH + " ASC ");
+                    c = getContentProviderClient().query (
+                        ProviderTableMeta.CONTENT_URI, 
+                        null,
+                        ProviderTableMeta.FILE_ACCOUNT_OWNER + "=? AND " + 
+                                ProviderTableMeta.FILE_PATH + " LIKE ? ",
+                        new String[] { mAccount.name, folder.getRemotePath() + "%"  }, 
+                        ProviderTableMeta.FILE_PATH + " ASC "
+                    );
                 } catch (RemoteException e) {
                     Log_OC.e(TAG, e.getMessage());
                 }
             } else {
-                c = getContentResolver().query(ProviderTableMeta.CONTENT_URI, 
-                        null,
-                        ProviderTableMeta.FILE_ACCOUNT_OWNER + "=? AND " + ProviderTableMeta.FILE_PATH + " LIKE ? ",
-                        new String[] { mAccount.name, folder.getRemotePath() + "%"  }, ProviderTableMeta.FILE_PATH + " ASC ");
+                c = getContentResolver().query (
+                    ProviderTableMeta.CONTENT_URI, 
+                    null,
+                    ProviderTableMeta.FILE_ACCOUNT_OWNER + "=? AND " + 
+                            ProviderTableMeta.FILE_PATH + " LIKE ? ",
+                    new String[] { mAccount.name, folder.getRemotePath() + "%"  }, 
+                    ProviderTableMeta.FILE_PATH + " ASC "
+                );
             }
 
             /// 2. prepare a batch of update operations to change all the descendants
-            ArrayList<ContentProviderOperation> operations = new ArrayList<ContentProviderOperation>(c.getCount());
+            ArrayList<ContentProviderOperation> operations = 
+                    new ArrayList<ContentProviderOperation>(c.getCount());
             int lengthOfOldPath = folder.getRemotePath().length();
             String defaultSavePath = FileStorageUtils.getSavePath(mAccount.name);
             int lengthOfOldStoragePath = defaultSavePath.length() + lengthOfOldPath;
             if (c.moveToFirst()) {
                 do {
-                    ContentValues cv = new ContentValues(); // don't take the constructor out of the loop and clear the object
+                    ContentValues cv = new ContentValues(); // keep the constructor in the loop
                     OCFile child = createFileInstance(c);
-                    cv.put(ProviderTableMeta.FILE_PATH, newPath + child.getRemotePath().substring(lengthOfOldPath));
-                    if (child.getStoragePath() != null && child.getStoragePath().startsWith(defaultSavePath)) {
-                        cv.put(ProviderTableMeta.FILE_STORAGE_PATH, defaultSavePath + newPath + child.getStoragePath().substring(lengthOfOldStoragePath));
+                    cv.put(
+                        ProviderTableMeta.FILE_PATH, 
+                        newPath + child.getRemotePath().substring(lengthOfOldPath)
+                    );
+                    if (    child.getStoragePath() != null && 
+                            child.getStoragePath().startsWith(defaultSavePath)  ) {
+                        cv.put(
+                                ProviderTableMeta.FILE_STORAGE_PATH, 
+                                defaultSavePath + newPath + 
+                                    child.getStoragePath().substring(lengthOfOldStoragePath)
+                        );
                     }
-                    operations.add(ContentProviderOperation.newUpdate(ProviderTableMeta.CONTENT_URI).
+                    operations.add(
+                            ContentProviderOperation.
+                            newUpdate(ProviderTableMeta.CONTENT_URI).
                             withValues(cv).
-                            withSelection(  ProviderTableMeta._ID + "=?", 
-                                    new String[] { String.valueOf(child.getFileId()) })
-                                    .build());
+                            withSelection(  
+                                    ProviderTableMeta._ID + "=?", 
+                                    new String[] { String.valueOf(child.getFileId()) }
+                            ).
+                            build()
+                    );
                 } while (c.moveToNext());
             }
             c.close();
@@ -551,16 +659,138 @@ public class FileDataStorageManager {
                 }
 
             } catch (OperationApplicationException e) {
-                Log_OC.e(TAG, "Fail to update descendants of " + folder.getFileId() + " in database", e);
+                Log_OC.e(TAG, "Fail to update descendants of " + 
+                        folder.getFileId() + " in database", e);
 
             } catch (RemoteException e) {
-                Log_OC.e(TAG, "Fail to update desendants of " + folder.getFileId() + " in database", e);
+                Log_OC.e(TAG, "Fail to update desendants of " + 
+                        folder.getFileId() + " in database", e);
             }
 
         }
     }
 
     
+    public void moveLocalFile(OCFile file, String targetPath, String targetParentPath) {
+
+        if (file != null && file.fileExists() && !OCFile.ROOT_PATH.equals(file.getFileName())) {
+            
+            OCFile targetParent = getFileByPath(targetParentPath);
+            if (targetParent == null) {
+                // TODO panic
+            }
+            
+            /// 1. get all the descendants of the moved element in a single QUERY
+            Cursor c = null;
+            if (getContentProviderClient() != null) {
+                try {
+                    c = getContentProviderClient().query(
+                        ProviderTableMeta.CONTENT_URI, 
+                        null,
+                        ProviderTableMeta.FILE_ACCOUNT_OWNER + "=? AND " + 
+                                ProviderTableMeta.FILE_PATH + " LIKE ? ",
+                        new String[] { 
+                                mAccount.name, 
+                                file.getRemotePath() + "%"  
+                        }, 
+                        ProviderTableMeta.FILE_PATH + " ASC "
+                    );
+                } catch (RemoteException e) {
+                    Log_OC.e(TAG, e.getMessage());
+                }
+                
+            } else {
+                c = getContentResolver().query(
+                    ProviderTableMeta.CONTENT_URI, 
+                    null,
+                    ProviderTableMeta.FILE_ACCOUNT_OWNER + "=? AND " + 
+                            ProviderTableMeta.FILE_PATH + " LIKE ? ",
+                    new String[] { 
+                            mAccount.name, 
+                            file.getRemotePath() + "%"  
+                    }, 
+                    ProviderTableMeta.FILE_PATH + " ASC "
+                );
+            }
+
+            /// 2. prepare a batch of update operations to change all the descendants
+            ArrayList<ContentProviderOperation> operations = 
+                    new ArrayList<ContentProviderOperation>(c.getCount());
+            String defaultSavePath = FileStorageUtils.getSavePath(mAccount.name);
+            if (c.moveToFirst()) {
+                int lengthOfOldPath = file.getRemotePath().length();
+                int lengthOfOldStoragePath = defaultSavePath.length() + lengthOfOldPath;
+                do {
+                    ContentValues cv = new ContentValues(); // keep construction in the loop
+                    OCFile child = createFileInstance(c);
+                    cv.put(
+                        ProviderTableMeta.FILE_PATH, 
+                        targetPath + child.getRemotePath().substring(lengthOfOldPath)
+                    );
+                    if (child.getStoragePath() != null && 
+                            child.getStoragePath().startsWith(defaultSavePath)) {
+                        // update link to downloaded content - but local move is not done here!
+                        cv.put(
+                            ProviderTableMeta.FILE_STORAGE_PATH, 
+                            defaultSavePath + targetPath + 
+                                child.getStoragePath().substring(lengthOfOldStoragePath)
+                        );
+                    }
+                    if (child.getRemotePath().equals(file.getRemotePath())) {
+                        cv.put(
+                                ProviderTableMeta.FILE_PARENT,
+                                targetParent.getFileId()
+                            );
+                    }
+                    operations.add(
+                        ContentProviderOperation.newUpdate(ProviderTableMeta.CONTENT_URI).
+                            withValues(cv).
+                            withSelection(  
+                                    ProviderTableMeta._ID + "=?", 
+                                    new String[] { String.valueOf(child.getFileId()) }
+                                    )
+                            .build());
+                    
+                } while (c.moveToNext());
+            }
+            c.close();
+
+            /// 3. apply updates in batch
+            try {
+                if (getContentResolver() != null) {
+                    getContentResolver().applyBatch(MainApp.getAuthority(), operations);
+
+                } else {
+                    getContentProviderClient().applyBatch(operations);
+                }
+
+            } catch (Exception e) {
+                Log_OC.e(
+                    TAG, 
+                    "Fail to update " + file.getFileId() + " and descendants in database", 
+                    e
+                );
+            }
+
+            /// 4. move in local file system 
+            String localPath = FileStorageUtils.getDefaultSavePathFor(mAccount.name, file);
+            File localFile = new File(localPath);
+            boolean renamed = false;
+            if (localFile.exists()) {
+                File targetFile = new File(defaultSavePath + targetPath);
+                File targetFolder = targetFile.getParentFile();
+                if (!targetFolder.exists()) {
+                    targetFolder.mkdirs();
+                }
+                renamed = localFile.renameTo(targetFile);
+            }
+            Log_OC.d(TAG, "Local file RENAMED : " + renamed);
+            
+        }
+        
+    }
+    
+    
     private Vector<OCFile> getFolderContent(long parentId) {
 
         Vector<OCFile> ret = new Vector<OCFile>();
@@ -663,6 +893,7 @@ public class FileDataStorageManager {
         }
         return c;
     }
+    
 
     private OCFile createFileInstance(Cursor c) {
         OCFile file = null;
@@ -678,7 +909,9 @@ public class FileDataStorageManager {
                 file.setStoragePath(c.getString(c
                         .getColumnIndex(ProviderTableMeta.FILE_STORAGE_PATH)));
                 if (file.getStoragePath() == null) {
-                    // try to find existing file and bind it with current account; - with the current update of SynchronizeFolderOperation, this won't be necessary anymore after a full synchronization of the account
+                    // try to find existing file and bind it with current account; 
+                    // with the current update of SynchronizeFolderOperation, this won't be 
+                    // necessary anymore after a full synchronization of the account
                     File f = new File(FileStorageUtils.getDefaultSavePathFor(mAccount.name, file));
                     if (f.exists()) {
                         file.setStoragePath(f.getAbsolutePath());
@@ -701,9 +934,618 @@ public class FileDataStorageManager {
             file.setKeepInSync(c.getInt(
                     c.getColumnIndex(ProviderTableMeta.FILE_KEEP_IN_SYNC)) == 1 ? true : false);
             file.setEtag(c.getString(c.getColumnIndex(ProviderTableMeta.FILE_ETAG)));
+            file.setShareByLink(c.getInt(
+                    c.getColumnIndex(ProviderTableMeta.FILE_SHARE_BY_LINK)) == 1 ? true : false);
+            file.setPublicLink(c.getString(c.getColumnIndex(ProviderTableMeta.FILE_PUBLIC_LINK)));
+            file.setPermissions(c.getString(c.getColumnIndex(ProviderTableMeta.FILE_PERMISSIONS)));
+            file.setRemoteId(c.getString(c.getColumnIndex(ProviderTableMeta.FILE_REMOTE_ID)));
+            file.setNeedsUpdateThumbnail(c.getInt(
+                    c.getColumnIndex(ProviderTableMeta.FILE_UPDATE_THUMBNAIL)) == 1 ? true : false);
                     
         }
         return file;
     }
+    
+    /**
+     * Returns if the file/folder is shared by link or not
+     * @param path  Path of the file/folder
+     * @return
+     */
+    public boolean isShareByLink(String path) {
+        Cursor c = getCursorForValue(ProviderTableMeta.FILE_STORAGE_PATH, path);
+        OCFile file = null;
+        if (c.moveToFirst()) {
+            file = createFileInstance(c);
+        }
+        c.close();
+        return file.isShareByLink();
+    }
+    
+    /**
+     * Returns the public link of the file/folder
+     * @param path  Path of the file/folder
+     * @return
+     */
+    public String getPublicLink(String path) {
+        Cursor c = getCursorForValue(ProviderTableMeta.FILE_STORAGE_PATH, path);
+        OCFile file = null;
+        if (c.moveToFirst()) {
+            file = createFileInstance(c);
+        }
+        c.close();
+        return file.getPublicLink();
+    }
+    
+    
+    // Methods for Shares
+    public boolean saveShare(OCShare share) {
+        boolean overriden = false;
+        ContentValues cv = new ContentValues();
+        cv.put(ProviderTableMeta.OCSHARES_FILE_SOURCE, share.getFileSource());
+        cv.put(ProviderTableMeta.OCSHARES_ITEM_SOURCE, share.getItemSource());
+        cv.put(ProviderTableMeta.OCSHARES_SHARE_TYPE, share.getShareType().getValue());
+        cv.put(ProviderTableMeta.OCSHARES_SHARE_WITH, share.getShareWith());
+        cv.put(ProviderTableMeta.OCSHARES_PATH, share.getPath());
+        cv.put(ProviderTableMeta.OCSHARES_PERMISSIONS, share.getPermissions());
+        cv.put(ProviderTableMeta.OCSHARES_SHARED_DATE, share.getSharedDate());
+        cv.put(ProviderTableMeta.OCSHARES_EXPIRATION_DATE, share.getExpirationDate());
+        cv.put(ProviderTableMeta.OCSHARES_TOKEN, share.getToken());
+        cv.put(
+            ProviderTableMeta.OCSHARES_SHARE_WITH_DISPLAY_NAME, 
+            share.getSharedWithDisplayName()
+        );
+        cv.put(ProviderTableMeta.OCSHARES_IS_DIRECTORY, share.isFolder() ? 1 : 0);
+        cv.put(ProviderTableMeta.OCSHARES_USER_ID, share.getUserId());
+        cv.put(ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED, share.getIdRemoteShared());
+        cv.put(ProviderTableMeta.OCSHARES_ACCOUNT_OWNER, mAccount.name);
+        
+        if (shareExists(share.getIdRemoteShared())) {   // for renamed files
+
+            overriden = true;
+            if (getContentResolver() != null) {
+                getContentResolver().update(ProviderTableMeta.CONTENT_URI_SHARE, cv,
+                        ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED + "=?",
+                        new String[] { String.valueOf(share.getIdRemoteShared()) });
+            } else {
+                try {
+                    getContentProviderClient().update(ProviderTableMeta.CONTENT_URI_SHARE,
+                            cv, ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED + "=?",
+                            new String[] { String.valueOf(share.getIdRemoteShared()) });
+                } catch (RemoteException e) {
+                    Log_OC.e(TAG,
+                            "Fail to insert insert file to database "
+                                    + e.getMessage());
+                }
+            }
+        } else {
+            Uri result_uri = null;
+            if (getContentResolver() != null) {
+                result_uri = getContentResolver().insert(
+                        ProviderTableMeta.CONTENT_URI_SHARE, cv);
+            } else {
+                try {
+                    result_uri = getContentProviderClient().insert(
+                            ProviderTableMeta.CONTENT_URI_SHARE, cv);
+                } catch (RemoteException e) {
+                    Log_OC.e(TAG,
+                            "Fail to insert insert file to database "
+                                    + e.getMessage());
+                }
+            }
+            if (result_uri != null) {
+                long new_id = Long.parseLong(result_uri.getPathSegments()
+                        .get(1));
+                share.setId(new_id);
+            }            
+        }
+
+        return overriden;
+    }
+
+
+    public OCShare getFirstShareByPathAndType(String path, ShareType type) {
+        Cursor c = null;
+        if (getContentResolver() != null) {
+            c = getContentResolver().query(
+                    ProviderTableMeta.CONTENT_URI_SHARE,
+                    null,
+                    ProviderTableMeta.OCSHARES_PATH + "=? AND "
+                            + ProviderTableMeta.OCSHARES_SHARE_TYPE + "=? AND "
+                            + ProviderTableMeta.OCSHARES_ACCOUNT_OWNER + "=?",
+                    new String[] { path, Integer.toString(type.getValue()), mAccount.name },
+                    null);
+        } else {
+            try {
+                c = getContentProviderClient().query(
+                        ProviderTableMeta.CONTENT_URI_SHARE,
+                        null,
+                        ProviderTableMeta.OCSHARES_PATH + "=? AND "
+                                + ProviderTableMeta.OCSHARES_SHARE_TYPE + "=? AND "
+                                + ProviderTableMeta.OCSHARES_ACCOUNT_OWNER + "=?",
+                        new String[] { path, Integer.toString(type.getValue()), mAccount.name }, 
+                        null);
+
+            } catch (RemoteException e) {
+                Log_OC.e(TAG, "Could not get file details: " + e.getMessage());
+                c = null;
+            }
+        }
+        OCShare share = null;
+        if (c.moveToFirst()) {
+            share = createShareInstance(c);
+        }
+        c.close();
+        return share;
+    }
+    
+    private OCShare createShareInstance(Cursor c) {
+        OCShare share = null;
+        if (c != null) {
+            share = new OCShare(c.getString(c
+                    .getColumnIndex(ProviderTableMeta.OCSHARES_PATH)));
+            share.setId(c.getLong(c.getColumnIndex(ProviderTableMeta._ID)));
+            share.setFileSource(c.getLong(c
+                    .getColumnIndex(ProviderTableMeta.OCSHARES_ITEM_SOURCE)));
+            share.setShareType(ShareType.fromValue(c.getInt(c
+                    .getColumnIndex(ProviderTableMeta.OCSHARES_SHARE_TYPE))));
+            share.setPermissions(c.getInt(c
+                    .getColumnIndex(ProviderTableMeta.OCSHARES_PERMISSIONS)));
+            share.setSharedDate(c.getLong(c
+                    .getColumnIndex(ProviderTableMeta.OCSHARES_SHARED_DATE)));
+            share.setExpirationDate(c.getLong(c
+                    .getColumnIndex(ProviderTableMeta.OCSHARES_EXPIRATION_DATE)));
+            share.setToken(c.getString(c
+                    .getColumnIndex(ProviderTableMeta.OCSHARES_TOKEN)));
+            share.setSharedWithDisplayName(c.getString(c
+                    .getColumnIndex(ProviderTableMeta.OCSHARES_SHARE_WITH_DISPLAY_NAME)));
+            share.setIsFolder(c.getInt(
+                    c.getColumnIndex(ProviderTableMeta.OCSHARES_IS_DIRECTORY)) == 1 ? true : false);
+            share.setUserId(c.getLong(c.getColumnIndex(ProviderTableMeta.OCSHARES_USER_ID)));
+            share.setIdRemoteShared(
+                c.getLong(c.getColumnIndex(ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED))
+            );
+                    
+        }
+        return share;
+    }
+
+    private boolean shareExists(String cmp_key, String value) {
+        Cursor c;
+        if (getContentResolver() != null) {
+            c = getContentResolver()
+                    .query(ProviderTableMeta.CONTENT_URI_SHARE,
+                            null,
+                            cmp_key + "=? AND "
+                                    + ProviderTableMeta.OCSHARES_ACCOUNT_OWNER
+                                    + "=?",
+                                    new String[] { value, mAccount.name }, null);
+        } else {
+            try {
+                c = getContentProviderClient().query(
+                        ProviderTableMeta.CONTENT_URI_SHARE,
+                        null,
+                        cmp_key + "=? AND "
+                                + ProviderTableMeta.OCSHARES_ACCOUNT_OWNER + "=?",
+                                new String[] { value, mAccount.name }, null);
+            } catch (RemoteException e) {
+                Log_OC.e(TAG,
+                        "Couldn't determine file existance, assuming non existance: "
+                                + e.getMessage());
+                return false;
+            }
+        }
+        boolean retval = c.moveToFirst();
+        c.close();
+        return retval;
+    }
+    
+    private boolean shareExists(long remoteId) {
+        return shareExists(ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED, String.valueOf(remoteId));
+    }
+
+    private void cleanSharedFiles() {
+        ContentValues cv = new ContentValues();
+        cv.put(ProviderTableMeta.FILE_SHARE_BY_LINK, false);
+        cv.put(ProviderTableMeta.FILE_PUBLIC_LINK, "");
+        String where = ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?";
+        String [] whereArgs = new String[]{mAccount.name};
+        
+        if (getContentResolver() != null) {
+            getContentResolver().update(ProviderTableMeta.CONTENT_URI, cv, where, whereArgs);
+
+        } else {
+            try {
+                getContentProviderClient().update(
+                        ProviderTableMeta.CONTENT_URI, cv, where, whereArgs
+                );
+                
+            } catch (RemoteException e) {
+                Log_OC.e(TAG, "Exception in cleanSharedFiles" + e.getMessage());
+            }
+        }
+    }
+
+    private void cleanSharedFilesInFolder(OCFile folder) {
+        ContentValues cv = new ContentValues();
+        cv.put(ProviderTableMeta.FILE_SHARE_BY_LINK, false);
+        cv.put(ProviderTableMeta.FILE_PUBLIC_LINK, "");
+        String where = ProviderTableMeta.FILE_ACCOUNT_OWNER + "=? AND " + 
+                ProviderTableMeta.FILE_PARENT + "=?";
+        String [] whereArgs = new String[] { mAccount.name , String.valueOf(folder.getFileId()) };
+        
+        if (getContentResolver() != null) {
+            getContentResolver().update(ProviderTableMeta.CONTENT_URI, cv, where, whereArgs);
+
+        } else {
+            try {
+                getContentProviderClient().update(
+                        ProviderTableMeta.CONTENT_URI, cv, where, whereArgs
+                );
+                
+            } catch (RemoteException e) {
+                Log_OC.e(TAG, "Exception in cleanSharedFilesInFolder " + e.getMessage());
+            }
+        }
+    }
+
+    private void cleanShares() {
+        String where = ProviderTableMeta.OCSHARES_ACCOUNT_OWNER + "=?";
+        String [] whereArgs = new String[]{mAccount.name};
+        
+        if (getContentResolver() != null) {
+            getContentResolver().delete(ProviderTableMeta.CONTENT_URI_SHARE, where, whereArgs);
+
+        } else {
+            try {
+                getContentProviderClient().delete(
+                        ProviderTableMeta.CONTENT_URI_SHARE, where, whereArgs
+                );
+                
+            } catch (RemoteException e) {
+                Log_OC.e(TAG, "Exception in cleanShares" + e.getMessage());
+            }
+        }
+    }
+    
+    public void saveShares(Collection<OCShare> shares) {
+        cleanShares();
+        if (shares != null) {
+            ArrayList<ContentProviderOperation> operations = 
+                    new ArrayList<ContentProviderOperation>(shares.size());
+
+            // prepare operations to insert or update files to save in the given folder
+            for (OCShare share : shares) {
+                ContentValues cv = new ContentValues();
+                cv.put(ProviderTableMeta.OCSHARES_FILE_SOURCE, share.getFileSource());
+                cv.put(ProviderTableMeta.OCSHARES_ITEM_SOURCE, share.getItemSource());
+                cv.put(ProviderTableMeta.OCSHARES_SHARE_TYPE, share.getShareType().getValue());
+                cv.put(ProviderTableMeta.OCSHARES_SHARE_WITH, share.getShareWith());
+                cv.put(ProviderTableMeta.OCSHARES_PATH, share.getPath());
+                cv.put(ProviderTableMeta.OCSHARES_PERMISSIONS, share.getPermissions());
+                cv.put(ProviderTableMeta.OCSHARES_SHARED_DATE, share.getSharedDate());
+                cv.put(ProviderTableMeta.OCSHARES_EXPIRATION_DATE, share.getExpirationDate());
+                cv.put(ProviderTableMeta.OCSHARES_TOKEN, share.getToken());
+                cv.put(
+                    ProviderTableMeta.OCSHARES_SHARE_WITH_DISPLAY_NAME, 
+                    share.getSharedWithDisplayName()
+                );
+                cv.put(ProviderTableMeta.OCSHARES_IS_DIRECTORY, share.isFolder() ? 1 : 0);
+                cv.put(ProviderTableMeta.OCSHARES_USER_ID, share.getUserId());
+                cv.put(ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED, share.getIdRemoteShared());
+                cv.put(ProviderTableMeta.OCSHARES_ACCOUNT_OWNER, mAccount.name);
+
+                if (shareExists(share.getIdRemoteShared())) {
+                    // updating an existing file
+                    operations.add(
+                            ContentProviderOperation.newUpdate(ProviderTableMeta.CONTENT_URI_SHARE).
+                            withValues(cv).
+                            withSelection(
+                                    ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED + "=?", 
+                                    new String[] { String.valueOf(share.getIdRemoteShared()) }
+                            ).
+                            build()
+                    );
+
+                } else {
+                    // adding a new file
+                    operations.add(
+                            ContentProviderOperation.newInsert(ProviderTableMeta.CONTENT_URI_SHARE).
+                            withValues(cv).
+                            build()
+                    );
+                }
+            }
+            
+            // apply operations in batch
+            if (operations.size() > 0) {
+                @SuppressWarnings("unused")
+                ContentProviderResult[] results = null;
+                Log_OC.d(TAG, "Sending " + operations.size() + 
+                        " operations to FileContentProvider");
+                try {
+                    if (getContentResolver() != null) {
+                        results = getContentResolver().applyBatch(
+                                MainApp.getAuthority(), operations
+                        );
+    
+                    } else {
+                        results = getContentProviderClient().applyBatch(operations);
+                    }
+    
+                } catch (OperationApplicationException e) {
+                    Log_OC.e(TAG, "Exception in batch of operations " + e.getMessage());
+    
+                } catch (RemoteException e) {
+                    Log_OC.e(TAG, "Exception in batch of operations  " + e.getMessage());
+                }
+            }
+        }
+        
+    }
+    
+    public void updateSharedFiles(Collection<OCFile> sharedFiles) {
+        cleanSharedFiles();
+        
+        if (sharedFiles != null) {
+            ArrayList<ContentProviderOperation> operations = 
+                    new ArrayList<ContentProviderOperation>(sharedFiles.size());
+
+            // prepare operations to insert or update files to save in the given folder
+            for (OCFile file : sharedFiles) {
+                ContentValues cv = new ContentValues();
+                cv.put(ProviderTableMeta.FILE_MODIFIED, file.getModificationTimestamp());
+                cv.put(
+                    ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA, 
+                    file.getModificationTimestampAtLastSyncForData()
+                );
+                cv.put(ProviderTableMeta.FILE_CREATION, file.getCreationTimestamp());
+                cv.put(ProviderTableMeta.FILE_CONTENT_LENGTH, file.getFileLength());
+                cv.put(ProviderTableMeta.FILE_CONTENT_TYPE, file.getMimetype());
+                cv.put(ProviderTableMeta.FILE_NAME, file.getFileName());
+                cv.put(ProviderTableMeta.FILE_PARENT, file.getParentId());
+                cv.put(ProviderTableMeta.FILE_PATH, file.getRemotePath());
+                if (!file.isFolder()) {
+                    cv.put(ProviderTableMeta.FILE_STORAGE_PATH, file.getStoragePath());
+                }
+                cv.put(ProviderTableMeta.FILE_ACCOUNT_OWNER, mAccount.name);
+                cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE, file.getLastSyncDateForProperties());
+                cv.put(
+                    ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA, 
+                    file.getLastSyncDateForData()
+                );
+                cv.put(ProviderTableMeta.FILE_KEEP_IN_SYNC, file.keepInSync() ? 1 : 0);
+                cv.put(ProviderTableMeta.FILE_ETAG, file.getEtag());
+                cv.put(ProviderTableMeta.FILE_SHARE_BY_LINK, file.isShareByLink() ? 1 : 0);
+                cv.put(ProviderTableMeta.FILE_PUBLIC_LINK, file.getPublicLink());
+                cv.put(ProviderTableMeta.FILE_PERMISSIONS, file.getPermissions());
+                cv.put(ProviderTableMeta.FILE_REMOTE_ID, file.getRemoteId());
+                cv.put(
+                    ProviderTableMeta.FILE_UPDATE_THUMBNAIL, 
+                    file.needsUpdateThumbnail() ? 1 : 0
+                );
+
+                boolean existsByPath = fileExists(file.getRemotePath());
+                if (existsByPath || fileExists(file.getFileId())) {
+                    // updating an existing file
+                    operations.add(
+                            ContentProviderOperation.newUpdate(ProviderTableMeta.CONTENT_URI).
+                            withValues(cv).
+                            withSelection(
+                                    ProviderTableMeta._ID + "=?", 
+                                    new String[] { String.valueOf(file.getFileId()) }
+                            ).build()
+                    );
+
+                } else {
+                    // adding a new file
+                    operations.add(
+                            ContentProviderOperation.newInsert(ProviderTableMeta.CONTENT_URI).
+                            withValues(cv).
+                            build()
+                    );
+                }
+            }
+            
+            // apply operations in batch
+            if (operations.size() > 0) {
+                @SuppressWarnings("unused")
+                ContentProviderResult[] results = null;
+                Log_OC.d(TAG, "Sending " + operations.size() + 
+                        " operations to FileContentProvider");
+                try {
+                    if (getContentResolver() != null) {
+                        results = getContentResolver().applyBatch(
+                                MainApp.getAuthority(), operations
+                        );
+    
+                    } else {
+                        results = getContentProviderClient().applyBatch(operations);
+                    }
+    
+                } catch (OperationApplicationException e) {
+                    Log_OC.e(TAG, "Exception in batch of operations " + e.getMessage());
+    
+                } catch (RemoteException e) {
+                    Log_OC.e(TAG, "Exception in batch of operations  " + e.getMessage());
+                }
+            }
+        }
+        
+    } 
+    
+    public void removeShare(OCShare share){
+        Uri share_uri = ProviderTableMeta.CONTENT_URI_SHARE;
+        String where = ProviderTableMeta.OCSHARES_ACCOUNT_OWNER + "=?" + " AND " + 
+                ProviderTableMeta.FILE_PATH + "=?";
+        String [] whereArgs = new String[]{mAccount.name, share.getPath()};
+        if (getContentProviderClient() != null) {
+            try {
+                getContentProviderClient().delete(share_uri, where, whereArgs);
+            } catch (RemoteException e) {
+                e.printStackTrace();
+            }
+        } else {
+            getContentResolver().delete(share_uri, where, whereArgs); 
+        }
+    }
+    
+    public void saveSharesDB(ArrayList<OCShare> shares) {
+        saveShares(shares);
+
+        ArrayList<OCFile> sharedFiles = new ArrayList<OCFile>();
+
+        for (OCShare share : shares) {
+            // Get the path
+            String path = share.getPath();
+            if (share.isFolder()) {
+                path = path + FileUtils.PATH_SEPARATOR;
+            }           
+
+            // Update OCFile with data from share: ShareByLink  ¿and publicLink?
+            OCFile file = getFileByPath(path);
+            if (file != null) {
+                if (share.getShareType().equals(ShareType.PUBLIC_LINK)) {
+                    file.setShareByLink(true);
+                    sharedFiles.add(file);
+                }
+            } 
+        }
+        
+        updateSharedFiles(sharedFiles);
+    }
+
+    
+    public void saveSharesInFolder(ArrayList<OCShare> shares, OCFile folder) {
+        cleanSharedFilesInFolder(folder);
+        ArrayList<ContentProviderOperation> operations = new ArrayList<ContentProviderOperation>();
+        operations = prepareRemoveSharesInFolder(folder, operations);
+        
+        if (shares != null) {
+            // prepare operations to insert or update files to save in the given folder
+            for (OCShare share : shares) {
+                ContentValues cv = new ContentValues();
+                cv.put(ProviderTableMeta.OCSHARES_FILE_SOURCE, share.getFileSource());
+                cv.put(ProviderTableMeta.OCSHARES_ITEM_SOURCE, share.getItemSource());
+                cv.put(ProviderTableMeta.OCSHARES_SHARE_TYPE, share.getShareType().getValue());
+                cv.put(ProviderTableMeta.OCSHARES_SHARE_WITH, share.getShareWith());
+                cv.put(ProviderTableMeta.OCSHARES_PATH, share.getPath());
+                cv.put(ProviderTableMeta.OCSHARES_PERMISSIONS, share.getPermissions());
+                cv.put(ProviderTableMeta.OCSHARES_SHARED_DATE, share.getSharedDate());
+                cv.put(ProviderTableMeta.OCSHARES_EXPIRATION_DATE, share.getExpirationDate());
+                cv.put(ProviderTableMeta.OCSHARES_TOKEN, share.getToken());
+                cv.put(
+                    ProviderTableMeta.OCSHARES_SHARE_WITH_DISPLAY_NAME, 
+                    share.getSharedWithDisplayName()
+                );
+                cv.put(ProviderTableMeta.OCSHARES_IS_DIRECTORY, share.isFolder() ? 1 : 0);
+                cv.put(ProviderTableMeta.OCSHARES_USER_ID, share.getUserId());
+                cv.put(ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED, share.getIdRemoteShared());
+                cv.put(ProviderTableMeta.OCSHARES_ACCOUNT_OWNER, mAccount.name);
+
+                /*
+                if (shareExists(share.getIdRemoteShared())) {
+                    // updating an existing share resource
+                    operations.add(
+                            ContentProviderOperation.newUpdate(ProviderTableMeta.CONTENT_URI_SHARE).
+                            withValues(cv).
+                            withSelection(  ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED + "=?", 
+                                    new String[] { String.valueOf(share.getIdRemoteShared()) })
+                                    .build());
+
+                } else {
+                */
+                // adding a new share resource
+                operations.add(
+                        ContentProviderOperation.newInsert(ProviderTableMeta.CONTENT_URI_SHARE).
+                        withValues(cv).
+                        build()
+                );
+                //}
+            }
+        }
+            
+        // apply operations in batch
+        if (operations.size() > 0) {
+            @SuppressWarnings("unused")
+            ContentProviderResult[] results = null;
+            Log_OC.d(TAG, "Sending " + operations.size() + " operations to FileContentProvider");
+            try {
+                if (getContentResolver() != null) {
+                    results = getContentResolver().applyBatch(MainApp.getAuthority(), operations);
+
+                } else {
+                    results = getContentProviderClient().applyBatch(operations);
+                }
+
+            } catch (OperationApplicationException e) {
+                Log_OC.e(TAG, "Exception in batch of operations " + e.getMessage());
+
+            } catch (RemoteException e) {
+                Log_OC.e(TAG, "Exception in batch of operations  " + e.getMessage());
+            }
+        }
+        //}
+        
+    }
+
+    private ArrayList<ContentProviderOperation> prepareRemoveSharesInFolder(
+            OCFile folder, ArrayList<ContentProviderOperation> preparedOperations
+            ) {
+        if (folder != null) {
+            String where = ProviderTableMeta.OCSHARES_PATH + "=?" + " AND " 
+                    + ProviderTableMeta.OCSHARES_ACCOUNT_OWNER + "=?";
+            String [] whereArgs = new String[]{ "", mAccount.name };
+            
+            Vector<OCFile> files = getFolderContent(folder);
+            
+            for (OCFile file : files) {
+                whereArgs[0] = file.getRemotePath();
+                preparedOperations.add(
+                        ContentProviderOperation.newDelete(ProviderTableMeta.CONTENT_URI_SHARE).
+                        withSelection(where, whereArgs).
+                        build()
+                );
+            }
+        }
+        return preparedOperations;
+        
+        /*
+        if (operations.size() > 0) {
+            try {
+                if (getContentResolver() != null) {
+                    getContentResolver().applyBatch(MainApp.getAuthority(), operations);
+
+                } else {
+                    getContentProviderClient().applyBatch(operations);
+                }
+
+            } catch (OperationApplicationException e) {
+                Log_OC.e(TAG, "Exception in batch of operations " + e.getMessage());
+
+            } catch (RemoteException e) {
+                Log_OC.e(TAG, "Exception in batch of operations  " + e.getMessage());
+            }
+        }            
+        */
+            
+            /*
+            if (getContentResolver() != null) {
+                
+                getContentResolver().delete(ProviderTableMeta.CONTENT_URI_SHARE, 
+                                            where,
+                                            whereArgs);
+            } else {
+                try {
+                    getContentProviderClient().delete(  ProviderTableMeta.CONTENT_URI_SHARE, 
+                                                        where,
+                                                        whereArgs);
+
+                } catch (RemoteException e) {
+                    Log_OC.e(TAG, "Exception deleting shares in a folder " + e.getMessage());
+                }
+            }
+            */
+        //}
+    }
 
 }
index 67de500..392d03b 100644 (file)
@@ -20,8 +20,8 @@ package com.owncloud.android.datamodel;
 
 import java.io.File;
 
-import com.owncloud.android.Log_OC;
-
+import com.owncloud.android.lib.common.utils.Log_OC;
+import third_parties.daveKoeller.AlphanumComparator;
 
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -61,6 +61,14 @@ public class OCFile implements Parcelable, Comparable<OCFile> {
     private boolean mKeepInSync;
 
     private String mEtag;
+    
+    private boolean mShareByLink;
+    private String mPublicLink;
+
+    private String mPermissions;
+    private String mRemoteId;
+
+    private boolean mNeedsUpdateThumbnail;
 
 
     /**
@@ -99,6 +107,12 @@ public class OCFile implements Parcelable, Comparable<OCFile> {
         mLastSyncDateForProperties = source.readLong();
         mLastSyncDateForData = source.readLong();
         mEtag = source.readString();
+        mShareByLink = source.readInt() == 1;
+        mPublicLink = source.readString();
+        mPermissions = source.readString();
+        mRemoteId = source.readString();
+        mNeedsUpdateThumbnail = source.readInt() == 0;
+
     }
 
     @Override
@@ -117,6 +131,11 @@ public class OCFile implements Parcelable, Comparable<OCFile> {
         dest.writeLong(mLastSyncDateForProperties);
         dest.writeLong(mLastSyncDateForData);
         dest.writeString(mEtag);
+        dest.writeInt(mShareByLink ? 1 : 0);
+        dest.writeString(mPublicLink);
+        dest.writeString(mPermissions);
+        dest.writeString(mRemoteId);
+        dest.writeInt(mNeedsUpdateThumbnail ? 1 : 0);
     }
     
     /**
@@ -325,6 +344,11 @@ public class OCFile implements Parcelable, Comparable<OCFile> {
         mKeepInSync = false;
         mNeedsUpdating = false;
         mEtag = null;
+        mShareByLink = false;
+        mPublicLink = null;
+        mPermissions = null;
+        mRemoteId = null;
+        mNeedsUpdateThumbnail = false;
     }
 
     /**
@@ -390,6 +414,14 @@ public class OCFile implements Parcelable, Comparable<OCFile> {
         return mNeedsUpdating;
     }
     
+    public boolean needsUpdateThumbnail() {
+        return mNeedsUpdateThumbnail;
+    }
+
+    public void setNeedsUpdateThumbnail(boolean needsUpdateThumbnail) {
+        this.mNeedsUpdateThumbnail = needsUpdateThumbnail;
+    }
+
     public long getLastSyncDateForProperties() {
         return mLastSyncDateForProperties;
     }
@@ -428,7 +460,7 @@ public class OCFile implements Parcelable, Comparable<OCFile> {
         } else if (another.isFolder()) {
             return 1;
         }
-        return getRemotePath().toLowerCase().compareTo(another.getRemotePath().toLowerCase());
+        return new AlphanumComparator().compare(this, another);
     }
 
     @Override
@@ -445,7 +477,7 @@ public class OCFile implements Parcelable, Comparable<OCFile> {
 
     @Override
     public String toString() {
-        String asString = "[id=%s, name=%s, mime=%s, downloaded=%s, local=%s, remote=%s, parentId=%s, keepInSinc=%s etag=%s]";
+        String asString = "[id=%s, name=%s, mime=%s, downloaded=%s, local=%s, remote=%s, parentId=%s, keepInSync=%s etag=%s]";
         asString = String.format(asString, Long.valueOf(mId), getFileName(), mMimeType, isDown(), mLocalPath, mRemotePath, Long.valueOf(mParentId), Boolean.valueOf(mKeepInSync), mEtag);
         return asString;
     }
@@ -458,6 +490,23 @@ public class OCFile implements Parcelable, Comparable<OCFile> {
         this.mEtag = etag;
     }
     
+    
+    public boolean isShareByLink() {
+        return mShareByLink;
+    }
+
+    public void setShareByLink(boolean shareByLink) {
+        this.mShareByLink = shareByLink;
+    }
+
+    public String getPublicLink() {
+        return mPublicLink;
+    }
+
+    public void setPublicLink(String publicLink) {
+        this.mPublicLink = publicLink;
+    }
+
     public long getLocalModificationTimestamp() {
         if (mLocalPath != null && mLocalPath.length() > 0) {
             File f = new File(mLocalPath);
@@ -492,4 +541,20 @@ public class OCFile implements Parcelable, Comparable<OCFile> {
         return (result != null) ? result : "";
     }
 
+    public String getPermissions() {
+        return mPermissions;
+    }
+
+    public void setPermissions(String permissions) {
+        this.mPermissions = permissions;
+    }
+
+    public String getRemoteId() {
+        return mRemoteId;
+    }
+
+    public void setRemoteId(String remoteId) {
+        this.mRemoteId = remoteId;
+    }
+
 }
diff --git a/src/com/owncloud/android/datamodel/ThumbnailsCacheManager.java b/src/com/owncloud/android/datamodel/ThumbnailsCacheManager.java
new file mode 100644 (file)
index 0000000..e75404e
--- /dev/null
@@ -0,0 +1,265 @@
+/* ownCloud Android client application
+ *   Copyright (C) 2012-2014 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.datamodel;
+
+import java.io.File;
+import java.lang.ref.WeakReference;
+
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Bitmap.CompressFormat;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.media.ThumbnailUtils;
+import android.os.AsyncTask;
+import android.util.TypedValue;
+import android.widget.ImageView;
+
+import com.owncloud.android.MainApp;
+import com.owncloud.android.lib.common.utils.Log_OC;
+import com.owncloud.android.ui.adapter.DiskLruImageCache;
+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
+ */
+public class ThumbnailsCacheManager {
+    
+    private static final String TAG = ThumbnailsCacheManager.class.getSimpleName();
+    
+    private static final String CACHE_FOLDER = "thumbnailCache"; 
+    
+    private static final Object mThumbnailsDiskCacheLock = new Object();
+    private static DiskLruImageCache mThumbnailCache = null;
+    private static boolean mThumbnailCacheStarting = true;
+    
+    private static final int DISK_CACHE_SIZE = 1024 * 1024 * 10; // 10MB
+    private static final CompressFormat mCompressFormat = CompressFormat.JPEG;
+    private static final int mCompressQuality = 70;
+    
+    public static Bitmap mDefaultImg = 
+            BitmapFactory.decodeResource(
+                    MainApp.getAppContext().getResources(), 
+                    DisplayUtils.getResourceId("image/png", "default.png")
+            );
+
+    
+    public static class InitDiskCacheTask extends AsyncTask<File, Void, Void> {
+        @Override
+        protected Void doInBackground(File... params) {
+            synchronized (mThumbnailsDiskCacheLock) {
+                mThumbnailCacheStarting = true;
+                if (mThumbnailCache == null) {
+                    try {
+                        // Check if media is mounted or storage is built-in, if so, 
+                        // try and use external cache dir; otherwise use internal cache dir
+                        final String cachePath = 
+                                MainApp.getAppContext().getExternalCacheDir().getPath() + 
+                                File.separator + CACHE_FOLDER;
+                        Log_OC.d(TAG, "create dir: " + cachePath);
+                        final File diskCacheDir = new File(cachePath);
+                        mThumbnailCache = new DiskLruImageCache(
+                                diskCacheDir, 
+                                DISK_CACHE_SIZE, 
+                                mCompressFormat, 
+                                mCompressQuality
+                        );
+                    } catch (Exception e) {
+                        Log_OC.d(TAG, "Thumbnail cache could not be opened ", e);
+                        mThumbnailCache = null;
+                    }
+                }
+                mThumbnailCacheStarting = false; // Finished initialization
+                mThumbnailsDiskCacheLock.notifyAll(); // Wake any waiting threads
+            }
+            return null;
+        }
+    }
+    
+    
+    public static void addBitmapToCache(String key, Bitmap bitmap) {
+        synchronized (mThumbnailsDiskCacheLock) {
+            if (mThumbnailCache != null) {
+                mThumbnailCache.put(key, bitmap);
+            }
+        }
+    }
+
+
+    public static Bitmap getBitmapFromDiskCache(String key) {
+        synchronized (mThumbnailsDiskCacheLock) {
+            // Wait while disk cache is started from background thread
+            while (mThumbnailCacheStarting) {
+                try {
+                    mThumbnailsDiskCacheLock.wait();
+                } catch (InterruptedException e) {}
+            }
+            if (mThumbnailCache != null) {
+                return (Bitmap) mThumbnailCache.getBitmap(key);
+            }
+        }
+        return null;
+    }
+
+    
+    public static boolean cancelPotentialWork(OCFile file, ImageView imageView) {
+        final ThumbnailGenerationTask bitmapWorkerTask = getBitmapWorkerTask(imageView);
+
+        if (bitmapWorkerTask != null) {
+            final OCFile bitmapData = bitmapWorkerTask.mFile;
+            // If bitmapData is not yet set or it differs from the new data
+            if (bitmapData == null || bitmapData != file) {
+                // Cancel previous task
+                bitmapWorkerTask.cancel(true);
+            } else {
+                // The same work is already in progress
+                return false;
+            }
+        }
+        // No task associated with the ImageView, or an existing task was cancelled
+        return true;
+    }
+    
+    public static ThumbnailGenerationTask getBitmapWorkerTask(ImageView imageView) {
+        if (imageView != null) {
+            final Drawable drawable = imageView.getDrawable();
+            if (drawable instanceof AsyncDrawable) {
+                final AsyncDrawable asyncDrawable = (AsyncDrawable) drawable;
+                return asyncDrawable.getBitmapWorkerTask();
+            }
+         }
+         return null;
+     }
+
+    public static class ThumbnailGenerationTask extends AsyncTask<OCFile, Void, Bitmap> {
+        private final WeakReference<ImageView> mImageViewReference;
+        private OCFile mFile;
+        private FileDataStorageManager mStorageManager;
+        
+        public ThumbnailGenerationTask(ImageView imageView, FileDataStorageManager storageManager) {
+         // Use a WeakReference to ensure the ImageView can be garbage collected
+            mImageViewReference = new WeakReference<ImageView>(imageView);
+            if (storageManager == null)
+                throw new IllegalArgumentException("storageManager must not be NULL");
+            mStorageManager = storageManager;
+        }
+
+        // Decode image in background.
+        @Override
+        protected Bitmap doInBackground(OCFile... params) {
+            Bitmap thumbnail = null;
+            
+            try {
+                mFile = params[0];
+                final String imageKey = String.valueOf(mFile.getRemoteId());
+    
+                // Check disk cache in background thread
+                thumbnail = getBitmapFromDiskCache(imageKey);
+    
+                // Not found in disk cache
+                if (thumbnail == null || mFile.needsUpdateThumbnail()) { 
+                    // Converts dp to pixel
+                    Resources r = MainApp.getAppContext().getResources();
+                    int px = (int) Math.round(TypedValue.applyDimension(
+                            TypedValue.COMPLEX_UNIT_DIP, 150, r.getDisplayMetrics()
+                    ));
+                    
+                    if (mFile.isDown()){
+                        Bitmap bitmap = BitmapUtils.decodeSampledBitmapFromFile(
+                                mFile.getStoragePath(), px, px);
+                        
+                        if (bitmap != null) {
+                            thumbnail = ThumbnailUtils.extractThumbnail(bitmap, px, px);
+    
+                            // Add thumbnail to cache
+                            addBitmapToCache(imageKey, thumbnail);
+
+                            mFile.setNeedsUpdateThumbnail(false);
+                            mStorageManager.saveFile(mFile);
+                        }
+    
+                    }
+                }
+                
+            } catch (Throwable t) {
+                // the app should never break due to a problem with thumbnails
+                Log_OC.e(TAG, "Generation of thumbnail for " + mFile + " failed", t);
+                if (t instanceof OutOfMemoryError) {
+                    System.gc();
+                }
+            }
+            
+            return thumbnail;
+        }
+        
+        protected void onPostExecute(Bitmap bitmap){
+            if (isCancelled()) {
+                bitmap = null;
+            }
+
+            if (mImageViewReference != null && bitmap != null) {
+                final ImageView imageView = mImageViewReference.get();
+                final ThumbnailGenerationTask bitmapWorkerTask =
+                        getBitmapWorkerTask(imageView);
+                if (this == bitmapWorkerTask && imageView != null) {
+                    if (imageView.getTag().equals(mFile.getFileId())) {
+                        imageView.setImageBitmap(bitmap);
+                    }
+                }
+            }
+        }
+    }
+  
+    
+    public static class AsyncDrawable extends BitmapDrawable {
+        private final WeakReference<ThumbnailGenerationTask> bitmapWorkerTaskReference;
+
+        public AsyncDrawable(
+                Resources res, Bitmap bitmap, ThumbnailGenerationTask bitmapWorkerTask
+            ) {
+            
+            super(res, bitmap);
+            bitmapWorkerTaskReference =
+                new WeakReference<ThumbnailGenerationTask>(bitmapWorkerTask);
+        }
+
+        public ThumbnailGenerationTask getBitmapWorkerTask() {
+            return bitmapWorkerTaskReference.get();
+        }
+    }
+
+    
+    /**
+     * Remove from cache the remoteId passed
+     * @param fileRemoteId: remote id of mFile passed
+     */
+    public static void removeFileFromCache(String fileRemoteId){
+        synchronized (mThumbnailsDiskCacheLock) {
+            if (mThumbnailCache != null) {
+                mThumbnailCache.removeKey(fileRemoteId);
+            }
+            mThumbnailsDiskCacheLock.notifyAll(); // Wake any waiting threads
+        }
+    }
+
+}
index 0ba7b0c..717066b 100644 (file)
@@ -17,8 +17,8 @@
  */
 package com.owncloud.android.db;
 
-import com.owncloud.android.Log_OC;
 import com.owncloud.android.MainApp;
+import com.owncloud.android.lib.common.utils.Log_OC;
 
 import android.content.ContentValues;
 import android.content.Context;
index 8701ebd..bc59869 100644 (file)
  */\r
 package com.owncloud.android.db;\r
 \r
-import com.owncloud.android.MainApp;\r
-\r
 import android.net.Uri;\r
 import android.provider.BaseColumns;\r
 \r
+import com.owncloud.android.MainApp;\r
+\r
 /**\r
  * Meta-Class that holds various static field information\r
  * \r
@@ -30,28 +30,28 @@ import android.provider.BaseColumns;
  */\r
 public class ProviderMeta {\r
 \r
-    /* These constants are now in MainApp\r
-        public static final String AUTHORITY_FILES = "org.owncloud";\r
-        public static final String DB_FILE = "owncloud.db";\r
-    */\r
     public static final String DB_NAME = "filelist";\r
-    public static final int DB_VERSION = 5;\r
+    public static final int DB_VERSION = 8;\r
 \r
     private ProviderMeta() {\r
     }\r
 \r
     static public class ProviderTableMeta implements BaseColumns {\r
-        public static final String DB_NAME = "filelist";\r
+        public static final String FILE_TABLE_NAME = "filelist";\r
+        public static final String OCSHARES_TABLE_NAME = "ocshares";\r
         public static final Uri CONTENT_URI = Uri.parse("content://"\r
                 + MainApp.getAuthority() + "/");\r
         public static final Uri CONTENT_URI_FILE = Uri.parse("content://"\r
                 + MainApp.getAuthority() + "/file");\r
         public static final Uri CONTENT_URI_DIR = Uri.parse("content://"\r
                 + MainApp.getAuthority() + "/dir");\r
+        public static final Uri CONTENT_URI_SHARE = Uri.parse("content://"\r
+                + MainApp.getAuthority() + "/shares");\r
 \r
         public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.owncloud.file";\r
         public static final String CONTENT_TYPE_ITEM = "vnd.android.cursor.item/vnd.owncloud.file";\r
 \r
+        // Columns of filelist table\r
         public static final String FILE_PARENT = "parent";\r
         public static final String FILE_NAME = "filename";\r
         public static final String FILE_CREATION = "created";\r
@@ -66,9 +66,34 @@ public class ProviderMeta {
         public static final String FILE_LAST_SYNC_DATE_FOR_DATA = "last_sync_date_for_data";\r
         public static final String FILE_KEEP_IN_SYNC = "keep_in_sync";\r
         public static final String FILE_ETAG = "etag";\r
+        public static final String FILE_SHARE_BY_LINK = "share_by_link";\r
+        public static final String FILE_PUBLIC_LINK = "public_link";\r
+        public static final String FILE_PERMISSIONS = "permissions";\r
+        public static final String FILE_REMOTE_ID = "remote_id";\r
+        public static final String FILE_UPDATE_THUMBNAIL = "update_thumbnail";\r
 \r
-        public static final String DEFAULT_SORT_ORDER = FILE_NAME\r
+        public static final String FILE_DEFAULT_SORT_ORDER = FILE_NAME\r
+                + " collate nocase asc";\r
+        \r
+        // Columns of ocshares table\r
+        public static final String OCSHARES_FILE_SOURCE = "file_source";\r
+        public static final String OCSHARES_ITEM_SOURCE = "item_source";\r
+        public static final String OCSHARES_SHARE_TYPE = "share_type";\r
+        public static final String OCSHARES_SHARE_WITH = "shate_with";\r
+        public static final String OCSHARES_PATH = "path";\r
+        public static final String OCSHARES_PERMISSIONS = "permissions";\r
+        public static final String OCSHARES_SHARED_DATE = "shared_date";\r
+        public static final String OCSHARES_EXPIRATION_DATE = "expiration_date";\r
+        public static final String OCSHARES_TOKEN = "token";\r
+        public static final String OCSHARES_SHARE_WITH_DISPLAY_NAME = "shared_with_display_name";\r
+        public static final String OCSHARES_IS_DIRECTORY = "is_directory";\r
+        public static final String OCSHARES_USER_ID = "user_id";\r
+        public static final String OCSHARES_ID_REMOTE_SHARED = "id_remote_shared";\r
+        public static final String OCSHARES_ACCOUNT_OWNER = "owner_share";\r
+        \r
+        public static final String OCSHARES_DEFAULT_SORT_ORDER = OCSHARES_FILE_SOURCE \r
                 + " collate nocase asc";\r
+        \r
 \r
     }\r
 }\r
index 8a8c430..4e139ae 100644 (file)
 
 package com.owncloud.android.files;
 
-import com.owncloud.android.Log_OC;
-import com.owncloud.android.files.services.FileObserverService;
+import com.owncloud.android.lib.common.utils.Log_OC;
+import com.owncloud.android.services.observer.FileObserverService;
 
 import android.content.BroadcastReceiver;
 import android.content.Context;
 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 {
 
-    private static String TAG = "BootupBroadcastReceiver";
+    private static String TAG = BootupBroadcastReceiver.class.getSimpleName();
     
+    /**
+     * Receives broadcast intent reporting that the system was just boot up.
+     *
+     * Starts {@link FileObserverService} to enable observation of favourite files.
+     * 
+     * @param   context     The context where the receiver is running.
+     * @param   intent      The intent received.
+     */
     @Override
     public void onReceive(Context context, Intent intent) {
         if (!intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
@@ -36,11 +51,8 @@ public class BootupBroadcastReceiver extends BroadcastReceiver {
             return;
         }
         Log_OC.d(TAG, "Starting file observer service...");
-        Intent i = new Intent(context, FileObserverService.class);
-        i.putExtra(FileObserverService.KEY_FILE_CMD,
-                   FileObserverService.CMD_INIT_OBSERVED_LIST);
-        context.startService(i);
-        Log_OC.d(TAG, "DONE");
+        Intent initObservers = FileObserverService.makeInitIntent(context);
+        context.startService(initObservers);
     }
 
 }
diff --git a/src/com/owncloud/android/files/FileHandler.java b/src/com/owncloud/android/files/FileHandler.java
deleted file mode 100644 (file)
index 2eb754d..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012-2013 ownCloud Inc.
- *
- *   This program is free software: you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License version 2,
- *   as published by the Free Software Foundation.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-package com.owncloud.android.files;
-
-import com.owncloud.android.datamodel.OCFile;
-
-public interface FileHandler {
-
-    /**
-     * TODO
-     */
-    public void openFile(OCFile file);
-
-    
-}
diff --git a/src/com/owncloud/android/files/FileMenuFilter.java b/src/com/owncloud/android/files/FileMenuFilter.java
new file mode 100644 (file)
index 0000000..6eb746c
--- /dev/null
@@ -0,0 +1,247 @@
+/* ownCloud Android client application
+ *   Copyright (C) 2014 ownCloud Inc.
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License version 2,
+ *   as published by the Free Software Foundation.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.files;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import android.accounts.Account;
+import android.content.Context;
+import android.view.Menu;
+import android.view.MenuItem;
+
+import com.owncloud.android.R;
+import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.files.services.FileDownloader;
+import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder;
+import com.owncloud.android.files.services.FileUploader;
+import com.owncloud.android.files.services.FileUploader.FileUploaderBinder;
+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 {
+
+    private OCFile mFile;
+    private ComponentsGetter mComponentsGetter;
+    private Account mAccount;
+    private Context mContext;
+    
+    /**
+     * Constructor
+     * 
+     * @param targetFile        {@link OCFile} target of the action to filter in the {@link Menu}.
+     * @param account           ownCloud {@link Account} holding targetFile.
+     * @param cg                Accessor to app components, needed to get access the 
+     *                          {@link FileUploader} and {@link FileDownloader} services.
+     * @param context           Android {@link Context}, needed to access build setup resources.
+     */
+    public FileMenuFilter(OCFile targetFile, Account account, ComponentsGetter cg, Context context) {
+        mFile = targetFile;
+        mAccount = account;
+        mComponentsGetter = cg;
+        mContext = context;
+    }
+    
+    
+    /**
+     * Filters out the file actions available in the passed {@link Menu} taken into account
+     * the state of the {@link OCFile} held by the filter.
+     *  
+     * @param menu              Options or context menu to filter.
+     */
+    public void filter(Menu menu) {
+        List<Integer> toShow = new ArrayList<Integer>();  
+        List<Integer> toHide = new ArrayList<Integer>();    
+        
+        filter(toShow, toHide);
+        
+        MenuItem item = null;
+        for (int i : toShow) {
+            item = menu.findItem(i);
+            if (item != null) {
+                item.setVisible(true);
+                item.setEnabled(true);
+            }
+        }
+        
+        for (int i : toHide) {
+            item = menu.findItem(i);
+            if (item != null) {
+                item.setVisible(false);
+                item.setEnabled(false);
+            }
+        }
+    }
+
+    /**
+     * Filters out the file actions available in the passed {@link Menu} taken into account
+     * the state of the {@link OCFile} held by the filter.
+     * 
+     * Second method needed thanks to ActionBarSherlock.
+     * 
+     * TODO Get rid of it when ActionBarSherlock is replaced for newer Android Support Library.
+     *  
+     * @param menu              Options or context menu to filter.
+     */
+    public void filter(com.actionbarsherlock.view.Menu menu) {
+
+        List<Integer> toShow = new ArrayList<Integer>();
+        List<Integer> toHide = new ArrayList<Integer>();
+        
+        filter(toShow, toHide);
+
+        com.actionbarsherlock.view.MenuItem item = null;
+        for (int i : toShow) {
+            item = menu.findItem(i);
+            if (item != null) {
+                item.setVisible(true);
+                item.setEnabled(true);
+            }
+        }
+        for (int i : toHide) {
+            item = menu.findItem(i);
+            if (item != null) {
+                item.setVisible(false);
+                item.setEnabled(false);
+            }
+        }
+    }
+
+    /**
+     * Performs the real filtering, to be applied in the {@link Menu} by the caller methods.
+     * 
+     * Decides what actions must be shown and hidden.
+     *  
+     * @param toShow            List to save the options that must be shown in the menu. 
+     * @param toHide            List to save the options that must be shown in the menu.
+     */
+    private void filter(List<Integer> toShow, List <Integer> toHide) {
+        boolean downloading = false;
+        boolean uploading = false;
+        if (mComponentsGetter != null && mFile != null && mAccount != null) {
+            FileDownloaderBinder downloaderBinder = mComponentsGetter.getFileDownloaderBinder();
+            downloading = downloaderBinder != null && downloaderBinder.isDownloading(mAccount, mFile);
+            FileUploaderBinder uploaderBinder = mComponentsGetter.getFileUploaderBinder();
+            uploading = uploaderBinder != null && uploaderBinder.isUploading(mAccount, mFile);
+        }
+        
+        /// decision is taken for each possible action on a file in the menu
+        
+        // DOWNLOAD 
+        if (mFile == null || mFile.isFolder() || mFile.isDown() || downloading || uploading) {
+            toHide.add(R.id.action_download_file);
+            
+        } else {
+            toShow.add(R.id.action_download_file);
+        }
+        
+        // RENAME
+        if (mFile == null || downloading || uploading) {
+            toHide.add(R.id.action_rename_file);
+            
+        } else {
+            toShow.add(R.id.action_rename_file);
+        }
+
+        // MOVE
+        if (mFile == null || downloading || uploading) {
+            toHide.add(R.id.action_move);
+
+        } else {
+            toShow.add(R.id.action_move);
+        }
+        
+        // REMOVE
+        if (mFile == null || downloading || uploading) {
+            toHide.add(R.id.action_remove_file);
+            
+        } else {
+            toShow.add(R.id.action_remove_file);
+        }
+        
+        // OPEN WITH (different to preview!)
+        if (mFile == null || mFile.isFolder() || !mFile.isDown() || downloading || uploading) {
+            toHide.add(R.id.action_open_file_with);
+            
+        } else {
+            toShow.add(R.id.action_open_file_with);
+        }
+        
+        
+        // CANCEL DOWNLOAD
+        if (mFile == null || !downloading || mFile.isFolder()) {
+            toHide.add(R.id.action_cancel_download);
+        } else {
+            toShow.add(R.id.action_cancel_download);
+        }
+        
+        // CANCEL UPLOAD
+        if (mFile == null || !uploading || mFile.isFolder()) {
+            toHide.add(R.id.action_cancel_upload);
+        } else {
+            toShow.add(R.id.action_cancel_upload);
+        }
+        
+        // SYNC FILE CONTENTS
+        if (mFile == null || mFile.isFolder() || !mFile.isDown() || downloading || uploading) {
+            toHide.add(R.id.action_sync_file);
+        } else {
+            toShow.add(R.id.action_sync_file);
+        }
+        
+        // SHARE FILE 
+        // TODO add check on SHARE available on server side?
+        if (mFile == null) {
+            toHide.add(R.id.action_share_file);
+        } else {
+            toShow.add(R.id.action_share_file);
+        }
+        
+        // UNSHARE FILE  
+        // TODO add check on SHARE available on server side?
+        if (mFile == null || !mFile.isShareByLink()) { 
+            toHide.add(R.id.action_unshare_file);
+        } else {
+            toShow.add(R.id.action_unshare_file);
+        }
+        
+        
+        // SEE DETAILS
+        if (mFile == null || mFile.isFolder()) {
+            toHide.add(R.id.action_see_details);
+        } else {
+            toShow.add(R.id.action_see_details);
+        }
+        
+        // SEND
+        boolean sendAllowed = (mContext != null &&
+                mContext.getString(R.string.send_files_to_other_apps).equalsIgnoreCase("on"));
+        if (mFile == null || !sendAllowed || mFile.isFolder() || uploading || downloading) {
+            toHide.add(R.id.action_send_file);
+        } else {
+            toShow.add(R.id.action_send_file);
+        }
+
+    }
+
+}
diff --git a/src/com/owncloud/android/files/FileOperationsHelper.java b/src/com/owncloud/android/files/FileOperationsHelper.java
new file mode 100644 (file)
index 0000000..e1ab195
--- /dev/null
@@ -0,0 +1,298 @@
+/* ownCloud Android client application
+ *   Copyright (C) 2012-2014 ownCloud Inc.
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License version 2,
+ *   as published by the Free Software Foundation.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.files;
+
+import org.apache.http.protocol.HTTP;
+
+import android.accounts.Account;
+import android.accounts.AccountManager;
+import android.content.Intent;
+import android.net.Uri;
+import android.support.v4.app.DialogFragment;
+import android.webkit.MimeTypeMap;
+import android.widget.Toast;
+
+import com.owncloud.android.R;
+import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder;
+import com.owncloud.android.files.services.FileUploader.FileUploaderBinder;
+
+import com.owncloud.android.lib.common.accounts.AccountUtils.Constants;
+import com.owncloud.android.lib.common.network.WebdavUtils;
+import com.owncloud.android.lib.common.utils.Log_OC;
+import com.owncloud.android.lib.resources.status.OwnCloudVersion;
+import com.owncloud.android.services.OperationsService;
+import com.owncloud.android.ui.activity.FileActivity;
+import com.owncloud.android.ui.dialog.ShareLinkToDialog;
+
+/**
+ * 
+ * @author masensio
+ * @author David A. Velasco
+ */
+public class FileOperationsHelper {
+
+    private static final String TAG = FileOperationsHelper.class.getName();
+    
+    private static final String FTAG_CHOOSER_DIALOG = "CHOOSER_DIALOG"; 
+
+    protected FileActivity mFileActivity = null;
+
+    /// Identifier of operation in progress which result shouldn't be lost 
+    private long mWaitingForOpId = Long.MAX_VALUE;
+    
+    public FileOperationsHelper(FileActivity fileActivity) {
+        mFileActivity = fileActivity;
+    }
+
+
+    public void openFile(OCFile file) {
+        if (file != null) {
+            String storagePath = file.getStoragePath();
+            String encodedStoragePath = WebdavUtils.encodePath(storagePath);
+            
+            Intent intentForSavedMimeType = new Intent(Intent.ACTION_VIEW);
+            intentForSavedMimeType.setDataAndType(Uri.parse("file://"+ encodedStoragePath), file.getMimetype());
+            intentForSavedMimeType.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+            
+            Intent intentForGuessedMimeType = null;
+            if (storagePath.lastIndexOf('.') >= 0) {
+                String guessedMimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(storagePath.substring(storagePath.lastIndexOf('.') + 1));
+                if (guessedMimeType != null && !guessedMimeType.equals(file.getMimetype())) {
+                    intentForGuessedMimeType = new Intent(Intent.ACTION_VIEW);
+                    intentForGuessedMimeType.setDataAndType(Uri.parse("file://"+ encodedStoragePath), guessedMimeType);
+                    intentForGuessedMimeType.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+                }
+            }
+            
+            Intent chooserIntent = null;
+            if (intentForGuessedMimeType != null) {
+                chooserIntent = Intent.createChooser(intentForGuessedMimeType, mFileActivity.getString(R.string.actionbar_open_with));
+            } else {
+                chooserIntent = Intent.createChooser(intentForSavedMimeType, mFileActivity.getString(R.string.actionbar_open_with));
+            }
+            
+            mFileActivity.startActivity(chooserIntent);
+            
+        } else {
+            Log_OC.wtf(TAG, "Trying to open a NULL OCFile");
+        }
+    }
+    
+    
+    public void shareFileWithLink(OCFile file) {
+        
+        if (isSharedSupported()) {
+            if (file != null) {
+                String link = "https://fake.url";
+                Intent intent = createShareWithLinkIntent(link);
+                String[] packagesToExclude = new String[] { mFileActivity.getPackageName() };
+                DialogFragment chooserDialog = ShareLinkToDialog.newInstance(intent, packagesToExclude, file);
+                chooserDialog.show(mFileActivity.getSupportFragmentManager(), FTAG_CHOOSER_DIALOG);
+                
+            } else {
+                Log_OC.wtf(TAG, "Trying to share a NULL OCFile");
+            }
+            
+        } else {
+            // Show a Message
+            Toast t = Toast.makeText(mFileActivity, mFileActivity.getString(R.string.share_link_no_support_share_api), Toast.LENGTH_LONG);
+            t.show();
+        }
+    }
+    
+    
+    public void shareFileWithLinkToApp(OCFile file, Intent sendIntent) {
+        
+        if (file != null) {
+            mFileActivity.showLoadingDialog();
+            
+            Intent service = new Intent(mFileActivity, OperationsService.class);
+            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_SEND_INTENT, sendIntent);
+            mWaitingForOpId = mFileActivity.getOperationsServiceBinder().newOperation(service);
+            
+        } else {
+            Log_OC.wtf(TAG, "Trying to open a NULL OCFile");
+        }
+    }
+    
+    
+    private Intent createShareWithLinkIntent(String link) {
+        Intent intentToShareLink = new Intent(Intent.ACTION_SEND);
+        intentToShareLink.putExtra(Intent.EXTRA_TEXT, link);
+        intentToShareLink.setType(HTTP.PLAIN_TEXT_TYPE);
+        return intentToShareLink; 
+    }
+    
+    
+    /**
+     *  @return 'True' if the server supports the Share API
+     */
+    public boolean isSharedSupported() {
+        if (mFileActivity.getAccount() != null) {
+            AccountManager accountManager = AccountManager.get(mFileActivity);
+
+            String version = accountManager.getUserData(mFileActivity.getAccount(), Constants.KEY_OC_VERSION);
+            return (new OwnCloudVersion(version)).isSharedSupported();
+        }
+        return false;
+    }
+    
+    
+    public void unshareFileWithLink(OCFile file) {
+        
+        if (isSharedSupported()) {
+            // Unshare the file
+            Intent service = new Intent(mFileActivity, OperationsService.class);
+            service.setAction(OperationsService.ACTION_UNSHARE);
+            service.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
+            service.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
+            mWaitingForOpId = mFileActivity.getOperationsServiceBinder().newOperation(service);
+            
+            mFileActivity.showLoadingDialog();
+            
+        } else {
+            // Show a Message
+            Toast t = Toast.makeText(mFileActivity, mFileActivity.getString(R.string.share_link_no_support_share_api), Toast.LENGTH_LONG);
+            t.show();
+            
+        }
+    }
+    
+    public void sendDownloadedFile(OCFile file) {
+        if (file != null) {
+            Intent sendIntent = new Intent(android.content.Intent.ACTION_SEND);
+            // set MimeType
+            sendIntent.setType(file.getMimetype());
+            sendIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse("file://" + file.getStoragePath()));
+            sendIntent.putExtra(Intent.ACTION_SEND, true);      // Send Action
+            
+            // Show dialog, without the own app
+            String[] packagesToExclude = new String[] { mFileActivity.getPackageName() };
+            DialogFragment chooserDialog = ShareLinkToDialog.newInstance(sendIntent, packagesToExclude, file);
+            chooserDialog.show(mFileActivity.getSupportFragmentManager(), FTAG_CHOOSER_DIALOG);
+
+        } else {
+            Log_OC.wtf(TAG, "Trying to send a NULL OCFile");
+        }
+    }
+    
+    
+    public void syncFile(OCFile file) {
+        // Sync file
+        Intent service = new Intent(mFileActivity, OperationsService.class);
+        service.setAction(OperationsService.ACTION_SYNC_FILE);
+        service.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
+        service.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath()); 
+        service.putExtra(OperationsService.EXTRA_SYNC_FILE_CONTENTS, true);
+        mWaitingForOpId = mFileActivity.getOperationsServiceBinder().newOperation(service);
+        
+        mFileActivity.showLoadingDialog();
+    }
+    
+    
+    public void renameFile(OCFile file, String newFilename) {
+        // RenameFile
+        Intent service = new Intent(mFileActivity, OperationsService.class);
+        service.setAction(OperationsService.ACTION_RENAME);
+        service.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
+        service.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
+        service.putExtra(OperationsService.EXTRA_NEWNAME, newFilename);
+        mWaitingForOpId = mFileActivity.getOperationsServiceBinder().newOperation(service);
+        
+        mFileActivity.showLoadingDialog();
+    }
+
+
+    public void removeFile(OCFile file, boolean onlyLocalCopy) {
+        // RemoveFile
+        Intent service = new Intent(mFileActivity, OperationsService.class);
+        service.setAction(OperationsService.ACTION_REMOVE);
+        service.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
+        service.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
+        service.putExtra(OperationsService.EXTRA_REMOVE_ONLY_LOCAL, onlyLocalCopy);
+        mWaitingForOpId =  mFileActivity.getOperationsServiceBinder().newOperation(service);
+        
+        mFileActivity.showLoadingDialog();
+    }
+    
+    
+    public void createFolder(String remotePath, boolean createFullPath) {
+        // Create Folder
+        Intent service = new Intent(mFileActivity, OperationsService.class);
+        service.setAction(OperationsService.ACTION_CREATE_FOLDER);
+        service.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
+        service.putExtra(OperationsService.EXTRA_REMOTE_PATH, remotePath);
+        service.putExtra(OperationsService.EXTRA_CREATE_FULL_PATH, createFullPath);
+        mWaitingForOpId =  mFileActivity.getOperationsServiceBinder().newOperation(service);
+        
+        mFileActivity.showLoadingDialog();
+    }
+
+    
+    public void cancelTransference(OCFile file) {
+        Account account = mFileActivity.getAccount();
+        FileDownloaderBinder downloaderBinder = mFileActivity.getFileDownloaderBinder();
+        FileUploaderBinder uploaderBinder =  mFileActivity.getFileUploaderBinder();
+        if (downloaderBinder != null && downloaderBinder.isDownloading(account, file)) {
+            // Remove etag for parent, if file is a keep_in_sync
+            if (file.keepInSync()) {
+               OCFile parent = mFileActivity.getStorageManager().getFileById(file.getParentId());
+               parent.setEtag("");
+               mFileActivity.getStorageManager().saveFile(parent);
+            }
+            
+            downloaderBinder.cancel(account, file);
+            
+        } else if (uploaderBinder != null && uploaderBinder.isUploading(account, file)) {
+            uploaderBinder.cancel(account, file);
+        }
+    }
+
+    /**
+     * Start move file operation
+     * @param newfile           File where it is going to be moved
+     * @param currentFile       File with the previous info
+     */
+    public void moveFile(OCFile newfile, OCFile currentFile) {
+        // Move files
+        Intent service = new Intent(mFileActivity, OperationsService.class);
+        service.setAction(OperationsService.ACTION_MOVE_FILE);
+        service.putExtra(OperationsService.EXTRA_NEW_PARENT_PATH, newfile.getRemotePath());
+        service.putExtra(OperationsService.EXTRA_REMOTE_PATH, currentFile.getRemotePath());
+        service.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
+        mWaitingForOpId =  mFileActivity.getOperationsServiceBinder().newOperation(service);
+
+        mFileActivity.showLoadingDialog();
+    }
+
+
+    public long getOpIdWaitingFor() {
+        return mWaitingForOpId;
+    }
+
+
+    public void setOpIdWaitingFor(long waitingForOpId) {
+        mWaitingForOpId = waitingForOpId;
+    }
+    
+    
+}
index fbb6888..efaa803 100644 (file)
@@ -1,6 +1,6 @@
 /* ownCloud Android client application
  *   Copyright (C) 2012  Bartek Przybylski
- *   Copyright (C) 2012-2013 ownCloud Inc.
+ *   Copyright (C) 2012-2014 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,11 +20,11 @@ package com.owncloud.android.files;
 
 import java.io.File;
 
-import com.owncloud.android.Log_OC;
 import com.owncloud.android.MainApp;
 import com.owncloud.android.authentication.AccountUtils;
 import com.owncloud.android.db.DbHandler;
 import com.owncloud.android.files.services.FileUploader;
+import com.owncloud.android.lib.common.utils.Log_OC;
 import com.owncloud.android.utils.FileStorageUtils;
 
 
@@ -32,23 +32,26 @@ import android.accounts.Account;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
-//import android.content.IntentFilter;
 import android.database.Cursor;
 import android.net.ConnectivityManager;
 import android.net.NetworkInfo.State;
 import android.preference.PreferenceManager;
-import android.provider.MediaStore.Images.Media;
+import android.provider.MediaStore.Images;
+import android.provider.MediaStore.Video;
 import android.webkit.MimeTypeMap;
 
 
 public class InstantUploadBroadcastReceiver extends BroadcastReceiver {
 
-    private static String TAG = "InstantUploadBroadcastReceiver";
-    private static final String[] CONTENT_PROJECTION = { Media.DATA, Media.DISPLAY_NAME, Media.MIME_TYPE, Media.SIZE };
-    //Unofficial action, works for most devices but not HTC. See: https://github.com/owncloud/android/issues/6
+    private static String TAG = InstantUploadBroadcastReceiver.class.getName();
+    // Image action
+    // Unofficial action, works for most devices but not HTC. See: https://github.com/owncloud/android/issues/6
     private static String NEW_PHOTO_ACTION_UNOFFICIAL = "com.android.camera.NEW_PICTURE";
-    //Officially supported action since SDK 14: http://developer.android.com/reference/android/hardware/Camera.html#ACTION_NEW_PICTURE
+    // Officially supported action since SDK 14: http://developer.android.com/reference/android/hardware/Camera.html#ACTION_NEW_PICTURE
     private static String NEW_PHOTO_ACTION = "android.hardware.action.NEW_PICTURE";
+    // Video action
+    // Officially supported action since SDK 14: http://developer.android.com/reference/android/hardware/Camera.html#ACTION_NEW_VIDEO
+    private static String NEW_VIDEO_ACTION = "android.hardware.action.NEW_VIDEO";
 
     @Override
     public void onReceive(Context context, Intent intent) {
@@ -56,35 +59,29 @@ public class InstantUploadBroadcastReceiver extends BroadcastReceiver {
         if (intent.getAction().equals(android.net.ConnectivityManager.CONNECTIVITY_ACTION)) {
             handleConnectivityAction(context, intent);
         }else if (intent.getAction().equals(NEW_PHOTO_ACTION_UNOFFICIAL)) {
-            handleNewPhotoAction(context, intent);
+            handleNewPictureAction(context, intent); 
             Log_OC.d(TAG, "UNOFFICIAL processed: com.android.camera.NEW_PICTURE");
         } else if (intent.getAction().equals(NEW_PHOTO_ACTION)) {
-            handleNewPhotoAction(context, intent);
+            handleNewPictureAction(context, intent); 
             Log_OC.d(TAG, "OFFICIAL processed: android.hardware.action.NEW_PICTURE");
-        } else if (intent.getAction().equals(FileUploader.getUploadFinishMessage())) {
-            handleUploadFinished(context, intent);
+        } else if (intent.getAction().equals(NEW_VIDEO_ACTION)) {
+            Log_OC.d(TAG, "OFFICIAL processed: android.hardware.action.NEW_VIDEO");
+            handleNewVideoAction(context, intent);
         } else {
             Log_OC.e(TAG, "Incorrect intent sent: " + intent.getAction());
         }
     }
 
-    private void handleUploadFinished(Context context, Intent intent) {
-        // remove successfull uploading, ignore rest for reupload on reconnect
-        /*
-        if (intent.getBooleanExtra(FileUploader.EXTRA_UPLOAD_RESULT, false)) {
-            DbHandler db = new DbHandler(context);
-            String localPath = intent.getStringExtra(FileUploader.EXTRA_OLD_FILE_PATH);
-            if (!db.removeIUPendingFile(localPath)) {
-                Log_OC.w(TAG, "Tried to remove non existing instant upload file " + localPath);
-            }
-            db.close();
-        }
-        */
-    }
+    private void handleNewPictureAction(Context context, Intent intent) {
+        Cursor c = null;
+        String file_path = null;
+        String file_name = null;
+        String mime_type = null;
 
-    private void handleNewPhotoAction(Context context, Intent intent) {
-        if (!instantUploadEnabled(context)) {
-            Log_OC.d(TAG, "Instant upload disabled, aborting uploading");
+        Log_OC.w(TAG, "New photo received");
+        
+        if (!instantPictureUploadEnabled(context)) {
+            Log_OC.d(TAG, "Instant picture upload disabled, ignoring new picture");
             return;
         }
 
@@ -94,39 +91,72 @@ public class InstantUploadBroadcastReceiver extends BroadcastReceiver {
             return;
         }
 
-        Cursor c = context.getContentResolver().query(intent.getData(), CONTENT_PROJECTION, null, null, null);
-
+        String[] CONTENT_PROJECTION = { Images.Media.DATA, Images.Media.DISPLAY_NAME, Images.Media.MIME_TYPE, Images.Media.SIZE };
+        c = context.getContentResolver().query(intent.getData(), CONTENT_PROJECTION, null, null, null);
         if (!c.moveToFirst()) {
             Log_OC.e(TAG, "Couldn't resolve given uri: " + intent.getDataString());
             return;
         }
-
-        String file_path = c.getString(c.getColumnIndex(Media.DATA));
-        String file_name = c.getString(c.getColumnIndex(Media.DISPLAY_NAME));
-        String mime_type = c.getString(c.getColumnIndex(Media.MIME_TYPE));
-
+        file_path = c.getString(c.getColumnIndex(Images.Media.DATA));
+        file_name = c.getString(c.getColumnIndex(Images.Media.DISPLAY_NAME));
+        mime_type = c.getString(c.getColumnIndex(Images.Media.MIME_TYPE));
         c.close();
-        Log_OC.e(TAG, file_path + "");
+        
+        Log_OC.d(TAG, file_path + "");
 
-        // same always temporally the picture to upload
+        // save always temporally the picture to upload
         DbHandler db = new DbHandler(context);
         db.putFileForLater(file_path, account.name, null);
         db.close();
 
-        if (!isOnline(context) || (instantUploadViaWiFiOnly(context) && !isConnectedViaWiFi(context))) {
+        if (!isOnline(context) || (instantPictureUploadViaWiFiOnly(context) && !isConnectedViaWiFi(context))) {
+            return;
+        }
+
+        Intent i = new Intent(context, FileUploader.class);
+        i.putExtra(FileUploader.KEY_ACCOUNT, account);
+        i.putExtra(FileUploader.KEY_LOCAL_FILE, file_path);
+        i.putExtra(FileUploader.KEY_REMOTE_FILE, FileStorageUtils.getInstantUploadFilePath(context, file_name));
+        i.putExtra(FileUploader.KEY_UPLOAD_TYPE, FileUploader.UPLOAD_SINGLE_FILE);
+        i.putExtra(FileUploader.KEY_MIME_TYPE, mime_type);
+        i.putExtra(FileUploader.KEY_INSTANT_UPLOAD, true);
+        context.startService(i);
+    }
+
+    private void handleNewVideoAction(Context context, Intent intent) {
+        Cursor c = null;
+        String file_path = null;
+        String file_name = null;
+        String mime_type = null;
+
+        Log_OC.w(TAG, "New video received");
+        
+        if (!instantVideoUploadEnabled(context)) {
+            Log_OC.d(TAG, "Instant video upload disabled, ignoring new video");
             return;
         }
 
-        // register for upload finishe message
-        // there is a litte problem with android API, we can register for
-        // particular
-        // intent in registerReceiver but we cannot unregister from precise
-        // intent
-        // we can unregister from entire listenings but thats suck a bit.
-        // On the other hand this might be only for dynamicly registered
-        // broadcast receivers, needs investigation.
-        /*IntentFilter filter = new IntentFilter(FileUploader.UPLOAD_FINISH_MESSAGE);
-        context.getApplicationContext().registerReceiver(this, filter);*/
+        Account account = AccountUtils.getCurrentOwnCloudAccount(context);
+        if (account == null) {
+            Log_OC.w(TAG, "No owncloud account found for instant upload, aborting");
+            return;
+        }
+
+        String[] CONTENT_PROJECTION = { Video.Media.DATA, Video.Media.DISPLAY_NAME, Video.Media.MIME_TYPE, Video.Media.SIZE };
+        c = context.getContentResolver().query(intent.getData(), CONTENT_PROJECTION, null, null, null);
+        if (!c.moveToFirst()) {
+            Log_OC.e(TAG, "Couldn't resolve given uri: " + intent.getDataString());
+            return;
+        } 
+        file_path = c.getString(c.getColumnIndex(Video.Media.DATA));
+        file_name = c.getString(c.getColumnIndex(Video.Media.DISPLAY_NAME));
+        mime_type = c.getString(c.getColumnIndex(Video.Media.MIME_TYPE));
+        c.close();
+        Log_OC.d(TAG, file_path + "");
+
+        if (!isOnline(context) || (instantVideoUploadViaWiFiOnly(context) && !isConnectedViaWiFi(context))) {
+            return;
+        }
 
         Intent i = new Intent(context, FileUploader.class);
         i.putExtra(FileUploader.KEY_ACCOUNT, account);
@@ -140,19 +170,17 @@ public class InstantUploadBroadcastReceiver extends BroadcastReceiver {
     }
 
     private void handleConnectivityAction(Context context, Intent intent) {
-        if (!instantUploadEnabled(context)) {
-            Log_OC.d(TAG, "Instant upload disabled, abording uploading");
+        if (!instantPictureUploadEnabled(context)) {
+            Log_OC.d(TAG, "Instant upload disabled, don't upload anything");
             return;
         }
 
         if (!intent.hasExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY)
                 && isOnline(context)
-                && (!instantUploadViaWiFiOnly(context) || (instantUploadViaWiFiOnly(context) == isConnectedViaWiFi(context) == true))) {
+                && (!instantPictureUploadViaWiFiOnly(context) || (instantPictureUploadViaWiFiOnly(context) == isConnectedViaWiFi(context) == true))) {
             DbHandler db = new DbHandler(context);
             Cursor c = db.getAwaitingFiles();
             if (c.moveToFirst()) {
-                //IntentFilter filter = new IntentFilter(FileUploader.UPLOAD_FINISH_MESSAGE);
-                //context.getApplicationContext().registerReceiver(this, filter);
                 do {
                     String account_name = c.getString(c.getColumnIndex("account"));
                     String file_path = c.getString(c.getColumnIndex("path"));
@@ -202,11 +230,19 @@ public class InstantUploadBroadcastReceiver extends BroadcastReceiver {
                 && cm.getActiveNetworkInfo().getState() == State.CONNECTED;
     }
 
-    public static boolean instantUploadEnabled(Context context) {
+    public static boolean instantPictureUploadEnabled(Context context) {
         return PreferenceManager.getDefaultSharedPreferences(context).getBoolean("instant_uploading", false);
     }
 
-    public static boolean instantUploadViaWiFiOnly(Context context) {
+    public static boolean instantVideoUploadEnabled(Context context) {
+        return PreferenceManager.getDefaultSharedPreferences(context).getBoolean("instant_video_uploading", false);
+    }
+
+    public static boolean instantPictureUploadViaWiFiOnly(Context context) {
         return PreferenceManager.getDefaultSharedPreferences(context).getBoolean("instant_upload_on_wifi", false);
     }
+    
+    public static boolean instantVideoUploadViaWiFiOnly(Context context) {
+        return PreferenceManager.getDefaultSharedPreferences(context).getBoolean("instant_video_upload_on_wifi", false);
+    }
 }
diff --git a/src/com/owncloud/android/files/OwnCloudFileObserver.java b/src/com/owncloud/android/files/OwnCloudFileObserver.java
deleted file mode 100644 (file)
index 964b61c..0000000
+++ /dev/null
@@ -1,112 +0,0 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012 Bartek Przybylski
- *   Copyright (C) 2012-2013 ownCloud Inc.
- *
- *   This program is free software: you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License version 2,
- *   as published by the Free Software Foundation.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-package com.owncloud.android.files;
-
-import java.io.File;
-
-import com.owncloud.android.Log_OC;
-import com.owncloud.android.datamodel.FileDataStorageManager;
-import com.owncloud.android.datamodel.OCFile;
-import com.owncloud.android.operations.RemoteOperationResult;
-import com.owncloud.android.operations.SynchronizeFileOperation;
-import com.owncloud.android.operations.RemoteOperationResult.ResultCode;
-import com.owncloud.android.ui.activity.ConflictsResolveActivity;
-
-import android.accounts.Account;
-import android.content.Context;
-import android.content.Intent;
-import android.os.FileObserver;
-
-public class OwnCloudFileObserver extends FileObserver {
-
-    private static int MASK = (FileObserver.MODIFY | FileObserver.CLOSE_WRITE);
-    
-    private static String TAG = OwnCloudFileObserver.class.getSimpleName();
-    
-    private String mPath;
-    private int mMask;
-    private Account mOCAccount;
-    private Context mContext;
-    private boolean mModified;
-
-    
-    public OwnCloudFileObserver(String path, Account account, Context context) {
-        super(path, MASK);
-        if (path == null)
-            throw new IllegalArgumentException("NULL path argument received"); 
-        if (account == null)
-            throw new IllegalArgumentException("NULL account argument received"); 
-        if (context == null)
-            throw new IllegalArgumentException("NULL context argument received");
-        mPath = path;
-        mOCAccount = account;
-        mContext = context; 
-        mModified = false;
-    }
-    
-    
-    @Override
-    public void onEvent(int event, String path) {
-        Log_OC.d(TAG, "Got file modified with event " + event + " and path " + mPath + ((path != null) ? File.separator + path : ""));
-        if ((event & MASK) == 0) {
-            Log_OC.wtf(TAG, "Incorrect event " + event + " sent for file " + mPath + ((path != null) ? File.separator + path : "") +
-                         " with registered for " + mMask + " and original path " +
-                         mPath);
-        } else {
-            if ((event & FileObserver.MODIFY) != 0) {
-                // file changed
-                mModified = true;
-            }
-            // not sure if it's possible, but let's assume that both kind of events can be received at the same time
-            if ((event & FileObserver.CLOSE_WRITE) != 0) {
-                // file closed
-                if (mModified) {
-                    mModified = false;
-                    startSyncOperation();
-                }
-            }
-        }  
-    }
-
-    
-    private void startSyncOperation() {
-        FileDataStorageManager storageManager = new FileDataStorageManager(mOCAccount, mContext.getContentResolver());
-        OCFile file = storageManager.getFileByLocalPath(mPath);     // a fresh object is needed; many things could have occurred to the file since it was registered to observe
-                                                                    // again, assuming that local files are linked to a remote file AT MOST, SOMETHING TO BE DONE; 
-        SynchronizeFileOperation sfo = new SynchronizeFileOperation(file, 
-                                                                    null, 
-                                                                    storageManager, 
-                                                                    mOCAccount, 
-                                                                    true, 
-                                                                    mContext);
-        RemoteOperationResult result = sfo.execute(mOCAccount, mContext);
-        if (result.getCode() == ResultCode.SYNC_CONFLICT) {
-            // ISSUE 5: if the user is not running the app (this is a service!), this can be very intrusive; a notification should be preferred
-            Intent i = new Intent(mContext, ConflictsResolveActivity.class);
-            i.setFlags(i.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
-            i.putExtra(ConflictsResolveActivity.EXTRA_FILE, file);
-            i.putExtra(ConflictsResolveActivity.EXTRA_ACCOUNT, mOCAccount);
-            mContext.startActivity(i);
-        }
-        // TODO save other errors in some point where the user can inspect them later;
-        //      or maybe just toast them;
-        //      or nothing, very strange fails
-    }
-    
-}
diff --git a/src/com/owncloud/android/files/managers/OCNotificationManager.java b/src/com/owncloud/android/files/managers/OCNotificationManager.java
deleted file mode 100644 (file)
index 11a8c37..0000000
+++ /dev/null
@@ -1,155 +0,0 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012  Bartek Przybylski
- *   Copyright (C) 2012-2013 ownCloud Inc.
- *
- *   This program is free software: you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License version 2,
- *   as published by the Free Software Foundation.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-package com.owncloud.android.files.managers;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import com.owncloud.android.R;
-
-import android.app.Notification;
-import android.app.NotificationManager;
-import android.content.Context;
-import android.widget.RemoteViews;
-
-
-public class OCNotificationManager {
-
-    enum NotificationType {
-        NOTIFICATION_SIMPLE,
-        NOTIFICATION_PROGRESS
-    }
-    
-    static public class NotificationData {
-        private String mText, mSubtitle;
-        private int mPercent;
-        private boolean mOngoing;
-
-        public NotificationData(String text, String subtitle, boolean ongoing) {
-            this(text, subtitle, -1, ongoing);
-        }
-        
-        public NotificationData(int percent, boolean ongoing) {
-            this(null, null, percent, ongoing);
-        }
-        
-        public NotificationData(String text, int percent, boolean ongoing) {
-            this(text, null, percent, ongoing);
-        }
-        
-        public NotificationData(String text, String subtitle, int percent, boolean ongoing) {
-            mText = text;
-            mPercent = percent;
-            mSubtitle = subtitle;
-            mOngoing = ongoing;
-        }
-        
-        public String getText() { return mText; }
-        public int getPercent() { return mPercent; }
-        public String getSubtitle() { return mSubtitle; }
-        public boolean getOngoing() { return mOngoing; }
-    }
-    
-    static private OCNotificationManager mInstance = null;
-
-    private class NotificationTypePair {
-        public Notification mNotificaiton;
-        public NotificationType mType;
-        public NotificationTypePair(Notification n, NotificationType type) {
-            mNotificaiton = n;
-            mType = type;
-        }
-    }
-    
-    private Context mContext;
-    private Map<Integer, NotificationTypePair> mNotificationMap;
-    private int mNotificationCounter;
-    NotificationManager mNM;
-    
-    static OCNotificationManager getInstance(Context context) {
-        if (mInstance == null)
-            mInstance = new OCNotificationManager(context);
-        return mInstance;
-    }
-    
-    OCNotificationManager(Context context) {
-        mContext = context;
-        mNotificationMap = new HashMap<Integer, NotificationTypePair>();
-        mNM = (NotificationManager)mContext.getSystemService(Context.NOTIFICATION_SERVICE);
-        mNotificationCounter = 0;
-    }
-    
-    public int postNotification(NotificationType type, NotificationData data) {
-        mNotificationCounter++;
-        Notification notification = null;
-        
-        switch (type) {
-            case NOTIFICATION_SIMPLE:
-                notification = new Notification(R.drawable.icon, data.getText(), System.currentTimeMillis());
-                break;
-            case NOTIFICATION_PROGRESS:
-                notification = new Notification();
-                notification.contentView = new RemoteViews(mContext.getPackageName(), R.layout.progressbar_layout);
-                notification.contentView.setTextViewText(R.id.status_text,
-                                                         data.getText());
-                notification.contentView.setImageViewResource(R.id.status_icon,
-                                                              R.id.icon);
-                notification.contentView.setProgressBar(R.id.status_progress,
-                                                        100,
-                                                        data.getPercent(),
-                                                        false);
-                break;
-            default:
-                return -1;
-        }
-        if (data.getOngoing()) {
-            notification.flags |= notification.flags | Notification.FLAG_ONGOING_EVENT;
-        }
-        
-        mNotificationMap.put(mNotificationCounter, new NotificationTypePair(notification, type));
-        return mNotificationCounter;
-    }
-    
-    public boolean updateNotification(int notification_id, NotificationData data) {
-        if (!mNotificationMap.containsKey(notification_id)) {
-            return false;
-        }
-        NotificationTypePair pair = mNotificationMap.get(notification_id);
-        switch (pair.mType) {
-            case NOTIFICATION_PROGRESS:
-                pair.mNotificaiton.contentView.setProgressBar(R.id.status_text,
-                                                              100,
-                                                              data.getPercent(),
-                                                              false);
-                return true;
-            case NOTIFICATION_SIMPLE:
-                pair.mNotificaiton = new Notification(R.drawable.icon,
-                                                      data.getText(), System.currentTimeMillis());
-                mNM.notify(notification_id, pair.mNotificaiton);
-                return true;
-            default:
-                return false;
-        }
-    }
-    
-    public void discardNotification(int notification_id) {
-        mNM.cancel(notification_id);
-        mNotificationMap.remove(notification_id);
-    }
-}
index 2e479f4..fdc35f8 100644 (file)
@@ -28,27 +28,30 @@ import java.util.Vector;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 
-import com.owncloud.android.Log_OC;
-import com.owncloud.android.MainApp;
 import com.owncloud.android.R;
 import com.owncloud.android.authentication.AuthenticatorActivity;
 import com.owncloud.android.datamodel.FileDataStorageManager;
 import com.owncloud.android.datamodel.OCFile;
-import com.owncloud.android.network.OwnCloudClientUtils;
+
+import com.owncloud.android.lib.common.network.OnDatatransferProgressListener;
+import com.owncloud.android.lib.common.OwnCloudAccount;
+import com.owncloud.android.lib.common.OwnCloudClient;
+import com.owncloud.android.lib.common.OwnCloudClientManagerFactory;
+import com.owncloud.android.notifications.NotificationBuilderWithProgressBar;
+import com.owncloud.android.notifications.NotificationDelayer;
+import com.owncloud.android.lib.common.operations.RemoteOperationResult;
+import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;
+import com.owncloud.android.lib.common.utils.Log_OC;
+import com.owncloud.android.lib.resources.files.FileUtils;
 import com.owncloud.android.operations.DownloadFileOperation;
-import com.owncloud.android.operations.RemoteOperationResult;
-import com.owncloud.android.operations.RemoteOperationResult.ResultCode;
 import com.owncloud.android.ui.activity.FileActivity;
 import com.owncloud.android.ui.activity.FileDisplayActivity;
 import com.owncloud.android.ui.preview.PreviewImageActivity;
 import com.owncloud.android.ui.preview.PreviewImageFragment;
-
-import eu.alefzero.webdav.OnDatatransferProgressListener;
-
+import com.owncloud.android.utils.ErrorMessageAdapter;
 
 import android.accounts.Account;
 import android.accounts.AccountsException;
-import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.app.Service;
@@ -60,9 +63,7 @@ import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
 import android.os.Process;
-import android.widget.RemoteViews;
-
-import eu.alefzero.webdav.WebdavClient;
+import android.support.v4.app.NotificationCompat;
 
 public class FileDownloader extends Service implements OnDatatransferProgressListener {
     
@@ -81,7 +82,7 @@ public class FileDownloader extends Service implements OnDatatransferProgressLis
     private Looper mServiceLooper;
     private ServiceHandler mServiceHandler;
     private IBinder mBinder;
-    private WebdavClient mDownloadClient = null;
+    private OwnCloudClient mDownloadClient = null;
     private Account mLastAccount = null;
     private FileDataStorageManager mStorageManager;
     
@@ -89,7 +90,7 @@ public class FileDownloader extends Service implements OnDatatransferProgressLis
     private DownloadFileOperation mCurrentDownload = null;
     
     private NotificationManager mNotificationManager;
-    private Notification mNotification;
+    private NotificationCompat.Builder mNotificationBuilder;
     private int mLastPercent;
     
     
@@ -284,13 +285,6 @@ public class FileDownloader extends Service implements OnDatatransferProgressLis
             }
         }
 
-
-        @Override
-        public void onTransferProgress(long progressRate) {
-            // old way, should not be in use any more
-        }
-
-
         @Override
         public void onTransferProgress(long progressRate, long totalTransferredSoFar, long totalToTransfer,
                 String fileName) {
@@ -354,8 +348,11 @@ public class FileDownloader extends Service implements OnDatatransferProgressLis
                 /// prepare client object to send the request to the ownCloud server
                 if (mDownloadClient == null || !mLastAccount.equals(mCurrentDownload.getAccount())) {
                     mLastAccount = mCurrentDownload.getAccount();
-                    mStorageManager = new FileDataStorageManager(mLastAccount, getContentResolver());
-                    mDownloadClient = OwnCloudClientUtils.createOwnCloudClient(mLastAccount, getApplicationContext());
+                    mStorageManager = 
+                            new FileDataStorageManager(mLastAccount, getContentResolver());
+                    OwnCloudAccount ocAccount = new OwnCloudAccount(mLastAccount, this);
+                    mDownloadClient = OwnCloudClientManagerFactory.getDefaultSingleton().
+                            getClientFor(ocAccount, this);
                 }
 
                 /// perform the download
@@ -390,16 +387,18 @@ public class FileDownloader extends Service implements OnDatatransferProgressLis
      * Updates the OC File after a successful download.
      */
     private void saveDownloadedFile() {
-        OCFile file = mCurrentDownload.getFile();
+        OCFile file = mStorageManager.getFileById(mCurrentDownload.getFile().getFileId());
         long syncDate = System.currentTimeMillis();
         file.setLastSyncDateForProperties(syncDate);
         file.setLastSyncDateForData(syncDate);
+        file.setNeedsUpdateThumbnail(true);
         file.setModificationTimestamp(mCurrentDownload.getModificationTimestamp());
         file.setModificationTimestampAtLastSyncForData(mCurrentDownload.getModificationTimestamp());
         // file.setEtag(mCurrentDownload.getEtag());    // TODO Etag, where available
         file.setMimetype(mCurrentDownload.getMimeType());
         file.setStoragePath(mCurrentDownload.getSavePath());
         file.setFileLength((new File(mCurrentDownload.getSavePath()).length()));
+        file.setRemoteId(mCurrentDownload.getFile().getRemoteId());
         mStorageManager.saveFile(file);
     }
 
@@ -412,13 +411,19 @@ public class FileDownloader extends Service implements OnDatatransferProgressLis
     private void notifyDownloadStart(DownloadFileOperation download) {
         /// create status notification with a progress bar
         mLastPercent = 0;
-        mNotification = new Notification(R.drawable.icon, getString(R.string.downloader_download_in_progress_ticker), System.currentTimeMillis());
-        mNotification.flags |= Notification.FLAG_ONGOING_EVENT;
-        mNotification.contentView = new RemoteViews(getApplicationContext().getPackageName(), R.layout.progressbar_layout);
-        mNotification.contentView.setProgressBar(R.id.status_progress, 100, 0, download.getSize() < 0);
-        mNotification.contentView.setTextViewText(R.id.status_text, String.format(getString(R.string.downloader_download_in_progress_content), 0, new File(download.getSavePath()).getName()));
-        mNotification.contentView.setImageViewResource(R.id.status_icon, R.drawable.icon);
-        
+        mNotificationBuilder = 
+                NotificationBuilderWithProgressBar.newNotificationBuilderWithProgressBar(this);
+        mNotificationBuilder
+                .setSmallIcon(R.drawable.notification_icon)
+                .setTicker(getString(R.string.downloader_download_in_progress_ticker))
+                .setContentTitle(getString(R.string.downloader_download_in_progress_ticker))
+                .setOngoing(true)
+                .setProgress(100, 0, download.getSize() < 0)
+                .setContentText(
+                        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())) {
@@ -429,9 +434,12 @@ 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);
-        mNotification.contentIntent = PendingIntent.getActivity(getApplicationContext(), (int)System.currentTimeMillis(), showDetailsIntent, 0);
         
-        mNotificationManager.notify(R.string.downloader_download_in_progress_ticker, mNotification);
+        mNotificationBuilder.setContentIntent(PendingIntent.getActivity(
+            this, (int) System.currentTimeMillis(), showDetailsIntent, 0
+        ));
+
+        mNotificationManager.notify(R.string.downloader_download_in_progress_ticker, mNotificationBuilder.build());
     }
 
     
@@ -439,28 +447,20 @@ public class FileDownloader extends Service implements OnDatatransferProgressLis
      * Callback method to update the progress bar in the status notification.
      */
     @Override
-    public void onTransferProgress(long progressRate, long totalTransferredSoFar, long totalToTransfer, String fileName) {
+    public void onTransferProgress(long progressRate, long totalTransferredSoFar, long totalToTransfer, String filePath) {
         int percent = (int)(100.0*((double)totalTransferredSoFar)/((double)totalToTransfer));
         if (percent != mLastPercent) {
-          mNotification.contentView.setProgressBar(R.id.status_progress, 100, percent, totalToTransfer < 0);
-          String text = String.format(getString(R.string.downloader_download_in_progress_content), percent, fileName);
-          mNotification.contentView.setTextViewText(R.id.status_text, text);
-          mNotificationManager.notify(R.string.downloader_download_in_progress_ticker, mNotification);
+            mNotificationBuilder.setProgress(100, percent, totalToTransfer < 0);
+            String fileName = filePath.substring(filePath.lastIndexOf(FileUtils.PATH_SEPARATOR) + 1);
+            String text = String.format(getString(R.string.downloader_download_in_progress_content), percent, fileName);
+            mNotificationBuilder.setContentText(text);
+            mNotificationManager.notify(R.string.downloader_download_in_progress_ticker, mNotificationBuilder.build());
         }
         mLastPercent = percent;
     }
     
     
     /**
-     * Callback method to update the progress bar in the status notification (old version)
-     */
-    @Override
-    public void onTransferProgress(long progressRate) {
-        // NOTHING TO DO HERE ANYMORE
-    }
-    
-
-    /**
      * Updates the status notification with the result of a download operation.
      * 
      * @param downloadResult    Result of the download operation.
@@ -469,50 +469,58 @@ public class FileDownloader extends Service implements OnDatatransferProgressLis
     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 contentId = (downloadResult.isSuccess()) ? R.string.downloader_download_succeeded_content : R.string.downloader_download_failed_content;
-            Notification finalNotification = new Notification(R.drawable.icon, getString(tickerId), System.currentTimeMillis());
-            finalNotification.flags |= Notification.FLAG_AUTO_CANCEL;
-            boolean needsToUpdateCredentials = (downloadResult.getCode() == ResultCode.UNAUTHORIZED ||
-                                                // (downloadResult.isTemporalRedirection() && downloadResult.isIdPRedirection()
-                                                  (downloadResult.isIdPRedirection()
-                                                        && MainApp.getAuthTokenTypeSamlSessionCookie().equals(mDownloadClient.getAuthTokenType())));
+            int tickerId = (downloadResult.isSuccess()) ? R.string.downloader_download_succeeded_ticker : 
+                R.string.downloader_download_failed_ticker;
+            
+            boolean needsToUpdateCredentials = (
+                    downloadResult.getCode() == ResultCode.UNAUTHORIZED ||
+                    downloadResult.isIdPRedirection()
+            );
+            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);
+            
             if (needsToUpdateCredentials) {
+                
                 // let the user update credentials with one click
                 Intent updateAccountCredentials = new Intent(this, AuthenticatorActivity.class);
                 updateAccountCredentials.putExtra(AuthenticatorActivity.EXTRA_ACCOUNT, download.getAccount());
-                updateAccountCredentials.putExtra(AuthenticatorActivity.EXTRA_ENFORCED_UPDATE, true);
-                updateAccountCredentials.putExtra(AuthenticatorActivity.EXTRA_ACTION, AuthenticatorActivity.ACTION_UPDATE_TOKEN);
+                updateAccountCredentials.putExtra(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);
-                finalNotification.contentIntent = PendingIntent.getActivity(this, (int)System.currentTimeMillis(), updateAccountCredentials, PendingIntent.FLAG_ONE_SHOT);
-                finalNotification.setLatestEventInfo(   getApplicationContext(), 
-                                                        getString(tickerId), 
-                                                        String.format(getString(contentId), new File(download.getSavePath()).getName()),
-                                                        finalNotification.contentIntent);
+                mNotificationBuilder
+                    .setContentIntent(PendingIntent.getActivity(
+                        this, (int) System.currentTimeMillis(), updateAccountCredentials, PendingIntent.FLAG_ONE_SHOT));
+                
                 mDownloadClient = null;   // grant that future retries on the same account will get the fresh credentials
                 
             } else {
-                Intent showDetailsIntent = null;
-                if (downloadResult.isSuccess()) {
-                    if (PreviewImageFragment.canBePreviewed(download.getFile())) {
-                        showDetailsIntent = new Intent(this, PreviewImageActivity.class);
-                    } else {
-                        showDetailsIntent = new Intent(this, FileDisplayActivity.class);
-                    }
-                    showDetailsIntent.putExtra(FileActivity.EXTRA_FILE, download.getFile());
-                    showDetailsIntent.putExtra(FileActivity.EXTRA_ACCOUNT, download.getAccount());
-                    showDetailsIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
-                    
-                } else {
-                    // TODO put something smart in showDetailsIntent
-                    showDetailsIntent = new Intent();
-                }
-                finalNotification.contentIntent = PendingIntent.getActivity(getApplicationContext(), (int)System.currentTimeMillis(), showDetailsIntent, 0);
-                finalNotification.setLatestEventInfo(getApplicationContext(), getString(tickerId), String.format(getString(contentId), new File(download.getSavePath()).getName()), finalNotification.contentIntent);
+                // TODO put something smart in showDetailsIntent
+                Intent   showDetailsIntent = new Intent();
+                mNotificationBuilder
+                    .setContentIntent(PendingIntent.getActivity(
+                        this, (int) System.currentTimeMillis(), showDetailsIntent, 0));
             }
-            mNotificationManager.notify(tickerId, finalNotification);
+            
+            mNotificationBuilder.setContentText(ErrorMessageAdapter.getErrorCauseMessage(downloadResult, download, getResources()));
+            mNotificationManager.notify(tickerId, mNotificationBuilder.build());
+            
+            // Remove success notification
+            if (downloadResult.isSuccess()) {   
+                // Sleep 2 seconds, so show the notification before remove it
+                NotificationDelayer.cancelWithDelay(
+                        mNotificationManager, 
+                        R.string.downloader_download_succeeded_ticker, 
+                        2000);
+            }
+                
         }
     }
     
diff --git a/src/com/owncloud/android/files/services/FileObserverService.java b/src/com/owncloud/android/files/services/FileObserverService.java
deleted file mode 100644 (file)
index 502d459..0000000
+++ /dev/null
@@ -1,276 +0,0 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012 Bartek Przybylski
- *   Copyright (C) 2012-2013 ownCloud Inc.
- *
- *   This program is free software: you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License version 2,
- *   as published by the Free Software Foundation.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-package com.owncloud.android.files.services;
-
-import java.io.File;
-import java.util.HashMap;
-import java.util.Map;
-
-import com.owncloud.android.Log_OC;
-import com.owncloud.android.datamodel.FileDataStorageManager;
-import com.owncloud.android.datamodel.OCFile;
-import com.owncloud.android.db.ProviderMeta.ProviderTableMeta;
-import com.owncloud.android.files.OwnCloudFileObserver;
-import com.owncloud.android.operations.SynchronizeFileOperation;
-import com.owncloud.android.utils.FileStorageUtils;
-
-
-import android.accounts.Account;
-import android.accounts.AccountManager;
-import android.app.Service;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.database.Cursor;
-import android.os.Binder;
-import android.os.IBinder;
-
-public class FileObserverService extends Service {
-
-    public final static int CMD_INIT_OBSERVED_LIST = 1;
-    public final static int CMD_ADD_OBSERVED_FILE = 2;
-    public final static int CMD_DEL_OBSERVED_FILE = 3;
-
-    public final static String KEY_FILE_CMD = "KEY_FILE_CMD";
-    public final static String KEY_CMD_ARG_FILE = "KEY_CMD_ARG_FILE";
-    public final static String KEY_CMD_ARG_ACCOUNT = "KEY_CMD_ARG_ACCOUNT";
-
-    private static String TAG = FileObserverService.class.getSimpleName();
-
-    private static Map<String, OwnCloudFileObserver> mObserversMap;
-    private static DownloadCompletedReceiverBis mDownloadReceiver;
-    private IBinder mBinder = new LocalBinder();
-    
-    public class LocalBinder extends Binder {
-        FileObserverService getService() {
-            return FileObserverService.this;
-        }
-    }
-    
-    @Override
-    public void onCreate() {
-        super.onCreate();
-        mDownloadReceiver = new DownloadCompletedReceiverBis();
-        
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(FileDownloader.getDownloadAddedMessage());
-        filter.addAction(FileDownloader.getDownloadFinishMessage());        
-        registerReceiver(mDownloadReceiver, filter);
-        
-        mObserversMap = new HashMap<String, OwnCloudFileObserver>();
-        //initializeObservedList();
-    }
-    
-    
-    @Override
-    public void onDestroy() {
-        super.onDestroy();
-        unregisterReceiver(mDownloadReceiver);
-        mObserversMap = null;   // TODO study carefully the life cycle of Services to grant the best possible observance
-        Log_OC.d(TAG, "Bye, bye");
-    }
-    
-    
-    @Override
-    public IBinder onBind(Intent intent) {
-        return mBinder;
-    }
-
-    @Override
-    public int onStartCommand(Intent intent, int flags, int startId) {
-        // this occurs when system tries to restart
-        // service, so we need to reinitialize observers
-        if (intent == null) {
-            initializeObservedList();
-            return Service.START_STICKY;
-        }
-            
-        if (!intent.hasExtra(KEY_FILE_CMD)) {
-            Log_OC.e(TAG, "No KEY_FILE_CMD argument given");
-            return Service.START_STICKY;
-        }
-
-        switch (intent.getIntExtra(KEY_FILE_CMD, -1)) {
-            case CMD_INIT_OBSERVED_LIST:
-                initializeObservedList();
-                break;
-            case CMD_ADD_OBSERVED_FILE:
-                addObservedFile( (OCFile)intent.getParcelableExtra(KEY_CMD_ARG_FILE), 
-                                 (Account)intent.getParcelableExtra(KEY_CMD_ARG_ACCOUNT));
-                break;
-            case CMD_DEL_OBSERVED_FILE:
-                removeObservedFile( (OCFile)intent.getParcelableExtra(KEY_CMD_ARG_FILE), 
-                                    (Account)intent.getParcelableExtra(KEY_CMD_ARG_ACCOUNT));
-                break;
-            default:
-                Log_OC.wtf(TAG, "Incorrect key given");
-        }
-
-        return Service.START_STICKY;
-    }
-
-    
-    /**
-     * Read from the local database the list of files that must to be kept synchronized and 
-     * starts file observers to monitor local changes on them
-     */
-    private void initializeObservedList() {
-        mObserversMap.clear();
-        Cursor c = getContentResolver().query(
-                ProviderTableMeta.CONTENT_URI,
-                null,
-                ProviderTableMeta.FILE_KEEP_IN_SYNC + " = ?",
-                new String[] {String.valueOf(1)},
-                null);
-        if (c == null || !c.moveToFirst()) return;
-        AccountManager acm = AccountManager.get(this);
-        Account[] accounts = acm.getAccounts();
-        do {
-            Account account = null;
-            for (Account a : accounts)
-                if (a.name.equals(c.getString(c.getColumnIndex(ProviderTableMeta.FILE_ACCOUNT_OWNER)))) {
-                    account = a;
-                    break;
-                }
-
-            if (account == null) continue;
-            FileDataStorageManager storage =
-                    new FileDataStorageManager(account, getContentResolver());
-            if (!storage.fileExists(c.getString(c.getColumnIndex(ProviderTableMeta.FILE_PATH))))
-                continue;
-
-            String path = c.getString(c.getColumnIndex(ProviderTableMeta.FILE_STORAGE_PATH));
-            if (path == null || path.length() <= 0)
-                continue;
-            OwnCloudFileObserver observer =
-                    new OwnCloudFileObserver(   path, 
-                                                account, 
-                                                getApplicationContext());
-            mObserversMap.put(path, observer);
-            if (new File(path).exists()) {
-                observer.startWatching();
-                Log_OC.d(TAG, "Started watching file " + path);
-            }
-            
-        } while (c.moveToNext());
-        c.close();
-    }
-    
-    
-    /**
-     * Registers the local copy of a remote file to be observed for local changes,
-     * an automatically updated in the ownCloud server.
-     * 
-     * This method does NOT perform a {@link SynchronizeFileOperation} over the file. 
-     *
-     * TODO We are ignoring that, currently, a local file can be linked to different files
-     * in ownCloud if it's uploaded several times. That's something pending to update: we 
-     * will avoid that the same local file is linked to different remote files.
-     * 
-     * @param file      Object representing a remote file which local copy must be observed.
-     * @param account   OwnCloud account containing file.
-     */
-    private void addObservedFile(OCFile file, Account account) {
-        if (file == null) {
-            Log_OC.e(TAG, "Trying to add a NULL file to observer");
-            return;
-        }
-        String localPath = file.getStoragePath();
-        if (localPath == null || localPath.length() <= 0) { // file downloading / to be download for the first time
-            localPath = FileStorageUtils.getDefaultSavePathFor(account.name, file);
-        }
-        OwnCloudFileObserver observer = mObserversMap.get(localPath);
-        if (observer == null) {
-            /// the local file was never registered to observe before
-            observer = new OwnCloudFileObserver(    localPath, 
-                                                    account, 
-                                                    getApplicationContext());
-            mObserversMap.put(localPath, observer);
-            Log_OC.d(TAG, "Observer added for path " + localPath);
-        
-            if (file.isDown()) {
-                observer.startWatching();
-                Log_OC.d(TAG, "Started watching " + localPath);
-            }   // else - the observance can't be started on a file not already down; mDownloadReceiver will get noticed when the download of the file finishes
-        }
-        
-    }
-
-    
-    /**
-     * Unregisters the local copy of a remote file to be observed for local changes.
-     *
-     * Starts to watch it, if the file has a local copy to watch.
-     * 
-     * TODO We are ignoring that, currently, a local file can be linked to different files
-     * in ownCloud if it's uploaded several times. That's something pending to update: we 
-     * will avoid that the same local file is linked to different remote files.
-     *
-     * @param file      Object representing a remote file which local copy must be not observed longer.
-     * @param account   OwnCloud account containing file.
-     */
-    private void removeObservedFile(OCFile file, Account account) {
-        if (file == null) {
-            Log_OC.e(TAG, "Trying to remove a NULL file");
-            return;
-        }
-        String localPath = file.getStoragePath();
-        if (localPath == null || localPath.length() <= 0) {
-            localPath = FileStorageUtils.getDefaultSavePathFor(account.name, file);
-        }
-        
-        OwnCloudFileObserver observer = mObserversMap.get(localPath);
-        if (observer != null) {
-            observer.stopWatching();
-            mObserversMap.remove(observer);
-            Log_OC.d(TAG, "Stopped watching " + localPath);
-        }
-        
-    }
-
-
-    /**
-     *  Private receiver listening to events broadcast by the FileDownloader service.
-     * 
-     *  Starts and stops the observance on registered files when they are being download,
-     *  in order to avoid to start unnecessary synchronizations. 
-     */
-    private class DownloadCompletedReceiverBis extends BroadcastReceiver {
-        
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            String downloadPath = intent.getStringExtra(FileDownloader.EXTRA_FILE_PATH);
-            OwnCloudFileObserver observer = mObserversMap.get(downloadPath);
-            if (observer != null) {
-                if (intent.getAction().equals(FileDownloader.getDownloadFinishMessage()) &&
-                        new File(downloadPath).exists()) {  // the download could be successful. not; in both cases, the file could be down, due to a former download or upload   
-                    observer.startWatching();
-                    Log_OC.d(TAG, "Watching again " + downloadPath);
-                
-                } else if (intent.getAction().equals(FileDownloader.getDownloadAddedMessage())) {
-                    observer.stopWatching();
-                    Log_OC.d(TAG, "Disabling observance of " + downloadPath);
-                } 
-            }
-        }
-        
-    }
-    
-}
index 7f45b6b..ad2a2cb 100644 (file)
@@ -28,45 +28,9 @@ import java.util.Vector;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 
-import org.apache.http.HttpStatus;
-import org.apache.jackrabbit.webdav.DavConstants;
-import org.apache.jackrabbit.webdav.MultiStatus;
-import org.apache.jackrabbit.webdav.client.methods.PropFindMethod;
-
-import com.owncloud.android.Log_OC;
-import com.owncloud.android.MainApp;
-import com.owncloud.android.R;
-import com.owncloud.android.authentication.AccountAuthenticator;
-import com.owncloud.android.authentication.AuthenticatorActivity;
-import com.owncloud.android.datamodel.FileDataStorageManager;
-import com.owncloud.android.datamodel.OCFile;
-import com.owncloud.android.db.DbHandler;
-import com.owncloud.android.network.OwnCloudClientUtils;
-import com.owncloud.android.operations.ChunkedUploadFileOperation;
-import com.owncloud.android.operations.CreateFolderOperation;
-import com.owncloud.android.operations.ExistenceCheckOperation;
-import com.owncloud.android.operations.RemoteOperation;
-import com.owncloud.android.operations.RemoteOperationResult;
-import com.owncloud.android.operations.UploadFileOperation;
-import com.owncloud.android.operations.RemoteOperationResult.ResultCode;
-import com.owncloud.android.ui.activity.FailedUploadActivity;
-import com.owncloud.android.ui.activity.FileActivity;
-import com.owncloud.android.ui.activity.FileDisplayActivity;
-import com.owncloud.android.ui.activity.InstantUploadActivity;
-import com.owncloud.android.ui.preview.PreviewImageActivity;
-import com.owncloud.android.ui.preview.PreviewImageFragment;
-import com.owncloud.android.utils.OwnCloudVersion;
-
-
-import eu.alefzero.webdav.OnDatatransferProgressListener;
-import eu.alefzero.webdav.WebdavEntry;
-import eu.alefzero.webdav.WebdavUtils;
-
-
 import android.accounts.Account;
 import android.accounts.AccountManager;
 import android.accounts.AccountsException;
-import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.app.Service;
@@ -78,11 +42,39 @@ import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
 import android.os.Process;
+import android.support.v4.app.NotificationCompat;
 import android.webkit.MimeTypeMap;
-import android.widget.RemoteViews;
+
+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.lib.common.OwnCloudAccount;
+import com.owncloud.android.lib.common.OwnCloudClient;
+import com.owncloud.android.lib.common.OwnCloudClientManagerFactory;
+import com.owncloud.android.lib.common.accounts.AccountUtils.Constants;
+import com.owncloud.android.lib.common.network.OnDatatransferProgressListener;
+import com.owncloud.android.lib.common.operations.RemoteOperation;
+import com.owncloud.android.lib.common.operations.RemoteOperationResult;
+import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;
+import com.owncloud.android.lib.common.utils.Log_OC;
+import com.owncloud.android.lib.resources.files.ExistenceCheckRemoteOperation;
+import com.owncloud.android.lib.resources.files.FileUtils;
+import com.owncloud.android.lib.resources.files.ReadRemoteFileOperation;
+import com.owncloud.android.lib.resources.files.RemoteFile;
+import com.owncloud.android.lib.resources.status.OwnCloudVersion;
+import com.owncloud.android.notifications.NotificationBuilderWithProgressBar;
+import com.owncloud.android.notifications.NotificationDelayer;
+import com.owncloud.android.operations.CreateFolderOperation;
+import com.owncloud.android.operations.UploadFileOperation;
+import com.owncloud.android.operations.common.SyncOperation;
+import com.owncloud.android.ui.activity.FileActivity;
+import com.owncloud.android.ui.activity.FileDisplayActivity;
+import com.owncloud.android.utils.ErrorMessageAdapter;
 
 
-import eu.alefzero.webdav.WebdavClient;
 
 public class FileUploader extends Service implements OnDatatransferProgressListener {
 
@@ -117,7 +109,7 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
     private Looper mServiceLooper;
     private ServiceHandler mServiceHandler;
     private IBinder mBinder;
-    private WebdavClient mUploadClient = null;
+    private OwnCloudClient mUploadClient = null;
     private Account mLastAccount = null;
     private FileDataStorageManager mStorageManager;
 
@@ -125,9 +117,8 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
     private UploadFileOperation mCurrentUpload = null;
 
     private NotificationManager mNotificationManager;
-    private Notification mNotification;
+    private NotificationCompat.Builder mNotificationBuilder;
     private int mLastPercent;
-    private RemoteViews mDefaultNotificationContentView;
 
     
     public static String getUploadFinishMessage() {
@@ -195,6 +186,9 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
             return Service.START_NOT_STICKY;
         }
         Account account = intent.getParcelableExtra(KEY_ACCOUNT);
+        if (!AccountUtils.exists(account, getApplicationContext())) {
+            return Service.START_NOT_STICKY;
+        }
 
         String[] localPaths = null, remotePaths = null, mimeTypes = null;
         OCFile[] files = null;
@@ -255,14 +249,16 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
                 files[i] = obtainNewOCFileToUpload(remotePaths[i], localPaths[i], ((mimeTypes != null) ? mimeTypes[i]
                         : (String) null), storageManager);
                 if (files[i] == null) {
-                    // TODO @andomaex add failure Notiification
+                    // TODO @andomaex add failure Notification
                     return Service.START_NOT_STICKY;
                 }
             }
         }
 
-        OwnCloudVersion ocv = new OwnCloudVersion(AccountManager.get(this).getUserData(account,
-                AccountAuthenticator.KEY_OC_VERSION));
+        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,12 +266,8 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
         try {
             for (int i = 0; i < files.length; i++) {
                 uploadKey = buildRemoteName(account, files[i].getRemotePath());
-                if (chunked) {
-                    newUpload = new ChunkedUploadFileOperation(account, files[i], isInstant, forceOverwrite,
-                            localAction);
-                } else {
-                    newUpload = new UploadFileOperation(account, files[i], isInstant, forceOverwrite, localAction);
-                }
+                newUpload = new UploadFileOperation(account, files[i], chunked, isInstant, forceOverwrite, localAction, 
+                        getApplicationContext());
                 if (isInstant) {
                     newUpload.setRemoteFolderToBeCreated();
                 }
@@ -431,12 +423,6 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
 
 
         @Override
-        public void onTransferProgress(long progressRate) {
-            // old way, should not be in use any more
-        }
-
-
-        @Override
         public void onTransferProgress(long progressRate, long totalTransferredSoFar, long totalToTransfer,
                 String fileName) {
             String key = buildRemoteName(mCurrentUpload.getAccount(), mCurrentUpload.getFile());
@@ -503,8 +489,11 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
                 /// prepare client object to send requests to the ownCloud server
                 if (mUploadClient == null || !mLastAccount.equals(mCurrentUpload.getAccount())) {
                     mLastAccount = mCurrentUpload.getAccount();
-                    mStorageManager = new FileDataStorageManager(mLastAccount, getContentResolver());
-                    mUploadClient = OwnCloudClientUtils.createOwnCloudClient(mLastAccount, getApplicationContext());
+                    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
@@ -564,13 +553,11 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
      *  @return  An {@link OCFile} instance corresponding to the folder where the file will be uploaded.
      */
     private RemoteOperationResult grantFolderExistence(String pathToGrant) {
-        RemoteOperation operation = new ExistenceCheckOperation(pathToGrant, this, false);
+        RemoteOperation operation = new ExistenceCheckRemoteOperation(pathToGrant, this, false);
         RemoteOperationResult result = operation.execute(mUploadClient);
         if (!result.isSuccess() && result.getCode() == ResultCode.FILE_NOT_FOUND && mCurrentUpload.isRemoteFolderToBeCreated()) {
-            operation = new CreateFolderOperation(  pathToGrant,
-                                                    true,
-                                                    mStorageManager    );
-            result = operation.execute(mUploadClient);
+            SyncOperation syncOp = new CreateFolderOperation( pathToGrant, true);
+            result = syncOp.execute(mUploadClient, mStorageManager);
         }
         if (result.isSuccess()) {
             OCFile parentDir = mStorageManager.getFileByPath(pathToGrant);
@@ -616,43 +603,21 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
      */
     private void saveUploadedFile() {
         OCFile file = mCurrentUpload.getFile();
+        if (file.fileExists()) {
+            file = mStorageManager.getFileById(file.getFileId());
+        }
         long syncDate = System.currentTimeMillis();
         file.setLastSyncDateForData(syncDate);
 
-        // / new PROPFIND to keep data consistent with server in theory, should
-        // return the same we already have
-        PropFindMethod propfind = null;
-        RemoteOperationResult result = null;
-        try {
-            propfind = new PropFindMethod(mUploadClient.getBaseUri() + WebdavUtils.encodePath(mCurrentUpload.getRemotePath()),
-                    DavConstants.PROPFIND_ALL_PROP,
-                    DavConstants.DEPTH_0);
-            int status = mUploadClient.executeMethod(propfind);
-            boolean isMultiStatus = (status == HttpStatus.SC_MULTI_STATUS);
-            if (isMultiStatus) {
-                MultiStatus resp = propfind.getResponseBodyAsMultiStatus();
-                WebdavEntry we = new WebdavEntry(resp.getResponses()[0], mUploadClient.getBaseUri().getPath());
-                updateOCFile(file, we);
-                file.setLastSyncDateForProperties(syncDate);
-
-            } else {
-                mUploadClient.exhaustResponse(propfind.getResponseBodyAsStream());
-            }
-
-            result = new RemoteOperationResult(isMultiStatus, status, propfind.getResponseHeaders());
-            Log_OC.i(TAG, "Update: synchronizing properties for uploaded " + mCurrentUpload.getRemotePath() + ": "
-                    + result.getLogMessage());
-
-        } catch (Exception e) {
-            result = new RemoteOperationResult(e);
-            Log_OC.e(TAG, "Update: synchronizing properties for uploaded " + mCurrentUpload.getRemotePath() + ": "
-                    + result.getLogMessage(), e);
-
-        } finally {
-            if (propfind != null)
-                propfind.releaseConnection();
+        // new PROPFIND to keep data consistent with server 
+        // in theory, should return the same we already have
+        ReadRemoteFileOperation operation = new ReadRemoteFileOperation(mCurrentUpload.getRemotePath());
+        RemoteOperationResult result = operation.execute(mUploadClient);
+        if (result.isSuccess()) {
+            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()) {
@@ -665,17 +630,18 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
               // coincidence; nothing else is needed, the storagePath is right
               // in the instance returned by mCurrentUpload.getFile()
         }
-
+        file.setNeedsUpdateThumbnail(true);
         mStorageManager.saveFile(file);
     }
 
-    private void updateOCFile(OCFile file, WebdavEntry we) {
-        file.setCreationTimestamp(we.createTimestamp());
-        file.setFileLength(we.contentLength());
-        file.setMimetype(we.contentType());
-        file.setModificationTimestamp(we.modifiedTimestamp());
-        file.setModificationTimestampAtLastSyncForData(we.modifiedTimestamp());
-        // file.setEtag(mCurrentUpload.getEtag());    // TODO Etag, where available
+    private void updateOCFile(OCFile file, RemoteFile remoteFile) {
+        file.setCreationTimestamp(remoteFile.getCreationTimestamp());
+        file.setFileLength(remoteFile.getLength());
+        file.setMimetype(remoteFile.getMimeType());
+        file.setModificationTimestamp(remoteFile.getModifiedTimestamp());
+        file.setModificationTimestampAtLastSyncForData(remoteFile.getModifiedTimestamp());
+        // file.setEtag(remoteFile.getEtag());    // TODO Etag, where available
+        file.setRemoteId(remoteFile.getRemoteId());
     }
 
     private OCFile obtainNewOCFileToUpload(String remotePath, String localPath, String mimeType,
@@ -715,172 +681,129 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
      * 
      * @param upload Upload operation starting.
      */
-    @SuppressWarnings("deprecation")
     private void notifyUploadStart(UploadFileOperation upload) {
         // / create status notification with a progress bar
         mLastPercent = 0;
-        mNotification = new Notification(R.drawable.icon, getString(R.string.uploader_upload_in_progress_ticker),
-                System.currentTimeMillis());
-        mNotification.flags |= Notification.FLAG_ONGOING_EVENT;
-        mDefaultNotificationContentView = mNotification.contentView;
-        mNotification.contentView = new RemoteViews(getApplicationContext().getPackageName(),
-                R.layout.progressbar_layout);
-        mNotification.contentView.setProgressBar(R.id.status_progress, 100, 0, false);
-        mNotification.contentView.setTextViewText(R.id.status_text,
-                String.format(getString(R.string.uploader_upload_in_progress_content), 0, upload.getFileName()));
-        mNotification.contentView.setImageViewResource(R.id.status_icon, R.drawable.icon);
-        
+        mNotificationBuilder = 
+                NotificationBuilderWithProgressBar.newNotificationBuilderWithProgressBar(this);
+        mNotificationBuilder
+                .setOngoing(true)
+                .setSmallIcon(R.drawable.notification_icon)
+                .setTicker(getString(R.string.uploader_upload_in_progress_ticker))
+                .setContentTitle(getString(R.string.uploader_upload_in_progress_ticker))
+                .setProgress(100, 0, false)
+                .setContentText(
+                        String.format(getString(R.string.uploader_upload_in_progress_content), 0, upload.getFileName()));
+
         /// includes a pending intent in the notification showing the details view of the file
         Intent showDetailsIntent = new Intent(this, FileDisplayActivity.class);
         showDetailsIntent.putExtra(FileActivity.EXTRA_FILE, upload.getFile());
         showDetailsIntent.putExtra(FileActivity.EXTRA_ACCOUNT, upload.getAccount());
         showDetailsIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
-        mNotification.contentIntent = PendingIntent.getActivity(getApplicationContext(),
-                (int) System.currentTimeMillis(), showDetailsIntent, 0);
+        mNotificationBuilder.setContentIntent(PendingIntent.getActivity(
+            this, (int) System.currentTimeMillis(), showDetailsIntent, 0
+        ));
 
-        mNotificationManager.notify(R.string.uploader_upload_in_progress_ticker, mNotification);
+        mNotificationManager.notify(R.string.uploader_upload_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 fileName) {
+    public void onTransferProgress(long progressRate, long totalTransferredSoFar, long totalToTransfer, String filePath) {
         int percent = (int) (100.0 * ((double) totalTransferredSoFar) / ((double) totalToTransfer));
         if (percent != mLastPercent) {
-            mNotification.contentView.setProgressBar(R.id.status_progress, 100, percent, false);
+            mNotificationBuilder.setProgress(100, percent, false);
+            String fileName = filePath.substring(filePath.lastIndexOf(FileUtils.PATH_SEPARATOR) + 1);
             String text = String.format(getString(R.string.uploader_upload_in_progress_content), percent, fileName);
-            mNotification.contentView.setTextViewText(R.id.status_text, text);
-            mNotificationManager.notify(R.string.uploader_upload_in_progress_ticker, mNotification);
+            mNotificationBuilder.setContentText(text);
+            mNotificationManager.notify(R.string.uploader_upload_in_progress_ticker, mNotificationBuilder.build());
         }
         mLastPercent = percent;
     }
 
     /**
-     * Callback method to update the progress bar in the status notification
-     * (old version)
-     */
-    @Override
-    public void onTransferProgress(long progressRate) {
-        // NOTHING TO DO HERE ANYMORE
-    }
-
-    /**
      * Updates the status notification with the result of an upload operation.
      * 
      * @param uploadResult Result of the upload operation.
      * @param upload Finished upload operation
      */
-    private void notifyUploadResult(RemoteOperationResult uploadResult, UploadFileOperation upload) {
+    private void notifyUploadResult(
+            RemoteOperationResult uploadResult, UploadFileOperation upload) {
         Log_OC.d(TAG, "NotifyUploadResult with resultCode: " + uploadResult.getCode());
-        if (uploadResult.isCancelled()) {
-            // / cancelled operation -> silent removal of progress notification
-            mNotificationManager.cancel(R.string.uploader_upload_in_progress_ticker);
-
-        } else if (uploadResult.isSuccess()) {
-            // / success -> silent update of progress notification to success
-            // message
-            mNotification.flags ^= Notification.FLAG_ONGOING_EVENT; // remove
-                                                                    // the
-                                                                    // ongoing
-                                                                    // flag
-            mNotification.flags |= Notification.FLAG_AUTO_CANCEL;
-            mNotification.contentView = mDefaultNotificationContentView;
+        // / 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;
             
-            /// includes a pending intent in the notification showing the details view of the file
-            Intent showDetailsIntent = null;
-            if (PreviewImageFragment.canBePreviewed(upload.getFile())) {
-                showDetailsIntent = new Intent(this, PreviewImageActivity.class); 
-            } else {
-                showDetailsIntent = new Intent(this, FileDisplayActivity.class); 
-            }
-            showDetailsIntent.putExtra(FileActivity.EXTRA_FILE, upload.getFile());
-            showDetailsIntent.putExtra(FileActivity.EXTRA_ACCOUNT, upload.getAccount());
-            showDetailsIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
-            mNotification.contentIntent = PendingIntent.getActivity(getApplicationContext(),
-                    (int) System.currentTimeMillis(), showDetailsIntent, 0);
-
-            mNotification.setLatestEventInfo(getApplicationContext(),
-                    getString(R.string.uploader_upload_succeeded_ticker),
-                    String.format(getString(R.string.uploader_upload_succeeded_content_single), upload.getFileName()),
-                    mNotification.contentIntent);
-
-            mNotificationManager.notify(R.string.uploader_upload_in_progress_ticker, mNotification); // NOT
-                                                                                                     // AN
-            DbHandler db = new DbHandler(this.getBaseContext());
-            db.removeIUPendingFile(mCurrentUpload.getOriginalStoragePath());
-            db.close();
-
-        } else {
-
-            // / fail -> explicit failure notification
-            mNotificationManager.cancel(R.string.uploader_upload_in_progress_ticker);
-            Notification finalNotification = new Notification(R.drawable.icon,
-                    getString(R.string.uploader_upload_failed_ticker), System.currentTimeMillis());
-            finalNotification.flags |= Notification.FLAG_AUTO_CANCEL;
             String content = null;
+
+            // check credentials error
+            boolean needsToUpdateCredentials = (
+                    uploadResult.getCode() == ResultCode.UNAUTHORIZED || 
+                    uploadResult.isIdPRedirection()
+            );
+            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);
+            
+            content =  ErrorMessageAdapter.getErrorCauseMessage(
+                    uploadResult, upload, getResources()
+            );
             
-            boolean needsToUpdateCredentials = (uploadResult.getCode() == ResultCode.UNAUTHORIZED ||
-                    //(uploadResult.isTemporalRedirection() && uploadResult.isIdPRedirection() && 
-                    (uploadResult.isIdPRedirection() &&
-                            MainApp.getAuthTokenTypeSamlSessionCookie().equals(mUploadClient.getAuthTokenType())));
             if (needsToUpdateCredentials) {
                 // let the user update credentials with one click
                 Intent updateAccountCredentials = new Intent(this, AuthenticatorActivity.class);
-                updateAccountCredentials.putExtra(AuthenticatorActivity.EXTRA_ACCOUNT, upload.getAccount());
-                updateAccountCredentials.putExtra(AuthenticatorActivity.EXTRA_ENFORCED_UPDATE, true);
-                updateAccountCredentials.putExtra(AuthenticatorActivity.EXTRA_ACTION, AuthenticatorActivity.ACTION_UPDATE_TOKEN);
+                updateAccountCredentials.putExtra(
+                        AuthenticatorActivity.EXTRA_ACCOUNT, upload.getAccount()
+                );
+                updateAccountCredentials.putExtra(
+                        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);
-                finalNotification.contentIntent = PendingIntent.getActivity(this, (int)System.currentTimeMillis(), updateAccountCredentials, PendingIntent.FLAG_ONE_SHOT);
-                content =  String.format(getString(R.string.uploader_upload_failed_content_single), upload.getFileName());
-                finalNotification.setLatestEventInfo(getApplicationContext(),
-                        getString(R.string.uploader_upload_failed_ticker), content, finalNotification.contentIntent);
-                mUploadClient = null;   // grant that future retries on the same account will get the fresh credentials
+                mNotificationBuilder.setContentIntent(PendingIntent.getActivity(
+                    this, 
+                    (int) System.currentTimeMillis(), 
+                    updateAccountCredentials, 
+                    PendingIntent.FLAG_ONE_SHOT
+                ));
+                
+                mUploadClient = null;   
+                    // grant that future retries on the same account will get the fresh credentials
             } else {
-                // TODO put something smart in the contentIntent below
-            //    finalNotification.contentIntent = PendingIntent.getActivity(getApplicationContext(), (int)System.currentTimeMillis(), new Intent(), 0);
-            //}
-            
-                if (uploadResult.getCode() == ResultCode.LOCAL_STORAGE_FULL
-                        || uploadResult.getCode() == ResultCode.LOCAL_STORAGE_NOT_COPIED) {
-                    // TODO we need a class to provide error messages for the users
-                    // from a RemoteOperationResult and a RemoteOperation
-                    content = String.format(getString(R.string.error__upload__local_file_not_copied), upload.getFileName(),
-                            getString(R.string.app_name));
-                } else if (uploadResult.getCode() == ResultCode.QUOTA_EXCEEDED) {
-                    content = getString(R.string.failed_upload_quota_exceeded_text);
-                } else {
-                    content = String
-                            .format(getString(R.string.uploader_upload_failed_content_single), upload.getFileName());
-                }
-
-                // we add only for instant-uploads the InstantUploadActivity and the
-                // db entry
-                Intent detailUploadIntent = null;
-                if (upload.isInstant() && InstantUploadActivity.IS_ENABLED) {
-                    detailUploadIntent = new Intent(this, InstantUploadActivity.class);
-                    detailUploadIntent.putExtra(FileUploader.KEY_ACCOUNT, upload.getAccount());
-                } else {
-                    detailUploadIntent = new Intent(this, FailedUploadActivity.class);
-                    detailUploadIntent.putExtra(FailedUploadActivity.MESSAGE, content);
-                }
-                finalNotification.contentIntent = PendingIntent.getActivity(getApplicationContext(),
-                        (int) System.currentTimeMillis(), detailUploadIntent, PendingIntent.FLAG_UPDATE_CURRENT
-                        | PendingIntent.FLAG_ONE_SHOT);
-
+                mNotificationBuilder.setContentText(content);
+    
                 if (upload.isInstant()) {
                     DbHandler db = null;
                     try {
                         db = new DbHandler(this.getBaseContext());
-                        String message = uploadResult.getLogMessage() + " errorCode: " + uploadResult.getCode();
+                        String message = uploadResult.getLogMessage() + " errorCode: " +
+                                uploadResult.getCode();
                         Log_OC.e(TAG, message + " Http-Code: " + uploadResult.getHttpCode());
                         if (uploadResult.getCode() == ResultCode.QUOTA_EXCEEDED) {
-                            message = getString(R.string.failed_upload_quota_exceeded_text);
-                            if (db.updateFileState(upload.getOriginalStoragePath(), DbHandler.UPLOAD_STATUS_UPLOAD_FAILED,
+                            //message = getString(R.string.failed_upload_quota_exceeded_text);
+                            if (db.updateFileState(
+                                    upload.getOriginalStoragePath(), 
+                                    DbHandler.UPLOAD_STATUS_UPLOAD_FAILED,
                                     message) == 0) {
-                                db.putFileForLater(upload.getOriginalStoragePath(), upload.getAccount().name, message);
+                                db.putFileForLater(
+                                        upload.getOriginalStoragePath(), 
+                                        upload.getAccount().name, 
+                                        message
+                                );
                             }
                         }
                     } finally {
@@ -890,12 +813,24 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
                     }
                 }
             }
-            finalNotification.setLatestEventInfo(getApplicationContext(),
-                    getString(R.string.uploader_upload_failed_ticker), content, finalNotification.contentIntent);
             
-            mNotificationManager.notify(R.string.uploader_upload_failed_ticker, finalNotification);
+            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, 
+                        2000);
+                
+            }
         }
-
     }
 
     /**
index eb57222..52daa04 100644 (file)
@@ -37,9 +37,9 @@ import android.widget.Toast;
 
 import java.io.IOException;
 
-import com.owncloud.android.Log_OC;
 import com.owncloud.android.R;
 import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.lib.common.utils.Log_OC;
 import com.owncloud.android.ui.activity.FileActivity;
 import com.owncloud.android.ui.activity.FileDisplayActivity;
 
@@ -218,6 +218,7 @@ public class MediaService extends Service implements OnCompletionListener, OnPre
      */
     @Override
     public void onCreate() {
+        super.onCreate();
         Log_OC.d(TAG, "Creating ownCloud media service");
 
         mWifiLock = ((WifiManager) getSystemService(Context.WIFI_SERVICE)).
@@ -637,6 +638,7 @@ public class MediaService extends Service implements OnCompletionListener, OnPre
         mState = State.STOPPED;
         releaseResources(true);
         giveUpAudioFocus();
+        super.onDestroy();
     }
     
 
index ab018f6..1b56ec0 100644 (file)
@@ -18,8 +18,8 @@
 package com.owncloud.android.media;
 
 
-import com.owncloud.android.Log_OC;
 import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.lib.common.utils.Log_OC;
 import com.owncloud.android.media.MediaService.State;
 
 import android.accounts.Account;
diff --git a/src/com/owncloud/android/network/AdvancedSslSocketFactory.java b/src/com/owncloud/android/network/AdvancedSslSocketFactory.java
deleted file mode 100644 (file)
index 6a69871..0000000
+++ /dev/null
@@ -1,241 +0,0 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012 Bartek Przybylski
- *   Copyright (C) 2012-2013 ownCloud Inc.
- *
- *   This program is free software: you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License version 2,
- *   as published by the Free Software Foundation.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-package com.owncloud.android.network;
-
-import java.io.IOException;
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.net.Socket;
-import java.net.SocketAddress;
-import java.net.UnknownHostException;
-import java.security.cert.X509Certificate;
-
-import javax.net.SocketFactory;
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.SSLException;
-import javax.net.ssl.SSLHandshakeException;
-import javax.net.ssl.SSLPeerUnverifiedException;
-import javax.net.ssl.SSLSession;
-import javax.net.ssl.SSLSocket;
-
-import org.apache.commons.httpclient.ConnectTimeoutException;
-import org.apache.commons.httpclient.params.HttpConnectionParams;
-import org.apache.commons.httpclient.protocol.ProtocolSocketFactory;
-import org.apache.http.conn.ssl.X509HostnameVerifier;
-
-import com.owncloud.android.Log_OC;
-
-
-/**
- * AdvancedSSLProtocolSocketFactory allows to create SSL {@link Socket}s with 
- * a custom SSLContext and an optional Hostname Verifier.
- * 
- * @author David A. Velasco
- */
-
-public class AdvancedSslSocketFactory implements ProtocolSocketFactory {
-
-    private static final String TAG = AdvancedSslSocketFactory.class.getSimpleName();
-    
-    private SSLContext mSslContext = null;
-    private AdvancedX509TrustManager mTrustManager = null;
-    private X509HostnameVerifier mHostnameVerifier = null;
-
-    public SSLContext getSslContext() {
-        return mSslContext;
-    }
-    
-    /**
-     * Constructor for AdvancedSSLProtocolSocketFactory.
-     */
-    public AdvancedSslSocketFactory(SSLContext sslContext, AdvancedX509TrustManager trustManager, X509HostnameVerifier hostnameVerifier) {
-        if (sslContext == null)
-            throw new IllegalArgumentException("AdvancedSslSocketFactory can not be created with a null SSLContext");
-        if (trustManager == null)
-            throw new IllegalArgumentException("AdvancedSslSocketFactory can not be created with a null Trust Manager");
-        mSslContext = sslContext;
-        mTrustManager = trustManager;
-        mHostnameVerifier = hostnameVerifier;
-    }
-
-    /**
-     * @see ProtocolSocketFactory#createSocket(java.lang.String,int,java.net.InetAddress,int)
-     */
-    public Socket createSocket(String host, int port, InetAddress clientHost, int clientPort) throws IOException, UnknownHostException {
-        Socket socket = mSslContext.getSocketFactory().createSocket(host, port, clientHost, clientPort);
-        verifyPeerIdentity(host, port, socket);
-        return socket;
-    }
-
-    
-    /**
-     * Attempts to get a new socket connection to the given host within the
-     * given time limit.
-     * 
-     * @param host the host name/IP
-     * @param port the port on the host
-     * @param clientHost the local host name/IP to bind the socket to
-     * @param clientPort the port on the local machine
-     * @param params {@link HttpConnectionParams Http connection parameters}
-     * 
-     * @return Socket a new socket
-     * 
-     * @throws IOException if an I/O error occurs while creating the socket
-     * @throws UnknownHostException if the IP address of the host cannot be
-     *             determined
-     */
-    public Socket createSocket(final String host, final int port,
-            final InetAddress localAddress, final int localPort,
-            final HttpConnectionParams params) throws IOException,
-            UnknownHostException, ConnectTimeoutException {
-        Log_OC.d(TAG, "Creating SSL Socket with remote " + host + ":" + port + ", local " + localAddress + ":" + localPort + ", params: " + params);
-        if (params == null) {
-            throw new IllegalArgumentException("Parameters may not be null");
-        } 
-        int timeout = params.getConnectionTimeout();
-        SocketFactory socketfactory = mSslContext.getSocketFactory();
-        Log_OC.d(TAG, " ... with connection timeout " + timeout + " and socket timeout " + params.getSoTimeout());
-        Socket socket = socketfactory.createSocket();
-        SocketAddress localaddr = new InetSocketAddress(localAddress, localPort);
-        SocketAddress remoteaddr = new InetSocketAddress(host, port);
-        socket.setSoTimeout(params.getSoTimeout());
-        socket.bind(localaddr);
-        socket.connect(remoteaddr, timeout);
-        verifyPeerIdentity(host, port, socket);
-        return socket;
-    }
-
-    /**
-     * @see ProtocolSocketFactory#createSocket(java.lang.String,int)
-     */
-    public Socket createSocket(String host, int port) throws IOException,
-            UnknownHostException {
-        Log_OC.d(TAG, "Creating SSL Socket with remote " + host + ":" + port);
-        Socket socket = mSslContext.getSocketFactory().createSocket(host, port);
-        verifyPeerIdentity(host, port, socket);
-        return socket; 
-    }
-
-    public boolean equals(Object obj) {
-        return ((obj != null) && obj.getClass().equals(
-                AdvancedSslSocketFactory.class));
-    }
-
-    public int hashCode() {
-        return AdvancedSslSocketFactory.class.hashCode();
-    }
-
-
-    public X509HostnameVerifier getHostNameVerifier() {
-        return mHostnameVerifier;
-    }
-    
-    
-    public void setHostNameVerifier(X509HostnameVerifier hostnameVerifier) {
-        mHostnameVerifier = hostnameVerifier;
-    }
-    
-    /**
-     * Verifies the identity of the server. 
-     * 
-     * The server certificate is verified first.
-     * 
-     * Then, the host name is compared with the content of the server certificate using the current host name verifier, if any.
-     * @param socket
-     */
-    private void verifyPeerIdentity(String host, int port, Socket socket) throws IOException {
-        try {
-            CertificateCombinedException failInHandshake = null;
-            /// 1. VERIFY THE SERVER CERTIFICATE through the registered TrustManager (that should be an instance of AdvancedX509TrustManager) 
-            try {
-                SSLSocket sock = (SSLSocket) socket;    // a new SSLSession instance is created as a "side effect" 
-                sock.startHandshake();
-                
-            } catch (RuntimeException e) {
-                
-                if (e instanceof CertificateCombinedException) {
-                    failInHandshake = (CertificateCombinedException) e;
-                } else {
-                    Throwable cause = e.getCause();
-                    Throwable previousCause = null;
-                    while (cause != null && cause != previousCause && !(cause instanceof CertificateCombinedException)) {
-                        previousCause = cause;
-                        cause = cause.getCause();
-                    }
-                    if (cause != null && cause instanceof CertificateCombinedException) {
-                        failInHandshake = (CertificateCombinedException)cause;
-                    }
-                }
-                if (failInHandshake == null) {
-                    throw e;
-                }
-                failInHandshake.setHostInUrl(host);
-                
-            }
-            
-            /// 2. VERIFY HOSTNAME
-            SSLSession newSession = null;
-            boolean verifiedHostname = true;
-            if (mHostnameVerifier != null) {
-                if (failInHandshake != null) {
-                    /// 2.1 : a new SSLSession instance was NOT created in the handshake
-                    X509Certificate serverCert = failInHandshake.getServerCertificate();
-                    try {
-                        mHostnameVerifier.verify(host, serverCert);
-                    } catch (SSLException e) {
-                        verifiedHostname = false;
-                    }
-                
-                } else {
-                    /// 2.2 : a new SSLSession instance was created in the handshake
-                    newSession = ((SSLSocket)socket).getSession();
-                    if (!mTrustManager.isKnownServer((X509Certificate)(newSession.getPeerCertificates()[0]))) {
-                        verifiedHostname = mHostnameVerifier.verify(host, newSession); 
-                    }
-                }
-            }
-
-            /// 3. Combine the exceptions to throw, if any
-            if (!verifiedHostname) {
-                SSLPeerUnverifiedException pue = new SSLPeerUnverifiedException("Names in the server certificate do not match to " + host + " in the URL");
-                if (failInHandshake == null) {
-                    failInHandshake = new CertificateCombinedException((X509Certificate) newSession.getPeerCertificates()[0]);
-                    failInHandshake.setHostInUrl(host);
-                }
-                failInHandshake.setSslPeerUnverifiedException(pue);
-                pue.initCause(failInHandshake);
-                throw pue;
-                
-            } else if (failInHandshake != null) {
-                SSLHandshakeException hse = new SSLHandshakeException("Server certificate could not be verified");
-                hse.initCause(failInHandshake);
-                throw hse;
-            }
-            
-        } catch (IOException io) {        
-            try {
-                socket.close();
-            } catch (Exception x) {
-                // NOTHING - irrelevant exception for the caller 
-            }
-            throw io;
-        }
-    }
-
-}
diff --git a/src/com/owncloud/android/network/AdvancedX509TrustManager.java b/src/com/owncloud/android/network/AdvancedX509TrustManager.java
deleted file mode 100644 (file)
index 81dcdbd..0000000
+++ /dev/null
@@ -1,147 +0,0 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012-2013 ownCloud Inc.
- *
- *   This program is free software: you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License version 2,
- *   as published by the Free Software Foundation.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-package com.owncloud.android.network;
-
-import java.security.KeyStore;
-import java.security.KeyStoreException;
-import java.security.NoSuchAlgorithmException;
-import java.security.cert.CertPathValidatorException;
-import java.security.cert.CertStoreException;
-import java.security.cert.CertificateException;
-import java.security.cert.CertificateExpiredException;
-import java.security.cert.CertificateNotYetValidException;
-import java.security.cert.X509Certificate;
-
-import javax.net.ssl.TrustManager;
-import javax.net.ssl.TrustManagerFactory;
-import javax.net.ssl.X509TrustManager;
-
-import com.owncloud.android.Log_OC;
-
-
-/**
- * @author David A. Velasco
- */
-public class AdvancedX509TrustManager implements X509TrustManager {
-    
-    private static final String TAG = AdvancedX509TrustManager.class.getSimpleName();
-
-    private X509TrustManager mStandardTrustManager = null;
-    private KeyStore mKnownServersKeyStore;
-
-    /**
-     * Constructor for AdvancedX509TrustManager
-     * 
-     * @param  knownServersCertStore    Local certificates store with server certificates explicitly trusted by the user.
-     * @throws CertStoreException       When no default X509TrustManager instance was found in the system.
-     */
-    public AdvancedX509TrustManager(KeyStore knownServersKeyStore)
-            throws NoSuchAlgorithmException, KeyStoreException, CertStoreException {
-        super();
-        TrustManagerFactory factory = TrustManagerFactory
-                .getInstance(TrustManagerFactory.getDefaultAlgorithm());
-        factory.init((KeyStore)null);
-        mStandardTrustManager = findX509TrustManager(factory);
-
-        mKnownServersKeyStore = knownServersKeyStore;
-    }
-    
-    
-    /**
-     * Locates the first X509TrustManager provided by a given TrustManagerFactory
-     * @param factory               TrustManagerFactory to inspect in the search for a X509TrustManager
-     * @return                      The first X509TrustManager found in factory.
-     * @throws CertStoreException   When no X509TrustManager instance was found in factory
-     */
-    private X509TrustManager findX509TrustManager(TrustManagerFactory factory) throws CertStoreException {
-        TrustManager tms[] = factory.getTrustManagers();
-        for (int i = 0; i < tms.length; i++) {
-            if (tms[i] instanceof X509TrustManager) {
-                return (X509TrustManager) tms[i];
-            }
-        }
-        return null;
-    }
-    
-
-    /**
-     * @see javax.net.ssl.X509TrustManager#checkClientTrusted(X509Certificate[],
-     *      String authType)
-     */
-    public void checkClientTrusted(X509Certificate[] certificates, String authType) throws CertificateException {
-        mStandardTrustManager.checkClientTrusted(certificates, authType);
-    }
-
-    
-    /**
-     * @see javax.net.ssl.X509TrustManager#checkServerTrusted(X509Certificate[],
-     *      String authType)
-     */
-    public void checkServerTrusted(X509Certificate[] certificates, String authType) throws CertificateException {
-        if (!isKnownServer(certificates[0])) {
-               CertificateCombinedException result = new CertificateCombinedException(certificates[0]);
-               try {
-                       certificates[0].checkValidity();
-               } catch (CertificateExpiredException c) {
-                       result.setCertificateExpiredException(c);
-                       
-               } catch (CertificateNotYetValidException c) {
-                result.setCertificateNotYetException(c);
-               }
-               
-               try {
-                   mStandardTrustManager.checkServerTrusted(certificates, authType);
-               } catch (CertificateException c) {
-                Throwable cause = c.getCause();
-                Throwable previousCause = null;
-                while (cause != null && cause != previousCause && !(cause instanceof CertPathValidatorException)) {     // getCause() is not funny
-                    previousCause = cause;
-                    cause = cause.getCause();
-                }
-                if (cause != null && cause instanceof CertPathValidatorException) {
-                       result.setCertPathValidatorException((CertPathValidatorException)cause);
-                } else {
-                       result.setOtherCertificateException(c);
-                }
-               }
-               
-               if (result.isException())
-                       throw result;
-
-        }
-    }
-    
-    
-    /**
-     * @see javax.net.ssl.X509TrustManager#getAcceptedIssuers()
-     */
-    public X509Certificate[] getAcceptedIssuers() {
-        return mStandardTrustManager.getAcceptedIssuers();
-    }
-
-    
-    public boolean isKnownServer(X509Certificate cert) {
-        try {
-            return (mKnownServersKeyStore.getCertificateAlias(cert) != null);
-        } catch (KeyStoreException e) {
-            Log_OC.d(TAG, "Fail while checking certificate in the known-servers store");
-            return false;
-        }
-    }
-    
-}
\ No newline at end of file
diff --git a/src/com/owncloud/android/network/BearerAuthScheme.java b/src/com/owncloud/android/network/BearerAuthScheme.java
deleted file mode 100644 (file)
index 16791c2..0000000
+++ /dev/null
@@ -1,269 +0,0 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012  ownCloud Inc.
- *
- *   This program is free software: you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License version 2,
- *   as published by the Free Software Foundation.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-package com.owncloud.android.network;
-
-import java.util.Map;
-
-import org.apache.commons.httpclient.Credentials;
-import org.apache.commons.httpclient.HttpMethod;
-import org.apache.commons.httpclient.auth.AuthChallengeParser;
-import org.apache.commons.httpclient.auth.AuthScheme;
-import org.apache.commons.httpclient.auth.AuthenticationException;
-import org.apache.commons.httpclient.auth.InvalidCredentialsException;
-import org.apache.commons.httpclient.auth.MalformedChallengeException;
-
-import com.owncloud.android.Log_OC;
-
-
-/**
- * Bearer authentication scheme as defined in RFC 6750.
- * 
- * @author David A. Velasco
- */
-
-public class BearerAuthScheme implements AuthScheme /*extends RFC2617Scheme*/ {
-    
-    private static final String TAG = BearerAuthScheme.class.getSimpleName();
-
-    public static final String AUTH_POLICY = "Bearer";
-    
-    /** Whether the bearer authentication process is complete */
-    private boolean mComplete;
-    
-    /** Authentication parameter map */
-    private Map mParams = null;
-    
-    
-    /**
-     * Default constructor for the bearer authentication scheme.
-     */
-    public BearerAuthScheme() {
-        mComplete = false;
-    }
-
-    /**
-     * Constructor for the basic authentication scheme.
-     * 
-     * @param   challenge                       Authentication challenge
-     * 
-     * @throws  MalformedChallengeException     Thrown if the authentication challenge is malformed
-     * 
-     * @deprecated Use parameterless constructor and {@link AuthScheme#processChallenge(String)} method
-     */
-    public BearerAuthScheme(final String challenge) throws MalformedChallengeException {
-        processChallenge(challenge);
-        mComplete = true;
-    }
-
-    /**
-     * Returns textual designation of the bearer authentication scheme.
-     * 
-     * @return "Bearer"
-     */
-    public String getSchemeName() {
-        return "bearer";
-    }
-
-    /**
-     * Processes the Bearer challenge.
-     *  
-     * @param   challenge                   The challenge string
-     * 
-     * @throws MalformedChallengeException  Thrown if the authentication challenge is malformed
-     */
-    public void processChallenge(String challenge) throws MalformedChallengeException {
-        String s = AuthChallengeParser.extractScheme(challenge);
-        if (!s.equalsIgnoreCase(getSchemeName())) {
-            throw new MalformedChallengeException(
-              "Invalid " + getSchemeName() + " challenge: " + challenge); 
-        }
-        mParams = AuthChallengeParser.extractParams(challenge);
-        mComplete = true;
-    }
-
-    /**
-     * Tests if the Bearer authentication process has been completed.
-     * 
-     * @return 'true' if Bearer authorization has been processed, 'false' otherwise.
-     */
-    public boolean isComplete() {
-        return this.mComplete;
-    }
-
-    /**
-     * Produces bearer authorization string for the given set of 
-     * {@link Credentials}.
-     * 
-     * @param   credentials                     The set of credentials to be used for authentication
-     * @param   method                          Method name is ignored by the bearer authentication scheme
-     * @param   uri                             URI is ignored by the bearer authentication scheme
-     * @throws  InvalidCredentialsException     If authentication credentials are not valid or not applicable 
-     *                                          for this authentication scheme
-     * @throws  AuthenticationException         If authorization string cannot be generated due to an authentication failure
-     * @return  A bearer authorization string
-     * 
-     * @deprecated Use {@link #authenticate(Credentials, HttpMethod)}
-     */
-    public String authenticate(Credentials credentials, String method, String uri) throws AuthenticationException {
-        Log_OC.d(TAG, "enter BearerScheme.authenticate(Credentials, String, String)");
-
-        BearerCredentials bearer = null;
-        try {
-            bearer = (BearerCredentials) credentials;
-        } catch (ClassCastException e) {
-            throw new InvalidCredentialsException(
-             "Credentials cannot be used for bearer authentication: " 
-              + credentials.getClass().getName());
-        }
-        return BearerAuthScheme.authenticate(bearer);
-    }
-
-    
-    /**
-     * Returns 'false'. Bearer authentication scheme is request based.
-     * 
-     * @return 'false'.
-     */
-    public boolean isConnectionBased() {
-        return false;    
-    }
-
-    /**
-     * Produces bearer authorization string for the given set of {@link Credentials}.
-     * 
-     * @param   credentials                     The set of credentials to be used for authentication
-     * @param   method                          The method being authenticated
-     * @throws  InvalidCredentialsException     If authentication credentials are not valid or not applicable for this authentication 
-     *                                          scheme.
-     * @throws AuthenticationException         If authorization string cannot be generated due to an authentication failure.
-     * 
-     * @return a basic authorization string
-     */
-    public String authenticate(Credentials credentials, HttpMethod method) throws AuthenticationException {
-        Log_OC.d(TAG, "enter BearerScheme.authenticate(Credentials, HttpMethod)");
-
-        if (method == null) {
-            throw new IllegalArgumentException("Method may not be null");
-        }
-        BearerCredentials bearer = null;
-        try {
-            bearer = (BearerCredentials) credentials;
-        } catch (ClassCastException e) {
-            throw new InvalidCredentialsException(
-                    "Credentials cannot be used for bearer authentication: " 
-                    + credentials.getClass().getName());
-        }
-        return BearerAuthScheme.authenticate(
-            bearer, 
-            method.getParams().getCredentialCharset());
-    }
-    
-    /**
-     * @deprecated Use {@link #authenticate(BearerCredentials, String)}
-     * 
-     * Returns a bearer Authorization header value for the given 
-     * {@link BearerCredentials}.
-     * 
-     * @param   credentials     The credentials to encode.
-     * 
-     * @return                  A bearer authorization string
-     */
-    public static String authenticate(BearerCredentials credentials) {
-        return authenticate(credentials, "ISO-8859-1");
-    }
-
-    /**
-     * Returns a bearer Authorization header value for the given 
-     * {@link BearerCredentials} and charset.
-     * 
-     * @param   credentials         The credentials to encode.
-     * @param   charset             The charset to use for encoding the credentials
-     * 
-     * @return                      A bearer authorization string
-     * 
-     * @since 3.0
-     */
-    public static String authenticate(BearerCredentials credentials, String charset) {
-        Log_OC.d(TAG, "enter BearerAuthScheme.authenticate(BearerCredentials, String)");
-
-        if (credentials == null) {
-            throw new IllegalArgumentException("Credentials may not be null"); 
-        }
-        if (charset == null || charset.length() == 0) {
-            throw new IllegalArgumentException("charset may not be null or empty");
-        }
-        StringBuffer buffer = new StringBuffer();
-        buffer.append(credentials.getAccessToken());
-        
-        //return "Bearer " + EncodingUtil.getAsciiString(EncodingUtil.getBytes(buffer.toString(), charset));
-        return "Bearer " + buffer.toString();
-    }
-
-    /**
-     * Returns a String identifying the authentication challenge.  This is
-     * used, in combination with the host and port to determine if
-     * authorization has already been attempted or not.  Schemes which
-     * require multiple requests to complete the authentication should
-     * return a different value for each stage in the request.
-     * 
-     * Additionally, the ID should take into account any changes to the
-     * authentication challenge and return a different value when appropriate.
-     * For example when the realm changes in basic authentication it should be
-     * considered a different authentication attempt and a different value should
-     * be returned.
-     * 
-     * This method simply returns the realm for the challenge.
-     * 
-     * @return String       a String identifying the authentication challenge.
-     * 
-     * @deprecated no longer used
-     */
-    @Override
-    public String getID() {
-        return getRealm();
-    }
-
-    /**
-     * Returns authentication parameter with the given name, if available.
-     * 
-     * @param   name    The name of the parameter to be returned
-     * 
-     * @return          The parameter with the given name
-     */
-    @Override
-    public String getParameter(String name) {
-        if (name == null) {
-            throw new IllegalArgumentException("Parameter name may not be null"); 
-        }
-        if (mParams == null) {
-            return null;
-        }
-        return (String) mParams.get(name.toLowerCase());
-    }
-
-    /**
-     * Returns authentication realm. The realm may not be null.
-     * 
-     * @return  The authentication realm
-     */
-    @Override
-    public String getRealm() {
-        return getParameter("realm");
-    }
-    
-}
diff --git a/src/com/owncloud/android/network/BearerCredentials.java b/src/com/owncloud/android/network/BearerCredentials.java
deleted file mode 100644 (file)
index 50799b0..0000000
+++ /dev/null
@@ -1,97 +0,0 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012  ownCloud Inc.
- *
- *   This program is free software: you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License version 2,
- *   as published by the Free Software Foundation.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-package com.owncloud.android.network;
-
-import org.apache.commons.httpclient.Credentials;
-import org.apache.commons.httpclient.util.LangUtils;
-
-/**
- * Bearer token {@link Credentials}
- *
- * @author David A. Velasco
- */
-public class BearerCredentials implements Credentials {
-
-    
-    private String mAccessToken;
-    
-    
-    /**
-     * The constructor with the bearer token
-     *
-     * @param token     The bearer token
-     */
-    public BearerCredentials(String token) {
-        /*if (token == null) {
-            throw new IllegalArgumentException("Bearer token may not be null");            
-        }*/
-        mAccessToken = (token == null) ? "" : token;
-    }
-
-
-    /**
-     * Returns the access token
-     *
-     * @return      The access token
-     */
-    public String getAccessToken() {
-        return mAccessToken;
-    }
-
-
-    /**
-     * Get this object string.
-     *
-     * @return  The access token
-     */
-    public String toString() {
-        return mAccessToken;
-    }
-
-    /**
-     * Does a hash of the access token.
-     *
-     * @return The hash code of the access token
-     */
-    public int hashCode() {
-        int hash = LangUtils.HASH_SEED;
-        hash = LangUtils.hashCode(hash, mAccessToken);
-        return hash;
-    }
-
-    /**
-     * These credentials are assumed equal if accessToken is the same.
-     *
-     * @param   o   The other object to compare with.
-     *
-     * @return      'True' if the object is equivalent.
-     */
-    public boolean equals(Object o) {
-        if (o == null) return false;
-        if (this == o) return true;
-        if (this.getClass().equals(o.getClass())) {
-            BearerCredentials that = (BearerCredentials) o;
-            if (LangUtils.equals(mAccessToken, that.mAccessToken)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-}
-
diff --git a/src/com/owncloud/android/network/CertificateCombinedException.java b/src/com/owncloud/android/network/CertificateCombinedException.java
deleted file mode 100644 (file)
index e96d9dc..0000000
+++ /dev/null
@@ -1,130 +0,0 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012-2013 ownCloud Inc.
- *
- *   This program is free software: you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License version 2,
- *   as published by the Free Software Foundation.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-package com.owncloud.android.network;
-
-import java.security.cert.CertPathValidatorException;
-import java.security.cert.CertificateException;
-import java.security.cert.CertificateExpiredException;
-import java.security.cert.CertificateNotYetValidException;
-import java.security.cert.X509Certificate;
-
-import javax.net.ssl.SSLPeerUnverifiedException;
-
-/**
- * Exception joining all the problems that {@link AdvancedX509TrustManager} can find in
- * a certificate chain for a server.
- * 
- * This was initially created as an extension of CertificateException, but some
- * implementations of the SSL socket layer in existing devices are REPLACING the CertificateException
- * instances thrown by {@link javax.net.ssl.X509TrustManager#checkServerTrusted(X509Certificate[], String)}
- * with SSLPeerUnverifiedException FORGETTING THE CAUSING EXCEPTION instead of wrapping it. 
- * 
- * Due to this, extending RuntimeException is necessary to get that the CertificateCombinedException 
- * instance reaches {@link AdvancedSslSocketFactory#verifyPeerIdentity}.
- * 
- * BE CAREFUL. As a RuntimeException extensions, Java compilers do not require to handle it
- * in client methods. Be sure to use it only when you know exactly where it will go.
- * 
- * @author David A. Velasco
- */
-public class CertificateCombinedException extends RuntimeException {
-
-    /** Generated - to refresh every time the class changes */
-    private static final long serialVersionUID = -8875782030758554999L;
-    
-    private X509Certificate mServerCert = null;
-    private String mHostInUrl;
-
-    private CertificateExpiredException mCertificateExpiredException = null;
-    private CertificateNotYetValidException mCertificateNotYetValidException = null;
-    private CertPathValidatorException mCertPathValidatorException = null;
-    private CertificateException mOtherCertificateException = null;
-    private SSLPeerUnverifiedException mSslPeerUnverifiedException = null;
-    
-    public CertificateCombinedException(X509Certificate x509Certificate) {
-        mServerCert = x509Certificate;
-    }
-
-    public X509Certificate getServerCertificate() {
-        return mServerCert;
-    }
-
-    public String getHostInUrl() {
-        return mHostInUrl;
-    }
-
-    public void setHostInUrl(String host) {
-        mHostInUrl = host;
-    }
-
-    public CertificateExpiredException getCertificateExpiredException() {
-        return mCertificateExpiredException;
-    }
-
-    public void setCertificateExpiredException(CertificateExpiredException c) {
-        mCertificateExpiredException  = c;
-    }
-
-    public CertificateNotYetValidException getCertificateNotYetValidException() {
-        return mCertificateNotYetValidException;
-    }
-
-    public void setCertificateNotYetException(CertificateNotYetValidException c) {
-        mCertificateNotYetValidException = c;
-    }
-
-    public CertPathValidatorException getCertPathValidatorException() {
-        return mCertPathValidatorException;
-    }
-
-    public void setCertPathValidatorException(CertPathValidatorException c) {
-        mCertPathValidatorException = c;
-    }
-
-    public CertificateException getOtherCertificateException() {
-        return mOtherCertificateException;
-    }
-
-    public void setOtherCertificateException(CertificateException c) {
-        mOtherCertificateException = c;
-    }
-
-    public SSLPeerUnverifiedException getSslPeerUnverifiedException() {
-        return mSslPeerUnverifiedException ; 
-    }
-
-    public void setSslPeerUnverifiedException(SSLPeerUnverifiedException s) {
-        mSslPeerUnverifiedException = s;
-    }
-
-    public boolean isException() {
-        return (mCertificateExpiredException != null ||
-                mCertificateNotYetValidException != null ||
-                mCertPathValidatorException != null ||
-                mOtherCertificateException != null ||
-                mSslPeerUnverifiedException != null);
-    }
-
-    public boolean isRecoverable() {
-        return (mCertificateExpiredException != null ||
-                mCertificateNotYetValidException != null ||
-                mCertPathValidatorException != null ||
-                mSslPeerUnverifiedException != null);
-    }
-
-}
diff --git a/src/com/owncloud/android/network/OwnCloudClientUtils.java b/src/com/owncloud/android/network/OwnCloudClientUtils.java
deleted file mode 100644 (file)
index bb29938..0000000
+++ /dev/null
@@ -1,285 +0,0 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012-2013 ownCloud Inc.
- *
- *   This program is free software: you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License version 2,
- *   as published by the Free Software Foundation.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- */
-package com.owncloud.android.network;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.security.GeneralSecurityException;
-import java.security.KeyStore;
-import java.security.KeyStoreException;
-import java.security.NoSuchAlgorithmException;
-import java.security.cert.Certificate;
-import java.security.cert.CertificateException;
-
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.TrustManager;
-
-import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
-import org.apache.commons.httpclient.protocol.Protocol;
-import org.apache.http.conn.ssl.BrowserCompatHostnameVerifier;
-import org.apache.http.conn.ssl.X509HostnameVerifier;
-
-import com.owncloud.android.Log_OC;
-import com.owncloud.android.MainApp;
-import com.owncloud.android.authentication.AccountAuthenticator;
-import com.owncloud.android.authentication.AccountUtils;
-import com.owncloud.android.authentication.AccountUtils.AccountNotFoundException;
-
-
-import eu.alefzero.webdav.WebdavClient;
-
-import android.accounts.Account;
-import android.accounts.AccountManager;
-import android.accounts.AccountManagerFuture;
-import android.accounts.AuthenticatorException;
-import android.accounts.OperationCanceledException;
-import android.app.Activity;
-import android.content.Context;
-import android.net.Uri;
-import android.os.Bundle;
-
-public class OwnCloudClientUtils {
-    
-    final private static String TAG = OwnCloudClientUtils.class.getSimpleName();
-    
-    /** Default timeout for waiting data from the server */
-    public static final int DEFAULT_DATA_TIMEOUT = 60000;
-    
-    /** Default timeout for establishing a connection */
-    public static final int DEFAULT_CONNECTION_TIMEOUT = 60000;
-
-    /** Connection manager for all the WebdavClients */
-    private static MultiThreadedHttpConnectionManager mConnManager = null;
-    
-    private static Protocol mDefaultHttpsProtocol = null;
-
-    private static AdvancedSslSocketFactory mAdvancedSslSocketFactory = null;
-
-    private static X509HostnameVerifier mHostnameVerifier = null;
-    
-    
-    /**
-     * Creates a WebdavClient setup for an ownCloud account
-     * 
-     * Do not call this method from the main thread.
-     * 
-     * @param account                       The ownCloud account
-     * @param appContext                    Android application context
-     * @return                              A WebdavClient object ready to be used
-     * @throws AuthenticatorException       If the authenticator failed to get the authorization token for the account.
-     * @throws OperationCanceledException   If the authenticator operation was cancelled while getting the authorization token for the account. 
-     * @throws IOException                  If there was some I/O error while getting the authorization token for the account.
-     * @throws AccountNotFoundException     If 'account' is unknown for the AccountManager
-     */
-    public static WebdavClient createOwnCloudClient (Account account, Context appContext) throws OperationCanceledException, AuthenticatorException, IOException, AccountNotFoundException {
-        //Log_OC.d(TAG, "Creating WebdavClient associated to " + account.name);
-       
-        Uri uri = Uri.parse(AccountUtils.constructFullURLForAccount(appContext, account));
-        AccountManager am = AccountManager.get(appContext);
-        boolean isOauth2 = am.getUserData(account, AccountAuthenticator.KEY_SUPPORTS_OAUTH2) != null;   // TODO avoid calling to getUserData here
-        boolean isSamlSso = am.getUserData(account, AccountAuthenticator.KEY_SUPPORTS_SAML_WEB_SSO) != null;
-        WebdavClient client = createOwnCloudClient(uri, appContext, !isSamlSso);
-        if (isOauth2) {    
-            String accessToken = am.blockingGetAuthToken(account, MainApp.getAuthTokenTypeAccessToken(), false);
-            client.setBearerCredentials(accessToken);   // TODO not assume that the access token is a bearer token
-        
-        } else if (isSamlSso) {    // TODO avoid a call to getUserData here
-            String accessToken = am.blockingGetAuthToken(account, MainApp.getAuthTokenTypeSamlSessionCookie(), false);
-            client.setSsoSessionCookie(accessToken);
-            
-        } else {
-            String username = account.name.substring(0, account.name.lastIndexOf('@'));
-            //String password = am.getPassword(account);
-            String password = am.blockingGetAuthToken(account, MainApp.getAuthTokenTypePass(), false);
-            client.setBasicCredentials(username, password);
-        }
-        
-        return client;
-    }
-    
-    
-    public static WebdavClient createOwnCloudClient (Account account, Context appContext, Activity currentActivity) throws OperationCanceledException, AuthenticatorException, IOException, AccountNotFoundException {
-        Uri uri = Uri.parse(AccountUtils.constructFullURLForAccount(appContext, account));
-        AccountManager am = AccountManager.get(appContext);
-        boolean isOauth2 = am.getUserData(account, AccountAuthenticator.KEY_SUPPORTS_OAUTH2) != null;   // TODO avoid calling to getUserData here
-        boolean isSamlSso = am.getUserData(account, AccountAuthenticator.KEY_SUPPORTS_SAML_WEB_SSO) != null;
-        WebdavClient client = createOwnCloudClient(uri, appContext, !isSamlSso);
-        
-        if (isOauth2) {    // TODO avoid a call to getUserData here
-            AccountManagerFuture<Bundle> future =  am.getAuthToken(account, MainApp.getAuthTokenTypeAccessToken(), null, currentActivity, null, null);
-            Bundle result = future.getResult();
-            String accessToken = result.getString(AccountManager.KEY_AUTHTOKEN);
-            if (accessToken == null) throw new AuthenticatorException("WTF!");
-            client.setBearerCredentials(accessToken);   // TODO not assume that the access token is a bearer token
-
-        } else if (isSamlSso) {    // TODO avoid a call to getUserData here
-            AccountManagerFuture<Bundle> future =  am.getAuthToken(account, MainApp.getAuthTokenTypeSamlSessionCookie(), null, currentActivity, null, null);
-            Bundle result = future.getResult();
-            String accessToken = result.getString(AccountManager.KEY_AUTHTOKEN);
-            if (accessToken == null) throw new AuthenticatorException("WTF!");
-            client.setSsoSessionCookie(accessToken);
-
-        } else {
-            String username = account.name.substring(0, account.name.lastIndexOf('@'));
-            //String password = am.getPassword(account);
-            //String password = am.blockingGetAuthToken(account, MainApp.getAuthTokenTypePass(), false);
-            AccountManagerFuture<Bundle> future =  am.getAuthToken(account, MainApp.getAuthTokenTypePass(), null, currentActivity, null, null);
-            Bundle result = future.getResult();
-            String password = result.getString(AccountManager.KEY_AUTHTOKEN);
-            client.setBasicCredentials(username, password);
-        }
-        
-        return client;
-    }
-    
-    /**
-     * Creates a WebdavClient to access a URL and sets the desired parameters for ownCloud client connections.
-     * 
-     * @param uri       URL to the ownCloud server
-     * @param context   Android context where the WebdavClient is being created.
-     * @return          A WebdavClient object ready to be used
-     */
-    public static WebdavClient createOwnCloudClient(Uri uri, Context context, boolean followRedirects) {
-        try {
-            registerAdvancedSslContext(true, context);
-        }  catch (GeneralSecurityException e) {
-            Log_OC.e(TAG, "Advanced SSL Context could not be loaded. Default SSL management in the system will be used for HTTPS connections", e);
-            
-        } catch (IOException e) {
-            Log_OC.e(TAG, "The local server truststore could not be read. Default SSL management in the system will be used for HTTPS connections", e);
-        }
-        
-        WebdavClient client = new WebdavClient(getMultiThreadedConnManager());
-        
-        client.setDefaultTimeouts(DEFAULT_DATA_TIMEOUT, DEFAULT_CONNECTION_TIMEOUT);
-        client.setBaseUri(uri);
-        client.setFollowRedirects(followRedirects);
-        
-        return client;
-    }
-    
-    
-    /**
-     * Registers or unregisters the proper components for advanced SSL handling.
-     * @throws IOException 
-     */
-    private static void registerAdvancedSslContext(boolean register, Context context) throws GeneralSecurityException, IOException {
-        Protocol pr = null;
-        try {
-            pr = Protocol.getProtocol("https");
-            if (pr != null && mDefaultHttpsProtocol == null) {
-                mDefaultHttpsProtocol = pr;
-            }
-        } catch (IllegalStateException e) {
-            // nothing to do here; really
-        }
-        boolean isRegistered = (pr != null && pr.getSocketFactory() instanceof AdvancedSslSocketFactory);
-        if (register && !isRegistered) {
-            Protocol.registerProtocol("https", new Protocol("https", getAdvancedSslSocketFactory(context), 443));
-            
-        } else if (!register && isRegistered) {
-            if (mDefaultHttpsProtocol != null) {
-                Protocol.registerProtocol("https", mDefaultHttpsProtocol);
-            }
-        }
-    }
-    
-    public static AdvancedSslSocketFactory getAdvancedSslSocketFactory(Context context) throws GeneralSecurityException, IOException {
-        if (mAdvancedSslSocketFactory  == null) {
-            KeyStore trustStore = getKnownServersStore(context);
-            AdvancedX509TrustManager trustMgr = new AdvancedX509TrustManager(trustStore);
-            TrustManager[] tms = new TrustManager[] { trustMgr };
-                
-            SSLContext sslContext = SSLContext.getInstance("TLS");
-            sslContext.init(null, tms, null);
-                    
-            mHostnameVerifier = new BrowserCompatHostnameVerifier();
-            mAdvancedSslSocketFactory = new AdvancedSslSocketFactory(sslContext, trustMgr, mHostnameVerifier);
-        }
-        return mAdvancedSslSocketFactory;
-    }
-
-
-    private static String LOCAL_TRUSTSTORE_FILENAME = "knownServers.bks";
-    
-    private static String LOCAL_TRUSTSTORE_PASSWORD = "password";
-
-    private static KeyStore mKnownServersStore = null;
-    
-    /**
-     * Returns the local store of reliable server certificates, explicitly accepted by the user.
-     * 
-     * Returns a KeyStore instance with empty content if the local store was never created.
-     * 
-     * Loads the store from the storage environment if needed.
-     * 
-     * @param context                       Android context where the operation is being performed.
-     * @return                              KeyStore instance with explicitly-accepted server certificates. 
-     * @throws KeyStoreException            When the KeyStore instance could not be created.
-     * @throws IOException                  When an existing local trust store could not be loaded.
-     * @throws NoSuchAlgorithmException     When the existing local trust store was saved with an unsupported algorithm.
-     * @throws CertificateException         When an exception occurred while loading the certificates from the local trust store.
-     */
-    private static KeyStore getKnownServersStore(Context context) throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException {
-        if (mKnownServersStore == null) {
-            //mKnownServersStore = KeyStore.getInstance("BKS");
-            mKnownServersStore = KeyStore.getInstance(KeyStore.getDefaultType());
-            File localTrustStoreFile = new File(context.getFilesDir(), LOCAL_TRUSTSTORE_FILENAME);
-            Log_OC.d(TAG, "Searching known-servers store at " + localTrustStoreFile.getAbsolutePath());
-            if (localTrustStoreFile.exists()) {
-                InputStream in = new FileInputStream(localTrustStoreFile);
-                try {
-                    mKnownServersStore.load(in, LOCAL_TRUSTSTORE_PASSWORD.toCharArray());
-                } finally {
-                    in.close();
-                }
-            } else {
-                mKnownServersStore.load(null, LOCAL_TRUSTSTORE_PASSWORD.toCharArray()); // necessary to initialize an empty KeyStore instance
-            }
-        }
-        return mKnownServersStore;
-    }
-    
-    
-    public static void addCertToKnownServersStore(Certificate cert, Context context) throws  KeyStoreException, NoSuchAlgorithmException, 
-                                                                                            CertificateException, IOException {
-        KeyStore knownServers = getKnownServersStore(context);
-        knownServers.setCertificateEntry(Integer.toString(cert.hashCode()), cert);
-        FileOutputStream fos = null;
-        try {
-            fos = context.openFileOutput(LOCAL_TRUSTSTORE_FILENAME, Context.MODE_PRIVATE);
-            knownServers.store(fos, LOCAL_TRUSTSTORE_PASSWORD.toCharArray());
-        } finally {
-            fos.close();
-        }
-    }
-    
-    
-    static private MultiThreadedHttpConnectionManager getMultiThreadedConnManager() {
-        if (mConnManager == null) {
-            mConnManager = new MultiThreadedHttpConnectionManager();
-            mConnManager.getParams().setDefaultMaxConnectionsPerHost(5);
-            mConnManager.getParams().setMaxTotalConnections(5);
-        }
-        return mConnManager;
-    }
-
-
-}
diff --git a/src/com/owncloud/android/network/ProgressiveDataTransferer.java b/src/com/owncloud/android/network/ProgressiveDataTransferer.java
deleted file mode 100644 (file)
index c6fa545..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012-2013 ownCloud Inc.
- *
- *   This program is free software: you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License version 2,
- *   as published by the Free Software Foundation.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-package com.owncloud.android.network;
-
-import java.util.Collection;
-
-import eu.alefzero.webdav.OnDatatransferProgressListener;
-
-public interface ProgressiveDataTransferer {
-
-    public void addDatatransferProgressListener (OnDatatransferProgressListener listener);
-    
-    public void addDatatransferProgressListeners(Collection<OnDatatransferProgressListener> listeners);
-
-    public void removeDatatransferProgressListener(OnDatatransferProgressListener listener);
-
-}
diff --git a/src/com/owncloud/android/notifications/NotificationBuilderWithProgressBar.java b/src/com/owncloud/android/notifications/NotificationBuilderWithProgressBar.java
new file mode 100644 (file)
index 0000000..63ddf63
--- /dev/null
@@ -0,0 +1,132 @@
+/* ownCloud Android client application
+ *   Copyright (C) 2014 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 com.owncloud.android.R;
+
+import android.app.Notification;
+import android.content.Context;
+import android.os.Build;
+import android.support.v4.app.NotificationCompat;
+import android.view.View;
+import android.widget.RemoteViews;
+
+/**
+ * Extends the support class {@link NotificationCompat.Builder} to grant that
+ * 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 {
+
+    /**
+     * Custom view to replace the original layout of the notifications
+     */
+    private RemoteViews mContentView = null;
+    
+    /**
+     * Fatory method.
+     * 
+     * Instances of this class will be only returned in Android versions needing it.
+     * 
+     * @param context       Context that will use the builder to create notifications
+     * @return              An instance of this class, or of the regular 
+     *                      {@link NotificationCompat.Builder}, when it is good enough.
+     */
+    public static NotificationCompat.Builder newNotificationBuilderWithProgressBar(Context context) {
+        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
+            return new NotificationBuilderWithProgressBar(context); 
+        } else {
+            return new NotificationCompat.Builder(context);
+        }
+    }
+    
+    /**
+     * Constructor.
+     * 
+     * @param context       Context that will use the builder to create notifications.
+     */
+    private NotificationBuilderWithProgressBar(Context context) {
+        super(context);
+        mContentView = new RemoteViews(context.getPackageName(), R.layout.notification_with_progress_bar);
+        setContent(mContentView);
+    }
+    
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public NotificationCompat.Builder setProgress(int max, int progress, boolean indeterminate) {
+        mContentView.setProgressBar(R.id.progress, max, progress, indeterminate);
+        if (max > 0) {
+            mContentView.setViewVisibility(R.id.progressHolder, View.VISIBLE);
+        } else {
+            mContentView.setViewVisibility(R.id.progressHolder, View.GONE);
+        }
+        return this;
+    }
+    
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public NotificationCompat.Builder setSmallIcon(int icon) {
+        super.setSmallIcon(icon);   // necessary
+        mContentView.setImageViewResource(R.id.icon, icon);
+        return this;
+    }
+    
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public NotificationCompat.Builder setContentTitle(CharSequence title) {
+        super.setContentTitle(title);
+        mContentView.setTextViewText(R.id.title, title);
+        return this;
+    }
+    
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public NotificationCompat.Builder setContentText(CharSequence text) {
+        super.setContentText(text);
+        mContentView.setTextViewText(R.id.text, text);
+        if (text != null && text.length() > 0) {
+            mContentView.setViewVisibility(R.id.text, View.VISIBLE);
+        } else {
+            mContentView.setViewVisibility(R.id.text, View.GONE);
+        }
+        return this;
+    }
+
+    @Override
+    public Notification build() {
+        Notification result = super.build();
+        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
+            // super.build() in Android 2.x totally ruins whatever was made #setContent 
+            result.contentView = mContentView;
+        }
+        return result;
+    }
+    
+    
+}
diff --git a/src/com/owncloud/android/notifications/NotificationDelayer.java b/src/com/owncloud/android/notifications/NotificationDelayer.java
new file mode 100644 (file)
index 0000000..aeefe12
--- /dev/null
@@ -0,0 +1,33 @@
+package com.owncloud.android.notifications;
+
+import java.util.Random;
+
+import android.app.NotificationManager;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Process;
+
+public class NotificationDelayer {
+    
+    public static void cancelWithDelay(
+            final NotificationManager notificationManager,
+            final int notificationId,
+            long delayInMillis) {
+    
+        HandlerThread thread = new HandlerThread(
+                "NotificationDelayerThread_" + (new Random(System.currentTimeMillis())).nextInt(),
+                Process.THREAD_PRIORITY_BACKGROUND);
+        thread.start();
+        
+        Handler handler = new Handler(thread.getLooper()); 
+        handler.postDelayed(new Runnable() { 
+             public void run() { 
+                 notificationManager.cancel(notificationId);
+                 ((HandlerThread)Thread.currentThread()).getLooper().quit();
+             } 
+        }, delayInMillis); 
+    
+    }
+    
+
+}
diff --git a/src/com/owncloud/android/operations/ChunkedUploadFileOperation.java b/src/com/owncloud/android/operations/ChunkedUploadFileOperation.java
deleted file mode 100644 (file)
index 2649d19..0000000
+++ /dev/null
@@ -1,97 +0,0 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012 Bartek Przybylski
- *   Copyright (C) 2012-2013 ownCloud Inc.
- *
- *   This program is free software: you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License version 2,
- *   as published by the Free Software Foundation.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-package com.owncloud.android.operations;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.RandomAccessFile;
-import java.nio.channels.FileChannel;
-import java.util.Random;
-
-import org.apache.commons.httpclient.HttpException;
-import org.apache.commons.httpclient.methods.PutMethod;
-
-import com.owncloud.android.Log_OC;
-import com.owncloud.android.datamodel.OCFile;
-import com.owncloud.android.network.ProgressiveDataTransferer;
-
-
-import android.accounts.Account;
-
-import eu.alefzero.webdav.ChunkFromFileChannelRequestEntity;
-import eu.alefzero.webdav.WebdavClient;
-import eu.alefzero.webdav.WebdavUtils;
-
-public class ChunkedUploadFileOperation extends UploadFileOperation {
-    
-    private static final long CHUNK_SIZE = 1024000;
-    private static final String OC_CHUNKED_HEADER = "OC-Chunked";
-    private static final String TAG = ChunkedUploadFileOperation.class.getSimpleName();
-
-    public ChunkedUploadFileOperation(  Account account,
-                                        OCFile file,
-                                        boolean isInstant, 
-                                        boolean forceOverwrite,
-                                        int localBehaviour) {
-        
-        super(account, file, isInstant, forceOverwrite, localBehaviour);
-    }
-
-    @Override
-    protected int uploadFile(WebdavClient client) throws HttpException, IOException {
-        int status = -1;
-
-        FileChannel channel = null;
-        RandomAccessFile raf = null;
-        try {
-            File file = new File(getStoragePath());
-            raf = new RandomAccessFile(file, "r");
-            channel = raf.getChannel();
-            mEntity = new ChunkFromFileChannelRequestEntity(channel, getMimeType(), CHUNK_SIZE, file);
-            ((ProgressiveDataTransferer)mEntity).addDatatransferProgressListeners(getDataTransferListeners());
-            long offset = 0;
-            String uriPrefix = client.getBaseUri() + WebdavUtils.encodePath(getRemotePath()) + "-chunking-" + Math.abs((new Random()).nextInt(9000)+1000) + "-" ;
-            long chunkCount = (long) Math.ceil((double)file.length() / CHUNK_SIZE);
-            for (int chunkIndex = 0; chunkIndex < chunkCount ; chunkIndex++, offset += CHUNK_SIZE) {
-                if (mPutMethod != null) {
-                    mPutMethod.releaseConnection();    // let the connection available for other methods
-                }
-                mPutMethod = new PutMethod(uriPrefix + chunkCount + "-" + chunkIndex);
-                mPutMethod.addRequestHeader(OC_CHUNKED_HEADER, OC_CHUNKED_HEADER);
-                ((ChunkFromFileChannelRequestEntity)mEntity).setOffset(offset);
-                mPutMethod.setRequestEntity(mEntity);
-                status = client.executeMethod(mPutMethod);
-                client.exhaustResponse(mPutMethod.getResponseBodyAsStream());
-                Log_OC.d(TAG, "Upload of " + getStoragePath() + " to " + getRemotePath() + ", chunk index " + chunkIndex + ", count " + chunkCount + ", HTTP result status " + status);
-                if (!isSuccess(status))
-                    break;
-            }
-            
-        } finally {
-            if (channel != null)
-                channel.close();
-            if (raf != null)
-                raf.close();
-            if (mPutMethod != null)
-                mPutMethod.releaseConnection();    // let the connection available for other methods
-        }
-        return status;
-    }
-
-}
index f28ad29..4df8b3d 100644 (file)
@@ -1,5 +1,5 @@
 /* ownCloud Android client application
- *   Copyright (C) 2012 ownCloud Inc.
+ *   Copyright (C) 2014 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.operations;
 
-import java.io.File;
-
-import org.apache.commons.httpclient.HttpStatus;
-import org.apache.jackrabbit.webdav.client.methods.MkColMethod;
-
-import com.owncloud.android.Log_OC;
-import com.owncloud.android.datamodel.FileDataStorageManager;
 import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.lib.common.OwnCloudClient;
+import com.owncloud.android.lib.resources.files.CreateRemoteFolderOperation;
+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.operations.common.SyncOperation;
+import com.owncloud.android.utils.FileStorageUtils;
 
 
-import eu.alefzero.webdav.WebdavClient;
-import eu.alefzero.webdav.WebdavUtils;
-
 /**
- * Remote operation performing the creation of a new folder in the ownCloud server.
+ * 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 RemoteOperation {
+public class CreateFolderOperation extends SyncOperation implements OnRemoteOperationListener{
     
     private static final String TAG = CreateFolderOperation.class.getSimpleName();
-
-    private static final int READ_TIMEOUT = 10000;
-    private static final int CONNECTION_TIMEOUT = 5000;
     
     protected String mRemotePath;
     protected boolean mCreateFullPath;
-    protected FileDataStorageManager mStorageManager;
     
     /**
      * Constructor
      * 
-     * @param remotePath            Full path to the new directory to create in the remote server.
      * @param createFullPath        'True' means that all the ancestor folders should be created if don't exist yet.
-     * @param storageManager        Reference to the local database corresponding to the account where the file is contained. 
      */
-    public CreateFolderOperation(String remotePath, boolean createFullPath, FileDataStorageManager storageManager) {
+    public CreateFolderOperation(String remotePath, boolean createFullPath) {
         mRemotePath = remotePath;
         mCreateFullPath = createFullPath;
-        mStorageManager = storageManager;
+        
     }
-    
-    
-    /**
-     * Performs the operation
-     * 
-     * @param   client      Client object to communicate with the remote ownCloud server.
-     */
+
+
     @Override
-    protected RemoteOperationResult run(WebdavClient client) {
-        RemoteOperationResult result = null;
-        MkColMethod mkcol = null;
-        try {
-            mkcol = new MkColMethod(client.getBaseUri() + WebdavUtils.encodePath(mRemotePath));
-            int status =  client.executeMethod(mkcol, READ_TIMEOUT, CONNECTION_TIMEOUT);
-            if (!mkcol.succeeded() && mkcol.getStatusCode() == HttpStatus.SC_CONFLICT && mCreateFullPath) {
-                result = createParentFolder(getParentPath(), client);
-                status = client.executeMethod(mkcol, READ_TIMEOUT, CONNECTION_TIMEOUT);    // second (and last) try
-            }
-            if (mkcol.succeeded()) {
-                // Save new directory in local database
-                OCFile newDir = new OCFile(mRemotePath);
-                newDir.setMimetype("DIR");
-                long parentId = mStorageManager.getFileByPath(getParentPath()).getFileId();
-                newDir.setParentId(parentId);
-                newDir.setModificationTimestamp(System.currentTimeMillis());
-                mStorageManager.saveFile(newDir);
-            }
-            result = new RemoteOperationResult(mkcol.succeeded(), status, mkcol.getResponseHeaders());
-            Log_OC.d(TAG, "Create directory " + mRemotePath + ": " + result.getLogMessage());
-            client.exhaustResponse(mkcol.getResponseBodyAsStream());
-                
-        } catch (Exception e) {
-            result = new RemoteOperationResult(e);
-            Log_OC.e(TAG, "Create directory " + mRemotePath + ": " + result.getLogMessage(), e);
-            
-        } finally {
-            if (mkcol != null)
-                mkcol.releaseConnection();
+    protected RemoteOperationResult run(OwnCloudClient client) {
+        CreateRemoteFolderOperation operation = new CreateRemoteFolderOperation(mRemotePath, mCreateFullPath);
+        RemoteOperationResult result =  operation.execute(client);
+        
+        if (result.isSuccess()) {
+            saveFolderInDB();
+        } else {
+            Log_OC.e(TAG, mRemotePath + "hasn't been created");
         }
+        
         return result;
     }
 
-
-    private String getParentPath() {
-        String parentPath = new File(mRemotePath).getParent();
-        parentPath = parentPath.endsWith(OCFile.PATH_SEPARATOR) ? parentPath : parentPath + OCFile.PATH_SEPARATOR;
-        return parentPath;
+    @Override
+    public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationResult result) {
+        if (operation instanceof CreateRemoteFolderOperation) {
+            onCreateRemoteFolderOperationFinish((CreateRemoteFolderOperation)operation, result);
+        }
     }
-
     
-    private RemoteOperationResult createParentFolder(String parentPath, WebdavClient client) {
-        RemoteOperation operation = new CreateFolderOperation(  parentPath,
-                                                                mCreateFullPath,
-                                                                mStorageManager    );
-        return operation.execute(client);
+    
+    private void onCreateRemoteFolderOperationFinish(CreateRemoteFolderOperation operation, RemoteOperationResult result) {
+       if (result.isSuccess()) {
+           saveFolderInDB();
+       } else {
+           Log_OC.e(TAG, mRemotePath + "hasn't been created");
+       }
     }
 
+    /**
+     * Save new directory in local database
+     */
+    public void saveFolderInDB() {
+        if (mCreateFullPath && getStorageManager().
+                getFileByPath(FileStorageUtils.getParentPath(mRemotePath)) == null){// When parent
+                                                                                    // of remote path
+                                                                                    // is not created 
+            String[] subFolders = mRemotePath.split("/");
+            String composedRemotePath = "/";
+
+            // For each antecesor folders create them recursively
+            for (int i=0; i<subFolders.length; i++) {
+                String subFolder =  subFolders[i];
+                if (!subFolder.isEmpty()) {
+                    composedRemotePath = composedRemotePath + subFolder + "/";
+                    mRemotePath = composedRemotePath;
+                    saveFolderInDB();
+                }
+            }
+        } else { // Create directory on DB
+            OCFile newDir = new OCFile(mRemotePath);
+            newDir.setMimetype("DIR");
+            long parentId = getStorageManager().
+                    getFileByPath(FileStorageUtils.getParentPath(mRemotePath)).getFileId();
+            newDir.setParentId(parentId);
+            newDir.setModificationTimestamp(System.currentTimeMillis());
+            getStorageManager().saveFile(newDir);
+
+            Log_OC.d(TAG, "Create directory " + mRemotePath + " in Database");
+        }
+    }
 }
diff --git a/src/com/owncloud/android/operations/CreateShareOperation.java b/src/com/owncloud/android/operations/CreateShareOperation.java
new file mode 100644 (file)
index 0000000..c32c477
--- /dev/null
@@ -0,0 +1,139 @@
+/* ownCloud Android client application
+ *   Copyright (C) 2014 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;
+
+/**
+ * Creates a new share from a given file
+ * 
+ * @author masensio
+ *
+ */
+
+import android.content.Intent;
+
+import com.owncloud.android.datamodel.FileDataStorageManager;
+import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.lib.common.OwnCloudClient;
+import com.owncloud.android.lib.resources.shares.OCShare;
+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.shares.GetRemoteSharesForFileOperation;
+import com.owncloud.android.lib.resources.shares.ShareType;
+import com.owncloud.android.lib.resources.shares.CreateRemoteShareOperation;
+import com.owncloud.android.lib.resources.files.FileUtils;
+import com.owncloud.android.operations.common.SyncOperation;
+
+public class CreateShareOperation extends SyncOperation {
+
+    private static final String TAG = CreateShareOperation.class.getSimpleName();
+    
+
+    protected FileDataStorageManager mStorageManager;
+
+    private String mPath;
+    private ShareType mShareType;
+    private String mShareWith;
+    private boolean mPublicUpload;
+    private String mPassword;
+    private int mPermissions;
+    private Intent mSendIntent;
+
+    /**
+     * Constructor
+     * @param path          Full path of the file/folder being shared. Mandatory argument
+     * @param shareType     \910\92 = user, \911\92 = group, \913\92 = Public link. Mandatory argument
+     * @param shareWith     User/group ID with who the file should be shared.  This is mandatory for shareType of 0 or 1
+     * @param publicUpload  If \91false\92 (default) public cannot upload to a public shared folder. 
+     *                      If \91true\92 public can upload to a shared folder. Only available for public link shares
+     * @param password      Password to protect a public link share. Only available for public link shares
+     * @param permissions   1 - Read only \96 Default for \93public\94 shares
+     *                      2 - Update
+     *                      4 - Create
+     *                      8 - Delete
+     *                      16- Re-share
+     *                      31- All above \96 Default for \93private\94 shares
+     *                      For user or group shares.
+     *                      To obtain combinations, add the desired values together.  
+     *                      For instance, for \93Re-Share\94\93delete\94\93read\94\93update\94, add 16+8+2+1 = 27.
+     */
+    public CreateShareOperation(String path, ShareType shareType, String shareWith, boolean publicUpload, 
+            String password, int permissions, Intent sendIntent) {
+
+        mPath = path;
+        mShareType = shareType;
+        mShareWith = shareWith;
+        mPublicUpload = publicUpload;
+        mPassword = password;
+        mPermissions = permissions;
+        mSendIntent = sendIntent;
+    }
+
+    @Override
+    protected RemoteOperationResult run(OwnCloudClient client) {
+        RemoteOperation operation = null;
+        
+        // Check if the share link already exists
+        operation = new GetRemoteSharesForFileOperation(mPath, false, false);
+        RemoteOperationResult result = ((GetRemoteSharesForFileOperation)operation).execute(client);
+
+        if (!result.isSuccess() || result.getData().size() <= 0) {
+            operation = new CreateRemoteShareOperation(mPath, mShareType, mShareWith, mPublicUpload, mPassword, mPermissions);
+            result = ((CreateRemoteShareOperation)operation).execute(client);
+        }
+        
+        if (result.isSuccess()) {
+            if (result.getData().size() > 0) {
+                OCShare share = (OCShare) result.getData().get(0);
+                updateData(share);
+            } 
+        }
+        
+        return result;
+    }
+    
+    
+    public Intent getSendIntent() {
+        return mSendIntent;
+    }
+    
+    private void updateData(OCShare share) {
+        // Update DB with the response
+        share.setPath(mPath);
+        if (mPath.endsWith(FileUtils.PATH_SEPARATOR)) {
+            share.setIsFolder(true);
+        } else {
+            share.setIsFolder(false);
+        }
+        share.setPermissions(mPermissions);
+        
+        getStorageManager().saveShare(share);
+        
+        // Update OCFile with data from share: ShareByLink  and publicLink
+        OCFile file = getStorageManager().getFileByPath(mPath);
+        if (file!=null) {
+            mSendIntent.putExtra(Intent.EXTRA_TEXT, share.getShareLink());
+            file.setPublicLink(share.getShareLink());
+            file.setShareByLink(true);
+            getStorageManager().saveFile(file);
+            Log_OC.d(TAG, "Public Link = " + file.getPublicLink());
+
+        }
+    }
+
+}
diff --git a/src/com/owncloud/android/operations/DetectAuthenticationMethodOperation.java b/src/com/owncloud/android/operations/DetectAuthenticationMethodOperation.java
new file mode 100644 (file)
index 0000000..c86c8b5
--- /dev/null
@@ -0,0 +1,153 @@
+/* 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.
+ *
+ */
+
+package com.owncloud.android.operations;
+
+import java.util.ArrayList;
+
+import com.owncloud.android.lib.common.OwnCloudClient;
+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.operations.RemoteOperationResult.ResultCode;
+import com.owncloud.android.lib.common.utils.Log_OC;
+import com.owncloud.android.lib.resources.files.ExistenceCheckRemoteOperation;
+
+import android.content.Context;
+import android.net.Uri;
+import android.util.Log;
+
+/**
+ * Operation to find out what authentication method requires
+ * the server to access files.
+ * 
+ * Basically, tries to access to the root folder without authorization
+ * and analyzes the response.
+ * 
+ * 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
+ */
+public class DetectAuthenticationMethodOperation extends RemoteOperation {
+    
+    private static final String TAG = DetectAuthenticationMethodOperation.class.getSimpleName();
+    
+    public enum AuthenticationMethod {
+        UNKNOWN,
+        NONE,
+        BASIC_HTTP_AUTH, 
+        SAML_WEB_SSO,
+        BEARER_TOKEN
+    }
+    
+    private Context mContext;
+    
+    /**
+     * Constructor
+     * 
+     * @param context       Android context of the caller.
+     * @param webdavUrl
+     */
+    public DetectAuthenticationMethodOperation(Context context) {
+        mContext = context;
+    }
+    
+
+    /**
+     *  Performs the operation.
+     * 
+     *  Triggers a check of existence on the root folder of the server, granting
+     *  that the request is not authenticated.
+     *  
+     *  Analyzes the result of check to find out what authentication method, if
+     *  any, is requested by the server.
+     */
+       @Override
+       protected RemoteOperationResult run(OwnCloudClient client) {
+        RemoteOperationResult result = null;
+        AuthenticationMethod authMethod = AuthenticationMethod.UNKNOWN;
+        
+        RemoteOperation operation = new ExistenceCheckRemoteOperation("", mContext, false);
+        client.clearCredentials();
+        client.setFollowRedirects(false);
+        
+        // try to access the root folder, following redirections but not SAML SSO redirections
+        result = operation.execute(client);
+        String redirectedLocation = result.getRedirectedLocation(); 
+        while (redirectedLocation != null && redirectedLocation.length() > 0 && 
+                !result.isIdPRedirection()) {
+            client.setBaseUri(Uri.parse(result.getRedirectedLocation()));
+            result = operation.execute(client);
+            redirectedLocation = result.getRedirectedLocation();
+        } 
+
+        // analyze response  
+        if (result.getCode() == ResultCode.UNAUTHORIZED) {
+            String authRequest = ((result.getAuthenticateHeader()).trim()).toLowerCase();
+            if (authRequest.startsWith("basic")) {
+                authMethod = AuthenticationMethod.BASIC_HTTP_AUTH;
+                
+            } else if (authRequest.startsWith("bearer")) {
+                authMethod = AuthenticationMethod.BEARER_TOKEN;
+            }
+            // else - fall back to UNKNOWN
+                    
+        } else if (result.isSuccess()) {
+            authMethod = AuthenticationMethod.NONE;
+            
+        } else if (result.isIdPRedirection()) {
+            authMethod = AuthenticationMethod.SAML_WEB_SSO;
+        }
+        // else - fall back to UNKNOWN
+        Log_OC.d(TAG, "Authentication method found: " + authenticationMethodToString(authMethod));
+        
+        if (!authMethod.equals(AuthenticationMethod.UNKNOWN)) {
+            result = new RemoteOperationResult(true, result.getHttpCode(), null);
+        }
+        ArrayList<Object> data = new ArrayList<Object>();
+        data.add(authMethod);
+        result.setData(data);
+        return result;  // same result instance, so that other errors can be handled by the caller transparently
+       }
+       
+       
+       private String authenticationMethodToString(AuthenticationMethod value) {
+           switch (value){
+           case NONE:
+               return "NONE";
+           case BASIC_HTTP_AUTH:
+               return "BASIC_HTTP_AUTH";
+           case BEARER_TOKEN:
+               return "BEARER_TOKEN";
+           case SAML_WEB_SSO:
+               return "SAML_WEB_SSO";
+           default:
+            return "UNKNOWN";
+           }
+    }
+
+}
index db986f4..9f2bed7 100644 (file)
 
 package com.owncloud.android.operations;
 
-import java.io.BufferedInputStream;
 import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.util.Date;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.Set;
 import java.util.concurrent.atomic.AtomicBoolean;
 
-import org.apache.commons.httpclient.Header;
-import org.apache.commons.httpclient.HttpException;
-import org.apache.commons.httpclient.methods.GetMethod;
-import org.apache.http.HttpStatus;
-
-import com.owncloud.android.Log_OC;
 import com.owncloud.android.datamodel.OCFile;
-import com.owncloud.android.operations.RemoteOperation;
-import com.owncloud.android.operations.RemoteOperationResult;
+import com.owncloud.android.lib.common.network.OnDatatransferProgressListener;
+import com.owncloud.android.lib.common.OwnCloudClient;
+import com.owncloud.android.lib.common.operations.OperationCancelledException;
+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.DownloadRemoteFileOperation;
 import com.owncloud.android.utils.FileStorageUtils;
 
-
-import eu.alefzero.webdav.OnDatatransferProgressListener;
-import eu.alefzero.webdav.WebdavClient;
-import eu.alefzero.webdav.WebdavUtils;
 import android.accounts.Account;
 import android.webkit.MimeTypeMap;
 
 /**
- * Remote operation performing the download of a file to an ownCloud server
+ * Remote mDownloadOperation performing the download of a file to an ownCloud server
  * 
  * @author David A. Velasco
+ * @author masensio
  */
 public class DownloadFileOperation extends RemoteOperation {
     
@@ -57,9 +49,10 @@ public class DownloadFileOperation extends RemoteOperation {
     private Account mAccount;
     private OCFile mFile;
     private Set<OnDatatransferProgressListener> mDataTransferListeners = new HashSet<OnDatatransferProgressListener>();
-    private final AtomicBoolean mCancellationRequested = new AtomicBoolean(false);
     private long mModificationTimestamp = 0;
-    private GetMethod mGet;
+    private final AtomicBoolean mCancellationRequested = new AtomicBoolean(false);
+    
+    private DownloadRemoteFileOperation mDownloadOperation;
 
     
     public DownloadFileOperation(Account account, OCFile file) {
@@ -70,6 +63,7 @@ public class DownloadFileOperation extends RemoteOperation {
         
         mAccount = account;
         mFile = file;
+        
     }
 
 
@@ -93,6 +87,10 @@ public class DownloadFileOperation extends RemoteOperation {
         return FileStorageUtils.getTemporalPath(mAccount.name) + mFile.getRemotePath();
     }
     
+    public String getTmpFolder() {
+        return FileStorageUtils.getTemporalPath(mAccount.name);
+    }
+    
     public String getRemotePath() {
         return mFile.getRemotePath();
     }
@@ -121,22 +119,9 @@ public class DownloadFileOperation extends RemoteOperation {
     public long getModificationTimestamp() {
         return (mModificationTimestamp > 0) ? mModificationTimestamp : mFile.getModificationTimestamp();
     }
-    
-    
-    public void addDatatransferProgressListener (OnDatatransferProgressListener listener) {
-        synchronized (mDataTransferListeners) {
-            mDataTransferListeners.add(listener);
-        }
-    }
-    
-    public void removeDatatransferProgressListener(OnDatatransferProgressListener listener) {
-        synchronized (mDataTransferListeners) {
-            mDataTransferListeners.remove(listener);
-        }
-    }
 
     @Override
-    protected RemoteOperationResult run(WebdavClient client) {
+    protected RemoteOperationResult run(OwnCloudClient client) {
         RemoteOperationResult result = null;
         File newFile = null;
         boolean moved = true;
@@ -144,93 +129,55 @@ public class DownloadFileOperation extends RemoteOperation {
         /// download will be performed to a temporal file, then moved to the final location
         File tmpFile = new File(getTmpPath());
         
+        String tmpFolder =  getTmpFolder();
+        
         /// perform the download
-        try {
-            tmpFile.getParentFile().mkdirs();
-            int status = downloadFile(client, tmpFile);
-            if (isSuccess(status)) {
-                newFile = new File(getSavePath());
-                newFile.getParentFile().mkdirs();
-                moved = tmpFile.renameTo(newFile);
+        synchronized(mCancellationRequested) {
+            if (mCancellationRequested.get()) {
+                return new RemoteOperationResult(new OperationCancelledException());
             }
+        }
+        
+        mDownloadOperation = new DownloadRemoteFileOperation(mFile.getRemotePath(), tmpFolder);
+        Iterator<OnDatatransferProgressListener> listener = mDataTransferListeners.iterator();
+        while (listener.hasNext()) {
+            mDownloadOperation.addDatatransferProgressListener(listener.next());
+        }
+        result = mDownloadOperation.execute(client);
+        
+        if (result.isSuccess()) {
+            mModificationTimestamp = mDownloadOperation.getModificationTimestamp();
+            newFile = new File(getSavePath());
+            newFile.getParentFile().mkdirs();
+            moved = tmpFile.renameTo(newFile);
+        
             if (!moved)
                 result = new RemoteOperationResult(RemoteOperationResult.ResultCode.LOCAL_STORAGE_NOT_MOVED);
-            else
-                result = new RemoteOperationResult(isSuccess(status), status, (mGet != null ? mGet.getResponseHeaders() : null));
-            Log_OC.i(TAG, "Download of " + mFile.getRemotePath() + " to " + getSavePath() + ": " + result.getLogMessage());
-            
-        } catch (Exception e) {
-            result = new RemoteOperationResult(e);
-            Log_OC.e(TAG, "Download of " + mFile.getRemotePath() + " to " + getSavePath() + ": " + result.getLogMessage(), e);
         }
+        Log_OC.i(TAG, "Download of " + mFile.getRemotePath() + " to " + getSavePath() + ": " + result.getLogMessage());
+        
         
         return result;
     }
 
-    
-    public boolean isSuccess(int status) {
-        return (status == HttpStatus.SC_OK);
+    public void cancel() {
+        mCancellationRequested.set(true);   // atomic set; there is no need of synchronizing it
+        if (mDownloadOperation != null) {
+            mDownloadOperation.cancel();
+        }
     }
-    
-    
-    protected int downloadFile(WebdavClient client, File targetFile) throws HttpException, IOException, OperationCancelledException {
-        int status = -1;
-        boolean savedFile = false;
-        mGet = new GetMethod(client.getBaseUri() + WebdavUtils.encodePath(mFile.getRemotePath()));
-        Iterator<OnDatatransferProgressListener> it = null;
-        
-        FileOutputStream fos = null;
-        try {
-            status = client.executeMethod(mGet);
-            if (isSuccess(status)) {
-                targetFile.createNewFile();
-                BufferedInputStream bis = new BufferedInputStream(mGet.getResponseBodyAsStream());
-                fos = new FileOutputStream(targetFile);
-                long transferred = 0;
 
-                byte[] bytes = new byte[4096];
-                int readResult = 0;
-                while ((readResult = bis.read(bytes)) != -1) {
-                    synchronized(mCancellationRequested) {
-                        if (mCancellationRequested.get()) {
-                            mGet.abort();
-                            throw new OperationCancelledException();
-                        }
-                    }
-                    fos.write(bytes, 0, readResult);
-                    transferred += readResult;
-                    synchronized (mDataTransferListeners) {
-                        it = mDataTransferListeners.iterator();
-                        while (it.hasNext()) {
-                            it.next().onTransferProgress(readResult, transferred, mFile.getFileLength(), targetFile.getName());
-                        }
-                    }
-                }
-                savedFile = true;
-                Header modificationTime = mGet.getResponseHeader("Last-Modified");
-                if (modificationTime != null) {
-                    Date d = WebdavUtils.parseResponseDate((String) modificationTime.getValue());
-                    mModificationTimestamp = (d != null) ? d.getTime() : 0;
-                }
-                
-            } else {
-                client.exhaustResponse(mGet.getResponseBodyAsStream());
-            }
-                
-        } finally {
-            if (fos != null) fos.close();
-            if (!savedFile && targetFile.exists()) {
-                targetFile.delete();
-            }
-            mGet.releaseConnection();    // let the connection available for other methods
+
+    public void addDatatransferProgressListener (OnDatatransferProgressListener listener) {
+        synchronized (mDataTransferListeners) {
+            mDataTransferListeners.add(listener);
         }
-        return status;
     }
-
     
-    public void cancel() {
-        mCancellationRequested.set(true);   // atomic set; there is no need of synchronizing it
+    public void removeDatatransferProgressListener(OnDatatransferProgressListener listener) {
+        synchronized (mDataTransferListeners) {
+            mDataTransferListeners.remove(listener);
+        }
     }
-
-
+    
 }
diff --git a/src/com/owncloud/android/operations/ExistenceCheckOperation.java b/src/com/owncloud/android/operations/ExistenceCheckOperation.java
deleted file mode 100644 (file)
index 24336bd..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012 ownCloud Inc.
- *
- *   This program is free software: you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License version 2,
- *   as published by the Free Software Foundation.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-package com.owncloud.android.operations;
-
-import org.apache.commons.httpclient.HttpStatus;
-import org.apache.commons.httpclient.methods.HeadMethod;
-
-import com.owncloud.android.Log_OC;
-
-
-import eu.alefzero.webdav.WebdavClient;
-import eu.alefzero.webdav.WebdavUtils;
-import android.content.Context;
-import android.net.ConnectivityManager;
-
-/**
- * Operation to check the existence or absence of a path in a remote server.
- * 
- * @author David A. Velasco
- */
-public class ExistenceCheckOperation extends RemoteOperation {
-    
-    /** Maximum time to wait for a response from the server in MILLISECONDs.  */
-    public static final int TIMEOUT = 10000;
-    
-    private static final String TAG = ExistenceCheckOperation.class.getSimpleName();
-    
-    private String mPath;
-    private Context mContext;
-    private boolean mSuccessIfAbsent;
-
-    
-    /**
-     * Full constructor. Success of the operation will depend upon the value of successIfAbsent.
-     * 
-     * @param path              Path to append to the URL owned by the client instance.
-     * @param context           Android application context.
-     * @param successIfAbsent   When 'true', the operation finishes in success if the path does NOT exist in the remote server (HTTP 404).
-     */
-    public ExistenceCheckOperation(String path, Context context, boolean successIfAbsent) {
-        mPath = (path != null) ? path : "";
-        mContext = context;
-        mSuccessIfAbsent = successIfAbsent;
-    }
-    
-
-       @Override
-       protected RemoteOperationResult run(WebdavClient client) {
-        if (!isOnline()) {
-            return new RemoteOperationResult(RemoteOperationResult.ResultCode.NO_NETWORK_CONNECTION);
-        }
-        RemoteOperationResult result = null;
-        HeadMethod head = null;
-        try {
-            head = new HeadMethod(client.getBaseUri() + WebdavUtils.encodePath(mPath));
-            int status = client.executeMethod(head, TIMEOUT, TIMEOUT);
-            client.exhaustResponse(head.getResponseBodyAsStream());
-            boolean success = (status == HttpStatus.SC_OK && !mSuccessIfAbsent) || (status == HttpStatus.SC_NOT_FOUND && mSuccessIfAbsent);
-            result = new RemoteOperationResult(success, status, head.getResponseHeaders());
-            Log_OC.d(TAG, "Existence check for " + client.getBaseUri() + WebdavUtils.encodePath(mPath) + " targeting for " + (mSuccessIfAbsent ? " absence " : " existence ") + "finished with HTTP status " + status + (!success?"(FAIL)":""));
-            
-        } catch (Exception e) {
-            result = new RemoteOperationResult(e);
-            Log_OC.e(TAG, "Existence check for " + client.getBaseUri() + WebdavUtils.encodePath(mPath) + " targeting for " + (mSuccessIfAbsent ? " absence " : " existence ") + ": " + result.getLogMessage(), result.getException());
-            
-        } finally {
-            if (head != null)
-                head.releaseConnection();
-        }
-        return result;
-       }
-
-    private boolean isOnline() {
-        ConnectivityManager cm = (ConnectivityManager) mContext
-                .getSystemService(Context.CONNECTIVITY_SERVICE);
-        return cm != null && cm.getActiveNetworkInfo() != null
-                && cm.getActiveNetworkInfo().isConnectedOrConnecting();
-    }
-
-
-}
diff --git a/src/com/owncloud/android/operations/GetServerInfoOperation.java b/src/com/owncloud/android/operations/GetServerInfoOperation.java
new file mode 100644 (file)
index 0000000..9b7cf87
--- /dev/null
@@ -0,0 +1,158 @@
+/* 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.
+ *
+ */
+
+package com.owncloud.android.operations;
+
+import java.util.ArrayList;
+
+import com.owncloud.android.authentication.AccountUtils;
+import com.owncloud.android.lib.common.OwnCloudClient;
+import com.owncloud.android.lib.common.operations.RemoteOperation;
+import com.owncloud.android.lib.common.operations.RemoteOperationResult;
+import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;
+import com.owncloud.android.lib.common.utils.Log_OC;
+import com.owncloud.android.lib.resources.status.GetRemoteStatusOperation;
+import com.owncloud.android.lib.resources.status.OwnCloudVersion;
+import com.owncloud.android.operations.DetectAuthenticationMethodOperation.AuthenticationMethod;
+
+import android.content.Context;
+
+/**
+ * Get basic information from an ownCloud server given its URL.
+ * 
+ * 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 {
+    
+    private static final String TAG = GetServerInfoOperation.class.getSimpleName();
+    
+    private String mUrl;
+    private Context mContext;
+    
+    private ServerInfo mResultData;
+
+    /** 
+     * Constructor.
+     * 
+     * @param url               URL to an ownCloud server.
+     * @param context           Android context; needed to check network state
+     *                          TODO ugly dependency, get rid of it. 
+     */
+    public GetServerInfoOperation(String url, Context context) {
+        mUrl = trimWebdavSuffix(url);
+        mContext = context;
+        
+        mResultData = new ServerInfo();
+    }
+    
+    
+    /**
+     * Performs the operation
+     * 
+     * @return      Result of the operation. If successful, includes an instance of 
+     *              {@link ServerInfo} with the information retrieved from the server. 
+     *              Call {@link RemoteOperationResult#getData()}.get(0) to get it.
+     */
+       @Override
+       protected RemoteOperationResult run(OwnCloudClient client) {
+           
+           // first: check the status of the server (including its version)
+           GetRemoteStatusOperation getStatus = new GetRemoteStatusOperation(mContext);
+           RemoteOperationResult result = getStatus.execute(client);
+           
+        if (result.isSuccess()) {
+            // second: get authentication method required by the server
+            mResultData.mVersion = (OwnCloudVersion)(result.getData().get(0));
+            mResultData.mIsSslConn = (result.getCode() == ResultCode.OK_SSL);
+            mResultData.mBaseUrl = normalizeProtocolPrefix(mUrl, mResultData.mIsSslConn);
+            RemoteOperationResult detectAuthResult = detectAuthorizationMethod(client);
+            
+            // third: merge results
+            if (detectAuthResult.isSuccess()) {
+                mResultData.mAuthMethod = 
+                        (AuthenticationMethod)detectAuthResult.getData().get(0);
+                ArrayList<Object> data = new ArrayList<Object>();
+                data.add(mResultData);
+                result.setData(data);
+            } else {
+                result = detectAuthResult;
+            }
+        }
+        return result;
+       }
+
+       
+    private RemoteOperationResult detectAuthorizationMethod(OwnCloudClient client) {
+        Log_OC.d(TAG, "Trying empty authorization to detect authentication method");
+        DetectAuthenticationMethodOperation operation = 
+                new DetectAuthenticationMethodOperation(mContext);
+        return operation.execute(client);
+    }
+    
+
+    private String trimWebdavSuffix(String url) {
+        if (url == null) {
+            url = "";
+        } else {
+            if (url.endsWith("/")) {
+                url = url.substring(0, url.length() - 1);
+            }
+            if(url.toLowerCase().endsWith(AccountUtils.WEBDAV_PATH_4_0)){
+                url = url.substring(0, url.length() - AccountUtils.WEBDAV_PATH_4_0.length());
+            } else if(url.toLowerCase().endsWith(AccountUtils.WEBDAV_PATH_2_0)){
+                url = url.substring(0, url.length() - AccountUtils.WEBDAV_PATH_2_0.length());
+            } else if (url.toLowerCase().endsWith(AccountUtils.WEBDAV_PATH_1_2)){
+                url = url.substring(0, url.length() - AccountUtils.WEBDAV_PATH_1_2.length());
+            }
+        }
+        return url;
+    }
+
+    
+    private String normalizeProtocolPrefix(String url, boolean isSslConn) {
+        if (!url.toLowerCase().startsWith("http://") &&
+                !url.toLowerCase().startsWith("https://")) {
+            if (isSslConn) {
+                return "https://" + url;
+            } else {
+                return "http://" + url;
+            }
+        }
+        return url;
+    }
+    
+    
+    public static class ServerInfo {
+        public OwnCloudVersion mVersion = null;
+        public String mBaseUrl = "";
+        public AuthenticationMethod mAuthMethod = AuthenticationMethod.UNKNOWN;
+        public boolean mIsSslConn = false;
+    }
+       
+}
diff --git a/src/com/owncloud/android/operations/GetSharesForFileOperation.java b/src/com/owncloud/android/operations/GetSharesForFileOperation.java
new file mode 100644 (file)
index 0000000..c319d62
--- /dev/null
@@ -0,0 +1,79 @@
+/* ownCloud Android client application
+ *   Copyright (C) 2012-2013 ownCloud Inc.
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License version 2,
+ *   as published by the Free Software Foundation.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+package com.owncloud.android.operations;
+
+import java.util.ArrayList;
+
+import com.owncloud.android.lib.common.OwnCloudClient;
+import com.owncloud.android.lib.resources.shares.OCShare;
+import com.owncloud.android.lib.common.operations.RemoteOperationResult;
+import com.owncloud.android.lib.common.utils.Log_OC;
+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
+ *
+ */
+public class GetSharesForFileOperation extends SyncOperation {
+    
+    private static final String TAG = GetSharesForFileOperation.class.getSimpleName();
+    
+    private String mPath;
+    private boolean mReshares;
+    private boolean mSubfiles;
+
+    /**
+     * Constructor
+     * 
+     * @param path      Path to file or folder
+     * @param reshares  If set to \91false\92 (default), only shares from the current user are returned
+     *                  If set to \91true\92, all shares from the given file are returned
+     * @param subfiles  If set to \91false\92 (default), lists only the folder being shared
+     *                  If set to \91true\92, all shared files within the folder are returned.
+     */
+    public GetSharesForFileOperation(String path, boolean reshares, boolean subfiles) {
+        mPath = path;
+        mReshares = reshares;
+        mSubfiles = subfiles;
+    }
+
+    @Override
+    protected RemoteOperationResult run(OwnCloudClient client) {
+        GetRemoteSharesForFileOperation operation = new GetRemoteSharesForFileOperation(mPath, mReshares, mSubfiles);
+        RemoteOperationResult result = operation.execute(client);
+
+        if (result.isSuccess()) {
+
+            // Update DB with the response
+            Log_OC.d(TAG, "File = " + mPath + " Share list size  " + result.getData().size());
+            ArrayList<OCShare> shares = new ArrayList<OCShare>();
+            for(Object obj: result.getData()) {
+                shares.add((OCShare) obj);
+            }
+
+            getStorageManager().saveSharesDB(shares);
+        }
+
+        return result;
+    }
+
+}
diff --git a/src/com/owncloud/android/operations/GetSharesOperation.java b/src/com/owncloud/android/operations/GetSharesOperation.java
new file mode 100644 (file)
index 0000000..d096788
--- /dev/null
@@ -0,0 +1,61 @@
+/* ownCloud Android client application
+ *   Copyright (C) 2012-2014 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;
+
+import com.owncloud.android.lib.common.OwnCloudClient;
+import com.owncloud.android.lib.common.operations.RemoteOperationResult;
+import com.owncloud.android.lib.common.utils.Log_OC;
+import com.owncloud.android.lib.resources.shares.OCShare;
+import com.owncloud.android.lib.resources.shares.GetRemoteSharesOperation;
+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 {
+
+    private static final String TAG = GetSharesOperation.class.getSimpleName();
+
+    @Override
+    protected RemoteOperationResult run(OwnCloudClient client) {
+        GetRemoteSharesOperation operation = new GetRemoteSharesOperation();
+        RemoteOperationResult result = operation.execute(client);
+
+        if (result.isSuccess()) {
+
+            // Update DB with the response
+            Log_OC.d(TAG, "Share list size = " + result.getData().size());
+            ArrayList<OCShare> shares = new ArrayList<OCShare>();
+            for(Object obj: result.getData()) {
+                shares.add((OCShare) obj);
+            }
+
+            getStorageManager().saveSharesDB(shares);
+        }
+
+        return result;
+    }
+
+}
diff --git a/src/com/owncloud/android/operations/MoveFileOperation.java b/src/com/owncloud/android/operations/MoveFileOperation.java
new file mode 100644 (file)
index 0000000..63856c3
--- /dev/null
@@ -0,0 +1,103 @@
+/* ownCloud Android client application
+ *   Copyright (C) 2012-2014 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 com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.lib.common.OwnCloudClient;
+import com.owncloud.android.lib.common.operations.RemoteOperationResult;
+import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;
+import com.owncloud.android.lib.resources.files.MoveRemoteFileOperation;
+import com.owncloud.android.operations.common.SyncOperation;
+
+import android.accounts.Account;
+
+
+/**
+ * Operation mmoving an {@link OCFile} to a different folder.
+ * 
+ * @author David A. Velasco
+ */
+public class MoveFileOperation extends SyncOperation {
+    
+    //private static final String TAG = MoveFileOperation.class.getSimpleName();
+    
+    private String mSrcPath;
+    private String mTargetParentPath;
+    
+    private OCFile mFile;
+
+    
+    
+    /**
+     * Constructor
+     * 
+     * @param path              Remote path of the {@link OCFile} to move.
+     * @param newParentPath     Path to the folder where the file will be moved into. 
+     * @param account           OwnCloud account containing both the file and the target folder 
+     */
+    public MoveFileOperation(String srcPath, String targetParentPath, Account account) {
+        mSrcPath = srcPath;
+        mTargetParentPath = targetParentPath;
+        if (!mTargetParentPath.endsWith(OCFile.PATH_SEPARATOR)) {
+            mTargetParentPath += OCFile.PATH_SEPARATOR;
+        }
+        
+        mFile = null;
+    }
+  
+    /**
+     * Performs the operation.
+     * 
+     * @param   client      Client object to communicate with the remote ownCloud server.
+     */
+    @Override
+    protected RemoteOperationResult run(OwnCloudClient client) {
+        RemoteOperationResult result = null;
+        
+        /// 1. check move validity
+        if (mTargetParentPath.startsWith(mSrcPath)) {
+            return new RemoteOperationResult(ResultCode.INVALID_MOVE_INTO_DESCENDANT);
+        }
+        mFile = getStorageManager().getFileByPath(mSrcPath);
+        if (mFile == null) {
+            return new RemoteOperationResult(ResultCode.FILE_NOT_FOUND);
+        }
+        
+        /// 2. remote move
+        String targetPath = mTargetParentPath + mFile.getFileName();
+        if (mFile.isFolder()) {
+            targetPath += OCFile.PATH_SEPARATOR;
+        }
+        MoveRemoteFileOperation operation = new MoveRemoteFileOperation(
+                mSrcPath, 
+                targetPath, 
+                false
+        );
+        result = operation.execute(client);
+        
+        /// 3. local move
+        if (result.isSuccess()) {
+            getStorageManager().moveLocalFile(mFile, targetPath, mTargetParentPath);
+        } 
+        // TODO handle ResultCode.PARTIAL_MOVE_DONE in client Activity, for the moment
+        
+        return result;
+    }
+    
+
+}
index 09a6e1e..6f4ff74 100644 (file)
@@ -1,5 +1,6 @@
 package com.owncloud.android.operations;
 
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -8,13 +9,14 @@ import org.apache.commons.httpclient.NameValuePair;
 import org.json.JSONException;
 import org.json.JSONObject;
 
-import com.owncloud.android.Log_OC;
 import com.owncloud.android.authentication.OAuth2Constants;
-import com.owncloud.android.operations.RemoteOperationResult.ResultCode;
+import com.owncloud.android.lib.common.OwnCloudClient;
+import com.owncloud.android.lib.common.operations.RemoteOperation;
+import com.owncloud.android.lib.common.operations.RemoteOperationResult;
+import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;
+import com.owncloud.android.lib.common.utils.Log_OC;
 
 
-import eu.alefzero.webdav.WebdavClient;
-
 public class OAuth2GetAccessToken extends RemoteOperation {
     
     private static final String TAG = OAuth2GetAccessToken.class.getSimpleName();
@@ -36,18 +38,15 @@ public class OAuth2GetAccessToken extends RemoteOperation {
         mOAuth2ParsedAuthorizationResponse = new HashMap<String, String>();
         mResultTokenMap = null;
     }
-    
-    
-    public Map<String, String> getOauth2AutorizationResponse() {
-        return mOAuth2ParsedAuthorizationResponse;
-    }
 
+    /*
     public Map<String, String> getResultTokenMap() {
         return mResultTokenMap;
     }
+    */
     
     @Override
-    protected RemoteOperationResult run(WebdavClient client) {
+    protected RemoteOperationResult run(OwnCloudClient client) {
         RemoteOperationResult result = null;
         PostMethod postMethod = null;
         
@@ -69,7 +68,7 @@ public class OAuth2GetAccessToken extends RemoteOperation {
                 nameValuePairs[3] = new NameValuePair(OAuth2Constants.KEY_CLIENT_ID, mClientId);
                 //nameValuePairs[4] = new NameValuePair(OAuth2Constants.KEY_SCOPE, mOAuth2ParsedAuthorizationResponse.get(OAuth2Constants.KEY_SCOPE));         
                 
-                postMethod = new PostMethod(client.getBaseUri().toString());
+                postMethod = new PostMethod(client.getWebdavUri().toString());
                 postMethod.setRequestBody(nameValuePairs);
                 int status = client.executeMethod(postMethod);
                 
@@ -82,6 +81,9 @@ public class OAuth2GetAccessToken extends RemoteOperation {
                     
                     } else {
                         result = new RemoteOperationResult(true, status, postMethod.getResponseHeaders());
+                        ArrayList<Object> data = new ArrayList<Object>();
+                        data.add(mResultTokenMap);
+                        result.setData(data);
                     }
                     
                 } else {
@@ -98,16 +100,16 @@ public class OAuth2GetAccessToken extends RemoteOperation {
                 postMethod.releaseConnection();    // let the connection available for other methods
             
             if (result.isSuccess()) {
-                Log_OC.i(TAG, "OAuth2 TOKEN REQUEST with auth code " + mOAuth2ParsedAuthorizationResponse.get("code") + " to " + client.getBaseUri() + ": " + result.getLogMessage());
+                Log_OC.i(TAG, "OAuth2 TOKEN REQUEST with auth code " + mOAuth2ParsedAuthorizationResponse.get("code") + " to " + client.getWebdavUri() + ": " + result.getLogMessage());
             
             } else if (result.getException() != null) {
-                Log_OC.e(TAG, "OAuth2 TOKEN REQUEST with auth code " + mOAuth2ParsedAuthorizationResponse.get("code") + " to " + client.getBaseUri() + ": " + result.getLogMessage(), result.getException());
+                Log_OC.e(TAG, "OAuth2 TOKEN REQUEST with auth code " + mOAuth2ParsedAuthorizationResponse.get("code") + " to " + client.getWebdavUri() + ": " + result.getLogMessage(), result.getException());
                 
             } else if (result.getCode() == ResultCode.OAUTH2_ERROR) {
-                Log_OC.e(TAG, "OAuth2 TOKEN REQUEST with auth code " + mOAuth2ParsedAuthorizationResponse.get("code") + " to " + client.getBaseUri() + ": " + ((mResultTokenMap != null) ? mResultTokenMap.get(OAuth2Constants.KEY_ERROR) : "NULL"));
+                Log_OC.e(TAG, "OAuth2 TOKEN REQUEST with auth code " + mOAuth2ParsedAuthorizationResponse.get("code") + " to " + client.getWebdavUri() + ": " + ((mResultTokenMap != null) ? mResultTokenMap.get(OAuth2Constants.KEY_ERROR) : "NULL"));
                     
             } else {
-                Log_OC.e(TAG, "OAuth2 TOKEN REQUEST with auth code " + mOAuth2ParsedAuthorizationResponse.get("code") + " to " + client.getBaseUri() + ": " + result.getLogMessage());
+                Log_OC.e(TAG, "OAuth2 TOKEN REQUEST with auth code " + mOAuth2ParsedAuthorizationResponse.get("code") + " to " + client.getWebdavUri() + ": " + result.getLogMessage());
             }
         }
         
diff --git a/src/com/owncloud/android/operations/OnRemoteOperationListener.java b/src/com/owncloud/android/operations/OnRemoteOperationListener.java
deleted file mode 100644 (file)
index e6a58e7..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012 Bartek Przybylski
- *   Copyright (C) 2012-2013 ownCloud Inc.
- *
- *   This program is free software: you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License version 2,
- *   as published by the Free Software Foundation.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-package com.owncloud.android.operations;
-
-public interface OnRemoteOperationListener {
-
-       void onRemoteOperationFinish(RemoteOperation caller, RemoteOperationResult result);
-       
-}
diff --git a/src/com/owncloud/android/operations/OperationCancelledException.java b/src/com/owncloud/android/operations/OperationCancelledException.java
deleted file mode 100644 (file)
index 0b7878c..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012 Bartek Przybylski
- *   Copyright (C) 2012-2013 ownCloud Inc.
- *
- *   This program is free software: you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License version 2,
- *   as published by the Free Software Foundation.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-package com.owncloud.android.operations;
-
-public class OperationCancelledException extends Exception {
-
-    /**
-     * Generated serial version - to avoid Java warning
-     */
-    private static final long serialVersionUID = -6350981497740424983L;
-
-}
diff --git a/src/com/owncloud/android/operations/OwnCloudServerCheckOperation.java b/src/com/owncloud/android/operations/OwnCloudServerCheckOperation.java
deleted file mode 100644 (file)
index 6234224..0000000
+++ /dev/null
@@ -1,138 +0,0 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012-2013 ownCloud Inc.
- *
- *   This program is free software: you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License version 2,
- *   as published by the Free Software Foundation.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-package com.owncloud.android.operations;
-
-import org.apache.commons.httpclient.HttpStatus;
-import org.apache.commons.httpclient.methods.GetMethod;
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import com.owncloud.android.Log_OC;
-import com.owncloud.android.authentication.AccountUtils;
-import com.owncloud.android.utils.OwnCloudVersion;
-
-
-import eu.alefzero.webdav.WebdavClient;
-import android.content.Context;
-import android.net.ConnectivityManager;
-import android.net.Uri;
-
-public class OwnCloudServerCheckOperation extends RemoteOperation {
-    
-    /** Maximum time to wait for a response from the server when the connection is being tested, in MILLISECONDs.  */
-    public static final int TRY_CONNECTION_TIMEOUT = 5000;
-    
-    private static final String TAG = OwnCloudServerCheckOperation.class.getSimpleName();
-    
-    private String mUrl;
-    private RemoteOperationResult mLatestResult;
-    private Context mContext;
-    private OwnCloudVersion mOCVersion;
-
-    public OwnCloudServerCheckOperation(String url, Context context) {
-        mUrl = url;
-        mContext = context;
-        mOCVersion = null;
-    }
-    
-    public OwnCloudVersion getDiscoveredVersion() {
-        return mOCVersion;
-    }
-
-    private boolean tryConnection(WebdavClient wc, String urlSt) {
-        boolean retval = false;
-        GetMethod get = null;
-        try {
-            get = new GetMethod(urlSt);
-            int status = wc.executeMethod(get, TRY_CONNECTION_TIMEOUT, TRY_CONNECTION_TIMEOUT);
-            String response = get.getResponseBodyAsString();
-            if (status == HttpStatus.SC_OK) {
-                JSONObject json = new JSONObject(response);
-                if (!json.getBoolean("installed")) {
-                    mLatestResult = new RemoteOperationResult(RemoteOperationResult.ResultCode.INSTANCE_NOT_CONFIGURED);
-                } else {
-                    mOCVersion = new OwnCloudVersion(json.getString("version"));
-                    if (!mOCVersion.isVersionValid()) {
-                        mLatestResult = new RemoteOperationResult(RemoteOperationResult.ResultCode.BAD_OC_VERSION);
-                        
-                    } else {
-                        mLatestResult = new RemoteOperationResult(urlSt.startsWith("https://") ? 
-                                                                    RemoteOperationResult.ResultCode.OK_SSL : 
-                                                                    RemoteOperationResult.ResultCode.OK_NO_SSL
-                            );
-
-                        retval = true;
-                    }
-                }
-                
-            } else {
-                mLatestResult = new RemoteOperationResult(false, status, get.getResponseHeaders());
-            }
-
-        } catch (JSONException e) {
-            mLatestResult = new RemoteOperationResult(RemoteOperationResult.ResultCode.INSTANCE_NOT_CONFIGURED);
-            
-        } catch (Exception e) {
-            mLatestResult = new RemoteOperationResult(e);
-            
-        } finally {
-            if (get != null)
-                get.releaseConnection();
-        }
-        
-        if (mLatestResult.isSuccess()) {
-            Log_OC.i(TAG, "Connection check at " + urlSt + ": " + mLatestResult.getLogMessage());
-            
-        } else if (mLatestResult.getException() != null) {
-            Log_OC.e(TAG, "Connection check at " + urlSt + ": " + mLatestResult.getLogMessage(), mLatestResult.getException());
-            
-        } else {
-            Log_OC.e(TAG, "Connection check at " + urlSt + ": " + mLatestResult.getLogMessage());
-        }
-
-        return retval;
-    }
-
-    private boolean isOnline() {
-        ConnectivityManager cm = (ConnectivityManager) mContext
-                .getSystemService(Context.CONNECTIVITY_SERVICE);
-        return cm != null && cm.getActiveNetworkInfo() != null
-                && cm.getActiveNetworkInfo().isConnectedOrConnecting();
-    }
-
-       @Override
-       protected RemoteOperationResult run(WebdavClient client) {
-        if (!isOnline()) {
-               return new RemoteOperationResult(RemoteOperationResult.ResultCode.NO_NETWORK_CONNECTION);
-        }
-        if (mUrl.startsWith("http://") || mUrl.startsWith("https://")) {
-            tryConnection(client, mUrl + AccountUtils.STATUS_PATH);
-            
-        } else {
-            client.setBaseUri(Uri.parse("https://" + mUrl + AccountUtils.STATUS_PATH));
-            boolean httpsSuccess = tryConnection(client, "https://" + mUrl + AccountUtils.STATUS_PATH); 
-            if (!httpsSuccess && !mLatestResult.isSslRecoverableException()) {
-                Log_OC.d(TAG, "establishing secure connection failed, trying non secure connection");
-                client.setBaseUri(Uri.parse("http://" + mUrl + AccountUtils.STATUS_PATH));
-                tryConnection(client, "http://" + mUrl + AccountUtils.STATUS_PATH);
-            }
-        }
-        return mLatestResult;
-       }
-       
-}
diff --git a/src/com/owncloud/android/operations/RemoteOperation.java b/src/com/owncloud/android/operations/RemoteOperation.java
deleted file mode 100644 (file)
index 6e674c4..0000000
+++ /dev/null
@@ -1,287 +0,0 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012-2013 ownCloud Inc.
- *
- *   This program is free software: you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License version 2,
- *   as published by the Free Software Foundation.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- */
-package com.owncloud.android.operations;
-
-import java.io.IOException;
-
-import org.apache.commons.httpclient.Credentials;
-
-import com.owncloud.android.Log_OC;
-import com.owncloud.android.MainApp;
-import com.owncloud.android.network.BearerCredentials;
-import com.owncloud.android.network.OwnCloudClientUtils;
-import com.owncloud.android.operations.RemoteOperationResult.ResultCode;
-
-
-import android.accounts.Account;
-import android.accounts.AccountManager;
-import android.accounts.AccountsException;
-import android.app.Activity;
-import android.content.Context;
-import android.os.Handler;
-
-import eu.alefzero.webdav.WebdavClient;
-
-/**
- * Operation which execution involves one or several interactions with an ownCloud server.
- * 
- * Provides methods to execute the operation both synchronously or asynchronously.
- * 
- * @author David A. Velasco 
- */
-public abstract class RemoteOperation implements Runnable {
-       
-    private static final String TAG = RemoteOperation.class.getSimpleName();
-
-    /** ownCloud account in the remote ownCloud server to operate */
-    private Account mAccount = null;
-    
-    /** Android Application context */
-    private Context mContext = null;
-    
-       /** Object to interact with the remote server */
-       private WebdavClient mClient = null;
-       
-       /** Callback object to notify about the execution of the remote operation */
-       private OnRemoteOperationListener mListener = null;
-       
-       /** Handler to the thread where mListener methods will be called */
-       private Handler mListenerHandler = null;
-
-       /** Activity */
-    private Activity mCallerActivity;
-
-       
-       /**
-        *  Abstract method to implement the operation in derived classes.
-        */
-       protected abstract RemoteOperationResult run(WebdavClient client); 
-       
-
-    /**
-     * Synchronously executes the remote operation on the received ownCloud account.
-     * 
-     * Do not call this method from the main thread.
-     * 
-     * This method should be used whenever an ownCloud account is available, instead of {@link #execute(WebdavClient)}. 
-     * 
-     * @param account   ownCloud account in remote ownCloud server to reach during the execution of the operation.
-     * @param context   Android context for the component calling the method.
-     * @return          Result of the operation.
-     */
-    public final RemoteOperationResult execute(Account account, Context context) {
-        if (account == null)
-            throw new IllegalArgumentException("Trying to execute a remote operation with a NULL Account");
-        if (context == null)
-            throw new IllegalArgumentException("Trying to execute a remote operation with a NULL Context");
-        mAccount = account;
-        mContext = context.getApplicationContext();
-        try {
-            mClient = OwnCloudClientUtils.createOwnCloudClient(mAccount, mContext);
-        } catch (Exception e) {
-            Log_OC.e(TAG, "Error while trying to access to " + mAccount.name, e);
-            return new RemoteOperationResult(e);
-        }
-        return run(mClient);
-    }
-    
-       
-       /**
-        * Synchronously executes the remote operation
-        * 
-     * Do not call this method from the main thread.
-     * 
-        * @param client        Client object to reach an ownCloud server during the execution of the operation.
-        * @return                      Result of the operation.
-        */
-       public final RemoteOperationResult execute(WebdavClient client) {
-               if (client == null)
-                       throw new IllegalArgumentException("Trying to execute a remote operation with a NULL WebdavClient");
-               mClient = client;
-               return run(client);
-       }
-
-       
-    /**
-     * Asynchronously executes the remote operation
-     * 
-     * This method should be used whenever an ownCloud account is available, instead of {@link #execute(WebdavClient)}. 
-     * 
-     * @param account           ownCloud account in remote ownCloud server to reach during the execution of the operation.
-     * @param context           Android context for the component calling the method.
-     * @param listener          Listener to be notified about the execution of the operation.
-     * @param listenerHandler   Handler associated to the thread where the methods of the listener objects must be called.
-     * @return                  Thread were the remote operation is executed.
-     */
-    public final Thread execute(Account account, Context context, OnRemoteOperationListener listener, Handler listenerHandler, Activity callerActivity) {
-        if (account == null)
-            throw new IllegalArgumentException("Trying to execute a remote operation with a NULL Account");
-        if (context == null)
-            throw new IllegalArgumentException("Trying to execute a remote operation with a NULL Context");
-        mAccount = account;
-        mContext = context.getApplicationContext();
-        mCallerActivity = callerActivity;
-        mClient = null;     // the client instance will be created from mAccount and mContext in the runnerThread to create below
-        
-        mListener = listener;
-        
-        mListenerHandler = listenerHandler;
-        
-        Thread runnerThread = new Thread(this);
-        runnerThread.start();
-        return runnerThread;
-    }
-
-    
-       /**
-        * Asynchronously executes the remote operation
-        * 
-        * @param client                        Client object to reach an ownCloud server during the execution of the operation.
-        * @param listener                      Listener to be notified about the execution of the operation.
-        * @param listenerHandler       Handler associated to the thread where the methods of the listener objects must be called.
-        * @return                                      Thread were the remote operation is executed.
-        */
-       public final Thread execute(WebdavClient client, OnRemoteOperationListener listener, Handler listenerHandler) {
-               if (client == null) {
-                       throw new IllegalArgumentException("Trying to execute a remote operation with a NULL WebdavClient");
-               }
-               mClient = client;
-               
-               if (listener == null) {
-                       throw new IllegalArgumentException("Trying to execute a remote operation asynchronously without a listener to notiy the result");
-               }
-               mListener = listener;
-               
-               if (listenerHandler == null) {
-                       throw new IllegalArgumentException("Trying to execute a remote operation asynchronously without a handler to the listener's thread");
-               }
-               mListenerHandler = listenerHandler;
-               
-               Thread runnerThread = new Thread(this);
-               runnerThread.start();
-               return runnerThread;
-       }
-       
-    /**
-     * Synchronously retries the remote operation using the same WebdavClient in the last call to {@link RemoteOperation#execute(WebdavClient)}
-     * 
-     * @param listener          Listener to be notified about the execution of the operation.
-     * @param listenerHandler   Handler associated to the thread where the methods of the listener objects must be called.
-     * @return                  Thread were the remote operation is executed.
-     */
-    public final RemoteOperationResult retry() {
-        return execute(mClient);
-    }
-    
-    /**
-     * Asynchronously retries the remote operation using the same WebdavClient in the last call to {@link RemoteOperation#execute(WebdavClient, OnRemoteOperationListener, Handler)}
-     * 
-     * @param listener          Listener to be notified about the execution of the operation.
-     * @param listenerHandler   Handler associated to the thread where the methods of the listener objects must be called.
-     * @return                  Thread were the remote operation is executed.
-     */
-    public final Thread retry(OnRemoteOperationListener listener, Handler listenerHandler) {
-        return execute(mClient, listener, listenerHandler);
-    }
-       
-       
-       /**
-        * Asynchronous execution of the operation 
-        * started by {@link RemoteOperation#execute(WebdavClient, OnRemoteOperationListener, Handler)}, 
-        * and result posting.
-        * 
-        * TODO refactor && clean the code; now it's a mess
-        */
-    @Override
-    public final void run() {
-        RemoteOperationResult result = null;
-        boolean repeat = false;
-        do {
-            try{
-                if (mClient == null) {
-                    if (mAccount != null && mContext != null) {
-                        if (mCallerActivity != null) {
-                            mClient = OwnCloudClientUtils.createOwnCloudClient(mAccount, mContext, mCallerActivity);
-                        } else {
-                            mClient = OwnCloudClientUtils.createOwnCloudClient(mAccount, mContext);
-                        }
-                    } else {
-                        throw new IllegalStateException("Trying to run a remote operation asynchronously with no client instance or account");
-                    }
-                }
-            
-            } catch (IOException e) {
-                Log_OC.e(TAG, "Error while trying to access to " + mAccount.name, new AccountsException("I/O exception while trying to authorize the account", e));
-                result = new RemoteOperationResult(e);
-            
-            } catch (AccountsException e) {
-                Log_OC.e(TAG, "Error while trying to access to " + mAccount.name, e);
-                result = new RemoteOperationResult(e);
-            }
-       
-            if (result == null)
-                result = run(mClient);
-        
-            repeat = false;
-            if (mCallerActivity != null && mAccount != null && mContext != null && !result.isSuccess() &&
-//                    (result.getCode() == ResultCode.UNAUTHORIZED || (result.isTemporalRedirection() && result.isIdPRedirection()))) {
-                    (result.getCode() == ResultCode.UNAUTHORIZED || result.isIdPRedirection())) {
-                /// possible fail due to lack of authorization in an operation performed in foreground
-                Credentials cred = mClient.getCredentials();
-                String ssoSessionCookie = mClient.getSsoSessionCookie();
-                if (cred != null || ssoSessionCookie != null) {
-                    /// confirmed : unauthorized operation
-                    AccountManager am = AccountManager.get(mContext);
-                    boolean bearerAuthorization = (cred != null && cred instanceof BearerCredentials);
-                    boolean samlBasedSsoAuthorization = (cred == null && ssoSessionCookie != null);
-                    if (bearerAuthorization) {
-                        am.invalidateAuthToken(MainApp.getAccountType(), ((BearerCredentials)cred).getAccessToken());
-                    } else if (samlBasedSsoAuthorization ) {
-                        am.invalidateAuthToken(MainApp.getAccountType(), ssoSessionCookie);
-                    } else {
-                        am.clearPassword(mAccount);
-                    }
-                    mClient = null;
-                    repeat = true;  // when repeated, the creation of a new OwnCloudClient after erasing the saved credentials will trigger the login activity
-                    result = null;
-                }
-            }
-        } while (repeat);
-        
-        final RemoteOperationResult resultToSend = result;
-        if (mListenerHandler != null && mListener != null) {
-               mListenerHandler.post(new Runnable() {
-                @Override
-                public void run() {
-                    mListener.onRemoteOperationFinish(RemoteOperation.this, resultToSend);
-                }
-            });
-        }
-    }
-
-
-    /**
-     * Returns the current client instance to access the remote server.
-     * 
-     * @return      Current client instance to access the remote server.
-     */
-    public final WebdavClient getClient() {
-        return mClient;
-    }
-
-
-}
diff --git a/src/com/owncloud/android/operations/RemoteOperationResult.java b/src/com/owncloud/android/operations/RemoteOperationResult.java
deleted file mode 100644 (file)
index 8d9b3ee..0000000
+++ /dev/null
@@ -1,338 +0,0 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012 Bartek Przybylski
- *   Copyright (C) 2012-2013 ownCloud Inc.
- *
- *   This program is free software: you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License version 2,
- *   as published by the Free Software Foundation.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-package com.owncloud.android.operations;
-
-import java.io.IOException;
-import java.io.Serializable;
-import java.net.MalformedURLException;
-import java.net.SocketException;
-import java.net.SocketTimeoutException;
-import java.net.UnknownHostException;
-
-import javax.net.ssl.SSLException;
-
-import org.apache.commons.httpclient.ConnectTimeoutException;
-import org.apache.commons.httpclient.Header;
-import org.apache.commons.httpclient.HttpException;
-import org.apache.commons.httpclient.HttpStatus;
-import org.apache.jackrabbit.webdav.DavException;
-
-import com.owncloud.android.Log_OC;
-import com.owncloud.android.authentication.AccountUtils.AccountNotFoundException;
-import com.owncloud.android.network.CertificateCombinedException;
-
-import android.accounts.Account;
-import android.accounts.AccountsException;
-
-
-/**
- * The result of a remote operation required to an ownCloud server.
- * 
- * Provides a common classification of remote operation results for all the
- * application.
- * 
- * @author David A. Velasco
- */
-public class RemoteOperationResult implements Serializable {
-
-    /** Generated - should be refreshed every time the class changes!! */
-    private static final long serialVersionUID = -4415103901492836870L;
-    
-
-    
-    private static final String TAG = "RemoteOperationResult";
-    
-    public enum ResultCode { 
-        OK,
-        OK_SSL,
-        OK_NO_SSL,
-        UNHANDLED_HTTP_CODE,
-        UNAUTHORIZED,        
-        FILE_NOT_FOUND, 
-        INSTANCE_NOT_CONFIGURED, 
-        UNKNOWN_ERROR, 
-        WRONG_CONNECTION,  
-        TIMEOUT, 
-        INCORRECT_ADDRESS, 
-        HOST_NOT_AVAILABLE, 
-        NO_NETWORK_CONNECTION, 
-        SSL_ERROR,
-        SSL_RECOVERABLE_PEER_UNVERIFIED,
-        BAD_OC_VERSION,
-        CANCELLED, 
-        INVALID_LOCAL_FILE_NAME, 
-        INVALID_OVERWRITE,
-        CONFLICT, 
-        OAUTH2_ERROR,
-        SYNC_CONFLICT,
-        LOCAL_STORAGE_FULL, 
-        LOCAL_STORAGE_NOT_MOVED, 
-        LOCAL_STORAGE_NOT_COPIED, 
-        OAUTH2_ERROR_ACCESS_DENIED,
-        QUOTA_EXCEEDED, 
-        ACCOUNT_NOT_FOUND, 
-        ACCOUNT_EXCEPTION, 
-        ACCOUNT_NOT_NEW, 
-        ACCOUNT_NOT_THE_SAME
-    }
-
-    private boolean mSuccess = false;
-    private int mHttpCode = -1;
-    private Exception mException = null;
-    private ResultCode mCode = ResultCode.UNKNOWN_ERROR;
-    private String mRedirectedLocation;
-
-    public RemoteOperationResult(ResultCode code) {
-        mCode = code;
-        mSuccess = (code == ResultCode.OK || code == ResultCode.OK_SSL || code == ResultCode.OK_NO_SSL);
-    }
-
-    private RemoteOperationResult(boolean success, int httpCode) {
-        mSuccess = success;
-        mHttpCode = httpCode;
-
-        if (success) {
-            mCode = ResultCode.OK;
-
-        } else if (httpCode > 0) {
-            switch (httpCode) {
-            case HttpStatus.SC_UNAUTHORIZED:
-                mCode = ResultCode.UNAUTHORIZED;
-                break;
-            case HttpStatus.SC_NOT_FOUND:
-                mCode = ResultCode.FILE_NOT_FOUND;
-                break;
-            case HttpStatus.SC_INTERNAL_SERVER_ERROR:
-                mCode = ResultCode.INSTANCE_NOT_CONFIGURED;
-                break;
-            case HttpStatus.SC_CONFLICT:
-                mCode = ResultCode.CONFLICT;
-                break;
-            case HttpStatus.SC_INSUFFICIENT_STORAGE:
-                mCode = ResultCode.QUOTA_EXCEEDED;
-                break;
-            default:
-                mCode = ResultCode.UNHANDLED_HTTP_CODE;
-                Log_OC.d(TAG, "RemoteOperationResult has processed UNHANDLED_HTTP_CODE: " + httpCode);
-            }
-        }
-    }
-    
-    public RemoteOperationResult(boolean success, int httpCode, Header[] headers) {
-        this(success, httpCode);
-        if (headers != null) {
-            Header current;
-            for (int i=0; i<headers.length; i++) {
-                current = headers[i];
-                if ("Location".equals(current.getName())) {
-                    mRedirectedLocation = current.getValue();
-                    break;
-                }
-            }
-        }
-    }    
-
-    public RemoteOperationResult(Exception e) {
-        mException = e;
-
-        if (e instanceof OperationCancelledException) {
-            mCode = ResultCode.CANCELLED;
-
-        } else if (e instanceof SocketException) {
-            mCode = ResultCode.WRONG_CONNECTION;
-
-        } else if (e instanceof SocketTimeoutException) {
-            mCode = ResultCode.TIMEOUT;
-
-        } else if (e instanceof ConnectTimeoutException) {
-            mCode = ResultCode.TIMEOUT;
-
-        } else if (e instanceof MalformedURLException) {
-            mCode = ResultCode.INCORRECT_ADDRESS;
-
-        } else if (e instanceof UnknownHostException) {
-            mCode = ResultCode.HOST_NOT_AVAILABLE;
-
-        } else if (e instanceof AccountNotFoundException) {
-            mCode = ResultCode.ACCOUNT_NOT_FOUND;
-            
-        } else if (e instanceof AccountsException) {
-            mCode = ResultCode.ACCOUNT_EXCEPTION;
-            
-        } else if (e instanceof SSLException || e instanceof RuntimeException) {
-            CertificateCombinedException se = getCertificateCombinedException(e);
-            if (se != null) {
-                mException = se;
-                if (se.isRecoverable()) {
-                    mCode = ResultCode.SSL_RECOVERABLE_PEER_UNVERIFIED;
-                }
-            } else if (e instanceof RuntimeException) {
-                mCode = ResultCode.HOST_NOT_AVAILABLE;
-
-            } else {
-                mCode = ResultCode.SSL_ERROR;
-            }
-
-        } else {
-            mCode = ResultCode.UNKNOWN_ERROR;
-        }
-
-    }
-
-    public boolean isSuccess() {
-        return mSuccess;
-    }
-
-    public boolean isCancelled() {
-        return mCode == ResultCode.CANCELLED;
-    }
-
-    public int getHttpCode() {
-        return mHttpCode;
-    }
-
-    public ResultCode getCode() {
-        return mCode;
-    }
-
-    public Exception getException() {
-        return mException;
-    }
-
-    public boolean isSslRecoverableException() {
-        return mCode == ResultCode.SSL_RECOVERABLE_PEER_UNVERIFIED;
-    }
-
-    private CertificateCombinedException getCertificateCombinedException(Exception e) {
-        CertificateCombinedException result = null;
-        if (e instanceof CertificateCombinedException) {
-            return (CertificateCombinedException) e;
-        }
-        Throwable cause = mException.getCause();
-        Throwable previousCause = null;
-        while (cause != null && cause != previousCause && !(cause instanceof CertificateCombinedException)) {
-            previousCause = cause;
-            cause = cause.getCause();
-        }
-        if (cause != null && cause instanceof CertificateCombinedException) {
-            result = (CertificateCombinedException) cause;
-        }
-        return result;
-    }
-
-    public String getLogMessage() {
-
-        if (mException != null) {
-            if (mException instanceof OperationCancelledException) {
-                return "Operation cancelled by the caller";
-
-            } else if (mException instanceof SocketException) {
-                return "Socket exception";
-
-            } else if (mException instanceof SocketTimeoutException) {
-                return "Socket timeout exception";
-
-            } else if (mException instanceof ConnectTimeoutException) {
-                return "Connect timeout exception";
-
-            } else if (mException instanceof MalformedURLException) {
-                return "Malformed URL exception";
-
-            } else if (mException instanceof UnknownHostException) {
-                return "Unknown host exception";
-
-            } else if (mException instanceof CertificateCombinedException) {
-                if (((CertificateCombinedException) mException).isRecoverable())
-                    return "SSL recoverable exception";
-                else
-                    return "SSL exception";
-
-            } else if (mException instanceof SSLException) {
-                return "SSL exception";
-
-            } else if (mException instanceof DavException) {
-                return "Unexpected WebDAV exception";
-
-            } else if (mException instanceof HttpException) {
-                return "HTTP violation";
-
-            } else if (mException instanceof IOException) {
-                return "Unrecovered transport exception";
-
-            } else if (mException instanceof AccountNotFoundException) {
-                Account failedAccount = ((AccountNotFoundException)mException).getFailedAccount();
-                return mException.getMessage() + " (" + (failedAccount != null ? failedAccount.name : "NULL") + ")";
-                
-            } else if (mException instanceof AccountsException) {
-                return "Exception while using account";
-                
-            } else {
-                return "Unexpected exception";
-            }
-        }
-
-        if (mCode == ResultCode.INSTANCE_NOT_CONFIGURED) {
-            return "The ownCloud server is not configured!";
-
-        } else if (mCode == ResultCode.NO_NETWORK_CONNECTION) {
-            return "No network connection";
-
-        } else if (mCode == ResultCode.BAD_OC_VERSION) {
-            return "No valid ownCloud version was found at the server";
-
-        } else if (mCode == ResultCode.LOCAL_STORAGE_FULL) {
-            return "Local storage full";
-
-        } else if (mCode == ResultCode.LOCAL_STORAGE_NOT_MOVED) {
-            return "Error while moving file to final directory";
-
-        } else if (mCode == ResultCode.ACCOUNT_NOT_NEW) {
-            return "Account already existing when creating a new one";
-
-        } else if (mCode == ResultCode.ACCOUNT_NOT_THE_SAME) {
-            return "Authenticated with a different account than the one updating";
-        }
-
-        return "Operation finished with HTTP status code " + mHttpCode + " (" + (isSuccess() ? "success" : "fail") + ")";
-
-    }
-
-    public boolean isServerFail() {
-        return (mHttpCode >= HttpStatus.SC_INTERNAL_SERVER_ERROR);
-    }
-
-    public boolean isException() {
-        return (mException != null);
-    }
-
-    public boolean isTemporalRedirection() {
-        return (mHttpCode == 302 || mHttpCode == 307);
-    }
-
-    public String getRedirectedLocation() {
-        return mRedirectedLocation;
-    }
-    
-    public boolean isIdPRedirection() {
-        return (mRedirectedLocation != null &&
-                (mRedirectedLocation.toUpperCase().contains("SAML") || 
-                mRedirectedLocation.toLowerCase().contains("wayf")));
-    }
-
-}
index 659037b..6bd4e8a 100644 (file)
@@ -1,5 +1,5 @@
 /* ownCloud Android client application
- *   Copyright (C) 2012-2013 ownCloud Inc.
+ *   Copyright (C) 2012-2014 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.operations;
 
-import org.apache.commons.httpclient.HttpStatus;
-import org.apache.jackrabbit.webdav.client.methods.DeleteMethod;
-
-import com.owncloud.android.Log_OC;
-import com.owncloud.android.datamodel.FileDataStorageManager;
 import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.lib.common.OwnCloudClient;
+import com.owncloud.android.lib.common.operations.RemoteOperationResult;
+import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;
+import com.owncloud.android.lib.resources.files.RemoveRemoteFileOperation;
+import com.owncloud.android.operations.common.SyncOperation;
 
 
-import eu.alefzero.webdav.WebdavClient;
-import eu.alefzero.webdav.WebdavUtils;
-
 /**
  * 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 RemoteOperation {
+public class RemoveFileOperation extends SyncOperation {
     
-    private static final String TAG = RemoveFileOperation.class.getSimpleName();
-
-    private static final int REMOVE_READ_TIMEOUT = 10000;
-    private static final int REMOVE_CONNECTION_TIMEOUT = 5000;
+    // private static final String TAG = RemoveFileOperation.class.getSimpleName();
     
     OCFile mFileToRemove;
-    boolean mDeleteLocalCopy;
-    FileDataStorageManager mDataStorageManager;
+    String mRemotePath;
+    boolean mOnlyLocalCopy;
     
     
     /**
      * Constructor
      * 
-     * @param fileToRemove          OCFile instance describing the remote file or folder to remove from the server
-     * @param deleteLocalCopy       When 'true', and a local copy of the file exists, it is also removed.
-     * @param storageManager        Reference to the local database corresponding to the account where the file is contained. 
+     * @param remotePath            RemotePath of the OCFile instance describing the remote file or 
+     *                              folder to remove from the server
+     * @param onlyLocalCopy         When 'true', and a local copy of the file exists, only this is 
+     *                              removed.
      */
-    public RemoveFileOperation(OCFile fileToRemove, boolean deleteLocalCopy, FileDataStorageManager storageManager) {
-        mFileToRemove = fileToRemove;
-        mDeleteLocalCopy = deleteLocalCopy;
-        mDataStorageManager = storageManager;
+    public RemoveFileOperation(String remotePath, boolean onlyLocalCopy) {
+        mRemotePath = remotePath;
+        mOnlyLocalCopy = onlyLocalCopy;
     }
     
     
@@ -68,34 +63,36 @@ public class RemoveFileOperation extends RemoteOperation {
         return mFileToRemove;
     }
     
-    
     /**
      * Performs the remove operation
      * 
      * @param   client      Client object to communicate with the remote ownCloud server.
      */
     @Override
-    protected RemoteOperationResult run(WebdavClient client) {
+    protected RemoteOperationResult run(OwnCloudClient client) {
         RemoteOperationResult result = null;
-        DeleteMethod delete = null;
-        try {
-            delete = new DeleteMethod(client.getBaseUri() + WebdavUtils.encodePath(mFileToRemove.getRemotePath()));
-            int status = client.executeMethod(delete, REMOVE_READ_TIMEOUT, REMOVE_CONNECTION_TIMEOUT);
-            if (delete.succeeded() || status == HttpStatus.SC_NOT_FOUND) {
-                mDataStorageManager.removeFile(mFileToRemove, true, mDeleteLocalCopy);
+        
+        mFileToRemove = getStorageManager().getFileByPath(mRemotePath);
+
+        boolean localRemovalFailed = false;
+        if (!mOnlyLocalCopy) {
+            RemoveRemoteFileOperation operation = new RemoveRemoteFileOperation(mRemotePath);
+            result = operation.execute(client);
+            if (result.isSuccess() || result.getCode() == ResultCode.FILE_NOT_FOUND) {
+                localRemovalFailed = !(getStorageManager().removeFile(mFileToRemove, true, true));
             }
-            delete.getResponseBodyAsString();   // exhaust the response, although not interesting
-            result = new RemoteOperationResult((delete.succeeded() || status == HttpStatus.SC_NOT_FOUND), status, delete.getResponseHeaders());
-            Log_OC.i(TAG, "Remove " + mFileToRemove.getRemotePath() + ": " + result.getLogMessage());
-            
-        } catch (Exception e) {
-            result = new RemoteOperationResult(e);
-            Log_OC.e(TAG, "Remove " + mFileToRemove.getRemotePath() + ": " + result.getLogMessage(), e);
             
-        } finally {
-            if (delete != null)
-                delete.releaseConnection();
+        } else {
+            localRemovalFailed = !(getStorageManager().removeFile(mFileToRemove, false, true));
+            if (!localRemovalFailed) {
+                result = new RemoteOperationResult(ResultCode.OK);
+            }
+        }
+        
+        if (localRemovalFailed) {
+            result = new RemoteOperationResult(ResultCode.LOCAL_STORAGE_NOT_REMOVED);
         }
+        
         return result;
     }
     
index a2370f3..95a5a9b 100644 (file)
@@ -1,5 +1,5 @@
 /* ownCloud Android client application
- *   Copyright (C) 2012-2013 ownCloud Inc.
+ *   Copyright (C) 2012-2014 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,55 +20,48 @@ package com.owncloud.android.operations;
 import java.io.File;
 import java.io.IOException;
 
-import org.apache.jackrabbit.webdav.client.methods.DavMethodBase;
-
-import com.owncloud.android.Log_OC;
-import com.owncloud.android.datamodel.FileDataStorageManager;
 import com.owncloud.android.datamodel.OCFile;
-import com.owncloud.android.operations.RemoteOperationResult.ResultCode;
+import com.owncloud.android.lib.common.OwnCloudClient;
+import com.owncloud.android.lib.common.operations.RemoteOperationResult;
+import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;
+import com.owncloud.android.lib.common.utils.Log_OC;
+import com.owncloud.android.lib.resources.files.RenameRemoteFileOperation;
+import com.owncloud.android.operations.common.SyncOperation;
 import com.owncloud.android.utils.FileStorageUtils;
-//import org.apache.jackrabbit.webdav.client.methods.MoveMethod;
 
 import android.accounts.Account;
 
 
-import eu.alefzero.webdav.WebdavClient;
-import eu.alefzero.webdav.WebdavUtils;
-
 /**
  * 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 RemoteOperation {
+public class RenameFileOperation extends SyncOperation {
     
     private static final String TAG = RenameFileOperation.class.getSimpleName();
-
-    private static final int RENAME_READ_TIMEOUT = 10000;
-    private static final int RENAME_CONNECTION_TIMEOUT = 5000;
     
-
     private OCFile mFile;
+    private String mRemotePath;
     private Account mAccount;
     private String mNewName;
     private String mNewRemotePath;
-    private FileDataStorageManager mStorageManager;
+
     
     
     /**
      * Constructor
      * 
-     * @param file                  OCFile instance describing the remote file or folder to rename
+     * @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.
-     * @param storageManager        Reference to the local database corresponding to the account where the file is contained. 
      */
-    public RenameFileOperation(OCFile file, Account account, String newName, FileDataStorageManager storageManager) {
-        mFile = file;
+    public RenameFileOperation(String remotePath, Account account, String newName) {
+        mRemotePath = remotePath;
         mAccount = account;
         mNewName = newName;
         mNewRemotePath = null;
-        mStorageManager = storageManager;
     }
   
     public OCFile getFile() {
@@ -82,78 +75,52 @@ public class RenameFileOperation extends RemoteOperation {
      * @param   client      Client object to communicate with the remote ownCloud server.
      */
     @Override
-    protected RemoteOperationResult run(WebdavClient client) {
+    protected RemoteOperationResult run(OwnCloudClient client) {
         RemoteOperationResult result = null;
         
-        LocalMoveMethod move = null;
-        mNewRemotePath = null;
+        mFile = getStorageManager().getFileByPath(mRemotePath);
+        
+        // check if the new name is valid in the local file system
         try {
-            if (mNewName.equals(mFile.getFileName())) {
-                return new RemoteOperationResult(ResultCode.OK);
+            if (!isValidNewName()) {
+                return new RemoteOperationResult(ResultCode.INVALID_LOCAL_FILE_NAME);
             }
-        
             String parent = (new File(mFile.getRemotePath())).getParent();
             parent = (parent.endsWith(OCFile.PATH_SEPARATOR)) ? parent : parent + OCFile.PATH_SEPARATOR; 
             mNewRemotePath =  parent + mNewName;
             if (mFile.isFolder()) {
                 mNewRemotePath += OCFile.PATH_SEPARATOR;
             }
-            
-            // check if the new name is valid in the local file system
-            if (!isValidNewName()) {
-                return new RemoteOperationResult(ResultCode.INVALID_LOCAL_FILE_NAME);
-            }
-        
-            // check if a file with the new name already exists
-            if (client.existsFile(mNewRemotePath) ||                             // remote check could fail by network failure. by indeterminate behavior of HEAD for folders ... 
-                    mStorageManager.getFileByPath(mNewRemotePath) != null) {     // ... so local check is convenient
+
+            // check local overwrite
+            if (getStorageManager().getFileByPath(mNewRemotePath) != null) {
                 return new RemoteOperationResult(ResultCode.INVALID_OVERWRITE);
             }
-            move = new LocalMoveMethod( client.getBaseUri() + WebdavUtils.encodePath(mFile.getRemotePath()),
-                                        client.getBaseUri() + WebdavUtils.encodePath(mNewRemotePath));
-            int status = client.executeMethod(move, RENAME_READ_TIMEOUT, RENAME_CONNECTION_TIMEOUT);
-            if (move.succeeded()) {
+            
+            RenameRemoteFileOperation operation = new RenameRemoteFileOperation(mFile.getFileName(), mFile.getRemotePath(), 
+                    mNewName, mFile.isFolder());
+            result = operation.execute(client);
 
+            if (result.isSuccess()) {
                 if (mFile.isFolder()) {
                     saveLocalDirectory();
-                    
+
                 } else {
                     saveLocalFile();
-                    
                 }
-             
-            /* 
-             *} else if (mFile.isDirectory() && (status == 207 || status >= 500)) {
-             *   // TODO 
-             *   // if server fails in the rename of a folder, some children files could have been moved to a folder with the new name while some others
-             *   // stayed in the old folder;
-             *   //
-             *   // easiest and heaviest solution is synchronizing the parent folder (or the full account);
-             *   //
-             *   // a better solution is synchronizing the folders with the old and new names;
-             *}
-             */
-                
             }
             
-            move.getResponseBodyAsString(); // exhaust response, although not interesting
-            result = new RemoteOperationResult(move.succeeded(), status, move.getResponseHeaders());
-            Log_OC.i(TAG, "Rename " + mFile.getRemotePath() + " to " + mNewRemotePath + ": " + result.getLogMessage());
-            
-        } catch (Exception e) {
-            result = new RemoteOperationResult(e);
-            Log_OC.e(TAG, "Rename " + mFile.getRemotePath() + " to " + ((mNewRemotePath==null) ? mNewName : mNewRemotePath) + ": " + result.getLogMessage(), e);
-            
-        } finally {
-            if (move != null)
-                move.releaseConnection();
+        } catch (IOException e) {
+            Log_OC.e(TAG, "Rename " + mFile.getRemotePath() + " to " + ((mNewRemotePath==null) ? mNewName : mNewRemotePath) + ": " + 
+                    ((result!= null) ? result.getLogMessage() : ""), e);
         }
+
         return result;
     }
 
     
     private void saveLocalDirectory() {
-        mStorageManager.moveFolder(mFile, mNewRemotePath);
+        getStorageManager().moveFolder(mFile, mNewRemotePath);
         String localPath = FileStorageUtils.getDefaultSavePathFor(mAccount.name, mFile);
         File localDir = new File(localPath);
         if (localDir.exists()) {
@@ -178,7 +145,7 @@ public class RenameFileOperation extends RemoteOperation {
             // TODO - study conditions when this could be a problem
         }
         
-        mStorageManager.saveFile(mFile);
+        getStorageManager().saveFile(mFile);
     }
 
     /**
@@ -223,26 +190,4 @@ public class RenameFileOperation extends RemoteOperation {
         return result;
     }
 
-
-    // move operation
-    private class LocalMoveMethod extends DavMethodBase {
-
-        public LocalMoveMethod(String uri, String dest) {
-            super(uri);
-            addRequestHeader(new org.apache.commons.httpclient.Header("Destination", dest));
-        }
-
-        @Override
-        public String getName() {
-            return "MOVE";
-        }
-
-        @Override
-        protected boolean isSuccess(int status) {
-            return status == 201 || status == 204;
-        }
-            
-    }
-    
-
 }
index 2e15c2f..45a7305 100644 (file)
@@ -1,6 +1,6 @@
 /* ownCloud Android client application
  *   Copyright (C) 2012 Bartek Przybylski
- *   Copyright (C) 2012-2013 ownCloud Inc.
+ *   Copyright (C) 2012-2014 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.operations;
 
-import org.apache.http.HttpStatus;
-import org.apache.jackrabbit.webdav.DavConstants;
-import org.apache.jackrabbit.webdav.MultiStatus;
-import org.apache.jackrabbit.webdav.client.methods.PropFindMethod;
-
-import com.owncloud.android.Log_OC;
-import com.owncloud.android.datamodel.FileDataStorageManager;
 import com.owncloud.android.datamodel.OCFile;
 import com.owncloud.android.files.services.FileDownloader;
 import com.owncloud.android.files.services.FileUploader;
-import com.owncloud.android.operations.RemoteOperationResult.ResultCode;
+import com.owncloud.android.lib.common.OwnCloudClient;
+import com.owncloud.android.lib.resources.files.RemoteFile;
+import com.owncloud.android.lib.common.operations.RemoteOperationResult;
+import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;
+import com.owncloud.android.lib.common.utils.Log_OC;
+import com.owncloud.android.lib.resources.files.ReadRemoteFileOperation;
+import com.owncloud.android.operations.common.SyncOperation;
+import com.owncloud.android.utils.FileStorageUtils;
 
 import android.accounts.Account;
 import android.content.Context;
 import android.content.Intent;
 
+/**
+ * Remote operation performing the read of remote file in the ownCloud server.
+ * 
+ * @author David A. Velasco
+ * @author masensio
+ */
 
-import eu.alefzero.webdav.WebdavClient;
-import eu.alefzero.webdav.WebdavEntry;
-import eu.alefzero.webdav.WebdavUtils;
-
-public class SynchronizeFileOperation extends RemoteOperation {
+public class SynchronizeFileOperation extends SyncOperation {
 
     private String TAG = SynchronizeFileOperation.class.getSimpleName();
-    private static final int SYNC_READ_TIMEOUT = 10000;
-    private static final int SYNC_CONNECTION_TIMEOUT = 5000;
     
     private OCFile mLocalFile;
+    private String mRemotePath;
     private OCFile mServerFile;
-    private FileDataStorageManager mStorageManager;
     private Account mAccount;
     private boolean mSyncFileContents;
     private Context mContext;
     
     private boolean mTransferWasRequested = false;
+
+    
+    /**
+     * Constructor.
+     * 
+     * Uses remotePath to retrieve all the data in local cache and remote server when the operation
+     * is executed, instead of reusing {@link OCFile} instances.
+     * 
+     * @param 
+     * @param account               ownCloud account holding the file.
+     * @param syncFileContents      When 'true', transference of data will be started by the 
+     *                              operation if needed and no conflict is detected.
+     * @param context               Android context; needed to start transfers.
+     */
+    public SynchronizeFileOperation(
+            String remotePath,  
+            Account account, 
+            boolean syncFileContents,
+            Context context) {
+        
+        mRemotePath = remotePath;
+        mLocalFile = null;
+        mServerFile = null;
+        mAccount = account;
+        mSyncFileContents = syncFileContents;
+        mContext = context;
+    }
+
     
+    /**
+     * Constructor allowing to reuse {@link OCFile} instances just queried from cache or network.
+     * 
+     * Useful for folder / account synchronizations.
+     * 
+     * @param localFile             Data of file currently hold in device cache. MUSTN't be null.
+     * @param serverFile            Data of file just retrieved from network. If null, will be
+     *                              retrieved from network by the operation when executed.
+     * @param account               ownCloud account holding the file.
+     * @param syncFileContents      When 'true', transference of data will be started by the 
+     *                              operation if needed and no conflict is detected.
+     * @param context               Android context; needed to start transfers.
+     */
     public SynchronizeFileOperation(
             OCFile localFile,
-            OCFile serverFile,          // make this null to let the operation checks the server; added to reuse info from SynchronizeFolderOperation 
-            FileDataStorageManager storageManager, 
+            OCFile serverFile, 
             Account account, 
             boolean syncFileContents,
             Context context) {
         
         mLocalFile = localFile;
         mServerFile = serverFile;
-        mStorageManager = storageManager;
+        mRemotePath = localFile.getRemotePath();
         mAccount = account;
         mSyncFileContents = syncFileContents;
         mContext = context;
     }
-
+    
 
     @Override
-    protected RemoteOperationResult run(WebdavClient client) {
-        
-        PropFindMethod propfind = null;
+    protected RemoteOperationResult run(OwnCloudClient client) {
+
         RemoteOperationResult result = null;
         mTransferWasRequested = false;
-        try {
-            if (!mLocalFile.isDown()) {
-                /// easy decision
-                requestForDownload(mLocalFile);
-                result = new RemoteOperationResult(ResultCode.OK);
-                
-            } else {
-                /// local copy in the device -> need to think a bit more before do anything
-                
-                if (mServerFile == null) {
-                    /// take the duty of check the server for the current state of the file there
-                    propfind = new PropFindMethod(client.getBaseUri() + WebdavUtils.encodePath(mLocalFile.getRemotePath()),
-                            DavConstants.PROPFIND_ALL_PROP,
-                            DavConstants.DEPTH_0);
-                    int status = client.executeMethod(propfind, SYNC_READ_TIMEOUT, SYNC_CONNECTION_TIMEOUT);
-                    boolean isMultiStatus = status == HttpStatus.SC_MULTI_STATUS;
-                    if (isMultiStatus) {
-                        MultiStatus resp = propfind.getResponseBodyAsMultiStatus();
-                        WebdavEntry we = new WebdavEntry(resp.getResponses()[0],
-                                               client.getBaseUri().getPath());
-                        mServerFile = fillOCFile(we);
-                        mServerFile.setLastSyncDateForProperties(System.currentTimeMillis());
-                        
-                    } else {
-                        client.exhaustResponse(propfind.getResponseBodyAsStream());
-                        result = new RemoteOperationResult(false, status, propfind.getResponseHeaders());
-                    }
+        
+        if (mLocalFile == null) {
+            // Get local file from the DB
+            mLocalFile = getStorageManager().getFileByPath(mRemotePath);
+        }
+        
+        if (!mLocalFile.isDown()) {
+            /// easy decision
+            requestForDownload(mLocalFile);
+            result = new RemoteOperationResult(ResultCode.OK);
+
+        } else {
+            /// local copy in the device -> need to think a bit more before do anything
+
+            if (mServerFile == null) {
+                ReadRemoteFileOperation operation = new ReadRemoteFileOperation(mRemotePath);
+                result = operation.execute(client);
+                if (result.isSuccess()){
+                    mServerFile = FileStorageUtils.fillOCFile((RemoteFile) result.getData().get(0));
+                    mServerFile.setLastSyncDateForProperties(System.currentTimeMillis());
                 }
-                
-                if (result == null) {   // true if the server was not checked. nothing was wrong with the remote request
-              
-                    /// check changes in server and local file
-                    boolean serverChanged = false;
-                    /* time for eTag is coming, but not yet
+            }
+
+            if (mServerFile != null) {   
+
+                /// check changes in server and local file
+                boolean serverChanged = false;
+                /* time for eTag is coming, but not yet
                     if (mServerFile.getEtag() != null) {
                         serverChanged = (!mServerFile.getEtag().equals(mLocalFile.getEtag()));   // TODO could this be dangerous when the user upgrades the server from non-tagged to tagged?
                     } else { */
-                        // server without etags
-                        serverChanged = (mServerFile.getModificationTimestamp() > mLocalFile.getModificationTimestampAtLastSyncForData());
-                    //}
-                    boolean localChanged = (mLocalFile.getLocalModificationTimestamp() > mLocalFile.getLastSyncDateForData());
-                        // TODO this will be always true after the app is upgraded to database version 2; will result in unnecessary uploads
-              
-                    /// decide action to perform depending upon changes
-                    //if (!mLocalFile.getEtag().isEmpty() && localChanged && serverChanged) {
-                    if (localChanged && serverChanged) {
-                        result = new RemoteOperationResult(ResultCode.SYNC_CONFLICT);
-                  
-                    } else if (localChanged) {
-                        if (mSyncFileContents) {
-                            requestForUpload(mLocalFile);
-                            // the local update of file properties will be done by the FileUploader service when the upload finishes
-                        } else {
-                            // NOTHING TO DO HERE: updating the properties of the file in the server without uploading the contents would be stupid; 
-                            // So, an instance of SynchronizeFileOperation created with syncFileContents == false is completely useless when we suspect
-                            // that an upload is necessary (for instance, in FileObserverService).
-                        }
-                        result = new RemoteOperationResult(ResultCode.OK);
-                  
-                    } else if (serverChanged) {
-                        if (mSyncFileContents) {
-                            requestForDownload(mLocalFile); // local, not server; we won't to keep the value of keepInSync!
-                            // the update of local data will be done later by the FileUploader service when the upload finishes
-                        } else {
-                            // TODO CHECK: is this really useful in some point in the code?
-                            mServerFile.setKeepInSync(mLocalFile.keepInSync());
-                            mServerFile.setLastSyncDateForData(mLocalFile.getLastSyncDateForData());
-                            mServerFile.setStoragePath(mLocalFile.getStoragePath());
-                            mServerFile.setParentId(mLocalFile.getParentId());
-                            mStorageManager.saveFile(mServerFile);
-                            
-                        }
-                        result = new RemoteOperationResult(ResultCode.OK);
-              
+                // server without etags
+                serverChanged = (mServerFile.getModificationTimestamp() != mLocalFile.getModificationTimestampAtLastSyncForData());
+                //}
+                boolean localChanged = (mLocalFile.getLocalModificationTimestamp() > mLocalFile.getLastSyncDateForData());
+                // TODO this will be always true after the app is upgraded to database version 2; will result in unnecessary uploads
+
+                /// decide action to perform depending upon changes
+                //if (!mLocalFile.getEtag().isEmpty() && localChanged && serverChanged) {
+                if (localChanged && serverChanged) {
+                    result = new RemoteOperationResult(ResultCode.SYNC_CONFLICT);
+
+                } else if (localChanged) {
+                    if (mSyncFileContents) {
+                        requestForUpload(mLocalFile);
+                        // the local update of file properties will be done by the FileUploader service when the upload finishes
                     } else {
-                        // nothing changed, nothing to do
-                        result = new RemoteOperationResult(ResultCode.OK);
+                        // NOTHING TO DO HERE: updating the properties of the file in the server without uploading the contents would be stupid; 
+                        // So, an instance of SynchronizeFileOperation created with syncFileContents == false is completely useless when we suspect
+                        // that an upload is necessary (for instance, in FileObserverService).
                     }
-              
-                } 
-          
-            }
-            
-            Log_OC.i(TAG, "Synchronizing " + mAccount.name + ", file " + mLocalFile.getRemotePath() + ": " + result.getLogMessage());
-          
-        } catch (Exception e) {
-            result = new RemoteOperationResult(e);
-            Log_OC.e(TAG, "Synchronizing " + mAccount.name + ", file " + (mLocalFile != null ? mLocalFile.getRemotePath() : "NULL") + ": " + result.getLogMessage(), result.getException());
-
-        } finally {
-            if (propfind != null)
-                propfind.releaseConnection();
+                    result = new RemoteOperationResult(ResultCode.OK);
+
+                } else if (serverChanged) {
+                    mLocalFile.setRemoteId(mServerFile.getRemoteId());
+                    
+                    if (mSyncFileContents) {
+                        requestForDownload(mLocalFile); // local, not server; we won't to keep the value of keepInSync!
+                        // the update of local data will be done later by the FileUploader service when the upload finishes
+                    } else {
+                        // TODO CHECK: is this really useful in some point in the code?
+                        mServerFile.setKeepInSync(mLocalFile.keepInSync());
+                        mServerFile.setLastSyncDateForData(mLocalFile.getLastSyncDateForData());
+                        mServerFile.setStoragePath(mLocalFile.getStoragePath());
+                        mServerFile.setParentId(mLocalFile.getParentId());
+                        getStorageManager().saveFile(mServerFile);
+
+                    }
+                    result = new RemoteOperationResult(ResultCode.OK);
+
+                } else {
+                    // nothing changed, nothing to do
+                    result = new RemoteOperationResult(ResultCode.OK);
+                }
+
+            } 
+
         }
+
+        Log_OC.i(TAG, "Synchronizing " + mAccount.name + ", file " + mLocalFile.getRemotePath() + ": " + result.getLogMessage());
+
         return result;
     }
 
@@ -206,24 +233,6 @@ public class SynchronizeFileOperation extends RemoteOperation {
     }
 
 
-    /**
-     * Creates and populates a new {@link OCFile} object with the data read from the server.
-     * 
-     * @param we        WebDAV entry read from the server for a WebDAV resource (remote file or folder).
-     * @return          New OCFile instance representing the remote resource described by we.
-     */
-    private OCFile fillOCFile(WebdavEntry we) {
-        OCFile file = new OCFile(we.decodedPath());
-        file.setCreationTimestamp(we.createTimestamp());
-        file.setFileLength(we.contentLength());
-        file.setMimetype(we.contentType());
-        file.setModificationTimestamp(we.modifiedTimestamp());
-        file.setEtag(we.etag());
-        
-        return file;
-    }
-
-
     public boolean transferWasRequested() {
         return mTransferWasRequested;
     }
index 09683d6..cdf1282 100644 (file)
@@ -1,5 +1,5 @@
 /* ownCloud Android client application
- *   Copyright (C) 2012-2013 ownCloud Inc.
+ *   Copyright (C) 2012-2014 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,30 +23,36 @@ import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Vector;
 
 import org.apache.http.HttpStatus;
-import org.apache.jackrabbit.webdav.DavConstants;
-import org.apache.jackrabbit.webdav.MultiStatus;
-import org.apache.jackrabbit.webdav.client.methods.PropFindMethod;
-
 import android.accounts.Account;
 import android.content.Context;
 import android.content.Intent;
+//import android.support.v4.content.LocalBroadcastManager;
 
-import com.owncloud.android.Log_OC;
 import com.owncloud.android.datamodel.FileDataStorageManager;
 import com.owncloud.android.datamodel.OCFile;
-import com.owncloud.android.operations.RemoteOperationResult.ResultCode;
-import com.owncloud.android.syncadapter.FileSyncService;
+
+import com.owncloud.android.lib.common.OwnCloudClient;
+import com.owncloud.android.lib.resources.shares.OCShare;
+import com.owncloud.android.lib.common.operations.RemoteOperation;
+import com.owncloud.android.lib.common.operations.RemoteOperationResult;
+import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;
+import com.owncloud.android.lib.common.utils.Log_OC;
+import com.owncloud.android.lib.resources.shares.GetRemoteSharesForFileOperation;
+import com.owncloud.android.lib.resources.files.FileUtils;
+import com.owncloud.android.lib.resources.files.ReadRemoteFileOperation;
+import com.owncloud.android.lib.resources.files.ReadRemoteFolderOperation;
+import com.owncloud.android.lib.resources.files.RemoteFile;
+
+import com.owncloud.android.syncadapter.FileSyncAdapter;
 import com.owncloud.android.utils.FileStorageUtils;
 
-import eu.alefzero.webdav.WebdavClient;
-import eu.alefzero.webdav.WebdavEntry;
-import eu.alefzero.webdav.WebdavUtils;
 
 
 /**
@@ -64,6 +70,10 @@ public class SynchronizeFolderOperation extends RemoteOperation {
 
     private static final String TAG = SynchronizeFolderOperation.class.getSimpleName();
 
+    public static final String EVENT_SINGLE_FOLDER_CONTENTS_SYNCED  = 
+            SynchronizeFolderOperation.class.getName() + ".EVENT_SINGLE_FOLDER_CONTENTS_SYNCED";
+    public static final String EVENT_SINGLE_FOLDER_SHARES_SYNCED    = 
+            SynchronizeFolderOperation.class.getName() + ".EVENT_SINGLE_FOLDER_SHARES_SYNCED";
     
     /** Time stamp for the synchronization process in progress */
     private long mCurrentSyncTime;
@@ -89,24 +99,36 @@ public class SynchronizeFolderOperation extends RemoteOperation {
     /** Counter of failed operations in synchronization of kept-in-sync files */
     private int mFailsInFavouritesFound;
 
-    /** Map of remote and local paths to files that where locally stored in a location out of the ownCloud folder and couldn't be copied automatically into it */
+    /**
+     * Map of remote and local paths to files that where locally stored in a location 
+     * out of the ownCloud folder and couldn't be copied automatically into it 
+     **/
     private Map<String, String> mForgottenLocalFiles;
 
     /** 'True' means that this operation is part of a full account synchronization */ 
     private boolean mSyncFullAccount;
 
-    /** 'True' means that the remote folder changed from last synchronization and should be fetched */
-    private boolean mRemoteFolderChanged;
+    /** 'True' means that Share resources bound to the files into should be refreshed also */
+    private boolean mIsShareSupported;
     
+    /** 'True' means that the remote folder changed and should be fetched */
+    private boolean mRemoteFolderChanged;
+
+    /** 'True' means that Etag will be ignored */
+    private boolean mIgnoreETag;
+
     
     /**
      * Creates a new instance of {@link SynchronizeFolderOperation}.
      * 
-     * @param   remoteFolderPath        Remote folder to synchronize.
+     * @param   folder                  Folder to synchronize.
      * @param   currentSyncTime         Time stamp for the synchronization process in progress.
-     * @param   localFolderId           Identifier in the local database of the folder to synchronize.
-     * @param   updateFolderProperties  'True' means that the properties of the folder should be updated also, not just its content.
-     * @param   syncFullAccount         'True' means that this operation is part of a full account synchronization.
+     * @param   syncFullAccount         'True' means that this operation is part of a full account 
+     *                                  synchronization.
+     * @param   isShareSupported        'True' means that the server supports the sharing API.           
+     * @param   ignoreEtag              'True' means that the content of the remote folder should
+     *                                  be fetched and updated even though the 'eTag' did not 
+     *                                  change.  
      * @param   dataStorageManager      Interface with the local database.
      * @param   account                 ownCloud account where the folder is located. 
      * @param   context                 Application context.
@@ -114,17 +136,21 @@ public class SynchronizeFolderOperation extends RemoteOperation {
     public SynchronizeFolderOperation(  OCFile folder, 
                                         long currentSyncTime, 
                                         boolean syncFullAccount,
+                                        boolean isShareSupported,
+                                        boolean ignoreETag,
                                         FileDataStorageManager dataStorageManager, 
                                         Account account, 
                                         Context context ) {
         mLocalFolder = folder;
         mCurrentSyncTime = currentSyncTime;
         mSyncFullAccount = syncFullAccount;
+        mIsShareSupported = isShareSupported;
         mStorageManager = dataStorageManager;
         mAccount = account;
         mContext = context;
         mForgottenLocalFiles = new HashMap<String, String>();
         mRemoteFolderChanged = false;
+        mIgnoreETag = ignoreETag;
     }
     
     
@@ -141,7 +167,8 @@ public class SynchronizeFolderOperation extends RemoteOperation {
     }
     
     /**
-     * Returns the list of files and folders contained in the synchronized folder, if called after synchronization is complete.
+     * Returns the list of files and folders contained in the synchronized folder, 
+     * if called after synchronization is complete.
      * 
      * @return  List of files and folders contained in the synchronized folder.
      */
@@ -155,12 +182,16 @@ public class SynchronizeFolderOperation extends RemoteOperation {
      * {@inheritDoc}
      */
     @Override
-    protected RemoteOperationResult run(WebdavClient client) {
+    protected RemoteOperationResult run(OwnCloudClient client) {
         RemoteOperationResult result = null;
         mFailsInFavouritesFound = 0;
         mConflictsFound = 0;
         mForgottenLocalFiles.clear();
         
+        if (FileUtils.PATH_SEPARATOR.equals(mLocalFolder.getRemotePath()) && !mSyncFullAccount) {
+            updateOCVersion(client);
+        }
+        
         result = checkForChanges(client);
         
         if (result.isSuccess()) {
@@ -172,130 +203,109 @@ public class SynchronizeFolderOperation extends RemoteOperation {
         }
         
         if (!mSyncFullAccount) {            
-            sendStickyBroadcast(false, mLocalFolder.getRemotePath(), result);
+            sendLocalBroadcast(
+                    EVENT_SINGLE_FOLDER_CONTENTS_SYNCED, mLocalFolder.getRemotePath(), result
+            );
         }
-
+        
+        if (result.isSuccess() && mIsShareSupported && !mSyncFullAccount) {
+            refreshSharesForFolder(client); // share result is ignored 
+        }
+        
+        if (!mSyncFullAccount) {            
+            sendLocalBroadcast(
+                    EVENT_SINGLE_FOLDER_SHARES_SYNCED, mLocalFolder.getRemotePath(), result
+            );
+        }
+        
         return result;
         
     }
 
 
-    private RemoteOperationResult checkForChanges(WebdavClient client) {
-        mRemoteFolderChanged = false;
+    private void updateOCVersion(OwnCloudClient client) {
+        UpdateOCVersionOperation update = new UpdateOCVersionOperation(mAccount, mContext);
+        RemoteOperationResult result = update.execute(client);
+        if (result.isSuccess()) {
+            mIsShareSupported = update.getOCVersion().isSharedSupported();
+        }
+    }
+
+    
+    private RemoteOperationResult checkForChanges(OwnCloudClient client) {
+        mRemoteFolderChanged = true;
         RemoteOperationResult result = null;
         String remotePath = null;
-        PropFindMethod query = null;
+
+        remotePath = mLocalFolder.getRemotePath();
+        Log_OC.d(TAG, "Checking changes in " + mAccount.name + remotePath);
         
-        try {
-            remotePath = mLocalFolder.getRemotePath();
-            Log_OC.d(TAG, "Checking changes in " + mAccount.name + remotePath);
-
-            // remote request 
-            query = new PropFindMethod(client.getBaseUri() + WebdavUtils.encodePath(remotePath),
-                    DavConstants.PROPFIND_ALL_PROP,
-                    DavConstants.DEPTH_0);
-            int status = client.executeMethod(query);
-
-            // check and process response
-            if (isMultiStatus(status)) {
-                // parse data from remote folder 
-                WebdavEntry we = new WebdavEntry(query.getResponseBodyAsMultiStatus().getResponses()[0], client.getBaseUri().getPath());
-                OCFile remoteFolder = fillOCFile(we);
-                
+        // remote request 
+        ReadRemoteFileOperation operation = new ReadRemoteFileOperation(remotePath);
+        result = operation.execute(client);
+        if (result.isSuccess()){
+            OCFile remoteFolder = FileStorageUtils.fillOCFile((RemoteFile) result.getData().get(0));
+
+            if (!mIgnoreETag) {
                 // check if remote and local folder are different
-                mRemoteFolderChanged = !(remoteFolder.getEtag().equalsIgnoreCase(mLocalFolder.getEtag()));
-                
-                result = new RemoteOperationResult(ResultCode.OK);
-                
-            } else {
-                // check failed
-                client.exhaustResponse(query.getResponseBodyAsStream());
-                if (status == HttpStatus.SC_NOT_FOUND) {
-                    removeLocalFolder();
-                }
-                result = new RemoteOperationResult(false, status, query.getResponseHeaders());
+                mRemoteFolderChanged = 
+                        !(remoteFolder.getEtag().equalsIgnoreCase(mLocalFolder.getEtag()));
             }
 
-        } catch (Exception e) {
-            result = new RemoteOperationResult(e);
+            result = new RemoteOperationResult(ResultCode.OK);
+        
+            Log_OC.i(TAG, "Checked " + mAccount.name + remotePath + " : " + 
+                    (mRemoteFolderChanged ? "changed" : "not changed"));
             
-
-        } finally {
-            if (query != null)
-                query.releaseConnection();  // let the connection available for other methods
-            if (result.isSuccess()) {
-                Log_OC.i(TAG, "Checked " + mAccount.name + remotePath + " : " + (mRemoteFolderChanged ? "changed" : "not changed"));
+        } else {
+            // check failed
+            if (result.getCode() == ResultCode.FILE_NOT_FOUND) {
+                removeLocalFolder();
+            }
+            if (result.isException()) {
+                Log_OC.e(TAG, "Checked " + mAccount.name + remotePath  + " : " + 
+                        result.getLogMessage(), result.getException());
             } else {
-                if (result.isException()) {
-                    Log_OC.e(TAG, "Checked " + mAccount.name + remotePath  + " : " + result.getLogMessage(), result.getException());
-                } else {
-                    Log_OC.e(TAG, "Checked " + mAccount.name + remotePath + " : " + result.getLogMessage());
-                }
+                Log_OC.e(TAG, "Checked " + mAccount.name + remotePath + " : " + 
+                        result.getLogMessage());
             }
-            
         }
+        
         return result;
     }
 
 
-    private RemoteOperationResult fetchAndSyncRemoteFolder(WebdavClient client) {
-        RemoteOperationResult result = null;
-        String remotePath = null;
-        PropFindMethod query = null;
-        try {
-            remotePath = mLocalFolder.getRemotePath();
-            Log_OC.d(TAG, "Synchronizing " + mAccount.name + remotePath);
-
-            // remote request 
-            query = new PropFindMethod(client.getBaseUri() + WebdavUtils.encodePath(remotePath),
-                    DavConstants.PROPFIND_ALL_PROP,
-                    DavConstants.DEPTH_1);
-            int status = client.executeMethod(query);
-
-            // check and process response
-            if (isMultiStatus(status)) {
-                synchronizeData(query.getResponseBodyAsMultiStatus(), client);
-                if (mConflictsFound > 0  || mFailsInFavouritesFound > 0) { 
-                    result = new RemoteOperationResult(ResultCode.SYNC_CONFLICT);   // should be different result, but will do the job
-                } else {
-                    result = new RemoteOperationResult(true, status, query.getResponseHeaders());
-                }
-                
-            } else {
-                // synchronization failed
-                client.exhaustResponse(query.getResponseBodyAsStream());
-                if (status == HttpStatus.SC_NOT_FOUND) {
-                    removeLocalFolder();
-                }
-                result = new RemoteOperationResult(false, status, query.getResponseHeaders());
-            }
-
-        } catch (Exception e) {
-            result = new RemoteOperationResult(e);
-            
-
-        } finally {
-            if (query != null)
-                query.releaseConnection();  // let the connection available for other methods
-            if (result.isSuccess()) {
-                Log_OC.i(TAG, "Synchronized " + mAccount.name + remotePath + ": " + result.getLogMessage());
-            } else {
-                if (result.isException()) {
-                    Log_OC.e(TAG, "Synchronized " + mAccount.name + remotePath  + ": " + result.getLogMessage(), result.getException());
-                } else {
-                    Log_OC.e(TAG, "Synchronized " + mAccount.name + remotePath + ": " + result.getLogMessage());
-                }
+    private RemoteOperationResult fetchAndSyncRemoteFolder(OwnCloudClient client) {
+        String remotePath = mLocalFolder.getRemotePath();
+        ReadRemoteFolderOperation operation = new ReadRemoteFolderOperation(remotePath);
+        RemoteOperationResult result = operation.execute(client);
+        Log_OC.d(TAG, "Synchronizing " + mAccount.name + remotePath);
+        
+        if (result.isSuccess()) {
+            synchronizeData(result.getData(), client);
+            if (mConflictsFound > 0  || mFailsInFavouritesFound > 0) { 
+                result = new RemoteOperationResult(ResultCode.SYNC_CONFLICT);   
+                    // should be a different result code, but will do the job
             }
-            
+        } else {
+            if (result.getCode() == ResultCode.FILE_NOT_FOUND)
+                removeLocalFolder();
         }
+        
         return result;
     }
 
-
+    
     private void removeLocalFolder() {
         if (mStorageManager.fileExists(mLocalFolder.getFileId())) {
             String currentSavePath = FileStorageUtils.getSavePath(mAccount.name);
-            mStorageManager.removeFolder(mLocalFolder, true, (mLocalFolder.isDown() && mLocalFolder.getStoragePath().startsWith(currentSavePath)));
+            mStorageManager.removeFolder(
+                    mLocalFolder, 
+                    true, 
+                    (   mLocalFolder.isDown() && 
+                            mLocalFolder.getStoragePath().startsWith(currentSavePath)
+                    )
+            );
         }
     }
 
@@ -305,26 +315,26 @@ public class SynchronizeFolderOperation extends RemoteOperation {
      *  with the current data in the local database.
      *  
      *  Grants that mChildren is updated with fresh data after execution.
-     * 
-     *  @param dataInServer     Full response got from the server with the data of the target 
-     *                          folder and its direct children.
+     *  
+     *  @param folderAndFiles   Remote folder and children files in Folder 
+     *  
      *  @param client           Client instance to the remote server where the data were 
      *                          retrieved.  
-     *  @return                 'True' when any change was made in the local data, 'false' otherwise.
+     *  @return                 'True' when any change was made in the local data, 'false' otherwise
      */
-    private void synchronizeData(MultiStatus dataInServer, WebdavClient client) {
+    private void synchronizeData(ArrayList<Object> folderAndFiles, OwnCloudClient client) {
         // get 'fresh data' from the database
         mLocalFolder = mStorageManager.getFileByPath(mLocalFolder.getRemotePath());
         
         // parse data from remote folder 
-        WebdavEntry we = new WebdavEntry(dataInServer.getResponses()[0], client.getBaseUri().getPath());
-        OCFile remoteFolder = fillOCFile(we);
+        OCFile remoteFolder = fillOCFile((RemoteFile)folderAndFiles.get(0));
         remoteFolder.setParentId(mLocalFolder.getParentId());
         remoteFolder.setFileId(mLocalFolder.getFileId());
         
-        Log_OC.d(TAG, "Remote folder " + mLocalFolder.getRemotePath() + " changed - starting update of local data ");
+        Log_OC.d(TAG, "Remote folder " + mLocalFolder.getRemotePath() 
+                + " changed - starting update of local data ");
         
-        List<OCFile> updatedFiles = new Vector<OCFile>(dataInServer.getResponses().length - 1);
+        List<OCFile> updatedFiles = new Vector<OCFile>(folderAndFiles.size() - 1);
         List<SynchronizeFileOperation> filesToSyncContents = new Vector<SynchronizeFileOperation>();
 
         // get current data about local contents of the folder to synchronize
@@ -336,89 +346,97 @@ public class SynchronizeFolderOperation extends RemoteOperation {
         
         // loop to update every child
         OCFile remoteFile = null, localFile = null;
-        for (int i = 1; i < dataInServer.getResponses().length; ++i) {
+        for (int i=1; i<folderAndFiles.size(); i++) {
             /// new OCFile instance with the data from the server
-            we = new WebdavEntry(dataInServer.getResponses()[i], client.getBaseUri().getPath());                        
-            remoteFile = fillOCFile(we);
+            remoteFile = fillOCFile((RemoteFile)folderAndFiles.get(i));
             remoteFile.setParentId(mLocalFolder.getFileId());
 
             /// retrieve local data for the read file 
-            //localFile = mStorageManager.getFileByPath(remoteFile.getRemotePath());
+            //  localFile = mStorageManager.getFileByPath(remoteFile.getRemotePath());
             localFile = localFilesMap.remove(remoteFile.getRemotePath());
             
-            /// add to the remoteFile (the new one) data about LOCAL STATE (not existing in the server side)
+            /// add to the remoteFile (the new one) data about LOCAL STATE (not existing in server)
             remoteFile.setLastSyncDateForProperties(mCurrentSyncTime);
             if (localFile != null) {
                 // some properties of local state are kept unmodified
                 remoteFile.setFileId(localFile.getFileId());
                 remoteFile.setKeepInSync(localFile.keepInSync());
                 remoteFile.setLastSyncDateForData(localFile.getLastSyncDateForData());
-                remoteFile.setModificationTimestampAtLastSyncForData(localFile.getModificationTimestampAtLastSyncForData());
+                remoteFile.setModificationTimestampAtLastSyncForData(
+                        localFile.getModificationTimestampAtLastSyncForData()
+                );
                 remoteFile.setStoragePath(localFile.getStoragePath());
-                remoteFile.setEtag(localFile.getEtag());    // eTag will not be updated unless contents are synchronized (Synchronize[File|Folder]Operation with remoteFile as parameter)
+                // eTag will not be updated unless contents are synchronized 
+                //  (Synchronize[File|Folder]Operation with remoteFile as parameter)
+                remoteFile.setEtag(localFile.getEtag());    
                 if (remoteFile.isFolder()) {
-                    remoteFile.setFileLength(localFile.getFileLength()); // TODO move operations about size of folders to FileContentProvider
+                    remoteFile.setFileLength(localFile.getFileLength()); 
+                        // TODO move operations about size of folders to FileContentProvider
                 }
+                remoteFile.setPublicLink(localFile.getPublicLink());
+                remoteFile.setShareByLink(localFile.isShareByLink());
             } else {
-                remoteFile.setEtag(""); // remote eTag will not be updated unless contents are synchronized (Synchronize[File|Folder]Operation with remoteFile as parameter)
+                // remote eTag will not be updated unless contents are synchronized 
+                //  (Synchronize[File|Folder]Operation with remoteFile as parameter)
+                remoteFile.setEtag(""); 
             }
 
             /// check and fix, if needed, local storage path
-            checkAndFixForeignStoragePath(remoteFile);      // fixing old policy - now local files must be copied into the ownCloud local folder 
+            checkAndFixForeignStoragePath(remoteFile);      // policy - local files are COPIED 
+                                                            // into the ownCloud local folder;
             searchForLocalFileInDefaultPath(remoteFile);    // legacy   
 
             /// prepare content synchronization for kept-in-sync files
             if (remoteFile.keepInSync()) {
                 SynchronizeFileOperation operation = new SynchronizeFileOperation(  localFile,        
                                                                                     remoteFile, 
-                                                                                    mStorageManager,
-                                                                                    mAccount,       
+                                                                                    mAccount, 
                                                                                     true, 
                                                                                     mContext
                                                                                     );
+                
                 filesToSyncContents.add(operation);
             }
             
             updatedFiles.add(remoteFile);
         }
 
-        // save updated contents in local database; all at once, trying to get a best performance in database update (not a big deal, indeed)
+        // save updated contents in local database
         mStorageManager.saveFolder(remoteFolder, updatedFiles, localFilesMap.values());
 
         // request for the synchronization of file contents AFTER saving current remote properties
         startContentSynchronizations(filesToSyncContents, client);
 
-        // removal of obsolete files
-        //removeObsoleteFiles();
-       
-        // must be done AFTER saving all the children information, so that eTag is not updated in the database in case of unexpected exceptions
-        //mStorageManager.saveFile(remoteFolder);
         mChildren = updatedFiles;
-        
     }
 
     /**
-     * Performs a list of synchronization operations, determining if a download or upload is needed or
-     * if exists conflict due to changes both in local and remote contents of the each file.
+     * Performs a list of synchronization operations, determining if a download or upload is needed
+     * or if exists conflict due to changes both in local and remote contents of the each file.
      * 
-     * If download or upload is needed, request the operation to the corresponding service and goes on.
+     * If download or upload is needed, request the operation to the corresponding service and goes 
+     * on.
      * 
      * @param filesToSyncContents       Synchronization operations to execute.
      * @param client                    Interface to the remote ownCloud server.
      */
-    private void startContentSynchronizations(List<SynchronizeFileOperation> filesToSyncContents, WebdavClient client) {
+    private void startContentSynchronizations(
+            List<SynchronizeFileOperation> filesToSyncContents, OwnCloudClient client
+        ) {
         RemoteOperationResult contentsResult = null;
         for (SynchronizeFileOperation op: filesToSyncContents) {
-            contentsResult = op.execute(client);   // returns without waiting for upload or download finishes
+            contentsResult = op.execute(mStorageManager, mContext);   // async
             if (!contentsResult.isSuccess()) {
                 if (contentsResult.getCode() == ResultCode.SYNC_CONFLICT) {
                     mConflictsFound++;
                 } else {
                     mFailsInFavouritesFound++;
                     if (contentsResult.getException() != null) {
-                        Log_OC.e(TAG, "Error while synchronizing favourites : " +  contentsResult.getLogMessage(), contentsResult.getException());
+                        Log_OC.e(TAG, "Error while synchronizing favourites : " 
+                                +  contentsResult.getLogMessage(), contentsResult.getException());
                     } else {
-                        Log_OC.e(TAG, "Error while synchronizing favourites : " + contentsResult.getLogMessage());
+                        Log_OC.e(TAG, "Error while synchronizing favourites : " 
+                                + contentsResult.getLogMessage());
                     }
                 }
             }   // won't let these fails break the synchronization process
@@ -430,30 +448,31 @@ public class SynchronizeFolderOperation extends RemoteOperation {
         return (status == HttpStatus.SC_MULTI_STATUS); 
     }
 
-
     /**
      * Creates and populates a new {@link OCFile} object with the data read from the server.
      * 
-     * @param we        WebDAV entry read from the server for a WebDAV resource (remote file or folder).
+     * @param remote    remote file read from the server (remote file or folder).
      * @return          New OCFile instance representing the remote resource described by we.
      */
-    private OCFile fillOCFile(WebdavEntry we) {
-        OCFile file = new OCFile(we.decodedPath());
-        file.setCreationTimestamp(we.createTimestamp());
-        file.setFileLength(we.contentLength());
-        file.setMimetype(we.contentType());
-        file.setModificationTimestamp(we.modifiedTimestamp());
-        file.setEtag(we.etag());
+    private OCFile fillOCFile(RemoteFile remote) {
+        OCFile file = new OCFile(remote.getRemotePath());
+        file.setCreationTimestamp(remote.getCreationTimestamp());
+        file.setFileLength(remote.getLength());
+        file.setMimetype(remote.getMimeType());
+        file.setModificationTimestamp(remote.getModifiedTimestamp());
+        file.setEtag(remote.getEtag());
+        file.setPermissions(remote.getPermissions());
+        file.setRemoteId(remote.getRemoteId());
         return file;
     }
     
 
     /**
-     * Checks the storage path of the OCFile received as parameter. If it's out of the local ownCloud folder,
-     * tries to copy the file inside it. 
+     * Checks the storage path of the OCFile received as parameter. 
+     * If it's out of the local ownCloud folder, tries to copy the file inside it. 
      * 
-     * If the copy fails, the link to the local file is nullified. The account of forgotten files is kept in 
-     * {@link #mForgottenLocalFiles}
+     * If the copy fails, the link to the local file is nullified. The account of forgotten 
+     * files is kept in {@link #mForgottenLocalFiles}
      *) 
      * @param file      File to check and fix.
      */
@@ -475,7 +494,9 @@ public class SynchronizeFolderOperation extends RemoteOperation {
                     File expectedParent = expectedFile.getParentFile();
                     expectedParent.mkdirs();
                     if (!expectedParent.isDirectory()) {
-                        throw new IOException("Unexpected error: parent directory could not be created");
+                        throw new IOException(
+                                "Unexpected error: parent directory could not be created"
+                        );
                     }
                     expectedFile.createNewFile();
                     if (!expectedFile.isFile()) {
@@ -499,17 +520,41 @@ public class SynchronizeFolderOperation extends RemoteOperation {
                     try {
                         if (in != null) in.close();
                     } catch (Exception e) {
-                        Log_OC.d(TAG, "Weird exception while closing input stream for " + storagePath + " (ignoring)", e);
+                        Log_OC.d(TAG, "Weird exception while closing input stream for " 
+                                + storagePath + " (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);
                     }
                 }
             }
         }
     }
+    
+    
+    private RemoteOperationResult refreshSharesForFolder(OwnCloudClient client) {
+        RemoteOperationResult result = null;
+        
+        // remote request 
+        GetRemoteSharesForFileOperation operation = 
+                new GetRemoteSharesForFileOperation(mLocalFolder.getRemotePath(), false, true);
+        result = operation.execute(client);
+        
+        if (result.isSuccess()) {
+            // update local database
+            ArrayList<OCShare> shares = new ArrayList<OCShare>();
+            for(Object obj: result.getData()) {
+                shares.add((OCShare) obj);
+            }
+            mStorageManager.saveSharesInFolder(shares, mLocalFolder);
+        }
+
+        return result;
+    }
+    
 
     /**
      * Scans the default location for saving local copies of files searching for
@@ -530,22 +575,26 @@ public class SynchronizeFolderOperation extends RemoteOperation {
 
     
     /**
-     * Sends a message to any application component interested in the progress of the synchronization.
+     * Sends a message to any application component interested in the progress 
+     * of the synchronization.
      * 
-     * @param inProgress        'True' when the synchronization progress is not finished.
-     * @param dirRemotePath     Remote path of a folder that was just synchronized (with or without success)
+     * @param event
+     * @param dirRemotePath     Remote path of a folder that was just synchronized 
+     *                          (with or without success)
+     * @param result
      */
-    private void sendStickyBroadcast(boolean inProgress, String dirRemotePath, RemoteOperationResult result) {
-        Intent i = new Intent(FileSyncService.getSyncMessage());
-        i.putExtra(FileSyncService.IN_PROGRESS, inProgress);
-        i.putExtra(FileSyncService.ACCOUNT_NAME, mAccount.name);
+    private void sendLocalBroadcast(
+            String event, String dirRemotePath, RemoteOperationResult result
+        ) {
+        Log_OC.d(TAG, "Send broadcast " + event);
+        Intent intent = new Intent(event);
+        intent.putExtra(FileSyncAdapter.EXTRA_ACCOUNT_NAME, mAccount.name);
         if (dirRemotePath != null) {
-            i.putExtra(FileSyncService.SYNC_FOLDER_REMOTE_PATH, dirRemotePath);
-        }
-        if (result != null) {
-            i.putExtra(FileSyncService.SYNC_RESULT, result);
+            intent.putExtra(FileSyncAdapter.EXTRA_FOLDER_PATH, dirRemotePath);
         }
-        mContext.sendStickyBroadcast(i);
+        intent.putExtra(FileSyncAdapter.EXTRA_RESULT, result);
+        mContext.sendStickyBroadcast(intent);
+        //LocalBroadcastManager.getInstance(mContext).sendBroadcast(intent);
     }
 
 
diff --git a/src/com/owncloud/android/operations/UnshareLinkOperation.java b/src/com/owncloud/android/operations/UnshareLinkOperation.java
new file mode 100644 (file)
index 0000000..c08c8e5
--- /dev/null
@@ -0,0 +1,96 @@
+/* ownCloud Android client application
+ *   Copyright (C) 2014 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 android.content.Context;
+
+import com.owncloud.android.datamodel.OCFile;
+
+import com.owncloud.android.lib.common.OwnCloudClient;
+import com.owncloud.android.lib.common.operations.RemoteOperationResult;
+import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;
+import com.owncloud.android.lib.common.utils.Log_OC;
+import com.owncloud.android.lib.resources.files.ExistenceCheckRemoteOperation;
+import com.owncloud.android.lib.resources.shares.OCShare;
+import com.owncloud.android.lib.resources.shares.RemoveRemoteShareOperation;
+import com.owncloud.android.lib.resources.shares.ShareType;
+
+import com.owncloud.android.operations.common.SyncOperation;
+
+/**
+ * Unshare file/folder
+ * Save the data in Database
+ * 
+ * @author masensio
+ */
+public class UnshareLinkOperation extends SyncOperation {
+
+    private static final String TAG = UnshareLinkOperation.class.getSimpleName();
+    
+    private String mRemotePath;
+    private Context mContext;
+    
+    
+    public UnshareLinkOperation(String remotePath, Context context) {
+        mRemotePath = remotePath;
+        mContext = context;
+    }
+
+    @Override
+    protected RemoteOperationResult run(OwnCloudClient client) {
+        RemoteOperationResult result  = null;
+        
+        // Get Share for a file
+        OCShare share = getStorageManager().getFirstShareByPathAndType(mRemotePath, ShareType.PUBLIC_LINK);
+        
+        if (share != null) {
+            RemoveRemoteShareOperation operation = new RemoveRemoteShareOperation((int) share.getIdRemoteShared());
+            result = operation.execute(client);
+
+            if (result.isSuccess() || result.getCode() == ResultCode.SHARE_NOT_FOUND) {
+                Log_OC.d(TAG, "Share id = " + share.getIdRemoteShared() + " deleted");
+
+                OCFile file = getStorageManager().getFileByPath(mRemotePath);
+                file.setShareByLink(false);
+                file.setPublicLink("");
+                getStorageManager().saveFile(file);
+                getStorageManager().removeShare(share);
+                
+                if (result.getCode() == ResultCode.SHARE_NOT_FOUND) {
+                    if (existsFile(client, file.getRemotePath())) {
+                        result = new RemoteOperationResult(ResultCode.OK);
+                    } else {
+                        getStorageManager().removeFile(file, true, true);
+                    }
+                }
+            } 
+                
+        } else {
+            result = new RemoteOperationResult(ResultCode.SHARE_NOT_FOUND);
+        }
+
+        return result;
+    }
+    
+    private boolean existsFile(OwnCloudClient client, String remotePath){
+        ExistenceCheckRemoteOperation existsOperation = new ExistenceCheckRemoteOperation(remotePath, mContext, false);
+        RemoteOperationResult result = existsOperation.execute(client);
+        return result.isSuccess();
+    }
+
+}
index 2e116ac..ac73d96 100644 (file)
@@ -22,19 +22,20 @@ import org.apache.commons.httpclient.methods.GetMethod;
 import org.json.JSONException;
 import org.json.JSONObject;
 
-import com.owncloud.android.Log_OC;
-import com.owncloud.android.authentication.AccountAuthenticator;
 import com.owncloud.android.authentication.AccountUtils;
-import com.owncloud.android.operations.RemoteOperationResult.ResultCode;
-import com.owncloud.android.utils.OwnCloudVersion;
+import com.owncloud.android.lib.common.OwnCloudClient;
+import com.owncloud.android.lib.common.accounts.AccountUtils.Constants;
+import com.owncloud.android.lib.common.operations.RemoteOperation;
+import com.owncloud.android.lib.common.operations.RemoteOperationResult;
+import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;
+import com.owncloud.android.lib.common.utils.Log_OC;
+import com.owncloud.android.lib.resources.status.OwnCloudVersion;
 
 import android.accounts.Account;
 import android.accounts.AccountManager;
 import android.content.Context;
 
 
-import eu.alefzero.webdav.WebdavClient;
-
 /**
  * Remote operation that checks the version of an ownCloud server and stores it locally
  * 
@@ -46,18 +47,20 @@ public class UpdateOCVersionOperation extends RemoteOperation {
 
     private Account mAccount;
     private Context mContext;
+    private OwnCloudVersion mOwnCloudVersion;
     
     
     public UpdateOCVersionOperation(Account account, Context context) {
         mAccount = account;
         mContext = context;
+        mOwnCloudVersion = null;
     }
     
     
     @Override
-    protected RemoteOperationResult run(WebdavClient client) {
+    protected RemoteOperationResult run(OwnCloudClient client) {
         AccountManager accountMngr = AccountManager.get(mContext); 
-        String statUrl = accountMngr.getUserData(mAccount, AccountAuthenticator.KEY_OC_BASE_URL);
+        String statUrl = accountMngr.getUserData(mAccount, Constants.KEY_OC_BASE_URL);
         statUrl += AccountUtils.STATUS_PATH;
         RemoteOperationResult result = null;
         GetMethod get = null;
@@ -73,10 +76,13 @@ public class UpdateOCVersionOperation extends RemoteOperation {
                 if (response != null) {
                     JSONObject json = new JSONObject(response);
                     if (json != null && json.getString("version") != null) {
-                        OwnCloudVersion ocver = new OwnCloudVersion(json.getString("version"));
-                        if (ocver.isVersionValid()) {
-                            accountMngr.setUserData(mAccount, AccountAuthenticator.KEY_OC_VERSION, ocver.toString());
-                            Log_OC.d(TAG, "Got new OC version " + ocver.toString());
+
+                        String version = json.getString("version");
+                        mOwnCloudVersion = new OwnCloudVersion(version);
+                        if (mOwnCloudVersion.isVersionValid()) {
+                            accountMngr.setUserData(mAccount, Constants.KEY_OC_VERSION, mOwnCloudVersion.getVersion());
+                            Log_OC.d(TAG, "Got new OC version " + mOwnCloudVersion.toString());
+
                             result = new RemoteOperationResult(ResultCode.OK);
                             
                         } else {
@@ -89,15 +95,15 @@ public class UpdateOCVersionOperation extends RemoteOperation {
                     result = new RemoteOperationResult(RemoteOperationResult.ResultCode.INSTANCE_NOT_CONFIGURED);
                 }
             }
-            Log_OC.i(TAG, "Check for update of ownCloud server version at " + client.getBaseUri() + ": " + result.getLogMessage());
+            Log_OC.i(TAG, "Check for update of ownCloud server version at " + client.getWebdavUri() + ": " + result.getLogMessage());
             
         } catch (JSONException e) {
             result = new RemoteOperationResult(RemoteOperationResult.ResultCode.INSTANCE_NOT_CONFIGURED);
-            Log_OC.e(TAG, "Check for update of ownCloud server version at " + client.getBaseUri() + ": " + result.getLogMessage(), e);
+            Log_OC.e(TAG, "Check for update of ownCloud server version at " + client.getWebdavUri() + ": " + result.getLogMessage(), e);
                 
         } catch (Exception e) {
             result = new RemoteOperationResult(e);
-            Log_OC.e(TAG, "Check for update of ownCloud server version at " + client.getBaseUri() + ": " + result.getLogMessage(), e);
+            Log_OC.e(TAG, "Check for update of ownCloud server version at " + client.getWebdavUri() + ": " + result.getLogMessage(), e);
             
         } finally {
             if (get != null) 
@@ -106,4 +112,9 @@ public class UpdateOCVersionOperation extends RemoteOperation {
         return result;
     }
 
+
+    public OwnCloudVersion getOCVersion() {
+        return mOwnCloudVersion;
+    }
+
 }
index 936ac01..43fcaa5 100644 (file)
@@ -24,31 +24,32 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.Set;
 import java.util.concurrent.atomic.AtomicBoolean;
 
-import org.apache.commons.httpclient.HttpException;
 import org.apache.commons.httpclient.methods.PutMethod;
 import org.apache.commons.httpclient.methods.RequestEntity;
-import org.apache.http.HttpStatus;
 
-import com.owncloud.android.Log_OC;
 import com.owncloud.android.datamodel.OCFile;
 import com.owncloud.android.files.services.FileUploader;
-import com.owncloud.android.network.ProgressiveDataTransferer;
-import com.owncloud.android.operations.RemoteOperation;
-import com.owncloud.android.operations.RemoteOperationResult;
-import com.owncloud.android.operations.RemoteOperationResult.ResultCode;
+import com.owncloud.android.lib.common.network.ProgressiveDataTransferer;
+import com.owncloud.android.lib.common.network.OnDatatransferProgressListener;
+import com.owncloud.android.lib.common.OwnCloudClient;
+import com.owncloud.android.lib.common.operations.OperationCancelledException;
+import com.owncloud.android.lib.common.operations.RemoteOperation;
+import com.owncloud.android.lib.common.operations.RemoteOperationResult;
+import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;
+import com.owncloud.android.lib.common.utils.Log_OC;
+import com.owncloud.android.lib.resources.files.ChunkedUploadRemoteFileOperation;
+import com.owncloud.android.lib.resources.files.ExistenceCheckRemoteOperation;
+import com.owncloud.android.lib.resources.files.UploadRemoteFileOperation;
 import com.owncloud.android.utils.FileStorageUtils;
 
 import android.accounts.Account;
+import android.content.Context;
 
 
-import eu.alefzero.webdav.FileRequestEntity;
-import eu.alefzero.webdav.OnDatatransferProgressListener;
-import eu.alefzero.webdav.WebdavClient;
-import eu.alefzero.webdav.WebdavUtils;
-
 /**
  * Remote operation performing the upload of a file to an ownCloud server
  * 
@@ -62,6 +63,7 @@ public class UploadFileOperation extends RemoteOperation {
     private OCFile mFile;
     private OCFile mOldFile;
     private String mRemotePath = null;
+    private boolean mChunked = false;
     private boolean mIsInstant = false;
     private boolean mRemoteFolderToBeCreated = false;
     private boolean mForceOverwrite = false;
@@ -72,15 +74,20 @@ public class UploadFileOperation extends RemoteOperation {
     PutMethod mPutMethod = null;
     private Set<OnDatatransferProgressListener> mDataTransferListeners = new HashSet<OnDatatransferProgressListener>();
     private final AtomicBoolean mCancellationRequested = new AtomicBoolean(false);
+    private Context mContext;
+    
+    private UploadRemoteFileOperation mUploadOperation;
 
     protected RequestEntity mEntity = null;
 
     
     public UploadFileOperation( Account account,
                                 OCFile file,
+                                boolean chunked,
                                 boolean isInstant, 
                                 boolean forceOverwrite,
-                                int localBehaviour) {
+                                int localBehaviour, 
+                                Context context) {
         if (account == null)
             throw new IllegalArgumentException("Illegal NULL account in UploadFileOperation creation");
         if (file == null)
@@ -95,11 +102,13 @@ public class UploadFileOperation extends RemoteOperation {
         mAccount = account;
         mFile = file;
         mRemotePath = file.getRemotePath();
+        mChunked = chunked;
         mIsInstant = isInstant;
         mForceOverwrite = forceOverwrite;
         mLocalBehaviour = localBehaviour;
         mOriginalStoragePath = mFile.getStoragePath();
         mOriginalFileName = mFile.getFileName();
+        mContext = context;
     }
 
     public Account getAccount() {
@@ -177,7 +186,7 @@ public class UploadFileOperation extends RemoteOperation {
     }
 
     @Override
-    protected RemoteOperationResult run(WebdavClient client) {
+    protected RemoteOperationResult run(OwnCloudClient client) {
         RemoteOperationResult result = null;
         boolean localCopyPassed = false, nameCheckPassed = false;
         File temporalFile = null, originalFile = new File(mOriginalStoragePath), expectedFile = null;
@@ -199,7 +208,7 @@ public class UploadFileOperation extends RemoteOperation {
                                                                                                 // !!!
             expectedFile = new File(expectedPath);
 
-            // check location of local file; if not the expected, copy to a
+            // 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) {
 
@@ -260,19 +269,23 @@ public class UploadFileOperation extends RemoteOperation {
             }
             localCopyPassed = true;
 
-            // / perform the upload
-            synchronized (mCancellationRequested) {
-                if (mCancellationRequested.get()) {
-                    throw new OperationCancelledException();
-                } else {
-                    mPutMethod = new PutMethod(client.getBaseUri() + WebdavUtils.encodePath(mFile.getRemotePath()));
-                }
+            /// perform the upload
+            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());
+            }
+            Iterator <OnDatatransferProgressListener> listener = mDataTransferListeners.iterator();
+            while (listener.hasNext()) {
+                mUploadOperation.addDatatransferProgressListener(listener.next());
             }
-            int status = uploadFile(client);
+            result = mUploadOperation.execute(client);
 
-            // / move local temporal file or original file to its corresponding
+            /// move local temporal file or original file to its corresponding
             // location in the ownCloud local folder
-            if (isSuccess(status)) {
+            if (result.isSuccess()) {
                 if (mLocalBehaviour == FileUploader.LOCAL_BEHAVIOUR_FORGET) {
                     mFile.setStoragePath(null);
 
@@ -305,8 +318,6 @@ public class UploadFileOperation extends RemoteOperation {
                 }
             }
 
-            result = new RemoteOperationResult(isSuccess(status), status, (mPutMethod != null ? mPutMethod.getResponseHeaders() : null));
-
         } catch (Exception e) {
             // TODO something cleaner with cancellations
             if (mCancellationRequested.get()) {
@@ -358,29 +369,6 @@ public class UploadFileOperation extends RemoteOperation {
         mFile = newFile;
     }
 
-    public boolean isSuccess(int status) {
-        return ((status == HttpStatus.SC_OK || status == HttpStatus.SC_CREATED || status == HttpStatus.SC_NO_CONTENT));
-    }
-
-    protected int uploadFile(WebdavClient client) throws HttpException, IOException, OperationCancelledException {
-        int status = -1;
-        try {
-            File f = new File(mFile.getStoragePath());
-            mEntity  = new FileRequestEntity(f, getMimeType());
-            synchronized (mDataTransferListeners) {
-                ((ProgressiveDataTransferer)mEntity).addDatatransferProgressListeners(mDataTransferListeners);
-            }
-            mPutMethod.setRequestEntity(mEntity);
-            status = client.executeMethod(mPutMethod);
-            client.exhaustResponse(mPutMethod.getResponseBodyAsStream());
-
-        } finally {
-            mPutMethod.releaseConnection(); // let the connection available for
-                                            // other methods
-        }
-        return status;
-    }
-
     /**
      * 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.
@@ -388,8 +376,8 @@ public class UploadFileOperation extends RemoteOperation {
      * @param string
      * @return
      */
-    private String getAvailableRemotePath(WebdavClient wc, String remotePath) throws Exception {
-        boolean check = wc.existsFile(remotePath);
+    private String getAvailableRemotePath(OwnCloudClient wc, String remotePath) throws Exception {
+        boolean check = existsFile(wc, remotePath);
         if (!check) {
             return remotePath;
         }
@@ -404,10 +392,12 @@ public class UploadFileOperation extends RemoteOperation {
         int count = 2;
         do {
             suffix = " (" + count + ")";
-            if (pos >= 0)
-                check = wc.existsFile(remotePath + suffix + "." + extension);
-            else
-                check = wc.existsFile(remotePath + suffix);
+            if (pos >= 0) {
+                check = existsFile(wc, remotePath + suffix + "." + extension);
+            }
+            else {
+                check = existsFile(wc, remotePath + suffix);
+            }
             count++;
         } while (check);
 
@@ -418,12 +408,14 @@ public class UploadFileOperation extends RemoteOperation {
         }
     }
 
+    private boolean existsFile(OwnCloudClient client, String remotePath){
+        ExistenceCheckRemoteOperation existsOperation = new ExistenceCheckRemoteOperation(remotePath, mContext, false);
+        RemoteOperationResult result = existsOperation.execute(client);
+        return result.isSuccess();
+    }
+    
     public void cancel() {
-        synchronized (mCancellationRequested) {
-            mCancellationRequested.set(true);
-            if (mPutMethod != null)
-                mPutMethod.abort();
-        }
+        mUploadOperation.cancel();
     }
 
 }
diff --git a/src/com/owncloud/android/operations/common/SyncOperation.java b/src/com/owncloud/android/operations/common/SyncOperation.java
new file mode 100644 (file)
index 0000000..8c5678b
--- /dev/null
@@ -0,0 +1,130 @@
+/* ownCloud Android client application
+ *   Copyright (C) 2012-2014 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.common;
+
+import com.owncloud.android.datamodel.FileDataStorageManager;
+import com.owncloud.android.lib.common.OwnCloudClient;
+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 android.content.Context;
+import android.os.Handler;
+
+
+/**
+ * Operation which execution involves both interactions with an ownCloud server and
+ * 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 {
+       
+    //private static final String TAG = SyncOperation.class.getSimpleName();
+
+    private FileDataStorageManager mStorageManager;
+    
+    public FileDataStorageManager getStorageManager() {
+        return mStorageManager;
+    }
+       
+
+    /**
+     * Synchronously executes the operation on the received ownCloud account.
+     * 
+     * Do not call this method from the main thread.
+     * 
+     * This method should be used whenever an ownCloud account is available, instead of {@link #execute(OwnCloudClient)}. 
+     * 
+     * @param account   ownCloud account in remote ownCloud server to reach during the execution of the operation.
+     * @param context   Android context for the component calling the method.
+     * @return          Result of the operation.
+     */
+    public RemoteOperationResult execute(FileDataStorageManager storageManager, Context context) {
+        if (storageManager == null) {
+            throw new IllegalArgumentException("Trying to execute a sync operation with a NULL storage manager");
+        }
+        if (storageManager.getAccount() == null) {
+            throw new IllegalArgumentException("Trying to execute a sync operation with a storage manager for a NULL account");
+        }
+        mStorageManager = storageManager;
+        return super.execute(mStorageManager.getAccount(), context);
+    }
+    
+       
+       /**
+        * Synchronously executes the remote operation
+        * 
+     * Do not call this method from the main thread.
+     * 
+        * @param client        Client object to reach an ownCloud server during the execution of the operation.
+        * @return                      Result of the operation.
+        */
+       public RemoteOperationResult execute(OwnCloudClient client, FileDataStorageManager storageManager) {
+        if (storageManager == null)
+            throw new IllegalArgumentException("Trying to execute a sync operation with a NULL storage manager");
+        mStorageManager = storageManager;
+               return super.execute(client);
+       }
+
+       
+    /**
+     * Asynchronously executes the remote operation
+     * 
+     * This method should be used whenever an ownCloud account is available, instead of {@link #execute(OwnCloudClient)}. 
+     * 
+     * @param account           ownCloud account in remote ownCloud server to reach during the execution of the operation.
+     * @param context           Android context for the component calling the method.
+     * @param listener          Listener to be notified about the execution of the operation.
+     * @param listenerHandler   Handler associated to the thread where the methods of the listener objects must be called.
+     * @return                  Thread were the remote operation is executed.
+     */
+       /*
+    public Thread execute(FileDataStorageManager storageManager, Context context, OnRemoteOperationListener listener, Handler listenerHandler, Activity callerActivity) {
+        if (storageManager == null) {
+            throw new IllegalArgumentException("Trying to execute a sync operation with a NULL storage manager");
+        }
+        if (storageManager.getAccount() == null) {
+            throw new IllegalArgumentException("Trying to execute a sync operation with a storage manager for a NULL account");
+        }
+        mStorageManager = storageManager;
+        return super.execute(storageManager.getAccount(), context, listener, listenerHandler, callerActivity);
+    }
+    */
+
+    
+       /**
+        * Asynchronously executes the remote operation
+        * 
+        * @param client                        Client object to reach an ownCloud server during the execution of the operation.
+        * @param listener                      Listener to be notified about the execution of the operation.
+        * @param listenerHandler       Handler associated to the thread where the methods of the listener objects must be called.
+        * @return                                      Thread were the remote operation is executed.
+        */
+       public Thread execute(OwnCloudClient client, FileDataStorageManager storageManager, OnRemoteOperationListener listener, Handler listenerHandler) {
+        if (storageManager == null) {
+            throw new IllegalArgumentException("Trying to execute a sync operation with a NULL storage manager");
+        }
+        mStorageManager = storageManager;
+        return super.execute(client, listener, listenerHandler);
+       }
+
+       
+}
index 41b643c..a94454c 100644 (file)
@@ -21,13 +21,12 @@ package com.owncloud.android.providers;
 import java.util.ArrayList;
 import java.util.HashMap;
 
-import com.owncloud.android.Log_OC;
 import com.owncloud.android.R;
-import com.owncloud.android.datamodel.FileDataStorageManager;
+import com.owncloud.android.datamodel.ThumbnailsCacheManager;
 import com.owncloud.android.db.ProviderMeta;
 import com.owncloud.android.db.ProviderMeta.ProviderTableMeta;
-
-
+import com.owncloud.android.lib.common.utils.Log_OC;
+import com.owncloud.android.lib.resources.shares.ShareType;
 
 import android.content.ContentProvider;
 import android.content.ContentProviderOperation;
@@ -56,44 +55,93 @@ public class FileContentProvider extends ContentProvider {
 
     private DataBaseHelper mDbHelper;
 
-    private static HashMap<String, String> mProjectionMap;
+    // Projection for filelist table
+    private static HashMap<String, String> mFileProjectionMap;
     static {
-        mProjectionMap = new HashMap<String, String>();
-        mProjectionMap.put(ProviderTableMeta._ID, ProviderTableMeta._ID);
-        mProjectionMap.put(ProviderTableMeta.FILE_PARENT,
+        mFileProjectionMap = new HashMap<String, String>();
+        mFileProjectionMap.put(ProviderTableMeta._ID, ProviderTableMeta._ID);
+        mFileProjectionMap.put(ProviderTableMeta.FILE_PARENT,
                 ProviderTableMeta.FILE_PARENT);
-        mProjectionMap.put(ProviderTableMeta.FILE_PATH,
+        mFileProjectionMap.put(ProviderTableMeta.FILE_PATH,
                 ProviderTableMeta.FILE_PATH);
-        mProjectionMap.put(ProviderTableMeta.FILE_NAME,
+        mFileProjectionMap.put(ProviderTableMeta.FILE_NAME,
                 ProviderTableMeta.FILE_NAME);
-        mProjectionMap.put(ProviderTableMeta.FILE_CREATION,
+        mFileProjectionMap.put(ProviderTableMeta.FILE_CREATION,
                 ProviderTableMeta.FILE_CREATION);
-        mProjectionMap.put(ProviderTableMeta.FILE_MODIFIED,
+        mFileProjectionMap.put(ProviderTableMeta.FILE_MODIFIED,
                 ProviderTableMeta.FILE_MODIFIED);
-        mProjectionMap.put(ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA,
+        mFileProjectionMap.put(ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA,
                 ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA);
-        mProjectionMap.put(ProviderTableMeta.FILE_CONTENT_LENGTH,
+        mFileProjectionMap.put(ProviderTableMeta.FILE_CONTENT_LENGTH,
                 ProviderTableMeta.FILE_CONTENT_LENGTH);
-        mProjectionMap.put(ProviderTableMeta.FILE_CONTENT_TYPE,
+        mFileProjectionMap.put(ProviderTableMeta.FILE_CONTENT_TYPE,
                 ProviderTableMeta.FILE_CONTENT_TYPE);
-        mProjectionMap.put(ProviderTableMeta.FILE_STORAGE_PATH,
+        mFileProjectionMap.put(ProviderTableMeta.FILE_STORAGE_PATH,
                 ProviderTableMeta.FILE_STORAGE_PATH);
-        mProjectionMap.put(ProviderTableMeta.FILE_LAST_SYNC_DATE,
+        mFileProjectionMap.put(ProviderTableMeta.FILE_LAST_SYNC_DATE,
                 ProviderTableMeta.FILE_LAST_SYNC_DATE);
-        mProjectionMap.put(ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA,
+        mFileProjectionMap.put(ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA,
                 ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA);
-        mProjectionMap.put(ProviderTableMeta.FILE_KEEP_IN_SYNC,
+        mFileProjectionMap.put(ProviderTableMeta.FILE_KEEP_IN_SYNC,
                 ProviderTableMeta.FILE_KEEP_IN_SYNC);
-        mProjectionMap.put(ProviderTableMeta.FILE_ACCOUNT_OWNER,
+        mFileProjectionMap.put(ProviderTableMeta.FILE_ACCOUNT_OWNER,
                 ProviderTableMeta.FILE_ACCOUNT_OWNER);
-        mProjectionMap.put(ProviderTableMeta.FILE_ETAG, 
+        mFileProjectionMap.put(ProviderTableMeta.FILE_ETAG, 
                 ProviderTableMeta.FILE_ETAG);
+        mFileProjectionMap.put(ProviderTableMeta.FILE_SHARE_BY_LINK,
+                ProviderTableMeta.FILE_SHARE_BY_LINK);
+        mFileProjectionMap.put(ProviderTableMeta.FILE_PUBLIC_LINK,
+                ProviderTableMeta.FILE_PUBLIC_LINK);
+        mFileProjectionMap.put(ProviderTableMeta.FILE_PERMISSIONS,
+                ProviderTableMeta.FILE_PERMISSIONS);
+        mFileProjectionMap.put(ProviderTableMeta.FILE_REMOTE_ID,
+                ProviderTableMeta.FILE_REMOTE_ID);
+        mFileProjectionMap.put(ProviderTableMeta.FILE_UPDATE_THUMBNAIL,
+                ProviderTableMeta.FILE_UPDATE_THUMBNAIL);
     }
 
     private static final int SINGLE_FILE = 1;
     private static final int DIRECTORY = 2;
     private static final int ROOT_DIRECTORY = 3;
+    private static final int SHARES = 4;
 
+    private static final String TAG = FileContentProvider.class.getSimpleName();
+    
+    // Projection for ocshares table
+    private static HashMap<String, String> mOCSharesProjectionMap;
+    static {
+        mOCSharesProjectionMap = new HashMap<String, String>();
+        mOCSharesProjectionMap.put(ProviderTableMeta._ID, ProviderTableMeta._ID);
+        mOCSharesProjectionMap.put(ProviderTableMeta.OCSHARES_FILE_SOURCE,
+                ProviderTableMeta.OCSHARES_FILE_SOURCE);
+        mOCSharesProjectionMap.put(ProviderTableMeta.OCSHARES_ITEM_SOURCE,
+                ProviderTableMeta.OCSHARES_ITEM_SOURCE);
+        mOCSharesProjectionMap.put(ProviderTableMeta.OCSHARES_SHARE_TYPE,
+                ProviderTableMeta.OCSHARES_SHARE_TYPE);
+        mOCSharesProjectionMap.put(ProviderTableMeta.OCSHARES_SHARE_WITH,
+                ProviderTableMeta.OCSHARES_SHARE_WITH);
+        mOCSharesProjectionMap.put(ProviderTableMeta.OCSHARES_PATH,
+                ProviderTableMeta.OCSHARES_PATH);
+        mOCSharesProjectionMap.put(ProviderTableMeta.OCSHARES_PERMISSIONS,
+                ProviderTableMeta.OCSHARES_PERMISSIONS);
+        mOCSharesProjectionMap.put(ProviderTableMeta.OCSHARES_SHARED_DATE,
+                ProviderTableMeta.OCSHARES_SHARED_DATE);
+        mOCSharesProjectionMap.put(ProviderTableMeta.OCSHARES_EXPIRATION_DATE,
+                ProviderTableMeta.OCSHARES_EXPIRATION_DATE);
+        mOCSharesProjectionMap.put(ProviderTableMeta.OCSHARES_TOKEN,
+                ProviderTableMeta.OCSHARES_TOKEN);
+        mOCSharesProjectionMap.put(ProviderTableMeta.OCSHARES_SHARE_WITH_DISPLAY_NAME,
+                ProviderTableMeta.OCSHARES_SHARE_WITH_DISPLAY_NAME);
+        mOCSharesProjectionMap.put(ProviderTableMeta.OCSHARES_IS_DIRECTORY,
+                ProviderTableMeta.OCSHARES_IS_DIRECTORY);
+        mOCSharesProjectionMap.put(ProviderTableMeta.OCSHARES_USER_ID,
+                ProviderTableMeta.OCSHARES_USER_ID);
+        mOCSharesProjectionMap.put(ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED,
+                ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED);
+        mOCSharesProjectionMap.put(ProviderTableMeta.OCSHARES_ACCOUNT_OWNER,
+                ProviderTableMeta.OCSHARES_ACCOUNT_OWNER);
+    }
+    
     private UriMatcher mUriMatcher;
     
     @Override
@@ -112,19 +160,19 @@ public class FileContentProvider extends ContentProvider {
         return count;
     }
     
-    
     private int delete(SQLiteDatabase db, Uri uri, String where, String[] whereArgs) {
         int count = 0;
         switch (mUriMatcher.match(uri)) {
         case SINGLE_FILE:
-            /*Cursor c = query(db, uri, null, where, whereArgs, null);
-            String remotePath = "(unexisting)";
+            Cursor c = query(db, uri, null, where, whereArgs, null);
+            String remoteId = "";
             if (c != null && c.moveToFirst()) {
-                remotePath = c.getString(c.getColumnIndex(ProviderTableMeta.FILE_PATH));
+                remoteId = c.getString(c.getColumnIndex(ProviderTableMeta.FILE_REMOTE_ID));
+                //ThumbnailsCacheManager.removeFileFromCache(remoteId);
             }
-            Log_OC.d(TAG, "Removing FILE " + remotePath);
-            */
-            count = db.delete(ProviderTableMeta.DB_NAME,
+            Log_OC.d(TAG, "Removing FILE " + remoteId);
+
+            count = db.delete(ProviderTableMeta.FILE_TABLE_NAME,
                     ProviderTableMeta._ID
                             + "="
                             + uri.getPathSegments().get(1)
@@ -149,16 +197,28 @@ public class FileContentProvider extends ContentProvider {
             Cursor children = query(uri, null, null, null, null);
             if (children != null && children.moveToFirst())  {
                 long childId;
-                boolean isDir; 
+                boolean isDir;
                 //String remotePath; 
                 while (!children.isAfterLast()) {
                     childId = children.getLong(children.getColumnIndex(ProviderTableMeta._ID));
-                    isDir = "DIR".equals(children.getString(children.getColumnIndex(ProviderTableMeta.FILE_CONTENT_TYPE)));
+                    isDir = "DIR".equals(children.getString(
+                            children.getColumnIndex(ProviderTableMeta.FILE_CONTENT_TYPE)
+                    ));
                     //remotePath = children.getString(children.getColumnIndex(ProviderTableMeta.FILE_PATH));
                     if (isDir) {
-                        count += delete(db, ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_DIR, childId), null, null);
+                        count += delete(
+                            db, 
+                            ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_DIR, childId), 
+                            null, 
+                            null
+                        );
                     } else {
-                        count += delete(db, ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_FILE, childId), null, null);
+                        count += delete(
+                            db, 
+                            ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_FILE, childId),
+                            null, 
+                            null
+                        );
                     }
                     children.moveToNext();
                 }
@@ -168,7 +228,7 @@ public class FileContentProvider extends ContentProvider {
             }
             Log_OC.d(TAG, "Removing DIRECTORY " + folderName + " (or maybe not) ");
             */
-            count += db.delete(ProviderTableMeta.DB_NAME,
+            count += db.delete(ProviderTableMeta.FILE_TABLE_NAME,
                     ProviderTableMeta._ID
                     + "="
                     + uri.getPathSegments().get(1)
@@ -181,7 +241,10 @@ public class FileContentProvider extends ContentProvider {
             break;
         case ROOT_DIRECTORY:
             //Log_OC.d(TAG, "Removing ROOT!");
-            count = db.delete(ProviderTableMeta.DB_NAME, where, whereArgs);
+            count = db.delete(ProviderTableMeta.FILE_TABLE_NAME, where, whereArgs);
+            break;
+        case SHARES:
+            count = db.delete(ProviderTableMeta.OCSHARES_TABLE_NAME, where, whereArgs);
             break;
         default:
             //Log_OC.e(TAG, "Unknown uri " + uri);
@@ -189,7 +252,6 @@ public class FileContentProvider extends ContentProvider {
         }
         return count;
     }
-    
 
     @Override
     public String getType(Uri uri) {
@@ -206,7 +268,6 @@ public class FileContentProvider extends ContentProvider {
 
     @Override
     public Uri insert(Uri uri, ContentValues values) {
-        //Log_OC.d(TAG, "Inserting " + values.getAsString(ProviderTableMeta.FILE_PATH) + " at provider " + this);
         Uri newUri = null;
         SQLiteDatabase db = mDbHelper.getWritableDatabase();
         db.beginTransaction();
@@ -221,37 +282,104 @@ public class FileContentProvider extends ContentProvider {
     }
     
     private Uri insert(SQLiteDatabase db, Uri uri, ContentValues values) {
-        if (mUriMatcher.match(uri) != SINGLE_FILE &&
-                mUriMatcher.match(uri) != ROOT_DIRECTORY) {
-            //Log_OC.e(TAG, "Inserting invalid URI: " + uri);
-            throw new IllegalArgumentException("Unknown uri id: " + uri);
-        }
+        switch (mUriMatcher.match(uri)){
+        case ROOT_DIRECTORY:
+        case SINGLE_FILE:
+            String remotePath = values.getAsString(ProviderTableMeta.FILE_PATH);
+            String accountName = values.getAsString(ProviderTableMeta.FILE_ACCOUNT_OWNER);
+            String[] projection = new String[] {
+                    ProviderTableMeta._ID, ProviderTableMeta.FILE_PATH, 
+                    ProviderTableMeta.FILE_ACCOUNT_OWNER 
+            };
+            String where = ProviderTableMeta.FILE_PATH + "=? AND " + 
+                    ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?";
+            String[] whereArgs = new String[] {remotePath, accountName};
+            Cursor doubleCheck = query(db, uri, projection, where, whereArgs, null);
+            // ugly patch; serious refactorization is needed to reduce work in 
+            // FileDataStorageManager and bring it to FileContentProvider
+            if (doubleCheck == null || !doubleCheck.moveToFirst()) {     
+                long rowId = db.insert(ProviderTableMeta.FILE_TABLE_NAME, null, values);
+                if (rowId > 0) {
+                    Uri insertedFileUri = 
+                            ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_FILE, rowId);
+                    return insertedFileUri;
+                } else {
+                    throw new SQLException("ERROR " + uri);
+                }
+            } else {
+                // file is already inserted; race condition, let's avoid a duplicated entry
+                Uri insertedFileUri = ContentUris.withAppendedId(
+                        ProviderTableMeta.CONTENT_URI_FILE, 
+                        doubleCheck.getLong(doubleCheck.getColumnIndex(ProviderTableMeta._ID))
+                );
+                doubleCheck.close();
 
-        String remotePath = values.getAsString(ProviderTableMeta.FILE_PATH);
-        String accountName = values.getAsString(ProviderTableMeta.FILE_ACCOUNT_OWNER);
-        String[] projection = new String[] {ProviderTableMeta._ID, ProviderTableMeta.FILE_PATH, ProviderTableMeta.FILE_ACCOUNT_OWNER };
-        String where = ProviderTableMeta.FILE_PATH + "=? AND " + ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?";
-        String[] whereArgs = new String[] {remotePath, accountName};
-        Cursor doubleCheck = query(db, uri, projection, where, whereArgs, null);
-        if (doubleCheck == null || !doubleCheck.moveToFirst()) {    // ugly patch; serious refactorization is needed to reduce work in FileDataStorageManager and bring it to FileContentProvider 
-            long rowId = db.insert(ProviderTableMeta.DB_NAME, null, values);
-            if (rowId > 0) {
-                Uri insertedFileUri = ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_FILE, rowId);
-                //Log_OC.d(TAG, "Inserted " + values.getAsString(ProviderTableMeta.FILE_PATH) + " at provider " + this);
                 return insertedFileUri;
+            }
+            
+        case SHARES:
+            String path = values.getAsString(ProviderTableMeta.OCSHARES_PATH);
+            String accountNameShare= values.getAsString(ProviderTableMeta.OCSHARES_ACCOUNT_OWNER);
+            String[] projectionShare = new String[] {
+                    ProviderTableMeta._ID, ProviderTableMeta.OCSHARES_PATH, 
+                    ProviderTableMeta.OCSHARES_ACCOUNT_OWNER 
+            };
+            String whereShare = ProviderTableMeta.OCSHARES_PATH + "=? AND " + 
+                    ProviderTableMeta.OCSHARES_ACCOUNT_OWNER + "=?";
+            String[] whereArgsShare = new String[] {path, accountNameShare};
+            Uri insertedShareUri = null;
+            Cursor doubleCheckShare = 
+                    query(db, uri, projectionShare, whereShare, whereArgsShare, null);
+            // ugly patch; serious refactorization is needed to reduce work in 
+            // FileDataStorageManager and bring it to FileContentProvider
+            if (doubleCheckShare == null || !doubleCheckShare.moveToFirst()) {     
+                long rowId = db.insert(ProviderTableMeta.OCSHARES_TABLE_NAME, null, values);
+                if (rowId >0) {
+                    insertedShareUri = 
+                            ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_SHARE, rowId);
+                } else {
+                    throw new SQLException("ERROR " + uri);
+
+                }
             } else {
-                //Log_OC.d(TAG, "Error while inserting " + values.getAsString(ProviderTableMeta.FILE_PATH)  + " at provider " + this);
-                throw new SQLException("ERROR " + uri);
+                // file is already inserted; race condition, let's avoid a duplicated entry
+                insertedShareUri = ContentUris.withAppendedId(
+                        ProviderTableMeta.CONTENT_URI_SHARE, 
+                        doubleCheckShare.getLong(
+                                doubleCheckShare.getColumnIndex(ProviderTableMeta._ID)
+                        )
+                );
+                doubleCheckShare.close();
             }
-        } else {
-            // file is already inserted; race condition, let's avoid a duplicated entry
-            Uri insertedFileUri = ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_FILE, doubleCheck.getLong(doubleCheck.getColumnIndex(ProviderTableMeta._ID)));
-            doubleCheck.close();
-            return insertedFileUri;
+            updateFilesTableAccordingToShareInsertion(db, uri, values);
+            return insertedShareUri;
+            
+
+        default:
+            throw new IllegalArgumentException("Unknown uri id: " + uri);
         }
+        
     }
-
     
+    private void updateFilesTableAccordingToShareInsertion(
+            SQLiteDatabase db, Uri uri, ContentValues shareValues
+            ) {
+        ContentValues fileValues = new ContentValues();
+        fileValues.put(
+                ProviderTableMeta.FILE_SHARE_BY_LINK, 
+                ShareType.PUBLIC_LINK.getValue() == 
+                    shareValues.getAsInteger(ProviderTableMeta.OCSHARES_SHARE_TYPE)? 1 : 0
+        );
+        String whereShare = ProviderTableMeta.FILE_PATH + "=? AND " + 
+                ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?";
+        String[] whereArgsShare = new String[] {
+                shareValues.getAsString(ProviderTableMeta.OCSHARES_PATH), 
+                shareValues.getAsString(ProviderTableMeta.OCSHARES_ACCOUNT_OWNER)
+        };
+        db.update(ProviderTableMeta.FILE_TABLE_NAME, fileValues, whereShare, whereArgsShare);
+    }
+    
+
     @Override
     public boolean onCreate() {
         mDbHelper = new DataBaseHelper(getContext());
@@ -263,13 +391,22 @@ public class FileContentProvider extends ContentProvider {
         mUriMatcher.addURI(authority, "file/#", SINGLE_FILE);
         mUriMatcher.addURI(authority, "dir/", DIRECTORY);
         mUriMatcher.addURI(authority, "dir/#", DIRECTORY);
+        mUriMatcher.addURI(authority, "shares/", SHARES);
+        mUriMatcher.addURI(authority, "shares/#", SHARES);
         
         return true;
     }
 
     
     @Override
-    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
+    public Cursor query(
+            Uri uri, 
+            String[] projection, 
+            String selection, 
+            String[] selectionArgs, 
+            String sortOrder
+        ) {
+        
         Cursor result = null;
         SQLiteDatabase db = mDbHelper.getReadableDatabase();
         db.beginTransaction();
@@ -282,11 +419,19 @@ public class FileContentProvider extends ContentProvider {
         return result;
     }
     
-    private Cursor query(SQLiteDatabase db, Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
+    private Cursor query(
+            SQLiteDatabase db, 
+            Uri uri, 
+            String[] projection, 
+            String selection, 
+            String[] selectionArgs, 
+            String sortOrder
+        ) {
+        
         SQLiteQueryBuilder sqlQuery = new SQLiteQueryBuilder();
 
-        sqlQuery.setTables(ProviderTableMeta.DB_NAME);
-        sqlQuery.setProjectionMap(mProjectionMap);
+        sqlQuery.setTables(ProviderTableMeta.FILE_TABLE_NAME);
+        sqlQuery.setProjectionMap(mFileProjectionMap);
 
         switch (mUriMatcher.match(uri)) {
         case ROOT_DIRECTORY:
@@ -302,13 +447,26 @@ public class FileContentProvider extends ContentProvider {
                         + uri.getPathSegments().get(1));
             }
             break;
+        case SHARES: 
+            sqlQuery.setTables(ProviderTableMeta.OCSHARES_TABLE_NAME);
+            sqlQuery.setProjectionMap(mOCSharesProjectionMap);
+            if (uri.getPathSegments().size() > 1) {
+                sqlQuery.appendWhere(ProviderTableMeta._ID + "="
+                        + uri.getPathSegments().get(1));
+            }
+            break;
         default:
             throw new IllegalArgumentException("Unknown uri id: " + uri);
         }
 
         String order;
         if (TextUtils.isEmpty(sortOrder)) {
-            order = ProviderTableMeta.DEFAULT_SORT_ORDER;
+            if (mUriMatcher.match(uri) == SHARES) {
+                order = ProviderTableMeta.OCSHARES_DEFAULT_SORT_ORDER;
+            } else {
+
+                order = ProviderTableMeta.FILE_DEFAULT_SORT_ORDER;
+            }
         } else {
             order = sortOrder;
         }
@@ -323,7 +481,6 @@ public class FileContentProvider extends ContentProvider {
     @Override
     public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
         
-        //Log_OC.d(TAG, "Updating " + values.getAsString(ProviderTableMeta.FILE_PATH) + " at provider " + this);
         int count = 0;
         SQLiteDatabase db = mDbHelper.getWritableDatabase();
         db.beginTransaction();
@@ -338,16 +495,29 @@ public class FileContentProvider extends ContentProvider {
     }
     
     
-    private int update(SQLiteDatabase db, Uri uri, ContentValues values, String selection, String[] selectionArgs) {
+
+    private int update(
+            SQLiteDatabase db, 
+            Uri uri, 
+            ContentValues values, 
+            String selection, 
+            String[] selectionArgs
+        ) {
         switch (mUriMatcher.match(uri)) {
             case DIRECTORY:
-                return updateFolderSize(db, selectionArgs[0]);
+                return  0; //updateFolderSize(db, selectionArgs[0]);
+            case SHARES:
+                return db.update(
+                        ProviderTableMeta.OCSHARES_TABLE_NAME, values, selection, selectionArgs
+                );
             default:
-                return db.update(ProviderTableMeta.DB_NAME, values, selection, selectionArgs);
+                return db.update(
+                        ProviderTableMeta.FILE_TABLE_NAME, values, selection, selectionArgs
+                );
         }
     }    
 
-    
+ /*   
     private int updateFolderSize(SQLiteDatabase db, String folderId) {
         int count = 0;
         String [] whereArgs = new String[] { folderId };
@@ -384,7 +554,7 @@ public class FileContentProvider extends ContentProvider {
             Log_OC.d("FileContentProvider", "Updating " + folderSize + " to " + childrenSize);
             ContentValues cv = new ContentValues();
             cv.put(ProviderTableMeta.FILE_CONTENT_LENGTH, childrenSize);
-            count = db.update(ProviderTableMeta.DB_NAME, cv, folderWhere, whereArgs);
+            count = db.update(ProviderTableMeta.FILE_TABLE_NAME, cv, folderWhere, whereArgs);
             
             // propagate update until root
             if (folderParentId > FileDataStorageManager.ROOT_PARENT_ID) {
@@ -398,11 +568,13 @@ public class FileContentProvider extends ContentProvider {
         }
         return count;
     }
-
+*/
     
     @Override
-    public ContentProviderResult[] applyBatch (ArrayList<ContentProviderOperation> operations) throws OperationApplicationException {
-        Log_OC.d("FileContentProvider", "applying batch in provider " + this + " (temporary: " + isTemporary() + ")" );
+    public ContentProviderResult[] applyBatch (ArrayList<ContentProviderOperation> operations) 
+            throws OperationApplicationException {
+        Log_OC.d("FileContentProvider", "applying batch in provider " + this + 
+                " (temporary: " + isTemporary() + ")" );
         ContentProviderResult[] results = new ContentProviderResult[operations.size()];
         int i=0;
         
@@ -433,7 +605,7 @@ public class FileContentProvider extends ContentProvider {
         public void onCreate(SQLiteDatabase db) {
             // files table
             Log_OC.i("SQL", "Entering in onCreate");
-            db.execSQL("CREATE TABLE " + ProviderTableMeta.DB_NAME + "("
+            db.execSQL("CREATE TABLE " + ProviderTableMeta.FILE_TABLE_NAME + "("
                     + ProviderTableMeta._ID + " INTEGER PRIMARY KEY, "
                     + ProviderTableMeta.FILE_NAME + " TEXT, "
                     + ProviderTableMeta.FILE_PATH + " TEXT, "
@@ -448,8 +620,31 @@ public class FileContentProvider extends ContentProvider {
                     + ProviderTableMeta.FILE_KEEP_IN_SYNC + " INTEGER, "
                     + ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA + " INTEGER, "
                     + ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA + " INTEGER, "
-                    + ProviderTableMeta.FILE_ETAG + " TEXT );"
+                    + ProviderTableMeta.FILE_ETAG + " TEXT, " 
+                    + ProviderTableMeta.FILE_SHARE_BY_LINK + " INTEGER, "
+                    + ProviderTableMeta.FILE_PUBLIC_LINK  + " TEXT, "
+                    + ProviderTableMeta.FILE_PERMISSIONS  + " TEXT null,"
+                    + ProviderTableMeta.FILE_REMOTE_ID  + " TEXT null,"
+                    + ProviderTableMeta.FILE_UPDATE_THUMBNAIL  + " INTEGER);" //boolean
                     );
+            
+            // Create table ocshares
+            db.execSQL("CREATE TABLE " + ProviderTableMeta.OCSHARES_TABLE_NAME + "("
+                    + ProviderTableMeta._ID + " INTEGER PRIMARY KEY, "
+                    + ProviderTableMeta.OCSHARES_FILE_SOURCE + " INTEGER, "
+                    + ProviderTableMeta.OCSHARES_ITEM_SOURCE + " INTEGER, "
+                    + ProviderTableMeta.OCSHARES_SHARE_TYPE + " INTEGER, "
+                    + ProviderTableMeta.OCSHARES_SHARE_WITH + " TEXT, "
+                    + ProviderTableMeta.OCSHARES_PATH + " TEXT, "
+                    + ProviderTableMeta.OCSHARES_PERMISSIONS+ " INTEGER, "
+                    + ProviderTableMeta.OCSHARES_SHARED_DATE + " INTEGER, "
+                    + ProviderTableMeta.OCSHARES_EXPIRATION_DATE + " INTEGER, "
+                    + ProviderTableMeta.OCSHARES_TOKEN + " TEXT, "
+                    + ProviderTableMeta.OCSHARES_SHARE_WITH_DISPLAY_NAME + " TEXT, "
+                    + ProviderTableMeta.OCSHARES_IS_DIRECTORY + " INTEGER, "  // boolean
+                    + ProviderTableMeta.OCSHARES_USER_ID + " INTEGER, "
+                    + ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED + " INTEGER," 
+                    + ProviderTableMeta.OCSHARES_ACCOUNT_OWNER + " TEXT );" );
         }
 
         @Override
@@ -458,7 +653,7 @@ public class FileContentProvider extends ContentProvider {
             boolean upgraded = false; 
             if (oldVersion == 1 && newVersion >= 2) {
                 Log_OC.i("SQL", "Entering in the #1 ADD in onUpgrade");
-                db.execSQL("ALTER TABLE " + ProviderTableMeta.DB_NAME +
+                db.execSQL("ALTER TABLE " + ProviderTableMeta.FILE_TABLE_NAME +
                            " ADD COLUMN " + ProviderTableMeta.FILE_KEEP_IN_SYNC  + " INTEGER " +
                            " DEFAULT 0");
                 upgraded = true;
@@ -467,13 +662,14 @@ public class FileContentProvider extends ContentProvider {
                 Log_OC.i("SQL", "Entering in the #2 ADD in onUpgrade");
                 db.beginTransaction();
                 try {
-                    db.execSQL("ALTER TABLE " + ProviderTableMeta.DB_NAME +
-                               " ADD COLUMN " + ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA  + " INTEGER " +
-                               " DEFAULT 0");
+                    db.execSQL("ALTER TABLE " + ProviderTableMeta.FILE_TABLE_NAME +
+                               " ADD COLUMN " + ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA  + 
+                               " INTEGER " + " DEFAULT 0");
                     
                     // assume there are not local changes pending to upload
-                    db.execSQL("UPDATE " + ProviderTableMeta.DB_NAME + 
-                            " SET " + ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA + " = " + System.currentTimeMillis() + 
+                    db.execSQL("UPDATE " + ProviderTableMeta.FILE_TABLE_NAME + 
+                            " SET " + ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA + " = " 
+                            + System.currentTimeMillis() + 
                             " WHERE " + ProviderTableMeta.FILE_STORAGE_PATH + " IS NOT NULL");
                  
                     upgraded = true;
@@ -486,12 +682,13 @@ public class FileContentProvider extends ContentProvider {
                 Log_OC.i("SQL", "Entering in the #3 ADD in onUpgrade");
                 db.beginTransaction();
                 try {
-                    db .execSQL("ALTER TABLE " + ProviderTableMeta.DB_NAME +
-                           " ADD COLUMN " + ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA  + " INTEGER " +
-                           " DEFAULT 0");
+                    db .execSQL("ALTER TABLE " + ProviderTableMeta.FILE_TABLE_NAME +
+                           " ADD COLUMN " + ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA +
+                           " INTEGER " + " DEFAULT 0");
                 
-                    db.execSQL("UPDATE " + ProviderTableMeta.DB_NAME + 
-                           " SET " + ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA + " = " + ProviderTableMeta.FILE_MODIFIED + 
+                    db.execSQL("UPDATE " + ProviderTableMeta.FILE_TABLE_NAME + 
+                           " SET " + ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA + " = " +
+                            ProviderTableMeta.FILE_MODIFIED +
                            " WHERE " + ProviderTableMeta.FILE_STORAGE_PATH + " IS NOT NULL");
                 
                     upgraded = true;
@@ -501,13 +698,14 @@ public class FileContentProvider extends ContentProvider {
                 }
             }
             if (!upgraded)
-                Log_OC.i("SQL", "OUT of the ADD in onUpgrade; oldVersion == " + oldVersion + ", newVersion == " + newVersion);
+                Log_OC.i("SQL", "OUT of the ADD in onUpgrade; oldVersion == " + oldVersion + 
+                        ", newVersion == " + newVersion);
         
             if (oldVersion < 5 && newVersion >= 5) {
                 Log_OC.i("SQL", "Entering in the #4 ADD in onUpgrade");
                 db.beginTransaction();
                 try {
-                    db .execSQL("ALTER TABLE " + ProviderTableMeta.DB_NAME +
+                    db .execSQL("ALTER TABLE " + ProviderTableMeta.FILE_TABLE_NAME +
                             " ADD COLUMN " + ProviderTableMeta.FILE_ETAG + " TEXT " +
                             " DEFAULT NULL");
                     
@@ -518,7 +716,88 @@ public class FileContentProvider extends ContentProvider {
                 }
             }
             if (!upgraded)
-                Log_OC.i("SQL", "OUT of the ADD in onUpgrade; oldVersion == " + oldVersion + ", newVersion == " + newVersion);
+                Log_OC.i("SQL", "OUT of the ADD in onUpgrade; oldVersion == " + oldVersion + 
+                        ", newVersion == " + newVersion);
+
+            if (oldVersion < 6 && newVersion >= 6) {
+                Log_OC.i("SQL", "Entering in the #5 ADD in onUpgrade");
+                db.beginTransaction();
+                try {
+                    db .execSQL("ALTER TABLE " + ProviderTableMeta.FILE_TABLE_NAME +
+                            " ADD COLUMN " + ProviderTableMeta.FILE_SHARE_BY_LINK + " INTEGER " +
+                            " DEFAULT 0");
+                    
+                    db .execSQL("ALTER TABLE " + ProviderTableMeta.FILE_TABLE_NAME +
+                            " ADD COLUMN " + ProviderTableMeta.FILE_PUBLIC_LINK + " TEXT " +
+                            " DEFAULT NULL");
+
+                    // Create table ocshares
+                    db.execSQL("CREATE TABLE " + ProviderTableMeta.OCSHARES_TABLE_NAME + "("
+                            + ProviderTableMeta._ID + " INTEGER PRIMARY KEY, "
+                            + ProviderTableMeta.OCSHARES_FILE_SOURCE + " INTEGER, "
+                            + ProviderTableMeta.OCSHARES_ITEM_SOURCE + " INTEGER, "
+                            + ProviderTableMeta.OCSHARES_SHARE_TYPE + " INTEGER, "
+                            + ProviderTableMeta.OCSHARES_SHARE_WITH + " TEXT, "
+                            + ProviderTableMeta.OCSHARES_PATH + " TEXT, "
+                            + ProviderTableMeta.OCSHARES_PERMISSIONS+ " INTEGER, "
+                            + ProviderTableMeta.OCSHARES_SHARED_DATE + " INTEGER, "
+                            + ProviderTableMeta.OCSHARES_EXPIRATION_DATE + " INTEGER, "
+                            + ProviderTableMeta.OCSHARES_TOKEN + " TEXT, "
+                            + ProviderTableMeta.OCSHARES_SHARE_WITH_DISPLAY_NAME + " TEXT, "
+                            + ProviderTableMeta.OCSHARES_IS_DIRECTORY + " INTEGER, "  // boolean
+                            + ProviderTableMeta.OCSHARES_USER_ID + " INTEGER, "
+                            + ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED + " INTEGER," 
+                            + ProviderTableMeta.OCSHARES_ACCOUNT_OWNER + " TEXT );" );
+
+                    upgraded = true;
+                    db.setTransactionSuccessful();
+                } finally {
+                    db.endTransaction();
+                }
+            }
+            if (!upgraded)
+                Log_OC.i("SQL", "OUT of the ADD in onUpgrade; oldVersion == " + oldVersion + 
+                        ", newVersion == " + newVersion);
+
+            if (oldVersion < 7 && newVersion >= 7) {
+                Log_OC.i("SQL", "Entering in the #7 ADD in onUpgrade");
+                db.beginTransaction();
+                try {
+                    db .execSQL("ALTER TABLE " + ProviderTableMeta.FILE_TABLE_NAME +
+                            " ADD COLUMN " + ProviderTableMeta.FILE_PERMISSIONS + " TEXT " +
+                            " DEFAULT NULL");
+
+                    db .execSQL("ALTER TABLE " + ProviderTableMeta.FILE_TABLE_NAME +
+                            " ADD COLUMN " + ProviderTableMeta.FILE_REMOTE_ID + " TEXT " +
+                            " DEFAULT NULL");
+                    
+                    upgraded = true;
+                    db.setTransactionSuccessful();
+                } finally {
+                    db.endTransaction();
+                }
+            }
+            if (!upgraded)
+                Log_OC.i("SQL", "OUT of the ADD in onUpgrade; oldVersion == " + oldVersion + 
+                        ", newVersion == " + newVersion);
+
+            if (oldVersion < 8 && newVersion >= 8) {
+                Log_OC.i("SQL", "Entering in the #8 ADD in onUpgrade");
+                db.beginTransaction();
+                try {
+                    db .execSQL("ALTER TABLE " + ProviderTableMeta.FILE_TABLE_NAME +
+                            " ADD COLUMN " + ProviderTableMeta.FILE_UPDATE_THUMBNAIL + " INTEGER " +
+                            " DEFAULT 0");
+
+                    upgraded = true;
+                    db.setTransactionSuccessful();
+                } finally {
+                    db.endTransaction();
+                }
+            }
+            if (!upgraded)
+                Log_OC.i("SQL", "OUT of the ADD in onUpgrade; oldVersion == " + oldVersion + 
+                        ", newVersion == " + newVersion);
         }
     }
 
diff --git a/src/com/owncloud/android/services/OperationsService.java b/src/com/owncloud/android/services/OperationsService.java
new file mode 100644 (file)
index 0000000..a5bb22d
--- /dev/null
@@ -0,0 +1,628 @@
+/* ownCloud Android client application
+ *   Copyright (C) 2012-2014 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.services;
+
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.ConcurrentMap;
+
+import com.owncloud.android.MainApp;
+import com.owncloud.android.R;
+import com.owncloud.android.datamodel.FileDataStorageManager;
+import com.owncloud.android.lib.common.OwnCloudAccount;
+import com.owncloud.android.lib.common.OwnCloudClient;
+import com.owncloud.android.lib.common.OwnCloudClientManagerFactory;
+import com.owncloud.android.lib.common.OwnCloudCredentials;
+import com.owncloud.android.lib.common.OwnCloudCredentialsFactory;
+import com.owncloud.android.lib.common.accounts.AccountUtils.AccountNotFoundException;
+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;
+import com.owncloud.android.operations.CreateFolderOperation;
+import com.owncloud.android.operations.CreateShareOperation;
+import com.owncloud.android.operations.GetServerInfoOperation;
+import com.owncloud.android.operations.MoveFileOperation;
+import com.owncloud.android.operations.OAuth2GetAccessToken;
+import com.owncloud.android.operations.RemoveFileOperation;
+import com.owncloud.android.operations.RenameFileOperation;
+import com.owncloud.android.operations.SynchronizeFileOperation;
+import com.owncloud.android.operations.UnshareLinkOperation;
+
+import android.accounts.Account;
+import android.accounts.AccountsException;
+import android.accounts.AuthenticatorException;
+import android.accounts.OperationCanceledException;
+import android.app.Service;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Process;
+import android.util.Pair;
+
+public class OperationsService extends Service {
+    
+    private static final String TAG = OperationsService.class.getSimpleName();
+    
+    public static final String EXTRA_ACCOUNT = "ACCOUNT";
+    public static final String EXTRA_SERVER_URL = "SERVER_URL";
+    public static final String EXTRA_OAUTH2_QUERY_PARAMETERS = "OAUTH2_QUERY_PARAMETERS";
+    public static final String EXTRA_REMOTE_PATH = "REMOTE_PATH";
+    public static final String EXTRA_SEND_INTENT = "SEND_INTENT";
+    public static final String EXTRA_NEWNAME = "NEWNAME";
+    public static final String EXTRA_REMOVE_ONLY_LOCAL = "REMOVE_LOCAL_COPY";
+    public static final String EXTRA_CREATE_FULL_PATH = "CREATE_FULL_PATH";
+    public static final String EXTRA_SYNC_FILE_CONTENTS = "SYNC_FILE_CONTENTS";
+    public static final String EXTRA_RESULT = "RESULT";
+    public static final String EXTRA_NEW_PARENT_PATH = "NEW_PARENT_PATH";
+    
+    // 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_MOVE_FILE = "MOVE_FILE";
+    
+    public static final String ACTION_OPERATION_ADDED = OperationsService.class.getName() + ".OPERATION_ADDED";
+    public static final String ACTION_OPERATION_FINISHED = OperationsService.class.getName() + ".OPERATION_FINISHED";
+
+    private ConcurrentLinkedQueue<Pair<Target, RemoteOperation>> mPendingOperations = 
+            new ConcurrentLinkedQueue<Pair<Target, RemoteOperation>>();
+
+    private ConcurrentMap<Integer, Pair<RemoteOperation, RemoteOperationResult>> 
+        mUndispatchedFinishedOperations =
+            new ConcurrentHashMap<Integer, Pair<RemoteOperation, RemoteOperationResult>>();
+    
+    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) {
+            mAccount = account;
+            mServerUrl = serverUrl;
+            mUsername = username;
+            mPassword = password;
+            mAuthToken = authToken;
+            mCookie = cookie;
+        }
+    }
+
+    private Looper mServiceLooper;
+    private ServiceHandler mServiceHandler;
+    private OperationsServiceBinder mBinder;
+    private OwnCloudClient mOwnCloudClient = null;
+    private Target mLastTarget = null;
+    private FileDataStorageManager mStorageManager;
+    private RemoteOperation mCurrentOperation = null;
+    
+    
+    /**
+     * Service initialization
+     */
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        HandlerThread thread = new HandlerThread("Operations service thread", Process.THREAD_PRIORITY_BACKGROUND);
+        thread.start();
+        mServiceLooper = thread.getLooper();
+        mServiceHandler = new ServiceHandler(mServiceLooper, this);
+        mBinder = new OperationsServiceBinder();
+    }
+
+    
+    /**
+     * Entry point to add a new operation to the queue of operations.
+     * 
+     * New operations 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.
+     * 
+     * IMPORTANT: the only operations performed here right now is {@link GetSharedFilesOperation}. The class
+     * is taking advantage of it due to time constraints.
+     */
+    @Override
+    public int onStartCommand(Intent intent, int flags, int startId) {
+        //Log_OC.wtf(TAG, "onStartCommand init" );
+        Message msg = mServiceHandler.obtainMessage();
+        msg.arg1 = startId;
+        mServiceHandler.sendMessage(msg);
+        //Log_OC.wtf(TAG, "onStartCommand end" );
+        return START_NOT_STICKY;
+    }
+
+    @Override
+    public void onDestroy() {
+        //Log_OC.wtf(TAG, "onDestroy init" );
+        // Saving cookies
+        try {
+            OwnCloudClientManagerFactory.getDefaultSingleton().
+                saveAllClients(this, MainApp.getAccountType());
+            
+            // 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();
+        }
+        
+        //Log_OC.wtf(TAG, "Clear mUndispatchedFinisiedOperations" );
+        mUndispatchedFinishedOperations.clear();
+        
+        //Log_OC.wtf(TAG, "onDestroy end" );
+        super.onDestroy();
+    }
+
+
+    /**
+     * Provides a binder object that clients can use to perform actions on the queue of operations, 
+     * except the addition of new operations. 
+     */
+    @Override
+    public IBinder onBind(Intent intent) {
+        //Log_OC.wtf(TAG, "onBind" );
+        return mBinder;
+    }
+
+    
+    /**
+     * Called when ALL the bound clients were unbound.
+     */
+    @Override
+    public boolean onUnbind(Intent intent) {
+        ((OperationsServiceBinder)mBinder).clearListeners();
+        return false;   // not accepting rebinding (default behaviour)
+    }
+
+    
+    /**
+     *  Binder to let client components to perform actions on the queue of operations.
+     * 
+     *  It provides by itself the available operations.
+     */
+    public class OperationsServiceBinder extends Binder /* implements OnRemoteOperationListener */ {
+        
+        /** 
+         * Map of listeners that will be reported about the end of operations from a {@link OperationsServiceBinder} instance 
+         */
+        private ConcurrentMap<OnRemoteOperationListener, Handler> mBoundListeners = 
+                new ConcurrentHashMap<OnRemoteOperationListener, Handler>();
+        
+        /**
+         * Cancels an operation
+         *
+         * TODO
+         */
+        public void cancel() {
+            // TODO
+        }
+        
+        
+        public void clearListeners() {
+            
+            mBoundListeners.clear();
+        }
+
+        
+        /**
+         * Adds a listener interested in being reported about the end of operations.
+         * 
+         * @param listener          Object to notify about the end of operations.    
+         * @param callbackHandler   {@link Handler} to access the listener without breaking Android threading protection.
+         */
+        public void addOperationListener (OnRemoteOperationListener listener, Handler callbackHandler) {
+            synchronized (mBoundListeners) {
+                mBoundListeners.put(listener, callbackHandler);
+            }
+        }
+        
+        
+        /**
+         * Removes a listener from the list of objects interested in the being reported about the end of operations.
+         * 
+         * @param listener      Object to notify about progress of transfer.    
+         */
+        public void removeOperationListener (OnRemoteOperationListener listener) {
+            synchronized (mBoundListeners) {
+                mBoundListeners.remove(listener);
+            }
+        }
+
+
+        /**
+         * TODO - IMPORTANT: update implementation when more operations are moved into the service 
+         * 
+         * @return  'True' when an operation that enforces the user to wait for completion is in process.
+         */
+        public boolean isPerformingBlockingOperation() {
+            return (!mPendingOperations.isEmpty());
+        }
+
+
+        /**
+         * Creates and adds to the queue a new operation, as described by operationIntent
+         * 
+         * @param operationIntent       Intent describing a new operation to queue and execute.
+         * @return                      Identifier of the operation created, or null if failed.
+         */
+        public long newOperation(Intent operationIntent) {
+            RemoteOperation operation = null;
+            Target target = null;
+            try {
+                if (!operationIntent.hasExtra(EXTRA_ACCOUNT) && 
+                        !operationIntent.hasExtra(EXTRA_SERVER_URL)) {
+                    Log_OC.e(TAG, "Not enough information provided in intent");
+                    
+                } 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);
+                        Intent sendIntent = operationIntent.getParcelableExtra(EXTRA_SEND_INTENT);
+                        if (remotePath.length() > 0) {
+                            operation = new CreateShareOperation(remotePath, ShareType.PUBLIC_LINK, 
+                                    "", false, "", 1, sendIntent);
+                        }
+                        
+                    } else if (action.equals(ACTION_UNSHARE)) {  // Unshare file
+                        String remotePath = operationIntent.getStringExtra(EXTRA_REMOTE_PATH);
+                        if (remotePath.length() > 0) {
+                            operation = new UnshareLinkOperation(
+                                    remotePath, 
+                                    OperationsService.this);
+                        }
+                        
+                    } else if (action.equals(ACTION_GET_SERVER_INFO)) { 
+                        // check OC server and get basic information from it
+                        operation = new GetServerInfoOperation(serverUrl, OperationsService.this);
+                        
+                    } else if (action.equals(ACTION_OAUTH2_GET_ACCESS_TOKEN)) {
+                        /// GET ACCESS TOKEN to the OAuth server
+                        String oauth2QueryParameters =
+                                operationIntent.getStringExtra(EXTRA_OAUTH2_QUERY_PARAMETERS);
+                        operation = new OAuth2GetAccessToken(
+                                getString(R.string.oauth2_client_id), 
+                                getString(R.string.oauth2_redirect_uri),       
+                                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();
+                        
+                    } else if (action.equals(ACTION_RENAME)) {
+                        // Rename file or folder
+                        String remotePath = operationIntent.getStringExtra(EXTRA_REMOTE_PATH);
+                        String newName = operationIntent.getStringExtra(EXTRA_NEWNAME);
+                        operation = new RenameFileOperation(remotePath, account, newName);
+                        
+                    } else if (action.equals(ACTION_REMOVE)) {
+                        // Remove file or folder
+                        String remotePath = operationIntent.getStringExtra(EXTRA_REMOTE_PATH);
+                        boolean onlyLocalCopy = operationIntent.getBooleanExtra(EXTRA_REMOVE_ONLY_LOCAL, false);
+                        operation = new RemoveFileOperation(remotePath, onlyLocalCopy);
+                        
+                    } else if (action.equals(ACTION_CREATE_FOLDER)) {
+                        // Create Folder
+                        String remotePath = operationIntent.getStringExtra(EXTRA_REMOTE_PATH);
+                        boolean createFullPath = operationIntent.getBooleanExtra(EXTRA_CREATE_FULL_PATH, true);
+                        operation = new CreateFolderOperation(remotePath, createFullPath);
+                        
+                    } else if (action.equals(ACTION_SYNC_FILE)) {
+                        // Sync file
+                        String remotePath = operationIntent.getStringExtra(EXTRA_REMOTE_PATH);
+                        boolean syncFileContents = operationIntent.getBooleanExtra(EXTRA_SYNC_FILE_CONTENTS, true);
+                        operation = new SynchronizeFileOperation(remotePath, account, syncFileContents, getApplicationContext());
+                    } else if (action.equals(ACTION_MOVE_FILE)) {
+                        // Move file/folder
+                        String remotePath = operationIntent.getStringExtra(EXTRA_REMOTE_PATH);
+                        String newParentPath = operationIntent.getStringExtra(EXTRA_NEW_PARENT_PATH);
+                        operation = new MoveFileOperation(remotePath,newParentPath,account);
+                    }
+                    
+                }
+                    
+            } catch (IllegalArgumentException e) {
+                Log_OC.e(TAG, "Bad information provided in intent: " + e.getMessage());
+                operation = null;
+            }
+
+            if (operation != null) {
+                mPendingOperations.add(new Pair<Target , RemoteOperation>(target, operation));
+                startService(new Intent(OperationsService.this, OperationsService.class));
+                //Log_OC.wtf(TAG, "New operation added, opId: " + operation.hashCode());
+                // better id than hash? ; should be good enough by the time being
+                return operation.hashCode();
+                
+            } else {
+                //Log_OC.wtf(TAG, "New operation failed, returned Long.MAX_VALUE");
+                return Long.MAX_VALUE;
+            }
+        }
+
+        public boolean dispatchResultIfFinished(int operationId, OnRemoteOperationListener listener) {
+            Pair<RemoteOperation, RemoteOperationResult> undispatched = 
+                    mUndispatchedFinishedOperations.remove(operationId);
+            if (undispatched != null) {
+                listener.onRemoteOperationFinish(undispatched.first, undispatched.second);
+                return true;
+                //Log_OC.wtf(TAG, "Sending callback later");
+            } else {
+                if (!mPendingOperations.isEmpty()) {
+                    return true;
+                } else {
+                    return false;
+                }
+                //Log_OC.wtf(TAG, "Not finished yet");
+            }
+        }
+
+    }
+    
+    
+    /** 
+     * Operations worker. Performs the pending operations in the order they were requested. 
+     * 
+     * Created with the Looper of a new thread, started in {@link OperationsService#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
+        OperationsService mService;
+        public ServiceHandler(Looper looper, OperationsService service) {
+            super(looper);
+            if (service == null) {
+                throw new IllegalArgumentException("Received invalid NULL in parameter 'service'");
+            }
+            mService = service;
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            mService.nextOperation();
+            mService.stopSelf(msg.arg1);
+        }
+    }
+    
+
+    /**
+     * Performs the next operation in the queue
+     */
+    private void nextOperation() {
+        
+        //Log_OC.wtf(TAG, "nextOperation init" );
+        
+        Pair<Target, RemoteOperation> next = null;
+        synchronized(mPendingOperations) {
+            next = mPendingOperations.peek();
+        }
+
+        if (next != null) {
+            
+            mCurrentOperation = next.second;
+            RemoteOperationResult result = null;
+            try {
+                /// prepare client object to send the request to the ownCloud server
+                if (mLastTarget == null || !mLastTarget.equals(next.first)) {
+                    mLastTarget = next.first;
+                    if (mLastTarget.mAccount != null) {
+                        OwnCloudAccount ocAccount = new OwnCloudAccount(mLastTarget.mAccount, this);
+                        mOwnCloudClient = OwnCloudClientManagerFactory.getDefaultSingleton().
+                                getClientFor(ocAccount, this);
+                        mStorageManager = 
+                                new FileDataStorageManager(
+                                        mLastTarget.mAccount, 
+                                        getContentResolver());
+                    } 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 &&
+                                mLastTarget.mCookie.length() > 0) {
+                            credentials = OwnCloudCredentialsFactory.newSamlSsoCredentials(
+                                    mLastTarget.mCookie); // SAML SSO
+                        }
+                        OwnCloudAccount ocAccount = new OwnCloudAccount(
+                                mLastTarget.mServerUrl, credentials);
+                        mOwnCloudClient = OwnCloudClientManagerFactory.getDefaultSingleton().
+                                getClientFor(ocAccount, this);
+                        mStorageManager = null;
+                    }
+                }
+
+                /// perform the operation
+                if (mCurrentOperation instanceof SyncOperation) {
+                    result = ((SyncOperation)mCurrentOperation).execute(mOwnCloudClient, mStorageManager);
+                } else {
+                    result = mCurrentOperation.execute(mOwnCloudClient);
+                }
+                
+            } catch (AccountsException e) {
+                if (mLastTarget.mAccount == null) {
+                    Log_OC.e(TAG, "Error while trying to get authorization for a NULL account", e);
+                } else {
+                    Log_OC.e(TAG, "Error while trying to get authorization for " + mLastTarget.mAccount.name, e);
+                }
+                result = new RemoteOperationResult(e);
+                
+            } catch (IOException e) {
+                if (mLastTarget.mAccount == null) {
+                    Log_OC.e(TAG, "Error while trying to get authorization for a NULL account", e);
+                } else {
+                    Log_OC.e(TAG, "Error while trying to get authorization for " + mLastTarget.mAccount.name, e);
+                }
+                result = new RemoteOperationResult(e);
+            } catch (Exception e) {
+                if (mLastTarget.mAccount == null) {
+                    Log_OC.e(TAG, "Unexpected error for a NULL account", e);
+                } else {
+                    Log_OC.e(TAG, "Unexpected error for " + mLastTarget.mAccount.name, e);
+                }
+                result = new RemoteOperationResult(e);
+            
+            } finally {
+                synchronized(mPendingOperations) {
+                    mPendingOperations.poll();
+                }
+            }
+            
+            //sendBroadcastOperationFinished(mLastTarget, mCurrentOperation, result);
+            dispatchResultToOperationListeners(mLastTarget, mCurrentOperation, result);
+        }
+    }
+
+
+    /**
+     * Sends a broadcast when a new operation is added to the queue.
+     * 
+     * Local broadcasts are only delivered to activities in the same process, but can't be done sticky :\
+     * 
+     * @param target            Account or URL pointing to an OC server.
+     * @param operation         Added operation.
+     */
+    private void sendBroadcastNewOperation(Target target, RemoteOperation operation) {
+        Intent intent = new Intent(ACTION_OPERATION_ADDED);
+        if (target.mAccount != null) {
+            intent.putExtra(EXTRA_ACCOUNT, target.mAccount);    
+        } else {
+            intent.putExtra(EXTRA_SERVER_URL, target.mServerUrl);    
+        }
+        //LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(this);
+        //lbm.sendBroadcast(intent);
+        sendStickyBroadcast(intent);
+    }
+
+    
+    // TODO - maybe add a notification for real start of operations
+    
+    /**
+     * Sends a LOCAL broadcast when an operations finishes in order to the interested activities can update their view
+     * 
+     * Local broadcasts are only delivered to activities in the same process.
+     * 
+     * @param target            Account or URL pointing to an OC server.
+     * @param operation         Finished operation.
+     * @param result            Result of the operation.
+     */
+    private void sendBroadcastOperationFinished(Target target, RemoteOperation operation, RemoteOperationResult result) {
+        Intent intent = new Intent(ACTION_OPERATION_FINISHED);
+        intent.putExtra(EXTRA_RESULT, result);
+        if (target.mAccount != null) {
+            intent.putExtra(EXTRA_ACCOUNT, target.mAccount);    
+        } else {
+            intent.putExtra(EXTRA_SERVER_URL, target.mServerUrl);    
+        }
+        //LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(this);
+        //lbm.sendBroadcast(intent);
+        sendStickyBroadcast(intent);
+    }
+
+    
+    /**
+     * 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.
+     */
+    private void dispatchResultToOperationListeners(
+            Target target, final RemoteOperation operation, final RemoteOperationResult result) {
+        int count = 0;
+        Iterator<OnRemoteOperationListener> listeners = mBinder.mBoundListeners.keySet().iterator();
+        while (listeners.hasNext()) {
+            final OnRemoteOperationListener listener = listeners.next();
+            final Handler handler = mBinder.mBoundListeners.get(listener);
+            if (handler != null) { 
+                handler.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        listener.onRemoteOperationFinish(operation, result);
+                    }
+                });
+                count += 1;
+            }
+        }
+        if (count == 0) {
+            //mOperationResults.put(operation.hashCode(), result);
+            Pair<RemoteOperation, RemoteOperationResult> undispatched = 
+                    new Pair<RemoteOperation, RemoteOperationResult>(operation, result);
+            mUndispatchedFinishedOperations.put(operation.hashCode(), undispatched);
+        }
+        Log_OC.d(TAG, "Called " + count + " listeners");
+    }
+    
+
+}
diff --git a/src/com/owncloud/android/services/observer/FileObserverService.java b/src/com/owncloud/android/services/observer/FileObserverService.java
new file mode 100644 (file)
index 0000000..114f0e4
--- /dev/null
@@ -0,0 +1,376 @@
+/* ownCloud Android client application
+ *   Copyright (C) 2012 Bartek Przybylski
+ *   Copyright (C) 2012-2014 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.services.observer;
+
+import java.io.File;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import android.accounts.Account;
+import android.app.Service;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.database.Cursor;
+import android.os.IBinder;
+
+import com.owncloud.android.MainApp;
+import com.owncloud.android.authentication.AccountUtils;
+import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.db.ProviderMeta.ProviderTableMeta;
+import com.owncloud.android.files.services.FileDownloader;
+import com.owncloud.android.lib.common.utils.Log_OC;
+import com.owncloud.android.operations.SynchronizeFileOperation;
+import com.owncloud.android.utils.FileStorageUtils;
+
+
+/**
+ * Service keeping a list of {@link FolderObserver} instances that watch for local
+ * changes in favorite files (formerly known as kept-in-sync files) and try to
+ * synchronize them with the OC server as soon as possible.
+ * 
+ * Tries to be alive as long as possible; that is the reason why stopSelf() is
+ * never called.
+ * 
+ * It is expected that the system eventually kills the service when runs low of
+ * 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 {
+
+    public final static String MY_NAME = FileObserverService.class.getCanonicalName();
+    public final static String ACTION_START_OBSERVE = MY_NAME + ".action.START_OBSERVATION";
+    public final static String ACTION_ADD_OBSERVED_FILE = MY_NAME + ".action.ADD_OBSERVED_FILE";
+    public final static String ACTION_DEL_OBSERVED_FILE = MY_NAME + ".action.DEL_OBSERVED_FILE";
+
+    private final static String ARG_FILE = "ARG_FILE";
+    private final static String ARG_ACCOUNT = "ARG_ACCOUNT";
+
+    private static String TAG = FileObserverService.class.getSimpleName();
+
+    private Map<String, FolderObserver> mFolderObserversMap;
+    private DownloadCompletedReceiver mDownloadReceiver;
+
+    /**
+     * Factory method to create intents that allow to start an ACTION_START_OBSERVE command.
+     * 
+     * @param context   Android context of the caller component.
+     * @return          Intent that starts a command ACTION_START_OBSERVE when
+     *                  {@link Context#startService(Intent)} is called.
+     */
+    public static Intent makeInitIntent(Context context) {
+        Intent i = new Intent(context, FileObserverService.class);
+        i.setAction(ACTION_START_OBSERVE);
+        return i;
+    }
+
+    /**
+     * Factory method to create intents that allow to start or stop the
+     * observance of a file.
+     * 
+     * @param context       Android context of the caller component.
+     * @param file          OCFile to start or stop to watch.
+     * @param account       OC account containing file.
+     * @param watchIt       'True' creates an intent to watch, 'false' an intent to stop watching.
+     * @return              Intent to start or stop the observance of a file through a call
+     *                      to {@link Context#startService(Intent)}.
+     */
+    public static Intent makeObservedFileIntent(
+            Context context, OCFile file, Account account, boolean watchIt) {
+        Intent intent = new Intent(context, FileObserverService.class);
+        intent.setAction(watchIt ? FileObserverService.ACTION_ADD_OBSERVED_FILE
+                : FileObserverService.ACTION_DEL_OBSERVED_FILE);
+        intent.putExtra(FileObserverService.ARG_FILE, file);
+        intent.putExtra(FileObserverService.ARG_ACCOUNT, account);
+        return intent;
+    }
+
+    /**
+     * Initialize the service. 
+     */
+    @Override
+    public void onCreate() {
+        Log_OC.d(TAG, "onCreate");
+        super.onCreate();
+
+        mDownloadReceiver = new DownloadCompletedReceiver();
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(FileDownloader.getDownloadAddedMessage());
+        filter.addAction(FileDownloader.getDownloadFinishMessage());
+        registerReceiver(mDownloadReceiver, filter);
+
+        mFolderObserversMap = new HashMap<String, FolderObserver>();
+    }
+
+    /**
+     * Release resources.
+     */
+    @Override
+    public void onDestroy() {
+        Log_OC.d(TAG, "onDestroy - finishing observation of favorite files");
+
+        unregisterReceiver(mDownloadReceiver);
+
+        Iterator<FolderObserver> itOCFolder = mFolderObserversMap.values().iterator();
+        while (itOCFolder.hasNext()) {
+            itOCFolder.next().stopWatching();
+        }
+        mFolderObserversMap.clear();
+        mFolderObserversMap = null;
+
+        super.onDestroy();
+    }
+
+    /**
+     * This service cannot be bound.
+     */
+    @Override
+    public IBinder onBind(Intent intent) {
+        return null;
+    }
+
+    /**
+     * Handles requests to:
+     *  - (re)start watching                    (ACTION_START_OBSERVE)
+     *  - add an {@link OCFile} to be watched   (ATION_ADD_OBSERVED_FILE)
+     *  - stop observing an {@link OCFile}      (ACTION_DEL_OBSERVED_FILE) 
+     */
+    @Override
+    public int onStartCommand(Intent intent, int flags, int startId) {
+        Log_OC.d(TAG, "Starting command " + intent);
+
+        if (intent == null || ACTION_START_OBSERVE.equals(intent.getAction())) {
+            // NULL occurs when system tries to restart the service after its
+            // process was killed
+            startObservation();
+            return Service.START_STICKY;
+
+        } else if (ACTION_ADD_OBSERVED_FILE.equals(intent.getAction())) {
+            OCFile file = (OCFile) intent.getParcelableExtra(ARG_FILE);
+            Account account = (Account) intent.getParcelableExtra(ARG_ACCOUNT);
+            addObservedFile(file, account);
+
+        } else if (ACTION_DEL_OBSERVED_FILE.equals(intent.getAction())) {
+            removeObservedFile((OCFile) intent.getParcelableExtra(ARG_FILE),
+                    (Account) intent.getParcelableExtra(ARG_ACCOUNT));
+
+        } else {
+            Log_OC.e(TAG, "Unknown action recieved; ignoring it: " + intent.getAction());
+        }
+
+        return Service.START_STICKY;
+    }
+
+    
+    /**
+     * Read from the local database the list of files that must to be kept
+     * synchronized and starts observers to monitor local changes on them.
+     * 
+     * Updates the list of currently observed files if called multiple times.
+     */
+    private void startObservation() {
+        Log_OC.d(TAG, "Loading all kept-in-sync files from database to start watching them");
+
+        // query for any favorite file in any OC account
+        Cursor cursorOnKeptInSync = getContentResolver().query(
+                ProviderTableMeta.CONTENT_URI, 
+                null,
+                ProviderTableMeta.FILE_KEEP_IN_SYNC + " = ?", 
+                new String[] { String.valueOf(1) }, 
+                null
+        );
+
+        if (cursorOnKeptInSync != null) {
+
+            if (cursorOnKeptInSync.moveToFirst()) {
+
+                String localPath = "";
+                String accountName = "";
+                Account account = null;
+                do {
+                    localPath = cursorOnKeptInSync.getString(cursorOnKeptInSync
+                            .getColumnIndex(ProviderTableMeta.FILE_STORAGE_PATH));
+                    accountName = cursorOnKeptInSync.getString(cursorOnKeptInSync
+                            .getColumnIndex(ProviderTableMeta.FILE_ACCOUNT_OWNER));
+
+                    account = new Account(accountName, MainApp.getAccountType());
+                    if (!AccountUtils.exists(account, this) || localPath == null || localPath.length() <= 0) {
+                        continue;
+                    }
+                    
+                    addObservedFile(localPath, account);
+
+                } while (cursorOnKeptInSync.moveToNext());
+
+            }
+            cursorOnKeptInSync.close();
+        }
+
+        // service does not stopSelf() ; that way it tries to be alive forever
+
+    }
+
+    
+    /**
+     * Registers the local copy of a remote file to be observed for local
+     * changes, an automatically updated in the ownCloud server.
+     * 
+     * This method does NOT perform a {@link SynchronizeFileOperation} over the
+     * file.
+     * 
+     * @param file      Object representing a remote file which local copy must be observed.
+     * @param account   OwnCloud account containing file.
+     */
+    private void addObservedFile(OCFile file, Account account) {
+        Log_OC.v(TAG, "Adding a file to be watched");
+
+        if (file == null) {
+            Log_OC.e(TAG, "Trying to add a NULL file to observer");
+            return;
+        }
+        if (account == null) {
+            Log_OC.e(TAG, "Trying to add a file with a NULL account to observer");
+            return;
+        }
+
+        String localPath = file.getStoragePath();
+        if (localPath == null || localPath.length() <= 0) {
+            // file downloading or to be downloaded for the first time
+            localPath = FileStorageUtils.getDefaultSavePathFor(account.name, file);
+        }
+        
+        addObservedFile(localPath, account);
+        
+    }
+
+    
+    
+    
+    /**
+     * Registers a local file to be observed for changes.
+     * 
+     * @param localPath     Absolute path in the local file system to the file to be observed.
+     * @param account       OwnCloud account associated to the local file.
+     */
+    private void addObservedFile(String localPath, Account account) {
+        File file = new File(localPath);
+        String parentPath = file.getParent();
+        FolderObserver observer = mFolderObserversMap.get(parentPath);
+        if (observer == null) {
+            observer = new FolderObserver(parentPath, account, getApplicationContext());
+            mFolderObserversMap.put(parentPath, observer);
+            Log_OC.d(TAG, "Observer added for parent folder " + parentPath + "/");
+        }
+        
+        observer.startWatching(file.getName());
+        Log_OC.d(TAG, "Added " + localPath + " to list of observed children");
+    }
+
+    
+    /**
+     * Unregisters the local copy of a remote file to be observed for local changes.
+     * 
+     * @param file      Object representing a remote file which local copy must be not 
+     *                  observed longer.
+     * @param account   OwnCloud account containing file.
+     */
+    private void removeObservedFile(OCFile file, Account account) {
+        Log_OC.v(TAG, "Removing a file from being watched");
+
+        if (file == null) {
+            Log_OC.e(TAG, "Trying to remove a NULL file");
+            return;
+        }
+        if (account == null) {
+            Log_OC.e(TAG, "Trying to add a file with a NULL account to observer");
+            return;
+        }
+
+        String localPath = file.getStoragePath();
+        if (localPath == null || localPath.length() <= 0) {
+            localPath = FileStorageUtils.getDefaultSavePathFor(account.name, file);
+        }
+
+        removeObservedFile(localPath);
+    }
+
+    
+    /**
+     * Unregisters a local file from being observed for changes.
+     * 
+     * @param localPath     Absolute path in the local file system to the target file.
+     */
+    private void removeObservedFile(String localPath) {
+        File file = new File(localPath);
+        String parentPath = file.getParent();
+        FolderObserver observer = mFolderObserversMap.get(parentPath);
+        if (observer != null) {
+            observer.stopWatching(file.getName());
+            if (observer.isEmpty()) {
+                mFolderObserversMap.remove(parentPath);
+                Log_OC.d(TAG, "Observer removed for parent folder " + parentPath + "/");
+            }
+        
+        } else {
+            Log_OC.d(TAG, "No observer to remove for path " + localPath);
+        }
+    }
+
+    
+    /**
+     * Private receiver listening to events broadcasted by the {@link FileDownloader} service.
+     * 
+     * Pauses and resumes the observance on registered files while being download,
+     * in order to avoid to unnecessary synchronizations.
+     */
+    private class DownloadCompletedReceiver extends BroadcastReceiver {
+
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            Log_OC.d(TAG, "Received broadcast intent " + intent);
+
+            File downloadedFile = new File(intent.getStringExtra(FileDownloader.EXTRA_FILE_PATH));
+            String parentPath = downloadedFile.getParent();
+            FolderObserver observer = mFolderObserversMap.get(parentPath);
+            if (observer != null) {
+                if (intent.getAction().equals(FileDownloader.getDownloadFinishMessage())
+                        && downloadedFile.exists()) {
+                    // no matter if the download was successful or not; the
+                    // file could be down anyway due to a former download or upload
+                    observer.startWatching(downloadedFile.getName());
+                    Log_OC.d(TAG, "Resuming observance of " + downloadedFile.getAbsolutePath());
+
+                } else if (intent.getAction().equals(FileDownloader.getDownloadAddedMessage())) {
+                    observer.stopWatching(downloadedFile.getName());
+                    Log_OC.d(TAG, "Pausing observance of " + downloadedFile.getAbsolutePath());
+                }
+
+            } else {
+                Log_OC.d(TAG, "No observer for path " + downloadedFile.getAbsolutePath());
+            }
+        }
+
+    }
+
+}
diff --git a/src/com/owncloud/android/services/observer/FolderObserver.java b/src/com/owncloud/android/services/observer/FolderObserver.java
new file mode 100644 (file)
index 0000000..67b41a1
--- /dev/null
@@ -0,0 +1,215 @@
+/* ownCloud Android client application
+ *   Copyright (C) 2012-2014 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.services.observer;
+
+import java.io.File;
+import java.util.HashMap;
+import java.util.Map;
+
+import android.accounts.Account;
+import android.content.Context;
+import android.content.Intent;
+import android.os.FileObserver;
+
+import com.owncloud.android.datamodel.FileDataStorageManager;
+import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.lib.common.operations.RemoteOperationResult;
+import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;
+import com.owncloud.android.lib.common.utils.Log_OC;
+import com.owncloud.android.operations.SynchronizeFileOperation;
+import com.owncloud.android.ui.activity.ConflictsResolveActivity;
+
+/**
+ * Observer watching a folder to request the synchronization of kept-in-sync files
+ * inside it.
+ * 
+ * Takes into account two possible update cases:
+ *  - an editor directly updates the file;
+ *  - an editor works on a temporary file, and later replaces the kept-in-sync file with the
+ *  former.
+ *  
+ *  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 {
+
+    private static String TAG = FolderObserver.class.getSimpleName();
+
+    private static int UPDATE_MASK = (
+            FileObserver.ATTRIB | FileObserver.MODIFY | 
+            FileObserver.MOVED_TO | FileObserver.CLOSE_WRITE
+    ); 
+    
+    private static int IN_IGNORE = 32768;
+    /* 
+    private static int ALL_EVENTS_EVEN_THOSE_NOT_DOCUMENTED = 0x7fffffff;   // NEVER use 0xffffffff
+    */
+
+    private String mPath;
+    private Account mAccount;
+    private Context mContext;
+    private Map<String, Boolean> mObservedChildren;
+
+    /**
+     * Constructor.
+     * 
+     * Initializes the observer to receive events about the update of the passed folder, and
+     * its children files.
+     * 
+     * @param path          Absolute path to the local folder to watch.
+     * @param account       OwnCloud account associated to the folder.
+     * @param context       Used to start an operation to synchronize the file, when needed.    
+     */
+    public FolderObserver(String path, Account account, Context context) {
+        super(path, UPDATE_MASK);
+        
+        if (path == null)
+            throw new IllegalArgumentException("NULL path argument received");
+        if (account == null)
+            throw new IllegalArgumentException("NULL account argument received");
+        if (context == null)
+            throw new IllegalArgumentException("NULL context argument received");
+        
+        mPath = path;
+        mAccount = account;
+        mContext = context;
+        mObservedChildren = new HashMap<String, Boolean>();
+    }
+
+
+    /**
+     * Receives and processes events about updates of the monitor folder and its children files.
+     * 
+     * @param event     Kind of event occurred.
+     * @param path      Relative path of the file referred by the event.
+     */
+    @Override
+    public void onEvent(int event, String path) {
+        Log_OC.d(TAG, "Got event " + event + " on FOLDER " + mPath + " about "
+                + ((path != null) ? path : ""));
+        
+        boolean shouldSynchronize = false;
+        synchronized(mObservedChildren) {
+            if (path != null && path.length() > 0 && mObservedChildren.containsKey(path)) {
+                
+                if (    ((event & FileObserver.MODIFY) != 0) ||
+                        ((event & FileObserver.ATTRIB) != 0) ||
+                        ((event & FileObserver.MOVED_TO) != 0) ) {
+                    
+                    if (mObservedChildren.get(path) != true) {
+                        mObservedChildren.put(path, Boolean.valueOf(true));
+                    }
+                }
+                
+                if ((event & FileObserver.CLOSE_WRITE) != 0 && mObservedChildren.get(path)) {
+                    mObservedChildren.put(path, Boolean.valueOf(false));
+                    shouldSynchronize = true;
+                }
+            }
+        }
+        if (shouldSynchronize) {
+            startSyncOperation(path);
+        }
+        
+        if ((event & IN_IGNORE) != 0 &&
+                (path == null || path.length() == 0)) {
+            Log_OC.d(TAG, "Stopping the observance on " + mPath);
+        }
+        
+    }
+    
+
+    /**
+     * Adds a child file to the list of files observed by the folder observer.
+     * 
+     * @param fileName         Name of a file inside the observed folder. 
+     */
+    public void startWatching(String fileName) {
+        synchronized (mObservedChildren) {
+            if (!mObservedChildren.containsKey(fileName)) {
+                mObservedChildren.put(fileName, Boolean.valueOf(false));
+            }
+        }
+        
+        if (new File(mPath).exists()) {
+            startWatching();
+            Log_OC.d(TAG, "Started watching parent folder " + mPath + "/");
+        }
+        // else - the observance can't be started on a file not existing;
+    }
+
+    
+    /**
+     * Removes a child file from the list of files observed by the folder observer.
+     * 
+     * @param fileName         Name of a file inside the observed folder. 
+     */
+    public void stopWatching(String fileName) {
+        synchronized (mObservedChildren) {
+            mObservedChildren.remove(fileName);
+            if (mObservedChildren.isEmpty()) {
+                stopWatching();
+                Log_OC.d(TAG, "Stopped watching parent folder " + mPath + "/");
+            }
+        }
+    }
+
+    /**
+     * @return      'True' when the folder is not watching any file inside.
+     */
+    public boolean isEmpty() {
+        synchronized (mObservedChildren) {
+            return mObservedChildren.isEmpty();
+        }
+    }
+    
+    
+    /**
+     * Triggers an operation to synchronize the contents of a file inside the observed folder with
+     * its remote counterpart in the associated ownCloud account.
+     *    
+     * @param fileName          Name of a file inside the watched folder.
+     */
+    private void startSyncOperation(String fileName) {
+        FileDataStorageManager storageManager = 
+                new FileDataStorageManager(mAccount, mContext.getContentResolver());
+        // a fresh object is needed; many things could have occurred to the file
+        // since it was registered to observe again, assuming that local files
+        // are linked to a remote file AT MOST, SOMETHING TO BE DONE;
+        OCFile file = storageManager.getFileByLocalPath(mPath + File.separator + fileName);
+        SynchronizeFileOperation sfo = 
+                new SynchronizeFileOperation(file, null, mAccount, true, mContext);
+        RemoteOperationResult result = sfo.execute(storageManager, mContext);
+        if (result.getCode() == ResultCode.SYNC_CONFLICT) {
+            // ISSUE 5: if the user is not running the app (this is a service!),
+            // this can be very intrusive; a notification should be preferred
+            Intent i = new Intent(mContext, ConflictsResolveActivity.class);
+            i.setFlags(i.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
+            i.putExtra(ConflictsResolveActivity.EXTRA_FILE, file);
+            i.putExtra(ConflictsResolveActivity.EXTRA_ACCOUNT, mAccount);
+            mContext.startActivity(i);
+        }
+        // TODO save other errors in some point where the user can inspect them later;
+        // or maybe just toast them;
+        // or nothing, very strange fails
+    }
+
+}
index 6e81557..28cfa54 100644 (file)
@@ -24,11 +24,12 @@ import org.apache.http.HttpRequest;
 import org.apache.http.HttpResponse;\r
 import org.apache.http.client.ClientProtocolException;\r
 \r
-import com.owncloud.android.authentication.AccountUtils;\r
-import com.owncloud.android.authentication.AccountUtils.AccountNotFoundException;\r
 import com.owncloud.android.datamodel.FileDataStorageManager;\r
-import com.owncloud.android.network.OwnCloudClientUtils;\r
-\r
+import com.owncloud.android.lib.common.accounts.AccountUtils;\r
+import com.owncloud.android.lib.common.accounts.AccountUtils.AccountNotFoundException;\r
+import com.owncloud.android.lib.common.OwnCloudAccount;\r
+import com.owncloud.android.lib.common.OwnCloudClient;\r
+import com.owncloud.android.lib.common.OwnCloudClientManagerFactory;\r
 \r
 import android.accounts.Account;\r
 import android.accounts.AccountManager;\r
@@ -37,7 +38,6 @@ import android.accounts.OperationCanceledException;
 import android.content.AbstractThreadedSyncAdapter;\r
 import android.content.ContentProviderClient;\r
 import android.content.Context;\r
-import eu.alefzero.webdav.WebdavClient;\r
 \r
 /**\r
  * Base synchronization adapter for ownCloud designed to be subclassed for different\r
@@ -56,7 +56,7 @@ public abstract class AbstractOwnCloudSyncAdapter extends
     private ContentProviderClient mContentProviderClient;\r
     private FileDataStorageManager mStoreManager;\r
 \r
-    private WebdavClient mClient = null;\r
+    private OwnCloudClient mClient = null;\r
 \r
     public AbstractOwnCloudSyncAdapter(Context context, boolean autoInitialize) {\r
         super(context, autoInitialize);\r
@@ -102,10 +102,12 @@ public abstract class AbstractOwnCloudSyncAdapter extends
 \r
     protected void initClientForCurrentAccount() throws OperationCanceledException, AuthenticatorException, IOException, AccountNotFoundException {\r
         AccountUtils.constructFullURLForAccount(getContext(), account);\r
-        mClient = OwnCloudClientUtils.createOwnCloudClient(account, getContext());\r
+        OwnCloudAccount ocAccount = new OwnCloudAccount(account, getContext());\r
+        mClient = OwnCloudClientManagerFactory.getDefaultSingleton().\r
+                getClientFor(ocAccount, getContext());\r
     }\r
     \r
-    protected WebdavClient getClient() {\r
+    protected OwnCloudClient getClient() {\r
         return mClient;\r
     }\r
     \r
index 662c8a6..3ba1676 100644 (file)
@@ -24,8 +24,8 @@ import java.io.IOException;
 import org.apache.http.client.methods.HttpPut;
 import org.apache.http.entity.ByteArrayEntity;
 
-import com.owncloud.android.authentication.AccountAuthenticator;
 import com.owncloud.android.authentication.AccountUtils;
+import com.owncloud.android.lib.common.accounts.AccountUtils.Constants;
 
 
 import android.accounts.Account;
@@ -92,7 +92,7 @@ public class ContactSyncAdapter extends AbstractOwnCloudSyncAdapter {
         AccountManager am = getAccountManager();
         @SuppressWarnings("deprecation")
         String uri = am.getUserData(getAccount(),
-                AccountAuthenticator.KEY_OC_URL).replace(
+                Constants.KEY_OC_URL).replace(
                 AccountUtils.WEBDAV_PATH_2_0, AccountUtils.CARDDAV_PATH_2_0);
         uri += "/addressbooks/"
                 + getAccount().name.substring(0,
index 5b0376c..33e2400 100644 (file)
@@ -26,22 +26,19 @@ import java.util.Map;
 
 import org.apache.jackrabbit.webdav.DavException;
 
-import com.owncloud.android.Log_OC;
-import com.owncloud.android.MainApp;
 import com.owncloud.android.R;
 import com.owncloud.android.authentication.AuthenticatorActivity;
 import com.owncloud.android.datamodel.FileDataStorageManager;
 import com.owncloud.android.datamodel.OCFile;
-import com.owncloud.android.operations.RemoteOperationResult;
+import com.owncloud.android.lib.common.operations.RemoteOperationResult;
 import com.owncloud.android.operations.SynchronizeFolderOperation;
 import com.owncloud.android.operations.UpdateOCVersionOperation;
-import com.owncloud.android.operations.RemoteOperationResult.ResultCode;
+import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;
+import com.owncloud.android.lib.common.utils.Log_OC;
 import com.owncloud.android.ui.activity.ErrorsWhileCopyingHandlerActivity;
 
-
 import android.accounts.Account;
 import android.accounts.AccountsException;
-import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.content.AbstractThreadedSyncAdapter;
@@ -51,6 +48,7 @@ import android.content.Context;
 import android.content.Intent;
 import android.content.SyncResult;
 import android.os.Bundle;
+import android.support.v4.app.NotificationCompat;
 
 /**
  * Implementation of {@link AbstractThreadedSyncAdapter} responsible for synchronizing 
@@ -69,6 +67,16 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter {
     private static final int MAX_FAILED_RESULTS = 3; 
     
     
+    public static final String EVENT_FULL_SYNC_START = FileSyncAdapter.class.getName() + ".EVENT_FULL_SYNC_START";
+    public static final String EVENT_FULL_SYNC_END = FileSyncAdapter.class.getName() + ".EVENT_FULL_SYNC_END";
+    public static final String EVENT_FULL_SYNC_FOLDER_CONTENTS_SYNCED = FileSyncAdapter.class.getName() + ".EVENT_FULL_SYNC_FOLDER_CONTENTS_SYNCED";
+    //public static final String EVENT_FULL_SYNC_FOLDER_SIZE_SYNCED = FileSyncAdapter.class.getName() + ".EVENT_FULL_SYNC_FOLDER_SIZE_SYNCED";
+    
+    public static final String EXTRA_ACCOUNT_NAME = FileSyncAdapter.class.getName() + ".EXTRA_ACCOUNT_NAME";
+    public static final String EXTRA_FOLDER_PATH = FileSyncAdapter.class.getName() + ".EXTRA_FOLDER_PATH";
+    public static final String EXTRA_RESULT = FileSyncAdapter.class.getName() + ".EXTRA_RESULT";
+    
+    
     /** Time stamp for the current synchronization process, used to distinguish fresh data */
     private long mCurrentSyncTime;
     
@@ -95,6 +103,9 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter {
 
     /** {@link SyncResult} instance to return to the system when the synchronization finish */
     private SyncResult mSyncResult;
+
+    /** 'True' means that the server supports the share API */
+    private boolean mIsShareSupported;
     
     
     /**
@@ -139,6 +150,7 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter {
         this.setAccount(account);
         this.setContentProviderClient(providerClient);
         this.setStorageManager(new FileDataStorageManager(account, providerClient));
+        
         try {
             this.initClientForCurrentAccount();
         } catch (IOException e) {
@@ -154,7 +166,7 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter {
         }
         
         Log_OC.d(TAG, "Synchronization of ownCloud account " + account.name + " starting");
-        sendStickyBroadcast(true, null, null);  // message to signal the start of the synchronization to the UI
+        sendLocalBroadcast(EVENT_FULL_SYNC_START, null, null);  // message to signal the start of the synchronization to the UI
         
         try {
             updateOCVersion();
@@ -184,7 +196,7 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter {
             if (mForgottenLocalFiles.size() > 0) {
                 notifyForgottenLocalFiles();
             }
-            sendStickyBroadcast(false, null, mLastFailedResult);        // message to signal the end to the UI
+            sendLocalBroadcast(EVENT_FULL_SYNC_END, null, mLastFailedResult);   // message to signal the end to the UI
         }
         
     }
@@ -215,6 +227,8 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter {
         RemoteOperationResult result = update.execute(getClient());
         if (!result.isSuccess()) {
             mLastFailedResult = result; 
+        } else {
+            mIsShareSupported = update.getOCVersion().isSharedSupported();
         }
     }
     
@@ -243,13 +257,14 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter {
         DataStorageManager dataStorageManager, 
         Account account, 
         Context context ) {
-            
         }
         */
         // folder synchronization
         SynchronizeFolderOperation synchFolderOp = new SynchronizeFolderOperation(  folder, 
                                                                                     mCurrentSyncTime, 
                                                                                     true,
+                                                                                    mIsShareSupported,
+                                                                                    false,
                                                                                     getStorageManager(), 
                                                                                     getAccount(), 
                                                                                     getContext()
@@ -258,7 +273,7 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter {
         
         
         // synchronized folder -> notice to UI - ALWAYS, although !result.isSuccess
-        sendStickyBroadcast(true, folder.getRemotePath(), null);
+        sendLocalBroadcast(EVENT_FULL_SYNC_FOLDER_CONTENTS_SYNCED, folder.getRemotePath(), result);
         
         // check the result of synchronizing the folder
         if (result.isSuccess() || result.getCode() == ResultCode.SYNC_CONFLICT) {
@@ -278,9 +293,9 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter {
             
         } else {
             // in failures, the statistics for the global result are updated
-            if (result.getCode() == RemoteOperationResult.ResultCode.UNAUTHORIZED ||
-                    ( result.isIdPRedirection() && 
-                            MainApp.getAuthTokenTypeSamlSessionCookie().equals(getClient().getAuthTokenType()))) {
+            if (    result.getCode() == RemoteOperationResult.ResultCode.UNAUTHORIZED ||
+                    result.isIdPRedirection()
+                ) {
                 mSyncResult.stats.numAuthExceptions++;
                 
             } else if (result.getException() instanceof DavException) {
@@ -321,8 +336,8 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter {
     private void fetchChildren(OCFile parent, List<OCFile> files, boolean parentEtagChanged) {
         int i;
         OCFile newFile = null;
-        String etag = null;
-        boolean syncDown = false;
+        //String etag = null;
+        //boolean syncDown = false;
         for (i=0; i < files.size() && !mCancellation; i++) {
             newFile = files.get(i);
             if (newFile.isFolder()) {
@@ -331,9 +346,7 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter {
                 syncDown = (parentEtagChanged || etag == null || etag.length() == 0);
                 if(syncDown) { */
                     synchronizeFolder(newFile);
-                    // update the size of the parent folder again after recursive synchronization 
-                    //getStorageManager().updateFolderSize(parent.getFileId());  
-                    sendStickyBroadcast(true, parent.getRemotePath(), null);        // notify again to refresh size in UI
+                    //sendLocalBroadcast(EVENT_FULL_SYNC_FOLDER_SIZE_SYNCED, parent.getRemotePath(), null);
                 //}
             }
         }
@@ -345,20 +358,22 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter {
     /**
      * Sends a message to any application component interested in the progress of the synchronization.
      * 
-     * @param inProgress        'True' when the synchronization progress is not finished.
-     * @param dirRemotePath     Remote path of a folder that was just synchronized (with or without success)
+     * @param event             Event in the process of synchronization to be notified.   
+     * @param dirRemotePath     Remote path of the folder target of the event occurred.
+     * @param result            Result of an individual {@ SynchronizeFolderOperation}, if completed; may be null.
      */
-    private void sendStickyBroadcast(boolean inProgress, String dirRemotePath, RemoteOperationResult result) {
-        Intent i = new Intent(FileSyncService.getSyncMessage());
-        i.putExtra(FileSyncService.IN_PROGRESS, inProgress);
-        i.putExtra(FileSyncService.ACCOUNT_NAME, getAccount().name);
+    private void sendLocalBroadcast(String event, String dirRemotePath, RemoteOperationResult result) {
+        Log_OC.d(TAG, "Send broadcast " + event);
+        Intent intent = new Intent(event);
+        intent.putExtra(FileSyncAdapter.EXTRA_ACCOUNT_NAME, getAccount().name);
         if (dirRemotePath != null) {
-            i.putExtra(FileSyncService.SYNC_FOLDER_REMOTE_PATH, dirRemotePath);
+            intent.putExtra(FileSyncAdapter.EXTRA_FOLDER_PATH, dirRemotePath);
         }
         if (result != null) {
-            i.putExtra(FileSyncService.SYNC_RESULT, result);
+            intent.putExtra(FileSyncAdapter.EXTRA_RESULT, result);
         }
-        getContext().sendStickyBroadcast(i);
+        getContext().sendStickyBroadcast(intent);
+        //LocalBroadcastManager.getInstance(getContext()).sendBroadcast(intent);
     }
 
     
@@ -367,38 +382,36 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter {
      * Notifies the user about a failed synchronization through the status notification bar 
      */
     private void notifyFailedSynchronization() {
-        Notification notification = new Notification(R.drawable.icon, getContext().getString(R.string.sync_fail_ticker), System.currentTimeMillis());
-        notification.flags |= Notification.FLAG_AUTO_CANCEL;
-        boolean needsToUpdateCredentials = (mLastFailedResult != null && 
-                                             (  mLastFailedResult.getCode() == ResultCode.UNAUTHORIZED ||
-                                                // (mLastFailedResult.isTemporalRedirection() && mLastFailedResult.isIdPRedirection() && 
-                                                ( mLastFailedResult.isIdPRedirection() && 
-                                                 MainApp.getAuthTokenTypeSamlSessionCookie().equals(getClient().getAuthTokenType()))
-                                             )
-                                           );
-        // TODO put something smart in the contentIntent below for all the possible errors
-        notification.contentIntent = PendingIntent.getActivity(getContext().getApplicationContext(), (int)System.currentTimeMillis(), new Intent(), 0);
+        NotificationCompat.Builder notificationBuilder = createNotificationBuilder();
+        boolean needsToUpdateCredentials = (
+                mLastFailedResult != null && (  
+                        mLastFailedResult.getCode() == ResultCode.UNAUTHORIZED ||
+                        mLastFailedResult.isIdPRedirection()
+                )
+        );
         if (needsToUpdateCredentials) {
             // let the user update credentials with one click
             Intent updateAccountCredentials = new Intent(getContext(), AuthenticatorActivity.class);
             updateAccountCredentials.putExtra(AuthenticatorActivity.EXTRA_ACCOUNT, getAccount());
-            updateAccountCredentials.putExtra(AuthenticatorActivity.EXTRA_ENFORCED_UPDATE, true);
-            updateAccountCredentials.putExtra(AuthenticatorActivity.EXTRA_ACTION, AuthenticatorActivity.ACTION_UPDATE_TOKEN);
+            updateAccountCredentials.putExtra(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);
-            notification.contentIntent = PendingIntent.getActivity(getContext(), (int)System.currentTimeMillis(), updateAccountCredentials, PendingIntent.FLAG_ONE_SHOT);
-            notification.setLatestEventInfo(getContext().getApplicationContext(), 
-                    getContext().getString(R.string.sync_fail_ticker), 
-                    String.format(getContext().getString(R.string.sync_fail_content_unauthorized), getAccount().name), 
-                    notification.contentIntent);
+            notificationBuilder
+                .setTicker(i18n(R.string.sync_fail_ticker_unauthorized))
+                .setContentTitle(i18n(R.string.sync_fail_ticker_unauthorized))
+                .setContentIntent(PendingIntent.getActivity(
+                    getContext(), (int)System.currentTimeMillis(), updateAccountCredentials, PendingIntent.FLAG_ONE_SHOT
+                ))
+                .setContentText(i18n(R.string.sync_fail_content_unauthorized, getAccount().name));
         } else {
-            notification.setLatestEventInfo(getContext().getApplicationContext(), 
-                                            getContext().getString(R.string.sync_fail_ticker), 
-                                            String.format(getContext().getString(R.string.sync_fail_content), getAccount().name), 
-                                            notification.contentIntent);
+            notificationBuilder
+                .setTicker(i18n(R.string.sync_fail_ticker))
+                .setContentTitle(i18n(R.string.sync_fail_ticker))
+                .setContentText(i18n(R.string.sync_fail_content, getAccount().name));
         }
-        ((NotificationManager) getContext().getSystemService(Context.NOTIFICATION_SERVICE)).notify(R.string.sync_fail_ticker, notification);
+        
+        showNotification(R.string.sync_fail_ticker, notificationBuilder);
     }
 
 
@@ -409,26 +422,31 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter {
      */
     private void notifyFailsInFavourites() {
         if (mFailedResultsCounter > 0) {
-            Notification notification = new Notification(R.drawable.icon, getContext().getString(R.string.sync_fail_in_favourites_ticker), System.currentTimeMillis());
-            notification.flags |= Notification.FLAG_AUTO_CANCEL;
+            NotificationCompat.Builder notificationBuilder = createNotificationBuilder();
+            notificationBuilder.setTicker(i18n(R.string.sync_fail_in_favourites_ticker));
+                
             // TODO put something smart in the contentIntent below
-            notification.contentIntent = PendingIntent.getActivity(getContext().getApplicationContext(), (int)System.currentTimeMillis(), new Intent(), 0);
-            notification.setLatestEventInfo(getContext().getApplicationContext(), 
-                                            getContext().getString(R.string.sync_fail_in_favourites_ticker), 
-                                            String.format(getContext().getString(R.string.sync_fail_in_favourites_content), mFailedResultsCounter + mConflictsFound, mConflictsFound), 
-                                            notification.contentIntent);
-            ((NotificationManager) getContext().getSystemService(Context.NOTIFICATION_SERVICE)).notify(R.string.sync_fail_in_favourites_ticker, notification);
+            notificationBuilder
+                .setContentIntent(PendingIntent.getActivity(
+                    getContext(), (int) System.currentTimeMillis(), new Intent(), 0
+                ))
+                .setContentTitle(i18n(R.string.sync_fail_in_favourites_ticker))
+                .setContentText(i18n(R.string.sync_fail_in_favourites_content, mFailedResultsCounter + mConflictsFound, mConflictsFound));
             
+            showNotification(R.string.sync_fail_in_favourites_ticker, notificationBuilder);
         } else {
-            Notification notification = new Notification(R.drawable.icon, getContext().getString(R.string.sync_conflicts_in_favourites_ticker), System.currentTimeMillis());
-            notification.flags |= Notification.FLAG_AUTO_CANCEL;
+            NotificationCompat.Builder notificationBuilder = createNotificationBuilder();
+            notificationBuilder.setTicker(i18n(R.string.sync_conflicts_in_favourites_ticker));
+          
             // TODO put something smart in the contentIntent below
-            notification.contentIntent = PendingIntent.getActivity(getContext().getApplicationContext(), (int)System.currentTimeMillis(), new Intent(), 0);
-            notification.setLatestEventInfo(getContext().getApplicationContext(), 
-                                            getContext().getString(R.string.sync_conflicts_in_favourites_ticker), 
-                                            String.format(getContext().getString(R.string.sync_conflicts_in_favourites_content), mConflictsFound), 
-                                            notification.contentIntent);
-            ((NotificationManager) getContext().getSystemService(Context.NOTIFICATION_SERVICE)).notify(R.string.sync_conflicts_in_favourites_ticker, notification);
+            notificationBuilder
+                .setContentIntent(PendingIntent.getActivity(
+                    getContext(), (int) System.currentTimeMillis(), new Intent(), 0
+                ))
+                .setContentTitle(i18n(R.string.sync_conflicts_in_favourites_ticker))
+                .setContentText(i18n(R.string.sync_conflicts_in_favourites_ticker, mConflictsFound));
+            
+            showNotification(R.string.sync_conflicts_in_favourites_ticker, notificationBuilder);
         } 
     }
     
@@ -442,9 +460,9 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter {
      * We won't consider a synchronization as failed when foreign files can not be copied to the ownCloud local directory.
      */
     private void notifyForgottenLocalFiles() {
-        Notification notification = new Notification(R.drawable.icon, getContext().getString(R.string.sync_foreign_files_forgotten_ticker), System.currentTimeMillis());
-        notification.flags |= Notification.FLAG_AUTO_CANCEL;
-
+        NotificationCompat.Builder notificationBuilder = createNotificationBuilder();
+        notificationBuilder.setTicker(i18n(R.string.sync_foreign_files_forgotten_ticker));
+      
         /// includes a pending intent in the notification showing a more detailed explanation
         Intent explanationIntent = new Intent(getContext(), ErrorsWhileCopyingHandlerActivity.class);
         explanationIntent.putExtra(ErrorsWhileCopyingHandlerActivity.EXTRA_ACCOUNT, getAccount());
@@ -456,14 +474,45 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter {
         explanationIntent.putExtra(ErrorsWhileCopyingHandlerActivity.EXTRA_REMOTE_PATHS, remotePaths);  
         explanationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
         
-        notification.contentIntent = PendingIntent.getActivity(getContext().getApplicationContext(), (int)System.currentTimeMillis(), explanationIntent, 0);
-        notification.setLatestEventInfo(getContext().getApplicationContext(), 
-                                        getContext().getString(R.string.sync_foreign_files_forgotten_ticker), 
-                                        String.format(getContext().getString(R.string.sync_foreign_files_forgotten_content), mForgottenLocalFiles.size(), getContext().getString(R.string.app_name)), 
-                                        notification.contentIntent);
-        ((NotificationManager) getContext().getSystemService(Context.NOTIFICATION_SERVICE)).notify(R.string.sync_foreign_files_forgotten_ticker, notification);
+        notificationBuilder
+            .setContentIntent(PendingIntent.getActivity(
+                getContext(), (int) System.currentTimeMillis(), explanationIntent, 0
+            ))
+            .setContentTitle(i18n(R.string.sync_foreign_files_forgotten_ticker))
+            .setContentText(i18n(R.string.sync_foreign_files_forgotten_content, mForgottenLocalFiles.size(), i18n(R.string.app_name)));
         
+        showNotification(R.string.sync_foreign_files_forgotten_ticker, notificationBuilder);
     }
     
+    /**
+     * Creates a notification builder with some commonly used settings
+     * 
+     * @return
+     */
+    private NotificationCompat.Builder createNotificationBuilder() {
+        NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(getContext());
+        notificationBuilder.setSmallIcon(R.drawable.notification_icon).setAutoCancel(true);
+        return notificationBuilder;
+    }
     
+    /**
+     * Builds and shows the notification
+     * 
+     * @param id
+     * @param builder
+     */
+    private void showNotification(int id, NotificationCompat.Builder builder) {
+        ((NotificationManager) getContext().getSystemService(Context.NOTIFICATION_SERVICE))
+            .notify(id, builder.build());
+    }
+    /**
+     * Shorthand translation
+     * 
+     * @param key
+     * @param args
+     * @return
+     */
+    private String i18n(int key, Object... args) {
+        return getContext().getString(key, args);
+    }
 }
index dafc771..5da8c24 100644 (file)
@@ -17,8 +17,6 @@
  */\r
 package com.owncloud.android.syncadapter;\r
 \r
-import com.owncloud.android.Log_OC;\r
-\r
 import android.app.Service;\r
 import android.content.Intent;\r
 import android.os.IBinder;\r
@@ -33,20 +31,11 @@ import android.os.IBinder;
  */\r
 public class FileSyncService extends Service {\r
     \r
-    private static final String SYNC_MESSAGE = "ACCOUNT_SYNC";\r
-    public static final String SYNC_FOLDER_REMOTE_PATH = "SYNC_FOLDER_REMOTE_PATH";\r
-    public static final String IN_PROGRESS = "SYNC_IN_PROGRESS";\r
-    public static final String ACCOUNT_NAME = "ACCOUNT_NAME";\r
-    public static final String SYNC_RESULT = "SYNC_RESULT";\r
-\r
     // Storage for an instance of the sync adapter\r
     private static FileSyncAdapter sSyncAdapter = null;\r
     // Object to use as a thread-safe lock\r
     private static final Object sSyncAdapterLock = new Object();\r
     \r
-    public static String getSyncMessage(){\r
-        return FileSyncService.class.getName().toString() + SYNC_MESSAGE;\r
-    }\r
     /*\r
      * {@inheritDoc}\r
      */\r
diff --git a/src/com/owncloud/android/ui/CheckBoxPreferenceWithLongTitle.java b/src/com/owncloud/android/ui/CheckBoxPreferenceWithLongTitle.java
new file mode 100644 (file)
index 0000000..dac083a
--- /dev/null
@@ -0,0 +1,47 @@
+/* ownCloud Android client application
+ *   Copyright (C) 2014 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.view.View;
+import android.widget.TextView;
+import android.preference.CheckBoxPreference;
+
+public class CheckBoxPreferenceWithLongTitle extends CheckBoxPreference{
+
+    public CheckBoxPreferenceWithLongTitle(Context context) {
+        super(context);
+    }
+
+    public CheckBoxPreferenceWithLongTitle(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+    public CheckBoxPreferenceWithLongTitle(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+    }
+
+    @Override
+    protected void onBindView(View view) {
+        super.onBindView(view);
+        TextView titleView = (TextView) view.findViewById(android.R.id.title);
+        titleView.setSingleLine(false);
+        titleView.setMaxLines(3);
+        titleView.setEllipsize(null);
+    }
+}
\ No newline at end of file
diff --git a/src/com/owncloud/android/ui/LongClickableCheckBoxPreference.java b/src/com/owncloud/android/ui/LongClickableCheckBoxPreference.java
new file mode 100644 (file)
index 0000000..5befe64
--- /dev/null
@@ -0,0 +1,17 @@
+package com.owncloud.android.ui;
+
+import android.content.Context;
+import android.preference.CheckBoxPreference;
+import android.view.View;
+
+public class LongClickableCheckBoxPreference extends CheckBoxPreference implements View.OnLongClickListener {
+
+    public LongClickableCheckBoxPreference(Context context) {
+        super(context);
+    }
+
+    @Override
+    public boolean onLongClick(View v) {
+        return true;
+    }
+}
diff --git a/src/com/owncloud/android/ui/activity/AccountSelectActivity.java b/src/com/owncloud/android/ui/activity/AccountSelectActivity.java
deleted file mode 100644 (file)
index 716d6df..0000000
+++ /dev/null
@@ -1,268 +0,0 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012 Bartek Przybylski
- *   Copyright (C) 2012-2013 ownCloud Inc.
- *
- *   This program is free software: you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License version 2,
- *   as published by the Free Software Foundation.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-package com.owncloud.android.ui.activity;
-
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-
-import android.accounts.Account;
-import android.accounts.AccountManager;
-import android.accounts.AccountManagerCallback;
-import android.accounts.AccountManagerFuture;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.os.Bundle;
-import android.os.Handler;
-import android.view.ContextMenu;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ContextMenu.ContextMenuInfo;
-import android.widget.AdapterView.AdapterContextMenuInfo;
-import android.widget.CheckedTextView;
-import android.widget.ListView;
-import android.widget.SimpleAdapter;
-import android.widget.TextView;
-
-import com.actionbarsherlock.app.ActionBar;
-import com.actionbarsherlock.app.SherlockListActivity;
-import com.actionbarsherlock.view.Menu;
-import com.actionbarsherlock.view.MenuInflater;
-import com.actionbarsherlock.view.MenuItem;
-import com.owncloud.android.Log_OC;
-import com.owncloud.android.MainApp;
-import com.owncloud.android.R;
-import com.owncloud.android.authentication.AccountAuthenticator;
-import com.owncloud.android.authentication.AccountUtils;
-import com.owncloud.android.authentication.AuthenticatorActivity;
-
-
-public class AccountSelectActivity extends SherlockListActivity implements
-        AccountManagerCallback<Boolean> {
-
-    private static final String  TAG = "AccountSelectActivity";
-    
-    private static final String PREVIOUS_ACCOUNT_KEY = "ACCOUNT";
-    
-    private final Handler mHandler = new Handler();
-    private Account mPreviousAccount = null;
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        if (savedInstanceState != null) {
-            mPreviousAccount = savedInstanceState.getParcelable(PREVIOUS_ACCOUNT_KEY);
-        } else {
-            mPreviousAccount = AccountUtils.getCurrentOwnCloudAccount(this);
-        }
-        
-        ActionBar action_bar = getSupportActionBar();
-        action_bar.setDisplayShowTitleEnabled(true);
-        action_bar.setDisplayHomeAsUpEnabled(false);
-    }
-
-    @Override
-    protected void onResume() {
-        super.onResume();
-        populateAccountList();
-    }
-    
-    @Override
-    protected void onPause() {
-        super.onPause();
-        if (this.isFinishing()) {
-            Account current = AccountUtils.getCurrentOwnCloudAccount(this);
-            if ((mPreviousAccount == null && current != null) || 
-                (mPreviousAccount != null && !mPreviousAccount.equals(current))) {
-                /// the account set as default changed since this activity was created 
-            
-                // restart the main activity
-                Intent i = new Intent(this, FileDisplayActivity.class);
-                i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
-                startActivity(i);
-            }
-        }
-    }
-
-    @Override
-    public boolean onCreateOptionsMenu(Menu menu) {
-        // Show Create Account if Multiaccount is enabled
-        if (getResources().getBoolean(R.bool.multiaccount_support)) {
-            MenuInflater inflater = getSherlock().getMenuInflater();
-            inflater.inflate(R.menu.account_picker, menu);
-        }
-        return true;
-    }
-
-    @Override
-    public void onCreateContextMenu(ContextMenu menu, View v,
-            ContextMenuInfo menuInfo) {
-        getMenuInflater().inflate(R.menu.account_picker_long_click, menu);
-        super.onCreateContextMenu(menu, v, menuInfo);
-    }
-
-    @Override
-    protected void onListItemClick(ListView l, View v, int position, long id) {
-        String accountName = ((TextView) v.findViewById(android.R.id.text1))
-                .getText().toString();
-        AccountUtils.setCurrentOwnCloudAccount(this, accountName);
-        finish();   // immediate exit
-    }
-
-    @Override
-    public boolean onMenuItemSelected(int featureId, MenuItem item) {
-        if (item.getItemId() == R.id.createAccount) {
-            /*Intent intent = new Intent(
-                    android.provider.Settings.ACTION_ADD_ACCOUNT);
-            intent.putExtra("authorities",
-                    new String[] { MainApp.getAuthTokenType() });
-            startActivity(intent);*/
-            AccountManager am = AccountManager.get(getApplicationContext());
-            am.addAccount(MainApp.getAccountType(), 
-                            null,
-                            null, 
-                            null, 
-                            this, 
-                            null,                        
-                            null);
-            return true;
-        }
-        return false;
-    }
-
-    /**
-     * Called when the user clicked on an item into the context menu created at 
-     * {@link #onCreateContextMenu(ContextMenu, View, ContextMenuInfo)} for every
-     * ownCloud {@link Account} , containing 'secondary actions' for them.
-     * 
-     * {@inheritDoc}}
-     */
-    @SuppressWarnings("unchecked")
-    @Override
-    public boolean onContextItemSelected(android.view.MenuItem item) {
-        AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
-        int index = info.position;
-        HashMap<String, String> map = null;
-        try {
-            map = (HashMap<String, String>) getListAdapter().getItem(index);
-        } catch (ClassCastException e) {
-            Log_OC.wtf(TAG, "getitem(index) from list adapter did not return hashmap, bailing out");
-            return false;
-        }
-        
-        String accountName = map.get("NAME");
-        AccountManager am = (AccountManager) getSystemService(ACCOUNT_SERVICE);
-        Account accounts[] = am.getAccountsByType(MainApp.getAccountType());
-        for (Account a : accounts) {
-            if (a.name.equals(accountName)) {
-                if (item.getItemId() == R.id.change_password) {
-                    Intent updateAccountCredentials = new Intent(this, AuthenticatorActivity.class);
-                    updateAccountCredentials.putExtra(AuthenticatorActivity.EXTRA_ACCOUNT, a);
-                    updateAccountCredentials.putExtra(AuthenticatorActivity.EXTRA_ACTION, AuthenticatorActivity.ACTION_UPDATE_TOKEN);
-                    startActivity(updateAccountCredentials);
-                    
-                } else if (item.getItemId() == R.id.delete_account) {
-                    am.removeAccount(a, this, mHandler);
-                }
-            }
-        }
-
-        return true;
-    }
-
-    private void populateAccountList() {
-        AccountManager am = (AccountManager) getSystemService(ACCOUNT_SERVICE);
-        Account accounts[] = am
-                .getAccountsByType(MainApp.getAccountType());
-        if (am.getAccountsByType(MainApp.getAccountType()).length == 0) {
-            // Show create account screen if there isn't any account
-            am.addAccount(MainApp.getAccountType(), 
-                    null,
-                    null, 
-                    null, 
-                    this, 
-                    null,                        
-                    null);
-        }
-        else {
-            LinkedList<HashMap<String, String>> ll = new LinkedList<HashMap<String, String>>();
-            for (Account a : accounts) {
-                HashMap<String, String> h = new HashMap<String, String>();
-                h.put("NAME", a.name);
-                h.put("VER",
-                        "ownCloud version: "
-                                + am.getUserData(a,
-                                        AccountAuthenticator.KEY_OC_VERSION));
-                ll.add(h);
-            }
-
-            setListAdapter(new AccountCheckedSimpleAdepter(this, ll,
-                    android.R.layout.simple_list_item_single_choice,
-                    new String[] { "NAME" }, new int[] { android.R.id.text1 }));
-            registerForContextMenu(getListView());
-        }
-    }
-
-    @Override
-    public void run(AccountManagerFuture<Boolean> future) {
-        if (future.isDone()) {
-            Account a = AccountUtils.getCurrentOwnCloudAccount(this);
-            String accountName = "";
-            if (a == null) {
-                Account[] accounts = AccountManager.get(this)
-                        .getAccountsByType(MainApp.getAccountType());
-                if (accounts.length != 0)
-                    accountName = accounts[0].name;
-                AccountUtils.setCurrentOwnCloudAccount(this, accountName);
-            }
-            populateAccountList();
-        }
-    }
-
-    private class AccountCheckedSimpleAdepter extends SimpleAdapter {
-        private Account mCurrentAccount;
-        private List<? extends Map<String, ?>> mPrivateData;
-
-        public AccountCheckedSimpleAdepter(Context context,
-                List<? extends Map<String, ?>> data, int resource,
-                String[] from, int[] to) {
-            super(context, data, resource, from, to);
-            mCurrentAccount = AccountUtils
-                    .getCurrentOwnCloudAccount(AccountSelectActivity.this);
-            mPrivateData = data;
-        }
-
-        @Override
-        public View getView(int position, View convertView, ViewGroup parent) {
-            View v = super.getView(position, convertView, parent);
-            CheckedTextView ctv = (CheckedTextView) v
-                    .findViewById(android.R.id.text1);
-            if (mPrivateData.get(position).get("NAME")
-                    .equals(mCurrentAccount.name)) {
-                ctv.setChecked(true);
-            }
-            return v;
-        }
-
-    }
-
-}
diff --git a/src/com/owncloud/android/ui/activity/ComponentsGetter.java b/src/com/owncloud/android/ui/activity/ComponentsGetter.java
new file mode 100644 (file)
index 0000000..076a6cb
--- /dev/null
@@ -0,0 +1,49 @@
+/* ownCloud Android client application
+ *   Copyright (C) 2012 Bartek Przybylski
+ *   Copyright (C) 2012-2013 ownCloud Inc.
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License version 2,
+ *   as published by the Free Software Foundation.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.ui.activity;
+
+import com.owncloud.android.datamodel.FileDataStorageManager;
+import com.owncloud.android.files.FileOperationsHelper;
+import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder;
+import com.owncloud.android.files.services.FileUploader.FileUploaderBinder;
+
+public interface ComponentsGetter {
+
+    /**
+     * Callback method invoked when the parent activity is fully created to get a reference to the FileDownloader service API.
+     * 
+     * @return  Directory to list firstly. Can be NULL.
+     */
+    public FileDownloaderBinder getFileDownloaderBinder();
+
+    
+    /**
+     * Callback method invoked when the parent activity is fully created to get a reference to the FileUploader service API.
+     * 
+     * @return  Directory to list firstly. Can be NULL.
+     */
+    public FileUploaderBinder getFileUploaderBinder();
+
+    
+    
+    public FileDataStorageManager getStorageManager();
+    
+    public FileOperationsHelper getFileOperationsHelper();
+
+}
index f0895bf..509e5c7 100644 (file)
 
 package com.owncloud.android.ui.activity;
 
-import com.owncloud.android.Log_OC;
-import com.owncloud.android.datamodel.FileDataStorageManager;
+import com.actionbarsherlock.app.ActionBar;
 import com.owncloud.android.datamodel.OCFile;
 import com.owncloud.android.files.services.FileUploader;
+import com.owncloud.android.lib.common.utils.Log_OC;
 import com.owncloud.android.ui.dialog.ConflictsResolveDialog;
 import com.owncloud.android.ui.dialog.ConflictsResolveDialog.Decision;
 import com.owncloud.android.ui.dialog.ConflictsResolveDialog.OnConflictDecisionMadeListener;
+import com.owncloud.android.utils.DisplayUtils;
 
 import android.content.Intent;
 import android.os.Bundle;
@@ -43,10 +44,12 @@ public class ConflictsResolveActivity extends FileActivity implements OnConflict
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
+        ActionBar actionBar = getSupportActionBar();
+        actionBar.setIcon(DisplayUtils.getSeasonalIconId());
     }
 
     @Override
-    public void ConflictDecisionMade(Decision decision) {
+    public void conflictDecisionMade(Decision decision) {
         Intent i = new Intent(getApplicationContext(), FileUploader.class);
         
         switch (decision) {
@@ -73,6 +76,7 @@ public class ConflictsResolveActivity extends FileActivity implements OnConflict
 
     @Override
     protected void onAccountSet(boolean stateWasRecovered) {
+        super.onAccountSet(stateWasRecovered);
         if (getAccount() != null) {
             OCFile file = getFile();
             if (getFile() == null) {
@@ -80,8 +84,7 @@ public class ConflictsResolveActivity extends FileActivity implements OnConflict
                 finish();
             } else {
                 /// Check whether the 'main' OCFile handled by the Activity is contained in the current Account
-                FileDataStorageManager storageManager = new FileDataStorageManager(getAccount(), getContentResolver());
-                file = storageManager.getFileByPath(file.getRemotePath());   // file = null if not in the current Account
+                file = getStorageManager().getFileByPath(file.getRemotePath());   // file = null if not in the current Account
                 if (file != null) {
                     setFile(file);
                     ConflictsResolveDialog d = ConflictsResolveDialog.newInstance(file.getRemotePath(), this);
@@ -94,7 +97,6 @@ public class ConflictsResolveActivity extends FileActivity implements OnConflict
             }
             
         } else {
-            Log_OC.wtf(TAG, "onAccountChanged was called with NULL account associated!");
             finish();
         }
         
diff --git a/src/com/owncloud/android/ui/activity/CopyToClipboardActivity.java b/src/com/owncloud/android/ui/activity/CopyToClipboardActivity.java
new file mode 100644 (file)
index 0000000..b503c37
--- /dev/null
@@ -0,0 +1,65 @@
+/* ownCloud Android client application
+ *   Copyright (C) 2012-2014 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 com.owncloud.android.R;
+
+import android.app.Activity;
+import android.content.ClipData;
+import android.content.Intent;
+import android.os.Bundle;
+import android.text.ClipboardManager;
+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 {
+    
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        
+        // get the clipboard system service
+        ClipboardManager clipboardManager = (ClipboardManager) this.getSystemService(CLIPBOARD_SERVICE);
+        
+        // get the text to copy into the clipboard 
+        Intent intent = getIntent();
+        CharSequence text = intent.getCharSequenceExtra(Intent.EXTRA_TEXT);
+        
+        // and put the text the clipboard
+        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) {
+            // API level >= 11 -> modern Clipboard
+            ClipData clip = ClipData.newPlainText("ownCloud was here", text);
+            ((android.content.ClipboardManager)clipboardManager).setPrimaryClip(clip);
+            
+        } else {
+            // API level >= 11 -> legacy Clipboard
+            clipboardManager.setText(text);    
+        }
+        
+        // alert the user that the text is in the clipboard and we're done
+        Toast.makeText(this, R.string.clipboard_text_copied, Toast.LENGTH_SHORT).show();
+        
+        finish();
+    }    
+
+}
index 056ffd6..bffec8b 100644 (file)
@@ -39,10 +39,10 @@ import android.widget.TextView;
 import android.widget.Toast;
 
 import com.actionbarsherlock.app.SherlockFragmentActivity;
-import com.owncloud.android.Log_OC;
 import com.owncloud.android.R;
 import com.owncloud.android.datamodel.FileDataStorageManager;
 import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.lib.common.utils.Log_OC;
 
 import com.owncloud.android.ui.dialog.IndeterminateProgressDialog;
 import com.owncloud.android.utils.FileStorageUtils;
diff --git a/src/com/owncloud/android/ui/activity/FailedUploadActivity.java b/src/com/owncloud/android/ui/activity/FailedUploadActivity.java
deleted file mode 100644 (file)
index 33432cf..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-/* ownCloud Android client application\r
- *   Copyright (C) 2012-2013 ownCloud Inc.\r
- *\r
- *   This program is free software: you can redistribute it and/or modify\r
- *   it under the terms of the GNU General Public License version 2,\r
- *   as published by the Free Software Foundation.\r
- *\r
- *   This program is distributed in the hope that it will be useful,\r
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
- *   GNU General Public License for more details.\r
- *\r
- *   You should have received a copy of the GNU General Public License\r
- *   along with this program.  If not, see <http://www.gnu.org/licenses/>.\r
- *\r
- */\r
-\r
-package com.owncloud.android.ui.activity;\r
-\r
-import com.owncloud.android.R;\r
-\r
-import android.app.Activity;\r
-import android.os.Bundle;\r
-import android.view.View;\r
-import android.view.View.OnClickListener;\r
-import android.widget.Button;\r
-import android.widget.TextView;\r
-\r
-\r
-/**\r
- * This Activity is used to display a detail message for failed uploads\r
- * \r
- * The entry-point for this activity is the 'Failed upload Notification"\r
- * \r
- * @author andomaex / Matthias Baumann\r
- */\r
-public class FailedUploadActivity extends Activity {\r
-\r
-    public static final String MESSAGE = "message";\r
-\r
-    @Override\r
-    public void onCreate(Bundle savedInstanceState) {\r
-        super.onCreate(savedInstanceState);\r
-        setContentView(R.layout.failed_upload_message_view);\r
-        String message = getIntent().getStringExtra(MESSAGE);\r
-        TextView textView = (TextView) findViewById(R.id.faild_upload_message);\r
-        textView.setText(message);\r
-        Button closeBtn = (Button) findViewById(R.id.failed_uploadactivity_close_button);\r
-        \r
-        closeBtn.setOnClickListener(new OnClickListener() {\r
-            @Override\r
-            public void onClick(View v) {\r
-                finish();\r
-            }\r
-        });\r
-    }\r
-}\r
index cddf9b6..136bdb5 100644 (file)
@@ -1,6 +1,6 @@
 /* ownCloud Android client application
  *   Copyright (C) 2011  Bartek Przybylski
- *   Copyright (C) 2012-2013 ownCloud Inc.
+ *   Copyright (C) 2012-2014 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,34 +22,65 @@ import android.accounts.Account;
 import android.accounts.AccountManager;
 import android.accounts.AccountManagerCallback;
 import android.accounts.AccountManagerFuture;
+import android.accounts.AuthenticatorException;
 import android.accounts.OperationCanceledException;
+import android.content.ComponentName;
+import android.content.Context;
 import android.content.Intent;
-import android.net.Uri;
+import android.content.ServiceConnection;
 import android.os.Bundle;
-import android.webkit.MimeTypeMap;
+import android.os.Handler;
+import android.os.IBinder;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentManager;
+import android.support.v4.app.FragmentTransaction;
+import android.widget.Toast;
 
 import com.actionbarsherlock.app.SherlockFragmentActivity;
-import com.owncloud.android.Log_OC;
 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.files.FileOperationsHelper;
+import com.owncloud.android.files.services.FileDownloader;
+import com.owncloud.android.files.services.FileUploader;
+import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder;
+import com.owncloud.android.files.services.FileUploader.FileUploaderBinder;
+import com.owncloud.android.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.operations.RemoteOperationResult.ResultCode;
+import com.owncloud.android.lib.common.utils.Log_OC;
+import com.owncloud.android.operations.CreateShareOperation;
+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.LoadingDialog;
+import com.owncloud.android.utils.ErrorMessageAdapter;
 
-import eu.alefzero.webdav.WebdavUtils;
 
 /**
  * Activity with common behaviour for activities handling {@link OCFile}s in ownCloud {@link Account}s .
  * 
  * @author David A. Velasco
  */
-public abstract class FileActivity extends SherlockFragmentActivity {
+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 TAG = FileActivity.class.getSimpleName(); 
+    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";;
+    
+    protected static final long DELAY_TO_REQUEST_OPERATION_ON_ACTIVITY_RESULTS = 200;
     
     
     /** OwnCloud {@link Account} where the main {@link OCFile} handled by the activity is located. */
@@ -66,7 +97,26 @@ public abstract class FileActivity extends SherlockFragmentActivity {
     
     /** Flag to signal when the value of mAccount was restored from a saved state */ 
     private boolean mAccountWasRestored;
-
+    
+    /** Flag to signal if the activity is launched by a notification */
+    private boolean mFromNotification;
+    
+    /** Messages handler associated to the main thread and the life cycle of the activity */
+    private Handler mHandler;
+    
+    /** Access point to the cached database for the current ownCloud {@link Account} */
+    private FileDataStorageManager mStorageManager = null;
+    
+    private FileOperationsHelper mFileOperationsHelper;
+    
+    private ServiceConnection mOperationsServiceConnection = null;
+    
+    private OperationsServiceBinder mOperationsServiceBinder = null;
+    
+    protected FileDownloaderBinder mDownloaderBinder = null;
+    protected FileUploaderBinder mUploaderBinder = null;
+    private ServiceConnection mDownloadServiceConnection, mUploadServiceConnection = null;
+    
     
     /**
      * Loads the ownCloud {@link Account} and main {@link OCFile} to be handled by the instance of 
@@ -78,17 +128,36 @@ public abstract class FileActivity extends SherlockFragmentActivity {
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-
+        mHandler = new Handler();
+        mFileOperationsHelper = new FileOperationsHelper(this);
         Account account;
         if(savedInstanceState != null) {
             account = savedInstanceState.getParcelable(FileActivity.EXTRA_ACCOUNT);
             mFile = savedInstanceState.getParcelable(FileActivity.EXTRA_FILE);
+            mFromNotification = savedInstanceState.getBoolean(FileActivity.EXTRA_FROM_NOTIFICATION);
+            mFileOperationsHelper.setOpIdWaitingFor(
+                    savedInstanceState.getLong(KEY_WAITING_FOR_OP_ID, Long.MAX_VALUE)
+                    );
         } else {
             account = getIntent().getParcelableExtra(FileActivity.EXTRA_ACCOUNT);
             mFile = getIntent().getParcelableExtra(FileActivity.EXTRA_FILE);
+            mFromNotification = getIntent().getBooleanExtra(FileActivity.EXTRA_FROM_NOTIFICATION, false);
         }
 
         setAccount(account, savedInstanceState != null);
+        
+        mOperationsServiceConnection = new OperationsServiceConnection();
+        bindService(new Intent(this, OperationsService.class), mOperationsServiceConnection, Context.BIND_AUTO_CREATE);
+        
+        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);
+        }
+        
     }
 
     
@@ -104,18 +173,56 @@ public abstract class FileActivity extends SherlockFragmentActivity {
         if (!validAccount) {
             swapToDefaultAccount();
         }
-        
     }
 
     
     @Override 
     protected void onStart() {
         super.onStart();
+
         if (mAccountWasSet) {
             onAccountSet(mAccountWasRestored);
         }
     }
     
+    @Override
+    protected void onResume() {
+        super.onResume();
+        
+        if (mOperationsServiceBinder != null) {
+            doOnResumeAndBound();
+        }
+
+    }
+    
+    @Override
+    protected void onPause()  {
+        
+        if (mOperationsServiceBinder != null) {
+            mOperationsServiceBinder.removeOperationListener(this);
+        }
+        
+        super.onPause();
+    }
+    
+    
+    @Override
+    protected void onDestroy() {
+        if (mOperationsServiceConnection != null) {
+            unbindService(mOperationsServiceConnection);
+            mOperationsServiceBinder = null;
+        }
+        if (mDownloadServiceConnection != null) {
+            unbindService(mDownloadServiceConnection);
+            mDownloadServiceConnection = null;
+        }
+        if (mUploadServiceConnection != null) {
+            unbindService(mUploadServiceConnection);
+            mUploadServiceConnection = null;
+        }
+        super.onDestroy();
+    }
+    
     
     /**
      *  Sets and validates the ownCloud {@link Account} associated to the Activity. 
@@ -192,6 +299,8 @@ public abstract class FileActivity extends SherlockFragmentActivity {
         super.onSaveInstanceState(outState);
         outState.putParcelable(FileActivity.EXTRA_FILE, mFile);
         outState.putParcelable(FileActivity.EXTRA_ACCOUNT, mAccount);
+        outState.putBoolean(FileActivity.EXTRA_FROM_NOTIFICATION, mFromNotification);
+        outState.putLong(KEY_WAITING_FOR_OP_ID, mFileOperationsHelper.getOpIdWaitingFor());
     }
     
     
@@ -224,6 +333,12 @@ public abstract class FileActivity extends SherlockFragmentActivity {
         return mAccount;
     }
 
+    /**
+     * @return Value of mFromNotification: True if the Activity is launched by a notification
+     */
+    public boolean fromNotification() {
+        return mFromNotification;
+    }
     
     /**
      * @return  'True' when the Activity is finishing to enforce the setup of a new account.
@@ -233,6 +348,15 @@ public abstract class FileActivity extends SherlockFragmentActivity {
     }
     
     
+    public OperationsServiceBinder getOperationsServiceBinder() {
+        return mOperationsServiceBinder;
+    }
+    
+    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.
@@ -280,41 +404,197 @@ public abstract class FileActivity extends SherlockFragmentActivity {
      * 
      *  Child classes must grant that state depending on the {@link Account} is updated.
      */
-    protected abstract void onAccountSet(boolean stateWasRecovered);
+    protected void onAccountSet(boolean stateWasRecovered) {
+        if (getAccount() != null) {
+            mStorageManager = new FileDataStorageManager(getAccount(), getContentResolver());
+            
+        } else {
+            Log_OC.wtf(TAG, "onAccountChanged was called with NULL account associated!");
+        }
+    }
+
+
+    public FileDataStorageManager getStorageManager() {
+        return mStorageManager;
+    }
+
+
+    public OnRemoteOperationListener getRemoteOperationListener() {
+        return this;
+    }
+
+
+    public Handler getHandler() {
+        return mHandler;
+    }
     
+    public FileOperationsHelper getFileOperationsHelper() {
+        return mFileOperationsHelper;
+    }
     
-
-    public void openFile(OCFile file) {
-        if (file != null) {
-            String storagePath = file.getStoragePath();
-            String encodedStoragePath = WebdavUtils.encodePath(storagePath);
+    /**
+     * 
+     * @param operation     Removal operation performed.
+     * @param result        Result of the removal.
+     */
+    @Override
+    public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationResult result) {
+        Log_OC.d(TAG, "Received result of operation in FileActivity - common behaviour for all the FileActivities ");
+        
+        mFileOperationsHelper.setOpIdWaitingFor(Long.MAX_VALUE);
+        
+        if (!result.isSuccess() && (
+                result.getCode() == ResultCode.UNAUTHORIZED || 
+                result.isIdPRedirection() ||
+                (result.isException() && result.getException() instanceof AuthenticatorException)
+                )) {
             
-            Intent intentForSavedMimeType = new Intent(Intent.ACTION_VIEW);
-            intentForSavedMimeType.setDataAndType(Uri.parse("file://"+ encodedStoragePath), file.getMimetype());
-            intentForSavedMimeType.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+            requestCredentialsUpdate();
             
-            Intent intentForGuessedMimeType = null;
-            if (storagePath.lastIndexOf('.') >= 0) {
-                String guessedMimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(storagePath.substring(storagePath.lastIndexOf('.') + 1));
-                if (guessedMimeType != null && !guessedMimeType.equals(file.getMimetype())) {
-                    intentForGuessedMimeType = new Intent(Intent.ACTION_VIEW);
-                    intentForGuessedMimeType.setDataAndType(Uri.parse("file://"+ encodedStoragePath), guessedMimeType);
-                    intentForGuessedMimeType.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
-                }
+            if (result.getCode() == ResultCode.UNAUTHORIZED) {
+                dismissLoadingDialog();
+                Toast t = Toast.makeText(this, ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()), 
+                        Toast.LENGTH_LONG);
+                t.show();
             }
+
+        } else if (operation instanceof CreateShareOperation) {
+            onCreateShareOperationFinish((CreateShareOperation) operation, result);
             
-            Intent chooserIntent = null;
-            if (intentForGuessedMimeType != null) {
-                chooserIntent = Intent.createChooser(intentForGuessedMimeType, getString(R.string.actionbar_open_with));
-            } else {
-                chooserIntent = Intent.createChooser(intentForSavedMimeType, getString(R.string.actionbar_open_with));
-            }
+        } else if (operation instanceof UnshareLinkOperation) {
+            onUnshareLinkOperationFinish((UnshareLinkOperation)operation, result);
+        
+        } 
+    }
+
+    protected void requestCredentialsUpdate() {
+        Intent updateAccountCredentials = new Intent(this, AuthenticatorActivity.class);
+        updateAccountCredentials.putExtra(AuthenticatorActivity.EXTRA_ACCOUNT, getAccount());
+        updateAccountCredentials.putExtra(
+                AuthenticatorActivity.EXTRA_ACTION, 
+                AuthenticatorActivity.ACTION_UPDATE_EXPIRED_TOKEN);
+        updateAccountCredentials.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+        startActivity(updateAccountCredentials);
+    }
+    
+
+    private void onCreateShareOperationFinish(CreateShareOperation operation, RemoteOperationResult result) {
+        dismissLoadingDialog();
+        if (result.isSuccess()) {
+            updateFileFromDB();
+            
+            Intent sendIntent = operation.getSendIntent();
+            startActivity(sendIntent);
             
-            startActivity(chooserIntent);
+        } else { 
+            Toast t = Toast.makeText(this, ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()), 
+                    Toast.LENGTH_LONG);
+            t.show();
+        } 
+    }
+    
+    
+    private void onUnshareLinkOperationFinish(UnshareLinkOperation operation, RemoteOperationResult result) {
+        dismissLoadingDialog();
+        
+        if (result.isSuccess()){
+            updateFileFromDB();
             
         } else {
-            Log_OC.wtf(TAG, "Trying to open a NULL OCFile");
+            Toast t = Toast.makeText(this, ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()), 
+                    Toast.LENGTH_LONG);
+            t.show();
+        } 
+    }
+    
+    
+    protected void updateFileFromDB(){
+        OCFile file = getFile();
+        if (file != null) {
+            file = getStorageManager().getFileByPath(file.getRemotePath());
+            setFile(file);
         }
     }
     
+    /**
+     * Show loading dialog 
+     */
+    public void showLoadingDialog() {
+        // Construct dialog
+        LoadingDialog loading = new LoadingDialog(getResources().getString(R.string.wait_a_moment));
+        FragmentManager fm = getSupportFragmentManager();
+        FragmentTransaction ft = fm.beginTransaction();
+        loading.show(ft, DIALOG_WAIT_TAG);
+        
+    }
+
+    
+    /**
+     * Dismiss loading dialog
+     */
+    public void dismissLoadingDialog(){
+        Fragment frag = getSupportFragmentManager().findFragmentByTag(DIALOG_WAIT_TAG);
+        if (frag != null) {
+            LoadingDialog loading = (LoadingDialog) frag;
+            loading.dismiss();
+        }
+    }
+
+    
+    private void doOnResumeAndBound() {
+        mOperationsServiceBinder.addOperationListener(FileActivity.this, mHandler);
+        long waitingForOpId = mFileOperationsHelper.getOpIdWaitingFor();
+        if (waitingForOpId <= Integer.MAX_VALUE) {
+            boolean wait = mOperationsServiceBinder.dispatchResultIfFinished((int)waitingForOpId, this);
+            if (!wait ) {
+                dismissLoadingDialog();
+            }
+        }
+    }
+
+
+    /** 
+     * Implements callback methods for service binding. Passed as a parameter to { 
+     */
+    private class OperationsServiceConnection implements ServiceConnection {
+
+        @Override
+        public void onServiceConnected(ComponentName component, IBinder service) {
+            if (component.equals(new ComponentName(FileActivity.this, OperationsService.class))) {
+                Log_OC.d(TAG, "Operations service connected");
+                mOperationsServiceBinder = (OperationsServiceBinder) service;
+                /*if (!mOperationsServiceBinder.isPerformingBlockingOperation()) {
+                    dismissLoadingDialog();
+                }*/
+                doOnResumeAndBound();
+
+            } else {
+                return;
+            }
+        }
+        
+
+        @Override
+        public void onServiceDisconnected(ComponentName component) {
+            if (component.equals(new ComponentName(FileActivity.this, OperationsService.class))) {
+                Log_OC.d(TAG, "Operations service disconnected");
+                mOperationsServiceBinder = null;
+                // TODO whatever could be waiting for the service is unbound
+            }
+        }
+    }
+
+
+    @Override
+    public FileDownloaderBinder getFileDownloaderBinder() {
+        return mDownloaderBinder;
+    }
+
+
+    @Override
+    public FileUploaderBinder getFileUploaderBinder() {
+        return mUploaderBinder;
+    };    
+    
+    
 }
index 39b7bd8..b5d543a 100644 (file)
@@ -1,6 +1,6 @@
 /* ownCloud Android client application
  *   Copyright (C) 2011  Bartek Przybylski
- *   Copyright (C) 2012-2013 ownCloud Inc.
+ *   Copyright (C) 2012-2014 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.app.AlertDialog;
 import android.app.Dialog;
 import android.app.ProgressDialog;
@@ -31,7 +35,6 @@ import android.content.Context;
 import android.content.DialogInterface;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.content.IntentFilter.AuthorityEntry;
 import android.content.ServiceConnection;
 import android.content.SharedPreferences;
 import android.content.SyncRequest;
@@ -39,14 +42,12 @@ import android.content.res.Resources.NotFoundException;
 import android.database.Cursor;
 import android.net.Uri;
 import android.os.Bundle;
-import android.os.Handler;
 import android.os.IBinder;
 import android.preference.PreferenceManager;
 import android.provider.MediaStore;
 import android.support.v4.app.Fragment;
 import android.support.v4.app.FragmentManager;
 import android.support.v4.app.FragmentTransaction;
-import android.util.Log;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.ArrayAdapter;
@@ -59,37 +60,47 @@ import com.actionbarsherlock.view.Menu;
 import com.actionbarsherlock.view.MenuInflater;
 import com.actionbarsherlock.view.MenuItem;
 import com.actionbarsherlock.view.Window;
-import com.owncloud.android.Log_OC;
+import com.owncloud.android.BuildConfig;
 import com.owncloud.android.MainApp;
 import com.owncloud.android.R;
-import com.owncloud.android.datamodel.FileDataStorageManager;
 import com.owncloud.android.datamodel.OCFile;
 import com.owncloud.android.files.services.FileDownloader;
-import com.owncloud.android.files.services.FileObserverService;
-import com.owncloud.android.files.services.FileUploader;
 import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder;
+import com.owncloud.android.files.services.FileUploader;
 import com.owncloud.android.files.services.FileUploader.FileUploaderBinder;
+import com.owncloud.android.lib.common.OwnCloudAccount;
+import com.owncloud.android.lib.common.OwnCloudClient;
+import com.owncloud.android.lib.common.OwnCloudClientManagerFactory;
+import com.owncloud.android.lib.common.OwnCloudCredentials;
+import com.owncloud.android.lib.common.accounts.AccountUtils.AccountNotFoundException;
+import com.owncloud.android.lib.common.network.CertificateCombinedException;
+import com.owncloud.android.lib.common.operations.RemoteOperation;
+import com.owncloud.android.lib.common.operations.RemoteOperationResult;
+import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;
+import com.owncloud.android.lib.common.utils.Log_OC;
 import com.owncloud.android.operations.CreateFolderOperation;
-import com.owncloud.android.operations.OnRemoteOperationListener;
-import com.owncloud.android.operations.RemoteOperation;
-import com.owncloud.android.operations.RemoteOperationResult;
-import com.owncloud.android.operations.RemoteOperationResult.ResultCode;
+import com.owncloud.android.operations.CreateShareOperation;
+import com.owncloud.android.operations.MoveFileOperation;
 import com.owncloud.android.operations.RemoveFileOperation;
 import com.owncloud.android.operations.RenameFileOperation;
 import com.owncloud.android.operations.SynchronizeFileOperation;
 import com.owncloud.android.operations.SynchronizeFolderOperation;
-import com.owncloud.android.syncadapter.FileSyncService;
-import com.owncloud.android.ui.dialog.EditNameDialog;
-import com.owncloud.android.ui.dialog.EditNameDialog.EditNameDialogListener;
-import com.owncloud.android.ui.dialog.LoadingDialog;
-import com.owncloud.android.ui.dialog.SslValidatorDialog;
-import com.owncloud.android.ui.dialog.SslValidatorDialog.OnSslValidatorListener;
+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;
 import com.owncloud.android.ui.fragment.FileDetailFragment;
 import com.owncloud.android.ui.fragment.FileFragment;
 import com.owncloud.android.ui.fragment.OCFileListFragment;
 import com.owncloud.android.ui.preview.PreviewImageActivity;
+import com.owncloud.android.ui.preview.PreviewImageFragment;
 import com.owncloud.android.ui.preview.PreviewMediaFragment;
 import com.owncloud.android.ui.preview.PreviewVideoActivity;
+import com.owncloud.android.utils.DisplayUtils;
+import com.owncloud.android.utils.ErrorMessageAdapter;
 
 
 /**
@@ -99,20 +110,15 @@ import com.owncloud.android.ui.preview.PreviewVideoActivity;
  * @author David A. Velasco
  */
 
-public class FileDisplayActivity extends FileActivity implements
-OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNavigationListener, OnSslValidatorListener, OnRemoteOperationListener, EditNameDialogListener {
-
+public class FileDisplayActivity extends HookActivity implements
+FileFragment.ContainerActivity, OnNavigationListener, 
+OnSslUntrustedCertListener, OnEnforceableRefreshListener {
+    
     private ArrayAdapter<String> mDirectories;
 
-    /** Access point to the cached database for the current ownCloud {@link Account} */
-    private FileDataStorageManager mStorageManager = null;
-
     private SyncBroadcastReceiver mSyncBroadcastReceiver;
     private UploadFinishReceiver mUploadFinishReceiver;
     private DownloadFinishReceiver mDownloadFinishReceiver;
-    private FileDownloaderBinder mDownloaderBinder = null;
-    private FileUploaderBinder mUploaderBinder = null;
-    private ServiceConnection mDownloadConnection = null, mUploadConnection = null;
     private RemoteOperationResult mLastSslUntrustedServerResult = null;
 
     private boolean mDualPane;
@@ -121,18 +127,17 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
 
     private static final String KEY_WAITING_TO_PREVIEW = "WAITING_TO_PREVIEW";
     private static final String KEY_SYNC_IN_PROGRESS = "SYNC_IN_PROGRESS";
+    private static final String KEY_WAITING_TO_SEND = "WAITING_TO_SEND";
 
     public static final int DIALOG_SHORT_WAIT = 0;
     private static final int DIALOG_CHOOSE_UPLOAD_SOURCE = 1;
-    private static final int DIALOG_SSL_VALIDATOR = 2;
-    private static final int DIALOG_CERT_NOT_SAVED = 3;
+    private static final int DIALOG_CERT_NOT_SAVED = 2;
     
-    private static final String DIALOG_WAIT_TAG = "DIALOG_WAIT";
-
     public static final String ACTION_DETAILS = "com.owncloud.android.ui.activity.action.DETAILS";
 
     private static final int ACTION_SELECT_CONTENT_FROM_APPS = 1;
     private static final int ACTION_SELECT_MULTIPLE_FILES = 2;
+    public static final int ACTION_MOVE_FILES = 3;
 
     private static final String TAG = FileDisplayActivity.class.getSimpleName();
 
@@ -140,10 +145,13 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
     private static final String TAG_SECOND_FRAGMENT = "SECOND_FRAGMENT";
 
     private OCFile mWaitingToPreview;
-    private Handler mHandler;
     
     private boolean mSyncInProgress = false;
 
+    private String DIALOG_UNTRUSTED_CERT;
+    
+    private OCFile mWaitingToSend;
+    
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         Log_OC.d(TAG, "onCreate() start");
@@ -151,32 +159,29 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
 
         super.onCreate(savedInstanceState); // this calls onAccountChanged() when ownCloud Account is valid
 
-        mHandler = new Handler();
-        
-        /// bindings to transference services
-        mUploadConnection = new ListServiceConnection(); 
-        mDownloadConnection = new ListServiceConnection();
-        bindService(new Intent(this, FileUploader.class), mUploadConnection, Context.BIND_AUTO_CREATE);
-        bindService(new Intent(this, FileDownloader.class), mDownloadConnection, Context.BIND_AUTO_CREATE);
-
         // PIN CODE request ;  best location is to decide, let's try this first
         if (getIntent().getAction() != null && getIntent().getAction().equals(Intent.ACTION_MAIN) && savedInstanceState == null) {
             requestPinCode();
+        } else if (getIntent().getAction() == null && savedInstanceState == null) {
+            requestPinCode();
         }
 
-        /// file observer
-        Intent observer_intent = new Intent(this, FileObserverService.class);
-        observer_intent.putExtra(FileObserverService.KEY_FILE_CMD, FileObserverService.CMD_INIT_OBSERVED_LIST);
-        startService(observer_intent);
-
+        /// grant that FileObserverService is watching favourite files
+        if (savedInstanceState == null) {
+            Intent initObserversIntent = FileObserverService.makeInitIntent(this);
+            startService(initObserversIntent);
+        }
+        
         /// Load of saved instance state
         if(savedInstanceState != null) {
             mWaitingToPreview = (OCFile) savedInstanceState.getParcelable(FileDisplayActivity.KEY_WAITING_TO_PREVIEW);
             mSyncInProgress = savedInstanceState.getBoolean(KEY_SYNC_IN_PROGRESS);
+            mWaitingToSend = (OCFile) savedInstanceState.getParcelable(FileDisplayActivity.KEY_WAITING_TO_SEND);
            
         } else {
             mWaitingToPreview = null;
             mSyncInProgress = false;
+            mWaitingToSend = null;
         }        
 
         /// USER INTERFACE
@@ -193,32 +198,31 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
         // Action bar setup
         mDirectories = new CustomArrayAdapter<String>(this, R.layout.sherlock_spinner_dropdown_item);
         getSupportActionBar().setHomeButtonEnabled(true);       // mandatory since Android ICS, according to the official documentation
-        setSupportProgressBarIndeterminateVisibility(mSyncInProgress);    // always AFTER setContentView(...) ; to work around bug in its implementation        
-        
-        
+        setSupportProgressBarIndeterminateVisibility(mSyncInProgress /*|| mRefreshSharesInProgress*/);    // always AFTER setContentView(...) ; to work around bug in its implementation
         
+        setBackgroundText();
+
         Log_OC.d(TAG, "onCreate() end");
     }
-
+    
+    @Override
+    protected void onStart() {
+        super.onStart();
+        getSupportActionBar().setIcon(DisplayUtils.getSeasonalIconId());
+    }
 
     @Override
     protected void onDestroy() {
         super.onDestroy();
-        if (mDownloadConnection != null)
-            unbindService(mDownloadConnection);
-        if (mUploadConnection != null)
-            unbindService(mUploadConnection);
     }
 
-
     /**
      *  Called when the ownCloud {@link Account} associated to the Activity was just updated.
      */ 
     @Override
     protected void onAccountSet(boolean stateWasRecovered) {
+        super.onAccountSet(stateWasRecovered);
         if (getAccount() != null) {
-            mStorageManager = new FileDataStorageManager(getAccount(), getContentResolver());
-
             /// Check whether the 'main' OCFile handled by the Activity is contained in the current Account
             OCFile file = getFile();
             // get parent from path
@@ -228,33 +232,30 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
                     // upload in progress - right now, files are not inserted in the local cache until the upload is successful
                     // get parent from path
                     parentPath = file.getRemotePath().substring(0, file.getRemotePath().lastIndexOf(file.getFileName()));
-                    if (mStorageManager.getFileByPath(parentPath) ==  null)
+                    if (getStorageManager().getFileByPath(parentPath) ==  null)
                         file = null; // not able to know the directory where the file is uploading
                 } else {
-                    file = mStorageManager.getFileByPath(file.getRemotePath());   // currentDir = null if not in the current Account
+                    file = getStorageManager().getFileByPath(file.getRemotePath());   // currentDir = null if not in the current Account
                 }
             }
             if (file == null) {
                 // fall back to root folder
-                file = mStorageManager.getFileByPath(OCFile.ROOT_PATH);  // never returns null
+                file = getStorageManager().getFileByPath(OCFile.ROOT_PATH);  // never returns null
             }
             setFile(file);
             setNavigationListWithFolder(file);
+            
             if (!stateWasRecovered) {
                 Log_OC.e(TAG, "Initializing Fragments in onAccountChanged..");
                 initFragmentsWithFile();
                 if (file.isFolder()) {
-                    startSyncFolderOperation(file);
+                    startSyncFolderOperation(file, false);
                 }
                 
             } else {
                 updateFragmentsVisibility(!file.isFolder());
                 updateNavigationElementsInActionBar(file.isFolder() ? null : file);
             }
-            
-            
-        } else {
-            Log_OC.wtf(TAG, "onAccountChanged was called with NULL account associated!");
         }
     }
 
@@ -267,10 +268,9 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
             if (fileIt.isFolder()) {
                 mDirectories.add(fileIt.getFileName());
             }
-            //fileIt = mStorageManager.getFileById(fileIt.getParentId());
             // get parent from path
             parentPath = fileIt.getRemotePath().substring(0, fileIt.getRemotePath().lastIndexOf(fileIt.getFileName()));
-            fileIt = mStorageManager.getFileByPath(parentPath);
+            fileIt = getStorageManager().getFileByPath(parentPath);
         }
         mDirectories.add(OCFile.PATH_SEPARATOR);
     }
@@ -282,7 +282,7 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
         transaction.add(R.id.left_fragment_container, listOfFiles, TAG_LIST_OF_FILES);
         transaction.commit();
     }
-
+    
     private void initFragmentsWithFile() {
         if (getAccount() != null && getFile() != null) {
             /// First fragment
@@ -290,7 +290,7 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
             if (listOfFiles != null) {
                 listOfFiles.listDirectory(getCurrentDir());   
             } else {
-                Log.e(TAG, "Still have a chance to lose the initializacion of list fragment >(");
+                Log_OC.e(TAG, "Still have a chance to lose the initializacion of list fragment >(");
             }
             
             /// Second fragment
@@ -306,12 +306,12 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
             }
 
         } else {
-            Log.wtf(TAG, "initFragments() called with invalid NULLs!");
+            Log_OC.wtf(TAG, "initFragments() called with invalid NULLs!");
             if (getAccount() == null) {
-                Log.wtf(TAG, "\t account is NULL");
+                Log_OC.wtf(TAG, "\t account is NULL");
             }
             if (getFile() == null) {
-                Log.wtf(TAG, "\t file is NULL");
+                Log_OC.wtf(TAG, "\t file is NULL");
             }
         }
     }
@@ -386,7 +386,7 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
         return null;
     }
 
-    protected FileFragment getSecondFragment() {
+    public FileFragment getSecondFragment() {
         Fragment second = getSupportFragmentManager().findFragmentByTag(FileDisplayActivity.TAG_SECOND_FRAGMENT);
         if (second != null) {
             return (FileFragment)second;
@@ -394,7 +394,7 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
         return null;
     }
 
-    public void cleanSecondFragment() {
+    protected void cleanSecondFragment() {
         Fragment second = getSecondFragment();
         if (second != null) {
             FragmentTransaction tr = getSupportFragmentManager().beginTransaction();
@@ -405,7 +405,7 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
         updateNavigationElementsInActionBar(null);
     }
 
-    protected void refeshListOfFilesFragment() {
+    protected void refreshListOfFilesFragment() {
         OCFileListFragment fileListFragment = getListOfFilesFragment();
         if (fileListFragment != null) { 
             fileListFragment.listDirectory();
@@ -432,12 +432,12 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
                 boolean detailsFragmentChanged = false;
                 if (waitedPreview) {
                     if (success) {
-                        mWaitingToPreview = mStorageManager.getFileById(mWaitingToPreview.getFileId());   // update the file from database, for the local storage path
+                        mWaitingToPreview = getStorageManager().getFileById(mWaitingToPreview.getFileId());   // update the file from database, for the local storage path
                         if (PreviewMediaFragment.canBePreviewed(mWaitingToPreview)) {
                             startMediaPreview(mWaitingToPreview, 0, true);
                             detailsFragmentChanged = true;
                         } else {
-                            openFile(mWaitingToPreview);
+                            getFileOperationsHelper().openFile(mWaitingToPreview);
                         }
                     }
                     mWaitingToPreview = null;
@@ -449,6 +449,15 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
         }
     }
 
+    @Override
+    public boolean onPrepareOptionsMenu(Menu menu) {
+        if (BuildConfig.DEBUG) {
+            menu.findItem(R.id.action_logger).setVisible(true);
+        } else {
+            menu.findItem(R.id.action_logger).setVisible(false);
+        }
+        return super.onPrepareOptionsMenu(menu);
+    }
 
     @Override
     public boolean onCreateOptionsMenu(Menu menu) {
@@ -462,7 +471,8 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
         boolean retval = true;
         switch (item.getItemId()) {
         case R.id.action_create_dir: {
-            EditNameDialog dialog = EditNameDialog.newInstance(getString(R.string.uploader_info_dirname), "", -1, -1, this);
+            CreateFolderDialogFragment dialog = 
+                    CreateFolderDialogFragment.newInstance(getCurrentDir());
             dialog.show(getSupportFragmentManager(), "createdirdialog");
             break;
         }
@@ -479,6 +489,11 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
             startActivity(settingsIntent);
             break;
         }
+        case R.id.action_logger: {
+            Intent loggerIntent = new Intent(getApplicationContext(),LogHistoryActivity.class);
+            startActivity(loggerIntent);
+            break;
+        }
         case android.R.id.home: {
             FileFragment second = getSecondFragment();
             OCFile currentDir = getCurrentDir();
@@ -489,6 +504,40 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
             }
             break;
         }
+        case R.id.action_sort: {
+            SharedPreferences appPreferences = PreferenceManager
+                    .getDefaultSharedPreferences(this);
+            
+            // Read sorting order, default to sort by name ascending
+            Integer sortOrder = appPreferences
+                    .getInt("sortOrder", FileListListAdapter.SORT_NAME);
+            
+            AlertDialog.Builder builder = new AlertDialog.Builder(this);
+            builder.setTitle(R.string.actionbar_sort_title)
+            .setSingleChoiceItems(R.array.actionbar_sortby, sortOrder , new DialogInterface.OnClickListener() {
+                public void onClick(DialogInterface dialog, int which) {
+                    
+                    switch (which){
+                    case 0:
+                        sortByName(true);
+                        break;
+                    case 1:
+                        sortByDate(false);
+                        break;
+                        
+// TODO re-enable when server-side folder size calculation is available                       
+//                    case 2:
+//                        sortBySize(false);
+//                        break;
+                    }
+                    
+                    dialog.dismiss();
+                    
+                }
+            });
+            builder.create().show();
+            break;
+        }
         default:
             retval = super.onOptionsItemSelected(item);
         }
@@ -528,7 +577,7 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
                 targetPath = mDirectories.getItem(i) + OCFile.PATH_SEPARATOR + targetPath; 
             }
             targetPath = OCFile.PATH_SEPARATOR + targetPath;
-            OCFile targetFolder = mStorageManager.getFileByPath(targetPath);
+            OCFile targetFolder = getStorageManager().getFileByPath(targetPath);
             if (targetFolder != null) {
                 browseTo(targetFolder);
             }
@@ -536,7 +585,8 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
             // the next operation triggers a new call to this method, but it's necessary to 
             // ensure that the name exposed in the action bar is the current directory when the 
             // user selected it in the navigation list
-            getSupportActionBar().setSelectedNavigationItem(0);
+            if (getSupportActionBar().getNavigationMode() == ActionBar.NAVIGATION_MODE_LIST  && itemPosition != 0) 
+                getSupportActionBar().setSelectedNavigationItem(0);
         }
         return true;
     }
@@ -553,6 +603,20 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
         } else if (requestCode == ACTION_SELECT_MULTIPLE_FILES && (resultCode == RESULT_OK || resultCode == UploadFilesActivity.RESULT_OK_AND_MOVE)) {
             requestMultipleUpload(data, resultCode);
 
+        } else if (requestCode == ACTION_MOVE_FILES && (resultCode == RESULT_OK || 
+                resultCode == MoveActivity.RESULT_OK_AND_MOVE)){
+
+            final Intent fData = data;
+            final int fResultCode = resultCode; 
+            getHandler().postDelayed(
+                new Runnable() {
+                    @Override
+                    public void run() {
+                        requestMoveOperation(fData, fResultCode);
+                    }
+                }, 
+                DELAY_TO_REQUEST_OPERATION_ON_ACTIVITY_RESULTS
+            );
         }
     }
 
@@ -633,6 +697,18 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
         startService(i);
     }
 
+    /**
+     * Request the operation for moving the file/folder from one path to another
+     * 
+     * @param data              Intent received
+     * @param resultCode        Result code received
+     */
+    private void requestMoveOperation(Intent data, int resultCode) {
+        OCFile folderToMoveAt = (OCFile) data.getParcelableExtra(MoveActivity.EXTRA_CURRENT_FOLDER);
+        OCFile targetFile = (OCFile) data.getParcelableExtra(MoveActivity.EXTRA_TARGET_FILE);
+        getFileOperationsHelper().moveFile(folderToMoveAt, targetFile);
+    }
+
     @Override
     public void onBackPressed() {
         OCFileListFragment listOfFiles = getListOfFilesFragment(); 
@@ -662,6 +738,8 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
         super.onSaveInstanceState(outState);
         outState.putParcelable(FileDisplayActivity.KEY_WAITING_TO_PREVIEW, mWaitingToPreview);
         outState.putBoolean(FileDisplayActivity.KEY_SYNC_IN_PROGRESS, mSyncInProgress);
+        //outState.putBoolean(FileDisplayActivity.KEY_REFRESH_SHARES_IN_PROGRESS, mRefreshSharesInProgress);
+        outState.putParcelable(FileDisplayActivity.KEY_WAITING_TO_SEND, mWaitingToSend);
 
         Log_OC.d(TAG, "onSaveInstanceState() end");
     }
@@ -672,11 +750,19 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
     protected void onResume() {
         super.onResume();
         Log_OC.e(TAG, "onResume() start");
+        
+        // refresh list of files
+        refreshListOfFilesFragment();
 
         // Listen for sync messages
-        IntentFilter syncIntentFilter = new IntentFilter(FileSyncService.getSyncMessage());
+        IntentFilter syncIntentFilter = new IntentFilter(FileSyncAdapter.EVENT_FULL_SYNC_START);
+        syncIntentFilter.addAction(FileSyncAdapter.EVENT_FULL_SYNC_END);
+        syncIntentFilter.addAction(FileSyncAdapter.EVENT_FULL_SYNC_FOLDER_CONTENTS_SYNCED);
+        syncIntentFilter.addAction(SynchronizeFolderOperation.EVENT_SINGLE_FOLDER_CONTENTS_SYNCED);
+        syncIntentFilter.addAction(SynchronizeFolderOperation.EVENT_SINGLE_FOLDER_SHARES_SYNCED);
         mSyncBroadcastReceiver = new SyncBroadcastReceiver();
         registerReceiver(mSyncBroadcastReceiver, syncIntentFilter);
+        //LocalBroadcastManager.getInstance(this).registerReceiver(mSyncBroadcastReceiver, syncIntentFilter);
 
         // Listen for upload messages
         IntentFilter uploadIntentFilter = new IntentFilter(FileUploader.getUploadFinishMessage());
@@ -688,17 +774,17 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
         downloadIntentFilter.addAction(FileDownloader.getDownloadFinishMessage());
         mDownloadFinishReceiver = new DownloadFinishReceiver();
         registerReceiver(mDownloadFinishReceiver, downloadIntentFilter);
-    
+        
         Log_OC.d(TAG, "onResume() end");
     }
 
 
     @Override
     protected void onPause() {
-        super.onPause();
         Log_OC.e(TAG, "onPause() start");
         if (mSyncBroadcastReceiver != null) {
             unregisterReceiver(mSyncBroadcastReceiver);
+            //LocalBroadcastManager.getInstance(this).unregisterReceiver(mSyncBroadcastReceiver);
             mSyncBroadcastReceiver = null;
         }
         if (mUploadFinishReceiver != null) {
@@ -709,16 +795,10 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
             unregisterReceiver(mDownloadFinishReceiver);
             mDownloadFinishReceiver = null;
         }
-
+        
+        
         Log_OC.d(TAG, "onPause() end");
-    }
-
-
-    @Override
-    protected void onPrepareDialog(int id, Dialog dialog, Bundle args) {
-        if (id == DIALOG_SSL_VALIDATOR && mLastSslUntrustedServerResult != null) {
-            ((SslValidatorDialog)dialog).updateResult(mLastSslUntrustedServerResult);
-        }
+        super.onPause();
     }
 
 
@@ -738,23 +818,13 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
         }
         case DIALOG_CHOOSE_UPLOAD_SOURCE: {
 
-            String[] items = null;
 
             String[] allTheItems = { getString(R.string.actionbar_upload_files),
-                    getString(R.string.actionbar_upload_from_apps),
-                    getString(R.string.actionbar_failed_instant_upload) };
-
-            String[] commonItems = { getString(R.string.actionbar_upload_files),
                     getString(R.string.actionbar_upload_from_apps) };
 
-            if (InstantUploadActivity.IS_ENABLED)
-                items = allTheItems;
-            else 
-                items = commonItems;
-
             builder = new AlertDialog.Builder(this);
             builder.setTitle(R.string.actionbar_upload);
-            builder.setItems(items, new DialogInterface.OnClickListener() {
+            builder.setItems(allTheItems, new DialogInterface.OnClickListener() {
                 public void onClick(DialogInterface dialog, int item) {
                     if (item == 0) {
                         // if (!mDualPane) {
@@ -770,20 +840,12 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
                         action = action.setType("*/*").addCategory(Intent.CATEGORY_OPENABLE);
                         startActivityForResult(Intent.createChooser(action, getString(R.string.upload_chooser_title)),
                                 ACTION_SELECT_CONTENT_FROM_APPS);
-                    } else if (item == 2 && InstantUploadActivity.IS_ENABLED) {
-                        Intent action = new Intent(FileDisplayActivity.this, InstantUploadActivity.class);
-                        action.putExtra(FileUploader.KEY_ACCOUNT, FileDisplayActivity.this.getAccount());
-                        startActivity(action);
                     }
                 }
             });
             dialog = builder.create();
             break;
         }
-        case DIALOG_SSL_VALIDATOR: {
-            dialog = SslValidatorDialog.newInstance(this, mLastSslUntrustedServerResult, this);
-            break;
-        }
         case DIALOG_CERT_NOT_SAVED: {
             builder = new AlertDialog.Builder(this);
             builder.setMessage(getResources().getString(R.string.ssl_validator_not_saved));
@@ -806,30 +868,6 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
 
 
     /**
-     * Show loading dialog 
-     */
-    public void showLoadingDialog() {
-        // Construct dialog
-        LoadingDialog loading = new LoadingDialog(getResources().getString(R.string.wait_a_moment));
-        FragmentManager fm = getSupportFragmentManager();
-        FragmentTransaction ft = fm.beginTransaction();
-        loading.show(ft, DIALOG_WAIT_TAG);
-        
-    }
-    
-    /**
-     * Dismiss loading dialog
-     */
-    public void dismissLoadingDialog(){
-        Fragment frag = getSupportFragmentManager().findFragmentByTag(DIALOG_WAIT_TAG);
-      if (frag != null) {
-          LoadingDialog loading = (LoadingDialog) frag;
-            loading.dismiss();
-        }
-    }
-    
-    
-    /**
      * Translates a content URI of an image to a physical path
      * on the disk
      * @param uri The URI to resolve
@@ -881,6 +919,8 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
 
             ((TextView) v).setTextColor(getResources().getColorStateList(
                     android.R.color.white));
+            
+            fixRoot((TextView) v );
             return v;
         }
 
@@ -891,9 +931,16 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
             ((TextView) v).setTextColor(getResources().getColorStateList(
                     android.R.color.white));
 
+            fixRoot((TextView) v );
             return v;
         }
 
+        private void fixRoot(TextView v) {
+            if (v.getText().equals(OCFile.PATH_SEPARATOR)) {
+                v.setText(R.string.default_display_name_for_root_folder);
+            }
+        }
+
     }
 
     private class SyncBroadcastReceiver extends BroadcastReceiver {
@@ -903,59 +950,136 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
          */
         @Override
         public void onReceive(Context context, Intent intent) {
-            boolean inProgress = intent.getBooleanExtra(FileSyncService.IN_PROGRESS, false);
-            String accountName = intent.getStringExtra(FileSyncService.ACCOUNT_NAME);
-            RemoteOperationResult synchResult = (RemoteOperationResult)intent.getSerializableExtra(FileSyncService.SYNC_RESULT);
-
-            if (getAccount() != null && accountName.equals(getAccount().name)
-                    && mStorageManager != null
-                    ) {  
-
-                String synchFolderRemotePath = intent.getStringExtra(FileSyncService.SYNC_FOLDER_REMOTE_PATH); 
-
-                OCFile currentFile = (getFile() == null) ? null : mStorageManager.getFileByPath(getFile().getRemotePath());
-                OCFile currentDir = (getCurrentDir() == null) ? null : mStorageManager.getFileByPath(getCurrentDir().getRemotePath());
-
-                if (currentDir == null) {
-                    // current folder was removed from the server 
-                    Toast.makeText( FileDisplayActivity.this, 
-                                    String.format(getString(R.string.sync_current_folder_was_removed), mDirectories.getItem(0)), 
-                                    Toast.LENGTH_LONG)
-                        .show();
-                    browseToRoot();
+            try {
+                String event = intent.getAction();
+                Log_OC.d(TAG, "Received broadcast " + event);
+                String accountName = intent.getStringExtra(FileSyncAdapter.EXTRA_ACCOUNT_NAME);
+                String synchFolderRemotePath = intent.getStringExtra(FileSyncAdapter.EXTRA_FOLDER_PATH); 
+                RemoteOperationResult synchResult = (RemoteOperationResult)intent.getSerializableExtra(FileSyncAdapter.EXTRA_RESULT);
+                boolean sameAccount = (getAccount() != null && accountName.equals(getAccount().name) && getStorageManager() != null); 
+    
+                if (sameAccount) {
                     
-                } else {
-                    if (currentFile == null && !getFile().isFolder()) {
-                        // currently selected file was removed in the server, and now we know it
-                        cleanSecondFragment();
-                        currentFile = currentDir;
-                    }
-                
-                    if (synchFolderRemotePath != null && currentDir.getRemotePath().equals(synchFolderRemotePath)) {
-                        OCFileListFragment fileListFragment = getListOfFilesFragment();
-                        if (fileListFragment != null) {
-                            fileListFragment.listDirectory(currentDir);
+                    if (FileSyncAdapter.EVENT_FULL_SYNC_START.equals(event)) {
+                        mSyncInProgress = true;
+                        
+                    } else {
+                        OCFile currentFile = (getFile() == null) ? null : getStorageManager().getFileByPath(getFile().getRemotePath());
+                        OCFile currentDir = (getCurrentDir() == null) ? null : getStorageManager().getFileByPath(getCurrentDir().getRemotePath());
+    
+                        if (currentDir == null) {
+                            // current folder was removed from the server 
+                            Toast.makeText( FileDisplayActivity.this, 
+                                            String.format(getString(R.string.sync_current_folder_was_removed), mDirectories.getItem(0)), 
+                                            Toast.LENGTH_LONG)
+                                .show();
+                            browseToRoot();
+                            
+                        } else {
+                            if (currentFile == null && !getFile().isFolder()) {
+                                // currently selected file was removed in the server, and now we know it
+                                cleanSecondFragment();
+                                currentFile = currentDir;
+                            }
+
+                            if (synchFolderRemotePath != null && currentDir.getRemotePath().equals(synchFolderRemotePath)) {
+                                OCFileListFragment fileListFragment = getListOfFilesFragment();
+                                if (fileListFragment != null) {
+                                    fileListFragment.listDirectory(currentDir);
+                                }
+                            }
+                            setFile(currentFile);
+                        }
+                        
+                        mSyncInProgress = (!FileSyncAdapter.EVENT_FULL_SYNC_END.equals(event) && !SynchronizeFolderOperation.EVENT_SINGLE_FOLDER_SHARES_SYNCED.equals(event));
+                                
+                        if (SynchronizeFolderOperation.EVENT_SINGLE_FOLDER_CONTENTS_SYNCED.
+                                    equals(event) &&
+                                /// TODO refactor and make common
+                                synchResult != null && !synchResult.isSuccess() &&  
+                                (synchResult.getCode() == ResultCode.UNAUTHORIZED   || 
+                                    synchResult.isIdPRedirection()                  ||
+                                    (synchResult.isException() && synchResult.getException() 
+                                            instanceof AuthenticatorException))) {
+
+                            OwnCloudClient client = null;
+                            try {
+                                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());
+                                    }
+                                }
+                            }
+                            
+                            requestCredentialsUpdate();
+                            
                         }
                     }
-                    setFile(currentFile);
+                    removeStickyBroadcast(intent);
+                    Log_OC.d(TAG, "Setting progress visibility to " + mSyncInProgress);
+                    setSupportProgressBarIndeterminateVisibility(mSyncInProgress /*|| mRefreshSharesInProgress*/);
+
+                    setBackgroundText();
+                        
                 }
                 
-                setSupportProgressBarIndeterminateVisibility(inProgress);
-                removeStickyBroadcast(intent);
-                mSyncInProgress = inProgress;
-
-            }
-            
-            if (synchResult != null) {
-                if (synchResult.getCode().equals(RemoteOperationResult.ResultCode.SSL_RECOVERABLE_PEER_UNVERIFIED)) {
-                    mLastSslUntrustedServerResult = synchResult;
-                    showDialog(DIALOG_SSL_VALIDATOR); 
+                if (synchResult != null) {
+                    if (synchResult.getCode().equals(RemoteOperationResult.ResultCode.SSL_RECOVERABLE_PEER_UNVERIFIED)) {
+                        mLastSslUntrustedServerResult = synchResult;
+                    }
                 }
+            } catch (RuntimeException e) {
+                // avoid app crashes after changing the serial id of RemoteOperationResult 
+                // in owncloud library with broadcast notifications pending to process
+                removeStickyBroadcast(intent);
             }
         }
     }
     
+    /**
+     * Show a text message on screen view for notifying user if content is
+     * loading or folder is empty
+     */
+    private void setBackgroundText() {
+        OCFileListFragment ocFileListFragment = getListOfFilesFragment();
+        if (ocFileListFragment != null) {
+            int message = R.string.file_list_loading;
+            if (!mSyncInProgress) {
+                // In case file list is empty
+                message = R.string.file_list_empty;
+            }
+            ocFileListFragment.setMessageForEmptyList(getString(message));
+        } else {
+            Log_OC.e(TAG, "OCFileListFragment is null");
+        }
+    }
 
+    /**
+     * Once the file upload has finished -> update view
+     */
     private class UploadFinishReceiver extends BroadcastReceiver {
         /**
          * Once the file upload has finished -> update view
@@ -964,16 +1088,61 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
          */
         @Override
         public void onReceive(Context context, Intent intent) {
-            String uploadedRemotePath = intent.getStringExtra(FileDownloader.EXTRA_REMOTE_PATH);
-            String accountName = intent.getStringExtra(FileUploader.ACCOUNT_NAME);
-            boolean sameAccount = getAccount() != null && accountName.equals(getAccount().name);
-            OCFile currentDir = getCurrentDir();
-            boolean isDescendant = (currentDir != null) && (uploadedRemotePath != null) && (uploadedRemotePath.startsWith(currentDir.getRemotePath()));
-            if (sameAccount && isDescendant) {
-                refeshListOfFilesFragment();
+            try {
+                String uploadedRemotePath = intent.getStringExtra(FileDownloader.EXTRA_REMOTE_PATH);
+                String accountName = intent.getStringExtra(FileUploader.ACCOUNT_NAME);
+                boolean sameAccount = getAccount() != null && accountName.equals(getAccount().name);
+                OCFile currentDir = getCurrentDir();
+                boolean isDescendant = (currentDir != null) && (uploadedRemotePath != null) && 
+                        (uploadedRemotePath.startsWith(currentDir.getRemotePath()));
+                
+                if (sameAccount && isDescendant) {
+                    refreshListOfFilesFragment();
+                }
+                
+                boolean uploadWasFine = intent.getBooleanExtra(FileUploader.EXTRA_UPLOAD_RESULT, false);
+                boolean renamedInUpload = getFile().getRemotePath().
+                        equals(intent.getStringExtra(FileUploader.EXTRA_OLD_REMOTE_PATH));
+                boolean sameFile = getFile().getRemotePath().equals(uploadedRemotePath) || 
+                        renamedInUpload;
+                FileFragment details = getSecondFragment();
+                boolean detailFragmentIsShown = (details != null && 
+                        details instanceof FileDetailFragment);
+                
+                if (sameAccount && sameFile && detailFragmentIsShown) {
+                    if (uploadWasFine) {
+                        setFile(getStorageManager().getFileByPath(uploadedRemotePath));
+                    }
+                    if (renamedInUpload) {
+                        String newName = (new File(uploadedRemotePath)).getName();
+                        Toast msg = Toast.makeText(
+                                context, 
+                                String.format(
+                                        getString(R.string.filedetails_renamed_in_upload_msg), 
+                                        newName), 
+                                Toast.LENGTH_LONG);
+                        msg.show();
+                    }
+                    if (uploadWasFine || getFile().fileExists()) {
+                        ((FileDetailFragment)details).updateFileDetails(false, true);
+                    } else {
+                        cleanSecondFragment();
+                    }
+                    
+                    // Force the preview if the file is an image
+                    if (uploadWasFine && PreviewImageFragment.canBePreviewed(getFile())) {
+                        startImagePreview(getFile());
+                    } // TODO what about other kind of previews?
+                }
+                
+            } finally {
+                if (intent != null) {
+                    removeStickyBroadcast(intent);
+                }
             }
+            
         }
-
+        
     }
 
 
@@ -986,16 +1155,28 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
     private class DownloadFinishReceiver extends BroadcastReceiver {
         @Override
         public void onReceive(Context context, Intent intent) {
-            boolean sameAccount = isSameAccount(context, intent);
-            String downloadedRemotePath = intent.getStringExtra(FileDownloader.EXTRA_REMOTE_PATH);
-            boolean isDescendant = isDescendant(downloadedRemotePath);
-
-            if (sameAccount && isDescendant) {
-                refeshListOfFilesFragment();
-                refreshSecondFragment(intent.getAction(), downloadedRemotePath, intent.getBooleanExtra(FileDownloader.EXTRA_DOWNLOAD_RESULT, false));
+            try {
+                boolean sameAccount = isSameAccount(context, intent);
+                String downloadedRemotePath = intent.getStringExtra(FileDownloader.EXTRA_REMOTE_PATH);
+                boolean isDescendant = isDescendant(downloadedRemotePath);
+    
+                if (sameAccount && isDescendant) {
+                    refreshListOfFilesFragment();
+                    refreshSecondFragment(intent.getAction(), downloadedRemotePath, intent.getBooleanExtra(FileDownloader.EXTRA_DOWNLOAD_RESULT, false));
+                }
+    
+                if (mWaitingToSend != null) {
+                    mWaitingToSend = getStorageManager().getFileByPath(mWaitingToSend.getRemotePath()); // Update the file to send
+                    if (mWaitingToSend.isDown()) { 
+                        sendDownloadedFile();
+                    }
+                }
+            
+            } finally {
+                if (intent != null) {
+                    removeStickyBroadcast(intent);
+                }
             }
-
-            removeStickyBroadcast(intent);
         }
 
         private boolean isDescendant(String downloadedRemotePath) {
@@ -1008,27 +1189,18 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
             return (accountName != null && getAccount() != null && accountName.equals(getAccount().name));
         }
     }
-
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public FileDataStorageManager getStorageManager() {
-        return mStorageManager;
-    }
-
-
+    
+    
     public void browseToRoot() {
         OCFileListFragment listOfFiles = getListOfFilesFragment(); 
         if (listOfFiles != null) {  // should never be null, indeed
             while (mDirectories.getCount() > 1) {
                 popDirname();
             }
-            OCFile root = mStorageManager.getFileByPath(OCFile.ROOT_PATH);
+            OCFile root = getStorageManager().getFileByPath(OCFile.ROOT_PATH);
             listOfFiles.listDirectory(root);
             setFile(listOfFiles.getCurrentFile());
-            startSyncFolderOperation(root);
+            startSyncFolderOperation(root, false);
         }
         cleanSecondFragment();
     }
@@ -1043,7 +1215,7 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
             setNavigationListWithFolder(folder);
             listOfFiles.listDirectory(folder);
             setFile(listOfFiles.getCurrentFile());
-            startSyncFolderOperation(folder);
+            startSyncFolderOperation(folder, false);
         } else {
             Log_OC.e(TAG, "Unexpected null when accessing list fragment");
         }
@@ -1062,59 +1234,11 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
         cleanSecondFragment();
         
         // Sync Folder
-        startSyncFolderOperation(directory);
+        startSyncFolderOperation(directory, false);
         
     }
 
     /**
-     * Opens the image gallery showing the image {@link OCFile} received as parameter.
-     * 
-     * @param file                      Image {@link OCFile} to show.
-     */
-    @Override
-    public void startImagePreview(OCFile file) {
-        Intent showDetailsIntent = new Intent(this, PreviewImageActivity.class);
-        showDetailsIntent.putExtra(EXTRA_FILE, file);
-        showDetailsIntent.putExtra(EXTRA_ACCOUNT, getAccount());
-        startActivity(showDetailsIntent);
-    }
-
-    /**
-     * Stars the preview of an already down media {@link OCFile}.
-     * 
-     * @param file                      Media {@link OCFile} to preview.
-     * @param startPlaybackPosition     Media position where the playback will be started, in milliseconds.
-     * @param autoplay                  When 'true', the playback will start without user interactions.
-     */
-    @Override
-    public void startMediaPreview(OCFile file, int startPlaybackPosition, boolean autoplay) {
-        Fragment mediaFragment = new PreviewMediaFragment(file, getAccount(), startPlaybackPosition, autoplay);
-        setSecondFragment(mediaFragment);
-        updateFragmentsVisibility(true);
-        updateNavigationElementsInActionBar(file);
-        setFile(file);
-    }
-
-    /**
-     * Requests the download of the received {@link OCFile} , updates the UI
-     * to monitor the download progress and prepares the activity to preview
-     * or open the file when the download finishes.
-     * 
-     * @param file          {@link OCFile} to download and preview.
-     */
-    @Override
-    public void startDownloadForPreview(OCFile file) {
-        Fragment detailFragment = new FileDetailFragment(file, getAccount());
-        setSecondFragment(detailFragment);
-        mWaitingToPreview = file;
-        requestForDownload();
-        updateFragmentsVisibility(true);
-        updateNavigationElementsInActionBar(file);
-        setFile(file);
-    }
-
-
-    /**
      * Shows the information of the {@link OCFile} received as a 
      * parameter in the second fragment.
      * 
@@ -1138,9 +1262,13 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
         if (chosenFile == null || mDualPane) {
             // only list of files - set for browsing through folders
             OCFile currentDir = getCurrentDir();
-            actionBar.setDisplayHomeAsUpEnabled(currentDir != null && currentDir.getParentId() != 0);
-            actionBar.setDisplayShowTitleEnabled(false);
-            actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
+            boolean noRoot = (currentDir != null && currentDir.getParentId() != 0);
+            actionBar.setDisplayHomeAsUpEnabled(noRoot);
+            actionBar.setDisplayShowTitleEnabled(!noRoot); 
+            if (!noRoot) {
+                actionBar.setTitle(getString(R.string.default_display_name_for_root_folder));
+            }
+            actionBar.setNavigationMode(!noRoot ? ActionBar.NAVIGATION_MODE_STANDARD : ActionBar.NAVIGATION_MODE_LIST);
             actionBar.setListNavigationCallbacks(mDirectories, this);   // assuming mDirectories is updated
 
         } else {
@@ -1152,47 +1280,11 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
     }
 
 
-//    private void updateDisplayHomeAtSync(){
-//        ActionBar actionBar = getSupportActionBar();
-//        OCFile currentDir = getCurrentDir();
-//        if (currentDir.getParentId() != DataStorageManager.ROOT_PARENT_ID) {
-//            actionBar.setHomeButtonEnabled(!mSyncInProgress);
-//            actionBar.setDisplayHomeAsUpEnabled(!mSyncInProgress);
-//        }
-//        else {
-//            actionBar.setHomeButtonEnabled(true);
-//            actionBar.setDisplayHomeAsUpEnabled(false);
-//        }
-//    }
-//    
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void onFileStateChanged() {
-        refeshListOfFilesFragment();
-        updateNavigationElementsInActionBar(getSecondFragment().getFile());
-    }
-
-
-    /**
-     * {@inheritDoc}
-     */
     @Override
-    public FileDownloaderBinder getFileDownloaderBinder() {
-        return mDownloaderBinder;
+    protected ServiceConnection newTransferenceServiceConnection() {
+        return new ListServiceConnection();
     }
 
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public FileUploaderBinder getFileUploaderBinder() {
-        return mUploaderBinder;
-    }
-
-
     /** Defines callbacks for service binding, passed to bindService() */
     private class ListServiceConnection implements ServiceConnection {
 
@@ -1201,8 +1293,12 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
             if (component.equals(new ComponentName(FileDisplayActivity.this, FileDownloader.class))) {
                 Log_OC.d(TAG, "Download service connected");
                 mDownloaderBinder = (FileDownloaderBinder) service;
-                if (mWaitingToPreview != null) {
-                    requestForDownload();
+                if (mWaitingToPreview != null)
+                    if (getStorageManager() != null) {
+                        mWaitingToPreview = getStorageManager().getFileById(mWaitingToPreview.getFileId()); // update the file
+                        if (!mWaitingToPreview.isDown()) {
+                            requestForDownload();
+                        }
                 }
 
             } else if (component.equals(new ComponentName(FileDisplayActivity.this, FileUploader.class))) {
@@ -1255,7 +1351,7 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
 
     @Override
     public void onSavedCertificate() {
-        startSyncFolderOperation(getCurrentDir());                
+        startSyncFolderOperation(getCurrentDir(), false);
     }
 
 
@@ -1264,6 +1360,10 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
         showDialog(DIALOG_CERT_NOT_SAVED);
     }
 
+    @Override
+    public void onCancelCertificate() {
+        // nothing to do
+    }
 
     /**
      * Updates the view associated to the activity after the finish of some operation over files
@@ -1274,6 +1374,8 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
      */
     @Override
     public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationResult result) {
+        super.onRemoteOperationFinish(operation, result);
+        
         if (operation instanceof RemoveFileOperation) {
             onRemoveFileOperationFinish((RemoveFileOperation)operation, result);
 
@@ -1286,10 +1388,55 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
         } else if (operation instanceof CreateFolderOperation) {
             onCreateFolderOperationFinish((CreateFolderOperation)operation, result);
             
-        } 
+        } else if (operation instanceof CreateShareOperation) {
+            onCreateShareOperationFinish((CreateShareOperation) operation, result);
+            
+        } else if (operation instanceof UnshareLinkOperation) {
+            onUnshareLinkOperationFinish((UnshareLinkOperation)operation, result);
+        
+        } else if (operation instanceof MoveFileOperation) {
+            onMoveFileOperationFinish((MoveFileOperation)operation, result);
+        }
+        
     }
 
+    
+    private void onCreateShareOperationFinish(CreateShareOperation operation, RemoteOperationResult result) {
+        if (result.isSuccess()) {
+            refreshShowDetails();
+            refreshListOfFilesFragment();
+        }
+    }
 
+    
+    private void onUnshareLinkOperationFinish(UnshareLinkOperation operation, RemoteOperationResult result) {
+        if (result.isSuccess()) {
+            refreshShowDetails();
+            refreshListOfFilesFragment();
+            
+        } else if (result.getCode() == ResultCode.SHARE_NOT_FOUND) {
+            cleanSecondFragment();
+            refreshListOfFilesFragment();
+        }
+    }
+    
+    private void refreshShowDetails() {
+        FileFragment details = getSecondFragment();
+        if (details != null) {
+            OCFile file = details.getFile();
+            if (file != null) {
+                file = getStorageManager().getFileByPath(file.getRemotePath()); 
+                if (details instanceof PreviewMediaFragment) {
+                    // Refresh  OCFile of the fragment
+                    ((PreviewMediaFragment) details).updateFile(file);
+                } else {
+                    showDetails(file);
+                } 
+            }
+            invalidateOptionsMenu();
+        } 
+    }
+    
     /**
      * Updates the view associated to the activity after the finish of an operation trying to remove a 
      * file. 
@@ -1299,44 +1446,51 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
      */
     private void onRemoveFileOperationFinish(RemoveFileOperation operation, RemoteOperationResult result) {
         dismissLoadingDialog();
+        
+        Toast msg = Toast.makeText(this, ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()), 
+                Toast.LENGTH_LONG); 
+        msg.show();
+        
         if (result.isSuccess()) {
-            Toast msg = Toast.makeText(this, R.string.remove_success_msg, Toast.LENGTH_LONG);
-            msg.show();
             OCFile removedFile = operation.getFile();
-            getSecondFragment();
             FileFragment second = getSecondFragment();
             if (second != null && removedFile.equals(second.getFile())) {
+                if (second instanceof PreviewMediaFragment) {
+                    ((PreviewMediaFragment)second).stopPreview(true);
+                }
+                setFile(getStorageManager().getFileById(removedFile.getParentId()));
                 cleanSecondFragment();
             }
-            if (mStorageManager.getFileById(removedFile.getParentId()).equals(getCurrentDir())) {
-                refeshListOfFilesFragment();
+            if (getStorageManager().getFileById(removedFile.getParentId()).equals(getCurrentDir())) {
+                refreshListOfFilesFragment();
             }
-
+            invalidateOptionsMenu();
         } else {
-            Toast msg = Toast.makeText(this, R.string.remove_fail_msg, Toast.LENGTH_LONG); 
-            msg.show();
             if (result.isSslRecoverableException()) {
                 mLastSslUntrustedServerResult = result;
-                showDialog(DIALOG_SSL_VALIDATOR); 
+                showUntrustedCertDialog(mLastSslUntrustedServerResult);
             }
         }
     }
-
+    
+    
     /**
-     * Updates the view associated to the activity after the finish of an operation trying create a new folder
+     * Updates the view associated to the activity after the finish of an operation trying to move a 
+     * file.
      * 
-     * @param operation     Creation operation performed.
-     * @param result        Result of the creation.
+     * @param operation     Move operation performed.
+     * @param result        Result of the move operation.
      */
-    private void onCreateFolderOperationFinish(CreateFolderOperation operation, RemoteOperationResult result) {
+    private void onMoveFileOperationFinish(MoveFileOperation operation, RemoteOperationResult result) {
         if (result.isSuccess()) {
             dismissLoadingDialog();
-            refeshListOfFilesFragment();
-
+            refreshListOfFilesFragment();
         } else {
             dismissLoadingDialog();
             try {
-                Toast msg = Toast.makeText(FileDisplayActivity.this, R.string.create_dir_fail_msg, Toast.LENGTH_LONG); 
+                Toast msg = Toast.makeText(FileDisplayActivity.this, 
+                        ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()), 
+                        Toast.LENGTH_LONG); 
                 msg.show();
 
             } catch (NotFoundException e) {
@@ -1357,33 +1511,39 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
         dismissLoadingDialog();
         OCFile renamedFile = operation.getFile();
         if (result.isSuccess()) {
-            if (mDualPane) {
-                FileFragment details = getSecondFragment();
-                if (details != null && details instanceof FileDetailFragment && renamedFile.equals(details.getFile()) ) {
+            FileFragment details = getSecondFragment();
+            if (details != null) {
+                if (details instanceof FileDetailFragment && renamedFile.equals(details.getFile()) ) {
                     ((FileDetailFragment) details).updateFileDetails(renamedFile, getAccount());
+                    showDetails(renamedFile);
+
+                } else if (details instanceof PreviewMediaFragment && renamedFile.equals(details.getFile())) {
+                    ((PreviewMediaFragment) details).updateFile(renamedFile);
+                    if (PreviewMediaFragment.canBePreviewed(renamedFile)) {
+                        int position = ((PreviewMediaFragment)details).getPosition();
+                        startMediaPreview(renamedFile, position, true);
+                    } else {
+                        getFileOperationsHelper().openFile(renamedFile);
+                    }
                 }
             }
-            if (mStorageManager.getFileById(renamedFile.getParentId()).equals(getCurrentDir())) {
-                refeshListOfFilesFragment();
+            
+            if (getStorageManager().getFileById(renamedFile.getParentId()).equals(getCurrentDir())) {
+                refreshListOfFilesFragment();
             }
 
         } else {
-            if (result.getCode().equals(ResultCode.INVALID_LOCAL_FILE_NAME)) {
-                Toast msg = Toast.makeText(this, R.string.rename_local_fail_msg, Toast.LENGTH_LONG); 
-                msg.show();
-                // TODO throw again the new rename dialog
-            } else {
-                Toast msg = Toast.makeText(this, R.string.rename_server_fail_msg, Toast.LENGTH_LONG); 
-                msg.show();
-                if (result.isSslRecoverableException()) {
-                    mLastSslUntrustedServerResult = result;
-                    showDialog(DIALOG_SSL_VALIDATOR); 
-                }
+            Toast msg = Toast.makeText(this, ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()), 
+                    Toast.LENGTH_LONG); 
+            msg.show();
+            
+            if (result.isSslRecoverableException()) {
+                mLastSslUntrustedServerResult = result;
+                showUntrustedCertDialog(mLastSslUntrustedServerResult);
             }
         }
     }
 
-
     private void onSynchronizeFileOperationFinish(SynchronizeFileOperation operation, RemoteOperationResult result) {
         dismissLoadingDialog();
         OCFile syncedFile = operation.getLocalFile();
@@ -1395,57 +1555,63 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
                 startActivity(i);
 
             } 
-
+            
         } else {
             if (operation.transferWasRequested()) {
-                refeshListOfFilesFragment();
                 onTransferStateChanged(syncedFile, true, true);
-
+                
             } else {
-                Toast msg = Toast.makeText(this, R.string.sync_file_nothing_to_do_msg, Toast.LENGTH_LONG); 
+                Toast msg = Toast.makeText(this, ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()), 
+                        Toast.LENGTH_LONG); 
                 msg.show();
             }
         }
     }
 
+    /**
+     * Updates the view associated to the activity after the finish of an operation trying create a new folder
+     * 
+     * @param operation     Creation operation performed.
+     * @param result        Result of the creation.
+     */
+    private void onCreateFolderOperationFinish(CreateFolderOperation operation, RemoteOperationResult result) {
+        if (result.isSuccess()) {
+            dismissLoadingDialog();
+            refreshListOfFilesFragment();
+        } else {
+            dismissLoadingDialog();
+            try {
+                Toast msg = Toast.makeText(FileDisplayActivity.this, 
+                        ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()), 
+                        Toast.LENGTH_LONG); 
+                msg.show();
+
+            } catch (NotFoundException e) {
+                Log_OC.e(TAG, "Error while trying to show fail message " , e);
+            }
+        }
+    }
 
+    
     /**
      * {@inheritDoc}
      */
     @Override
     public void onTransferStateChanged(OCFile file, boolean downloading, boolean uploading) {
-        if (mDualPane) {
-            FileFragment details = getSecondFragment();
-            if (details != null && details instanceof FileDetailFragment && file.equals(details.getFile()) ) {
-                if (downloading || uploading) {
-                    ((FileDetailFragment)details).updateFileDetails(file, getAccount());
+        refreshListOfFilesFragment();
+        FileFragment details = getSecondFragment();
+        if (details != null && details instanceof FileDetailFragment && file.equals(details.getFile()) ) {
+            if (downloading || uploading) {
+                ((FileDetailFragment)details).updateFileDetails(file, getAccount());
+            } else {
+                if (!file.fileExists()) {
+                    cleanSecondFragment();
                 } else {
                     ((FileDetailFragment)details).updateFileDetails(false, true);
                 }
             }
         }
-    }
-
-
-    public void onDismiss(EditNameDialog dialog) {
-        if (dialog.getResult()) {
-            String newDirectoryName = dialog.getNewFilename().trim();
-            Log_OC.d(TAG, "'create directory' dialog dismissed with new name " + newDirectoryName);
-            if (newDirectoryName.length() > 0) {
-                String path = getCurrentDir().getRemotePath();
-
-                // Create directory
-                path += newDirectoryName + OCFile.PATH_SEPARATOR;
-                RemoteOperation operation = new CreateFolderOperation(path, false, mStorageManager);
-                operation.execute(  getAccount(), 
-                        FileDisplayActivity.this, 
-                        FileDisplayActivity.this, 
-                        mHandler,
-                        FileDisplayActivity.this);
-
-                showLoadingDialog();
-            }
-        }
+            
     }
 
 
@@ -1465,15 +1631,15 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
         if (file != null) {
             if (file.isFolder()) {
                 return file;
-            } else if (mStorageManager != null) {
+            } else if (getStorageManager() != null) {
                 String parentPath = file.getRemotePath().substring(0, file.getRemotePath().lastIndexOf(file.getFileName()));
-                return mStorageManager.getFileByPath(parentPath);
+                return getStorageManager().getFileByPath(parentPath);
             }
         }
         return null;
     }
     
-    public void startSyncFolderOperation(OCFile folder) {
+    public void startSyncFolderOperation(OCFile folder, boolean ignoreETag) {
         long currentSyncTime = System.currentTimeMillis(); 
         
         mSyncInProgress = true;
@@ -1482,25 +1648,150 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
         RemoteOperation synchFolderOp = new SynchronizeFolderOperation( folder,  
                                                                         currentSyncTime, 
                                                                         false,
+                                                                        getFileOperationsHelper().isSharedSupported(),
+                                                                        ignoreETag,
                                                                         getStorageManager(), 
                                                                         getAccount(), 
                                                                         getApplicationContext()
                                                                       );
-        synchFolderOp.execute(getAccount(), this, null, null, this);
+        synchFolderOp.execute(getAccount(), this, null, null);
         
         setSupportProgressBarIndeterminateVisibility(true);
+
+        setBackgroundText();
+    }
+
+    /**
+     * Show untrusted cert dialog 
+     */
+    public void showUntrustedCertDialog(RemoteOperationResult result) {
+        // Show a dialog with the certificate info
+        SslUntrustedCertDialog dialog = SslUntrustedCertDialog.newInstanceForFullSslError((CertificateCombinedException)result.getException());
+        FragmentManager fm = getSupportFragmentManager();
+        FragmentTransaction ft = fm.beginTransaction();
+        dialog.show(ft, DIALOG_UNTRUSTED_CERT);
+    }
+    
+    private void requestForDownload(OCFile file) {
+        Account account = getAccount();
+        if (!mDownloaderBinder.isDownloading(account, file)) {
+            Intent i = new Intent(this, FileDownloader.class);
+            i.putExtra(FileDownloader.EXTRA_ACCOUNT, account);
+            i.putExtra(FileDownloader.EXTRA_FILE, file);
+            startService(i);
+        }
+    }
+    
+    private void sendDownloadedFile(){
+        getFileOperationsHelper().sendDownloadedFile(mWaitingToSend);
+        mWaitingToSend = null;
     }
 
     
-//    public void enableDisableViewGroup(ViewGroup viewGroup, boolean enabled) {
-//        int childCount = viewGroup.getChildCount();
-//        for (int i = 0; i < childCount; i++) {
-//          View view = viewGroup.getChildAt(i);
-//          view.setEnabled(enabled);
-//          view.setClickable(!enabled);
-//          if (view instanceof ViewGroup) {
-//            enableDisableViewGroup((ViewGroup) view, enabled);
-//          }
-//        }
-//      }
+    /**
+     * Requests the download of the received {@link OCFile} , updates the UI
+     * to monitor the download progress and prepares the activity to send the file
+     * when the download finishes.
+     * 
+     * @param file          {@link OCFile} to download and preview.
+     */
+    public void startDownloadForSending(OCFile file) {
+        mWaitingToSend = file;
+        requestForDownload(mWaitingToSend);
+        boolean hasSecondFragment = (getSecondFragment()!= null);
+        updateFragmentsVisibility(hasSecondFragment);
+    }
+    
+    /**
+     * Opens the image gallery showing the image {@link OCFile} received as parameter.
+     * 
+     * @param file                      Image {@link OCFile} to show.
+     */
+    public void startImagePreview(OCFile file) {
+        Intent showDetailsIntent = new Intent(this, PreviewImageActivity.class);
+        showDetailsIntent.putExtra(EXTRA_FILE, file);
+        showDetailsIntent.putExtra(EXTRA_ACCOUNT, getAccount());
+        startActivity(showDetailsIntent);
+        
+    }
+
+    /**
+     * Stars the preview of an already down media {@link OCFile}.
+     * 
+     * @param file                      Media {@link OCFile} to preview.
+     * @param startPlaybackPosition     Media position where the playback will be started, in milliseconds.
+     * @param autoplay                  When 'true', the playback will start without user interactions.
+     */
+    public void startMediaPreview(OCFile file, int startPlaybackPosition, boolean autoplay) {
+        Fragment mediaFragment = new PreviewMediaFragment(file, getAccount(), startPlaybackPosition, autoplay);
+        setSecondFragment(mediaFragment);
+        updateFragmentsVisibility(true);
+        updateNavigationElementsInActionBar(file);
+        setFile(file);
+    }
+
+    /**
+     * Requests the download of the received {@link OCFile} , updates the UI
+     * to monitor the download progress and prepares the activity to preview
+     * or open the file when the download finishes.
+     * 
+     * @param file          {@link OCFile} to download and preview.
+     */
+    public void startDownloadForPreview(OCFile file) {
+        Fragment detailFragment = new FileDetailFragment(file, getAccount());
+        setSecondFragment(detailFragment);
+        mWaitingToPreview = file;
+        requestForDownload();
+        updateFragmentsVisibility(true);
+        updateNavigationElementsInActionBar(file);
+        setFile(file);
+    }
+
+
+    public void cancelTransference(OCFile file) {
+        getFileOperationsHelper().cancelTransference(file);
+        if (mWaitingToPreview != null && 
+                mWaitingToPreview.getRemotePath().equals(file.getRemotePath())) {
+            mWaitingToPreview = null;
+        }
+        if (mWaitingToSend != null &&
+                mWaitingToSend.getRemotePath().equals(file.getRemotePath())) {
+            mWaitingToSend = null;
+        }
+        onTransferStateChanged(file, false, false);
+    }
+
+    @Override
+    public void onRefresh(boolean ignoreETag) {
+        refreshList(ignoreETag);
+    }
+
+    @Override
+    public void onRefresh() {
+        refreshList(true);
+    }
+
+    private void refreshList(boolean ignoreETag) {
+        OCFileListFragment listOfFiles = getListOfFilesFragment();
+        if (listOfFiles != null) {
+            OCFile folder = listOfFiles.getCurrentFile();
+            if (folder != null) {
+                /*mFile = mContainerActivity.getStorageManager().getFileById(mFile.getFileId());
+                listDirectory(mFile);*/
+                startSyncFolderOperation(folder, ignoreETag);
+            }
+        }
+    }
+
+    private void sortByDate(boolean ascending){
+        getListOfFilesFragment().sortByDate(ascending);
+    }
+
+    private void sortBySize(boolean ascending){
+        getListOfFilesFragment().sortBySize(ascending);
+    }
+
+    private void sortByName(boolean ascending){
+        getListOfFilesFragment().sortByName(ascending);
+    }
 }
index b971c40..901434e 100644 (file)
@@ -30,8 +30,10 @@ import android.widget.ListAdapter;
 import android.widget.ListView;
 import android.widget.TextView;
 
+import com.actionbarsherlock.app.ActionBar;
 import com.actionbarsherlock.app.SherlockFragmentActivity;
 import com.owncloud.android.R;
+import com.owncloud.android.utils.DisplayUtils;
 
 
 /**
@@ -74,6 +76,9 @@ public class GenericExplanationActivity  extends SherlockFragmentActivity {
         } else {
             listView.setVisibility(View.GONE);
         }
+        
+        ActionBar actionBar = getSupportActionBar();
+        actionBar.setIcon(DisplayUtils.getSeasonalIconId());
     }
     
     public class ExplanationListAdapterView extends ArrayAdapter<String> {
diff --git a/src/com/owncloud/android/ui/activity/HookActivity.java b/src/com/owncloud/android/ui/activity/HookActivity.java
new file mode 100644 (file)
index 0000000..54d65b1
--- /dev/null
@@ -0,0 +1,24 @@
+/* ownCloud Android client application
+ *   Copyright (C) 2012-2014 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;
+
+public abstract class HookActivity extends FileActivity {
+
+    private static final String TAG = HookActivity.class.getName();
+    
+}
diff --git a/src/com/owncloud/android/ui/activity/InstantUploadActivity.java b/src/com/owncloud/android/ui/activity/InstantUploadActivity.java
deleted file mode 100644 (file)
index a851dd1..0000000
+++ /dev/null
@@ -1,476 +0,0 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012-2013 ownCloud Inc.
- *
- *   This program is free software: you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License version 2,
- *   as published by the Free Software Foundation.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- */
-package com.owncloud.android.ui.activity;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import com.owncloud.android.Log_OC;
-import com.owncloud.android.R;
-import com.owncloud.android.authentication.AccountUtils;
-import com.owncloud.android.db.DbHandler;
-import com.owncloud.android.files.InstantUploadBroadcastReceiver;
-import com.owncloud.android.files.services.FileUploader;
-import com.owncloud.android.utils.FileStorageUtils;
-
-import android.accounts.Account;
-import android.app.Activity;
-import android.content.Intent;
-import android.database.Cursor;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.os.Bundle;
-import android.util.SparseArray;
-import android.view.Gravity;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.view.View.OnLongClickListener;
-import android.view.ViewGroup;
-import android.widget.Button;
-import android.widget.CheckBox;
-import android.widget.CompoundButton;
-import android.widget.CompoundButton.OnCheckedChangeListener;
-import android.widget.ImageButton;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-import android.widget.Toast;
-
-
-/**
- * This Activity is used to display a list with images they could not be
- * uploaded instantly. The images can be selected for delete or for a try again
- * upload
- * 
- * The entry-point for this activity is the 'Failed upload Notification" and a
- * sub-menu underneath the 'Upload' menu-item
- * 
- * @author andomaex / Matthias Baumann
- */
-public class InstantUploadActivity extends Activity {
-
-    private static final String LOG_TAG = InstantUploadActivity.class.getSimpleName();
-    private LinearLayout listView;
-    private static final String retry_chexbox_tag = "retry_chexbox_tag";
-    public static final boolean IS_ENABLED = false;
-    private static int MAX_LOAD_IMAGES = 5;
-    private int lastLoadImageIdx = 0;
-
-    private SparseArray<String> fileList = null;
-    CheckBox failed_upload_all_cb;
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.failed_upload_files);
-
-        Button deleteAllBtn = (Button) findViewById(R.id.failed_upload_delete_all_btn);
-        deleteAllBtn.setOnClickListener(getDeleteListner());
-        Button retryAllBtn = (Button) findViewById(R.id.failed_upload_retry_all_btn);
-        retryAllBtn.setOnClickListener(getRetryListner());
-        this.failed_upload_all_cb = (CheckBox) findViewById(R.id.failed_upload_headline_cb);
-        failed_upload_all_cb.setOnCheckedChangeListener(getCheckAllListener());
-        listView = (LinearLayout) findViewById(R.id.failed_upload_scrollviewlayout);
-        
-        loadListView(true);
-
-    }
-
-    /**
-     * init the listview with ImageButtons, checkboxes and filename for every
-     * Image that was not successfully uploaded
-     * 
-     * this method is call at Activity creation and on delete one ore more
-     * list-entry an on retry the upload by clicking the ImageButton or by click
-     * to the 'retry all' button
-     * 
-     */
-    private void loadListView(boolean reset) {
-        DbHandler db = new DbHandler(getApplicationContext());
-        Cursor c = db.getFailedFiles();
-
-        if (reset) {
-            fileList = new SparseArray<String>();
-            listView.removeAllViews();
-            lastLoadImageIdx = 0;
-        }
-        if (c != null) {
-            try {
-                c.moveToPosition(lastLoadImageIdx);
-
-                while (c.moveToNext()) {
-
-                    lastLoadImageIdx++;
-                    String imp_path = c.getString(1);
-                    String message = c.getString(4);
-                    fileList.put(lastLoadImageIdx, imp_path);
-                    LinearLayout rowLayout = getHorizontalLinearLayout(lastLoadImageIdx);
-                    rowLayout.addView(getFileCheckbox(lastLoadImageIdx));
-                    rowLayout.addView(getImageButton(imp_path, lastLoadImageIdx));
-                    rowLayout.addView(getFileButton(imp_path, message, lastLoadImageIdx));
-                    listView.addView(rowLayout);
-                    Log_OC.d(LOG_TAG, imp_path + " on idx: " + lastLoadImageIdx);
-                    if (lastLoadImageIdx % MAX_LOAD_IMAGES == 0) {
-                        break;
-                    }
-                }
-                if (lastLoadImageIdx > 0) {
-                    addLoadMoreButton(listView);
-                }
-            } finally {
-                db.close();
-            }
-        }
-    }
-
-    private void addLoadMoreButton(LinearLayout listView) {
-        if (listView != null) {
-            Button loadmoreBtn = null;
-            View oldButton = listView.findViewById(42);
-            if (oldButton != null) {
-                // remove existing button
-                listView.removeView(oldButton);
-                // to add the button at the end
-                loadmoreBtn = (Button) oldButton;
-            } else {
-                // create a new button to add to the scoll view
-                loadmoreBtn = new Button(this);
-                loadmoreBtn.setId(42);
-                loadmoreBtn.setText(getString(R.string.failed_upload_load_more_images));
-                loadmoreBtn.setBackgroundResource(R.color.background_color);
-                loadmoreBtn.setTextSize(12);
-                loadmoreBtn.setOnClickListener(new OnClickListener() {
-                    @Override
-                    public void onClick(View v) {
-                        loadListView(false);
-                    }
-
-                });
-            }
-            listView.addView(loadmoreBtn);
-        }
-    }
-
-    /**
-     * provide a list of CheckBox instances, looked up from parent listview this
-     * list ist used to select/deselect all checkboxes at the list
-     * 
-     * @return List<CheckBox>
-     */
-    private List<CheckBox> getCheckboxList() {
-        List<CheckBox> list = new ArrayList<CheckBox>();
-        for (int i = 0; i < listView.getChildCount(); i++) {
-            Log_OC.d(LOG_TAG, "ListView has Childs: " + listView.getChildCount());
-            View childView = listView.getChildAt(i);
-            if (childView != null && childView instanceof ViewGroup) {
-                View checkboxView = getChildViews((ViewGroup) childView);
-                if (checkboxView != null && checkboxView instanceof CheckBox) {
-                    Log_OC.d(LOG_TAG, "found Child: " + checkboxView.getId() + " " + checkboxView.getClass());
-                    list.add((CheckBox) checkboxView);
-                }
-            }
-        }
-        return list;
-    }
-
-    /**
-     * recursive called method, used from getCheckboxList method
-     * 
-     * @param View
-     * @return View
-     */
-    private View getChildViews(ViewGroup view) {
-        if (view != null) {
-            for (int i = 0; i < view.getChildCount(); i++) {
-                View cb = view.getChildAt(i);
-                if (cb != null && cb instanceof ViewGroup) {
-                    return getChildViews((ViewGroup) cb);
-                } else if (cb instanceof CheckBox) {
-                    return cb;
-                }
-            }
-        }
-        return null;
-    }
-
-    /**
-     * create a new OnCheckedChangeListener for the 'check all' checkbox *
-     * 
-     * @return OnCheckedChangeListener to select all checkboxes at the list
-     */
-    private OnCheckedChangeListener getCheckAllListener() {
-        return new OnCheckedChangeListener() {
-            @Override
-            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
-                List<CheckBox> list = getCheckboxList();
-                for (CheckBox checkbox : list) {
-                    ((CheckBox) checkbox).setChecked(isChecked);
-                }
-            }
-
-        };
-    }
-
-    /**
-     * Button click Listener for the retry button at the headline
-     * 
-     * @return a Listener to perform a retry for all selected images
-     */
-    private OnClickListener getRetryListner() {
-        return new OnClickListener() {
-
-            @Override
-            public void onClick(View v) {
-
-                try {
-
-                    List<CheckBox> list = getCheckboxList();
-                    for (CheckBox checkbox : list) {
-                        boolean to_retry = checkbox.isChecked();
-
-                        Log_OC.d(LOG_TAG, "Checkbox for " + checkbox.getId() + " was checked: " + to_retry);
-                        String img_path = fileList.get(checkbox.getId());
-                        if (to_retry) {
-
-                            final String msg = "Image-Path " + checkbox.getId() + " was checked: " + img_path;
-                            Log_OC.d(LOG_TAG, msg);
-                            startUpload(img_path);
-                        }
-
-                    }
-                } finally {
-                    // refresh the List
-                    listView.removeAllViews();
-                    loadListView(true);
-                    if (failed_upload_all_cb != null) {
-                        failed_upload_all_cb.setChecked(false);
-                    }
-                }
-
-            }
-        };
-    }
-
-    /**
-     * Button click Listener for the delete button at the headline
-     * 
-     * @return a Listener to perform a delete for all selected images
-     */
-    private OnClickListener getDeleteListner() {
-
-        return new OnClickListener() {
-
-            @Override
-            public void onClick(View v) {
-
-                final DbHandler dbh = new DbHandler(getApplicationContext());
-                try {
-                    List<CheckBox> list = getCheckboxList();
-                    for (CheckBox checkbox : list) {
-                        boolean to_be_delete = checkbox.isChecked();
-
-                        Log_OC.d(LOG_TAG, "Checkbox for " + checkbox.getId() + " was checked: " + to_be_delete);
-                        String img_path = fileList.get(checkbox.getId());
-                        Log_OC.d(LOG_TAG, "Image-Path " + checkbox.getId() + " was checked: " + img_path);
-                        if (to_be_delete) {
-                            boolean deleted = dbh.removeIUPendingFile(img_path);
-                            Log_OC.d(LOG_TAG, "removing " + checkbox.getId() + " was : " + deleted);
-
-                        }
-
-                    }
-                } finally {
-                    dbh.close();
-                    // refresh the List
-                    listView.removeAllViews();
-                    loadListView(true);
-                    if (failed_upload_all_cb != null) {
-                        failed_upload_all_cb.setChecked(false);
-                    }
-                }
-
-            }
-        };
-    }
-
-    private LinearLayout getHorizontalLinearLayout(int id) {
-        LinearLayout linearLayout = new LinearLayout(getApplicationContext());
-        linearLayout.setId(id);
-        linearLayout.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
-                LinearLayout.LayoutParams.MATCH_PARENT));
-        linearLayout.setGravity(Gravity.RIGHT);
-        linearLayout.setOrientation(LinearLayout.HORIZONTAL);
-        return linearLayout;
-    }
-
-    private LinearLayout getVerticalLinearLayout() {
-        LinearLayout linearLayout = new LinearLayout(getApplicationContext());
-        linearLayout.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
-                LinearLayout.LayoutParams.MATCH_PARENT));
-        linearLayout.setGravity(Gravity.TOP);
-        linearLayout.setOrientation(LinearLayout.VERTICAL);
-        return linearLayout;
-    }
-
-    private View getFileButton(final String img_path, String message, int id) {
-
-        TextView failureTextView = new TextView(this);
-        failureTextView.setText(getString(R.string.failed_upload_failure_text) + message);
-        failureTextView.setBackgroundResource(R.color.background_color);
-        failureTextView.setTextSize(8);
-        failureTextView.setOnLongClickListener(getOnLongClickListener(message));
-        failureTextView.setPadding(5, 5, 5, 10);
-        TextView retryButton = new TextView(this);
-        retryButton.setId(id);
-        retryButton.setText(img_path);
-        retryButton.setBackgroundResource(R.color.background_color);
-        retryButton.setTextSize(8);
-        retryButton.setOnClickListener(getImageButtonOnClickListener(img_path));
-        retryButton.setOnLongClickListener(getOnLongClickListener(message));
-        retryButton.setPadding(5, 5, 5, 10);
-        LinearLayout verticalLayout = getVerticalLinearLayout();
-        verticalLayout.addView(retryButton);
-        verticalLayout.addView(failureTextView);
-
-        return verticalLayout;
-    }
-
-    private OnLongClickListener getOnLongClickListener(final String message) {
-        return new OnLongClickListener() {
-
-            @Override
-            public boolean onLongClick(View v) {
-                Log_OC.d(LOG_TAG, message);
-                Toast toast = Toast.makeText(InstantUploadActivity.this, getString(R.string.failed_upload_retry_text)
-                        + message, Toast.LENGTH_LONG);
-                toast.show();
-                return true;
-            }
-
-        };
-    }
-
-    private CheckBox getFileCheckbox(int id) {
-        CheckBox retryCB = new CheckBox(this);
-        retryCB.setId(id);
-        retryCB.setBackgroundResource(R.color.background_color);
-        retryCB.setTextSize(8);
-        retryCB.setTag(retry_chexbox_tag);
-        return retryCB;
-    }
-
-    private ImageButton getImageButton(String img_path, int id) {
-        ImageButton imageButton = new ImageButton(this);
-        imageButton.setId(id);
-        imageButton.setClickable(true);
-        imageButton.setOnClickListener(getImageButtonOnClickListener(img_path));
-
-        // scale and add a thumbnail to the imagebutton
-        int base_scale_size = 32;
-        if (img_path != null) {
-            Log_OC.d(LOG_TAG, "add " + img_path + " to Image Button");
-            BitmapFactory.Options options = new BitmapFactory.Options();
-            options.inJustDecodeBounds = true;
-            Bitmap bitmap = BitmapFactory.decodeFile(img_path, options);
-            int width_tpm = options.outWidth, height_tmp = options.outHeight;
-            int scale = 3;
-            while (true) {
-                if (width_tpm / 2 < base_scale_size || height_tmp / 2 < base_scale_size) {
-                    break;
-                }
-                width_tpm /= 2;
-                height_tmp /= 2;
-                scale++;
-            }
-
-            Log_OC.d(LOG_TAG, "scale Imgae with: " + scale);
-            BitmapFactory.Options options2 = new BitmapFactory.Options();
-            options2.inSampleSize = scale;
-            bitmap = BitmapFactory.decodeFile(img_path, options2);
-
-            if (bitmap != null) {
-                Log_OC.d(LOG_TAG, "loaded Bitmap Bytes: " + bitmap.getRowBytes());
-                imageButton.setImageBitmap(bitmap);
-            } else {
-                Log_OC.d(LOG_TAG, "could not load imgage: " + img_path);
-            }
-        }
-        return imageButton;
-    }
-
-    private OnClickListener getImageButtonOnClickListener(final String img_path) {
-        return new OnClickListener() {
-
-            @Override
-            public void onClick(View v) {
-                startUpload(img_path);
-                loadListView(true);
-            }
-
-        };
-    }
-
-    /**
-     * start uploading a file to the INSTANT_UPLOD_DIR
-     * 
-     * @param img_path
-     */
-    private void startUpload(String img_path) {
-        // extract filename
-        String filename = FileStorageUtils.getInstantUploadFilePath(this, img_path);
-        if (canInstantUpload()) {
-            Account account = AccountUtils.getCurrentOwnCloudAccount(InstantUploadActivity.this);
-            // add file again to upload queue
-            DbHandler db = new DbHandler(InstantUploadActivity.this);
-            try {
-                db.updateFileState(img_path, DbHandler.UPLOAD_STATUS_UPLOAD_LATER, null);
-            } finally {
-                db.close();
-            }
-
-            Intent i = new Intent(InstantUploadActivity.this, FileUploader.class);
-            i.putExtra(FileUploader.KEY_ACCOUNT, account);
-            i.putExtra(FileUploader.KEY_LOCAL_FILE, img_path);
-            i.putExtra(FileUploader.KEY_REMOTE_FILE, filename);
-            i.putExtra(FileUploader.KEY_UPLOAD_TYPE, FileUploader.UPLOAD_SINGLE_FILE);
-            i.putExtra(com.owncloud.android.files.services.FileUploader.KEY_INSTANT_UPLOAD, true);
-
-            final String msg = "try to upload file with name :" + filename;
-            Log_OC.d(LOG_TAG, msg);
-            Toast toast = Toast.makeText(InstantUploadActivity.this, getString(R.string.failed_upload_retry_text)
-                    + filename, Toast.LENGTH_LONG);
-            toast.show();
-
-            startService(i);
-        } else {
-            Toast toast = Toast.makeText(InstantUploadActivity.this,
-                    getString(R.string.failed_upload_retry_do_nothing_text) + filename, Toast.LENGTH_LONG);
-            toast.show();
-        }
-    }
-
-    private boolean canInstantUpload() {
-
-        if (!InstantUploadBroadcastReceiver.isOnline(this)
-                || (InstantUploadBroadcastReceiver.instantUploadViaWiFiOnly(this) && !InstantUploadBroadcastReceiver
-                        .isConnectedViaWiFi(this))) {
-            return false;
-        } else {
-            return true;
-        }
-    }
-
-}
\ No newline at end of file
index e879cc7..676388d 100644 (file)
 
 package com.owncloud.android.ui.activity;
 
+import java.io.BufferedReader;
 import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.lang.ref.WeakReference;
+import java.lang.reflect.Field;
 import java.util.ArrayList;
 
 import android.content.Intent;
+import android.net.Uri;
+import android.os.AsyncTask;
 import android.os.Bundle;
-import android.preference.Preference;
-import android.preference.Preference.OnPreferenceChangeListener;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentManager;
+import android.support.v4.app.FragmentTransaction;
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.widget.Button;
-import android.widget.ListView;
+import android.widget.TextView;
 
 import com.actionbarsherlock.app.ActionBar;
-import com.actionbarsherlock.app.SherlockPreferenceActivity;
+import com.actionbarsherlock.app.SherlockFragmentActivity;
 import com.actionbarsherlock.view.MenuItem;
 import com.owncloud.android.R;
-import com.owncloud.android.ui.adapter.LogListAdapter;
+import com.owncloud.android.lib.common.utils.Log_OC;
+import com.owncloud.android.ui.dialog.LoadingDialog;
+import com.owncloud.android.utils.DisplayUtils;
 import com.owncloud.android.utils.FileStorageUtils;
 
 
+public class LogHistoryActivity extends SherlockFragmentActivity  {
+
+    private static final String MAIL_ATTACHMENT_TYPE = "text/plain";
+
+    private static final String TAG = LogHistoryActivity.class.getSimpleName();
+
+    private static final String DIALOG_WAIT_TAG = "DIALOG_WAIT";
+
+    private String mLogPath = FileStorageUtils.getLogPath();
+    private File logDIR = null;
 
 
-public class LogHistoryActivity extends SherlockPreferenceActivity implements OnPreferenceChangeListener {
-    String logpath = FileStorageUtils.getLogPath();
-    File logDIR = null;
-    
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        
+
         setContentView(R.layout.log_send_file);
-        setTitle("Log History");
+        setTitle(getText(R.string.actionbar_logger));
         ActionBar actionBar = getSherlock().getActionBar();
+        actionBar.setIcon(DisplayUtils.getSeasonalIconId());
         actionBar.setDisplayHomeAsUpEnabled(true);
-        ListView listView = (ListView) findViewById(android.R.id.list);
         Button deleteHistoryButton = (Button) findViewById(R.id.deleteLogHistoryButton);
-        
+        Button sendHistoryButton = (Button) findViewById(R.id.sendLogHistoryButton);
+
         deleteHistoryButton.setOnClickListener(new OnClickListener() {
             
             @Override
             public void onClick(View v) {
-                File dir = new File(logpath);
-                if (dir != null) {
-                    File[] files = dir.listFiles();
-                    if(files!=null) { 
-                        for(File f: files) {
-                                f.delete();
-                        }
-                    }
-                    dir.delete();
-                }
-                Intent intent = new Intent(getBaseContext(), Preferences.class);
-                intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
-                startActivity(intent);
+
+                Log_OC.deleteHistoryLogging();
+                finish();
             }
-            
         });
-        
-       
-        if(logpath != null){
-        logDIR = new File(logpath);
-        }
-        
-        if(logDIR != null && logDIR.isDirectory()) {
-            File[] files = logDIR.listFiles();
-          
-            if (files != null && files.length != 0) {
-                ArrayList<String> logfiles_name = new ArrayList<String>();
-                for (File file : files) {
-                    logfiles_name.add(file.getName());
-                }
-                    String[] logFiles2Array = logfiles_name.toArray(new String[logfiles_name.size()]);
-                    LogListAdapter listadapter = new LogListAdapter(this,logFiles2Array);
-                    listView.setAdapter(listadapter);
+
+        sendHistoryButton.setOnClickListener(new OnClickListener() {
+
+            @Override
+            public void onClick(View v) {
+                sendMail();
             }
+        });
+
+        if (mLogPath != null) {
+            logDIR = new File(mLogPath);
+        }
+
+        if (logDIR != null && logDIR.isDirectory()) {
+            // Show a dialog while log data is being loaded
+            showLoadingDialog();
+
+            TextView logTV = (TextView) findViewById(R.id.logTV);
+
+            // Start a new thread that will load all the log data
+            LoadingLogTask task = new LoadingLogTask(logTV);
+            task.execute();
+
         }
     }
 
-    
     @Override
     public boolean onMenuItemSelected(int featureId, MenuItem item) {
         super.onMenuItemSelected(featureId, item);
-        Intent intent;
-
         switch (item.getItemId()) {
-       
         case android.R.id.home:
-            intent = new Intent(getBaseContext(), Preferences.class);
-            intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
-            startActivity(intent);
+            finish();
             break;
         default:
             return false;
         }
         return true;
     }
-    @Override
-    public boolean onPreferenceChange(Preference arg0, Object arg1) {
-        return false;
+
+
+    /**
+     * Start activity for sending email with logs attached
+     */
+    private void sendMail() {
+
+        String emailAddress;
+        try {
+            Class<?> stringClass = R.string.class;
+            Field mailLoggerField = stringClass.getField("mail_logger");
+            int emailAddressId = (Integer)mailLoggerField.get(null);
+            emailAddress = getString(emailAddressId);
+            
+        } catch (Exception e) {
+            emailAddress = "";
+        }
+
+        ArrayList<Uri> uris = new ArrayList<Uri>();
+
+        // Convert from paths to Android friendly Parcelable Uri's
+        for (String file : Log_OC.getLogFileNames())
+        {
+            if (new File(mLogPath + File.separator, file).exists()) {
+                Uri u = Uri.parse("file://" + mLogPath + File.separator + file);
+                uris.add(u);
+            }
+        }
+
+        Intent intent = new Intent(Intent.ACTION_SEND_MULTIPLE);
+
+        // Explicitly only use Gmail to send
+        intent.setClassName("com.google.android.gm","com.google.android.gm.ComposeActivityGmail");
+        intent.putExtra(Intent.EXTRA_EMAIL, new String[]{ emailAddress });
+        intent.putExtra(Intent.EXTRA_SUBJECT, getText(R.string.log_mail_subject));
+        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        intent.setType(MAIL_ATTACHMENT_TYPE);
+        intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris);
+
+        if (intent.resolveActivity(getPackageManager()) != null) {
+            startActivity(intent);
+        }
+    }
+
+    /**
+     *
+     * Class for loading the log data async
+     *
+     */
+    private class LoadingLogTask extends AsyncTask<String, Void, String> {
+        private final WeakReference<TextView> textViewReference;
+
+        public LoadingLogTask(TextView logTV){
+            // Use of a WeakReference to ensure the TextView can be garbage collected
+            textViewReference  = new WeakReference<TextView>(logTV);
+        }
+
+        protected String doInBackground(String... args) {
+            return readLogFile();
+        }
+
+        protected void onPostExecute(String result) {
+            if (textViewReference != null && result != null) {
+                final TextView logTV = textViewReference.get();
+                if (logTV != null) {
+                    logTV.setText(result);
+                    dismissLoadingDialog();
+                }
+            }
+        }
+
+        /**
+         * Read and show log file info
+         */
+        private String readLogFile() {
+
+            String[] logFileName = Log_OC.getLogFileNames();
+
+            //Read text from files
+            StringBuilder text = new StringBuilder();
+
+            BufferedReader br = null;
+            try {
+                String line;
+
+                for (int i = logFileName.length-1; i >= 0; i--) {
+                    File file = new File(mLogPath,logFileName[i]);
+                    if (file.exists()) {
+                        // Check if FileReader is ready
+                        if (new FileReader(file).ready()) {
+                            br = new BufferedReader(new FileReader(file));
+                            while ((line = br.readLine()) != null) {
+                                // Append the log info
+                                text.append(line);
+                                text.append('\n');
+                            }
+                        }
+                    }
+                }
+            }
+            catch (IOException e) {
+                Log_OC.d(TAG, e.getMessage().toString());
+                
+            } finally {
+                if (br != null) {
+                    try {
+                        br.close();
+                    } catch (IOException e) {
+                        // ignore
+                    }
+                }
+            }
+
+            return text.toString();
+        }
+   }
+
+    /**
+     * Show loading dialog
+     */
+    public void showLoadingDialog() {
+        // Construct dialog
+        LoadingDialog loading = new LoadingDialog(
+                getResources().getString(R.string.log_progress_dialog_text)
+        );
+        FragmentManager fm = getSupportFragmentManager();
+        FragmentTransaction ft = fm.beginTransaction();
+        loading.show(ft, DIALOG_WAIT_TAG);
+    }
+
+    /**
+     * Dismiss loading dialog
+     */
+    public void dismissLoadingDialog(){
+        Fragment frag = getSupportFragmentManager().findFragmentByTag(DIALOG_WAIT_TAG);
+        if (frag != null) {
+            LoadingDialog loading = (LoadingDialog) frag;
+            loading.dismiss();
+        }
     }
 }
\ No newline at end of file
diff --git a/src/com/owncloud/android/ui/activity/MoveActivity.java b/src/com/owncloud/android/ui/activity/MoveActivity.java
new file mode 100644 (file)
index 0000000..8a25470
--- /dev/null
@@ -0,0 +1,575 @@
+/* ownCloud Android client application
+ *   Copyright (C) 2012-2014 ownCloud Inc.
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License version 2,
+ *   as published by the Free Software Foundation.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.ui.activity;
+
+import java.io.IOException;
+
+import android.accounts.Account;
+import android.accounts.AccountManager;
+import android.accounts.AuthenticatorException;
+import android.accounts.OperationCanceledException;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.res.Resources.NotFoundException;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentTransaction;
+import android.util.Log;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Button;
+import android.widget.Toast;
+
+import com.actionbarsherlock.app.ActionBar;
+import com.actionbarsherlock.view.Menu;
+import com.actionbarsherlock.view.MenuInflater;
+import com.actionbarsherlock.view.MenuItem;
+import com.actionbarsherlock.view.Window;
+import com.owncloud.android.R;
+import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.lib.common.OwnCloudAccount;
+import com.owncloud.android.lib.common.OwnCloudClient;
+import com.owncloud.android.lib.common.OwnCloudClientManagerFactory;
+import com.owncloud.android.lib.common.OwnCloudCredentials;
+import com.owncloud.android.lib.common.accounts.AccountUtils.AccountNotFoundException;
+import com.owncloud.android.lib.common.operations.RemoteOperation;
+import com.owncloud.android.lib.common.operations.RemoteOperationResult;
+import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;
+import com.owncloud.android.operations.CreateFolderOperation;
+import com.owncloud.android.operations.SynchronizeFolderOperation;
+import com.owncloud.android.syncadapter.FileSyncAdapter;
+import com.owncloud.android.ui.dialog.CreateFolderDialogFragment;
+import com.owncloud.android.ui.fragment.FileFragment;
+import com.owncloud.android.ui.fragment.OCFileListFragment;
+import com.owncloud.android.utils.DisplayUtils;
+import com.owncloud.android.utils.ErrorMessageAdapter;
+import com.owncloud.android.lib.common.utils.Log_OC;
+
+public class MoveActivity extends HookActivity implements FileFragment.ContainerActivity, 
+    OnClickListener, OnEnforceableRefreshListener {
+
+    public static final String EXTRA_CURRENT_FOLDER = UploadFilesActivity.class.getCanonicalName() + ".EXTRA_CURRENT_FOLDER";
+    public static final String EXTRA_TARGET_FILE = UploadFilesActivity.class.getCanonicalName() + "EXTRA_TARGET_FILE";
+
+    public static final int RESULT_OK_AND_MOVE = 1;
+    
+    private SyncBroadcastReceiver mSyncBroadcastReceiver;
+
+    private static final String TAG = MoveActivity.class.getSimpleName();
+    
+    private static final String TAG_LIST_OF_FOLDERS = "LIST_OF_FOLDERS";
+       
+    private boolean mSyncInProgress = false;
+
+    private Button mCancelBtn;
+    private Button mChooseBtn;
+
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        Log_OC.d(TAG, "onCreate() start");
+        requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
+
+        super.onCreate(savedInstanceState); 
+
+        setContentView(R.layout.files_move);
+        
+        if (savedInstanceState == null) {
+            createFragments();
+        }
+
+        // sets callback listeners for UI elements
+        initControls();
+
+        // Action bar setup
+        ActionBar actionBar = getSupportActionBar();
+        actionBar.setDisplayShowTitleEnabled(true);
+        actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
+        setSupportProgressBarIndeterminateVisibility(mSyncInProgress);
+            // always AFTER setContentView(...) ; to work around bug in its implementation
+        
+        // sets message for empty list of folders
+        setBackgroundText();
+
+        Log_OC.d(TAG, "onCreate() end");
+        
+    }
+
+    @Override
+    protected void onStart() {
+        super.onStart();
+        getSupportActionBar().setIcon(DisplayUtils.getSeasonalIconId());
+    }
+
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+    }
+
+    /**
+     *  Called when the ownCloud {@link Account} associated to the Activity was just updated.
+     */
+    @Override
+    protected void onAccountSet(boolean stateWasRecovered) {
+        super.onAccountSet(stateWasRecovered);
+        if (getAccount() != null) {
+            
+            updateFileFromDB();
+            
+            OCFile folder = getFile();
+            if (folder == null || !folder.isFolder()) {
+                // fall back to root folder
+                setFile(getStorageManager().getFileByPath(OCFile.ROOT_PATH));
+                folder = getFile();
+            }
+            
+            if (!stateWasRecovered) {
+                OCFileListFragment listOfFolders = getListOfFilesFragment(); 
+                listOfFolders.listDirectory(folder);   
+                
+                startSyncFolderOperation(folder, false);
+            }
+            
+            updateNavigationElementsInActionBar();
+        }
+    }
+
+    private void createFragments() {
+        OCFileListFragment listOfFiles = new OCFileListFragment();
+        Bundle args = new Bundle();
+        args.putBoolean(OCFileListFragment.ARG_JUST_FOLDERS, true);
+        args.putBoolean(OCFileListFragment.ARG_ALLOW_CONTEXTUAL_ACTIONS, false);
+        listOfFiles.setArguments(args);
+        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
+        transaction.add(R.id.fragment_container, listOfFiles, TAG_LIST_OF_FOLDERS);
+        transaction.commit();
+    }
+
+    /**
+     * Show a text message on screen view for notifying user if content is
+     * loading or folder is empty
+     */
+    private void setBackgroundText() {
+        OCFileListFragment listFragment = getListOfFilesFragment();
+        if (listFragment != null) {
+            int message = R.string.file_list_loading;
+            if (!mSyncInProgress) {
+                // In case folder list is empty
+                message = R.string.file_list_empty_moving;
+            }
+            listFragment.setMessageForEmptyList(getString(message));
+        } else {
+            Log.e(TAG, "OCFileListFragment is null");
+        }
+    }
+
+    private OCFileListFragment getListOfFilesFragment() {
+        Fragment listOfFiles = getSupportFragmentManager().findFragmentByTag(MoveActivity.TAG_LIST_OF_FOLDERS);
+        if (listOfFiles != null) {
+            return (OCFileListFragment)listOfFiles;
+        }
+        Log_OC.wtf(TAG, "Access to unexisting list of files fragment!!");
+        return null;
+    }
+
+    
+    /**
+     * {@inheritDoc}
+     * 
+     * Updates action bar and second fragment, if in dual pane mode.
+     */
+    @Override
+    public void onBrowsedDownTo(OCFile directory) {
+        setFile(directory);
+        updateNavigationElementsInActionBar();
+        // Sync Folder
+        startSyncFolderOperation(directory, false);
+        
+    }
+
+    
+    public void startSyncFolderOperation(OCFile folder, boolean ignoreETag) {
+        long currentSyncTime = System.currentTimeMillis(); 
+        
+        mSyncInProgress = true;
+                
+        // perform folder synchronization
+        RemoteOperation synchFolderOp = new SynchronizeFolderOperation( folder,  
+                                                                        currentSyncTime, 
+                                                                        false,
+                                                                        getFileOperationsHelper().isSharedSupported(),
+                                                                        ignoreETag,
+                                                                        getStorageManager(), 
+                                                                        getAccount(), 
+                                                                        getApplicationContext()
+                                                                      );
+        synchFolderOp.execute(getAccount(), this, null, null);
+        
+        setSupportProgressBarIndeterminateVisibility(true);
+
+        setBackgroundText();
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+        Log_OC.e(TAG, "onResume() start");
+        
+        // refresh list of files
+        refreshListOfFilesFragment();
+
+        // Listen for sync messages
+        IntentFilter syncIntentFilter = new IntentFilter(FileSyncAdapter.EVENT_FULL_SYNC_START);
+        syncIntentFilter.addAction(FileSyncAdapter.EVENT_FULL_SYNC_END);
+        syncIntentFilter.addAction(FileSyncAdapter.EVENT_FULL_SYNC_FOLDER_CONTENTS_SYNCED);
+        syncIntentFilter.addAction(SynchronizeFolderOperation.EVENT_SINGLE_FOLDER_CONTENTS_SYNCED);
+        syncIntentFilter.addAction(SynchronizeFolderOperation.EVENT_SINGLE_FOLDER_SHARES_SYNCED);
+        mSyncBroadcastReceiver = new SyncBroadcastReceiver();
+        registerReceiver(mSyncBroadcastReceiver, syncIntentFilter);
+        
+        Log_OC.d(TAG, "onResume() end");
+    }
+    
+    @Override
+    protected void onPause() {
+        Log_OC.e(TAG, "onPause() start");
+        if (mSyncBroadcastReceiver != null) {
+            unregisterReceiver(mSyncBroadcastReceiver);
+            //LocalBroadcastManager.getInstance(this).unregisterReceiver(mSyncBroadcastReceiver);
+            mSyncBroadcastReceiver = null;
+        }
+        
+        Log_OC.d(TAG, "onPause() end");
+        super.onPause();
+    }
+    
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        MenuInflater inflater = getSherlock().getMenuInflater();
+        inflater.inflate(R.menu.main_menu, menu);
+        menu.findItem(R.id.action_upload).setVisible(false);
+        menu.findItem(R.id.action_settings).setVisible(false);
+        menu.findItem(R.id.action_sync_account).setVisible(false);
+        return true;
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        boolean retval = true;
+        switch (item.getItemId()) {
+        case R.id.action_create_dir: {
+            CreateFolderDialogFragment dialog = 
+                    CreateFolderDialogFragment.newInstance(getCurrentFolder());
+            dialog.show(
+                    getSupportFragmentManager(), 
+                    CreateFolderDialogFragment.CREATE_FOLDER_FRAGMENT
+            );
+            break;
+        }
+        case android.R.id.home: {
+            OCFile currentDir = getCurrentFolder();
+            if(currentDir != null && currentDir.getParentId() != 0) {
+                onBackPressed();
+            }
+            break;
+        }
+        default:
+            retval = super.onOptionsItemSelected(item);
+        }
+        return retval;
+    }
+
+    private OCFile getCurrentFolder() {
+        OCFile file = getFile();
+        if (file != null) {
+            if (file.isFolder()) {
+                return file;
+            } else if (getStorageManager() != null) {
+                String parentPath = file.getRemotePath().substring(0, file.getRemotePath().lastIndexOf(file.getFileName()));
+                return getStorageManager().getFileByPath(parentPath);
+            }
+        }
+        return null;
+    }
+    
+    protected void refreshListOfFilesFragment() {
+        OCFileListFragment fileListFragment = getListOfFilesFragment();
+        if (fileListFragment != null) { 
+            fileListFragment.listDirectory();
+        }
+    }
+
+    public void browseToRoot() {
+        OCFileListFragment listOfFiles = getListOfFilesFragment(); 
+        if (listOfFiles != null) {  // should never be null, indeed
+            OCFile root = getStorageManager().getFileByPath(OCFile.ROOT_PATH);
+            listOfFiles.listDirectory(root);
+            setFile(listOfFiles.getCurrentFile());
+            updateNavigationElementsInActionBar();
+            startSyncFolderOperation(root, false);
+        }
+    }
+
+    @Override
+    public void onBackPressed() {
+        OCFileListFragment listOfFiles = getListOfFilesFragment();
+        if (listOfFiles != null) {  // should never be null, indeed
+            int levelsUp = listOfFiles.onBrowseUp();
+            if (levelsUp == 0) {
+                finish();
+                return;
+            }
+            setFile(listOfFiles.getCurrentFile());
+            updateNavigationElementsInActionBar();
+        }
+    }
+
+    private void updateNavigationElementsInActionBar() {
+        ActionBar actionBar = getSupportActionBar();
+        OCFile currentDir = getCurrentFolder();
+        boolean atRoot = (currentDir == null || currentDir.getParentId() == 0);
+        actionBar.setDisplayHomeAsUpEnabled(!atRoot);
+        actionBar.setHomeButtonEnabled(!atRoot);
+        actionBar.setTitle(
+            atRoot 
+                ? getString(R.string.default_display_name_for_root_folder) 
+                : currentDir.getFileName()
+        );
+    }
+
+    /**
+     * Set per-view controllers
+     */
+    private void initControls(){
+        mCancelBtn = (Button) findViewById(R.id.move_files_btn_cancel);
+        mCancelBtn.setOnClickListener(this);
+        mChooseBtn = (Button) findViewById(R.id.move_files_btn_choose);
+        mChooseBtn.setOnClickListener(this);
+    }
+    
+    @Override
+    public void onClick(View v) {
+        if (v == mCancelBtn) {
+            finish();
+        } else if (v == mChooseBtn) {
+            Intent i = getIntent();
+            OCFile targetFile = (OCFile) i.getParcelableExtra(MoveActivity.EXTRA_TARGET_FILE);
+
+            Intent data = new Intent();
+            data.putExtra(EXTRA_CURRENT_FOLDER, getCurrentFolder());
+            data.putExtra(EXTRA_TARGET_FILE, targetFile);
+            setResult(RESULT_OK_AND_MOVE, data);
+            finish();
+        }
+    }
+    
+    
+    @Override
+    public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationResult result) {
+        super.onRemoteOperationFinish(operation, result);
+        
+        if (operation instanceof CreateFolderOperation) {
+            onCreateFolderOperationFinish((CreateFolderOperation)operation, result);
+            
+        }
+    }
+    
+    
+    /**
+     * Updates the view associated to the activity after the finish of an operation trying 
+     * to create a new folder.
+     * 
+     * @param operation     Creation operation performed.
+     * @param result        Result of the creation.
+     */
+    private void onCreateFolderOperationFinish(
+            CreateFolderOperation operation, RemoteOperationResult result
+            ) {
+        
+        if (result.isSuccess()) {
+            dismissLoadingDialog();
+            refreshListOfFilesFragment();
+        } else {
+            dismissLoadingDialog();
+            try {
+                Toast msg = Toast.makeText(MoveActivity.this, 
+                        ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()), 
+                        Toast.LENGTH_LONG); 
+                msg.show();
+
+            } catch (NotFoundException e) {
+                Log_OC.e(TAG, "Error while trying to show fail message " , e);
+            }
+        }
+    }
+    
+    
+    
+    private class SyncBroadcastReceiver extends BroadcastReceiver {
+
+        /**
+         * {@link BroadcastReceiver} to enable syncing feedback in UI
+         */
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            try {
+                String event = intent.getAction();
+                Log_OC.d(TAG, "Received broadcast " + event);
+                String accountName = intent.getStringExtra(FileSyncAdapter.EXTRA_ACCOUNT_NAME);
+                String synchFolderRemotePath = intent.getStringExtra(FileSyncAdapter.EXTRA_FOLDER_PATH); 
+                RemoteOperationResult synchResult = (RemoteOperationResult)intent.getSerializableExtra(FileSyncAdapter.EXTRA_RESULT);
+                boolean sameAccount = (getAccount() != null && accountName.equals(getAccount().name) && getStorageManager() != null); 
+    
+                if (sameAccount) {
+                    
+                    if (FileSyncAdapter.EVENT_FULL_SYNC_START.equals(event)) {
+                        mSyncInProgress = true;
+                        
+                    } else {
+                        OCFile currentFile = (getFile() == null) ? null : getStorageManager().getFileByPath(getFile().getRemotePath());
+                        OCFile currentDir = (getCurrentFolder() == null) ? null : getStorageManager().getFileByPath(getCurrentFolder().getRemotePath());
+    
+                        if (currentDir == null) {
+                            // current folder was removed from the server 
+                            Toast.makeText( MoveActivity.this, 
+                                            String.format(getString(R.string.sync_current_folder_was_removed), getCurrentFolder().getFileName()), 
+                                            Toast.LENGTH_LONG)
+                                .show();
+                            browseToRoot();
+                            
+                        } else {
+                            if (currentFile == null && !getFile().isFolder()) {
+                                // currently selected file was removed in the server, and now we know it
+                                currentFile = currentDir;
+                            }
+
+                            if (synchFolderRemotePath != null && currentDir.getRemotePath().equals(synchFolderRemotePath)) {
+                                OCFileListFragment fileListFragment = getListOfFilesFragment();
+                                if (fileListFragment != null) {
+                                    fileListFragment.listDirectory(currentDir);
+                                }
+                            }
+                            setFile(currentFile);
+                        }
+                        
+                        mSyncInProgress = (!FileSyncAdapter.EVENT_FULL_SYNC_END.equals(event) && !SynchronizeFolderOperation.EVENT_SINGLE_FOLDER_SHARES_SYNCED.equals(event));
+                                
+                        if (SynchronizeFolderOperation.EVENT_SINGLE_FOLDER_CONTENTS_SYNCED.
+                                    equals(event) &&
+                                /// TODO refactor and make common
+                                synchResult != null && !synchResult.isSuccess() &&  
+                                (synchResult.getCode() == ResultCode.UNAUTHORIZED   || 
+                                    synchResult.isIdPRedirection()                  ||
+                                    (synchResult.isException() && synchResult.getException() 
+                                            instanceof AuthenticatorException))) {
+
+                            OwnCloudClient client = null;
+                            try {
+                                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());
+                                    }
+                                }
+                            }
+                            
+                            requestCredentialsUpdate();
+                            
+                        }
+                    }
+                    removeStickyBroadcast(intent);
+                    Log_OC.d(TAG, "Setting progress visibility to " + mSyncInProgress);
+                    setSupportProgressBarIndeterminateVisibility(mSyncInProgress /*|| mRefreshSharesInProgress*/);
+
+                    setBackgroundText();
+                        
+                }
+                
+            } catch (RuntimeException e) {
+                // avoid app crashes after changing the serial id of RemoteOperationResult 
+                // in owncloud library with broadcast notifications pending to process
+                removeStickyBroadcast(intent);
+            }
+        }
+    }
+
+    
+
+    /**
+     * Shows the information of the {@link OCFile} received as a 
+     * parameter in the second fragment.
+     * 
+     * @param file          {@link OCFile} whose details will be shown
+     */
+    @Override
+    public void showDetails(OCFile file) {
+
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void onTransferStateChanged(OCFile file, boolean downloading, boolean uploading) {
+            
+    }
+
+    @Override
+    public void onRefresh() {
+        refreshList(true);
+    }
+
+    @Override
+    public void onRefresh(boolean enforced) {
+        refreshList(enforced);
+    }
+
+    private void refreshList(boolean ignoreETag) {
+        OCFileListFragment listOfFiles = getListOfFilesFragment();
+        if (listOfFiles != null) {
+            OCFile folder = listOfFiles.getCurrentFile();
+            if (folder != null) {
+                startSyncFolderOperation(folder, ignoreETag);
+            }
+        }
+    }
+}
diff --git a/src/com/owncloud/android/ui/activity/OnEnforceableRefreshListener.java b/src/com/owncloud/android/ui/activity/OnEnforceableRefreshListener.java
new file mode 100644 (file)
index 0000000..22bdb18
--- /dev/null
@@ -0,0 +1,10 @@
+package com.owncloud.android.ui.activity;
+
+import android.support.v4.widget.SwipeRefreshLayout;
+
+    public interface OnEnforceableRefreshListener extends SwipeRefreshLayout.OnRefreshListener {
+
+        public void onRefresh(boolean enforced);
+
+    }
+
index c962fb2..39b973d 100644 (file)
@@ -18,8 +18,10 @@ package com.owncloud.android.ui.activity;
 
 import java.util.Arrays;
 
+import com.actionbarsherlock.app.ActionBar;
 import com.actionbarsherlock.app.SherlockFragmentActivity;
 import com.owncloud.android.R;
+import com.owncloud.android.utils.DisplayUtils;
 
 import android.app.AlertDialog;
 import android.content.DialogInterface;
@@ -44,23 +46,23 @@ public class PinCodeActivity extends SherlockFragmentActivity {
     public final static String EXTRA_ACTIVITY = "com.owncloud.android.ui.activity.PinCodeActivity.ACTIVITY";
     public final static String EXTRA_NEW_STATE = "com.owncloud.android.ui.activity.PinCodeActivity.NEW_STATE";
     
-    Button bCancel;
-    TextView mPinHdr;
-    TextView mPinHdrExplanation;
-    EditText mText1;
-    EditText mText2;
-    EditText mText3;
-    EditText mText4;
+    private Button mBCancel;
+    private TextView mPinHdr;
+    private TextView mPinHdrExplanation;
+    private EditText mText1;
+    private EditText mText2;
+    private EditText mText3;
+    private EditText mText4;
     
-    String [] tempText ={"","","",""};
+    private String [] mTempText ={"","","",""};
     
-    String activity;
+    private String mActivity;
     
-    boolean confirmingPinCode = false;
-    boolean pinCodeChecked = false;
-    boolean newPasswordEntered = false;
-    boolean bChange = true; // to control that only one blocks jump
-    int tCounter ; // Count the number of attempts an user could introduce the PIN code
+    private boolean mConfirmingPinCode = false;
+    private boolean mPinCodeChecked = false;
+    private boolean mNewPasswordEntered = false;
+    private boolean mBChange = true; // to control that only one blocks jump
+    //private int mTCounter ; // Count the number of attempts an user could introduce the PIN code
 
     
     protected void onCreate(Bundle savedInstanceState) {
@@ -68,9 +70,9 @@ public class PinCodeActivity extends SherlockFragmentActivity {
         setContentView(R.layout.pincodelock); 
         
         Intent intent = getIntent();
-        activity = intent.getStringExtra(EXTRA_ACTIVITY);
+        mActivity = intent.getStringExtra(EXTRA_ACTIVITY);
      
-        bCancel = (Button) findViewById(R.id.cancel);
+        mBCancel = (Button) findViewById(R.id.cancel);
         mPinHdr = (TextView) findViewById(R.id.pinHdr);
         mPinHdrExplanation = (TextView) findViewById(R.id.pinHdrExpl);
         mText1 = (EditText) findViewById(R.id.txt1);
@@ -88,23 +90,23 @@ public class PinCodeActivity extends SherlockFragmentActivity {
         // In a previous version settings is allow from start
         if ( (appPrefs.getString("PrefPinCode1", null) == null ) ){
             setChangePincodeView(true);
-            pinCodeChecked = true; 
-            newPasswordEntered = true;
+            mPinCodeChecked = true; 
+            mNewPasswordEntered = true;
             
         }else{ 
             
             if (appPrefs.getBoolean("set_pincode", false)){
                // pincode activated
-               if (activity.equals("preferences")){
+               if (mActivity.equals("preferences")){
                 // PIN has been activated yet
                  mPinHdr.setText(R.string.pincode_configure_your_pin);
                  mPinHdrExplanation.setVisibility(View.VISIBLE);
-                 pinCodeChecked = true ; // No need to check it 
+                 mPinCodeChecked = true ; // No need to check it 
                  setChangePincodeView(true);
                }else{
                 // PIN active
-                 bCancel.setVisibility(View.INVISIBLE);
-                 bCancel.setVisibility(View.GONE);
+                 mBCancel.setVisibility(View.INVISIBLE);
+                 mBCancel.setVisibility(View.GONE);
                  mPinHdr.setText(R.string.pincode_enter_pin_code);
                  mPinHdrExplanation.setVisibility(View.INVISIBLE);
                  setChangePincodeView(false);
@@ -114,28 +116,29 @@ public class PinCodeActivity extends SherlockFragmentActivity {
             // pincode removal
               mPinHdr.setText(R.string.pincode_remove_your_pincode);
               mPinHdrExplanation.setVisibility(View.INVISIBLE);
-              pinCodeChecked = false;
+              mPinCodeChecked = false;
               setChangePincodeView(true); 
            }
            
         }
         setTextListeners();
         
-        
+        ActionBar actionBar = getSupportActionBar();
+        actionBar.setIcon(DisplayUtils.getSeasonalIconId());
     }
     
 
      
     protected void setInitVars(){
-        confirmingPinCode = false;
-        pinCodeChecked = false;
-        newPasswordEntered = false;
+        mConfirmingPinCode = false;
+        mPinCodeChecked = false;
+        mNewPasswordEntered = false;
 
     }
     
     protected void setInitView(){
-        bCancel.setVisibility(View.INVISIBLE);
-        bCancel.setVisibility(View.GONE);
+        mBCancel.setVisibility(View.INVISIBLE);
+        mBCancel.setVisibility(View.GONE);
         mPinHdr.setText(R.string.pincode_enter_pin_code);
         mPinHdrExplanation.setVisibility(View.INVISIBLE);
     }
@@ -144,8 +147,8 @@ public class PinCodeActivity extends SherlockFragmentActivity {
     protected void setChangePincodeView(boolean state){
        
         if(state){
-        bCancel.setVisibility(View.VISIBLE);
-        bCancel.setOnClickListener(new OnClickListener() {
+        mBCancel.setVisibility(View.VISIBLE);
+        mBCancel.setOnClickListener(new OnClickListener() {
         @Override
         public void onClick(View v) {
             
@@ -192,8 +195,8 @@ public class PinCodeActivity extends SherlockFragmentActivity {
             @Override
             public void afterTextChanged(Editable s) {
                 if (s.length() > 0) {
-                    if (!confirmingPinCode){
-                       tempText[0] = mText1.getText().toString();
+                    if (!mConfirmingPinCode){
+                       mTempText[0] = mText1.getText().toString();
                        
                     }
                     mText2.requestFocus();
@@ -221,8 +224,8 @@ public class PinCodeActivity extends SherlockFragmentActivity {
             @Override
             public void afterTextChanged(Editable s) {
                 if (s.length() > 0) {
-                    if (!confirmingPinCode){
-                        tempText[1] = mText2.getText().toString();
+                    if (!mConfirmingPinCode){
+                        mTempText[1] = mText2.getText().toString();
                     }
                     
                     mText3.requestFocus();
@@ -234,16 +237,16 @@ public class PinCodeActivity extends SherlockFragmentActivity {
 
             @Override
             public boolean onKey(View v, int keyCode, KeyEvent event) {
-                if (keyCode == KeyEvent.KEYCODE_DEL && bChange) {
+                if (keyCode == KeyEvent.KEYCODE_DEL && mBChange) {
 
                     mText1.setText("");
                     mText1.requestFocus();
-                    if (!confirmingPinCode)
-                       tempText[0] = "";
-                    bChange= false;
+                    if (!mConfirmingPinCode)
+                       mTempText[0] = "";
+                    mBChange= false;
                 
-                }else if(!bChange){
-                    bChange=true;
+                }else if(!mBChange){
+                    mBChange=true;
                     
                 }
                 return false;
@@ -285,8 +288,8 @@ public class PinCodeActivity extends SherlockFragmentActivity {
             @Override
             public void afterTextChanged(Editable s) {
                 if (s.length() > 0) {
-                    if (!confirmingPinCode){
-                        tempText[2] = mText3.getText().toString();
+                    if (!mConfirmingPinCode){
+                        mTempText[2] = mText3.getText().toString();
                     }
                     mText4.requestFocus();
                 }
@@ -297,15 +300,15 @@ public class PinCodeActivity extends SherlockFragmentActivity {
 
             @Override
             public boolean onKey(View v, int keyCode, KeyEvent event) {
-                if (keyCode == KeyEvent.KEYCODE_DEL && bChange) {
+                if (keyCode == KeyEvent.KEYCODE_DEL && mBChange) {
                     mText2.requestFocus();
-                    if (!confirmingPinCode)
-                        tempText[1] = "";
+                    if (!mConfirmingPinCode)
+                        mTempText[1] = "";
                     mText2.setText("");
-                    bChange= false;
+                    mBChange= false;
                     
-                }else if(!bChange){
-                    bChange=true;                        
+                }else if(!mBChange){
+                    mBChange=true;                        
                     
                 }
                 return false;
@@ -353,18 +356,19 @@ public class PinCodeActivity extends SherlockFragmentActivity {
             public void afterTextChanged(Editable s) {
                 if (s.length() > 0) {
                     
-                    if (!confirmingPinCode){
-                       tempText[3] = mText4.getText().toString();
+                    if (!mConfirmingPinCode){
+                       mTempText[3] = mText4.getText().toString();
                     }
                     mText1.requestFocus();
 
-                    if (!pinCodeChecked){
-                        pinCodeChecked = checkPincode();
+                    if (!mPinCodeChecked){
+                        mPinCodeChecked = checkPincode();
                     }
                     
-                    if (pinCodeChecked && activity.equals("FileDisplayActivity")){
+                    if (mPinCodeChecked && 
+                            ( mActivity.equals("FileDisplayActivity") || mActivity.equals("PreviewImageActivity") ) ){
                         finish();
-                    } else if (pinCodeChecked){
+                    } else if (mPinCodeChecked){
                         
                         Intent intent = getIntent();
                         String newState = intent.getStringExtra(EXTRA_NEW_STATE);
@@ -380,7 +384,7 @@ public class PinCodeActivity extends SherlockFragmentActivity {
                             
                         }else{
                         
-                            if (!confirmingPinCode){
+                            if (!mConfirmingPinCode){
                                 pinCodeChangeRequest();
                              
                             } else {
@@ -400,15 +404,15 @@ public class PinCodeActivity extends SherlockFragmentActivity {
 
             @Override
             public boolean onKey(View v, int keyCode, KeyEvent event) {
-                if (keyCode == KeyEvent.KEYCODE_DEL && bChange) {
+                if (keyCode == KeyEvent.KEYCODE_DEL && mBChange) {
                     mText3.requestFocus();
-                    if (!confirmingPinCode)
-                        tempText[2]="";
+                    if (!mConfirmingPinCode)
+                        mTempText[2]="";
                     mText3.setText("");
-                    bChange= false;
+                    mBChange= false;
                     
-                }else if(!bChange){
-                    bChange=true;    
+                }else if(!mBChange){
+                    mBChange=true;    
                 }
                 return false;
             }
@@ -453,7 +457,7 @@ public class PinCodeActivity extends SherlockFragmentActivity {
         clearBoxes(); 
         mPinHdr.setText(R.string.pincode_reenter_your_pincode); 
         mPinHdrExplanation.setVisibility(View.INVISIBLE);        
-        confirmingPinCode =true;
+        mConfirmingPinCode =true;
         
     }
     
@@ -469,16 +473,16 @@ public class PinCodeActivity extends SherlockFragmentActivity {
         String pText3 = appPrefs.getString("PrefPinCode3", null);
         String pText4 = appPrefs.getString("PrefPinCode4", null);
 
-        if ( tempText[0].equals(pText1) && 
-             tempText[1].equals(pText2) &&
-             tempText[2].equals(pText3) &&
-             tempText[3].equals(pText4) ) {
+        if ( mTempText[0].equals(pText1) && 
+             mTempText[1].equals(pText2) &&
+             mTempText[2].equals(pText3) &&
+             mTempText[3].equals(pText4) ) {
             
             return true;
         
         
         }else {
-            Arrays.fill(tempText, null);
+            Arrays.fill(mTempText, null);
             AlertDialog aDialog = new AlertDialog.Builder(this).create();
             CharSequence errorSeq = getString(R.string.common_error);
             aDialog.setTitle(errorSeq);
@@ -497,8 +501,8 @@ public class PinCodeActivity extends SherlockFragmentActivity {
             clearBoxes(); 
             mPinHdr.setText(R.string.pincode_enter_pin_code);
             mPinHdrExplanation.setVisibility(View.INVISIBLE);
-            newPasswordEntered = true;
-            confirmingPinCode = false;
+            mNewPasswordEntered = true;
+            mConfirmingPinCode = false;
             
         }
      
@@ -508,23 +512,23 @@ public class PinCodeActivity extends SherlockFragmentActivity {
     
     protected void confirmPincode(){
         
-        confirmingPinCode = false;
+        mConfirmingPinCode = false;
         
         String rText1 = mText1.getText().toString();
         String rText2 = mText2.getText().toString();
         String rText3 = mText3.getText().toString();
         String rText4 = mText4.getText().toString();
         
-        if ( tempText[0].equals(rText1) && 
-             tempText[1].equals(rText2) &&
-             tempText[2].equals(rText3) &&
-             tempText[3].equals(rText4) ) {
+        if ( mTempText[0].equals(rText1) && 
+             mTempText[1].equals(rText2) &&
+             mTempText[2].equals(rText3) &&
+             mTempText[3].equals(rText4) ) {
                         
             savePincodeAndExit();
             
         } else {
             
-            Arrays.fill(tempText, null);
+            Arrays.fill(mTempText, null);
             AlertDialog aDialog = new AlertDialog.Builder(this).create();
             CharSequence errorSeq = getString(R.string.common_error);
             aDialog.setTitle(errorSeq);
@@ -581,10 +585,10 @@ public class PinCodeActivity extends SherlockFragmentActivity {
         SharedPreferences.Editor appPrefs = PreferenceManager
                 .getDefaultSharedPreferences(getApplicationContext()).edit();
         
-        appPrefs.putString("PrefPinCode1", tempText[0]);
-        appPrefs.putString("PrefPinCode2",tempText[1]);
-        appPrefs.putString("PrefPinCode3", tempText[2]);
-        appPrefs.putString("PrefPinCode4", tempText[3]);
+        appPrefs.putString("PrefPinCode1", mTempText[0]);
+        appPrefs.putString("PrefPinCode2",mTempText[1]);
+        appPrefs.putString("PrefPinCode3", mTempText[2]);
+        appPrefs.putString("PrefPinCode4", mTempText[3]);
         appPrefs.putBoolean("set_pincode",true);
         appPrefs.commit();
         
@@ -609,7 +613,7 @@ public class PinCodeActivity extends SherlockFragmentActivity {
     public boolean onKeyDown(int keyCode, KeyEvent event){
         if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount()== 0){
             
-            if (activity.equals("preferences")){
+            if (mActivity.equals("preferences")){
                 SharedPreferences.Editor appPrefsE = PreferenceManager
             
                     .getDefaultSharedPreferences(getApplicationContext()).edit();
index e94942e..d078b1e 100644 (file)
  */
 package com.owncloud.android.ui.activity;
 
-import java.util.Vector;
-
+import android.accounts.Account;
+import android.accounts.AccountManager;
+import android.accounts.AccountManagerCallback;
+import android.accounts.AccountManagerFuture;
 import android.content.Intent;
 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.preference.CheckBoxPreference;
 import android.preference.Preference;
 import android.preference.Preference.OnPreferenceChangeListener;
 import android.preference.Preference.OnPreferenceClickListener;
 import android.preference.PreferenceCategory;
 import android.preference.PreferenceManager;
+import android.view.ContextMenu;
+import android.view.ContextMenu.ContextMenuInfo;
+import android.view.View;
+import android.widget.AdapterView;
+import android.widget.AdapterView.OnItemLongClickListener;
+import android.widget.ListAdapter;
+import android.widget.ListView;
 
 import com.actionbarsherlock.app.ActionBar;
 import com.actionbarsherlock.app.SherlockPreferenceActivity;
 import com.actionbarsherlock.view.Menu;
 import com.actionbarsherlock.view.MenuItem;
-import com.owncloud.android.Log_OC;
-import com.owncloud.android.OwnCloudSession;
+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.db.DbHandler;
+import com.owncloud.android.lib.common.utils.Log_OC;
+import com.owncloud.android.ui.LongClickableCheckBoxPreference;
+import com.owncloud.android.utils.DisplayUtils;
 
 
 /**
@@ -48,18 +62,19 @@ import com.owncloud.android.db.DbHandler;
  * @author Bartek Przybylski
  * @author David A. Velasco
  */
-public class Preferences extends SherlockPreferenceActivity {
+public class Preferences extends SherlockPreferenceActivity implements AccountManagerCallback<Boolean> {
     
     private static final String TAG = "OwnCloudPreferences";
-    private final int mNewSession = 47;
-    private final int mEditSession = 48;
+
     private DbHandler mDbHandler;
-    private Vector<OwnCloudSession> mSessions;
     private CheckBoxPreference pCode;
-    //private CheckBoxPreference pLogging;
-    //private Preference pLoggingHistory;
     private Preference pAboutApp;
-    private int mSelectedMenuItem;
+
+    private PreferenceCategory mAccountsPrefCategory = null;
+    private final Handler mHandler = new Handler();
+    private String mAccountName;
+    private boolean mShowContextMenu = false;
+    private String mUploadPath;
 
 
     @SuppressWarnings("deprecation")
@@ -67,23 +82,42 @@ public class Preferences extends SherlockPreferenceActivity {
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         mDbHandler = new DbHandler(getBaseContext());
-        mSessions = new Vector<OwnCloudSession>();
         addPreferencesFromResource(R.xml.preferences);
-        //populateAccountList();
+
         ActionBar actionBar = getSherlock().getActionBar();
+        actionBar.setIcon(DisplayUtils.getSeasonalIconId());
         actionBar.setDisplayHomeAsUpEnabled(true);
-        
-        Preference p = findPreference("manage_account");
-        if (p != null)
-        p.setOnPreferenceClickListener(new OnPreferenceClickListener() {
+        actionBar.setTitle(R.string.actionbar_settings);
+
+        loadInstantUploadPath();
+
+        // Load the accounts category for adding the list of accounts
+        mAccountsPrefCategory = (PreferenceCategory) findPreference("accounts_category");
+
+        ListView listView = getListView();
+        listView.setOnItemLongClickListener(new OnItemLongClickListener() {
             @Override
-            public boolean onPreferenceClick(Preference preference) {
-                Intent i = new Intent(getApplicationContext(), AccountSelectActivity.class);
-                startActivity(i);
-                return true;
+            public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
+                ListView listView = (ListView) parent;
+                ListAdapter listAdapter = listView.getAdapter();
+                Object obj = listAdapter.getItem(position);
+
+                if (obj != null && obj instanceof LongClickableCheckBoxPreference) {
+                    mShowContextMenu = true;
+                    mAccountName = obj.toString();
+
+                    Preferences.this.openContextMenu(listView);
+
+                    View.OnLongClickListener longListener = (View.OnLongClickListener) obj;
+                    return longListener.onLongClick(view);
+                }
+                return false;
             }
         });
-        
+
+        // Register context menu for list of preferences.
+        registerForContextMenu(getListView());
+
         pCode = (CheckBoxPreference) findPreference("set_pincode");
         if (pCode != null){
             pCode.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
@@ -99,8 +133,6 @@ public class Preferences extends SherlockPreferenceActivity {
             });            
             
         }
-        
-        
 
         PreferenceCategory preferenceCategory = (PreferenceCategory) findPreference("more");
         
@@ -137,18 +169,19 @@ public class Preferences extends SherlockPreferenceActivity {
 
                         Intent intent = new Intent(Intent.ACTION_SENDTO); 
                         intent.setType("text/plain");
-                        //Account currentAccount = AccountUtils.getCurrentOwnCloudAccount(Preferences.this);
+                        intent.setData(Uri.parse(getString(R.string.mail_recommend))); 
+                        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 
+                        
                         String appName = getString(R.string.app_name);
-                        //String username = currentAccount.name.substring(0, currentAccount.name.lastIndexOf('@')); 
-                        //String recommendSubject = String.format(getString(R.string.recommend_subject), username, appName);
+                        String downloadUrl = getString(R.string.url_app_download);
+                        Account currentAccount = AccountUtils.getCurrentOwnCloudAccount(Preferences.this);
+                        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);
+                        
                         intent.putExtra(Intent.EXTRA_SUBJECT, recommendSubject);
-                        //String recommendText = String.format(getString(R.string.recommend_text), getString(R.string.app_name), username);
-                        String recommendText = String.format(getString(R.string.recommend_text), getString(R.string.app_name), getString(R.string.url_app_download));
                         intent.putExtra(Intent.EXTRA_TEXT, recommendText);
-
-                        intent.setData(Uri.parse(getString(R.string.mail_recommend))); 
-                        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 
                         startActivity(intent);
 
 
@@ -209,6 +242,16 @@ public class Preferences extends SherlockPreferenceActivity {
                 preferenceCategory.removePreference(pImprint);
             }
         }
+
+        Preference pInstantUploadPathApp = (Preference) findPreference("instant_upload_path");
+
+        pInstantUploadPathApp.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
+            @Override
+            public boolean onPreferenceChange(Preference preference, Object newValue) {
+                mUploadPath = updateInstantUploadPath(newValue.toString());
+                return true;
+            }
+        });
             
         /* About App */
        pAboutApp = (Preference) findPreference("about_app");
@@ -222,52 +265,83 @@ public class Preferences extends SherlockPreferenceActivity {
                    Log_OC.e(TAG, "Error while showing about dialog", e);
                }
        }
-       
-       /* DISABLED FOR RELEASE UNTIL FIXED 
-       pLogging = (CheckBoxPreference) findPreference("log_to_file");
-       if (pLogging != null) {
-           pLogging.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
-               @Override
-               public boolean onPreferenceChange(Preference preference, Object newValue) {
-                   
-                   String logpath = Environment.getExternalStorageDirectory()+File.separator+"owncloud"+File.separator+"log";
-                
-                   if(!pLogging.isChecked()) {
-                       Log_OC.d("Debug", "start logging");
-                       Log_OC.v("PATH", logpath);
-                       Log_OC.startLogging(logpath);
-                   }
-                   else {
-                       Log_OC.d("Debug", "stop logging");
-                       Log_OC.stopLogging();
-                   }
-                   return true;
-               }
-           });
-       }
-       
-       pLoggingHistory = (Preference) findPreference("log_history");
-       if (pLoggingHistory != null) {
-           pLoggingHistory.setOnPreferenceClickListener(new OnPreferenceClickListener() {
-            
-            @Override
-            public boolean onPreferenceClick(Preference preference) {
-                Intent intent = new Intent(getApplicationContext(),LogHistoryActivity.class);
-                startActivity(intent);
-                return true;
+    }
+
+    @Override
+    protected void onPause() {
+        saveInstantUploadPathOnPreferences();
+        super.onPause();
+    }
+
+    @Override
+    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
+
+        // Filter for only showing contextual menu when long press on the
+        // accounts
+        if (mShowContextMenu) {
+            getMenuInflater().inflate(R.menu.account_picker_long_click, menu);
+            mShowContextMenu = false;
+        }
+        super.onCreateContextMenu(menu, v, menuInfo);
+    }
+
+    /**
+     * Called when the user clicked on an item into the context menu created at
+     * {@link #onCreateContextMenu(ContextMenu, View, ContextMenuInfo)} for
+     * every ownCloud {@link Account} , containing 'secondary actions' for them.
+     * 
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean onContextItemSelected(android.view.MenuItem item) {
+        AccountManager am = (AccountManager) getSystemService(ACCOUNT_SERVICE);
+        Account accounts[] = am.getAccountsByType(MainApp.getAccountType());
+        for (Account a : accounts) {
+            if (a.name.equals(mAccountName)) {
+                if (item.getItemId() == R.id.change_password) {
+
+                    // Change account password
+                    Intent updateAccountCredentials = new Intent(this, AuthenticatorActivity.class);
+                    updateAccountCredentials.putExtra(AuthenticatorActivity.EXTRA_ACCOUNT, a);
+                    updateAccountCredentials.putExtra(AuthenticatorActivity.EXTRA_ACTION,
+                            AuthenticatorActivity.ACTION_UPDATE_TOKEN);
+                    startActivity(updateAccountCredentials);
+
+                } else if (item.getItemId() == R.id.delete_account) {
+
+                    // Remove account
+                    am.removeAccount(a, this, mHandler);
+                }
             }
-        });
-       }
-       */
-       
+        }
+
+        return true;
+    }
+
+    @Override
+    public void run(AccountManagerFuture<Boolean> future) {
+        if (future.isDone()) {
+            Account a = AccountUtils.getCurrentOwnCloudAccount(this);
+            String accountName = "";
+            if (a == null) {
+                Account[] accounts = AccountManager.get(this).getAccountsByType(MainApp.getAccountType());
+                if (accounts.length != 0)
+                    accountName = accounts[0].name;
+                AccountUtils.setCurrentOwnCloudAccount(this, accountName);
+            }
+            addAccountsCheckboxPreferences();
+        }
     }
 
     @Override
     protected void onResume() {
+        super.onResume();
         SharedPreferences appPrefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
         boolean state = appPrefs.getBoolean("set_pincode", false);
         pCode.setChecked(state);
-        super.onResume();
+
+        // Populate the accounts category with the list of accounts
+        addAccountsCheckboxPreferences();
     }
 
     @Override
@@ -304,5 +378,150 @@ public class Preferences extends SherlockPreferenceActivity {
         mDbHandler.close();
         super.onDestroy();
     }
-    
+
+    /**
+     * Create the list of accounts that has been added into the app
+     */
+    @SuppressWarnings("deprecation")
+    private void addAccountsCheckboxPreferences() {
+
+        // Remove accounts in case list is refreshing for avoiding to have
+        // duplicate items
+        if (mAccountsPrefCategory.getPreferenceCount() > 0) {
+            mAccountsPrefCategory.removeAll();
+        }
+
+        AccountManager am = (AccountManager) getSystemService(ACCOUNT_SERVICE);
+        Account accounts[] = am.getAccountsByType(MainApp.getAccountType());
+        Account currentAccount = AccountUtils.getCurrentOwnCloudAccount(getApplicationContext());
+
+        if (am.getAccountsByType(MainApp.getAccountType()).length == 0) {
+            // Show create account screen if there isn't any account
+            am.addAccount(MainApp.getAccountType(), null, null, null, this,
+                    null,
+                    null);
+        }
+        else {
+
+            for (Account a : accounts) {
+                LongClickableCheckBoxPreference accountPreference = new LongClickableCheckBoxPreference(this);
+                accountPreference.setKey(a.name);
+                accountPreference.setTitle(a.name);
+                mAccountsPrefCategory.addPreference(accountPreference);
+
+                // Check the current account that is being used
+                if (a.name.equals(currentAccount.name)) {
+                    accountPreference.setChecked(true);
+                } else {
+                    accountPreference.setChecked(false);
+                }
+
+                accountPreference.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
+                    @Override
+                    public boolean onPreferenceChange(Preference preference, Object newValue) {
+                        String key = preference.getKey();
+                        AccountManager am = (AccountManager) getSystemService(ACCOUNT_SERVICE);
+                        Account accounts[] = am.getAccountsByType(MainApp.getAccountType());
+                        for (Account a : accounts) {
+                            CheckBoxPreference p = (CheckBoxPreference) findPreference(a.name);
+                            if (key.equals(a.name)) {
+                                boolean accountChanged = !p.isChecked(); 
+                                p.setChecked(true);
+                                AccountUtils.setCurrentOwnCloudAccount(
+                                        getApplicationContext(),
+                                        a.name
+                                );
+                                if (accountChanged) {
+                                    // restart the main activity
+                                    Intent i = new Intent(
+                                            Preferences.this, 
+                                            FileDisplayActivity.class
+                                    );
+                                    i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+                                    startActivity(i);
+                                } else {
+                                    finish();
+                                }
+                            } else {
+                                p.setChecked(false);
+                            }
+                        }
+                        return (Boolean) newValue;
+                    }
+                });
+
+            }
+
+            // Add Create Account preference at the end of account list if
+            // Multiaccount is enabled
+            if (getResources().getBoolean(R.bool.multiaccount_support)) {
+                createAddAccountPreference();
+            }
+
+        }
+    }
+
+    /**
+     * Create the preference for allow adding new accounts
+     */
+    private void createAddAccountPreference() {
+        Preference addAccountPref = new Preference(this);
+        addAccountPref.setKey("add_account");
+        addAccountPref.setTitle(getString(R.string.prefs_add_account));
+        mAccountsPrefCategory.addPreference(addAccountPref);
+
+        addAccountPref.setOnPreferenceClickListener(new OnPreferenceClickListener() {
+            @Override
+            public boolean onPreferenceClick(Preference preference) {
+                AccountManager am = AccountManager.get(getApplicationContext());
+                am.addAccount(MainApp.getAccountType(), null, null, null, Preferences.this, null, null);
+                return true;
+            }
+        });
+
+    }
+
+    /**
+     * Update the upload path checking that it is a correct path
+     * @param uploadPath: path write by user
+     * @return String: uploadPath
+     */
+    private String updateInstantUploadPath(String uploadPath) {
+        String slashString = "/";
+
+        // If slashes are duplicated, replace them for only one slash
+        uploadPath = uploadPath.replaceAll("/+", slashString);
+
+        // Remove last slash from path
+        if (uploadPath.length() > 0 && uploadPath.charAt(uploadPath.length()-1) == slashString.charAt(0)) {
+            uploadPath = uploadPath.substring(0, uploadPath.length()-1);
+        }
+
+        if (uploadPath.isEmpty()) { // Set default instant upload path
+            uploadPath = getString(R.string.instant_upload_path);
+        }else {
+            if (!uploadPath.startsWith(slashString)) { // Add initial slash on path if necessary
+                uploadPath = slashString.concat(uploadPath);
+            }
+        }
+        return uploadPath;
+    }
+
+    /**
+     * Load upload path set on preferences
+     */
+    private void loadInstantUploadPath() {
+        SharedPreferences appPrefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
+        mUploadPath = appPrefs.getString("instant_upload_path", getString(R.string.instant_upload_path));
+    }
+
+    /**
+     * Save the "Instant Upload Path" on preferences
+     */
+    private void saveInstantUploadPathOnPreferences() {
+        SharedPreferences appPrefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());        
+        SharedPreferences.Editor editor = appPrefs.edit();
+        editor.putString("instant_upload_path", mUploadPath);
+        editor.commit();
+    }
 }
diff --git a/src/com/owncloud/android/ui/activity/TransferServiceGetter.java b/src/com/owncloud/android/ui/activity/TransferServiceGetter.java
deleted file mode 100644 (file)
index fbc348d..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012 Bartek Przybylski
- *   Copyright (C) 2012-2013 ownCloud Inc.
- *
- *   This program is free software: you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License version 2,
- *   as published by the Free Software Foundation.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-package com.owncloud.android.ui.activity;
-
-import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder;
-import com.owncloud.android.files.services.FileUploader.FileUploaderBinder;
-
-public interface TransferServiceGetter {
-
-    /**
-     * Callback method invoked when the parent activity is fully created to get a reference to the FileDownloader service API.
-     * 
-     * @return  Directory to list firstly. Can be NULL.
-     */
-    public FileDownloaderBinder getFileDownloaderBinder();
-
-    
-    /**
-     * Callback method invoked when the parent activity is fully created to get a reference to the FileUploader service API.
-     * 
-     * @return  Directory to list firstly. Can be NULL.
-     */
-    public FileUploaderBinder getFileUploaderBinder();
-
-
-}
index cc1f7de..0918572 100644 (file)
@@ -35,12 +35,13 @@ import android.widget.TextView;
 import com.actionbarsherlock.app.ActionBar;
 import com.actionbarsherlock.app.ActionBar.OnNavigationListener;
 import com.actionbarsherlock.view.MenuItem;
-import com.owncloud.android.Log_OC;
 import com.owncloud.android.R;
+import com.owncloud.android.lib.common.utils.Log_OC;
+import com.owncloud.android.ui.dialog.ConfirmationDialogFragment;
 import com.owncloud.android.ui.dialog.IndeterminateProgressDialog;
-import com.owncloud.android.ui.fragment.ConfirmationDialogFragment;
+import com.owncloud.android.ui.dialog.ConfirmationDialogFragment.ConfirmationDialogFragmentListener;
 import com.owncloud.android.ui.fragment.LocalFileListFragment;
-import com.owncloud.android.ui.fragment.ConfirmationDialogFragment.ConfirmationDialogFragmentListener;
+import com.owncloud.android.utils.DisplayUtils;
 import com.owncloud.android.utils.FileStorageUtils;
 
 
@@ -111,6 +112,7 @@ public class UploadFilesActivity extends FileActivity implements
             
         // Action bar setup
         ActionBar actionBar = getSupportActionBar();
+        actionBar.setIcon(DisplayUtils.getSeasonalIconId());
         actionBar.setHomeButtonEnabled(true);   // mandatory since Android ICS, according to the official documentation
         actionBar.setDisplayHomeAsUpEnabled(mCurrentDir != null && mCurrentDir.getName() != null);
         actionBar.setDisplayShowTitleEnabled(false);
@@ -378,6 +380,7 @@ public class UploadFilesActivity extends FileActivity implements
 
     @Override
     protected void onAccountSet(boolean stateWasRecovered) {
+        super.onAccountSet(stateWasRecovered);
         if (getAccount() != null) {
             if (!mAccountOnCreation.equals(getAccount())) {
                 setResult(RESULT_CANCELED);
@@ -385,7 +388,6 @@ public class UploadFilesActivity extends FileActivity implements
             }
             
         } else {
-            Log_OC.wtf(TAG, "onAccountChanged was called with NULL account associated!");
             setResult(RESULT_CANCELED);
             finish();
         }
diff --git a/src/com/owncloud/android/ui/activity/Uploader.java b/src/com/owncloud/android/ui/activity/Uploader.java
new file mode 100644 (file)
index 0000000..62ad44a
--- /dev/null
@@ -0,0 +1,420 @@
+/* ownCloud Android client application
+ *   Copyright (C) 2012  Bartek Przybylski
+ *   Copyright (C) 2012-2013 ownCloud Inc.
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License version 2,
+ *   as published by the Free Software Foundation.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.ui.activity;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Stack;
+import java.util.Vector;
+
+import com.owncloud.android.MainApp;
+import com.owncloud.android.R;
+import com.owncloud.android.authentication.AccountAuthenticator;
+import com.owncloud.android.datamodel.FileDataStorageManager;
+import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.files.services.FileUploader;
+import com.owncloud.android.lib.common.utils.Log_OC;
+
+import android.accounts.Account;
+import android.accounts.AccountManager;
+import android.app.AlertDialog;
+import android.app.AlertDialog.Builder;
+import android.app.Dialog;
+import android.app.ListActivity;
+import android.app.ProgressDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.DialogInterface.OnCancelListener;
+import android.content.DialogInterface.OnClickListener;
+import android.content.Intent;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Parcelable;
+import android.provider.MediaStore.Audio;
+import android.provider.MediaStore.Images;
+import android.provider.MediaStore.Video;
+import android.view.View;
+import android.view.Window;
+import android.widget.AdapterView;
+import android.widget.AdapterView.OnItemClickListener;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.SimpleAdapter;
+import android.widget.Toast;
+
+
+/**
+ * This can be used to upload things to an ownCloud instance.
+ * 
+ * @author Bartek Przybylski
+ * 
+ */
+public class Uploader extends ListActivity implements OnItemClickListener, android.view.View.OnClickListener {
+    private static final String TAG = "ownCloudUploader";
+
+    private Account mAccount;
+    private AccountManager mAccountManager;
+    private Stack<String> mParents;
+    private ArrayList<Parcelable> mStreamsToUpload;
+    private boolean mCreateDir;
+    private String mUploadPath;
+    private FileDataStorageManager mStorageManager;
+    private OCFile mFile;
+
+    private final static int DIALOG_NO_ACCOUNT = 0;
+    private final static int DIALOG_WAITING = 1;
+    private final static int DIALOG_NO_STREAM = 2;
+    private final static int DIALOG_MULTIPLE_ACCOUNT = 3;
+
+    private final static int REQUEST_CODE_SETUP_ACCOUNT = 0;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        getWindow().requestFeature(Window.FEATURE_NO_TITLE);
+        mParents = new Stack<String>();
+        mParents.add("");
+        if (prepareStreamsToUpload()) {
+            mAccountManager = (AccountManager) getSystemService(Context.ACCOUNT_SERVICE);
+            Account[] accounts = mAccountManager.getAccountsByType(MainApp.getAccountType());
+            if (accounts.length == 0) {
+                Log_OC.i(TAG, "No ownCloud account is available");
+                showDialog(DIALOG_NO_ACCOUNT);
+            } else if (accounts.length > 1) {
+                Log_OC.i(TAG, "More then one ownCloud is available");
+                showDialog(DIALOG_MULTIPLE_ACCOUNT);
+            } else {
+                mAccount = accounts[0];
+                mStorageManager = new FileDataStorageManager(mAccount, getContentResolver());
+                populateDirectoryList();
+            }
+        } else {
+            showDialog(DIALOG_NO_STREAM);
+        }
+    }
+    
+    @Override
+    protected Dialog onCreateDialog(final int id) {
+        final AlertDialog.Builder builder = new Builder(this);
+        switch (id) {
+        case DIALOG_WAITING:
+            ProgressDialog pDialog = new ProgressDialog(this);
+            pDialog.setIndeterminate(false);
+            pDialog.setCancelable(false);
+            pDialog.setMessage(getResources().getString(R.string.uploader_info_uploading));
+            return pDialog;
+        case DIALOG_NO_ACCOUNT:
+            builder.setIcon(android.R.drawable.ic_dialog_alert);
+            builder.setTitle(R.string.uploader_wrn_no_account_title);
+            builder.setMessage(String.format(getString(R.string.uploader_wrn_no_account_text), getString(R.string.app_name)));
+            builder.setCancelable(false);
+            builder.setPositiveButton(R.string.uploader_wrn_no_account_setup_btn_text, new OnClickListener() {
+                @Override
+                public void onClick(DialogInterface dialog, int which) {
+                    if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.ECLAIR_MR1) {
+                        // using string value since in API7 this
+                        // constatn is not defined
+                        // in API7 < this constatant is defined in
+                        // Settings.ADD_ACCOUNT_SETTINGS
+                        // and Settings.EXTRA_AUTHORITIES
+                        Intent intent = new Intent(android.provider.Settings.ACTION_ADD_ACCOUNT);
+                        intent.putExtra("authorities", new String[] { MainApp.getAuthTokenType() });
+                        startActivityForResult(intent, REQUEST_CODE_SETUP_ACCOUNT);
+                    } else {
+                        // since in API7 there is no direct call for
+                        // account setup, so we need to
+                        // show our own AccountSetupAcricity, get
+                        // desired results and setup
+                        // everything for ourself
+                        Intent intent = new Intent(getBaseContext(), AccountAuthenticator.class);
+                        startActivityForResult(intent, REQUEST_CODE_SETUP_ACCOUNT);
+                    }
+                }
+            });
+            builder.setNegativeButton(R.string.uploader_wrn_no_account_quit_btn_text, new OnClickListener() {
+                @Override
+                public void onClick(DialogInterface dialog, int which) {
+                    finish();
+                }
+            });
+            return builder.create();
+        case DIALOG_MULTIPLE_ACCOUNT:
+            CharSequence ac[] = new CharSequence[mAccountManager.getAccountsByType(MainApp.getAccountType()).length];
+            for (int i = 0; i < ac.length; ++i) {
+                ac[i] = mAccountManager.getAccountsByType(MainApp.getAccountType())[i].name;
+            }
+            builder.setTitle(R.string.common_choose_account);
+            builder.setItems(ac, new OnClickListener() {
+                @Override
+                public void onClick(DialogInterface dialog, int which) {
+                    mAccount = mAccountManager.getAccountsByType(MainApp.getAccountType())[which];
+                    mStorageManager = new FileDataStorageManager(mAccount, getContentResolver());
+                    populateDirectoryList();
+                }
+            });
+            builder.setCancelable(true);
+            builder.setOnCancelListener(new OnCancelListener() {
+                @Override
+                public void onCancel(DialogInterface dialog) {
+                    dialog.cancel();
+                    finish();
+                }
+            });
+            return builder.create();
+        case DIALOG_NO_STREAM:
+            builder.setIcon(android.R.drawable.ic_dialog_alert);
+            builder.setTitle(R.string.uploader_wrn_no_content_title);
+            builder.setMessage(R.string.uploader_wrn_no_content_text);
+            builder.setCancelable(false);
+            builder.setNegativeButton(R.string.common_cancel, new OnClickListener() {
+                @Override
+                public void onClick(DialogInterface dialog, int which) {
+                    finish();
+                }
+            });
+            return builder.create();
+        default:
+            throw new IllegalArgumentException("Unknown dialog id: " + id);
+        }
+    }
+
+    class a implements OnClickListener {
+        String mPath;
+        EditText mDirname;
+
+        public a(String path, EditText dirname) {
+            mPath = path; 
+            mDirname = dirname;
+        }
+
+        @Override
+        public void onClick(DialogInterface dialog, int which) {
+            Uploader.this.mUploadPath = mPath + mDirname.getText().toString();
+            Uploader.this.mCreateDir = true;
+            uploadFiles();
+        }
+    }
+
+    @Override
+    public void onBackPressed() {
+
+        if (mParents.size() <= 1) {
+            super.onBackPressed();
+            return;
+        } else {
+            mParents.pop();
+            populateDirectoryList();
+        }
+    }
+
+    @Override
+    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+        // click on folder in the list
+        Log_OC.d(TAG, "on item click");
+        Vector<OCFile> tmpfiles = mStorageManager.getFolderContent(mFile);
+        if (tmpfiles.size() <= 0) return;
+        // filter on dirtype
+        Vector<OCFile> files = new Vector<OCFile>();
+        for (OCFile f : tmpfiles)
+            if (f.isFolder())
+                files.add(f);
+        if (files.size() < position) {
+            throw new IndexOutOfBoundsException("Incorrect item selected");
+        }
+        mParents.push(files.get(position).getFileName());
+        populateDirectoryList();
+    }
+
+    @Override
+    public void onClick(View v) {
+        // click on button
+        switch (v.getId()) {
+        case R.id.uploader_choose_folder:
+            mUploadPath = "";   // first element in mParents is root dir, represented by ""; init mUploadPath with "/" results in a "//" prefix
+            for (String p : mParents)
+                mUploadPath += p + OCFile.PATH_SEPARATOR;
+            Log_OC.d(TAG, "Uploading file to dir " + mUploadPath);
+
+            uploadFiles();
+
+            break;
+        default:
+            throw new IllegalArgumentException("Wrong element clicked");
+        }
+    }
+
+    @Override
+    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+        super.onActivityResult(requestCode, resultCode, data);
+        Log_OC.i(TAG, "result received. req: " + requestCode + " res: " + resultCode);
+        if (requestCode == REQUEST_CODE_SETUP_ACCOUNT) {
+            dismissDialog(DIALOG_NO_ACCOUNT);
+            if (resultCode == RESULT_CANCELED) {
+                finish();
+            }
+            Account[] accounts = mAccountManager.getAccountsByType(MainApp.getAuthTokenType());
+            if (accounts.length == 0) {
+                showDialog(DIALOG_NO_ACCOUNT);
+            } else {
+                // there is no need for checking for is there more then one
+                // account at this point
+                // since account setup can set only one account at time
+                mAccount = accounts[0];
+                populateDirectoryList();
+            }
+        }
+    }
+
+    private void populateDirectoryList() {
+        setContentView(R.layout.uploader_layout);
+
+        String full_path = "";
+        for (String a : mParents)
+            full_path += a + "/";
+        
+        Log_OC.d(TAG, "Populating view with content of : " + full_path);
+        
+        mFile = mStorageManager.getFileByPath(full_path);
+        if (mFile != null) {
+            Vector<OCFile> files = mStorageManager.getFolderContent(mFile);
+            List<HashMap<String, Object>> data = new LinkedList<HashMap<String,Object>>();
+            for (OCFile f : files) {
+                HashMap<String, Object> h = new HashMap<String, Object>();
+                if (f.isFolder()) {
+                    h.put("dirname", f.getFileName());
+                    data.add(h);
+                }
+            }
+            SimpleAdapter sa = new SimpleAdapter(this,
+                                                data,
+                                                R.layout.uploader_list_item_layout,
+                                                new String[] {"dirname"},
+                                                new int[] {R.id.textView1});
+            setListAdapter(sa);
+            Button btn = (Button) findViewById(R.id.uploader_choose_folder);
+            btn.setOnClickListener(this);
+            getListView().setOnItemClickListener(this);
+        }
+    }
+
+    private boolean prepareStreamsToUpload() {
+        if (getIntent().getAction().equals(Intent.ACTION_SEND)) {
+            mStreamsToUpload = new ArrayList<Parcelable>();
+            mStreamsToUpload.add(getIntent().getParcelableExtra(Intent.EXTRA_STREAM));
+        } else if (getIntent().getAction().equals(Intent.ACTION_SEND_MULTIPLE)) {
+            mStreamsToUpload = getIntent().getParcelableArrayListExtra(Intent.EXTRA_STREAM);
+        }
+        return (mStreamsToUpload != null && mStreamsToUpload.get(0) != null);
+    }
+
+    public void uploadFiles() {
+        try {
+
+            ArrayList<String> local = new ArrayList<String>();
+            ArrayList<String> remote = new ArrayList<String>();
+            
+            // this checks the mimeType 
+            for (Parcelable mStream : mStreamsToUpload) {
+                
+                Uri uri = (Uri) mStream;
+                if (uri !=null) {
+                    if (uri.getScheme().equals("content")) {
+                        
+                       String mimeType = getContentResolver().getType(uri);
+                       
+                       if (mimeType.contains("image")) {
+                           String[] CONTENT_PROJECTION = { Images.Media.DATA, Images.Media.DISPLAY_NAME, Images.Media.MIME_TYPE, Images.Media.SIZE};
+                           Cursor c = getContentResolver().query(uri, CONTENT_PROJECTION, null, null, null);
+                           c.moveToFirst();
+                           int index = c.getColumnIndex(Images.Media.DATA);
+                           String data = c.getString(index);
+                           local.add(data);
+                           remote.add(mUploadPath + c.getString(c.getColumnIndex(Images.Media.DISPLAY_NAME)));
+                       
+                       }
+                       else if (mimeType.contains("video")) {
+                           String[] CONTENT_PROJECTION = { Video.Media.DATA, Video.Media.DISPLAY_NAME, Video.Media.MIME_TYPE, Video.Media.SIZE, Video.Media.DATE_MODIFIED };
+                           Cursor c = getContentResolver().query(uri, CONTENT_PROJECTION, null, null, null);
+                           c.moveToFirst();
+                           int index = c.getColumnIndex(Video.Media.DATA);
+                           String data = c.getString(index);
+                           local.add(data);
+                           remote.add(mUploadPath + c.getString(c.getColumnIndex(Video.Media.DISPLAY_NAME)));
+                          
+                       }
+                       else if (mimeType.contains("audio")) {
+                           String[] CONTENT_PROJECTION = { Audio.Media.DATA, Audio.Media.DISPLAY_NAME, Audio.Media.MIME_TYPE, Audio.Media.SIZE };
+                           Cursor c = getContentResolver().query(uri, CONTENT_PROJECTION, null, null, null);
+                           c.moveToFirst();
+                           int index = c.getColumnIndex(Audio.Media.DATA);
+                           String data = c.getString(index);
+                           local.add(data);
+                           remote.add(mUploadPath + c.getString(c.getColumnIndex(Audio.Media.DISPLAY_NAME)));
+                        
+                       }
+                       else {
+                           String filePath = Uri.decode(uri.toString()).replace(uri.getScheme() + "://", "");
+                           // cut everything whats before mnt. It occured to me that sometimes apps send their name into the URI
+                           if (filePath.contains("mnt")) {
+                              String splitedFilePath[] = filePath.split("/mnt");
+                              filePath = splitedFilePath[1];
+                           }
+                           final File file = new File(filePath);
+                           local.add(file.getAbsolutePath());
+                           remote.add(mUploadPath + file.getName());
+                       }
+                        
+                    } else if (uri.getScheme().equals("file")) {
+                        String filePath = Uri.decode(uri.toString()).replace(uri.getScheme() + "://", "");
+                        if (filePath.contains("mnt")) {
+                           String splitedFilePath[] = filePath.split("/mnt");
+                           filePath = splitedFilePath[1];
+                        }
+                        final File file = new File(filePath);
+                        local.add(file.getAbsolutePath());
+                        remote.add(mUploadPath + file.getName());
+                    }
+                    else {
+                        throw new SecurityException();
+                    }
+                }
+                else {
+                    throw new SecurityException();
+                }
+           
+            Intent intent = new Intent(getApplicationContext(), FileUploader.class);
+            intent.putExtra(FileUploader.KEY_UPLOAD_TYPE, FileUploader.UPLOAD_MULTIPLE_FILES);
+            intent.putExtra(FileUploader.KEY_LOCAL_FILE, local.toArray(new String[local.size()]));
+            intent.putExtra(FileUploader.KEY_REMOTE_FILE, remote.toArray(new String[remote.size()]));
+            intent.putExtra(FileUploader.KEY_ACCOUNT, mAccount);
+            startService(intent);
+            finish();
+            }
+            
+        } catch (SecurityException e) {
+            String message = String.format(getString(R.string.uploader_error_forbidden_content), getString(R.string.app_name));
+            Toast.makeText(this, message, Toast.LENGTH_LONG).show();            
+        }
+    }
+
+}
diff --git a/src/com/owncloud/android/ui/adapter/CertificateCombinedExceptionViewAdapter.java b/src/com/owncloud/android/ui/adapter/CertificateCombinedExceptionViewAdapter.java
new file mode 100644 (file)
index 0000000..b1c3263
--- /dev/null
@@ -0,0 +1,74 @@
+/* ownCloud Android client application
+ *   Copyright (C) 2012-2014 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 com.owncloud.android.R;
+import com.owncloud.android.lib.common.network.CertificateCombinedException;
+import com.owncloud.android.ui.dialog.SslUntrustedCertDialog;
+
+import android.view.View;
+import android.widget.TextView;
+
+/**
+ * TODO
+ * 
+ * @author masensio
+ * @author David A. Velasco
+ *
+ */
+public class CertificateCombinedExceptionViewAdapter implements SslUntrustedCertDialog.ErrorViewAdapter {
+    
+    //private final static String TAG = CertificateCombinedExceptionViewAdapter.class.getSimpleName();
+    
+    private CertificateCombinedException mSslException = null;
+    
+    public CertificateCombinedExceptionViewAdapter(CertificateCombinedException sslException) {
+        mSslException = sslException;
+    }
+    
+    @Override
+    public void updateErrorView(View dialogView) {
+        /// clean
+        dialogView.findViewById(R.id.reason_no_info_about_error).setVisibility(View.GONE);
+       
+        /// refresh
+        if (mSslException.getCertPathValidatorException() != null) {
+            ((TextView)dialogView.findViewById(R.id.reason_cert_not_trusted)).setVisibility(View.VISIBLE);
+        } else {
+            dialogView.findViewById(R.id.reason_cert_not_trusted).setVisibility(View.GONE);
+        }
+        
+        if (mSslException.getCertificateExpiredException() != null) {
+            ((TextView)dialogView.findViewById(R.id.reason_cert_expired)).setVisibility(View.VISIBLE);
+        } else {
+            dialogView.findViewById(R.id.reason_cert_expired).setVisibility(View.GONE);
+        }
+        
+        if (mSslException.getCertificateNotYetValidException() != null) {
+            ((TextView)dialogView.findViewById(R.id.reason_cert_not_yet_valid)).setVisibility(View.VISIBLE);
+        } else {
+            dialogView.findViewById(R.id.reason_cert_not_yet_valid).setVisibility(View.GONE);
+        }
+
+        if (mSslException.getSslPeerUnverifiedException() != null) {
+            ((TextView)dialogView.findViewById(R.id.reason_hostname_not_verified)).setVisibility(View.VISIBLE);
+        } else {
+            dialogView.findViewById(R.id.reason_hostname_not_verified).setVisibility(View.GONE);
+        }
+        
+    }
+}
diff --git a/src/com/owncloud/android/ui/adapter/DiskLruImageCache.java b/src/com/owncloud/android/ui/adapter/DiskLruImageCache.java
new file mode 100644 (file)
index 0000000..93efdf1
--- /dev/null
@@ -0,0 +1,194 @@
+/* ownCloud Android client application
+ *   Copyright (C) 2012-2014 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.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.CompressFormat;
+import android.graphics.BitmapFactory;
+
+import com.jakewharton.disklrucache.DiskLruCache;
+import com.owncloud.android.BuildConfig;
+import com.owncloud.android.lib.common.utils.Log_OC;
+
+public class DiskLruImageCache {
+
+    private DiskLruCache mDiskCache;
+    private CompressFormat mCompressFormat;
+    private int mCompressQuality;
+    private static final int CACHE_VERSION = 1;
+    private static final int VALUE_COUNT = 1;
+    private static final int IO_BUFFER_SIZE = 8 * 1024;
+            
+    private static final String TAG = DiskLruImageCache.class.getSimpleName();
+
+    //public DiskLruImageCache( Context context,String uniqueName, int diskCacheSize,
+    public DiskLruImageCache(
+            File diskCacheDir, int diskCacheSize, CompressFormat compressFormat, int quality 
+            ) throws IOException {
+
+        mDiskCache = DiskLruCache.open(
+                diskCacheDir, CACHE_VERSION, VALUE_COUNT, diskCacheSize 
+        );
+        mCompressFormat = compressFormat;
+        mCompressQuality = quality;
+    }
+
+    private boolean writeBitmapToFile( Bitmap bitmap, DiskLruCache.Editor editor )
+        throws IOException, FileNotFoundException {
+        OutputStream out = null;
+        try {
+            out = new BufferedOutputStream( editor.newOutputStream( 0 ), IO_BUFFER_SIZE );
+            return bitmap.compress( mCompressFormat, mCompressQuality, out );
+        } finally {
+            if ( out != null ) {
+                out.close();
+            }
+        }
+    }
+
+    public void put( String key, Bitmap data ) {
+
+        DiskLruCache.Editor editor = null;
+        String validKey = convertToValidKey(key);
+        try {
+            editor = mDiskCache.edit( validKey );
+            if ( editor == null ) {
+                return;
+            }
+
+            if( writeBitmapToFile( data, editor ) ) {               
+                mDiskCache.flush();
+                editor.commit();
+                if ( BuildConfig.DEBUG ) {
+                   Log_OC.d( "cache_test_DISK_", "image put on disk cache " + validKey );
+                }
+            } else {
+                editor.abort();
+                if ( BuildConfig.DEBUG ) {
+                    Log_OC.d( "cache_test_DISK_", "ERROR on: image put on disk cache " + validKey );
+                }
+            }   
+        } catch (IOException e) {
+            if ( BuildConfig.DEBUG ) {
+                Log_OC.d( "cache_test_DISK_", "ERROR on: image put on disk cache " + validKey );
+            }
+            try {
+                if ( editor != null ) {
+                    editor.abort();
+                }
+            } catch (IOException ignored) {
+            }           
+        }
+
+    }
+
+    public Bitmap getBitmap( String key ) {
+
+        Bitmap bitmap = null;
+        DiskLruCache.Snapshot snapshot = null;
+        String validKey = convertToValidKey(key);
+        try {
+
+            snapshot = mDiskCache.get( validKey );
+            if ( snapshot == null ) {
+                return null;
+            }
+            final InputStream in = snapshot.getInputStream( 0 );
+            if ( in != null ) {
+                final BufferedInputStream buffIn = 
+                new BufferedInputStream( in, IO_BUFFER_SIZE );
+                bitmap = BitmapFactory.decodeStream( buffIn );              
+            }   
+        } catch ( IOException e ) {
+            e.printStackTrace();
+        } finally {
+            if ( snapshot != null ) {
+                snapshot.close();
+            }
+        }
+
+        if ( BuildConfig.DEBUG ) {
+            Log_OC.d("cache_test_DISK_", bitmap == null ? 
+                    "not found" : "image read from disk " + validKey);
+        }
+
+        return bitmap;
+
+    }
+
+    public boolean containsKey( String key ) {
+
+        boolean contained = false;
+        DiskLruCache.Snapshot snapshot = null;
+        String validKey = convertToValidKey(key);
+        try {
+            snapshot = mDiskCache.get( validKey );
+            contained = snapshot != null;
+        } catch (IOException e) {
+            e.printStackTrace();
+        } finally {
+            if ( snapshot != null ) {
+                snapshot.close();
+            }
+        }
+
+        return contained;
+
+    }
+
+    public void clearCache() {
+        if ( BuildConfig.DEBUG ) {
+            Log_OC.d( "cache_test_DISK_", "disk cache CLEARED");
+        }
+        try {
+            mDiskCache.delete();
+        } catch ( IOException e ) {
+            e.printStackTrace();
+        }
+    }
+
+    public File getCacheFolder() {
+        return mDiskCache.getDirectory();
+    }
+    
+    private String convertToValidKey(String key) {
+        return Integer.toString(key.hashCode());
+    }
+
+    /**
+     * Remove passed key from cache
+     * @param key
+     */
+    public void removeKey( String key ) {
+        String validKey = convertToValidKey(key);
+        try {
+            mDiskCache.remove(validKey);
+            Log_OC.d(TAG, "removeKey from cache: " + validKey);
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+}
\ No newline at end of file
index a864f7a..9a2a0d3 100644 (file)
@@ -1,6 +1,6 @@
 /* ownCloud Android client application\r
  *   Copyright (C) 2011  Bartek Przybylski\r
- *   Copyright (C) 2012-2013 ownCloud Inc.\r
+ *   Copyright (C) 2012-2014 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
 package com.owncloud.android.ui.adapter;\r
 \r
+
+import java.io.File;\r
+import java.util.Collections;\r
+import java.util.Comparator;\r
+import java.util.Vector;\r
+\r
+import third_parties.daveKoeller.AlphanumComparator;\r
 import android.accounts.Account;\r
 import android.content.Context;\r
+import android.content.SharedPreferences;\r
+import android.graphics.Bitmap;\r
+import android.preference.PreferenceManager;\r
 import android.view.LayoutInflater;\r
 import android.view.View;\r
 import android.view.ViewGroup;\r
@@ -28,40 +38,68 @@ import android.widget.ListAdapter;
 import android.widget.ListView;\r
 import android.widget.TextView;\r
 \r
-\r
-import java.util.Vector;\r
-\r
-import com.owncloud.android.DisplayUtils;\r
 import com.owncloud.android.R;\r
 import com.owncloud.android.authentication.AccountUtils;\r
 import com.owncloud.android.datamodel.FileDataStorageManager;\r
 import com.owncloud.android.datamodel.OCFile;\r
+import com.owncloud.android.datamodel.ThumbnailsCacheManager;\r
+import com.owncloud.android.datamodel.ThumbnailsCacheManager.AsyncDrawable;\r
 import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder;\r
 import com.owncloud.android.files.services.FileUploader.FileUploaderBinder;\r
-import com.owncloud.android.ui.activity.TransferServiceGetter;\r
-\r
+import com.owncloud.android.ui.activity.ComponentsGetter;\r
+import com.owncloud.android.utils.DisplayUtils;\r
+import com.owncloud.android.utils.FileStorageUtils;\r
+
 \r
 /**\r
  * This Adapter populates a ListView with all files and folders in an ownCloud\r
  * instance.\r
  * \r
  * @author Bartek Przybylski\r
- * \r
+ * @author Tobias Kaminsky\r
+ * @author David A. Velasco\r
  */\r
-public class FileListListAdapter extends BaseAdapter implements ListAdapter {\r
+public class FileListListAdapter extends BaseAdapter implements ListAdapter {
+    private final static String PERMISSION_SHARED_WITH_ME = "S";\r
+    \r
     private Context mContext;\r
     private OCFile mFile = null;\r
     private Vector<OCFile> mFiles = null;\r
-    private FileDataStorageManager mStorageManager;\r
-    private Account mAccount;\r
-    private TransferServiceGetter mTransferServiceGetter;\r
+    private boolean mJustFolders;\r
+\r
+    private FileDataStorageManager mStorageManager;
+    private Account mAccount;
+    private ComponentsGetter mTransferServiceGetter;\r
+    private Integer mSortOrder;\r
+    public static final Integer SORT_NAME = 0;\r
+    public static final Integer SORT_DATE = 1;\r
+    public static final Integer SORT_SIZE = 2;\r
+    private Boolean mSortAscending;\r
+    private SharedPreferences mAppPreferences;\r
     \r
-    public FileListListAdapter(Context context, TransferServiceGetter transferServiceGetter) {\r
+    public FileListListAdapter(\r
+            boolean justFolders, \r
+            Context context, \r
+            ComponentsGetter transferServiceGetter\r
+            ) {\r
+        \r
+        mJustFolders = justFolders;\r
         mContext = context;\r
         mAccount = AccountUtils.getCurrentOwnCloudAccount(mContext);\r
-        mTransferServiceGetter = transferServiceGetter;\r
+        mTransferServiceGetter = transferServiceGetter;
+        \r
+        mAppPreferences = PreferenceManager\r
+                .getDefaultSharedPreferences(mContext);\r
+        \r
+        // Read sorting order, default to sort by name ascending\r
+        mSortOrder = mAppPreferences\r
+                .getInt("sortOrder", 0);\r
+        mSortAscending = mAppPreferences.getBoolean("sortAscending", true);
+        \r
+        // initialise thumbnails cache on background thread\r
+        new ThumbnailsCacheManager.InitDiskCacheTask().execute();\r
     }\r
-\r
+    
     @Override\r
     public boolean areAllItemsEnabled() {\r
         return true;\r
@@ -104,17 +142,23 @@ public class FileListListAdapter extends BaseAdapter implements ListAdapter {
                     .getSystemService(Context.LAYOUT_INFLATER_SERVICE);\r
             view = inflator.inflate(R.layout.list_item, null);\r
         }\r
-    \r
+         \r
         if (mFiles != null && mFiles.size() > position) {\r
             OCFile file = mFiles.get(position);\r
-            TextView fileName = (TextView) view.findViewById(R.id.Filename);\r
+            TextView fileName = (TextView) view.findViewById(R.id.Filename);           \r
             String name = file.getFileName();\r
 \r
             fileName.setText(name);\r
             ImageView fileIcon = (ImageView) view.findViewById(R.id.imageView1);\r
-            fileIcon.setImageResource(DisplayUtils.getResourceId(file.getMimetype()));\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
-            FileDownloaderBinder downloaderBinder = mTransferServiceGetter.getFileDownloaderBinder();\r
+            localStateView.bringToFront();\r
+            FileDownloaderBinder downloaderBinder = \r
+                    mTransferServiceGetter.getFileDownloaderBinder();\r
             FileUploaderBinder uploaderBinder = mTransferServiceGetter.getFileUploaderBinder();\r
             if (downloaderBinder != null && downloaderBinder.isDownloading(mAccount, file)) {\r
                 localStateView.setImageResource(R.drawable.downloading_file_indicator);\r
@@ -137,7 +181,9 @@ public class FileListListAdapter extends BaseAdapter implements ListAdapter {
                 fileSizeV.setVisibility(View.VISIBLE);\r
                 fileSizeV.setText(DisplayUtils.bytesToHumanReadable(file.getFileLength()));\r
                 lastModV.setVisibility(View.VISIBLE);\r
-                lastModV.setText(DisplayUtils.unixTimeToHumanReadable(file.getModificationTimestamp()));\r
+                lastModV.setText(\r
+                        DisplayUtils.unixTimeToHumanReadable(file.getModificationTimestamp())\r
+                );\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
@@ -156,23 +202,127 @@ public class FileListListAdapter extends BaseAdapter implements ListAdapter {
                         checkBoxV.setImageResource(android.R.drawable.checkbox_off_background);\r
                     }\r
                     checkBoxV.setVisibility(View.VISIBLE);\r
-                }\r
+                }               \r
                 \r
+                // get Thumbnail if file is image\r
+                if (file.isImage() && file.getRemoteId() != null){\r
+                     // Thumbnail in Cache?\r
+                    Bitmap thumbnail = ThumbnailsCacheManager.getBitmapFromDiskCache(\r
+                            String.valueOf(file.getRemoteId())\r
+                    );\r
+                    if (thumbnail != null && !file.needsUpdateThumbnail()){\r
+                        fileIcon.setImageBitmap(thumbnail);\r
+                    } else {\r
+                        // generate new Thumbnail\r
+                        if (ThumbnailsCacheManager.cancelPotentialWork(file, fileIcon)) {\r
+                            final ThumbnailsCacheManager.ThumbnailGenerationTask task = \r
+                                    new ThumbnailsCacheManager.ThumbnailGenerationTask(\r
+                                            fileIcon, mStorageManager\r
+                                    );\r
+                            if (thumbnail == null) {\r
+                                thumbnail = ThumbnailsCacheManager.mDefaultImg;\r
+                            }\r
+                            final AsyncDrawable asyncDrawable = new AsyncDrawable(\r
+                                    mContext.getResources(), \r
+                                    thumbnail, \r
+                                    task\r
+                            );\r
+                            fileIcon.setImageDrawable(asyncDrawable);\r
+                            task.execute(file);\r
+                        }\r
+                    }\r
+                } else {\r
+                    fileIcon.setImageResource(\r
+                            DisplayUtils.getResourceId(file.getMimetype(), file.getFileName())\r
+                    );\r
+                }\r
+
+                if (checkIfFileIsSharedWithMe(file)) {\r
+                    sharedWithMeIconV.setVisibility(View.VISIBLE);\r
+                }\r
             } \r
             else {\r
-                \r
-                fileSizeV.setVisibility(View.VISIBLE);\r
-                fileSizeV.setText(DisplayUtils.bytesToHumanReadable(file.getFileLength()));\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
+
                 lastModV.setVisibility(View.VISIBLE);\r
-                lastModV.setText(DisplayUtils.unixTimeToHumanReadable(file.getModificationTimestamp()));\r
-               checkBoxV.setVisibility(View.GONE);\r
-               view.findViewById(R.id.imageView3).setVisibility(View.GONE);\r
+                lastModV.setText(\r
+                        DisplayUtils.unixTimeToHumanReadable(file.getModificationTimestamp())\r
+                );\r
+                checkBoxV.setVisibility(View.GONE);\r
+                view.findViewById(R.id.imageView3).setVisibility(View.GONE);\r
+\r
+                if (checkIfFileIsSharedWithMe(file)) {\r
+                    fileIcon.setImageResource(R.drawable.shared_with_me_folder);\r
+                    sharedWithMeIconV.setVisibility(View.VISIBLE);\r
+                } else {\r
+                    fileIcon.setImageResource(\r
+                            DisplayUtils.getResourceId(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
         return view;\r
     }\r
+
+    /**\r
+     * Local Folder size in human readable format\r
+     * \r
+     * @param path\r
+     *            String\r
+     * @return Size in human readable format\r
+     */\r
+    private String getFolderSizeHuman(String path) {\r
+\r
+        File dir = new File(path);\r
 \r
+        if (dir.exists()) {\r
+            long bytes = getFolderSize(dir);\r
+            return DisplayUtils.bytesToHumanReadable(bytes);\r
+        }\r
+\r
+        return "0 B";\r
+    }\r
+\r
+    /**\r
+     * Local Folder size\r
+     * @param dir File\r
+     * @return Size in bytes\r
+     */\r
+    private long getFolderSize(File dir) {\r
+        if (dir.exists()) {\r
+            long result = 0;\r
+            File[] fileList = dir.listFiles();\r
+            for(int i = 0; i < fileList.length; i++) {\r
+                if(fileList[i].isDirectory()) {\r
+                    result += getFolderSize(fileList[i]);\r
+                } else {\r
+                    result += fileList[i].length();\r
+                }\r
+            }\r
+            return result;\r
+        }\r
+        return 0;\r
+    } 
+
     @Override\r
     public int getViewTypeCount() {\r
         return 1;\r
@@ -190,8 +340,10 @@ public class FileListListAdapter extends BaseAdapter implements ListAdapter {
 \r
     /**\r
      * Change the adapted directory for a new one\r
-     * @param directory                 New file to adapt. Can be NULL, meaning "no content to adapt".\r
-     * @param updatedStorageManager     Optional updated storage manager; used to replace mStorageManager if is different (and not NULL)\r
+     * @param directory                 New file to adapt. Can be NULL, meaning \r
+     *                                  "no content to adapt".\r
+     * @param updatedStorageManager     Optional updated storage manager; used to replace \r
+     *                                  mStorageManager if is different (and not NULL)\r
      */\r
     public void swapDirectory(OCFile directory, FileDataStorageManager updatedStorageManager) {\r
         mFile = directory;\r
@@ -201,10 +353,167 @@ public class FileListListAdapter extends BaseAdapter implements ListAdapter {
         }\r
         if (mStorageManager != null) {\r
             mFiles = mStorageManager.getFolderContent(mFile);\r
+            if (mJustFolders) {\r
+                mFiles = getFolders(mFiles);\r
+            }\r
         } else {\r
             mFiles = null;\r
         }\r
+\r
+        sortDirectory();\r
+    }\r
+    \r
+    /**\r
+     * Sorts all filenames, regarding last user decision \r
+     */\r
+    private void sortDirectory(){\r
+        switch (mSortOrder){\r
+        case 0:\r
+            sortByName(mSortAscending);\r
+            break;\r
+        case 1:\r
+            sortByDate(mSortAscending);\r
+            break;\r
+        case 2: \r
+            sortBySize(mSortAscending);\r
+            break;\r
+        }\r
+        \r
         notifyDataSetChanged();\r
     }\r
     \r
+    \r
+    /**\r
+     * Filter for getting only the folders\r
+     * @param files\r
+     * @return Vector<OCFile>\r
+     */\r
+    public Vector<OCFile> getFolders(Vector<OCFile> files) {\r
+        Vector<OCFile> ret = new Vector<OCFile>(); \r
+        OCFile current = null; \r
+        for (int i=0; i<files.size(); i++) {\r
+            current = files.get(i);\r
+            if (current.isFolder()) {\r
+                ret.add(current);\r
+            }\r
+        }\r
+        return ret;\r
+    }\r
+    \r
+    \r
+    /**\r
+     * Check if parent folder does not include 'S' permission and if file/folder\r
+     * is shared with me\r
+     * \r
+     * @param file: OCFile\r
+     * @return boolean: True if it is shared with me and false if it is not\r
+     */\r
+    private boolean checkIfFileIsSharedWithMe(OCFile file) {\r
+        return (mFile.getPermissions() != null \r
+                && !mFile.getPermissions().contains(PERMISSION_SHARED_WITH_ME)\r
+                && file.getPermissions() != null \r
+                && file.getPermissions().contains(PERMISSION_SHARED_WITH_ME));\r
+    }\r
+\r
+    /**\r
+     * Sorts list by Date\r
+     * @param sortAscending true: ascending, false: descending\r
+     */\r
+    private void sortByDate(boolean sortAscending){\r
+        final Integer val;\r
+        if (sortAscending){\r
+            val = 1;\r
+        } else {\r
+            val = -1;\r
+        }\r
+        \r
+        Collections.sort(mFiles, new Comparator<OCFile>() {\r
+            public int compare(OCFile o1, OCFile o2) {\r
+                if (o1.isFolder() && o2.isFolder()) {\r
+                    Long obj1 = o1.getModificationTimestamp();\r
+                    return val * obj1.compareTo(o2.getModificationTimestamp());\r
+                }\r
+                else if (o1.isFolder()) {\r
+                    return -1;\r
+                } else if (o2.isFolder()) {\r
+                    return 1;\r
+                } else if (o1.getModificationTimestamp() == 0 || o2.getModificationTimestamp() == 0){\r
+                    return 0;\r
+                } else {\r
+                    Long obj1 = o1.getModificationTimestamp();\r
+                    return val * obj1.compareTo(o2.getModificationTimestamp());\r
+                }\r
+            }\r
+        });\r
+    }\r
+\r
+    /**\r
+     * Sorts list by Size\r
+     * @param sortAscending true: ascending, false: descending\r
+     */\r
+    private void sortBySize(boolean sortAscending){\r
+        final Integer val;\r
+        if (sortAscending){\r
+            val = 1;\r
+        } else {\r
+            val = -1;\r
+        }\r
+        \r
+        Collections.sort(mFiles, new Comparator<OCFile>() {\r
+            public int compare(OCFile o1, OCFile o2) {\r
+                if (o1.isFolder() && o2.isFolder()) {\r
+                    Long obj1 = getFolderSize(new File(FileStorageUtils.getDefaultSavePathFor(mAccount.name, o1)));\r
+                    return val * obj1.compareTo(getFolderSize(new File(FileStorageUtils.getDefaultSavePathFor(mAccount.name, o2))));\r
+                }\r
+                else if (o1.isFolder()) {\r
+                    return -1;\r
+                } else if (o2.isFolder()) {\r
+                    return 1;\r
+                } else if (o1.getFileLength() == 0 || o2.getFileLength() == 0){\r
+                    return 0;\r
+                } else {\r
+                    Long obj1 = o1.getFileLength();\r
+                    return val * obj1.compareTo(o2.getFileLength());\r
+                }\r
+            }\r
+        });\r
+    }\r
+\r
+    /**\r
+     * Sorts list by Name\r
+     * @param sortAscending true: ascending, false: descending\r
+     */\r
+    private void sortByName(boolean sortAscending){\r
+        final Integer val;\r
+        if (sortAscending){\r
+            val = 1;\r
+        } else {\r
+            val = -1;\r
+        }\r
+\r
+        Collections.sort(mFiles, new Comparator<OCFile>() {\r
+            public int compare(OCFile o1, OCFile o2) {\r
+                if (o1.isFolder() && o2.isFolder()) {\r
+                    return val * o1.getRemotePath().toLowerCase().compareTo(o2.getRemotePath().toLowerCase());\r
+                } else if (o1.isFolder()) {\r
+                    return -1;\r
+                } else if (o2.isFolder()) {\r
+                    return 1;\r
+                }\r
+                return val * new AlphanumComparator().compare(o1, o2);\r
+            }\r
+        });\r
+    }\r
+\r
+    public void setSortOrder(Integer order, boolean ascending) {\r
+        SharedPreferences.Editor editor = mAppPreferences.edit();\r
+        editor.putInt("sortOrder", order);\r
+        editor.putBoolean("sortAscending", ascending);\r
+        editor.commit();\r
+        \r
+        mSortOrder = order;\r
+        mSortAscending = ascending;\r
+        \r
+        sortDirectory();\r
+    }    
 }\r
index ff883c5..6190ebe 100644 (file)
@@ -1,6 +1,6 @@
 /* ownCloud Android client application
  *   Copyright (C) 2011  Bartek Przybylski
- *   Copyright (C) 2012-2013 ownCloud Inc.
+ *   Copyright (C) 2012-2014 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,10 +21,6 @@ import java.io.File;
 import java.util.Arrays;
 import java.util.Comparator;
 
-import com.owncloud.android.DisplayUtils;
-import com.owncloud.android.R;
-
-
 import android.content.Context;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -35,6 +31,9 @@ import android.widget.ListAdapter;
 import android.widget.ListView;
 import android.widget.TextView;
 
+import com.owncloud.android.R;
+import com.owncloud.android.utils.DisplayUtils;
+
 /**
  * This Adapter populates a ListView with all files and directories contained
  * in a local directory
@@ -135,6 +134,9 @@ public class LocalFileListAdapter extends BaseAdapter implements ListAdapter {
             
             view.findViewById(R.id.imageView2).setVisibility(View.INVISIBLE);   // not GONE; the alignment changes; ugly way to keep it
             view.findViewById(R.id.imageView3).setVisibility(View.GONE);
+            
+            view.findViewById(R.id.sharedIcon).setVisibility(View.GONE);
+            view.findViewById(R.id.sharedWithMeIcon).setVisibility(View.GONE);
         }
 
         return view;
diff --git a/src/com/owncloud/android/ui/adapter/SslCertificateViewAdapter.java b/src/com/owncloud/android/ui/adapter/SslCertificateViewAdapter.java
new file mode 100644 (file)
index 0000000..a944ead
--- /dev/null
@@ -0,0 +1,126 @@
+/* ownCloud Android client application
+ *   Copyright (C) 2012-2014 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.text.DateFormat;
+import java.util.Date;
+
+import com.owncloud.android.R;
+import com.owncloud.android.ui.dialog.SslUntrustedCertDialog;
+import android.net.http.SslCertificate;
+import android.view.View;
+import android.widget.TextView;
+
+/**
+ * TODO
+ * 
+ * @author masensio
+ * @author David A. Velasco
+ */
+public class SslCertificateViewAdapter implements SslUntrustedCertDialog.CertificateViewAdapter {
+    
+    //private final static String TAG = SslCertificateViewAdapter.class.getSimpleName();
+    
+    private SslCertificate mCertificate;
+
+    
+    /**
+     * Constructor
+     * 
+     * @param 
+     */
+    public SslCertificateViewAdapter(SslCertificate certificate) {
+        mCertificate = certificate;
+    }
+
+    @Override
+    public void updateCertificateView(View dialogView) {
+        TextView nullCerView = (TextView) dialogView.findViewById(R.id.null_cert);
+        if (mCertificate != null) {
+            nullCerView.setVisibility(View.GONE);
+            showSubject(mCertificate.getIssuedTo(), dialogView);
+            showIssuer(mCertificate.getIssuedBy(), dialogView);
+            showValidity(mCertificate.getValidNotBeforeDate(), mCertificate.getValidNotAfterDate(), dialogView);
+            hideSignature(dialogView);
+            
+        } else {
+            nullCerView.setVisibility(View.VISIBLE);
+        }
+    }
+    
+    private void showValidity(Date notBefore, Date notAfter, View dialogView) {
+        TextView fromView = ((TextView)dialogView.findViewById(R.id.value_validity_from));
+        TextView toView = ((TextView)dialogView.findViewById(R.id.value_validity_to));
+        DateFormat dateFormat = DateFormat.getDateInstance();
+        fromView.setText(dateFormat.format(notBefore));
+        toView.setText(dateFormat.format(notAfter));
+    }
+
+    
+    private void showSubject(SslCertificate.DName subject, View dialogView) {
+        TextView cnView = ((TextView)dialogView.findViewById(R.id.value_subject_CN));
+        cnView.setText(subject.getCName());
+        cnView.setVisibility(View.VISIBLE);
+        
+        TextView oView = ((TextView)dialogView.findViewById(R.id.value_subject_O));
+        oView.setText(subject.getOName());
+        oView.setVisibility(View.VISIBLE);
+        
+        TextView ouView = ((TextView)dialogView.findViewById(R.id.value_subject_OU));
+        ouView.setText(subject.getUName());
+        ouView.setVisibility(View.VISIBLE);
+
+        // SslCertificates don't offer this information
+        ((TextView)dialogView.findViewById(R.id.value_subject_C)).setVisibility(View.GONE);
+        ((TextView)dialogView.findViewById(R.id.value_subject_ST)).setVisibility(View.GONE);
+        ((TextView)dialogView.findViewById(R.id.value_subject_L)).setVisibility(View.GONE);
+        ((TextView)dialogView.findViewById(R.id.label_subject_C)).setVisibility(View.GONE);
+        ((TextView)dialogView.findViewById(R.id.label_subject_ST)).setVisibility(View.GONE);
+        ((TextView)dialogView.findViewById(R.id.label_subject_L)).setVisibility(View.GONE);
+    }
+    
+    
+    private void showIssuer(SslCertificate.DName issuer, View dialogView) {
+        TextView cnView = ((TextView)dialogView.findViewById(R.id.value_issuer_CN));
+        cnView.setText(issuer.getCName());
+        cnView.setVisibility(View.VISIBLE);
+        
+        TextView oView = ((TextView)dialogView.findViewById(R.id.value_issuer_O));
+        oView.setText(issuer.getOName());
+        oView.setVisibility(View.VISIBLE);
+
+        TextView ouView = ((TextView)dialogView.findViewById(R.id.value_issuer_OU));
+        ouView.setText(issuer.getUName());
+        ouView.setVisibility(View.VISIBLE);
+        
+        // SslCertificates don't offer this information
+        ((TextView)dialogView.findViewById(R.id.value_issuer_C)).setVisibility(View.GONE);
+        ((TextView)dialogView.findViewById(R.id.value_issuer_ST)).setVisibility(View.GONE);
+        ((TextView)dialogView.findViewById(R.id.value_issuer_L)).setVisibility(View.GONE);
+        ((TextView)dialogView.findViewById(R.id.label_issuer_C)).setVisibility(View.GONE);
+        ((TextView)dialogView.findViewById(R.id.label_issuer_ST)).setVisibility(View.GONE);
+        ((TextView)dialogView.findViewById(R.id.label_issuer_L)).setVisibility(View.GONE);
+    }
+    
+    private void hideSignature(View dialogView) {
+        ((TextView)dialogView.findViewById(R.id.label_signature)).setVisibility(View.GONE);
+        ((TextView)dialogView.findViewById(R.id.label_signature_algorithm)).setVisibility(View.GONE);
+        ((TextView)dialogView.findViewById(R.id.value_signature_algorithm)).setVisibility(View.GONE);
+        ((TextView)dialogView.findViewById(R.id.value_signature)).setVisibility(View.GONE);
+    }
+
+}
diff --git a/src/com/owncloud/android/ui/adapter/SslErrorViewAdapter.java b/src/com/owncloud/android/ui/adapter/SslErrorViewAdapter.java
new file mode 100644 (file)
index 0000000..7d2e291
--- /dev/null
@@ -0,0 +1,73 @@
+/* ownCloud Android client application
+ *   Copyright (C) 2012-2014 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 com.owncloud.android.R;
+import com.owncloud.android.ui.dialog.SslUntrustedCertDialog;
+import android.net.http.SslError;
+import android.view.View;
+import android.widget.TextView;
+
+/**
+ * Dialog to show an Untrusted Certificate
+ * 
+ * @author masensio
+ * @author David A. Velasco
+ *
+ */
+public class SslErrorViewAdapter implements SslUntrustedCertDialog.ErrorViewAdapter {
+    
+    //private final static String TAG = SslErrorViewAdapter.class.getSimpleName();
+    
+    private SslError mSslError;
+    
+    public SslErrorViewAdapter(SslError sslError) {
+        mSslError = sslError;
+    }
+    
+    @Override
+    public void updateErrorView(View dialogView) {
+        /// clean
+        dialogView.findViewById(R.id.reason_no_info_about_error).setVisibility(View.GONE);
+        
+        /// refresh
+        if (mSslError.hasError(SslError.SSL_UNTRUSTED)) {
+            ((TextView)dialogView.findViewById(R.id.reason_cert_not_trusted)).setVisibility(View.VISIBLE);
+        } else {
+            dialogView.findViewById(R.id.reason_cert_not_trusted).setVisibility(View.GONE);
+        }
+        
+        if (mSslError.hasError(SslError.SSL_EXPIRED)) {
+            ((TextView)dialogView.findViewById(R.id.reason_cert_expired)).setVisibility(View.VISIBLE);
+        } else {
+            dialogView.findViewById(R.id.reason_cert_expired).setVisibility(View.GONE);
+        }
+        
+        if (mSslError.getPrimaryError() == SslError.SSL_NOTYETVALID) {
+            ((TextView)dialogView.findViewById(R.id.reason_cert_not_yet_valid)).setVisibility(View.VISIBLE);
+        } else {
+            dialogView.findViewById(R.id.reason_cert_not_yet_valid).setVisibility(View.GONE);
+        }
+        
+        if (mSslError.getPrimaryError() == SslError.SSL_IDMISMATCH) {
+            ((TextView)dialogView.findViewById(R.id.reason_hostname_not_verified)).setVisibility(View.VISIBLE);
+        } else {
+            dialogView.findViewById(R.id.reason_hostname_not_verified).setVisibility(View.GONE);
+        }
+    }
+
+}
diff --git a/src/com/owncloud/android/ui/adapter/X509CertificateViewAdapter.java b/src/com/owncloud/android/ui/adapter/X509CertificateViewAdapter.java
new file mode 100644 (file)
index 0000000..a290dca
--- /dev/null
@@ -0,0 +1,204 @@
+/* ownCloud Android client application
+ *   Copyright (C) 2012-2014 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.security.cert.X509Certificate;
+import java.text.DateFormat;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.security.auth.x500.X500Principal;
+
+import com.owncloud.android.R;
+import com.owncloud.android.ui.dialog.SslUntrustedCertDialog;
+
+import android.view.View;
+import android.widget.TextView;
+
+/**
+ * 
+ * @author masensio
+ * @author David A. Velasco
+ *
+ */
+public class X509CertificateViewAdapter implements SslUntrustedCertDialog.CertificateViewAdapter {
+    
+    //private final static String TAG = X509CertificateViewAdapter.class.getSimpleName();
+    
+    private X509Certificate mCertificate = null;
+    
+    public X509CertificateViewAdapter(X509Certificate certificate) {
+        mCertificate = certificate;
+    }
+    
+    @Override
+    public void updateCertificateView(View dialogView) {
+        TextView nullCerView = (TextView) dialogView.findViewById(R.id.null_cert);
+        
+        if (mCertificate != null) {
+            nullCerView.setVisibility(View.GONE);
+            showSubject(mCertificate.getSubjectX500Principal(), dialogView);
+            showIssuer(mCertificate.getIssuerX500Principal(), dialogView);
+            showValidity(mCertificate.getNotBefore(), mCertificate.getNotAfter(), dialogView);
+            showSignature(dialogView);
+            
+        } else {
+            nullCerView.setVisibility(View.VISIBLE);
+        }
+    }
+
+    private void showSignature(View dialogView) {
+        TextView sigView = ((TextView)dialogView.findViewById(R.id.value_signature));
+        TextView algorithmView = ((TextView)dialogView.findViewById(R.id.value_signature_algorithm));
+        sigView.setText(getHex(mCertificate.getSignature()));
+        algorithmView.setText(mCertificate.getSigAlgName());
+    }
+    
+    public String getHex(final byte [] raw) {
+        if (raw == null) {
+           return null;
+        }
+        final StringBuilder hex = new StringBuilder(2 * raw.length);
+        for (final byte b : raw) {
+           final int hiVal = (b & 0xF0) >> 4;
+           final int loVal = b & 0x0F;
+           hex.append((char) ('0' + (hiVal + (hiVal / 10 * 7))));
+           hex.append((char) ('0' + (loVal + (loVal / 10 * 7))));
+        }
+        return hex.toString();
+     }    
+
+    private void showValidity(Date notBefore, Date notAfter, View dialogView) {
+        TextView fromView = ((TextView)dialogView.findViewById(R.id.value_validity_from));
+        TextView toView = ((TextView)dialogView.findViewById(R.id.value_validity_to));
+        DateFormat dateFormat = DateFormat.getDateInstance();
+        fromView.setText(dateFormat.format(notBefore));
+        toView.setText(dateFormat.format(notAfter));
+    }
+
+    private void showSubject(X500Principal subject, View dialogView) {
+        Map<String, String> s = parsePrincipal(subject);
+        TextView cnView = ((TextView)dialogView.findViewById(R.id.value_subject_CN));
+        TextView oView = ((TextView)dialogView.findViewById(R.id.value_subject_O));
+        TextView ouView = ((TextView)dialogView.findViewById(R.id.value_subject_OU));
+        TextView cView = ((TextView)dialogView.findViewById(R.id.value_subject_C));
+        TextView stView = ((TextView)dialogView.findViewById(R.id.value_subject_ST));
+        TextView lView = ((TextView)dialogView.findViewById(R.id.value_subject_L));
+        
+        if (s.get("CN") != null) {
+            cnView.setText(s.get("CN"));
+            cnView.setVisibility(View.VISIBLE);
+        } else {
+            cnView.setVisibility(View.GONE);
+        }
+        if (s.get("O") != null) {
+            oView.setText(s.get("O"));
+            oView.setVisibility(View.VISIBLE);
+        } else {
+            oView.setVisibility(View.GONE);
+        }
+        if (s.get("OU") != null) {
+            ouView.setText(s.get("OU"));
+            ouView.setVisibility(View.VISIBLE);
+        } else {
+            ouView.setVisibility(View.GONE);
+        }
+        if (s.get("C") != null) {
+            cView.setText(s.get("C"));
+            cView.setVisibility(View.VISIBLE);
+        } else {
+            cView.setVisibility(View.GONE);
+        }
+        if (s.get("ST") != null) {
+            stView.setText(s.get("ST"));
+            stView.setVisibility(View.VISIBLE);
+        } else {
+            stView.setVisibility(View.GONE);
+        }
+        if (s.get("L") != null) {
+            lView.setText(s.get("L"));
+            lView.setVisibility(View.VISIBLE);
+        } else {
+            lView.setVisibility(View.GONE);
+        }
+    }
+    
+    private void showIssuer(X500Principal issuer, View dialogView) {
+        Map<String, String> s = parsePrincipal(issuer);
+        TextView cnView = ((TextView)dialogView.findViewById(R.id.value_issuer_CN));
+        TextView oView = ((TextView)dialogView.findViewById(R.id.value_issuer_O));
+        TextView ouView = ((TextView)dialogView.findViewById(R.id.value_issuer_OU));
+        TextView cView = ((TextView)dialogView.findViewById(R.id.value_issuer_C));
+        TextView stView = ((TextView)dialogView.findViewById(R.id.value_issuer_ST));
+        TextView lView = ((TextView)dialogView.findViewById(R.id.value_issuer_L));
+        
+        if (s.get("CN") != null) {
+            cnView.setText(s.get("CN"));
+            cnView.setVisibility(View.VISIBLE);
+        } else {
+            cnView.setVisibility(View.GONE);
+        }
+        if (s.get("O") != null) {
+            oView.setText(s.get("O"));
+            oView.setVisibility(View.VISIBLE);
+        } else {
+            oView.setVisibility(View.GONE);
+        }
+        if (s.get("OU") != null) {
+            ouView.setText(s.get("OU"));
+            ouView.setVisibility(View.VISIBLE);
+        } else {
+            ouView.setVisibility(View.GONE);
+        }
+        if (s.get("C") != null) {
+            cView.setText(s.get("C"));
+            cView.setVisibility(View.VISIBLE);
+        } else {
+            cView.setVisibility(View.GONE);
+        }
+        if (s.get("ST") != null) {
+            stView.setText(s.get("ST"));
+            stView.setVisibility(View.VISIBLE);
+        } else {
+            stView.setVisibility(View.GONE);
+        }
+        if (s.get("L") != null) {
+            lView.setText(s.get("L"));
+            lView.setVisibility(View.VISIBLE);
+        } else {
+            lView.setVisibility(View.GONE);
+        }
+    }
+    
+
+    private Map<String, String> parsePrincipal(X500Principal principal) {
+        Map<String, String> result = new HashMap<String, String>();
+        String toParse = principal.getName();
+        String[] pieces = toParse.split(",");
+        String[] tokens = {"CN", "O", "OU", "C", "ST", "L"}; 
+        for (int i=0; i < pieces.length ; i++) {
+            for (int j=0; j<tokens.length; j++) {
+                if (pieces[i].startsWith(tokens[j] + "=")) {
+                    result.put(tokens[j], pieces[i].substring(tokens[j].length()+1));
+                }
+            }
+        }
+        return result;
+    }
+
+}
index 676bea5..eef9d09 100644 (file)
@@ -25,6 +25,7 @@ import android.webkit.WebView;
 
 import com.actionbarsherlock.app.SherlockDialogFragment;
 import com.owncloud.android.R;
+import com.owncloud.android.utils.DisplayUtils;
 
 
 /**
@@ -63,7 +64,7 @@ public class ChangelogDialog extends SherlockDialogFragment {
         AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
         
         Dialog dialog = builder.setView(webview)
-                                .setIcon(R.drawable.icon)
+                                .setIcon(DisplayUtils.getSeasonalIconId())
                                 //.setTitle(R.string.whats_new)
                                 .setPositiveButton(R.string.common_ok,
                                         new DialogInterface.OnClickListener() {
diff --git a/src/com/owncloud/android/ui/dialog/ConfirmationDialogFragment.java b/src/com/owncloud/android/ui/dialog/ConfirmationDialogFragment.java
new file mode 100644 (file)
index 0000000..a9307b9
--- /dev/null
@@ -0,0 +1,126 @@
+/* ownCloud Android client application
+ *   Copyright (C) 2012 Bartek Przybylski
+ *   Copyright (C) 2012-2013 ownCloud Inc.
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License version 2,
+ *   as published by the Free Software Foundation.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.ui.dialog;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.DialogInterface;
+import android.os.Bundle;
+
+import com.actionbarsherlock.app.SherlockDialogFragment;
+import com.owncloud.android.lib.common.utils.Log_OC;
+
+
+public class ConfirmationDialogFragment extends SherlockDialogFragment {
+
+    public final static String ARG_CONF_RESOURCE_ID = "resource_id";
+    public final static String ARG_CONF_ARGUMENTS = "string_array";
+    
+    public final static String ARG_POSITIVE_BTN_RES = "positive_btn_res";
+    public final static String ARG_NEUTRAL_BTN_RES = "neutral_btn_res";
+    public final static String ARG_NEGATIVE_BTN_RES = "negative_btn_res";
+    
+    public static final String FTAG_CONFIRMATION = "CONFIRMATION_FRAGMENT";
+
+    private ConfirmationDialogFragmentListener mListener;
+    
+    /**
+     * Public factory method to create new ConfirmationDialogFragment instances.
+     * 
+     * @param string_id         Resource id for a message to show in the dialog.
+     * @param arguments         Arguments to complete the message, if it's a format string.
+     * @param posBtn            Resource id for the text of the positive button.
+     * @param neuBtn            Resource id for the text of the neutral button.
+     * @param negBtn            Resource id for the text of the negative button.
+     * @return                  Dialog ready to show.
+     */
+    public static ConfirmationDialogFragment newInstance(int string_id, String[] arguments, int posBtn, int neuBtn, int negBtn) {
+        ConfirmationDialogFragment frag = new ConfirmationDialogFragment();
+        Bundle args = new Bundle();
+        args.putInt(ARG_CONF_RESOURCE_ID, string_id);
+        args.putStringArray(ARG_CONF_ARGUMENTS, arguments);
+        args.putInt(ARG_POSITIVE_BTN_RES, posBtn);
+        args.putInt(ARG_NEUTRAL_BTN_RES, neuBtn);
+        args.putInt(ARG_NEGATIVE_BTN_RES, negBtn);
+        frag.setArguments(args);
+        return frag;
+    }
+    
+    public void setOnConfirmationListener(ConfirmationDialogFragmentListener listener) {
+        mListener = listener;
+    }
+
+    @Override
+    public Dialog onCreateDialog(Bundle savedInstanceState) {
+        Object[] confirmationTarget = getArguments().getStringArray(ARG_CONF_ARGUMENTS);
+        int resourceId = getArguments().getInt(ARG_CONF_RESOURCE_ID, -1);
+        int posBtn = getArguments().getInt(ARG_POSITIVE_BTN_RES, -1);
+        int neuBtn = getArguments().getInt(ARG_NEUTRAL_BTN_RES, -1);
+        int negBtn = getArguments().getInt(ARG_NEGATIVE_BTN_RES, -1);
+        
+        if (confirmationTarget == null || resourceId == -1) {
+            Log_OC.wtf(getTag(), "Calling confirmation dialog without resource or arguments");
+            return null;
+        }
+
+        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity())
+            .setIcon(android.R.drawable.ic_dialog_alert)
+            .setMessage(String.format(getString(resourceId), confirmationTarget))
+            .setTitle(android.R.string.dialog_alert_title);
+        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) {
+            builder.setIconAttribute(android.R.attr.alertDialogIcon);
+        }
+        
+        if (posBtn != -1)
+            builder.setPositiveButton(posBtn,
+                    new DialogInterface.OnClickListener() {
+                        public void onClick(DialogInterface dialog, int whichButton) {
+                            mListener.onConfirmation(getTag()); 
+                            dialog.dismiss();
+                        }
+                    });
+        if (neuBtn != -1)
+            builder.setNeutralButton(neuBtn,
+                    new DialogInterface.OnClickListener() {
+                        public void onClick(DialogInterface dialog, int whichButton) {
+                            mListener.onNeutral(getTag()); 
+                            dialog.dismiss();
+                        }
+                    });
+        if (negBtn != -1)
+            builder.setNegativeButton(negBtn,
+                    new DialogInterface.OnClickListener() {
+                        @Override
+                        public void onClick(DialogInterface dialog, int which) {
+                            mListener.onCancel(getTag());
+                            dialog.dismiss();
+                        }
+                    });
+      return builder.create();
+    }
+    
+    
+    public interface ConfirmationDialogFragmentListener {
+        public void onConfirmation(String callerTag);
+        public void onNeutral(String callerTag);
+        public void onCancel(String callerTag);
+    }
+    
+}
+
index 1998fcb..91cfbfd 100644 (file)
@@ -28,6 +28,7 @@ import android.support.v4.app.FragmentTransaction;
 import com.actionbarsherlock.app.SherlockDialogFragment;
 import com.actionbarsherlock.app.SherlockFragmentActivity;
 import com.owncloud.android.R;
+import com.owncloud.android.utils.DisplayUtils;
 
 
 /**
@@ -59,7 +60,7 @@ public class ConflictsResolveDialog extends SherlockDialogFragment {
     public Dialog onCreateDialog(Bundle savedInstanceState) {
         String remotepath = getArguments().getString("remotepath");
         return new AlertDialog.Builder(getSherlockActivity())
-                   .setIcon(R.drawable.icon)
+                   .setIcon(DisplayUtils.getSeasonalIconId())
                    .setTitle(R.string.conflict_title)
                    .setMessage(String.format(getString(R.string.conflict_message), remotepath))
                    .setPositiveButton(R.string.conflict_overwrite,
@@ -68,7 +69,7 @@ public class ConflictsResolveDialog extends SherlockDialogFragment {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                if (mListener != null)
-                                   mListener.ConflictDecisionMade(Decision.OVERWRITE);
+                                   mListener.conflictDecisionMade(Decision.OVERWRITE);
                            }
                        })
                    .setNeutralButton(R.string.conflict_keep_both,
@@ -76,7 +77,7 @@ public class ConflictsResolveDialog extends SherlockDialogFragment {
                             @Override
                             public void onClick(DialogInterface dialog, int which) {
                                 if (mListener != null)
-                                    mListener.ConflictDecisionMade(Decision.KEEP_BOTH);
+                                    mListener.conflictDecisionMade(Decision.KEEP_BOTH);
                             }
                         })
                    .setNegativeButton(R.string.conflict_dont_upload,
@@ -84,7 +85,7 @@ public class ConflictsResolveDialog extends SherlockDialogFragment {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                if (mListener != null)
-                                   mListener.ConflictDecisionMade(Decision.CANCEL);
+                                   mListener.conflictDecisionMade(Decision.CANCEL);
                            }
                    })
                    .create();
@@ -112,10 +113,10 @@ public class ConflictsResolveDialog extends SherlockDialogFragment {
     
     @Override
     public void onCancel(DialogInterface dialog) {
-        mListener.ConflictDecisionMade(Decision.CANCEL);
+        mListener.conflictDecisionMade(Decision.CANCEL);
     }
     
     public interface OnConflictDecisionMadeListener {
-        public void ConflictDecisionMade(Decision decision);
+        public void conflictDecisionMade(Decision decision);
     }
 }
diff --git a/src/com/owncloud/android/ui/dialog/CreateFolderDialogFragment.java b/src/com/owncloud/android/ui/dialog/CreateFolderDialogFragment.java
new file mode 100644 (file)
index 0000000..29b3be2
--- /dev/null
@@ -0,0 +1,124 @@
+/* ownCloud Android client application
+ *   Copyright (C) 2014 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 com.actionbarsherlock.app.SherlockDialogFragment;
+import com.owncloud.android.R;
+import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.lib.resources.files.FileUtils;
+import com.owncloud.android.ui.activity.ComponentsGetter;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.WindowManager.LayoutParams;
+import android.widget.EditText;
+import android.widget.TextView;
+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
+ */
+public class CreateFolderDialogFragment 
+extends SherlockDialogFragment implements DialogInterface.OnClickListener {
+
+    private static final String ARG_PARENT_FOLDER = "PARENT_FOLDER";
+    
+    public static final String CREATE_FOLDER_FRAGMENT = "CREATE_FOLDER_FRAGMENT";
+
+    /**
+     * Public factory method to create new CreateFolderDialogFragment instances.
+     * 
+     * @param file            File to remove.
+     * @return                Dialog ready to show.
+     */
+    public static CreateFolderDialogFragment newInstance(OCFile parentFolder) {
+        CreateFolderDialogFragment frag = new CreateFolderDialogFragment();
+        Bundle args = new Bundle();
+        args.putParcelable(ARG_PARENT_FOLDER, parentFolder);
+        frag.setArguments(args);
+        return frag;
+        
+    }
+
+    private OCFile mParentFolder;
+    
+    
+    @Override
+    public Dialog onCreateDialog(Bundle savedInstanceState) {
+        mParentFolder = getArguments().getParcelable(ARG_PARENT_FOLDER);
+        
+        // Inflate the layout for the dialog
+        LayoutInflater inflater = getSherlockActivity().getLayoutInflater();
+        View v = inflater.inflate(R.layout.edit_box_dialog, null);
+        
+        // Setup layout 
+        EditText inputText = ((EditText)v.findViewById(R.id.user_input));
+        inputText.setText("");
+        inputText.requestFocus();
+        
+        // Build the dialog  
+        AlertDialog.Builder builder = new AlertDialog.Builder(getSherlockActivity());
+        builder.setView(v)
+               .setPositiveButton(R.string.common_ok, this)
+               .setNegativeButton(R.string.common_cancel, this)
+               .setTitle(R.string.uploader_info_dirname);
+        Dialog d = builder.create();
+        d.getWindow().setSoftInputMode(LayoutParams.SOFT_INPUT_STATE_VISIBLE);
+        return d;
+    }    
+    
+    
+    @Override
+    public void onClick(DialogInterface dialog, int which) {
+        if (which == AlertDialog.BUTTON_POSITIVE) {
+            String newFolderName = 
+                    ((TextView)(getDialog().findViewById(R.id.user_input)))
+                        .getText().toString().trim();
+            
+            if (newFolderName.length() <= 0) {
+                Toast.makeText(
+                        getSherlockActivity(), 
+                        R.string.filename_empty, 
+                        Toast.LENGTH_LONG).show();
+                return;
+            }
+            
+            if (!FileUtils.isValidName(newFolderName)) {
+                Toast.makeText(
+                        getSherlockActivity(), 
+                        R.string.filename_forbidden_characters, 
+                        Toast.LENGTH_LONG).show();
+                return;
+            }
+            
+            String path = mParentFolder.getRemotePath();
+            path += newFolderName + OCFile.PATH_SEPARATOR;
+            ((ComponentsGetter)getSherlockActivity()).
+                getFileOperationsHelper().createFolder(path, false);
+        }
+    }
+        
+}
diff --git a/src/com/owncloud/android/ui/dialog/CredentialsDialogFragment.java b/src/com/owncloud/android/ui/dialog/CredentialsDialogFragment.java
new file mode 100644 (file)
index 0000000..080316b
--- /dev/null
@@ -0,0 +1,152 @@
+/* ownCloud Android client application
+ *   Copyright (C) 2014 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 com.actionbarsherlock.app.SherlockDialogFragment;
+import com.owncloud.android.R;
+import com.owncloud.android.authentication.AuthenticatorActivity;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.AlertDialog.Builder;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.text.InputType;
+import android.view.WindowManager.LayoutParams;
+import android.webkit.HttpAuthHandler;
+import android.webkit.WebView;
+import android.widget.EditText;
+import android.widget.LinearLayout;
+
+
+
+/**
+ *  Dialog to input authentication credentials
+ * 
+ */
+public class CredentialsDialogFragment extends SherlockDialogFragment
+    implements DialogInterface.OnClickListener {
+
+    private WebView mWebView = null;
+    private HttpAuthHandler mHandler = null;
+
+    private EditText mUsernameET;
+    private EditText mPasswordET;
+    
+    private String mUsernameStr;
+    private String mPasswordStr;
+
+
+    /**
+     * Public factory method to create new CredentialsDialogFragment instances.
+     * @param webView       WebView that is being loaded
+     * @param handler       HttpAuthHandler
+     * @return              Dialog ready to show
+     */
+    public static CredentialsDialogFragment newInstanceForCredentials(WebView webView, HttpAuthHandler handler) {
+        if (handler == null) {
+            throw new IllegalArgumentException("Trying to create instance with parameter handler == null");
+        }
+        CredentialsDialogFragment frag = new CredentialsDialogFragment();
+        frag.mHandler = handler;
+        frag.mWebView = webView;
+        return frag;
+    }
+
+
+    @Override
+    public Dialog onCreateDialog(Bundle savedInstanceState) {
+
+        // Create field for username
+        mUsernameET = new EditText(getSherlockActivity());
+        mUsernameET.setHint(getSherlockActivity().getText(R.string.auth_username));
+
+        // Create field for password
+        mPasswordET = new EditText(getSherlockActivity());
+        mPasswordET.setHint(getSherlockActivity().getText(R.string.auth_password));
+        mPasswordET.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
+
+        // Prepare LinearLayout for dialog
+        LinearLayout ll = new LinearLayout(getSherlockActivity());
+        ll.setOrientation(LinearLayout.VERTICAL);
+        ll.addView(mUsernameET);
+        ll.addView(mPasswordET);
+        
+        ll.requestFocus();
+        
+        setRetainInstance(true);
+
+        Builder authDialog = new AlertDialog
+                .Builder(getSherlockActivity())
+                .setTitle(getSherlockActivity().getText(R.string.saml_authentication_required_text))
+                .setView(ll)
+                .setCancelable(false)
+                .setPositiveButton(R.string.common_ok, this)
+                .setNegativeButton(R.string.common_cancel, this);
+
+        Dialog d = authDialog.create();
+        d.getWindow().setSoftInputMode(LayoutParams.SOFT_INPUT_STATE_VISIBLE);
+        return d;
+    }
+
+
+    @Override
+    public void onPause() {
+        super.onPause();
+        // Due to the use of setRetainInstance(true) for keep the dialog over the rest of dialogs,
+        // we need to save the inputs text for being injected in onResume()
+        mUsernameStr = mUsernameET.getText().toString();
+        mPasswordStr = mPasswordET.getText().toString();
+    }
+
+
+    @Override
+    public void onResume() {
+        super.onResume();
+        mUsernameET.setText(mUsernameStr);
+        mPasswordET.setText(mPasswordStr);
+    }
+
+
+    @Override
+    public void onClick(DialogInterface dialog, int which) {
+        if (which == AlertDialog.BUTTON_POSITIVE) { 
+
+            String username = mUsernameET.getText().toString();
+            String password = mPasswordET.getText().toString();
+
+            // Proceed with the authentication
+            mHandler.proceed(username, password);
+
+        } else if (which == AlertDialog.BUTTON_NEGATIVE) {
+            mWebView.stopLoading();
+            ((AuthenticatorActivity)getActivity()).doNegativeAuthenticatioDialogClick();
+        }
+
+        dialog.dismiss();
+    }
+    
+    
+    @Override
+    public void onDestroyView() {
+      if (getDialog() != null && getRetainInstance())
+        getDialog().setDismissMessage(null);
+      super.onDestroyView();
+    }
+
+}
diff --git a/src/com/owncloud/android/ui/dialog/EditNameDialog.java b/src/com/owncloud/android/ui/dialog/EditNameDialog.java
deleted file mode 100644 (file)
index 4d6243a..0000000
+++ /dev/null
@@ -1,173 +0,0 @@
-/* ownCloud Android client application
- *   Copyright (C) 2011  Bartek Przybylski
- *   Copyright (C) 2012-2013 ownCloud Inc.
- *
- *   This program is free software: you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License version 2,
- *   as published by the Free Software Foundation.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-package com.owncloud.android.ui.dialog;
-
-import android.app.AlertDialog;
-import android.app.Dialog;
-import android.content.DialogInterface;
-import android.os.Bundle;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.WindowManager.LayoutParams;
-import android.widget.EditText;
-import android.widget.TextView;
-
-import com.actionbarsherlock.app.SherlockDialogFragment;
-import com.owncloud.android.R;
-
-
-
-/**
- * Dialog to request the user to input a name, optionally initialized with a former name.
- * 
- * @author Bartek Przybylski
- * @author David A. Velasco
- */
-public class EditNameDialog extends SherlockDialogFragment implements DialogInterface.OnClickListener {
-
-    public static final String TAG = EditNameDialog.class.getSimpleName();
-    
-    protected static final String ARG_TITLE = "TITLE";
-    protected static final String ARG_NAME = "NAME";
-    protected static final String ARG_SELECTION_START = "SELECTION_START";
-    protected static final String ARG_SELECTION_END = "SELECTION_END";
-    
-    private String mNewFilename;
-    private boolean mResult;
-    private EditNameDialogListener mListener;
-    
-    /**
-     * Public factory method to get dialog instances.
-     * 
-     * @param title             Text to show as title in the dialog.
-     * @param name              Optional text to include in the text input field when the dialog is shown.
-     * @param listener          Instance to notify when the dialog is dismissed.
-     * @param selectionStart    Index to the first character to be selected in the input field; negative value for none
-     * @param selectionEnd      Index to the last character to be selected in the input field; negative value for none
-     * @return              New dialog instance, ready to show.
-     */
-    static public EditNameDialog newInstance(String title, String name, int selectionStart, int selectionEnd, EditNameDialogListener listener) {
-        EditNameDialog f = new EditNameDialog();
-        Bundle args = new Bundle();
-        args.putString(ARG_TITLE, title);
-        args.putString(ARG_NAME, name);
-        args.putInt(ARG_SELECTION_START, selectionStart);
-        args.putInt(ARG_SELECTION_END, selectionEnd);
-        f.setArguments(args);
-        f.setOnDismissListener(listener);
-        return f;
-    }
-    
-    
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public Dialog onCreateDialog(Bundle savedInstanceState) {
-        String currentName = getArguments().getString(ARG_NAME);
-        if (currentName == null)
-            currentName = "";
-        String title = getArguments().getString(ARG_TITLE);
-        
-        // Inflate the layout for the dialog
-        LayoutInflater inflater = getSherlockActivity().getLayoutInflater();
-        View v = inflater.inflate(R.layout.edit_box_dialog, null);  // null parent view because it will go in the dialog layout
-        EditText inputText = ((EditText)v.findViewById(R.id.user_input));
-        inputText.setText(currentName);
-        
-        // Set it to the dialog 
-        AlertDialog.Builder builder = new AlertDialog.Builder(getSherlockActivity());
-        builder.setView(v)
-               .setPositiveButton(R.string.common_ok, this)
-               .setNegativeButton(R.string.common_cancel, this);
-
-        if (title != null) {
-            builder.setTitle(title);
-        }
-        
-        mResult = false;
-        
-        Dialog d = builder.create();
-
-        inputText.requestFocus();
-        int selectionStart = getArguments().getInt(ARG_SELECTION_START, -1);
-        int selectionEnd = getArguments().getInt(ARG_SELECTION_END, -1);
-        if (selectionStart >= 0 && selectionEnd >= 0) {
-            inputText.setSelection(Math.min(selectionStart, selectionEnd), Math.max(selectionStart, selectionEnd));
-        }
-        d.getWindow().setSoftInputMode(LayoutParams.SOFT_INPUT_STATE_VISIBLE);
-        return d;
-    }    
-
-    
-    /**
-     * Performs the corresponding action when a dialog button is clicked.
-     * 
-     * Saves the text in the input field to be accessed through {@link #getNewFilename()} when the positive
-     * button is clicked.
-     * 
-     * Notify the current listener in any case.
-     */
-    @Override
-    public void onClick(DialogInterface dialog, int which) {
-        switch (which) {
-            case AlertDialog.BUTTON_POSITIVE: {
-                mNewFilename = ((TextView)(getDialog().findViewById(R.id.user_input))).getText().toString();
-                mResult = true;
-            }
-            case AlertDialog.BUTTON_NEGATIVE: { // fall through
-                dismiss();
-                if (mListener != null)
-                    mListener.onDismiss(this);
-            }
-        }
-    }
-    
-    protected void setOnDismissListener(EditNameDialogListener listener) {
-        mListener = listener;
-    }
-    
-    /**
-     * Returns the text in the input field after the user clicked the positive button.
-     * 
-     * @return      Text in the input field.
-     */
-    public String getNewFilename() {
-        return mNewFilename;
-    }
-    
-    /**
-     * 
-     * @return      True when the user clicked the positive button.
-     */
-    public boolean getResult() {
-        return mResult;
-    }
-
-    
-    /**
-     * Interface to receive a notification when any button in the dialog is clicked.
-     */
-    public interface EditNameDialogListener {
-        public void onDismiss(EditNameDialog dialog);
-    }
-
-
-}
-
index 2203e03..d0dcfb7 100644 (file)
@@ -1,3 +1,19 @@
+/* ownCloud Android client application
+ *   Copyright (C) 2012-2014 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 com.owncloud.android.R;
@@ -53,6 +69,6 @@ public class LoadingDialog extends DialogFragment {
     public void onDestroyView() {
         if (getDialog() != null && getRetainInstance())
             getDialog().setDismissMessage(null);
-            super.onDestroyView();
+        super.onDestroyView();
     }
 }
diff --git a/src/com/owncloud/android/ui/dialog/RemoveFileDialogFragment.java b/src/com/owncloud/android/ui/dialog/RemoveFileDialogFragment.java
new file mode 100644 (file)
index 0000000..a78584a
--- /dev/null
@@ -0,0 +1,144 @@
+/* ownCloud Android client application
+ *   Copyright (C) 2014 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;
+
+/**
+ *  Dialog requiring confirmation before removing a given OCFile.  
+ * 
+ *  Triggers the removal according to the user response. 
+ *  
+ *  @author David A. Velasco
+ */
+import java.util.Vector;
+
+import com.owncloud.android.R;
+import com.owncloud.android.datamodel.FileDataStorageManager;
+import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.ui.activity.ComponentsGetter;
+import com.owncloud.android.ui.dialog.ConfirmationDialogFragment.ConfirmationDialogFragmentListener;
+
+import android.app.Dialog;
+import android.os.Bundle;
+
+public class RemoveFileDialogFragment extends ConfirmationDialogFragment 
+implements ConfirmationDialogFragmentListener {
+
+    private static final String ARG_TARGET_FILE = "TARGET_FILE";
+
+    /**
+     * Public factory method to create new RemoveFileDialogFragment instances.
+     * 
+     * @param file            File to remove.
+     * @return                Dialog ready to show.
+     */
+    public static RemoveFileDialogFragment newInstance(OCFile file) {
+        RemoveFileDialogFragment frag = new RemoveFileDialogFragment();
+        Bundle args = new Bundle();
+        
+        int messageStringId = R.string.confirmation_remove_alert;
+        
+        int posBtn = R.string.confirmation_remove_remote;
+        int neuBtn = -1;
+        if (file.isFolder()) {
+            messageStringId = R.string.confirmation_remove_folder_alert;
+            posBtn = R.string.confirmation_remove_remote_and_local;
+            neuBtn = R.string.confirmation_remove_folder_local;
+        } else if (file.isDown()) {
+            posBtn = R.string.confirmation_remove_remote_and_local;
+            neuBtn = R.string.confirmation_remove_local;
+        }
+        
+        
+        args.putInt(ARG_CONF_RESOURCE_ID, messageStringId);
+        args.putStringArray(ARG_CONF_ARGUMENTS, new String[]{file.getFileName()});
+        args.putInt(ARG_POSITIVE_BTN_RES, posBtn);
+        args.putInt(ARG_NEUTRAL_BTN_RES, neuBtn);
+        args.putInt(ARG_NEGATIVE_BTN_RES, R.string.common_cancel);
+        args.putParcelable(ARG_TARGET_FILE, file);
+        frag.setArguments(args);
+        
+        return frag;
+    }
+
+    private OCFile mTargetFile;
+    
+    @Override
+    public Dialog onCreateDialog(Bundle savedInstanceState) {
+        Dialog dialog = super.onCreateDialog(savedInstanceState);
+        mTargetFile = getArguments().getParcelable(ARG_TARGET_FILE);
+        
+        setOnConfirmationListener(this);
+        
+        return dialog;
+    }    
+
+    /**
+     * Performs the removal of the target file, both locally and in the server.
+     */
+    @Override
+    public void onConfirmation(String callerTag) {
+        ComponentsGetter cg = (ComponentsGetter)getSherlockActivity();
+        FileDataStorageManager storageManager = cg.getStorageManager();
+        if (storageManager.getFileById(mTargetFile.getFileId()) != null) {
+            cg.getFileOperationsHelper().removeFile(mTargetFile, false);
+        }
+    }
+    
+    /**
+     * Performs the removal of the local copy of the target file
+     */
+    @Override
+    public void onNeutral(String callerTag) {
+        ComponentsGetter cg = (ComponentsGetter)getSherlockActivity();
+        cg.getFileOperationsHelper()
+            .removeFile(mTargetFile, true);
+        
+        FileDataStorageManager storageManager = cg.getStorageManager();
+        
+        boolean containsKeepInSync = false;
+        if (mTargetFile.isFolder()) {
+            Vector<OCFile> files = storageManager.getFolderContent(mTargetFile);
+            for(OCFile file: files) {
+                containsKeepInSync = file.keepInSync() || containsKeepInSync;
+
+                if (containsKeepInSync)
+                    break;
+            }
+        }
+
+        // Remove etag for parent, if file is a keep_in_sync 
+        // or is a folder and contains keep_in_sync        
+        if (mTargetFile.keepInSync() || containsKeepInSync) {
+            OCFile folder = null;
+            if (mTargetFile.isFolder()) {
+                folder = mTargetFile;
+            } else {
+                folder = storageManager.getFileById(mTargetFile.getParentId());
+            }
+            
+           folder.setEtag("");
+           storageManager.saveFile(folder);
+        }
+    }
+
+    @Override
+    public void onCancel(String callerTag) {
+        // nothing to do here
+    }
+    
+}
diff --git a/src/com/owncloud/android/ui/dialog/RenameFileDialogFragment.java b/src/com/owncloud/android/ui/dialog/RenameFileDialogFragment.java
new file mode 100644 (file)
index 0000000..530e920
--- /dev/null
@@ -0,0 +1,136 @@
+/* ownCloud Android client application
+ *   Copyright (C) 2014 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;
+
+/**
+ *  Dialog to input a new name for an {@link OCFile} being renamed.  
+ * 
+ *  Triggers the rename operation. 
+ */
+import com.actionbarsherlock.app.SherlockDialogFragment;
+import com.owncloud.android.R;
+import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.lib.resources.files.FileUtils;
+import com.owncloud.android.ui.activity.ComponentsGetter;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.WindowManager.LayoutParams;
+import android.widget.EditText;
+import android.widget.TextView;
+import android.widget.Toast;
+
+
+/**
+ *  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
+ */
+public class RenameFileDialogFragment
+extends SherlockDialogFragment implements DialogInterface.OnClickListener {
+
+    private static final String ARG_TARGET_FILE = "TARGET_FILE";
+
+    /**
+     * Public factory method to create new RenameFileDialogFragment instances.
+     * 
+     * @param file            File to rename.
+     * @return                Dialog ready to show.
+     */
+    public static RenameFileDialogFragment newInstance(OCFile file) {
+        RenameFileDialogFragment frag = new RenameFileDialogFragment();
+        Bundle args = new Bundle();
+        args.putParcelable(ARG_TARGET_FILE, file);
+        frag.setArguments(args);
+        return frag;
+        
+    }
+
+    private OCFile mTargetFile;
+    
+    @Override
+    public Dialog onCreateDialog(Bundle savedInstanceState) {
+        mTargetFile = getArguments().getParcelable(ARG_TARGET_FILE);
+
+        // Inflate the layout for the dialog
+        LayoutInflater inflater = getSherlockActivity().getLayoutInflater();
+        View v = inflater.inflate(R.layout.edit_box_dialog, null);
+        
+        // Setup layout 
+        String currentName = mTargetFile.getFileName();
+        EditText inputText = ((EditText)v.findViewById(R.id.user_input));
+        inputText.setText(currentName);
+        int selectionStart = 0;
+        int extensionStart = mTargetFile.isFolder() ? -1 : currentName.lastIndexOf(".");
+        int selectionEnd = (extensionStart >= 0) ? extensionStart : currentName.length();
+        if (selectionStart >= 0 && selectionEnd >= 0) {
+            inputText.setSelection(
+                    Math.min(selectionStart, selectionEnd), 
+                    Math.max(selectionStart, selectionEnd));
+        }
+        inputText.requestFocus();
+        
+        // Build the dialog  
+        AlertDialog.Builder builder = new AlertDialog.Builder(getSherlockActivity());
+        builder.setView(v)
+               .setPositiveButton(R.string.common_ok, this)
+               .setNegativeButton(R.string.common_cancel, this)
+               .setTitle(R.string.rename_dialog_title);
+        Dialog d = builder.create();
+        d.getWindow().setSoftInputMode(LayoutParams.SOFT_INPUT_STATE_VISIBLE);
+        return d;
+    }    
+
+    
+    @Override
+    public void onClick(DialogInterface dialog, int which) {
+        if (which == AlertDialog.BUTTON_POSITIVE) {
+            String newFileName = 
+                ((TextView)(getDialog().findViewById(R.id.user_input)))
+                    .getText().toString().trim();
+            
+            if (newFileName.length() <= 0) {
+                Toast.makeText(
+                        getSherlockActivity(), 
+                        R.string.filename_empty, 
+                        Toast.LENGTH_LONG).show();
+                return;
+            }
+            
+            if (!FileUtils.isValidName(newFileName)) {
+                Toast.makeText(
+                        getSherlockActivity(), 
+                        R.string.filename_forbidden_characters, 
+                        Toast.LENGTH_LONG).show();
+                return;
+            }
+            
+            ((ComponentsGetter)getSherlockActivity()).
+                getFileOperationsHelper().renameFile(mTargetFile, newFileName);
+            
+            
+        }
+    }
+    
+}
index 516fce1..76243ed 100644 (file)
@@ -1,5 +1,5 @@
 /* ownCloud Android client application
- *   Copyright (C) 2012-2013 ownCloud Inc.
+ *   Copyright (C) 2012-2014 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,19 +30,18 @@ import android.view.View;
 import android.view.ViewGroup;
 import android.webkit.CookieManager;
 import android.webkit.CookieSyncManager;
-import android.webkit.WebBackForwardList;
 import android.webkit.WebSettings;
 import android.webkit.WebView;
+import android.widget.RelativeLayout;
 
 import com.actionbarsherlock.app.SherlockDialogFragment;
-import com.owncloud.android.Log_OC;
 import com.owncloud.android.R;
 import com.owncloud.android.authentication.SsoWebViewClient;
 import com.owncloud.android.authentication.SsoWebViewClient.SsoWebViewClientListener;
+import com.owncloud.android.lib.common.OwnCloudClient;
+import com.owncloud.android.lib.common.utils.Log_OC;
 
 
-import eu.alefzero.webdav.WebdavClient;
-
 /**
  * Dialog to show the WebView for SAML Authentication
  * 
@@ -57,7 +56,6 @@ public class SamlWebViewDialog extends SherlockDialogFragment {
 
     private static final String ARG_INITIAL_URL = "INITIAL_URL";
     private static final String ARG_TARGET_URL = "TARGET_URL";
-    private static final String KEY_WEBVIEW_STATE = "WEBVIEW_STATE";
     
     private WebView mSsoWebView;
     private SsoWebViewClient mWebViewClient;
@@ -69,15 +67,12 @@ public class SamlWebViewDialog extends SherlockDialogFragment {
 
     private SsoWebViewClientListener mSsoWebViewClientListener;
 
-    //private View mSsoRootView;
-
-
     /**
      * Public factory method to get dialog instances.
      * 
      * @param handler
      * @param Url           Url to open at WebView
-     * @param targetURL     mHostBaseUrl + AccountUtils.getWebdavPath(mDiscoveredVersion, mCurrentAuthTokenType)
+     * @param targetURL     mBaseUrl + AccountUtils.getWebdavPath(mDiscoveredVersion, mCurrentAuthTokenType)
      * @return              New dialog instance, ready to show.
      */
     public static SamlWebViewDialog newInstance(String url, String targetUrl) {
@@ -104,7 +99,7 @@ public class SamlWebViewDialog extends SherlockDialogFragment {
         try {
             mSsoWebViewClientListener = (SsoWebViewClientListener) activity;
             mHandler = new Handler();
-            mWebViewClient = new SsoWebViewClient(mHandler, mSsoWebViewClientListener);
+            mWebViewClient = new SsoWebViewClient(activity, mHandler, mSsoWebViewClientListener);
             
        } catch (ClassCastException e) {
             throw new ClassCastException(activity.toString() + " must implement " + SsoWebViewClientListener.class.getSimpleName());
@@ -115,10 +110,12 @@ public class SamlWebViewDialog extends SherlockDialogFragment {
     @SuppressLint("SetJavaScriptEnabled")
     @Override
     public void onCreate(Bundle savedInstanceState) {
-        Log_OC.d(TAG, "onCreate");
+        Log_OC.d(TAG, "onCreate, savedInstanceState is " + savedInstanceState);
         super.onCreate(savedInstanceState);
         
-        CookieSyncManager.createInstance(getActivity());
+        setRetainInstance(true);
+        
+        CookieSyncManager.createInstance(getSherlockActivity().getApplicationContext());
 
         if (savedInstanceState == null) {
             mInitialUrl = getArguments().getString(ARG_INITIAL_URL);
@@ -131,82 +128,68 @@ public class SamlWebViewDialog extends SherlockDialogFragment {
         setStyle(SherlockDialogFragment.STYLE_NO_TITLE, R.style.Theme_ownCloud_Dialog);
     }
     
-    @Override
-    public Dialog onCreateDialog(Bundle savedInstanceState) {
-        Log_OC.d(TAG, "onCreateDialog");
-
-        /*
-        // build the dialog
-        AlertDialog.Builder builder = new AlertDialog.Builder(getSherlockActivity());
-        if (mSsoRootView.getParent() != null) {
-            ((ViewGroup)(mSsoRootView.getParent())).removeView(mSsoRootView);
-        }
-        builder.setView(mSsoRootView);
-        //builder.setView(mSsoWebView);
-        Dialog dialog = builder.create();
-        */
-        
-        return super.onCreateDialog(savedInstanceState);
-    }
-
+    @SuppressWarnings("deprecation")
     @SuppressLint("SetJavaScriptEnabled")
     @Override
     public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
-        Log_OC.d(TAG, "onCreateView");
+        Log_OC.d(TAG, "onCreateView, savedInsanceState is " + savedInstanceState);
         
         // Inflate layout of the dialog  
-        View rootView = inflater.inflate(R.layout.sso_dialog, container, false);  // null parent view because it will go in the dialog layout
-        mSsoWebView  = (WebView) rootView.findViewById(R.id.sso_webview);
-            
-        mWebViewClient.setTargetUrl(mTargetUrl);
-        mSsoWebView.setWebViewClient(mWebViewClient);
+        RelativeLayout ssoRootView = (RelativeLayout) inflater.inflate(R.layout.sso_dialog, container, false);  // null parent view because it will go in the dialog layout
         
-        if (savedInstanceState == null) {
-            Log_OC.d(TAG,  "   initWebView start");
+        if (mSsoWebView == null) {
+            // initialize the WebView
+            mSsoWebView = new SsoWebView(getSherlockActivity().getApplicationContext());
+            mSsoWebView.setFocusable(true);
+            mSsoWebView.setFocusableInTouchMode(true);
+            mSsoWebView.setClickable(true);
+            
             CookieManager cookieManager = CookieManager.getInstance();
             cookieManager.setAcceptCookie(true);
             cookieManager.removeAllCookie();
             mSsoWebView.loadUrl(mInitialUrl);
-            
-        } else {
-            Log_OC.d(TAG, "   restoreWebView start");
-            WebBackForwardList history = mSsoWebView.restoreState(savedInstanceState.getBundle(KEY_WEBVIEW_STATE));
-            if (history == null) {
-                Log_OC.e(TAG, "Error restoring WebView state ; back to starting URL");
-                mSsoWebView.loadUrl(mInitialUrl);
-            }
+          
+            WebSettings webSettings = mSsoWebView.getSettings();
+            webSettings.setJavaScriptEnabled(true);
+            webSettings.setBuiltInZoomControls(false);
+            webSettings.setLoadWithOverviewMode(false);
+            webSettings.setSavePassword(false);
+            webSettings.setUserAgentString(OwnCloudClient.USER_AGENT);
+            webSettings.setSaveFormData(false);
         }
-
-        WebSettings webSettings = mSsoWebView.getSettings();
-        webSettings.setJavaScriptEnabled(true);
-        webSettings.setBuiltInZoomControls(true);
-        webSettings.setLoadWithOverviewMode(false);
-        webSettings.setSavePassword(false);
-        webSettings.setUserAgentString(WebdavClient.USER_AGENT);
-        webSettings.setSaveFormData(false);
         
-        return rootView;
+        mWebViewClient.setTargetUrl(mTargetUrl);
+        mSsoWebView.setWebViewClient(mWebViewClient);
+        
+        // add the webview into the layout
+        RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(
+                RelativeLayout.LayoutParams.WRAP_CONTENT, 
+                RelativeLayout.LayoutParams.WRAP_CONTENT
+                );
+        ssoRootView.addView(mSsoWebView, layoutParams);
+        ssoRootView.requestLayout();
+        
+        return ssoRootView;
     }
 
     @Override
     public void onSaveInstanceState(Bundle outState) {
-        Log_OC.d(SAML_DIALOG_TAG, "onSaveInstanceState being CALLED");
+        Log_OC.d(TAG, "onSaveInstanceState being CALLED");
         super.onSaveInstanceState(outState);
         
         // save URLs
         outState.putString(ARG_INITIAL_URL, mInitialUrl);
         outState.putString(ARG_TARGET_URL, mTargetUrl);
-        
-        // Save the state of the WebView
-        Bundle webviewState = new Bundle();
-        mSsoWebView.saveState(webviewState);
-        outState.putBundle(KEY_WEBVIEW_STATE, webviewState);
     }
 
     @Override
     public void onDestroyView() {
         Log_OC.d(TAG, "onDestroyView");
         
+        if ((ViewGroup)mSsoWebView.getParent() != null) {
+            ((ViewGroup)mSsoWebView.getParent()).removeView(mSsoWebView);
+        }
+        
         mSsoWebView.setWebViewClient(null);
         
         // Work around bug: http://code.google.com/p/android/issues/detail?id=17423
@@ -236,50 +219,52 @@ public class SamlWebViewDialog extends SherlockDialogFragment {
     
     @Override
     public void onCancel (DialogInterface dialog) {
-        Log_OC.d(SAML_DIALOG_TAG, "onCancel");
+        Log_OC.d(TAG, "onCancel");
         super.onCancel(dialog);
     }
     
     @Override
     public void onDismiss (DialogInterface dialog) {
-        Log_OC.d(SAML_DIALOG_TAG, "onDismiss");
+        Log_OC.d(TAG, "onDismiss");
         super.onDismiss(dialog);
     }
     
     @Override
     public void onStart() {
-        Log_OC.d(SAML_DIALOG_TAG, "onStart");
+        Log_OC.d(TAG, "onStart");
         super.onStart();
     }
 
     @Override
     public void onStop() {
-        Log_OC.d(SAML_DIALOG_TAG, "onStop");
+        Log_OC.d(TAG, "onStop");
         super.onStop();
     }
 
     @Override
     public void onResume() {
-        Log_OC.d(SAML_DIALOG_TAG, "onResume");
+        Log_OC.d(TAG, "onResume");
         super.onResume();
+        mSsoWebView.onResume();
     }
 
     @Override
     public void onPause() {
-        Log_OC.d(SAML_DIALOG_TAG, "onPause");
+        Log_OC.d(TAG, "onPause");
+        mSsoWebView.onPause();
         super.onPause();
     }
     
     @Override
     public int show (FragmentTransaction transaction, String tag) {
-        Log_OC.d(SAML_DIALOG_TAG, "show (transaction)");
+        Log_OC.d(TAG, "show (transaction)");
         return super.show(transaction, tag);
     }
 
     @Override
     public void show (FragmentManager manager, String tag) {
-        Log_OC.d(SAML_DIALOG_TAG, "show (manager)");
+        Log_OC.d(TAG, "show (manager)");
         super.show(manager, tag);
     }
-
+    
 }
\ No newline at end of file
diff --git a/src/com/owncloud/android/ui/dialog/ShareLinkToDialog.java b/src/com/owncloud/android/ui/dialog/ShareLinkToDialog.java
new file mode 100644 (file)
index 0000000..2876f7b
--- /dev/null
@@ -0,0 +1,186 @@
+/* ownCloud Android client application
+ *   Copyright (C) 2012-2014 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 java.util.Arrays;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.actionbarsherlock.app.SherlockDialogFragment;
+import com.owncloud.android.R;
+import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.lib.common.utils.Log_OC;
+import com.owncloud.android.ui.activity.ComponentsGetter;
+import com.owncloud.android.ui.activity.CopyToClipboardActivity;
+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 {
+    
+    private final static String TAG =  ShareLinkToDialog.class.getSimpleName();
+    private final static String ARG_INTENT =  ShareLinkToDialog.class.getSimpleName() + ".ARG_INTENT";
+    private final static String ARG_PACKAGES_TO_EXCLUDE =  ShareLinkToDialog.class.getSimpleName() + ".ARG_PACKAGES_TO_EXCLUDE";
+    private final static String ARG_FILE_TO_SHARE = ShareLinkToDialog.class.getSimpleName() + ".FILE_TO_SHARE";
+    
+    private ActivityAdapter mAdapter;
+    private OCFile mFile;
+    private Intent mIntent;
+    
+    public static ShareLinkToDialog newInstance(Intent intent, String[] packagesToExclude, OCFile fileToShare) {
+        ShareLinkToDialog f = new ShareLinkToDialog();
+        Bundle args = new Bundle();
+        args.putParcelable(ARG_INTENT, intent);
+        args.putStringArray(ARG_PACKAGES_TO_EXCLUDE, packagesToExclude);
+        args.putParcelable(ARG_FILE_TO_SHARE, fileToShare);
+        f.setArguments(args);
+        return f;
+    }
+    
+    public ShareLinkToDialog() {
+        super();
+        Log_OC.d(TAG, "constructor");
+    }
+    
+    @Override
+    public Dialog onCreateDialog(Bundle savedInstanceState) {
+        mIntent = getArguments().getParcelable(ARG_INTENT);
+        String[] packagesToExclude = getArguments().getStringArray(ARG_PACKAGES_TO_EXCLUDE);
+        List<String> packagesToExcludeList = Arrays.asList(packagesToExclude != null ? packagesToExclude : new String[0]);
+        mFile = getArguments().getParcelable(ARG_FILE_TO_SHARE);
+        
+        PackageManager pm= getSherlockActivity().getPackageManager();
+        List<ResolveInfo> activities = pm.queryIntentActivities(mIntent, PackageManager.MATCH_DEFAULT_ONLY);
+        Iterator<ResolveInfo> it = activities.iterator();
+        ResolveInfo resolveInfo;
+        while (it.hasNext()) {
+            resolveInfo = it.next();
+            if (packagesToExcludeList.contains(resolveInfo.activityInfo.packageName.toLowerCase())) {
+                it.remove();
+            }
+        }
+        
+        boolean sendAction = mIntent.getBooleanExtra(Intent.ACTION_SEND, false);
+        
+        if (!sendAction) {
+            // add activity for copy to clipboard
+            Intent copyToClipboardIntent = new Intent(getSherlockActivity(), CopyToClipboardActivity.class);
+            List<ResolveInfo> copyToClipboard = pm.queryIntentActivities(copyToClipboardIntent, 0);
+            if (!copyToClipboard.isEmpty()) {
+                activities.add(copyToClipboard.get(0));
+            }
+        }
+        
+        Collections.sort(activities, new ResolveInfo.DisplayNameComparator(pm)); 
+        mAdapter = new ActivityAdapter(getSherlockActivity(), pm, activities);
+        
+        return createSelector(sendAction);
+        
+    }
+
+    private AlertDialog createSelector(final boolean sendAction) {
+    
+        int titleId;
+        if (sendAction) {
+            titleId = R.string.activity_chooser_send_file_title;
+        } else {
+            titleId = R.string.activity_chooser_title;
+        }
+        
+        return new AlertDialog.Builder(getSherlockActivity())
+                    .setTitle(titleId)
+                    .setAdapter(mAdapter, new DialogInterface.OnClickListener() {
+                        @Override
+                        public void onClick(DialogInterface dialog, int which) {
+                            // Add the information of the chosen activity to the intent to send 
+                            ResolveInfo chosen = mAdapter.getItem(which);
+                            ActivityInfo actInfo = chosen.activityInfo;
+                            ComponentName name=new ComponentName(
+                                    actInfo.applicationInfo.packageName, 
+                                    actInfo.name);
+                            mIntent.setComponent(name);                               
+
+                            if (sendAction) {
+                                dialog.dismiss();    // explicitly added for Android 2.x devices
+
+                                // Send the file
+                                ((FileActivity)getSherlockActivity()).startActivity(mIntent);
+
+                            } else {
+                                // Create a new share resource
+                                ((ComponentsGetter)getSherlockActivity()).getFileOperationsHelper()
+                                    .shareFileWithLinkToApp(mFile, mIntent);
+                            }
+                        }
+        })
+        .create();
+    }
+    
+    class ActivityAdapter extends ArrayAdapter<ResolveInfo> {
+        
+        private PackageManager mPackageManager;
+        
+        ActivityAdapter(Context context, PackageManager pm, List<ResolveInfo> apps) {
+            super(context, R.layout.activity_row, apps);
+            this.mPackageManager = pm;
+        }
+        
+        @Override
+        public View getView(int position, View convertView, ViewGroup parent) {
+            if (convertView == null) {
+                convertView = newView(parent);
+            }
+            bindView(position, convertView);
+            return convertView;
+        }
+        
+        private View newView(ViewGroup parent) {
+            return(((LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(R.layout.activity_row, parent, false));
+        }
+        
+        private void bindView(int position, View row) {
+            TextView label = (TextView) row.findViewById(R.id.title);
+            label.setText(getItem(position).loadLabel(mPackageManager));
+            ImageView icon = (ImageView) row.findViewById(R.id.icon);
+            icon.setImageDrawable(getItem(position).loadIcon(mPackageManager));
+        }
+    }
+    
+}
diff --git a/src/com/owncloud/android/ui/dialog/SslUntrustedCertDialog.java b/src/com/owncloud/android/ui/dialog/SslUntrustedCertDialog.java
new file mode 100644 (file)
index 0000000..167177b
--- /dev/null
@@ -0,0 +1,241 @@
+/* ownCloud Android client application
+ *   Copyright (C) 2012-2014 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 java.io.IOException;
+import java.security.GeneralSecurityException;
+import java.security.cert.X509Certificate;
+
+import android.app.Activity;
+import android.app.Dialog;
+import android.net.http.SslError;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.Window;
+import android.view.View.OnClickListener;
+import android.webkit.SslErrorHandler;
+import android.widget.Button;
+
+import com.actionbarsherlock.app.SherlockDialogFragment;
+import com.owncloud.android.R;
+import com.owncloud.android.lib.common.network.CertificateCombinedException;
+import com.owncloud.android.lib.common.network.NetworkUtils;
+import com.owncloud.android.lib.common.utils.Log_OC;
+import com.owncloud.android.ui.adapter.CertificateCombinedExceptionViewAdapter;
+import com.owncloud.android.ui.adapter.SslCertificateViewAdapter;
+import com.owncloud.android.ui.adapter.SslErrorViewAdapter;
+import com.owncloud.android.ui.adapter.X509CertificateViewAdapter;
+
+/**
+ * Dialog to show information about an untrusted certificate and allow the user
+ * 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
+ */
+public class SslUntrustedCertDialog extends SherlockDialogFragment {
+    
+    private final static String TAG = SslUntrustedCertDialog.class.getSimpleName();
+    
+    protected View mView = null;
+    protected SslErrorHandler mHandler = null;
+    protected X509Certificate m509Certificate = null;
+
+    private ErrorViewAdapter mErrorViewAdapter = null;
+    private CertificateViewAdapter mCertificateViewAdapter = null;
+    
+    public static SslUntrustedCertDialog newInstanceForEmptySslError(SslError error, SslErrorHandler handler) {
+        if (error == null) {
+            throw new IllegalArgumentException("Trying to create instance with parameter error == null");
+        }
+        if (handler == null) {
+            throw new IllegalArgumentException("Trying to create instance with parameter handler == null");
+        }
+        SslUntrustedCertDialog dialog = new SslUntrustedCertDialog();
+        dialog.mHandler = handler;
+        dialog.mErrorViewAdapter = new SslErrorViewAdapter(error);
+        dialog.mCertificateViewAdapter = new SslCertificateViewAdapter(error.getCertificate());
+        return dialog;
+    }
+    
+    public static SslUntrustedCertDialog newInstanceForFullSslError(CertificateCombinedException sslException) {
+        if (sslException == null) {
+            throw new IllegalArgumentException("Trying to create instance with parameter sslException == null");
+        }
+        SslUntrustedCertDialog dialog = new SslUntrustedCertDialog();
+        dialog.m509Certificate = sslException.getServerCertificate();
+        dialog.mErrorViewAdapter = new CertificateCombinedExceptionViewAdapter(sslException);
+        dialog.mCertificateViewAdapter = new X509CertificateViewAdapter(sslException.getServerCertificate());
+        return dialog;
+    }
+    
+    public static SslUntrustedCertDialog newInstanceForFullSslError(X509Certificate cert, SslError error, SslErrorHandler handler) {
+        if (cert == null) {
+            throw new IllegalArgumentException("Trying to create instance with parameter cert == null");
+        }
+        if (error == null) {
+            throw new IllegalArgumentException("Trying to create instance with parameter error == null");
+        }
+        if (handler == null) {
+            throw new IllegalArgumentException("Trying to create instance with parameter handler == null");
+        }
+        SslUntrustedCertDialog dialog = new SslUntrustedCertDialog();
+        dialog.m509Certificate = cert;
+        dialog.mHandler = handler;
+        dialog.mErrorViewAdapter = new SslErrorViewAdapter(error);
+        dialog.mCertificateViewAdapter = new X509CertificateViewAdapter(cert);
+        return dialog;
+    }
+    
+    
+    @Override
+    public void onAttach(Activity activity) {
+        Log_OC.d(TAG, "onAttach");
+        super.onAttach(activity);
+        if (!(activity instanceof OnSslUntrustedCertListener)) {
+            throw new IllegalArgumentException("The host activity must implement " + OnSslUntrustedCertListener.class.getCanonicalName());
+        }
+    }
+
+    
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        Log_OC.d(TAG, "onCreate, savedInstanceState is " + savedInstanceState);
+        super.onCreate(savedInstanceState);
+        setRetainInstance(true);    // force to keep the state of the fragment on configuration changes (such as device rotations)
+        setCancelable(false);
+        mView = null;
+    }
+    
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+        Log_OC.d(TAG, "onCreateView, savedInsanceState is " + savedInstanceState);
+        // Create a view by inflating desired layout
+        if (mView == null) {
+            mView = inflater.inflate(R.layout.ssl_untrusted_cert_layout, container,  false);
+            mView.findViewById(R.id.details_scroll).setVisibility(View.GONE);
+            mErrorViewAdapter.updateErrorView(mView);
+        } else {
+            ((ViewGroup)mView.getParent()).removeView(mView);
+        }
+        
+        Button ok = (Button) mView.findViewById(R.id.ok);
+        ok.setOnClickListener(new OnCertificateTrusted());
+        
+        Button cancel = (Button) mView.findViewById(R.id.cancel);
+        cancel.setOnClickListener(new OnCertificateNotTrusted());
+        
+        Button details = (Button) mView.findViewById(R.id.details_btn);
+        details.setOnClickListener(new OnClickListener() {
+
+            @Override
+            public void onClick(View v) {
+                View detailsScroll = mView.findViewById(R.id.details_scroll);
+                if (detailsScroll.getVisibility() == View.VISIBLE) {
+                    detailsScroll.setVisibility(View.GONE);
+                    ((Button) v).setText(R.string.ssl_validator_btn_details_see);
+
+                } else {
+                    detailsScroll.setVisibility(View.VISIBLE);
+                    ((Button) v).setText(R.string.ssl_validator_btn_details_hide);
+                    mCertificateViewAdapter.updateCertificateView(mView);
+                }
+            }
+
+        });
+        
+        return mView;
+    }
+    
+
+    @Override
+    public Dialog onCreateDialog(Bundle savedInstanceState) {
+        Log_OC.d(TAG, "onCreateDialog, savedInstanceState is " + savedInstanceState);
+        final Dialog dialog = super.onCreateDialog(savedInstanceState);
+        dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
+        return dialog;
+    }
+
+    @Override
+    public void onDestroyView() {
+        Log_OC.d(TAG, "onDestroyView");
+        if (getDialog() != null && getRetainInstance())
+            getDialog().setDismissMessage(null);
+        super.onDestroyView();
+    }
+    
+    private class OnCertificateNotTrusted implements OnClickListener {
+        
+        @Override
+        public void onClick(View v) {
+            getDialog().cancel();
+            if (mHandler != null) {
+                mHandler.cancel();
+            }
+            ((OnSslUntrustedCertListener)getSherlockActivity()).onCancelCertificate();
+        }
+    }
+    
+    
+    private class OnCertificateTrusted implements OnClickListener {
+
+        @Override
+        public void onClick(View v) {
+            dismiss();
+            if (mHandler != null) {
+                mHandler.proceed();
+            }
+            if (m509Certificate != null) {
+                Activity activity = getSherlockActivity();
+                try {
+                    NetworkUtils.addCertToKnownServersStore(m509Certificate, activity);   // TODO make this asynchronously, it can take some time
+                    ((OnSslUntrustedCertListener)activity).onSavedCertificate();
+    
+                } catch (GeneralSecurityException e) {
+                    ((OnSslUntrustedCertListener)activity).onFailedSavingCertificate();
+                    Log_OC.e(TAG, "Server certificate could not be saved in the known-servers trust store ", e);
+                  
+                } catch (IOException e) {
+                    ((OnSslUntrustedCertListener)activity).onFailedSavingCertificate();
+                    Log_OC.e(TAG, "Server certificate could not be saved in the known-servers trust store ", e);
+                }
+            }
+        }
+        
+    }
+    
+    
+    public interface OnSslUntrustedCertListener {
+        public void onSavedCertificate();
+        public void onFailedSavingCertificate();
+        public void onCancelCertificate();
+    }
+    
+    public interface ErrorViewAdapter {
+        void updateErrorView(View mView);
+    }
+    
+    public interface CertificateViewAdapter {
+        void updateCertificateView(View mView);
+    }
+    
+}
index 1ccc8fa..db20a5c 100644 (file)
@@ -29,11 +29,7 @@ import java.util.Map;
 
 import javax.security.auth.x500.X500Principal;
 
-import com.owncloud.android.Log_OC;
 import com.owncloud.android.R;
-import com.owncloud.android.network.CertificateCombinedException;
-import com.owncloud.android.network.OwnCloudClientUtils;
-import com.owncloud.android.operations.RemoteOperationResult;
 
 import android.app.Dialog;
 import android.content.Context;
@@ -43,6 +39,10 @@ import android.view.Window;
 import android.widget.Button;
 import android.widget.TextView;
 
+import com.owncloud.android.lib.common.network.CertificateCombinedException;
+import com.owncloud.android.lib.common.network.NetworkUtils;
+import com.owncloud.android.lib.common.operations.RemoteOperationResult;
+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.
@@ -223,6 +223,7 @@ public class SslValidatorDialog extends Dialog {
         return hex.toString();
      }    
 
+    @SuppressWarnings("deprecation")
     private void showValidity(Date notBefore, Date notAfter) {
         TextView fromView = ((TextView)mView.findViewById(R.id.value_validity_from));
         TextView toView = ((TextView)mView.findViewById(R.id.value_validity_to));
@@ -343,7 +344,7 @@ public class SslValidatorDialog extends Dialog {
     private void saveServerCert() throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException {
         if (mException.getServerCertificate() != null) {
             // TODO make this asynchronously, it can take some time
-            OwnCloudClientUtils.addCertToKnownServersStore(mException.getServerCertificate(), getContext());
+            NetworkUtils.addCertToKnownServersStore(mException.getServerCertificate(), getContext());
         }
     }
 
diff --git a/src/com/owncloud/android/ui/fragment/ConfirmationDialogFragment.java b/src/com/owncloud/android/ui/fragment/ConfirmationDialogFragment.java
deleted file mode 100644 (file)
index 869cb26..0000000
+++ /dev/null
@@ -1,126 +0,0 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012 Bartek Przybylski
- *   Copyright (C) 2012-2013 ownCloud Inc.
- *
- *   This program is free software: you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License version 2,
- *   as published by the Free Software Foundation.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-package com.owncloud.android.ui.fragment;
-
-import android.app.AlertDialog;
-import android.app.Dialog;
-import android.content.DialogInterface;
-import android.os.Bundle;
-
-import com.actionbarsherlock.app.SherlockDialogFragment;
-import com.owncloud.android.Log_OC;
-
-
-public class ConfirmationDialogFragment extends SherlockDialogFragment {
-
-    public final static String ARG_CONF_RESOURCE_ID = "resource_id";
-    public final static String ARG_CONF_ARGUMENTS = "string_array";
-    
-    public final static String ARG_POSITIVE_BTN_RES = "positive_btn_res";
-    public final static String ARG_NEUTRAL_BTN_RES = "neutral_btn_res";
-    public final static String ARG_NEGATIVE_BTN_RES = "negative_btn_res";
-    
-    public static final String FTAG_CONFIRMATION = "CONFIRMATION_FRAGMENT";
-
-    private ConfirmationDialogFragmentListener mListener;
-    
-    /**
-     * Public factory method to create new ConfirmationDialogFragment instances.
-     * 
-     * @param string_id         Resource id for a message to show in the dialog.
-     * @param arguments         Arguments to complete the message, if it's a format string.
-     * @param posBtn            Resource id for the text of the positive button.
-     * @param neuBtn            Resource id for the text of the neutral button.
-     * @param negBtn            Resource id for the text of the negative button.
-     * @return                  Dialog ready to show.
-     */
-    public static ConfirmationDialogFragment newInstance(int string_id, String[] arguments, int posBtn, int neuBtn, int negBtn) {
-        ConfirmationDialogFragment frag = new ConfirmationDialogFragment();
-        Bundle args = new Bundle();
-        args.putInt(ARG_CONF_RESOURCE_ID, string_id);
-        args.putStringArray(ARG_CONF_ARGUMENTS, arguments);
-        args.putInt(ARG_POSITIVE_BTN_RES, posBtn);
-        args.putInt(ARG_NEUTRAL_BTN_RES, neuBtn);
-        args.putInt(ARG_NEGATIVE_BTN_RES, negBtn);
-        frag.setArguments(args);
-        return frag;
-    }
-    
-    public void setOnConfirmationListener(ConfirmationDialogFragmentListener listener) {
-        mListener = listener;
-    }
-
-    @Override
-    public Dialog onCreateDialog(Bundle savedInstanceState) {
-        Object[] confirmationTarget = getArguments().getStringArray(ARG_CONF_ARGUMENTS);
-        int resourceId = getArguments().getInt(ARG_CONF_RESOURCE_ID, -1);
-        int posBtn = getArguments().getInt(ARG_POSITIVE_BTN_RES, -1);
-        int neuBtn = getArguments().getInt(ARG_NEUTRAL_BTN_RES, -1);
-        int negBtn = getArguments().getInt(ARG_NEGATIVE_BTN_RES, -1);
-        
-        if (confirmationTarget == null || resourceId == -1) {
-            Log_OC.wtf(getTag(), "Calling confirmation dialog without resource or arguments");
-            return null;
-        }
-
-        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity())
-            .setIcon(android.R.drawable.ic_dialog_alert)
-            .setMessage(String.format(getString(resourceId), confirmationTarget))
-            .setTitle(android.R.string.dialog_alert_title);
-        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) {
-            builder.setIconAttribute(android.R.attr.alertDialogIcon);
-        }
-        
-        if (posBtn != -1)
-            builder.setPositiveButton(posBtn,
-                    new DialogInterface.OnClickListener() {
-                        public void onClick(DialogInterface dialog, int whichButton) {
-                            mListener.onConfirmation(getTag()); 
-                            dialog.dismiss();
-                        }
-                    });
-        if (neuBtn != -1)
-            builder.setNeutralButton(neuBtn,
-                    new DialogInterface.OnClickListener() {
-                        public void onClick(DialogInterface dialog, int whichButton) {
-                            mListener.onNeutral(getTag()); 
-                            dialog.dismiss();
-                        }
-                    });
-        if (negBtn != -1)
-            builder.setNegativeButton(negBtn,
-                    new DialogInterface.OnClickListener() {
-                        @Override
-                        public void onClick(DialogInterface dialog, int which) {
-                            mListener.onCancel(getTag());
-                            dialog.dismiss();
-                        }
-                    });
-      return builder.create();
-    }
-    
-    
-    public interface ConfirmationDialogFragmentListener {
-        public void onConfirmation(String callerTag);
-        public void onNeutral(String callerTag);
-        public void onCancel(String callerTag);
-    }
-    
-}
-
index a57fb09..5d3f7ac 100644 (file)
 
 package com.owncloud.android.ui.fragment;
 
-import com.actionbarsherlock.app.SherlockFragment;
-import com.owncloud.android.Log_OC;
-import com.owncloud.android.R;
-import com.owncloud.android.ui.ExtendedListView;
-
+import java.util.ArrayList;
 
 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.AdapterView;
-import android.widget.ListAdapter;
 import android.widget.AdapterView.OnItemClickListener;
+import android.widget.ListAdapter;
 import android.widget.ListView;
+import android.widget.TextView;
+
+import com.actionbarsherlock.app.SherlockFragment;
+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;
 
 /**
  *  TODO extending SherlockListFragment instead of SherlockFragment 
  */
-public class ExtendedListFragment extends SherlockFragment implements OnItemClickListener {
+public class ExtendedListFragment extends SherlockFragment 
+implements OnItemClickListener, OnEnforceableRefreshListener {
     
     private static final String TAG = ExtendedListFragment.class.getSimpleName();
 
     private static final String KEY_SAVED_LIST_POSITION = "SAVED_LIST_POSITION"; 
+    private static final String KEY_INDEXES = "INDEXES";
+    private static final String KEY_FIRST_POSITIONS= "FIRST_POSITIONS";
+    private static final String KEY_TOPS = "TOPS";
+    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 mRefreshEmptyLayout;
+    private TextView mEmptyListMessage;
+    
+    // Save the state of the scroll in browsing
+    private ArrayList<Integer> mIndexes;
+    private ArrayList<Integer> mFirstPositions;
+    private ArrayList<Integer> mTops;
+    private int mHeightCell = 0;
+
+    private OnEnforceableRefreshListener mOnRefreshListener = null;
+    
+    
     public void setListAdapter(ListAdapter listAdapter) {
         mList.setAdapter(listAdapter);
         mList.invalidate();
@@ -57,11 +80,12 @@ public class ExtendedListFragment extends SherlockFragment implements OnItemClic
     @Override
     public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
         Log_OC.e(TAG, "onCreateView");
-        //mList = new ExtendedListView(getActivity());
+        
         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.setEmptyView(v.findViewById(R.id.empty_list_view));     // looks like it's not a cool idea 
+
         mList.setDivider(getResources().getDrawable(R.drawable.uploader_list_separator));
         mList.setDividerHeight(1);
 
@@ -70,15 +94,52 @@ public class ExtendedListFragment extends SherlockFragment implements OnItemClic
             setReferencePosition(referencePosition);
         }
         
+        // Pull down refresh
+        mRefreshLayout = (SwipeRefreshLayout) v.findViewById(R.id.swipe_refresh_files);
+        mRefreshEmptyLayout = (SwipeRefreshLayout) v.findViewById(R.id.swipe_refresh_files_emptyView);
+        
+        onCreateSwipeToRefresh(mRefreshLayout);
+        onCreateSwipeToRefresh(mRefreshEmptyLayout);
+        
+        mList.setEmptyView(mRefreshEmptyLayout);
+
         return v;
     }
 
     
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void onActivityCreated(Bundle savedInstanceState) {
+        super.onActivityCreated(savedInstanceState);
+        
+        if (savedInstanceState != null) {
+            mIndexes = savedInstanceState.getIntegerArrayList(KEY_INDEXES);
+            mFirstPositions = savedInstanceState.getIntegerArrayList(KEY_FIRST_POSITIONS);
+            mTops = savedInstanceState.getIntegerArrayList(KEY_TOPS);
+            mHeightCell = savedInstanceState.getInt(KEY_HEIGHT_CELL);
+            setMessageForEmptyList(savedInstanceState.getString(KEY_EMPTY_LIST_MESSAGE));
+            
+        } else {
+            mIndexes = new ArrayList<Integer>();
+            mFirstPositions = new ArrayList<Integer>();
+            mTops = new ArrayList<Integer>();
+            mHeightCell = 0;
+        }
+    }    
+    
+    
     @Override
     public void onSaveInstanceState(Bundle savedInstanceState) {
         super.onSaveInstanceState(savedInstanceState);
         Log_OC.e(TAG, "onSaveInstanceState()");
         savedInstanceState.putInt(KEY_SAVED_LIST_POSITION, getReferencePosition());
+        savedInstanceState.putIntegerArrayList(KEY_INDEXES, mIndexes);
+        savedInstanceState.putIntegerArrayList(KEY_FIRST_POSITIONS, mFirstPositions);
+        savedInstanceState.putIntegerArrayList(KEY_TOPS, mTops);
+        savedInstanceState.putInt(KEY_HEIGHT_CELL, mHeightCell);
+        savedInstanceState.putString(KEY_EMPTY_LIST_MESSAGE, getEmptyViewText());
     }
 
     
@@ -110,10 +171,143 @@ public class ExtendedListFragment extends SherlockFragment implements OnItemClic
         }
     }
 
+
+    /*
+     * Restore index and position
+     */
+    protected void restoreIndexAndTopPosition() {
+        if (mIndexes.size() > 0) {  
+            // 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);
+            
+            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); 
+                }
+                else if (android.os.Build.VERSION.SDK_INT >= 8)
+                {
+                    mList.setSelectionFromTop(index, 0);
+                }
+                
+            }
+        }
+    }
+    
+    /*
+     * Save index and top position
+     */
+    protected void saveIndexAndTopPosition(int index) {
+        
+        mIndexes.add(index);
+        
+        int firstPosition = mList.getFirstVisiblePosition();
+        mFirstPositions.add(firstPosition);
+        
+        View view = mList.getChildAt(0);
+        int top = (view == null) ? 0 : view.getTop() ;
+
+        mTops.add(top);
+        
+        // Save the height of a cell
+        mHeightCell = (view == null || mHeightCell != 0) ? mHeightCell : view.getHeight();
+    }
+    
+    
     @Override
-    public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
+    public void onItemClick (AdapterView<?> parent, View view, int position, long id) {
         // to be @overriden  
     }
 
+    @Override
+    public void onRefresh() {
+        // to be @overriden
+        mRefreshLayout.setRefreshing(false);
+        mRefreshEmptyLayout.setRefreshing(false);
+        
+        if (mOnRefreshListener != null) {
+            mOnRefreshListener.onRefresh();
+        }
+    }
+    
+    public void setOnRefreshListener(OnEnforceableRefreshListener listener) {
+        mOnRefreshListener = listener;
+    }
+    
+
+    /**
+     * 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
+     */
+    public void hideSwipeProgress() {
+        mRefreshLayout.setRefreshing(false);
+    }
+
+    /**
+     * Set message for empty list view
+     */
+    public void setMessageForEmptyList(String message) {
+        if (mEmptyListMessage != null) {
+            mEmptyListMessage.setText(message);
+        }
+    }
+
+    /**
+     * Get the text of EmptyListMessage TextView
+     * 
+     * @return String
+     */
+    public String getEmptyViewText() {
+        return (mEmptyListMessage != null) ? mEmptyListMessage.getText().toString() : "";
+    }
+
+    private void onCreateSwipeToRefresh(SwipeRefreshLayout refreshLayout) {
+        // Colors in animations: background
+        refreshLayout.setColorScheme(R.color.background_color, R.color.background_color, R.color.background_color,
+                R.color.background_color);
+
+        refreshLayout.setOnRefreshListener(this);
+    }
+
+    @Override
+    public void onRefresh(boolean ignoreETag) {
+        mRefreshLayout.setRefreshing(false);
+        mRefreshEmptyLayout.setRefreshing(false);
+
+        if (mOnRefreshListener != null) {
+            mOnRefreshListener.onRefresh(ignoreETag);
+        }
+    }
 }
index af73766..2ff2925 100644 (file)
  */
 package com.owncloud.android.ui.fragment;
 
-import java.io.File;
 import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-import java.util.List;
 
 import android.accounts.Account;
-import android.app.Activity;
-import android.content.BroadcastReceiver;
-import android.content.Context;
 import android.content.Intent;
-import android.content.IntentFilter;
 import android.os.Bundle;
-import android.os.Handler;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.View.OnClickListener;
@@ -38,62 +30,43 @@ import android.widget.CheckBox;
 import android.widget.ImageView;
 import android.widget.ProgressBar;
 import android.widget.TextView;
-import android.widget.Toast;
 
 import com.actionbarsherlock.view.Menu;
 import com.actionbarsherlock.view.MenuInflater;
 import com.actionbarsherlock.view.MenuItem;
-import com.owncloud.android.DisplayUtils;
-import com.owncloud.android.Log_OC;
 import com.owncloud.android.R;
 import com.owncloud.android.datamodel.FileDataStorageManager;
 import com.owncloud.android.datamodel.OCFile;
-import com.owncloud.android.files.services.FileObserverService;
-import com.owncloud.android.files.services.FileUploader;
+import com.owncloud.android.files.FileMenuFilter;
 import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder;
 import com.owncloud.android.files.services.FileUploader.FileUploaderBinder;
-import com.owncloud.android.operations.OnRemoteOperationListener;
-import com.owncloud.android.operations.RemoteOperation;
-import com.owncloud.android.operations.RemoteOperationResult;
-import com.owncloud.android.operations.RemoveFileOperation;
-import com.owncloud.android.operations.RenameFileOperation;
-import com.owncloud.android.operations.SynchronizeFileOperation;
-import com.owncloud.android.operations.RemoteOperationResult.ResultCode;
-import com.owncloud.android.ui.activity.ConflictsResolveActivity;
+import com.owncloud.android.lib.common.network.OnDatatransferProgressListener;
+import com.owncloud.android.lib.common.utils.Log_OC;
+import com.owncloud.android.services.observer.FileObserverService;
 import com.owncloud.android.ui.activity.FileActivity;
 import com.owncloud.android.ui.activity.FileDisplayActivity;
-import com.owncloud.android.ui.dialog.EditNameDialog;
-import com.owncloud.android.ui.dialog.EditNameDialog.EditNameDialogListener;
-import com.owncloud.android.ui.preview.PreviewImageFragment;
+import com.owncloud.android.ui.dialog.RemoveFileDialogFragment;
+import com.owncloud.android.ui.dialog.RenameFileDialogFragment;
+import com.owncloud.android.utils.DisplayUtils;
 
 
-import eu.alefzero.webdav.OnDatatransferProgressListener;
-
 /**
  * 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, 
-        ConfirmationDialogFragment.ConfirmationDialogFragmentListener, OnRemoteOperationListener, EditNameDialogListener {
+public class FileDetailFragment extends FileFragment implements OnClickListener {
 
-    private FileFragment.ContainerActivity mContainerActivity;
-    
     private int mLayout;
     private View mView;
     private Account mAccount;
-    private FileDataStorageManager mStorageManager;
     
-    private UploadFinishReceiver mUploadFinishReceiver;
     public ProgressListener mProgressListener;
     
-    private Handler mHandler;
-    private RemoteOperation mLastRemoteOperation;
-    
     private static final String TAG = FileDetailFragment.class.getSimpleName();
     public static final String FTAG_CONFIRMATION = "REMOVE_CONFIRMATION_FRAGMENT";
+    public static final String FTAG_RENAME_FILE = "RENAME_FILE_FRAGMENT";
     
 
     /**
@@ -104,7 +77,6 @@ public class FileDetailFragment extends FileFragment implements
     public FileDetailFragment() {
         super();
         mAccount = null;
-        mStorageManager = null;
         mLayout = R.layout.file_details_empty;
         mProgressListener = null;
     }
@@ -120,16 +92,14 @@ public class FileDetailFragment extends FileFragment implements
     public FileDetailFragment(OCFile fileToDetail, Account ocAccount) {
         super(fileToDetail);
         mAccount = ocAccount;
-        mStorageManager = null; // we need a context to init this; the container activity is not available yet at this moment 
         mLayout = R.layout.file_details_empty;
         mProgressListener = null;
     }
     
     
     @Override
-    public void onCreate(Bundle savedInstanceState) {
+    public void onActivityCreated(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        mHandler = new Handler();
         setHasOptionsMenu(true);
     }
     
@@ -137,7 +107,6 @@ public class FileDetailFragment extends FileFragment implements
     @Override
     public View onCreateView(LayoutInflater inflater, ViewGroup container,
             Bundle savedInstanceState) {
-        //super.onCreateView(inflater, container, savedInstanceState);
         
         if (savedInstanceState != null) {
             setFile((OCFile)savedInstanceState.getParcelable(FileActivity.EXTRA_FILE));
@@ -149,7 +118,6 @@ public class FileDetailFragment extends FileFragment implements
         }
         
         View view = null;
-        //view = inflater.inflate(mLayout, container, false);
         view = inflater.inflate(mLayout, null);
         mView = view;
         
@@ -163,33 +131,6 @@ public class FileDetailFragment extends FileFragment implements
         updateFileDetails(false, false);
         return view;
     }
-    
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void onAttach(Activity activity) {
-        super.onAttach(activity);
-        try {
-            mContainerActivity = (ContainerActivity) activity;
-            
-        } catch (ClassCastException e) {
-            throw new ClassCastException(activity.toString() + " must implement " + FileDetailFragment.ContainerActivity.class.getSimpleName());
-        }
-    }
-    
-    
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void onActivityCreated(Bundle savedInstanceState) {
-        super.onActivityCreated(savedInstanceState);
-        if (mAccount != null) {
-            mStorageManager = new FileDataStorageManager(mAccount, getActivity().getApplicationContext().getContentResolver());
-        }
-    }
-        
 
     @Override
     public void onSaveInstanceState(Bundle outState) {
@@ -205,29 +146,9 @@ public class FileDetailFragment extends FileFragment implements
     }
     
     @Override
-    public void onResume() {
-        super.onResume();
-        mUploadFinishReceiver = new UploadFinishReceiver();
-        IntentFilter filter = new IntentFilter(FileUploader.getUploadFinishMessage());
-        getActivity().registerReceiver(mUploadFinishReceiver, filter);
-
-    }
-
-
-    @Override
-    public void onPause() {
-        super.onPause();
-        if (mUploadFinishReceiver != null) {
-            getActivity().unregisterReceiver(mUploadFinishReceiver);
-            mUploadFinishReceiver = null;
-        }
-    }
-
-    
-    @Override
     public void onStop() {
-        super.onStop();
         leaveTransferProgress();
+        super.onStop();
     }
 
     
@@ -244,12 +165,7 @@ public class FileDetailFragment extends FileFragment implements
     public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
         super.onCreateOptionsMenu(menu, inflater);
         inflater.inflate(R.menu.file_actions_menu, menu);
-        MenuItem item = menu.findItem(R.id.action_see_details);
-        if (item != null) {
-            item.setVisible(false);
-            item.setEnabled(false);
-        }
-    }
+   }
 
     
     /**
@@ -259,73 +175,28 @@ public class FileDetailFragment extends FileFragment implements
     public void onPrepareOptionsMenu (Menu menu) {
         super.onPrepareOptionsMenu(menu);
         
-        List<Integer> toHide = new ArrayList<Integer>();
-        List<Integer> toShow = new ArrayList<Integer>();
-        OCFile file = getFile();
-        
-        FileDownloaderBinder downloaderBinder = mContainerActivity.getFileDownloaderBinder();
-        boolean downloading = downloaderBinder != null && downloaderBinder.isDownloading(mAccount, file);
-        FileUploaderBinder uploaderBinder = mContainerActivity.getFileUploaderBinder();
-        boolean uploading = uploaderBinder != null && uploaderBinder.isUploading(mAccount, getFile());
+        if (mContainerActivity.getStorageManager() != null) {
+            FileMenuFilter mf = new FileMenuFilter(
+                getFile(),
+                mContainerActivity.getStorageManager().getAccount(),
+                mContainerActivity,
+                getSherlockActivity()
+            );
+            mf.filter(menu);
+        }
         
-        if (downloading || uploading) {
-            toHide.add(R.id.action_download_file);
-            toHide.add(R.id.action_rename_file);
-            toHide.add(R.id.action_remove_file);
-            toHide.add(R.id.action_open_file_with);
-            if (!downloading) {
-                toHide.add(R.id.action_cancel_download);
-                toShow.add(R.id.action_cancel_upload);
-            } else {
-                toHide.add(R.id.action_cancel_upload);
-                toShow.add(R.id.action_cancel_download);
-            }
-
-        } else if (file != null && file.isDown()) {
-            toHide.add(R.id.action_download_file);
-            toHide.add(R.id.action_cancel_download);
-            toHide.add(R.id.action_cancel_upload);
-            
-            toShow.add(R.id.action_rename_file);
-            toShow.add(R.id.action_remove_file);
-            toShow.add(R.id.action_open_file_with);
-            toShow.add(R.id.action_sync_file);
-            
-        } else if (file != null) {
-            toHide.add(R.id.action_open_file_with);
-            toHide.add(R.id.action_cancel_download);
-            toHide.add(R.id.action_cancel_upload);
-            toHide.add(R.id.action_sync_file);
-            
-            toShow.add(R.id.action_rename_file);
-            toShow.add(R.id.action_remove_file);
-            toShow.add(R.id.action_download_file);
-            
-        } else {
-            toHide.add(R.id.action_open_file_with);
-            toHide.add(R.id.action_cancel_download);
-            toHide.add(R.id.action_cancel_upload);
-            toHide.add(R.id.action_sync_file);
-            toHide.add(R.id.action_download_file);
-            toHide.add(R.id.action_rename_file);
-            toHide.add(R.id.action_remove_file);
-            
+        // additional restriction for this fragment 
+        MenuItem item = menu.findItem(R.id.action_see_details);
+        if (item != null) {
+            item.setVisible(false);
+            item.setEnabled(false);
         }
 
-        MenuItem item = null;
-        for (int i : toHide) {
-            item = menu.findItem(i);
-            if (item != null) {
-                item.setVisible(false);
-                item.setEnabled(false);
-            }
-        }
-        for (int i : toShow) {
-            item = menu.findItem(i);
-            if (item != null) {
-                item.setVisible(true);
-                item.setEnabled(true);
-            }
+        // additional restriction for this fragment
+        item = menu.findItem(R.id.action_move);
+        if (item != null) {
+            item.setVisible(false);
+            item.setEnabled(false);
         }
     }
 
@@ -336,30 +207,54 @@ public class FileDetailFragment extends FileFragment implements
     @Override
     public boolean onOptionsItemSelected(MenuItem item) {
         switch (item.getItemId()) {
+            case R.id.action_share_file: {
+                mContainerActivity.getFileOperationsHelper().shareFileWithLink(getFile());
+                return true;
+            }
+            case R.id.action_unshare_file: {
+                mContainerActivity.getFileOperationsHelper().unshareFileWithLink(getFile());
+                return true;
+            }
             case R.id.action_open_file_with: {
-                mContainerActivity.openFile(getFile());
+                mContainerActivity.getFileOperationsHelper().openFile(getFile());
                 return true;
             }
             case R.id.action_remove_file: {
-                removeFile();
+                RemoveFileDialogFragment dialog = RemoveFileDialogFragment.newInstance(getFile());
+                dialog.show(getFragmentManager(), FTAG_CONFIRMATION);
                 return true;
             }
             case R.id.action_rename_file: {
-                renameFile();
+                RenameFileDialogFragment dialog = RenameFileDialogFragment.newInstance(getFile());
+                dialog.show(getFragmentManager(), FTAG_RENAME_FILE);
                 return true;
             }
-            case R.id.action_download_file: 
             case R.id.action_cancel_download:
-            case R.id.action_cancel_upload:
+            case R.id.action_cancel_upload: {
+                ((FileDisplayActivity)mContainerActivity).cancelTransference(getFile());
+                return true;
+            }
+            case R.id.action_download_file: 
             case R.id.action_sync_file: {
-                synchronizeFile();
+                mContainerActivity.getFileOperationsHelper().syncFile(getFile());
+                return true;
+            }
+            case R.id.action_send_file: {
+                // Obtain the file
+                if (!getFile().isDown()) {  // Download the file                    
+                    Log_OC.d(TAG, getFile().getRemotePath() + " : File must be downloaded");
+                    ((FileDisplayActivity)mContainerActivity).startDownloadForSending(getFile());
+                    
+                } else {
+                    mContainerActivity.getFileOperationsHelper().sendDownloadedFile(getFile());
+                }
                 return true;
             }
             default:
                 return false;
         }
     }
-    
+
     @Override
     public void onClick(View v) {
         switch (v.getId()) {
@@ -368,7 +263,7 @@ public class FileDetailFragment extends FileFragment implements
                 break;
             }
             case R.id.fdCancelBtn: {
-                synchronizeFile();
+                ((FileDisplayActivity)mContainerActivity).cancelTransference(getFile());
                 break;
             }
             default:
@@ -381,115 +276,22 @@ public class FileDetailFragment extends FileFragment implements
         CheckBox cb = (CheckBox) getView().findViewById(R.id.fdKeepInSync);
         OCFile file = getFile();
         file.setKeepInSync(cb.isChecked());
-        mStorageManager.saveFile(file);
+        mContainerActivity.getStorageManager().saveFile(file);
         
-        /// register the OCFile instance in the observer service to monitor local updates;
-        /// if necessary, the file is download 
-        Intent intent = new Intent(getActivity().getApplicationContext(),
-                                   FileObserverService.class);
-        intent.putExtra(FileObserverService.KEY_FILE_CMD,
-                   (cb.isChecked()?
-                           FileObserverService.CMD_ADD_OBSERVED_FILE:
-                           FileObserverService.CMD_DEL_OBSERVED_FILE));
-        intent.putExtra(FileObserverService.KEY_CMD_ARG_FILE, file);
-        intent.putExtra(FileObserverService.KEY_CMD_ARG_ACCOUNT, mAccount);
-        getActivity().startService(intent);
+        /// register the OCFile instance in the observer service to monitor local updates
+        Intent observedFileIntent = FileObserverService.makeObservedFileIntent(
+                getActivity(),
+                file, 
+                mAccount,
+                cb.isChecked());
+        getActivity().startService(observedFileIntent);
         
+        /// immediate content synchronization
         if (file.keepInSync()) {
-            synchronizeFile();   // force an immediate synchronization
-        }
-    }
-
-
-    private void removeFile() {
-        OCFile file = getFile();
-        ConfirmationDialogFragment confDialog = ConfirmationDialogFragment.newInstance(
-                R.string.confirmation_remove_alert,
-                new String[]{file.getFileName()},
-                file.isDown() ? R.string.confirmation_remove_remote_and_local : R.string.confirmation_remove_remote,
-                file.isDown() ? R.string.confirmation_remove_local : -1,
-                R.string.common_cancel);
-        confDialog.setOnConfirmationListener(this);
-        confDialog.show(getFragmentManager(), FTAG_CONFIRMATION);
-    }
-
-
-    private void renameFile() {
-        OCFile file = getFile();
-        String fileName = file.getFileName();
-        int extensionStart = file.isFolder() ? -1 : fileName.lastIndexOf(".");
-        int selectionEnd = (extensionStart >= 0) ? extensionStart : fileName.length();
-        EditNameDialog dialog = EditNameDialog.newInstance(getString(R.string.rename_dialog_title), fileName, 0, selectionEnd, this);
-        dialog.show(getFragmentManager(), "nameeditdialog");
-    }
-
-    private void synchronizeFile() {
-        OCFile file = getFile();
-        FileDownloaderBinder downloaderBinder = mContainerActivity.getFileDownloaderBinder();
-        FileUploaderBinder uploaderBinder = mContainerActivity.getFileUploaderBinder();
-        if (downloaderBinder != null && downloaderBinder.isDownloading(mAccount, file)) {
-            downloaderBinder.cancel(mAccount, file);
-            if (file.isDown()) {
-                setButtonsForDown();
-            } else {
-                setButtonsForRemote();
-            }
-
-        } else if (uploaderBinder != null && uploaderBinder.isUploading(mAccount, file)) {
-            uploaderBinder.cancel(mAccount, file);
-            if (!file.fileExists()) {
-                // TODO make something better
-                ((FileDisplayActivity)getActivity()).cleanSecondFragment();
-                
-            } else if (file.isDown()) {
-                setButtonsForDown();
-            } else {
-                setButtonsForRemote();
-            }
-            
-        } else {
-            mLastRemoteOperation = new SynchronizeFileOperation(file, null, mStorageManager, mAccount, true, getActivity());
-            mLastRemoteOperation.execute(mAccount, getSherlockActivity(), this, mHandler, getSherlockActivity());
-            
-            // update ui 
-            ((FileDisplayActivity) getActivity()).showLoadingDialog();
-            
+            mContainerActivity.getFileOperationsHelper().syncFile(getFile());
         }
     }
 
-    @Override
-    public void onConfirmation(String callerTag) {
-        OCFile file = getFile();
-        if (callerTag.equals(FTAG_CONFIRMATION)) {
-            if (mStorageManager.getFileById(file.getFileId()) != null) {
-                mLastRemoteOperation = new RemoveFileOperation( file, 
-                                                                true, 
-                                                                mStorageManager);
-                mLastRemoteOperation.execute(mAccount, getSherlockActivity(), this, mHandler, getSherlockActivity());
-                                
-                ((FileDisplayActivity) getActivity()).showLoadingDialog();
-            }
-        }
-    }
-    
-    @Override
-    public void onNeutral(String callerTag) {
-        File f = null;
-        OCFile file = getFile();
-        if (file.isDown() && (f = new File(file.getStoragePath())).exists()) {
-            f.delete();
-            file.setStoragePath(null);
-            mStorageManager.saveFile(file);
-            updateFileDetails(file, mAccount);
-        }
-    }
-    
-    @Override
-    public void onCancel(String callerTag) {
-        Log_OC.d(TAG, "REMOVAL CANCELED");
-    }
-    
-    
     /**
      * Check if the fragment was created with an empty layout. An empty fragment can't show file details, must be replaced.
      * 
@@ -507,12 +309,6 @@ public class FileDetailFragment extends FileFragment implements
      */
     public void updateFileDetails(OCFile file, Account ocAccount) {
         setFile(file);
-        if (ocAccount != null && ( 
-                mStorageManager == null || 
-                (mAccount != null && !mAccount.equals(ocAccount))
-           )) {
-            mStorageManager = new FileDataStorageManager(ocAccount, getActivity().getApplicationContext().getContentResolver());
-        }
         mAccount = ocAccount;
         updateFileDetails(false, false);
     }
@@ -522,26 +318,23 @@ public class FileDetailFragment extends FileFragment implements
      *
      * TODO Remove parameter when the transferring state of files is kept in database. 
      * 
-     * TODO REFACTORING! this method called 5 times before every time the fragment is shown! 
-     * 
      * @param transferring      Flag signaling if the file should be considered as downloading or uploading, 
      *                          although {@link FileDownloaderBinder#isDownloading(Account, OCFile)}  and 
      *                          {@link FileUploaderBinder#isUploading(Account, OCFile)} return false.
      *                          
-     * @param refresh           If 'true', try to refresh the hold file from the database
+     * @param refresh           If 'true', try to refresh the whole file from the database
      */
     public void updateFileDetails(boolean transferring, boolean refresh) {
-
         if (readyToShow()) {
-            
-            if (refresh && mStorageManager != null) {
-                setFile(mStorageManager.getFileByPath(getFile().getRemotePath()));
+            FileDataStorageManager storageManager = mContainerActivity.getStorageManager();
+            if (refresh && storageManager != null) {
+                setFile(storageManager.getFileByPath(getFile().getRemotePath()));
             }
             OCFile file = getFile();
             
             // set file details
             setFilename(file.getFileName());
-            setFiletype(file.getMimetype());
+            setFiletype(file.getMimetype(), file.getFileName());
             setFilesize(file.getFileLength());
             if(ocVersionSupportsTimeCreated()){
                 setTimeCreated(file.getCreationTimestamp());
@@ -553,7 +346,6 @@ public class FileDetailFragment extends FileFragment implements
             cb.setChecked(file.keepInSync());
 
             // configure UI for depending upon local state of the file
-            //if (FileDownloader.isDownloading(mAccount, mFile.getRemotePath()) || FileUploader.isUploading(mAccount, mFile.getRemotePath())) {
             FileDownloaderBinder downloaderBinder = mContainerActivity.getFileDownloaderBinder();
             FileUploaderBinder uploaderBinder = mContainerActivity.getFileUploaderBinder();
             if (transferring || (downloaderBinder != null && downloaderBinder.isDownloading(mAccount, file)) || (uploaderBinder != null && uploaderBinder.isUploading(mAccount, file))) {
@@ -594,8 +386,9 @@ public class FileDetailFragment extends FileFragment implements
     /**
      * Updates the MIME type in view
      * @param mimetype to set
+     * @param filename
      */
-    private void setFiletype(String mimetype) {
+    private void setFiletype(String mimetype, String filename) {
         TextView tv = (TextView) getView().findViewById(R.id.fdType);
         if (tv != null) {
             String printableMimetype = DisplayUtils.convertMIMEtoPrettyPrint(mimetype);;        
@@ -603,7 +396,7 @@ public class FileDetailFragment extends FileFragment implements
         }
         ImageView iv = (ImageView) getView().findViewById(R.id.fdIcon);
         if (iv != null) {
-            iv.setImageResource(DisplayUtils.getResourceId(mimetype));
+            iv.setImageResource(DisplayUtils.getResourceId(mimetype, filename));
         }
     }
 
@@ -713,158 +506,6 @@ public class FileDetailFragment extends FileFragment implements
     }
     
 
-    /**
-     * Once the file upload has finished -> update view
-     * 
-     * Being notified about the finish of an upload is necessary for the next sequence:
-     *   1. Upload a big file.
-     *   2. Force a synchronization; if it finished before the upload, the file in transfer will be included in the local database and in the file list
-     *      of its containing folder; the the server includes it in the PROPFIND requests although it's not fully upload. 
-     *   3. Click the file in the list to see its details.
-     *   4. Wait for the upload finishes; at this moment, the details view must be refreshed to enable the action buttons.
-     */
-    private class UploadFinishReceiver extends BroadcastReceiver {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            String accountName = intent.getStringExtra(FileUploader.ACCOUNT_NAME);
-
-            if (!isEmpty() && accountName.equals(mAccount.name)) {
-                boolean uploadWasFine = intent.getBooleanExtra(FileUploader.EXTRA_UPLOAD_RESULT, false);
-                String uploadRemotePath = intent.getStringExtra(FileUploader.EXTRA_REMOTE_PATH);
-                boolean renamedInUpload = getFile().getRemotePath().equals(intent.getStringExtra(FileUploader.EXTRA_OLD_REMOTE_PATH));
-                if (getFile().getRemotePath().equals(uploadRemotePath) ||
-                    renamedInUpload) {
-                    if (uploadWasFine) {
-                        setFile(mStorageManager.getFileByPath(uploadRemotePath));
-                    }
-                    if (renamedInUpload) {
-                        String newName = (new File(uploadRemotePath)).getName();
-                        Toast msg = Toast.makeText(getActivity().getApplicationContext(), String.format(getString(R.string.filedetails_renamed_in_upload_msg), newName), Toast.LENGTH_LONG);
-                        msg.show();
-                    }
-                    getSherlockActivity().removeStickyBroadcast(intent);    // not the best place to do this; a small refactorization of BroadcastReceivers should be done
-                    
-                    updateFileDetails(false, false);    // it updates the buttons; must be called although !uploadWasFine; interrupted uploads still leave an incomplete file in the server
-                   
-                    // Force the preview if the file is an image
-                    if (uploadWasFine && PreviewImageFragment.canBePreviewed(getFile())) {
-                        ((FileDisplayActivity) mContainerActivity).startImagePreview(getFile());
-                    } 
-                }
-            }
-        }
-    }
-    
-
-    public void onDismiss(EditNameDialog dialog) {
-        if (dialog.getResult()) {
-            String newFilename = dialog.getNewFilename();
-            Log_OC.d(TAG, "name edit dialog dismissed with new name " + newFilename);
-            mLastRemoteOperation = new RenameFileOperation( getFile(), 
-                                                            mAccount, 
-                                                            newFilename, 
-                                                            new FileDataStorageManager(mAccount, getActivity().getContentResolver()));
-            mLastRemoteOperation.execute(mAccount, getSherlockActivity(), this, mHandler, getSherlockActivity());
-            ((FileDisplayActivity) getActivity()).showLoadingDialog();
-        }
-    }
-    
-    
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationResult result) {
-        if (operation.equals(mLastRemoteOperation)) {
-            if (operation instanceof RemoveFileOperation) {
-                onRemoveFileOperationFinish((RemoveFileOperation)operation, result);
-                
-            } else if (operation instanceof RenameFileOperation) {
-                onRenameFileOperationFinish((RenameFileOperation)operation, result);
-                
-            } else if (operation instanceof SynchronizeFileOperation) {
-                onSynchronizeFileOperationFinish((SynchronizeFileOperation)operation, result);
-            }
-        }
-    }
-    
-    
-    private void onRemoveFileOperationFinish(RemoveFileOperation operation, RemoteOperationResult result) {
-        ((FileDisplayActivity) getActivity()).dismissLoadingDialog();
-        if (result.isSuccess()) {
-            Toast msg = Toast.makeText(getActivity().getApplicationContext(), R.string.remove_success_msg, Toast.LENGTH_LONG);
-            msg.show();
-            ((FileDisplayActivity)getActivity()).cleanSecondFragment();
-
-        } else {
-            Toast msg = Toast.makeText(getActivity(), R.string.remove_fail_msg, Toast.LENGTH_LONG); 
-            msg.show();
-            if (result.isSslRecoverableException()) {
-                // TODO show the SSL warning dialog
-            }
-        }
-    }
-    
-    private void onRenameFileOperationFinish(RenameFileOperation operation, RemoteOperationResult result) {
-        ((FileDisplayActivity) getActivity()).dismissLoadingDialog();
-        
-        if (result.isSuccess()) {
-            updateFileDetails(((RenameFileOperation)operation).getFile(), mAccount);
-            mContainerActivity.onFileStateChanged();
-            
-        } else {
-            if (result.getCode().equals(ResultCode.INVALID_LOCAL_FILE_NAME)) {
-                Toast msg = Toast.makeText(getActivity(), R.string.rename_local_fail_msg, Toast.LENGTH_LONG); 
-                msg.show();
-                // TODO throw again the new rename dialog
-            } else {
-                Toast msg = Toast.makeText(getActivity(), R.string.rename_server_fail_msg, Toast.LENGTH_LONG); 
-                msg.show();
-                if (result.isSslRecoverableException()) {
-                    // TODO show the SSL warning dialog
-                }
-            }
-        }
-    }
-    
-    private void onSynchronizeFileOperationFinish(SynchronizeFileOperation operation, RemoteOperationResult result) {
-        ((FileDisplayActivity) getActivity()).dismissLoadingDialog();
-        OCFile file = getFile();
-        if (!result.isSuccess()) {
-            if (result.getCode() == ResultCode.SYNC_CONFLICT) {
-                Intent i = new Intent(getActivity(), ConflictsResolveActivity.class);
-                i.putExtra(ConflictsResolveActivity.EXTRA_FILE, file);
-                i.putExtra(ConflictsResolveActivity.EXTRA_ACCOUNT, mAccount);
-                startActivity(i);
-                
-            } 
-            
-            if (file.isDown()) {
-                setButtonsForDown();
-                
-            } else {
-                setButtonsForRemote();
-            }
-            
-        } else {
-            if (operation.transferWasRequested()) {
-                setButtonsForTransferring();
-                mContainerActivity.onFileStateChanged();    // this is not working; FileDownloader won't do NOTHING at all until this method finishes, so 
-                                                            // checking the service to see if the file is downloading results in FALSE
-            } else {
-                Toast msg = Toast.makeText(getActivity(), R.string.sync_file_nothing_to_do_msg, Toast.LENGTH_LONG); 
-                msg.show();
-                if (file.isDown()) {
-                    setButtonsForDown();
-                    
-                } else {
-                    setButtonsForRemote();
-                }
-            }
-        }
-    }
-    
-
     public void listenForTransferProgress() {
         if (mProgressListener != null) {
             if (mContainerActivity.getFileDownloaderBinder() != null) {
@@ -904,11 +545,6 @@ public class FileDetailFragment extends FileFragment implements
         }
         
         @Override
-        public void onTransferProgress(long progressRate) {
-            // old method, nothing here
-        };
-
-        @Override
         public void onTransferProgress(long progressRate, long totalTransferredSoFar, long totalToTransfer, String filename) {
             int percent = (int)(100.0*((double)totalTransferredSoFar)/((double)totalToTransfer));
             if (percent != mLastPercent) {
index b6c6574..3e6fa31 100644 (file)
 
 package com.owncloud.android.ui.fragment;
 
+import android.accounts.Account;
+import android.app.Activity;
 import android.support.v4.app.Fragment;
 
 import com.actionbarsherlock.app.SherlockFragment;
 import com.owncloud.android.datamodel.OCFile;
-import com.owncloud.android.files.FileHandler;
-import com.owncloud.android.ui.activity.TransferServiceGetter;
+import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder;
+import com.owncloud.android.files.services.FileUploader.FileUploaderBinder;
+import com.owncloud.android.ui.activity.ComponentsGetter;
 
 
 /**
@@ -34,6 +37,8 @@ import com.owncloud.android.ui.activity.TransferServiceGetter;
 public class FileFragment extends SherlockFragment {
     
     private OCFile mFile;
+    
+    protected ContainerActivity mContainerActivity;
 
 
     /**
@@ -67,27 +72,40 @@ public class FileFragment extends SherlockFragment {
     protected void setFile(OCFile file) {
         mFile = file;
     }
-
+    
+    
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void onAttach(Activity activity) {
+        super.onAttach(activity);
+        try {
+            mContainerActivity = (ContainerActivity) activity;
+            
+        } catch (ClassCastException e) {
+            throw new ClassCastException(activity.toString() + " must implement " + ContainerActivity.class.getSimpleName());
+        }
+    }
+    
+    
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void onDetach() {
+        mContainerActivity = null;
+        super.onDetach();
+    }    
+    
+    
     /**
+     * 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 TransferServiceGetter, FileHandler {
-
-        /**
-         * Callback method invoked when the detail fragment wants to notice its container 
-         * activity about a relevant state the file shown by the fragment.
-         * 
-         * Added to notify to FileDisplayActivity about the need of refresh the files list. 
-         * 
-         * Currently called when:
-         *  - a download is started;
-         *  - a rename is completed;
-         *  - a deletion is completed;
-         *  - the 'inSync' flag is changed;
-         */
-        public void onFileStateChanged();
+    public interface ContainerActivity extends ComponentsGetter {
 
         /**
          * Request the parent activity to show the details of an {@link OCFile}.
@@ -95,8 +113,34 @@ public class FileFragment extends SherlockFragment {
          * @param file      File to show details
          */
         public void showDetails(OCFile file);
+
         
+        ///// TO UNIFY IN A SINGLE CALLBACK METHOD - EVENT NOTIFICATIONs  -> something happened inside the fragment, MAYBE activity is interested --> unify in notification method
+        /**
+         * Callback method invoked when a the user browsed into a different folder through the list of files
+         *  
+         * @param file
+         */
+        public void onBrowsedDownTo(OCFile folder);                 
+
+        /**
+         * Callback method invoked when a the 'transfer state' of a file changes.
+         * 
+         * This happens when a download or upload is started or ended for a file.
+         * 
+         * This method is necessary by now to update the user interface of the double-pane layout in tablets
+         * because methods {@link FileDownloaderBinder#isDownloading(Account, OCFile)} and {@link FileUploaderBinder#isUploading(Account, OCFile)}
+         * won't provide the needed response before the method where this is called finishes. 
+         * 
+         * TODO Remove this when the transfer state of a file is kept in the database (other thing TODO)
+         * 
+         * @param file          OCFile which state changed.
+         * @param downloading   Flag signaling if the file is now downloading.
+         * @param uploading     Flag signaling if the file is now uploading.
+         */
+        public void onTransferStateChanged(OCFile file, boolean downloading, boolean uploading); 
+
         
     }
-    
+
 }
index 9eb7d1d..c9408b1 100644 (file)
@@ -20,10 +20,6 @@ package com.owncloud.android.ui.fragment;
 import java.io.File;
 import java.util.ArrayList;
 
-import com.owncloud.android.Log_OC;
-import com.owncloud.android.R;
-import com.owncloud.android.ui.adapter.LocalFileListAdapter;
-
 import android.app.Activity;
 import android.os.Bundle;
 import android.os.Environment;
@@ -35,6 +31,10 @@ import android.widget.AdapterView;
 import android.widget.ImageView;
 import android.widget.ListView;
 
+import com.owncloud.android.R;
+import com.owncloud.android.lib.common.utils.Log_OC;
+import com.owncloud.android.ui.adapter.LocalFileListAdapter;
+
 
 /**
  * A Fragment that lists all files and folders in a given LOCAL path.
@@ -77,6 +77,8 @@ public class LocalFileListFragment extends ExtendedListFragment {
         Log_OC.i(TAG, "onCreateView() start");
         View v = super.onCreateView(inflater, container, savedInstanceState);
         getListView().setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
+        disableSwipe(); // Disable pull refresh
+        setMessageForEmptyList(getString(R.string.local_file_list_empty));
         Log_OC.i(TAG, "onCreateView() end");
         return v;
     }    
@@ -89,7 +91,7 @@ public class LocalFileListFragment extends ExtendedListFragment {
     public void onActivityCreated(Bundle savedInstanceState) {
         Log_OC.i(TAG, "onActivityCreated() start");
         
-        super.onCreate(savedInstanceState);
+        super.onActivityCreated(savedInstanceState);
         mAdapter = new LocalFileListAdapter(mContainerActivity.getInitialDirectory(), getActivity());
         setListAdapter(mAdapter);
         
@@ -110,6 +112,8 @@ public class LocalFileListFragment extends ExtendedListFragment {
                 listDirectory(file);
                 // notify the click to container Activity
                 mContainerActivity.onDirectoryClick(file);
+                // save index and top position
+                saveIndexAndTopPosition(position);
             
             } else {    /// Click on a file
                 ImageView checkBoxV = (ImageView) v.findViewById(R.id.custom_checkbox);
@@ -139,6 +143,9 @@ public class LocalFileListFragment extends ExtendedListFragment {
             parentDir = mDirectory.getParentFile();  // can be null
         }
         listDirectory(parentDir);
+
+        // restore index and top position
+        restoreIndexAndTopPosition();
     }
 
     
index a3c6d3b..0b1059f 100644 (file)
@@ -1,6 +1,6 @@
 /* ownCloud Android client application
  *   Copyright (C) 2011  Bartek Przybylski
- *   Copyright (C) 2012-2013 ownCloud Inc.
+ *   Copyright (C) 2012-2014 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.ArrayList;
-import java.util.List;
 
-import com.owncloud.android.Log_OC;
-import com.owncloud.android.R;
-import com.owncloud.android.authentication.AccountUtils;
-import com.owncloud.android.datamodel.FileDataStorageManager;
-import com.owncloud.android.datamodel.OCFile;
-import com.owncloud.android.files.FileHandler;
-import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder;
-import com.owncloud.android.files.services.FileUploader.FileUploaderBinder;
-import com.owncloud.android.operations.OnRemoteOperationListener;
-import com.owncloud.android.operations.RemoteOperation;
-import com.owncloud.android.operations.RemoveFileOperation;
-import com.owncloud.android.operations.RenameFileOperation;
-import com.owncloud.android.operations.SynchronizeFileOperation;
-import com.owncloud.android.ui.activity.FileDisplayActivity;
-import com.owncloud.android.ui.activity.TransferServiceGetter;
-import com.owncloud.android.ui.adapter.FileListListAdapter;
-import com.owncloud.android.ui.dialog.EditNameDialog;
-import com.owncloud.android.ui.dialog.EditNameDialog.EditNameDialogListener;
-import com.owncloud.android.ui.fragment.ConfirmationDialogFragment.ConfirmationDialogFragmentListener;
-import com.owncloud.android.ui.preview.PreviewImageFragment;
-import com.owncloud.android.ui.preview.PreviewMediaFragment;
-
-
-import android.accounts.Account;
 import android.app.Activity;
+import android.content.Intent;
 import android.os.Bundle;
-import android.os.Handler;
+import android.support.v4.widget.SwipeRefreshLayout;
 import android.view.ContextMenu;
 import android.view.MenuInflater;
 import android.view.MenuItem;
@@ -55,26 +30,49 @@ import android.view.View;
 import android.widget.AdapterView;
 import android.widget.AdapterView.AdapterContextMenuInfo;
 
+import com.owncloud.android.R;
+import com.owncloud.android.datamodel.FileDataStorageManager;
+import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.files.FileMenuFilter;
+import com.owncloud.android.lib.common.utils.Log_OC;
+import com.owncloud.android.ui.activity.FileDisplayActivity;
+import com.owncloud.android.ui.activity.MoveActivity;
+import com.owncloud.android.ui.activity.OnEnforceableRefreshListener;
+import com.owncloud.android.ui.adapter.FileListListAdapter;
+import com.owncloud.android.ui.dialog.ConfirmationDialogFragment;
+import com.owncloud.android.ui.dialog.RemoveFileDialogFragment;
+import com.owncloud.android.ui.dialog.RenameFileDialogFragment;
+import com.owncloud.android.ui.preview.PreviewImageFragment;
+import com.owncloud.android.ui.preview.PreviewMediaFragment;
+
 /**
  * A Fragment that lists all files and folders in a given path.
  * 
- * @author Bartek Przybylski
+ * TODO refactorize to get rid of direct dependency on FileDisplayActivity
  * 
+ * @author Bartek Przybylski
+ * @author masensio
+ * @author David A. Velasco
  */
-public class OCFileListFragment extends ExtendedListFragment implements EditNameDialogListener, ConfirmationDialogFragmentListener {
+public class OCFileListFragment extends ExtendedListFragment {
     
     private static final String TAG = OCFileListFragment.class.getSimpleName();
 
-    private static final String MY_PACKAGE = OCFileListFragment.class.getPackage() != null ? OCFileListFragment.class.getPackage().getName() : "com.owncloud.android.ui.fragment";
-    private static final String EXTRA_FILE = MY_PACKAGE + ".extra.FILE";
-    
-    private OCFileListFragment.ContainerActivity mContainerActivity;
-    
+    private static final String MY_PACKAGE = OCFileListFragment.class.getPackage() != null ?
+            OCFileListFragment.class.getPackage().getName() : "com.owncloud.android.ui.fragment";
+            
+    public final static String ARG_JUST_FOLDERS = MY_PACKAGE + ".JUST_FOLDERS";
+    public final static String ARG_ALLOW_CONTEXTUAL_ACTIONS = MY_PACKAGE + ".ALLOW_CONTEXTUAL";
+            
+    private static final String KEY_FILE = MY_PACKAGE + ".extra.FILE";
+
+    private FileFragment.ContainerActivity mContainerActivity;
+   
     private OCFile mFile = null;
     private FileListListAdapter mAdapter;
     
-    private Handler mHandler;
     private OCFile mTargetFile;
+
     
     /**
      * {@inheritDoc}
@@ -84,13 +82,29 @@ public class OCFileListFragment extends ExtendedListFragment implements EditName
         super.onAttach(activity);
         Log_OC.e(TAG, "onAttach");
         try {
-            mContainerActivity = (ContainerActivity) activity;
+            mContainerActivity = (FileFragment.ContainerActivity) activity;
+            
+        } catch (ClassCastException e) {
+            throw new ClassCastException(activity.toString() + " must implement " + 
+                    FileFragment.ContainerActivity.class.getSimpleName());
+        }
+        try {
+            setOnRefreshListener((OnEnforceableRefreshListener) activity);
+            
         } catch (ClassCastException e) {
-            throw new ClassCastException(activity.toString() + " must implement " + OCFileListFragment.ContainerActivity.class.getSimpleName());
+            throw new ClassCastException(activity.toString() + " must implement " + 
+                    SwipeRefreshLayout.OnRefreshListener.class.getSimpleName());
         }
     }
+
     
-    
+    @Override
+    public void onDetach() {
+        setOnRefreshListener(null);
+        mContainerActivity = null;
+        super.onDetach();
+    }
+
     /**
      * {@inheritDoc}
      */
@@ -98,18 +112,23 @@ public class OCFileListFragment extends ExtendedListFragment implements EditName
     public void onActivityCreated(Bundle savedInstanceState) {
         super.onActivityCreated(savedInstanceState);
         Log_OC.e(TAG, "onActivityCreated() start");
-        mAdapter = new FileListListAdapter(getActivity(), mContainerActivity);
+        
         if (savedInstanceState != null) {
-            mFile = savedInstanceState.getParcelable(EXTRA_FILE);
+            mFile = savedInstanceState.getParcelable(KEY_FILE);
         }
+        
+        Bundle args = getArguments();
+        boolean justFolders = (args == null) ? false : args.getBoolean(ARG_JUST_FOLDERS, false); 
+        mAdapter = new FileListListAdapter(
+                justFolders,
+                getSherlockActivity(), 
+                mContainerActivity
+        );
         setListAdapter(mAdapter);
         
         registerForContextMenu(getListView());
-        getListView().setOnCreateContextMenuListener(this);        
-        
-        mHandler = new Handler();
-
-    }
+        getListView().setOnCreateContextMenuListener(this);
+  }
     
     /**
      * Saves the current listed folder.
@@ -117,15 +136,14 @@ public class OCFileListFragment extends ExtendedListFragment implements EditName
     @Override
     public void onSaveInstanceState (Bundle outState) {
         super.onSaveInstanceState(outState);
-        outState.putParcelable(EXTRA_FILE, mFile);
+        outState.putParcelable(KEY_FILE, mFile);
     }
-
-
+    
     /**
      * Call this, when the user presses the up button.
      * 
-     * Tries to move up the current folder one level. If the parent folder was removed from the database, 
-     * it continues browsing up until finding an existing folders.
+     * Tries to move up the current folder one level. If the parent folder was removed from the 
+     * database, it continues browsing up until finding an existing folders.
      * 
      * return       Count of folder levels browsed up.
      */
@@ -139,25 +157,29 @@ public class OCFileListFragment extends ExtendedListFragment implements EditName
             String parentPath = null;
             if (mFile.getParentId() != FileDataStorageManager.ROOT_PARENT_ID) {
                 parentPath = new File(mFile.getRemotePath()).getParent();
-                parentPath = parentPath.endsWith(OCFile.PATH_SEPARATOR) ? parentPath : parentPath + OCFile.PATH_SEPARATOR;
+                parentPath = parentPath.endsWith(OCFile.PATH_SEPARATOR) ? parentPath : 
+                       parentPath + OCFile.PATH_SEPARATOR;
                 parentDir = storageManager.getFileByPath(parentPath);
                 moveCount++;
             } else {
-                parentDir = storageManager.getFileByPath(OCFile.ROOT_PATH);    // never returns null; keep the path in root folder
+                parentDir = storageManager.getFileByPath(OCFile.ROOT_PATH);
             }
             while (parentDir == null) {
                 parentPath = new File(parentPath).getParent();
-                parentPath = parentPath.endsWith(OCFile.PATH_SEPARATOR) ? parentPath : parentPath + OCFile.PATH_SEPARATOR;
+                parentPath = parentPath.endsWith(OCFile.PATH_SEPARATOR) ? parentPath : 
+                       parentPath + OCFile.PATH_SEPARATOR;
                 parentDir = storageManager.getFileByPath(parentPath);
                 moveCount++;
             }   // exit is granted because storageManager.getFileByPath("/") never returns null
-            mFile = parentDir;           
-        }
-        
-        if (mFile != null) {
+            mFile = parentDir;
+            
             listDirectory(mFile);
 
-            mContainerActivity.startSyncFolderOperation(mFile);
+            onRefresh(false);
+            
+            // restore index and top position
+            restoreIndexAndTopPosition();
+            
         }   // else - should never happen now
    
         return moveCount;
@@ -170,26 +192,27 @@ public class OCFileListFragment extends ExtendedListFragment implements EditName
             if (file.isFolder()) { 
                 // update state and view of this fragment
                 listDirectory(file);
-                // then, notify parent activity to let it update its state and view, and other fragments
+                // then, notify parent activity to let it update its state and view
                 mContainerActivity.onBrowsedDownTo(file);
+                // save index and top position
+                saveIndexAndTopPosition(position);
                 
             } else { /// Click on a file
                 if (PreviewImageFragment.canBePreviewed(file)) {
                     // preview image - it handles the download, if needed
-                    mContainerActivity.startImagePreview(file);
+                    ((FileDisplayActivity)mContainerActivity).startImagePreview(file);
                     
                 } else if (file.isDown()) {
                     if (PreviewMediaFragment.canBePreviewed(file)) {
                         // media preview
-                        mContainerActivity.startMediaPreview(file, 0, true);
+                        ((FileDisplayActivity)mContainerActivity).startMediaPreview(file, 0, true);
                     } else {
-                        // open with
-                        mContainerActivity.openFile(file);
+                        mContainerActivity.getFileOperationsHelper().openFile(file);
                     }
                     
                 } else {
                     // automatic download, preview on finish
-                    mContainerActivity.startDownloadForPreview(file);
+                    ((FileDisplayActivity)mContainerActivity).startDownloadForPreview(file);
                 }
                     
             }
@@ -204,73 +227,44 @@ public class OCFileListFragment extends ExtendedListFragment implements EditName
      * {@inheritDoc}
      */
     @Override
-    public void onCreateContextMenu (ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
+    public void onCreateContextMenu (
+            ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
         super.onCreateContextMenu(menu, v, menuInfo);
-        MenuInflater inflater = getActivity().getMenuInflater();
-        inflater.inflate(R.menu.file_actions_menu, menu);
-        AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo;
-        OCFile targetFile = (OCFile) mAdapter.getItem(info.position);
-        List<Integer> toHide = new ArrayList<Integer>();    
-        List<Integer> toDisable = new ArrayList<Integer>();  
-        
-        MenuItem item = null;
-        if (targetFile.isFolder()) {
-            // contextual menu for folders
-            toHide.add(R.id.action_open_file_with);
-            toHide.add(R.id.action_download_file);
-            toHide.add(R.id.action_cancel_download);
-            toHide.add(R.id.action_cancel_upload);
-            toHide.add(R.id.action_sync_file);
-            toHide.add(R.id.action_see_details);
-            if (    mContainerActivity.getFileDownloaderBinder().isDownloading(AccountUtils.getCurrentOwnCloudAccount(getActivity()), targetFile) ||
-                    mContainerActivity.getFileUploaderBinder().isUploading(AccountUtils.getCurrentOwnCloudAccount(getActivity()), targetFile)           ) {
-                toDisable.add(R.id.action_rename_file);
-                toDisable.add(R.id.action_remove_file);
-                
-            }
-            
-        } else {
-            // contextual menu for regular files
-            
-            // new design: 'download' and 'open with' won't be available anymore in context menu
-            toHide.add(R.id.action_download_file);
-            toHide.add(R.id.action_open_file_with);
+        Bundle args = getArguments();
+        boolean allowContextualActions = 
+                (args == null) ? true : args.getBoolean(ARG_ALLOW_CONTEXTUAL_ACTIONS, true); 
+        if (allowContextualActions) {
+            MenuInflater inflater = getSherlockActivity().getMenuInflater();
+            inflater.inflate(R.menu.file_actions_menu, menu);
+            AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo;
+            OCFile targetFile = (OCFile) mAdapter.getItem(info.position);
             
-            if (targetFile.isDown()) {
-                toHide.add(R.id.action_cancel_download);
-                toHide.add(R.id.action_cancel_upload);
-                
-            } else {
-                toHide.add(R.id.action_sync_file);
-            }
-            if ( mContainerActivity.getFileDownloaderBinder().isDownloading(AccountUtils.getCurrentOwnCloudAccount(getActivity()), targetFile)) {
-                toHide.add(R.id.action_cancel_upload);
-                toDisable.add(R.id.action_rename_file);
-                toDisable.add(R.id.action_remove_file);
-                    
-            } else if ( mContainerActivity.getFileUploaderBinder().isUploading(AccountUtils.getCurrentOwnCloudAccount(getActivity()), targetFile)) {
-                toHide.add(R.id.action_cancel_download);
-                toDisable.add(R.id.action_rename_file);
-                toDisable.add(R.id.action_remove_file);
-                    
-            } else {
-                toHide.add(R.id.action_cancel_download);
-                toHide.add(R.id.action_cancel_upload);
+            if (mContainerActivity.getStorageManager() != null) {
+                FileMenuFilter mf = new FileMenuFilter(
+                    targetFile,
+                    mContainerActivity.getStorageManager().getAccount(),
+                    mContainerActivity,
+                    getSherlockActivity()
+                );
+                mf.filter(menu);
             }
-        }
-
-        for (int i : toHide) {
-            item = menu.findItem(i);
+            
+            /// additional restrictions for this fragment 
+            // TODO allow in the future 'open with' for previewable files
+            MenuItem item = menu.findItem(R.id.action_open_file_with);
             if (item != null) {
                 item.setVisible(false);
                 item.setEnabled(false);
             }
-        }
-        
-        for (int i : toDisable) {
-            item = menu.findItem(i);
-            if (item != null) {
-                item.setEnabled(false);
+            /// TODO break this direct dependency on FileDisplayActivity... if possible
+            FileFragment frag = ((FileDisplayActivity)getSherlockActivity()).getSecondFragment();
+            if (frag != null && frag instanceof FileDetailFragment && 
+                    frag.getFile().getFileId() == targetFile.getFileId()) {
+                item = menu.findItem(R.id.action_see_details);
+                if (item != null) {
+                    item.setVisible(false);
+                    item.setEnabled(false);
+                }
             }
         }
     }
@@ -283,73 +277,63 @@ public class OCFileListFragment extends ExtendedListFragment implements EditName
     public boolean onContextItemSelected (MenuItem item) {
         AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();        
         mTargetFile = (OCFile) mAdapter.getItem(info.position);
-        switch (item.getItemId()) {
+        switch (item.getItemId()) {                
+            case R.id.action_share_file: {
+                mContainerActivity.getFileOperationsHelper().shareFileWithLink(mTargetFile);
+                return true;
+            }
+            case R.id.action_unshare_file: {
+                mContainerActivity.getFileOperationsHelper().unshareFileWithLink(mTargetFile);
+                return true;
+            }
             case R.id.action_rename_file: {
-                String fileName = mTargetFile.getFileName();
-                int extensionStart = mTargetFile.isFolder() ? -1 : fileName.lastIndexOf(".");
-                int selectionEnd = (extensionStart >= 0) ? extensionStart : fileName.length();
-                EditNameDialog dialog = EditNameDialog.newInstance(getString(R.string.rename_dialog_title), fileName, 0, selectionEnd, this);
-                dialog.show(getFragmentManager(), EditNameDialog.TAG);
+                RenameFileDialogFragment dialog = RenameFileDialogFragment.newInstance(mTargetFile);
+                dialog.show(getFragmentManager(), FileDetailFragment.FTAG_RENAME_FILE);
                 return true;
             }
             case R.id.action_remove_file: {
-                int messageStringId = R.string.confirmation_remove_alert;
-                int posBtnStringId = R.string.confirmation_remove_remote;
-                int neuBtnStringId = -1;
-                if (mTargetFile.isFolder()) {
-                    messageStringId = R.string.confirmation_remove_folder_alert;
-                    posBtnStringId = R.string.confirmation_remove_remote_and_local;
-                    neuBtnStringId = R.string.confirmation_remove_folder_local;
-                } else if (mTargetFile.isDown()) {
-                    posBtnStringId = R.string.confirmation_remove_remote_and_local;
-                    neuBtnStringId = R.string.confirmation_remove_local;
-                }
-                ConfirmationDialogFragment confDialog = ConfirmationDialogFragment.newInstance(
-                        messageStringId,
-                        new String[]{mTargetFile.getFileName()},
-                        posBtnStringId,
-                        neuBtnStringId,
-                        R.string.common_cancel);
-                confDialog.setOnConfirmationListener(this);
-                confDialog.show(getFragmentManager(), FileDetailFragment.FTAG_CONFIRMATION);
+                RemoveFileDialogFragment dialog = RemoveFileDialogFragment.newInstance(mTargetFile);
+                dialog.show(getFragmentManager(), ConfirmationDialogFragment.FTAG_CONFIRMATION);
                 return true;
             }
+            case R.id.action_download_file: 
             case R.id.action_sync_file: {
-                Account account = AccountUtils.getCurrentOwnCloudAccount(getSherlockActivity());
-                RemoteOperation operation = new SynchronizeFileOperation(mTargetFile, null, mContainerActivity.getStorageManager(), account, true, getSherlockActivity());
-                operation.execute(account, getSherlockActivity(), mContainerActivity, mHandler, getSherlockActivity());
-                ((FileDisplayActivity) getSherlockActivity()).showLoadingDialog();
+                mContainerActivity.getFileOperationsHelper().syncFile(mTargetFile);
                 return true;
             }
-            case R.id.action_cancel_download: {
-                FileDownloaderBinder downloaderBinder = mContainerActivity.getFileDownloaderBinder();
-                Account account = AccountUtils.getCurrentOwnCloudAccount(getActivity());
-                if (downloaderBinder != null && downloaderBinder.isDownloading(account, mTargetFile)) {
-                    downloaderBinder.cancel(account, mTargetFile);
-                    listDirectory();
-                    mContainerActivity.onTransferStateChanged(mTargetFile, false, false);
-                }
+            case R.id.action_cancel_download:
+            case R.id.action_cancel_upload: {
+                ((FileDisplayActivity)mContainerActivity).cancelTransference(mTargetFile);
                 return true;
             }
-            case R.id.action_cancel_upload: {
-                FileUploaderBinder uploaderBinder = mContainerActivity.getFileUploaderBinder();
-                Account account = AccountUtils.getCurrentOwnCloudAccount(getActivity());
-                if (uploaderBinder != null && uploaderBinder.isUploading(account, mTargetFile)) {
-                    uploaderBinder.cancel(account, mTargetFile);
-                    listDirectory();
-                    mContainerActivity.onTransferStateChanged(mTargetFile, false, false);
+            case R.id.action_see_details: {
+                mContainerActivity.showDetails(mTargetFile);
+                return true;
+            }
+            case R.id.action_send_file: {
+                // Obtain the file
+                if (!mTargetFile.isDown()) {  // Download the file
+                    Log_OC.d(TAG, mTargetFile.getRemotePath() + " : File must be downloaded");
+                    ((FileDisplayActivity)mContainerActivity).startDownloadForSending(mTargetFile);
+                    
+                } else {
+                    mContainerActivity.getFileOperationsHelper().sendDownloadedFile(mTargetFile);
                 }
                 return true;
             }
-            case R.id.action_see_details: {
-                ((FileFragment.ContainerActivity)getActivity()).showDetails(mTargetFile);
+            case R.id.action_move: {
+                Intent action = new Intent(getActivity(), MoveActivity.class);
+
+                // Pass mTargetFile that contains info of selected file/folder
+                action.putExtra(MoveActivity.EXTRA_TARGET_FILE, mTargetFile);
+                getActivity().startActivityForResult(action, FileDisplayActivity.ACTION_MOVE_FILES);
                 return true;
             }
             default:
                 return super.onContextItemSelected(item); 
         }
     }
-    
+
 
     /**
      * Use this to query the {@link OCFile} that is currently
@@ -403,96 +387,16 @@ public class OCFileListFragment extends ExtendedListFragment implements EditName
         }
     }
     
-    
-    
-    /**
-     * Interface to implement by any Activity that includes some instance of FileListFragment
-     * 
-     * @author David A. Velasco
-     */
-    public interface ContainerActivity extends TransferServiceGetter, OnRemoteOperationListener, FileHandler {
-
-        /**
-         * Callback method invoked when a the user browsed into a different folder through the list of files
-         *  
-         * @param file
-         */
-        public void onBrowsedDownTo(OCFile folder);
-        
-        public void startDownloadForPreview(OCFile file);
-
-        public void startMediaPreview(OCFile file, int i, boolean b);
-
-        public void startImagePreview(OCFile file);
-        
-        public void startSyncFolderOperation(OCFile folder);
-
-        /**
-         * Getter for the current DataStorageManager in the container activity
-         */
-        public FileDataStorageManager getStorageManager();
-        
-        
-        /**
-         * Callback method invoked when a the 'transfer state' of a file changes.
-         * 
-         * This happens when a download or upload is started or ended for a file.
-         * 
-         * This method is necessary by now to update the user interface of the double-pane layout in tablets
-         * because methods {@link FileDownloaderBinder#isDownloading(Account, OCFile)} and {@link FileUploaderBinder#isUploading(Account, OCFile)}
-         * won't provide the needed response before the method where this is called finishes. 
-         * 
-         * TODO Remove this when the transfer state of a file is kept in the database (other thing TODO)
-         * 
-         * @param file          OCFile which state changed.
-         * @param downloading   Flag signaling if the file is now downloading.
-         * @param uploading     Flag signaling if the file is now uploading.
-         */
-        public void onTransferStateChanged(OCFile file, boolean downloading, boolean uploading);
-        
-    }
-    
-    
-    @Override
-    public void onDismiss(EditNameDialog dialog) {
-        if (dialog.getResult()) {
-            String newFilename = dialog.getNewFilename();
-            Log_OC.d(TAG, "name edit dialog dismissed with new name " + newFilename);
-            RemoteOperation operation = new RenameFileOperation(mTargetFile, 
-                                                                AccountUtils.getCurrentOwnCloudAccount(getActivity()), 
-                                                                newFilename, 
-                                                                mContainerActivity.getStorageManager());
-            operation.execute(AccountUtils.getCurrentOwnCloudAccount(getSherlockActivity()), getSherlockActivity(), mContainerActivity, mHandler, getSherlockActivity());
-            ((FileDisplayActivity) getActivity()).showLoadingDialog();
-        }
+    public void sortByName(boolean descending) {
+        mAdapter.setSortOrder(FileListListAdapter.SORT_NAME, descending);
     }
 
-    
-    @Override
-    public void onConfirmation(String callerTag) {
-        if (callerTag.equals(FileDetailFragment.FTAG_CONFIRMATION)) {
-            if (mContainerActivity.getStorageManager().getFileById(mTargetFile.getFileId()) != null) {
-                RemoteOperation operation = new RemoveFileOperation( mTargetFile, 
-                                                                    true, 
-                                                                    mContainerActivity.getStorageManager());
-                operation.execute(AccountUtils.getCurrentOwnCloudAccount(getSherlockActivity()), getSherlockActivity(), mContainerActivity, mHandler, getSherlockActivity());
-                
-                ((FileDisplayActivity) getActivity()).showLoadingDialog();
-            }
-        }
-    }
-    
-    @Override
-    public void onNeutral(String callerTag) {
-        mContainerActivity.getStorageManager().removeFile(mTargetFile, false, true);    // TODO perform in background task / new thread
-        listDirectory();
-        mContainerActivity.onTransferStateChanged(mTargetFile, false, false);
-    }
-    
-    @Override
-    public void onCancel(String callerTag) {
-        Log_OC.d(TAG, "REMOVAL CANCELED");
+    public void sortByDate(boolean descending) {
+        mAdapter.setSortOrder(FileListListAdapter.SORT_DATE, descending);
     }
 
+    public void sortBySize(boolean descending) {
+        mAdapter.setSortOrder(FileListListAdapter.SORT_SIZE, descending);
+    }  
 
 }
index 306df1f..98bbda3 100644 (file)
@@ -19,14 +19,12 @@ package com.owncloud.android.ui.preview;
 
 import java.lang.ref.WeakReference;
 
-import com.owncloud.android.Log_OC;
 import com.owncloud.android.R;
 import com.owncloud.android.datamodel.OCFile;
 import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder;
 import com.owncloud.android.ui.fragment.FileFragment;
 
 import android.accounts.Account;
-import android.app.Activity;
 import android.os.Bundle;
 import android.support.v4.app.FragmentStatePagerAdapter;
 import android.view.LayoutInflater;
@@ -34,13 +32,14 @@ import android.view.View;
 import android.view.View.OnClickListener;
 import android.view.ViewGroup;
 import android.widget.ImageButton;
+import android.widget.LinearLayout;
 import android.widget.ProgressBar;
 import android.widget.TextView;
 
+import com.owncloud.android.lib.common.network.OnDatatransferProgressListener;
+import com.owncloud.android.lib.common.utils.Log_OC;
 
 
-import eu.alefzero.webdav.OnDatatransferProgressListener;
-
 /**
  * This Fragment is used to monitor the progress of a file downloading.
  * 
@@ -52,8 +51,6 @@ public class FileDownloadFragment extends FileFragment implements OnClickListene
     public static final String EXTRA_ACCOUNT = "ACCOUNT";
     private static final String EXTRA_ERROR = "ERROR";
 
-    private FileFragment.ContainerActivity mContainerActivity;
-    
     private View mView;
     private Account mAccount;
     
@@ -130,6 +127,13 @@ public class FileDownloadFragment extends FileFragment implements OnClickListene
         
         ((ImageButton)mView.findViewById(R.id.cancelBtn)).setOnClickListener(this);
         
+        ((LinearLayout)mView.findViewById(R.id.fileDownloadLL)).setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                ((PreviewImageActivity) getActivity()).toggleFullScreen();
+            }
+        });
+
         if (mError) {
             setButtonsForRemote();
         } else {
@@ -140,33 +144,6 @@ public class FileDownloadFragment extends FileFragment implements OnClickListene
     }
     
 
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void onAttach(Activity activity) {
-        super.onAttach(activity);
-        try {
-            mContainerActivity = (ContainerActivity) activity;
-            
-        } catch (ClassCastException e) {
-            throw new ClassCastException(activity.toString() + " must implement " + FileFragment.ContainerActivity.class.getSimpleName());
-        }
-    }
-    
-    
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void onActivityCreated(Bundle savedInstanceState) {
-        super.onActivityCreated(savedInstanceState);
-        if (mAccount != null) {
-            //mStorageManager = new FileDataStorageManager(mAccount, getActivity().getApplicationContext().getContentResolver());;
-        }
-    }
-        
-
     @Override
     public void onSaveInstanceState(Bundle outState) {
         super.onSaveInstanceState(outState);
@@ -195,8 +172,8 @@ public class FileDownloadFragment extends FileFragment implements OnClickListene
     
     @Override
     public void onStop() {
-        super.onStop();
         leaveTransferProgress();
+        super.onStop();
     }
     
     @Override
@@ -218,19 +195,8 @@ public class FileDownloadFragment extends FileFragment implements OnClickListene
     public void onClick(View v) {
         switch (v.getId()) {
             case R.id.cancelBtn: {
-                FileDownloaderBinder downloaderBinder = mContainerActivity.getFileDownloaderBinder();
-                if (downloaderBinder != null && downloaderBinder.isDownloading(mAccount, getFile())) {
-                    downloaderBinder.cancel(mAccount, getFile());
-                    getActivity().finish(); // :)
-                    /*
-                    leaveTransferProgress();
-                    if (mFile.isDown()) {
-                        setButtonsForDown();
-                    } else {
-                        setButtonsForRemote();
-                    }
-                    */
-                }
+                mContainerActivity.getFileOperationsHelper().cancelTransference(getFile());
+                getActivity().finish();
                 break;
             }
             default:
@@ -354,11 +320,6 @@ public class FileDownloadFragment extends FileFragment implements OnClickListene
         }
         
         @Override
-        public void onTransferProgress(long progressRate) {
-            // old method, nothing here
-        };
-
-        @Override
         public void onTransferProgress(long progressRate, long totalTransferredSoFar, long totalToTransfer, String filename) {
             int percent = (int)(100.0*((double)totalTransferredSoFar)/((double)totalToTransfer));
             if (percent != mLastPercent) {
diff --git a/src/com/owncloud/android/ui/preview/ImageViewCustom.java b/src/com/owncloud/android/ui/preview/ImageViewCustom.java
new file mode 100644 (file)
index 0000000..ad85140
--- /dev/null
@@ -0,0 +1,70 @@
+package com.owncloud.android.ui.preview;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.os.Build;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.ImageView;
+
+import com.owncloud.android.lib.common.utils.Log_OC;
+
+public class ImageViewCustom extends ImageView {
+    
+    private static final boolean IS_ICS_OR_HIGHER = Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH;
+    
+    private Bitmap mBitmap;
+
+    
+    public ImageViewCustom(Context context) {
+        super(context);
+    }
+    
+    public ImageViewCustom(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+    
+    public ImageViewCustom(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+    }
+
+    @SuppressLint("NewApi")
+       @Override
+    protected void onDraw(Canvas canvas) {
+
+        if(IS_ICS_OR_HIGHER && checkIfMaximumBitmapExceed(canvas)) {
+            // Set layer type to software one for avoiding exceed
+            // and problems in visualization
+            setLayerType(View.LAYER_TYPE_SOFTWARE, null);
+        }
+
+        super.onDraw(canvas);
+    }
+
+    /**
+     * Checks if current bitmaps exceed the maximum OpenGL texture size limit
+     * @param bitmap
+     * @return boolean
+     */
+    @SuppressLint("NewApi")
+       private boolean checkIfMaximumBitmapExceed(Canvas canvas) {
+        Log_OC.d("OC", "Canvas maximum: " + canvas.getMaximumBitmapWidth() + " - " + canvas.getMaximumBitmapHeight());
+        if (mBitmap!= null && (mBitmap.getWidth() > canvas.getMaximumBitmapWidth() 
+                || mBitmap.getHeight() > canvas.getMaximumBitmapHeight())) {
+            return true;
+        }
+        
+        return false;
+    }
+    
+    /**
+     * Set current bitmap
+     * @param bitmap
+     */
+    public void setBitmap (Bitmap bitmap) {
+        mBitmap = bitmap;
+    }
+
+}
index ef48d12..c06f341 100644 (file)
  */
 package com.owncloud.android.ui.preview;
 
+import android.annotation.SuppressLint;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.ServiceConnection;
+import android.content.SharedPreferences;
+import android.os.Build;
 import android.os.Bundle;
+import android.os.Handler;
 import android.os.IBinder;
-import android.support.v4.app.Fragment;
-import android.support.v4.app.FragmentManager;
-import android.support.v4.app.FragmentTransaction;
+import android.os.Message;
+import android.preference.PreferenceManager;
 import android.support.v4.view.ViewPager;
-import android.view.MotionEvent;
 import android.view.View;
-import android.view.View.OnTouchListener;
 
 import com.actionbarsherlock.app.ActionBar;
 import com.actionbarsherlock.view.MenuItem;
 import com.actionbarsherlock.view.Window;
-import com.owncloud.android.Log_OC;
+import com.ortiz.touch.ExtendedViewPager;
 import com.owncloud.android.R;
 import com.owncloud.android.authentication.AccountUtils;
 import com.owncloud.android.datamodel.FileDataStorageManager;
 import com.owncloud.android.datamodel.OCFile;
 import com.owncloud.android.files.services.FileDownloader;
-import com.owncloud.android.files.services.FileUploader;
 import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder;
+import com.owncloud.android.files.services.FileUploader;
 import com.owncloud.android.files.services.FileUploader.FileUploaderBinder;
+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.operations.RemoteOperationResult.ResultCode;
+import com.owncloud.android.lib.common.utils.Log_OC;
+import com.owncloud.android.operations.CreateShareOperation;
+import com.owncloud.android.operations.RemoveFileOperation;
+import com.owncloud.android.operations.UnshareLinkOperation;
 import com.owncloud.android.ui.activity.FileActivity;
 import com.owncloud.android.ui.activity.FileDisplayActivity;
-import com.owncloud.android.ui.dialog.LoadingDialog;
+import com.owncloud.android.ui.activity.PinCodeActivity;
 import com.owncloud.android.ui.fragment.FileFragment;
+import com.owncloud.android.utils.DisplayUtils;
 
 
 /**
@@ -55,7 +65,9 @@ import com.owncloud.android.ui.fragment.FileFragment;
  *  
  *  @author David A. Velasco
  */
-public class PreviewImageActivity extends FileActivity implements FileFragment.ContainerActivity, ViewPager.OnPageChangeListener, OnTouchListener {
+public class PreviewImageActivity extends FileActivity implements 
+ FileFragment.ContainerActivity,
+ViewPager.OnPageChangeListener, OnRemoteOperationListener {
     
     public static final int DIALOG_SHORT_WAIT = 0;
 
@@ -63,23 +75,17 @@ public class PreviewImageActivity extends FileActivity implements FileFragment.C
     
     public static final String KEY_WAITING_TO_PREVIEW = "WAITING_TO_PREVIEW";
     private static final String KEY_WAITING_FOR_BINDER = "WAITING_FOR_BINDER";
-    
-    private static final String DIALOG_WAIT_TAG = "DIALOG_WAIT";
-    
-    private FileDataStorageManager mStorageManager;
-    
-    private ViewPager mViewPager; 
+
+    private static final int INITIAL_HIDE_DELAY = 0; // immediate hide
+
+    private ExtendedViewPager mViewPager;
     private PreviewImagePagerAdapter mPreviewImagePagerAdapter;    
     
-    private FileDownloaderBinder mDownloaderBinder = null;
-    private ServiceConnection mDownloadConnection, mUploadConnection = null;
-    private FileUploaderBinder mUploaderBinder = null;
-
     private boolean mRequestWaitingForBinder;
     
     private DownloadFinishReceiver mDownloadFinishReceiver;
-
-    private boolean mFullScreen;
+    
+    private View mFullScreenAnchorView;
     
     
     @Override
@@ -90,10 +96,38 @@ public class PreviewImageActivity extends FileActivity implements FileFragment.C
         setContentView(R.layout.preview_image_activity);
         
         ActionBar actionBar = getSupportActionBar();
+        actionBar.setIcon(DisplayUtils.getSeasonalIconId());
         actionBar.setDisplayHomeAsUpEnabled(true);
         actionBar.hide();
         
-        mFullScreen = true;
+        // PIN CODE request
+        if (getIntent().getExtras() != null && savedInstanceState == null && fromNotification()) {
+            requestPinCode();
+        }
+
+        // Make sure we're running on Honeycomb or higher to use FullScreen and
+        // Immersive Mode
+        if (isHoneycombOrHigher()) {
+        
+            mFullScreenAnchorView = getWindow().getDecorView();
+            // to keep our UI controls visibility in line with system bars
+            // visibility
+            mFullScreenAnchorView.setOnSystemUiVisibilityChangeListener(new View.OnSystemUiVisibilityChangeListener() {
+                @SuppressLint("InlinedApi")
+                @Override
+                public void onSystemUiVisibilityChange(int flags) {
+                    boolean visible = (flags & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0;
+                    ActionBar actionBar = getSupportActionBar();
+                    if (visible) {
+                        actionBar.show();
+                    } else {
+                        actionBar.hide();
+                    }
+                }
+            });
+
+        }
+            
         if (savedInstanceState != null) {
             mRequestWaitingForBinder = savedInstanceState.getBoolean(KEY_WAITING_FOR_BINDER);
         } else {
@@ -105,14 +139,13 @@ public class PreviewImageActivity extends FileActivity implements FileFragment.C
     private void initViewPager() {
         // get parent from path
         String parentPath = getFile().getRemotePath().substring(0, getFile().getRemotePath().lastIndexOf(getFile().getFileName()));
-        OCFile parentFolder = mStorageManager.getFileByPath(parentPath);
-        //OCFile parentFolder = mStorageManager.getFileById(getFile().getParentId());
+        OCFile parentFolder = getStorageManager().getFileByPath(parentPath);
         if (parentFolder == null) {
             // should not be necessary
-            parentFolder = mStorageManager.getFileByPath(OCFile.ROOT_PATH);
+            parentFolder = getStorageManager().getFileByPath(OCFile.ROOT_PATH);
         }
-        mPreviewImagePagerAdapter = new PreviewImagePagerAdapter(getSupportFragmentManager(), parentFolder, getAccount(), mStorageManager);
-        mViewPager = (ViewPager) findViewById(R.id.fragmentPager);
+        mPreviewImagePagerAdapter = new PreviewImagePagerAdapter(getSupportFragmentManager(), parentFolder, getAccount(), getStorageManager());
+        mViewPager = (ExtendedViewPager) findViewById(R.id.fragmentPager);
         int position = mPreviewImagePagerAdapter.getFilePosition(getFile());
         position = (position >= 0) ? position : 0;
         mViewPager.setAdapter(mPreviewImagePagerAdapter); 
@@ -125,13 +158,49 @@ public class PreviewImageActivity extends FileActivity implements FileFragment.C
     }
     
     
+    protected void onPostCreate(Bundle savedInstanceState)  {
+        super.onPostCreate(savedInstanceState);
+        
+        // Trigger the initial hide() shortly after the activity has been 
+        // created, to briefly hint to the user that UI controls 
+        // are available
+        delayedHide(INITIAL_HIDE_DELAY);
+        
+    }
+    
+    Handler mHideSystemUiHandler = new Handler() {
+        @Override
+        public void handleMessage(Message msg) {
+            if (isHoneycombOrHigher()) {
+                hideSystemUI(mFullScreenAnchorView);
+            }
+            getSupportActionBar().hide();
+        }
+    };
+    
+    private void delayedHide(int delayMillis)   {
+        mHideSystemUiHandler.removeMessages(0);
+        mHideSystemUiHandler.sendEmptyMessageDelayed(0, delayMillis);
+    }
+    
+    
+    /// handle Window Focus changes
+    @Override
+    public void onWindowFocusChanged(boolean hasFocus) {
+        super.onWindowFocusChanged(hasFocus);
+        
+        // When the window loses focus (e.g. the action overflow is shown),
+        // cancel any pending hide action.
+        if (!hasFocus) {
+            mHideSystemUiHandler.removeMessages(0);
+        }
+    }
+    
+    
+    
     @Override
     public void onStart() {
         super.onStart();
-        mDownloadConnection = new PreviewImageServiceConnection();
-        bindService(new Intent(this, FileDownloader.class), mDownloadConnection, Context.BIND_AUTO_CREATE);
-        mUploadConnection = new PreviewImageServiceConnection();
-        bindService(new Intent(this, FileUploader.class), mUploadConnection, Context.BIND_AUTO_CREATE);
     }
     
     @Override
@@ -140,6 +209,49 @@ public class PreviewImageActivity extends FileActivity implements FileFragment.C
         outState.putBoolean(KEY_WAITING_FOR_BINDER, mRequestWaitingForBinder);    
     }
 
+    @Override
+    public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationResult result) {
+        super.onRemoteOperationFinish(operation, result);
+        
+        if (operation instanceof CreateShareOperation) {
+            onCreateShareOperationFinish((CreateShareOperation) operation, result);
+            
+        } else if (operation instanceof UnshareLinkOperation) {
+            onUnshareLinkOperationFinish((UnshareLinkOperation) operation, result);
+            
+        } else if (operation instanceof RemoveFileOperation) {
+            finish();
+        }
+    }
+    
+    
+    private void onUnshareLinkOperationFinish(UnshareLinkOperation operation, RemoteOperationResult result) {
+        if (result.isSuccess()) {
+            OCFile file = getStorageManager().getFileByPath(getFile().getRemotePath());
+            if (file != null) {
+                setFile(file);
+            }
+            invalidateOptionsMenu();
+        } else if  (result.getCode() == ResultCode.SHARE_NOT_FOUND) {
+            backToDisplayActivity();
+        }
+            
+    }
+    
+    private void onCreateShareOperationFinish(CreateShareOperation operation, RemoteOperationResult result) {
+        if (result.isSuccess()) {
+            OCFile file = getStorageManager().getFileByPath(getFile().getRemotePath());
+            if (file != null) {
+                setFile(file);
+            }
+            invalidateOptionsMenu();
+        }
+    }
+
+    @Override
+    protected ServiceConnection newTransferenceServiceConnection() {
+        return new PreviewImageServiceConnection();
+    }
 
     /** Defines callbacks for service binding, passed to bindService() */
     private class PreviewImageServiceConnection implements ServiceConnection {
@@ -180,14 +292,6 @@ public class PreviewImageActivity extends FileActivity implements FileFragment.C
     @Override
     public void onStop() {
         super.onStop();
-        if (mDownloadConnection != null) {
-            unbindService(mDownloadConnection);
-            mDownloadConnection = null;
-        }
-        if (mUploadConnection != null) {
-            unbindService(mUploadConnection);
-            mUploadConnection = null;
-        }
     }
     
     
@@ -196,7 +300,6 @@ public class PreviewImageActivity extends FileActivity implements FileFragment.C
         super.onDestroy();
     }
     
-    
     @Override
     public boolean onOptionsItemSelected(MenuItem item) {
         boolean returnValue = false;
@@ -217,7 +320,7 @@ public class PreviewImageActivity extends FileActivity implements FileFragment.C
     @Override
     protected void onResume() {
         super.onResume();
-        //Log.e(TAG, "ACTIVITY, ONRESUME");
+        //Log_OC.e(TAG, "ACTIVITY, ONRESUME");
         mDownloadFinishReceiver = new DownloadFinishReceiver();
         
         IntentFilter filter = new IntentFilter(FileDownloader.getDownloadFinishMessage());
@@ -227,15 +330,15 @@ public class PreviewImageActivity extends FileActivity implements FileFragment.C
 
     @Override
     protected void onPostResume() {
-        //Log.e(TAG, "ACTIVITY, ONPOSTRESUME");
+        //Log_OC.e(TAG, "ACTIVITY, ONPOSTRESUME");
         super.onPostResume();
     }
     
     @Override
     public void onPause() {
-        super.onPause();
         unregisterReceiver(mDownloadFinishReceiver);
         mDownloadFinishReceiver = null;
+        super.onPause();
     }
     
 
@@ -243,53 +346,6 @@ public class PreviewImageActivity extends FileActivity implements FileFragment.C
         finish();
     }
     
-    /**
-     * Show loading dialog 
-     */
-    public void showLoadingDialog() {
-        // Construct dialog
-        LoadingDialog loading = new LoadingDialog(getResources().getString(R.string.wait_a_moment));
-        FragmentManager fm = getSupportFragmentManager();
-        FragmentTransaction ft = fm.beginTransaction();
-        loading.show(ft, DIALOG_WAIT_TAG);
-        
-    }
-    
-    /**
-     * Dismiss loading dialog
-     */
-    public void dismissLoadingDialog(){
-        Fragment frag = getSupportFragmentManager().findFragmentByTag(DIALOG_WAIT_TAG);
-      if (frag != null) {
-          LoadingDialog loading = (LoadingDialog) frag;
-            loading.dismiss();
-        }
-    }
-    
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void onFileStateChanged() {
-        // nothing to do here!
-    }
-
-    
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public FileDownloaderBinder getFileDownloaderBinder() {
-        return mDownloaderBinder;
-    }
-
-
-    @Override
-    public FileUploaderBinder getFileUploaderBinder() {
-        return mUploaderBinder;
-    }
-
-
     @Override
     public void showDetails(OCFile file) {
         Intent showDetailsIntent = new Intent(this, FileDisplayActivity.class);
@@ -333,7 +389,11 @@ public class PreviewImageActivity extends FileActivity implements FileFragment.C
                     requestForDownload(currentFile);
                 }
             }
+
+            // Call to reset image zoom to initial state
+            ((PreviewImagePagerAdapter) mViewPager.getAdapter()).resetZoom();
         }
+
     }
     
     /**
@@ -375,7 +435,7 @@ public class PreviewImageActivity extends FileActivity implements FileFragment.C
             if (getAccount().name.equals(accountName) && 
                     downloadedRemotePath != null) {
 
-                OCFile file = mStorageManager.getFileByPath(downloadedRemotePath);
+                OCFile file = getStorageManager().getFileByPath(downloadedRemotePath);
                 int position = mPreviewImagePagerAdapter.getFilePosition(file);
                 boolean downloadWasFine = intent.getBooleanExtra(FileDownloader.EXTRA_DOWNLOAD_RESULT, false);
                 //boolean isOffscreen =  Math.abs((mViewPager.getCurrentItem() - position)) <= mViewPager.getOffscreenPageLimit();
@@ -399,30 +459,41 @@ public class PreviewImageActivity extends FileActivity implements FileFragment.C
 
     }
 
+    @SuppressLint("InlinedApi")
+       public void toggleFullScreen() {
 
-    @Override
-    public boolean onTouch(View v, MotionEvent event) {
-        if (event.getAction() == MotionEvent.ACTION_UP) {
-           toggleFullScreen();
-        }
-        return true;
-    }
+        if (isHoneycombOrHigher()) {
+        
+            boolean visible = (mFullScreenAnchorView.getSystemUiVisibility()
+                    & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0;
+
+            if (visible) {
+                hideSystemUI(mFullScreenAnchorView);
+                // actionBar.hide(); // propagated through
+                // OnSystemUiVisibilityChangeListener()
+            } else {
+                showSystemUI(mFullScreenAnchorView);
+                // actionBar.show(); // propagated through
+                // OnSystemUiVisibilityChangeListener()
+            }
 
-    
-    private void toggleFullScreen() {
-        ActionBar actionBar = getSupportActionBar();
-        if (mFullScreen) {
-            actionBar.show();
-            
         } else {
-            actionBar.hide();
-            
+
+            ActionBar actionBar = getSupportActionBar();
+            if (!actionBar.isShowing()) {
+                actionBar.show();
+
+            } else {
+                actionBar.hide();
+
+            }
+
         }
-        mFullScreen = !mFullScreen;
     }
 
     @Override
     protected void onAccountSet(boolean stateWasRecovered) {
+        super.onAccountSet(stateWasRecovered);
         if (getAccount() != null) {
             OCFile file = getFile();
             /// Validate handled file  (first image to preview)
@@ -432,15 +503,14 @@ public class PreviewImageActivity extends FileActivity implements FileFragment.C
             if (!file.isImage()) {
                 throw new IllegalArgumentException("Non-image file passed as argument");
             }
-            mStorageManager = new FileDataStorageManager(getAccount(), getContentResolver());            
             
             // Update file according to DB file, if it is possible
             if (file.getFileId() > FileDataStorageManager.ROOT_PARENT_ID)            
-                file = mStorageManager.getFileById(file.getFileId());
+                file = getStorageManager().getFileById(file.getFileId());
             
             if (file != null) {
                 /// Refresh the activity according to the Account and OCFile set
-                setFile(file);  // reset after getting it fresh from mStorageManager
+                setFile(file);  // reset after getting it fresh from storageManager
                 getSupportActionBar().setTitle(getFile().getFileName());
                 //if (!stateWasRecovered) {
                     initViewPager();
@@ -450,11 +520,68 @@ public class PreviewImageActivity extends FileActivity implements FileFragment.C
                 // handled file not in the current Account
                 finish();
             }
-            
-        } else {
-            Log_OC.wtf(TAG, "onAccountChanged was called with NULL account associated!");
         }
     }
     
     
+    /**
+     * Launch an intent to request the PIN code to the user before letting him use the app
+     */
+    private void requestPinCode() {
+        boolean pinStart = false;
+        SharedPreferences appPrefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
+        pinStart = appPrefs.getBoolean("set_pincode", false);
+        if (pinStart) {
+            Intent i = new Intent(getApplicationContext(), PinCodeActivity.class);
+            i.putExtra(PinCodeActivity.EXTRA_ACTIVITY, "PreviewImageActivity");
+            startActivity(i);
+        }
+    }
+
+    @Override
+    public void onBrowsedDownTo(OCFile folder) {
+        // TODO Auto-generated method stub
+        
+    }
+
+    @Override
+    public void onTransferStateChanged(OCFile file, boolean downloading, boolean uploading) {
+        // TODO Auto-generated method stub
+        
+    }
+    
+    
+    @SuppressLint("InlinedApi")
+       private void hideSystemUI(View anchorView) {
+        anchorView.setSystemUiVisibility(
+                View.SYSTEM_UI_FLAG_HIDE_NAVIGATION         // hides NAVIGATION BAR; Android >= 4.0
+            |   View.SYSTEM_UI_FLAG_FULLSCREEN              // hides STATUS BAR;     Android >= 4.1
+            |   View.SYSTEM_UI_FLAG_IMMERSIVE               // stays interactive;    Android >= 4.4
+            |   View.SYSTEM_UI_FLAG_LAYOUT_STABLE           // draw full window;     Android >= 4.1
+            |   View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN       // draw full window;     Android >= 4.1
+            |   View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION  // draw full window;     Android >= 4.1
+        );
+    }
+    
+    @SuppressLint("InlinedApi")
+    private void showSystemUI(View anchorView) {
+        anchorView.setSystemUiVisibility(
+                View.SYSTEM_UI_FLAG_LAYOUT_STABLE           // draw full window;     Android >= 4.1
+            |   View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN       // draw full window;     Android >= 4.1
+            |   View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION  // draw full window;     Android >= 4.1
+        );
+    }
+
+    /**
+     * Checks if OS version is Honeycomb one or higher
+     * 
+     * @return boolean
+     */
+    private boolean isHoneycombOrHigher() {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
+            return true;
+        }
+        return false;
+    }
+
 }
index 9ef4db4..4dd5c43 100644 (file)
@@ -1,5 +1,5 @@
 /* ownCloud Android client application
- *   Copyright (C) 2012-2013 ownCloud Inc. 
+ *   Copyright (C) 2012-2014 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.preview;
 
+import java.io.BufferedInputStream;
 import java.io.File;
+import java.io.FileInputStream;
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
 import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-import java.util.List;
-
 
 import android.accounts.Account;
 import android.annotation.SuppressLint;
 import android.app.Activity;
-import android.content.ActivityNotFoundException;
-import android.content.Intent;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.graphics.BitmapFactory.Options;
 import android.graphics.Point;
-import android.net.Uri;
 import android.os.AsyncTask;
 import android.os.Bundle;
-import android.os.Handler;
 import android.support.v4.app.FragmentStatePagerAdapter;
 import android.view.Display;
 import android.view.LayoutInflater;
 import android.view.View;
-import android.view.View.OnTouchListener;
+import android.view.View.OnClickListener;
 import android.view.ViewGroup;
-import android.webkit.MimeTypeMap;
 import android.widget.ImageView;
 import android.widget.ProgressBar;
 import android.widget.TextView;
-import android.widget.Toast;
 
 import com.actionbarsherlock.view.Menu;
 import com.actionbarsherlock.view.MenuInflater;
 import com.actionbarsherlock.view.MenuItem;
-import com.owncloud.android.Log_OC;
 import com.owncloud.android.R;
-import com.owncloud.android.datamodel.FileDataStorageManager;
 import com.owncloud.android.datamodel.OCFile;
-import com.owncloud.android.operations.OnRemoteOperationListener;
-import com.owncloud.android.operations.RemoteOperation;
-import com.owncloud.android.operations.RemoteOperationResult;
-import com.owncloud.android.operations.RemoveFileOperation;
-import com.owncloud.android.ui.fragment.ConfirmationDialogFragment;
+import com.owncloud.android.files.FileMenuFilter;
+import com.owncloud.android.lib.common.utils.Log_OC;
+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.TouchImageViewCustom;
 
-import eu.alefzero.webdav.WebdavUtils;
 
 
 /**
@@ -73,23 +66,19 @@ import eu.alefzero.webdav.WebdavUtils;
  * 
  * @author David A. Velasco
  */
-public class PreviewImageFragment extends FileFragment implements   OnRemoteOperationListener, 
-                                                                        ConfirmationDialogFragment.ConfirmationDialogFragmentListener {
+public class PreviewImageFragment extends FileFragment {
+
     public static final String EXTRA_FILE = "FILE";
     public static final String EXTRA_ACCOUNT = "ACCOUNT";
 
     private View mView;
     private Account mAccount;
-    private FileDataStorageManager mStorageManager;
-    private ImageView mImageView;
+    private TouchImageViewCustom mImageView;
     private TextView mMessageView;
     private ProgressBar mProgressWheel;
 
     public Bitmap mBitmap = null;
     
-    private Handler mHandler;
-    private RemoteOperation mLastRemoteOperation;
-    
     private static final String TAG = PreviewImageFragment.class.getSimpleName();
 
     private boolean mIgnoreFirstSavedState;
@@ -107,7 +96,6 @@ public class PreviewImageFragment extends FileFragment implements   OnRemoteOper
     public PreviewImageFragment(OCFile fileToDetail, Account ocAccount, boolean ignoreFirstSavedState) {
         super(fileToDetail);
         mAccount = ocAccount;
-        mStorageManager = null; // we need a context to init this; the container activity is not available yet at this moment
         mIgnoreFirstSavedState = ignoreFirstSavedState;
     }
     
@@ -122,7 +110,6 @@ public class PreviewImageFragment extends FileFragment implements   OnRemoteOper
     public PreviewImageFragment() {
         super();
         mAccount = null;
-        mStorageManager = null;
         mIgnoreFirstSavedState = false;
     }
     
@@ -133,7 +120,6 @@ public class PreviewImageFragment extends FileFragment implements   OnRemoteOper
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        mHandler = new Handler();
         setHasOptionsMenu(true);
     }
     
@@ -146,38 +132,32 @@ public class PreviewImageFragment extends FileFragment implements   OnRemoteOper
             Bundle savedInstanceState) {
         super.onCreateView(inflater, container, savedInstanceState);
         mView = inflater.inflate(R.layout.preview_image_fragment, container, false);
-        mImageView = (ImageView)mView.findViewById(R.id.image);
+        mImageView = (TouchImageViewCustom) mView.findViewById(R.id.image);
         mImageView.setVisibility(View.GONE);
-        mView.setOnTouchListener((OnTouchListener)getActivity());   // WATCH OUT THAT CAST
+        mImageView.setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                ((PreviewImageActivity) getActivity()).toggleFullScreen();
+            }
+
+        });
         mMessageView = (TextView)mView.findViewById(R.id.message);
         mMessageView.setVisibility(View.GONE);
         mProgressWheel = (ProgressBar)mView.findViewById(R.id.progressWheel);
         mProgressWheel.setVisibility(View.VISIBLE);
         return mView;
     }
-    
 
     /**
      * {@inheritDoc}
      */
     @Override
-    public void onAttach(Activity activity) {
-        super.onAttach(activity);
-        if (!(activity instanceof FileFragment.ContainerActivity))
-            throw new ClassCastException(activity.toString() + " must implement " + FileFragment.ContainerActivity.class.getSimpleName());
-    }
-    
-    
-    /**
-     * {@inheritDoc}
-     */
-    @Override
     public void onActivityCreated(Bundle savedInstanceState) {
         super.onActivityCreated(savedInstanceState);
-        mStorageManager = new FileDataStorageManager(mAccount, getActivity().getApplicationContext().getContentResolver());
         if (savedInstanceState != null) {
             if (!mIgnoreFirstSavedState) {
-                setFile((OCFile)savedInstanceState.getParcelable(PreviewImageFragment.EXTRA_FILE));
+                OCFile file = (OCFile)savedInstanceState.getParcelable(PreviewImageFragment.EXTRA_FILE);
+                setFile(file);
                 mAccount = savedInstanceState.getParcelable(PreviewImageFragment.EXTRA_ACCOUNT);
             } else {
                 mIgnoreFirstSavedState = false;
@@ -222,54 +202,100 @@ public class PreviewImageFragment extends FileFragment implements   OnRemoteOper
     @Override
     public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
         super.onCreateOptionsMenu(menu, inflater);
-
         inflater.inflate(R.menu.file_actions_menu, menu);
-        List<Integer> toHide = new ArrayList<Integer>();    
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void onPrepareOptionsMenu(Menu menu) {
+        super.onPrepareOptionsMenu(menu);
         
-        MenuItem item = null;
-        toHide.add(R.id.action_cancel_download);
-        toHide.add(R.id.action_cancel_upload);
-        toHide.add(R.id.action_download_file);
-        toHide.add(R.id.action_rename_file);    // by now
-
-        for (int i : toHide) {
-            item = menu.findItem(i);
-            if (item != null) {
-                item.setVisible(false);
-                item.setEnabled(false);
-            }
+        if (mContainerActivity.getStorageManager() != null) {
+            // Update the file
+            setFile(mContainerActivity.getStorageManager().getFileById(getFile().getFileId()));
+            
+            FileMenuFilter mf = new FileMenuFilter(
+                getFile(),
+                mContainerActivity.getStorageManager().getAccount(),
+                mContainerActivity,
+                getSherlockActivity()
+            );
+            mf.filter(menu);
+        }
+        
+        // additional restriction for this fragment 
+        // TODO allow renaming in PreviewImageFragment
+        MenuItem item = menu.findItem(R.id.action_rename_file);
+        if (item != null) {
+            item.setVisible(false);
+            item.setEnabled(false);
+        }
+        
+        // additional restriction for this fragment 
+        // TODO allow refresh file in PreviewImageFragment
+        item = menu.findItem(R.id.action_sync_file);
+        if (item != null) {
+            item.setVisible(false);
+            item.setEnabled(false);
+        }
+
+        // additional restriction for this fragment
+        item = menu.findItem(R.id.action_move);
+        if (item != null) {
+            item.setVisible(false);
+            item.setEnabled(false);
         }
         
     }
 
     
+    
     /**
      * {@inheritDoc}
      */
     @Override
     public boolean onOptionsItemSelected(MenuItem item) {
         switch (item.getItemId()) {
+            case R.id.action_share_file: {
+                mContainerActivity.getFileOperationsHelper().shareFileWithLink(getFile());
+                return true;
+            }
+            case R.id.action_unshare_file: {
+                mContainerActivity.getFileOperationsHelper().unshareFileWithLink(getFile());
+                return true;
+            }
             case R.id.action_open_file_with: {
                 openFile();
                 return true;
             }
             case R.id.action_remove_file: {
-                removeFile();
+                RemoveFileDialogFragment dialog = RemoveFileDialogFragment.newInstance(getFile());
+                dialog.show(getFragmentManager(), ConfirmationDialogFragment.FTAG_CONFIRMATION);
                 return true;
             }
             case R.id.action_see_details: {
                 seeDetails();
                 return true;
             }
+            case R.id.action_send_file: {
+                mContainerActivity.getFileOperationsHelper().sendDownloadedFile(getFile());
+                return true;
+            }
+            case R.id.action_sync_file: {
+                mContainerActivity.getFileOperationsHelper().syncFile(getFile());
+                return true;
+            }
             
             default:
                 return false;
         }
     }
-
     
+
     private void seeDetails() {
-        ((FileFragment.ContainerActivity)getActivity()).showDetails(getFile());        
+        mContainerActivity.showDetails(getFile());        
     }
 
 
@@ -284,131 +310,25 @@ public class PreviewImageFragment extends FileFragment implements   OnRemoteOper
         super.onPause();
     }
 
-
     @Override
     public void onDestroy() {
-        super.onDestroy();
         if (mBitmap != null) {
             mBitmap.recycle();
+            System.gc();
         }
+        super.onDestroy();
     }
 
     
     /**
      * Opens the previewed image with an external application.
-     * 
-     * TODO - improve this; instead of prioritize the actions available for the MIME type in the server, 
-     * we should get a list of available apps for MIME tpye in the server and join it with the list of 
-     * available apps for the MIME type known from the file extension, to let the user choose
      */
     private void openFile() {
-        OCFile file = getFile();
-        String storagePath = file.getStoragePath();
-        String encodedStoragePath = WebdavUtils.encodePath(storagePath);
-        try {
-            Intent i = new Intent(Intent.ACTION_VIEW);
-            i.setDataAndType(Uri.parse("file://"+ encodedStoragePath), file.getMimetype());
-            i.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
-            startActivity(i);
-            
-        } catch (Throwable t) {
-            Log_OC.e(TAG, "Fail when trying to open with the mimeType provided from the ownCloud server: " + file.getMimetype());
-            boolean toastIt = true; 
-            String mimeType = "";
-            try {
-                Intent i = new Intent(Intent.ACTION_VIEW);
-                mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(storagePath.substring(storagePath.lastIndexOf('.') + 1));
-                if (mimeType == null || !mimeType.equals(file.getMimetype())) {
-                    if (mimeType != null) {
-                        i.setDataAndType(Uri.parse("file://"+ encodedStoragePath), mimeType);
-                    } else {
-                        // desperate try
-                        i.setDataAndType(Uri.parse("file://"+ encodedStoragePath), "*-/*");
-                    }
-                    i.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
-                    startActivity(i);
-                    toastIt = false;
-                }
-                
-            } catch (IndexOutOfBoundsException e) {
-                Log_OC.e(TAG, "Trying to find out MIME type of a file without extension: " + storagePath);
-                
-            } catch (ActivityNotFoundException e) {
-                Log_OC.e(TAG, "No activity found to handle: " + storagePath + " with MIME type " + mimeType + " obtained from extension");
-                
-            } catch (Throwable th) {
-                Log_OC.e(TAG, "Unexpected problem when opening: " + storagePath, th);
-                
-            } finally {
-                if (toastIt) {
-                    Toast.makeText(getActivity(), "There is no application to handle file " + file.getFileName(), Toast.LENGTH_SHORT).show();
-                }
-            }
-            
-        }
+        mContainerActivity.getFileOperationsHelper().openFile(getFile());
         finish();
     }
     
     
-    /**
-     * Starts a the removal of the previewed file.
-     * 
-     * Shows a confirmation dialog. The action continues in {@link #onConfirmation(String)} , {@link #onNeutral(String)} or {@link #onCancel(String)},
-     * depending upon the user selection in the dialog. 
-     */
-    private void removeFile() {
-        ConfirmationDialogFragment confDialog = ConfirmationDialogFragment.newInstance(
-                R.string.confirmation_remove_alert,
-                new String[]{getFile().getFileName()},
-                R.string.confirmation_remove_remote_and_local,
-                R.string.confirmation_remove_local,
-                R.string.common_cancel);
-        confDialog.setOnConfirmationListener(this);
-        confDialog.show(getFragmentManager(), ConfirmationDialogFragment.FTAG_CONFIRMATION);
-    }
-
-    
-    /**
-     * Performs the removal of the previewed file, both locally and in the server.
-     */
-    @Override
-    public void onConfirmation(String callerTag) {
-        if (mStorageManager.getFileById(getFile().getFileId()) != null) {   // check that the file is still there;
-            mLastRemoteOperation = new RemoveFileOperation( getFile(),      // TODO we need to review the interface with RemoteOperations, and use OCFile IDs instead of OCFile objects as parameters
-                                                            true, 
-                                                            mStorageManager);
-            mLastRemoteOperation.execute(mAccount, getSherlockActivity(), this, mHandler, getSherlockActivity());
-            
-            ((PreviewImageActivity) getActivity()).showLoadingDialog();
-        }
-    }
-    
-    
-    /**
-     * Removes the file from local storage
-     */
-    @Override
-    public void onNeutral(String callerTag) {
-        // TODO this code should be made in a secondary thread,
-        OCFile file = getFile();
-        if (file.isDown()) {   // checks it is still there
-            File f = new File(file.getStoragePath());
-            f.delete();
-            file.setStoragePath(null);
-            mStorageManager.saveFile(file);
-            finish();
-        }
-    }
-    
-    /**
-     * User cancelled the removal action.
-     */
-    @Override
-    public void onCancel(String callerTag) {
-        // nothing to do here
-    }
-    
-
     private class BitmapLoader extends AsyncTask<String, Void, Bitmap> {
 
         /**
@@ -416,7 +336,7 @@ public class PreviewImageFragment extends FileFragment implements   OnRemoteOper
          * 
          * Using a weak reference will avoid memory leaks if the target ImageView is retired from memory before the load finishes.
          */
-        private final WeakReference<ImageView> mImageViewRef;
+        private final WeakReference<ImageViewCustom> mImageViewRef;
 
         /**
          * Weak reference to the target {@link TextView} where error messages will be written.
@@ -445,65 +365,27 @@ public class PreviewImageFragment extends FileFragment implements   OnRemoteOper
          * 
          * @param imageView     Target {@link ImageView} where the bitmap will be loaded into.
          */
-        public BitmapLoader(ImageView imageView, TextView messageView, ProgressBar progressWheel) {
-            mImageViewRef = new WeakReference<ImageView>(imageView);
+        public BitmapLoader(ImageViewCustom imageView, TextView messageView, ProgressBar progressWheel) {
+            mImageViewRef = new WeakReference<ImageViewCustom>(imageView);
             mMessageViewRef = new WeakReference<TextView>(messageView);
             mProgressWheelRef = new WeakReference<ProgressBar>(progressWheel);
         }
         
         
-        @SuppressWarnings("deprecation")
-        @SuppressLint({ "NewApi", "NewApi", "NewApi" }) // to avoid Lint errors since Android SDK r20
-               @Override
+        @Override
         protected Bitmap doInBackground(String... params) {
             Bitmap result = null;
             if (params.length != 1) return result;
             String storagePath = params[0];
             try {
-                // set desired options that will affect the size of the bitmap
-                BitmapFactory.Options options = new Options();
-                options.inScaled = true;
-                options.inPurgeable = true;
-                if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.GINGERBREAD_MR1) {
-                    options.inPreferQualityOverSpeed = false;
-                }
-                if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) {
-                    options.inMutable = false;
-                }
-                // make a false load of the bitmap - just to be able to read outWidth, outHeight and outMimeType
-                options.inJustDecodeBounds = true;
-                BitmapFactory.decodeFile(storagePath, options);   
-                
-                int width = options.outWidth;
-                int height = options.outHeight;
-                int scale = 1;
-                
-                Display display = getActivity().getWindowManager().getDefaultDisplay();
-                Point size = new Point();
-                int screenWidth;
-                int screenHeight;
-                if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB_MR2) {
-                    display.getSize(size);
-                    screenWidth = size.x;
-                    screenHeight = size.y;
-                } else {
-                    screenWidth = display.getWidth();
-                    screenHeight = display.getHeight();
-                }
 
-                if (width > screenWidth) {
-                    // second try to scale down the image , this time depending upon the screen size 
-                    scale = (int) Math.floor((float)width / screenWidth);
-                }
-                if (height > screenHeight) {
-                    scale = Math.max(scale, (int) Math.floor((float)height / screenHeight));
-                }
-                options.inSampleSize = scale;
+                File picture = new File(storagePath);
 
-                // really load the bitmap
-                options.inJustDecodeBounds = false; // the next decodeFile call will be real
-                result = BitmapFactory.decodeFile(storagePath, options);
-                //Log_OC.d(TAG, "Image loaded - width: " + options.outWidth + ", loaded height: " + options.outHeight);
+                if (picture != null) {
+                    //Decode file into a bitmap in real size for being able to make zoom on the image
+                    result = BitmapFactory.decodeStream(new FlushedInputStream
+                            (new BufferedInputStream(new FileInputStream(picture))));
+                }
 
                 if (result == null) {
                     mErrorMessageId = R.string.preview_image_error_unknown_format;
@@ -511,8 +393,15 @@ public class PreviewImageFragment extends FileFragment implements   OnRemoteOper
                 }
                 
             } catch (OutOfMemoryError e) {
-                mErrorMessageId = R.string.preview_image_error_unknown_format;
                 Log_OC.e(TAG, "Out of memory occured for file " + storagePath, e);
+
+                // If out of memory error when loading image, try to load it scaled
+                result = loadScaledImage(storagePath);
+
+                if (result == null) {
+                    mErrorMessageId = R.string.preview_image_error_unknown_format;
+                    Log_OC.e(TAG, "File could not be loaded as a bitmap: " + storagePath);
+                }
                     
             } catch (NoSuchFieldError e) {
                 mErrorMessageId = R.string.common_error_unknown;
@@ -535,11 +424,13 @@ public class PreviewImageFragment extends FileFragment implements   OnRemoteOper
                 showErrorMessage();
             }
         }
-        
+
+        @SuppressLint("InlinedApi")
         private void showLoadedImage(Bitmap result) {
             if (mImageViewRef != null) {
-                final ImageView imageView = mImageViewRef.get();
+                final ImageViewCustom imageView = mImageViewRef.get();
                 if (imageView != null) {
+                    imageView.setBitmap(result);
                     imageView.setImageBitmap(result);
                     imageView.setVisibility(View.VISIBLE);
                     mBitmap  = result;
@@ -593,39 +484,94 @@ public class PreviewImageFragment extends FileFragment implements   OnRemoteOper
 
     
     /**
-     * {@inheritDoc}
+     * Finishes the preview
      */
-    @Override
-    public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationResult result) {
-        if (operation.equals(mLastRemoteOperation) && operation instanceof RemoveFileOperation) {
-            onRemoveFileOperationFinish((RemoveFileOperation)operation, result);
-        }
+    private void finish() {
+        Activity container = getActivity();
+        container.finish();
     }
     
-    private void onRemoveFileOperationFinish(RemoveFileOperation operation, RemoteOperationResult result) {
-        ((PreviewImageActivity) getActivity()).dismissLoadingDialog();
-        
-        if (result.isSuccess()) {
-            Toast msg = Toast.makeText(getActivity().getApplicationContext(), R.string.remove_success_msg, Toast.LENGTH_LONG);
-            msg.show();
-            finish();
-                
-        } else {
-            Toast msg = Toast.makeText(getActivity(), R.string.remove_fail_msg, Toast.LENGTH_LONG); 
-            msg.show();
-            if (result.isSslRecoverableException()) {
-                // TODO show the SSL warning dialog
+    public TouchImageViewCustom getImageView() {
+        return mImageView;
+    }
+
+    static class FlushedInputStream extends FilterInputStream {
+        public FlushedInputStream(InputStream inputStream) {
+        super(inputStream);
+        }
+
+        @Override
+        public long skip(long n) throws IOException {
+            long totalBytesSkipped = 0L;
+            while (totalBytesSkipped < n) {
+                long bytesSkipped = in.skip(n - totalBytesSkipped);
+                if (bytesSkipped == 0L) {
+                      int byteValue = read();
+                      if (byteValue < 0) {
+                          break;  // we reached EOF
+                      } else {
+                          bytesSkipped = 1; // we read one byte
+                      }
+               }
+               totalBytesSkipped += bytesSkipped;
             }
+            return totalBytesSkipped;
         }
     }
 
     /**
-     * Finishes the preview
+     * Load image scaled
+     * @param storagePath: path of the image
+     * @return Bitmap
      */
-    private void finish() {
-        Activity container = getActivity();
-        container.finish();
+    @SuppressWarnings("deprecation")
+    private Bitmap loadScaledImage(String storagePath) {
+
+        Log_OC.d(TAG, "Loading image scaled");
+
+        // set desired options that will affect the size of the bitmap
+        BitmapFactory.Options options = new Options();
+        options.inScaled = true;
+        options.inPurgeable = true;
+        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.GINGERBREAD_MR1) {
+            options.inPreferQualityOverSpeed = false;
+        }
+        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) {
+            options.inMutable = false;
+        }
+        // make a false load of the bitmap - just to be able to read outWidth, outHeight and outMimeType
+        options.inJustDecodeBounds = true;
+        BitmapFactory.decodeFile(storagePath, options);
+
+        int width = options.outWidth;
+        int height = options.outHeight;
+        int scale = 1;
+
+        Display display = getActivity().getWindowManager().getDefaultDisplay();
+        Point size = new Point();
+        int screenWidth;
+        int screenHeight;
+        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB_MR2) {
+            display.getSize(size);
+            screenWidth = size.x;
+            screenHeight = size.y;
+        } else {
+            screenWidth = display.getWidth();
+            screenHeight = display.getHeight();
+        }
+
+        if (width > screenWidth) {
+            // second try to scale down the image , this time depending upon the screen size 
+            scale = (int) Math.floor((float)width / screenWidth);
+        }
+        if (height > screenHeight) {
+            scale = Math.max(scale, (int) Math.floor((float)height / screenHeight));
+        }
+        options.inSampleSize = scale;
+
+        // really load the bitmap
+        options.inJustDecodeBounds = false; // the next decodeFile call will be real
+        return BitmapFactory.decodeFile(storagePath, options);
+
     }
-    
-    
 }
index de90b4b..f2a9a9b 100644 (file)
@@ -18,13 +18,11 @@ package com.owncloud.android.ui.preview;
 
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.Map;
 import java.util.Set;
 import java.util.Vector;
 
-import com.owncloud.android.datamodel.OCFile;
-import com.owncloud.android.ui.fragment.FileFragment;
-
 import android.accounts.Account;
 import android.support.v4.app.Fragment;
 import android.support.v4.app.FragmentManager;
@@ -32,6 +30,8 @@ import android.support.v4.app.FragmentStatePagerAdapter;
 import android.view.ViewGroup;
 
 import com.owncloud.android.datamodel.FileDataStorageManager;
+import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.ui.fragment.FileFragment;
 
 /**
  * Adapter class that provides Fragment instances  
@@ -179,6 +179,19 @@ public class PreviewImagePagerAdapter extends FragmentStatePagerAdapter {
         return mDownloadErrors.contains(Integer.valueOf(position));
     }
 
+    /**
+     * Reset the image zoom to default value for each CachedFragments
+     */
+    public void resetZoom() {
+        Iterator<FileFragment> entries = mCachedFragments.values().iterator();
+        while (entries.hasNext()) {
+        FileFragment fileFragment = (FileFragment) entries.next();
+            if (fileFragment instanceof PreviewImageFragment) {
+                ((PreviewImageFragment) fileFragment).getImageView().resetZoom();
+            }
+        }
+    }
+
     /* -*
      * Called when a change in the shown pages is going to start being made.
      * 
@@ -186,17 +199,17 @@ public class PreviewImagePagerAdapter extends FragmentStatePagerAdapter {
      *- /
     @Override
     public void startUpdate(ViewGroup container) {
-        Log.e(TAG, "** startUpdate");
+        Log_OC.e(TAG, "** startUpdate");
     }
 
     @Override
     public Object instantiateItem(ViewGroup container, int position) {
-        Log.e(TAG, "** instantiateItem " + position);
+        Log_OC.e(TAG, "** instantiateItem " + position);
         
         if (mFragments.size() > position) {
             Fragment fragment = mFragments.get(position);
             if (fragment != null) {
-                Log.e(TAG, "** \t returning cached item");
+                Log_OC.e(TAG, "** \t returning cached item");
                 return fragment;
             }
         }
@@ -222,7 +235,7 @@ public class PreviewImagePagerAdapter extends FragmentStatePagerAdapter {
         }
         fragment.setMenuVisibility(false);
         mFragments.set(position, fragment);
-        //Log.e(TAG, "** \t adding fragment at position " + position + ", containerId " + container.getId());
+        //Log_OC.e(TAG, "** \t adding fragment at position " + position + ", containerId " + container.getId());
         mCurTransaction.add(container.getId(), fragment);
 
         return fragment;
@@ -230,13 +243,13 @@ public class PreviewImagePagerAdapter extends FragmentStatePagerAdapter {
 
     @Override
     public void destroyItem(ViewGroup container, int position, Object object) {
-        Log.e(TAG, "** destroyItem " + position);
+        Log_OC.e(TAG, "** destroyItem " + position);
         Fragment fragment = (Fragment)object;
         
         if (mCurTransaction == null) {
             mCurTransaction = mFragmentManager.beginTransaction();
         }
-        Log.e(TAG, "** \t removing fragment at position " + position);
+        Log_OC.e(TAG, "** \t removing fragment at position " + position);
         while (mSavedState.size() <= position) {
             mSavedState.add(null);
         }
@@ -262,13 +275,13 @@ public class PreviewImagePagerAdapter extends FragmentStatePagerAdapter {
 
     @Override
     public void finishUpdate(ViewGroup container) {
-        Log.e(TAG, "** finishUpdate (start)");
+        Log_OC.e(TAG, "** finishUpdate (start)");
         if (mCurTransaction != null) {
             mCurTransaction.commitAllowingStateLoss();
             mCurTransaction = null;
             mFragmentManager.executePendingTransactions();
         }
-        Log.e(TAG, "** finishUpdate (end)");
+        Log_OC.e(TAG, "** finishUpdate (end)");
     }
 
     @Override
@@ -323,7 +336,7 @@ public class PreviewImagePagerAdapter extends FragmentStatePagerAdapter {
                         f.setMenuVisibility(false);
                         mFragments.set(index, f);
                     } else {
-                        Log.w(TAG, "Bad fragment at key " + key);
+                        Log_OC.w(TAG, "Bad fragment at key " + key);
                     }
                 }
             }
index 815dbbd..7d6489b 100644 (file)
  */
 package com.owncloud.android.ui.preview;
 
-import java.io.File;
-import java.util.ArrayList;
-import java.util.List;
-
 import android.accounts.Account;
 import android.app.Activity;
 import android.app.AlertDialog;
-import android.content.ActivityNotFoundException;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.DialogInterface;
@@ -37,14 +32,12 @@ import android.media.MediaPlayer.OnPreparedListener;
 import android.net.Uri;
 import android.os.Build;
 import android.os.Bundle;
-import android.os.Handler;
 import android.os.IBinder;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.View.OnTouchListener;
 import android.view.ViewGroup;
-import android.webkit.MimeTypeMap;
 import android.widget.ImageView;
 import android.widget.Toast;
 import android.widget.VideoView;
@@ -52,23 +45,18 @@ import android.widget.VideoView;
 import com.actionbarsherlock.view.Menu;
 import com.actionbarsherlock.view.MenuInflater;
 import com.actionbarsherlock.view.MenuItem;
-import com.owncloud.android.Log_OC;
 import com.owncloud.android.R;
-import com.owncloud.android.datamodel.FileDataStorageManager;
 import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.files.FileMenuFilter;
+import com.owncloud.android.lib.common.utils.Log_OC;
 import com.owncloud.android.media.MediaControlView;
 import com.owncloud.android.media.MediaService;
 import com.owncloud.android.media.MediaServiceBinder;
-import com.owncloud.android.operations.OnRemoteOperationListener;
-import com.owncloud.android.operations.RemoteOperation;
-import com.owncloud.android.operations.RemoteOperationResult;
-import com.owncloud.android.operations.RemoveFileOperation;
 import com.owncloud.android.ui.activity.FileActivity;
-import com.owncloud.android.ui.activity.FileDisplayActivity;
-import com.owncloud.android.ui.fragment.ConfirmationDialogFragment;
+import com.owncloud.android.ui.dialog.ConfirmationDialogFragment;
+import com.owncloud.android.ui.dialog.RemoveFileDialogFragment;
 import com.owncloud.android.ui.fragment.FileFragment;
 
-import eu.alefzero.webdav.WebdavUtils;
 
 /**
  * This fragment shows a preview of a downloaded media file (audio or video).
@@ -80,8 +68,7 @@ import eu.alefzero.webdav.WebdavUtils;
  * @author David A. Velasco
  */
 public class PreviewMediaFragment extends FileFragment implements
-        OnTouchListener,  
-        ConfirmationDialogFragment.ConfirmationDialogFragmentListener, OnRemoteOperationListener  {
+        OnTouchListener {
 
     public static final String EXTRA_FILE = "FILE";
     public static final String EXTRA_ACCOUNT = "ACCOUNT";
@@ -90,14 +77,10 @@ public class PreviewMediaFragment extends FileFragment implements
 
     private View mView;
     private Account mAccount;
-    private FileDataStorageManager mStorageManager;
     private ImageView mImagePreview;
     private VideoView mVideoPreview;
     private int mSavedPlaybackPosition;
     
-    private Handler mHandler;
-    private RemoteOperation mLastRemoteOperation;
-    
     private MediaServiceBinder mMediaServiceBinder = null;
     private MediaControlView mMediaController = null;
     private MediaServiceConnection mMediaServiceConnection = null;
@@ -116,11 +99,15 @@ public class PreviewMediaFragment extends FileFragment implements
      * @param fileToDetail      An {@link OCFile} to preview in the fragment
      * @param ocAccount         An ownCloud account; needed to start downloads
      */
-    public PreviewMediaFragment(OCFile fileToDetail, Account ocAccount, int startPlaybackPosition, boolean autoplay) {
+    public PreviewMediaFragment(
+            OCFile fileToDetail, 
+            Account ocAccount, 
+            int startPlaybackPosition, 
+            boolean autoplay) {
+        
         super(fileToDetail);
         mAccount = ocAccount;
         mSavedPlaybackPosition = startPlaybackPosition;
-        mStorageManager = null; // we need a context to init this; the container activity is not available yet at this moment 
         mAutoplay = autoplay;
     }
     
@@ -128,15 +115,16 @@ public class PreviewMediaFragment extends FileFragment implements
     /**
      *  Creates an empty fragment for previews.
      * 
-     *  MUST BE KEPT: the system uses it when tries to reinstantiate a fragment automatically (for instance, when the device is turned a aside).
+     *  MUST BE KEPT: the system uses it when tries to reinstantiate a fragment automatically 
+     *  (for instance, when the device is turned a aside).
      * 
-     *  DO NOT CALL IT: an {@link OCFile} and {@link Account} must be provided for a successful construction 
+     *  DO NOT CALL IT: an {@link OCFile} and {@link Account} must be provided for a successful 
+     *  construction 
      */
     public PreviewMediaFragment() {
         super();
         mAccount = null;
         mSavedPlaybackPosition = 0;
-        mStorageManager = null;
         mAutoplay = true;
     }
     
@@ -147,7 +135,6 @@ public class PreviewMediaFragment extends FileFragment implements
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        mHandler = new Handler();
         setHasOptionsMenu(true);
     }
     
@@ -178,49 +165,41 @@ public class PreviewMediaFragment extends FileFragment implements
      * {@inheritDoc}
      */
     @Override
-    public void onAttach(Activity activity) {
-        super.onAttach(activity);
-        Log_OC.e(TAG, "onAttach");
-        
-        if (!(activity instanceof FileFragment.ContainerActivity))
-            throw new ClassCastException(activity.toString() + " must implement " + FileFragment.ContainerActivity.class.getSimpleName());
-    }
-    
-    
-    /**
-     * {@inheritDoc}
-     */
-    @Override
     public void onActivityCreated(Bundle savedInstanceState) {
         super.onActivityCreated(savedInstanceState);
         Log_OC.e(TAG, "onActivityCreated");
 
-        mStorageManager = new FileDataStorageManager(mAccount, getActivity().getApplicationContext().getContentResolver());
-        if (savedInstanceState != null) {
-            setFile((OCFile)savedInstanceState.getParcelable(PreviewMediaFragment.EXTRA_FILE));
+        OCFile file = getFile();
+        if (savedInstanceState == null) {
+            if (file == null) {
+                throw new IllegalStateException("Instanced with a NULL OCFile");
+            }
+            if (mAccount == null) {
+                throw new IllegalStateException("Instanced with a NULL ownCloud Account");
+            }
+            if (!file.isDown()) {
+                throw new IllegalStateException("There is no local file to preview");
+            }
+            
+        } else {
+            file = (OCFile)savedInstanceState.getParcelable(PreviewMediaFragment.EXTRA_FILE);
+            setFile(file);
             mAccount = savedInstanceState.getParcelable(PreviewMediaFragment.EXTRA_ACCOUNT);
-            mSavedPlaybackPosition = savedInstanceState.getInt(PreviewMediaFragment.EXTRA_PLAY_POSITION);
+            mSavedPlaybackPosition = 
+                    savedInstanceState.getInt(PreviewMediaFragment.EXTRA_PLAY_POSITION);
             mAutoplay = savedInstanceState.getBoolean(PreviewMediaFragment.EXTRA_PLAYING);
             
         }
-        OCFile file = getFile();
-        if (file == null) {
-            throw new IllegalStateException("Instanced with a NULL OCFile");
-        }
-        if (mAccount == null) {
-            throw new IllegalStateException("Instanced with a NULL ownCloud Account");
-        }
-        if (!file.isDown()) {
-            throw new IllegalStateException("There is no local file to preview");
-        }
-        if (file.isVideo()) {
-            mVideoPreview.setVisibility(View.VISIBLE);
-            mImagePreview.setVisibility(View.GONE);
-            prepareVideo();
+        if (file != null && file.isDown()) {
+            if (file.isVideo()) {
+                mVideoPreview.setVisibility(View.VISIBLE);
+                mImagePreview.setVisibility(View.GONE);
+                prepareVideo();
             
-        } else {
-            mVideoPreview.setVisibility(View.GONE);
-            mImagePreview.setVisibility(View.VISIBLE);
+            } else {
+                mVideoPreview.setVisibility(View.GONE);
+                mImagePreview.setVisibility(View.VISIBLE);
+            }
         }
         
     }
@@ -243,8 +222,11 @@ public class PreviewMediaFragment extends FileFragment implements
             outState.putInt(PreviewMediaFragment.EXTRA_PLAY_POSITION , mSavedPlaybackPosition);
             outState.putBoolean(PreviewMediaFragment.EXTRA_PLAYING , mAutoplay);
         } else {
-            outState.putInt(PreviewMediaFragment.EXTRA_PLAY_POSITION , mMediaServiceBinder.getCurrentPosition());
-            outState.putBoolean(PreviewMediaFragment.EXTRA_PLAYING , mMediaServiceBinder.isPlaying());
+            outState.putInt(
+                    PreviewMediaFragment.EXTRA_PLAY_POSITION , 
+                    mMediaServiceBinder.getCurrentPosition());
+            outState.putBoolean(
+                    PreviewMediaFragment.EXTRA_PLAYING , mMediaServiceBinder.isPlaying());
         }
     }
     
@@ -255,7 +237,7 @@ public class PreviewMediaFragment extends FileFragment implements
         Log_OC.e(TAG, "onStart");
 
         OCFile file = getFile();
-        if (file != null) {
+        if (file != null && file.isDown()) {
            if (file.isAudio()) {
                bindMediaService();
                
@@ -280,27 +262,43 @@ public class PreviewMediaFragment extends FileFragment implements
     @Override
     public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
         super.onCreateOptionsMenu(menu, inflater);
-
         inflater.inflate(R.menu.file_actions_menu, menu);
-        List<Integer> toHide = new ArrayList<Integer>();    
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void onPrepareOptionsMenu(Menu menu) {
+        super.onPrepareOptionsMenu(menu);
         
-        MenuItem item = null;
-        toHide.add(R.id.action_cancel_download);
-        toHide.add(R.id.action_cancel_upload);
-        toHide.add(R.id.action_download_file);
-        toHide.add(R.id.action_sync_file);
-        toHide.add(R.id.action_rename_file);    // by now
-
-        for (int i : toHide) {
-            item = menu.findItem(i);
-            if (item != null) {
-                item.setVisible(false);
-                item.setEnabled(false);
-            }
+        if (mContainerActivity.getStorageManager() != null) {
+            FileMenuFilter mf = new FileMenuFilter(
+                getFile(),
+                mContainerActivity.getStorageManager().getAccount(),
+                mContainerActivity,
+                getSherlockActivity()
+            );
+            mf.filter(menu);
+        }
+
+        // additional restriction for this fragment 
+        // TODO allow renaming in PreviewImageFragment
+        MenuItem item = menu.findItem(R.id.action_rename_file);
+        if (item != null) {
+            item.setVisible(false);
+            item.setEnabled(false);
         }
-        
-    }
 
+        // additional restriction for this fragment
+        item = menu.findItem(R.id.action_move);
+        if (item != null) {
+            item.setVisible(false);
+            item.setEnabled(false);
+        }
+    }
+    
     
     /**
      * {@inheritDoc}
@@ -308,28 +306,62 @@ public class PreviewMediaFragment extends FileFragment implements
     @Override
     public boolean onOptionsItemSelected(MenuItem item) {
         switch (item.getItemId()) {
+            case R.id.action_share_file: {
+                stopPreview(false);
+                mContainerActivity.getFileOperationsHelper().shareFileWithLink(getFile());
+                return true;
+            }
+            case R.id.action_unshare_file: {
+                stopPreview(false);
+                mContainerActivity.getFileOperationsHelper().unshareFileWithLink(getFile());
+                return true;
+            }
             case R.id.action_open_file_with: {
                 openFile();
                 return true;
             }
             case R.id.action_remove_file: {
-                removeFile();
+                RemoveFileDialogFragment dialog = RemoveFileDialogFragment.newInstance(getFile());
+                dialog.show(getFragmentManager(), ConfirmationDialogFragment.FTAG_CONFIRMATION);
                 return true;
             }
             case R.id.action_see_details: {
                 seeDetails();
                 return true;
             }
-            
+            case R.id.action_send_file: {
+                sendFile();
+                return true;
+            }
+            case R.id.action_sync_file: {
+                mContainerActivity.getFileOperationsHelper().syncFile(getFile());
+                return true;
+            }
+
             default:
                 return false;
         }
     }
+    
 
+
+    /**
+     * Update the file of the fragment with file value
+     * @param file
+     */
+    public void updateFile(OCFile file){
+        setFile(file);
+    }
     
+    private void sendFile() {
+        stopPreview(false);
+        mContainerActivity.getFileOperationsHelper().sendDownloadedFile(getFile());
+        
+    }
+
     private void seeDetails() {
         stopPreview(false);
-        ((FileFragment.ContainerActivity)getActivity()).showDetails(getFile());        
+        mContainerActivity.showDetails(getFile());        
     }
 
 
@@ -341,12 +373,15 @@ public class PreviewMediaFragment extends FileFragment implements
         mVideoPreview.setOnErrorListener(mVideoHelper);
     }
     
+    @SuppressWarnings("static-access")
     private void playVideo() {
         // create and prepare control panel for the user
         mMediaController.setMediaPlayer(mVideoPreview);
         
-        // load the video file in the video player ; when done, VideoHelper#onPrepared() will be called
-        mVideoPreview.setVideoPath(getFile().getStoragePath()); 
+        // load the video file in the video player ; 
+        // when done, VideoHelper#onPrepared() will be called
+        Uri uri = Uri.parse(getFile().getStoragePath());
+        mVideoPreview.setVideoPath(uri.encode(getFile().getStoragePath()));
     }
     
 
@@ -412,8 +447,9 @@ public class PreviewMediaFragment extends FileFragment implements
         @Override
         public boolean onError(MediaPlayer mp, int what, int extra) {
             if (mVideoPreview.getWindowToken() != null) {
-                String message = MediaService.getMessageForMediaError(getActivity(), what, extra);
-                new AlertDialog.Builder(getActivity())
+                String message = MediaService.getMessageForMediaError(
+                        getSherlockActivity(), what, extra);
+                new AlertDialog.Builder(getSherlockActivity())
                         .setMessage(message)
                         .setPositiveButton(android.R.string.VideoView_error_button,
                                 new DialogInterface.OnClickListener() {
@@ -433,8 +469,8 @@ public class PreviewMediaFragment extends FileFragment implements
     
     @Override
     public void onPause() {
-        super.onPause();
         Log_OC.e(TAG, "onPause");
+        super.onPause();
     }
     
     @Override
@@ -445,14 +481,13 @@ public class PreviewMediaFragment extends FileFragment implements
     
     @Override
     public void onDestroy() {
-        super.onDestroy();
         Log_OC.e(TAG, "onDestroy");
+        super.onDestroy();
     }
     
     @Override
     public void onStop() {
         Log_OC.e(TAG, "onStop");
-        super.onStop();
 
         mPrepared = false;
         if (mMediaServiceConnection != null) {
@@ -460,10 +495,12 @@ public class PreviewMediaFragment extends FileFragment implements
             if (mMediaServiceBinder != null && mMediaController != null) {
                 mMediaServiceBinder.unregisterMediaController(mMediaController);
             }
-            getActivity().unbindService(mMediaServiceConnection);
+            getSherlockActivity().unbindService(mMediaServiceConnection);
             mMediaServiceConnection = null;
             mMediaServiceBinder = null;
         }
+        
+        super.onStop();
     }
     
     @Override
@@ -477,7 +514,7 @@ public class PreviewMediaFragment extends FileFragment implements
 
     
     private void startFullScreenVideo() {
-        Intent i = new Intent(getActivity(), PreviewVideoActivity.class);
+        Intent i = new Intent(getSherlockActivity(), PreviewVideoActivity.class);
         i.putExtra(FileActivity.EXTRA_ACCOUNT, mAccount);
         i.putExtra(FileActivity.EXTRA_FILE, getFile());
         i.putExtra(PreviewVideoActivity.EXTRA_AUTOPLAY, mVideoPreview.isPlaying());
@@ -496,7 +533,8 @@ public class PreviewMediaFragment extends FileFragment implements
         Log_OC.e(TAG, "onActivityResult " + this);
         super.onActivityResult(requestCode, resultCode, data);
         if (resultCode == Activity.RESULT_OK) {
-            mSavedPlaybackPosition = data.getExtras().getInt(PreviewVideoActivity.EXTRA_START_POSITION);
+            mSavedPlaybackPosition = data.getExtras().getInt(
+                    PreviewVideoActivity.EXTRA_START_POSITION);
             mAutoplay = data.getExtras().getBoolean(PreviewVideoActivity.EXTRA_AUTOPLAY); 
         }
     }
@@ -522,7 +560,7 @@ public class PreviewMediaFragment extends FileFragment implements
         if (mMediaServiceConnection == null) {
             mMediaServiceConnection = new MediaServiceConnection();
         }
-        getActivity().bindService(  new Intent(getActivity(), 
+        getSherlockActivity().bindService(  new Intent(getSherlockActivity(), 
                                     MediaService.class),
                                     mMediaServiceConnection, 
                                     Context.BIND_AUTO_CREATE);
@@ -534,17 +572,20 @@ public class PreviewMediaFragment extends FileFragment implements
 
         @Override
         public void onServiceConnected(ComponentName component, IBinder service) {
-            if (component.equals(new ComponentName(getActivity(), MediaService.class))) {
-                Log_OC.d(TAG, "Media service connected");
-                mMediaServiceBinder = (MediaServiceBinder) service;
-                if (mMediaServiceBinder != null) {
-                    prepareMediaController();
-                    playAudio();    // do not wait for the touch of nobody to play audio
-                    
-                    Log_OC.d(TAG, "Successfully bound to MediaService, MediaController ready");
-                    
-                } else {
-                    Log_OC.e(TAG, "Unexpected response from MediaService while binding");
+            if (getSherlockActivity() != null) {
+                if (component.equals(
+                        new ComponentName(getSherlockActivity(), MediaService.class))) {
+                    Log_OC.d(TAG, "Media service connected");
+                    mMediaServiceBinder = (MediaServiceBinder) service;
+                    if (mMediaServiceBinder != null) {
+                        prepareMediaController();
+                        playAudio();    // do not wait for the touch of nobody to play audio
+
+                        Log_OC.d(TAG, "Successfully bound to MediaService, MediaController ready");
+
+                    } else {
+                        Log_OC.e(TAG, "Unexpected response from MediaService while binding");
+                    }
                 }
             }
         }
@@ -560,12 +601,15 @@ public class PreviewMediaFragment extends FileFragment implements
 
         @Override
         public void onServiceDisconnected(ComponentName component) {
-            if (component.equals(new ComponentName(getActivity(), MediaService.class))) {
+            if (component.equals(new ComponentName(getSherlockActivity(), MediaService.class))) {
                 Log_OC.e(TAG, "Media service suddenly disconnected");
                 if (mMediaController != null) {
                     mMediaController.setMediaPlayer(null);
                 } else {
-                    Toast.makeText(getActivity(), "No media controller to release when disconnected from media service", Toast.LENGTH_SHORT).show();
+                    Toast.makeText(
+                            getSherlockActivity(), 
+                            "No media controller to release when disconnected from media service", 
+                            Toast.LENGTH_SHORT).show();
                 }
                 mMediaServiceBinder = null;
                 mMediaServiceConnection = null;
@@ -577,124 +621,16 @@ public class PreviewMediaFragment extends FileFragment implements
 
     /**
      * Opens the previewed file with an external application.
-     * 
-     * TODO - improve this; instead of prioritize the actions available for the MIME type in the server, 
-     * we should get a list of available apps for MIME tpye in the server and join it with the list of 
-     * available apps for the MIME type known from the file extension, to let the user choose
      */
     private void openFile() {
-        OCFile file = getFile();
         stopPreview(true);
-        String storagePath = file.getStoragePath();
-        String encodedStoragePath = WebdavUtils.encodePath(storagePath);
-        try {
-            Intent i = new Intent(Intent.ACTION_VIEW);
-            i.setDataAndType(Uri.parse("file://"+ encodedStoragePath), file.getMimetype());
-            i.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
-            startActivity(i);
-            
-        } catch (Throwable t) {
-            Log_OC.e(TAG, "Fail when trying to open with the mimeType provided from the ownCloud server: " + file.getMimetype());
-            boolean toastIt = true; 
-            String mimeType = "";
-            try {
-                Intent i = new Intent(Intent.ACTION_VIEW);
-                mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(storagePath.substring(storagePath.lastIndexOf('.') + 1));
-                if (mimeType == null || !mimeType.equals(file.getMimetype())) {
-                    if (mimeType != null) {
-                        i.setDataAndType(Uri.parse("file://"+ encodedStoragePath), mimeType);
-                    } else {
-                        // desperate try
-                        i.setDataAndType(Uri.parse("file://"+ encodedStoragePath), "*-/*");
-                    }
-                    i.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
-                    startActivity(i);
-                    toastIt = false;
-                }
-                
-            } catch (IndexOutOfBoundsException e) {
-                Log_OC.e(TAG, "Trying to find out MIME type of a file without extension: " + storagePath);
-                
-            } catch (ActivityNotFoundException e) {
-                Log_OC.e(TAG, "No activity found to handle: " + storagePath + " with MIME type " + mimeType + " obtained from extension");
-                
-            } catch (Throwable th) {
-                Log_OC.e(TAG, "Unexpected problem when opening: " + storagePath, th);
-                
-            } finally {
-                if (toastIt) {
-                    Toast.makeText(getActivity(), "There is no application to handle file " + file.getFileName(), Toast.LENGTH_SHORT).show();
-                }
-            }
-            
-        }
+        mContainerActivity.getFileOperationsHelper().openFile(getFile());
         finish();
     }
     
     /**
-     * Starts a the removal of the previewed file.
-     * 
-     * Shows a confirmation dialog. The action continues in {@link #onConfirmation(String)} , {@link #onNeutral(String)} or {@link #onCancel(String)},
-     * depending upon the user selection in the dialog. 
-     */
-    private void removeFile() {
-        ConfirmationDialogFragment confDialog = ConfirmationDialogFragment.newInstance(
-                R.string.confirmation_remove_alert,
-                new String[]{getFile().getFileName()},
-                R.string.confirmation_remove_remote_and_local,
-                R.string.confirmation_remove_local,
-                R.string.common_cancel);
-        confDialog.setOnConfirmationListener(this);
-        confDialog.show(getFragmentManager(), ConfirmationDialogFragment.FTAG_CONFIRMATION);
-    }
-
-    
-    /**
-     * Performs the removal of the previewed file, both locally and in the server.
-     */
-    @Override
-    public void onConfirmation(String callerTag) {
-        OCFile file = getFile();
-        if (mStorageManager.getFileById(file.getFileId()) != null) {   // check that the file is still there;
-            stopPreview(true);
-            mLastRemoteOperation = new RemoveFileOperation( file,      // TODO we need to review the interface with RemoteOperations, and use OCFile IDs instead of OCFile objects as parameters
-                                                            true, 
-                                                            mStorageManager);
-            mLastRemoteOperation.execute(mAccount, getSherlockActivity(), this, mHandler, getSherlockActivity());
-            
-            ((FileDisplayActivity) getActivity()).showLoadingDialog();
-        }
-    }
-    
-    
-    /**
-     * Removes the file from local storage
-     */
-    @Override
-    public void onNeutral(String callerTag) {
-        // TODO this code should be made in a secondary thread,
-        OCFile file = getFile();
-        if (file.isDown()) {   // checks it is still there
-            stopPreview(true);
-            File f = new File(file.getStoragePath());
-            f.delete();
-            file.setStoragePath(null);
-            mStorageManager.saveFile(file);
-            finish();
-        }
-    }
-    
-    /**
-     * User cancelled the removal action.
-     */
-    @Override
-    public void onCancel(String callerTag) {
-        // nothing to do here
-    }
-    
-
-    /**
-     * Helper method to test if an {@link OCFile} can be passed to a {@link PreviewMediaFragment} to be previewed.
+     * Helper method to test if an {@link OCFile} can be passed to a {@link PreviewMediaFragment}
+     *  to be previewed.
      * 
      * @param file      File to test if can be previewed.
      * @return          'True' if the file can be handled by the fragment.
@@ -702,36 +638,9 @@ public class PreviewMediaFragment extends FileFragment implements
     public static boolean canBePreviewed(OCFile file) {
         return (file != null && (file.isAudio() || file.isVideo()));
     }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationResult result) {
-        if (operation.equals(mLastRemoteOperation)) {
-            if (operation instanceof RemoveFileOperation) {
-                onRemoveFileOperationFinish((RemoveFileOperation)operation, result);
-            }
-        }
-    }
     
-    private void onRemoveFileOperationFinish(RemoveFileOperation operation, RemoteOperationResult result) {
-        ((FileDisplayActivity) getActivity()).dismissLoadingDialog();
-        if (result.isSuccess()) {
-            Toast msg = Toast.makeText(getActivity().getApplicationContext(), R.string.remove_success_msg, Toast.LENGTH_LONG);
-            msg.show();
-            finish();
-                
-        } else {
-            Toast msg = Toast.makeText(getActivity(), R.string.remove_fail_msg, Toast.LENGTH_LONG); 
-            msg.show();
-            if (result.isSslRecoverableException()) {
-                // TODO show the SSL warning dialog
-            }
-        }
-    }
 
-    private void stopPreview(boolean stopAudio) {
+    public void stopPreview(boolean stopAudio) {
         OCFile file = getFile();
         if (file.isAudio() && stopAudio) {
             mMediaServiceBinder.pause();
@@ -747,7 +656,7 @@ public class PreviewMediaFragment extends FileFragment implements
      * Finishes the preview
      */
     private void finish() {
-        getActivity().onBackPressed();
+        getSherlockActivity().onBackPressed();
     }
 
 
index 7db07b3..39e8e23 100644 (file)
 
 package com.owncloud.android.ui.preview;
 
-import com.owncloud.android.Log_OC;
 import com.owncloud.android.R;
-import com.owncloud.android.authentication.AccountUtils;
-import com.owncloud.android.authentication.AccountUtils.AccountNotFoundException;
-import com.owncloud.android.datamodel.FileDataStorageManager;
 import com.owncloud.android.datamodel.OCFile;
 import com.owncloud.android.media.MediaService;
 import com.owncloud.android.ui.activity.FileActivity;
@@ -39,6 +35,10 @@ import android.os.Bundle;
 import android.widget.MediaController;
 import android.widget.VideoView;
 
+import com.owncloud.android.lib.common.accounts.AccountUtils;
+import com.owncloud.android.lib.common.accounts.AccountUtils.AccountNotFoundException;
+import com.owncloud.android.lib.common.utils.Log_OC;
+
 /**
  *  Activity implementing a basic video player.
  * 
@@ -59,8 +59,6 @@ public class PreviewVideoActivity extends FileActivity implements OnCompletionLi
     
     private static final String TAG = PreviewVideoActivity.class.getSimpleName();
 
-    private FileDataStorageManager mStorageManager;
-    
     private int mSavedPlaybackPosition;         // in the unit time handled by MediaPlayer.getCurrentPosition()
     private boolean mAutoplay;                  // when 'true', the playback starts immediately with the activity
     private VideoView mVideoPlayer;             // view to play the file; both performs and show the playback
@@ -190,9 +188,9 @@ public class PreviewVideoActivity extends FileActivity implements OnCompletionLi
         return true;
     }
     
-    
     @Override
     protected void onAccountSet(boolean stateWasRecovered) {
+        super.onAccountSet(stateWasRecovered);
         if (getAccount() != null) {
             OCFile file = getFile();
             /// Validate handled file  (first image to preview)
@@ -202,8 +200,7 @@ public class PreviewVideoActivity extends FileActivity implements OnCompletionLi
             if (!file.isVideo()) {
                 throw new IllegalArgumentException("Non-video file passed as argument");
             }
-            mStorageManager = new FileDataStorageManager(getAccount(), getContentResolver());
-            file = mStorageManager.getFileById(file.getFileId()); 
+            file = getStorageManager().getFileById(file.getFileId()); 
             if (file != null) {
                 if (file.isDown()) {
                     mVideoPlayer.setVideoPath(file.getStoragePath());
@@ -229,7 +226,6 @@ public class PreviewVideoActivity extends FileActivity implements OnCompletionLi
                 finish();
             }
         } else {
-            Log_OC.wtf(TAG, "onAccountChanged was called with NULL account associated!");
             finish();
         }
    }
diff --git a/src/com/owncloud/android/utils/BitmapUtils.java b/src/com/owncloud/android/utils/BitmapUtils.java
new file mode 100644 (file)
index 0000000..687b5a4
--- /dev/null
@@ -0,0 +1,99 @@
+/* ownCloud Android client application
+ *   Copyright (C) 2012-2014 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.utils;
+
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.BitmapFactory.Options;
+
+/**
+ * Utility class with methods for decoding Bitmaps.
+ * 
+ * @author David A. Velasco
+ */
+public class BitmapUtils {
+    
+    
+    /**
+     * Decodes a bitmap from a file containing it minimizing the memory use, known that the bitmap
+     * will be drawn in a surface of reqWidth x reqHeight
+     * 
+     * @param srcPath       Absolute path to the file containing the image.
+     * @param reqWidth      Width of the surface where the Bitmap will be drawn on, in pixels.
+     * @param reqHeight     Height of the surface where the Bitmap will be drawn on, in pixels.
+     * @return
+     */
+    public static Bitmap decodeSampledBitmapFromFile(String srcPath, int reqWidth, int reqHeight) {
+    
+        // set desired options that will affect the size of the bitmap
+        final Options options = new Options();
+        options.inScaled = true;
+        options.inPurgeable = true;
+        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.GINGERBREAD_MR1) {
+            options.inPreferQualityOverSpeed = false;
+        }
+        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) {
+            options.inMutable = false;
+        }
+        
+        // make a false load of the bitmap to get its dimensions
+        options.inJustDecodeBounds = true;
+        
+        BitmapFactory.decodeFile(srcPath, options);   
+        
+        // calculate factor to subsample the bitmap
+        options.inSampleSize = calculateSampleFactor(options, reqWidth, reqHeight);
+
+        // decode bitmap with inSampleSize set
+        options.inJustDecodeBounds = false;
+        return BitmapFactory.decodeFile(srcPath, options);
+        
+    }    
+
+
+    /**
+     * Calculates a proper value for options.inSampleSize in order to decode a Bitmap minimizing 
+     * the memory overload and covering a target surface of reqWidth x reqHeight if the original
+     * image is big enough. 
+     * 
+     * @param options       Bitmap decoding options; options.outHeight and options.inHeight should
+     *                      be set. 
+     * @param reqWidth      Width of the surface where the Bitmap will be drawn on, in pixels.
+     * @param reqHeight     Height of the surface where the Bitmap will be drawn on, in pixels.
+     * @return              The largest inSampleSize value that is a power of 2 and keeps both
+     *                      height and width larger than reqWidth and reqHeight.
+     */
+    private static int calculateSampleFactor(Options options, int reqWidth, int reqHeight) {
+        
+        final int height = options.outHeight;
+        final int width = options.outWidth;
+        int inSampleSize = 1;
+    
+        if (height > reqHeight || width > reqWidth) {
+            final int halfHeight = height / 2;
+            final int halfWidth = width / 2;
+    
+            while ((halfHeight / inSampleSize) > reqHeight
+                    && (halfWidth / inSampleSize) > reqWidth) {
+                inSampleSize *= 2;
+            }
+        }
+        
+        return inSampleSize;
+    }
+    
+}
diff --git a/src/com/owncloud/android/utils/DisplayUtils.java b/src/com/owncloud/android/utils/DisplayUtils.java
new file mode 100644 (file)
index 0000000..682d2be
--- /dev/null
@@ -0,0 +1,238 @@
+/* ownCloud Android client application\r
+ *   Copyright (C) 2011  Bartek Przybylski\r
+ *   Copyright (C) 2012-2013 ownCloud Inc.\r
+ *\r
+ *   This program is free software: you can redistribute it and/or modify\r
+ *   it under the terms of the GNU General Public License version 2,\r
+ *   as published by the Free Software Foundation.\r
+ *\r
+ *   This program is distributed in the hope that it will be useful,\r
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ *   GNU General Public License for more details.\r
+ *\r
+ *   You should have received a copy of the GNU General Public License\r
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.\r
+ *\r
+ */\r
+\r
+package com.owncloud.android.utils;\r
+\r
+import java.util.Arrays;\r
+import java.util.Calendar;\r
+import java.util.Date;\r
+import java.util.HashMap;\r
+import java.util.HashSet;\r
+import java.util.Set;\r
+\r
+import com.owncloud.android.R;\r
+\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
+    //private static String TAG = DisplayUtils.class.getSimpleName(); \r
+    \r
+    private static final String[] sizeSuffixes = { "B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" };\r
+\r
+    private static HashMap<String, String> mimeType2HUmanReadable;\r
+    static {\r
+        mimeType2HUmanReadable = new HashMap<String, String>();\r
+        // images\r
+        mimeType2HUmanReadable.put("image/jpeg", "JPEG image");\r
+        mimeType2HUmanReadable.put("image/jpg", "JPEG image");\r
+        mimeType2HUmanReadable.put("image/png", "PNG image");\r
+        mimeType2HUmanReadable.put("image/bmp", "Bitmap image");\r
+        mimeType2HUmanReadable.put("image/gif", "GIF image");\r
+        mimeType2HUmanReadable.put("image/svg+xml", "JPEG image");\r
+        mimeType2HUmanReadable.put("image/tiff", "TIFF image");\r
+        // music\r
+        mimeType2HUmanReadable.put("audio/mpeg", "MP3 music file");\r
+        mimeType2HUmanReadable.put("application/ogg", "OGG music file");\r
+\r
+    }\r
+\r
+    private static final String TYPE_APPLICATION = "application";\r
+    private static final String TYPE_AUDIO = "audio";\r
+    private static final String TYPE_IMAGE = "image";\r
+    private static final String TYPE_TXT = "text";\r
+    private static final String TYPE_VIDEO = "video";\r
+    \r
+    private static final String SUBTYPE_PDF = "pdf";\r
+    private static final String[] SUBTYPES_DOCUMENT = { "msword",\r
+                                                        "vnd.openxmlformats-officedocument.wordprocessingml.document",\r
+                                                        "vnd.oasis.opendocument.text",\r
+                                                        "rtf"\r
+                                                        };\r
+    private static Set<String> SUBTYPES_DOCUMENT_SET = new HashSet<String>(Arrays.asList(SUBTYPES_DOCUMENT));\r
+    private static final String[] SUBTYPES_SPREADSHEET = { "msexcel",\r
+                                                           "vnd.openxmlformats-officedocument.spreadsheetml.sheet",\r
+                                                           "vnd.oasis.opendocument.spreadsheet"\r
+                                                           };\r
+    private static Set<String> SUBTYPES_SPREADSHEET_SET = new HashSet<String>(Arrays.asList(SUBTYPES_SPREADSHEET));\r
+    private static final String[] SUBTYPES_PRESENTATION = { "mspowerpoint",\r
+                                                            "vnd.openxmlformats-officedocument.presentationml.presentation",\r
+                                                            "vnd.oasis.opendocument.presentation"\r
+                                                            };\r
+    private static Set<String> SUBTYPES_PRESENTATION_SET = new HashSet<String>(Arrays.asList(SUBTYPES_PRESENTATION));\r
+    private static final String[] SUBTYPES_COMPRESSED = {"x-tar", "x-gzip", "zip"};\r
+    private static final Set<String> SUBTYPES_COMPRESSED_SET = new HashSet<String>(Arrays.asList(SUBTYPES_COMPRESSED));\r
+    private static final String SUBTYPE_OCTET_STREAM = "octet-stream";\r
+    private static final String EXTENSION_RAR = "rar";\r
+    private static final String EXTENSION_RTF = "rtf";\r
+    private static final String EXTENSION_3GP = "3gp";\r
+    \r
+    /**\r
+     * Converts the file size in bytes to human readable output.\r
+     * \r
+     * @param bytes Input file size\r
+     * @return Like something readable like "12 MB"\r
+     */\r
+    public static String bytesToHumanReadable(long bytes) {\r
+        double result = bytes;\r
+        int attachedsuff = 0;\r
+        while (result > 1024 && attachedsuff < sizeSuffixes.length) {\r
+            result /= 1024.;\r
+            attachedsuff++;\r
+        }\r
+        result = ((int) (result * 100)) / 100.;\r
+        return result + " " + sizeSuffixes[attachedsuff];\r
+    }\r
+\r
+    /**\r
+     * Removes special HTML entities from a string\r
+     * \r
+     * @param s Input string\r
+     * @return A cleaned version of the string\r
+     */\r
+    public static String HtmlDecode(String s) {\r
+        /*\r
+         * TODO: Perhaps we should use something more proven like:\r
+         * http://commons.apache.org/lang/api-2.6/org/apache/commons/lang/StringEscapeUtils.html#unescapeHtml%28java.lang.String%29\r
+         */\r
+\r
+        String ret = "";\r
+        for (int i = 0; i < s.length(); ++i) {\r
+            if (s.charAt(i) == '%') {\r
+                ret += (char) Integer.parseInt(s.substring(i + 1, i + 3), 16);\r
+                i += 2;\r
+            } else {\r
+                ret += s.charAt(i);\r
+            }\r
+        }\r
+        return ret;\r
+    }\r
+\r
+    /**\r
+     * Converts MIME types like "image/jpg" to more end user friendly output\r
+     * like "JPG image".\r
+     * \r
+     * @param mimetype MIME type to convert\r
+     * @return A human friendly version of the MIME type\r
+     */\r
+    public static String convertMIMEtoPrettyPrint(String mimetype) {\r
+        if (mimeType2HUmanReadable.containsKey(mimetype)) {\r
+            return mimeType2HUmanReadable.get(mimetype);\r
+        }\r
+        if (mimetype.split("/").length >= 2)\r
+            return mimetype.split("/")[1].toUpperCase() + " file";\r
+        return "Unknown type";\r
+    }\r
+    \r
+    \r
+    /**\r
+     * Returns the resource identifier of an image resource to use as icon associated to a \r
+     * known MIME type.\r
+     * \r
+     * @param mimetype      MIME type string.\r
+     * @param filename      name, with extension\r
+     * @return              Resource identifier of an image resource.\r
+     */\r
+    public static int getResourceId(String mimetype, String filename) {\r
+\r
+        if (mimetype == null || "DIR".equals(mimetype)) {\r
+            return R.drawable.ic_menu_archive;\r
+            \r
+        } else {\r
+            String [] parts = mimetype.split("/");\r
+            String type = parts[0];\r
+            String subtype = (parts.length > 1) ? parts[1] : "";\r
+            \r
+            if(TYPE_TXT.equals(type)) {\r
+                return R.drawable.file_doc;\r
+    \r
+            } else if(TYPE_IMAGE.equals(type)) {\r
+                return R.drawable.file_image;\r
+                \r
+            } else if(TYPE_VIDEO.equals(type)) {\r
+                return R.drawable.file_movie;\r
+                \r
+            } else if(TYPE_AUDIO.equals(type)) {  \r
+                return R.drawable.file_sound;\r
+                \r
+            } else if(TYPE_APPLICATION.equals(type)) {\r
+                \r
+                if (SUBTYPE_PDF.equals(subtype)) {\r
+                    return R.drawable.file_pdf;\r
+                    \r
+                } else if (SUBTYPES_DOCUMENT_SET.contains(subtype)) {\r
+                    return R.drawable.file_doc;\r
+\r
+                } else if (SUBTYPES_SPREADSHEET_SET.contains(subtype)) {\r
+                    return R.drawable.file_xls;\r
+\r
+                } else if (SUBTYPES_PRESENTATION_SET.contains(subtype)) {\r
+                    return R.drawable.file_ppt;\r
+\r
+                } else if (SUBTYPES_COMPRESSED_SET.contains(subtype)) {\r
+                    return R.drawable.file_zip;\r
+                    \r
+                } else if (SUBTYPE_OCTET_STREAM.equals(subtype) ) {\r
+                    if (getExtension(filename).equalsIgnoreCase(EXTENSION_RAR)) {\r
+                        return R.drawable.file_zip;\r
+                        \r
+                    } else if (getExtension(filename).equalsIgnoreCase(EXTENSION_RTF)) {\r
+                        return R.drawable.file_doc;\r
+                        \r
+                    } else if (getExtension(filename).equalsIgnoreCase(EXTENSION_3GP)) {\r
+                        return R.drawable.file_movie;\r
+                        \r
+                    } \r
+                } \r
+            }\r
+        }\r
+\r
+        // default icon\r
+        return R.drawable.file;\r
+    }\r
+\r
+    \r
+    private static String getExtension(String filename) {\r
+        String extension = filename.substring(filename.lastIndexOf(".") + 1);\r
+        \r
+        return extension;\r
+    }\r
+    \r
+    /**\r
+     * Converts Unix time to human readable format\r
+     * @param miliseconds 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
+        Date date = new Date(milliseconds);\r
+        return date.toLocaleString();\r
+    }\r
+    \r
+    \r
+    public static int getSeasonalIconId() {\r
+        if (Calendar.getInstance().get(Calendar.DAY_OF_YEAR) >= 354) {\r
+            return R.drawable.winter_holidays_icon;\r
+        } else {\r
+            return R.drawable.icon;\r
+        }\r
+    }\r
+}\r
diff --git a/src/com/owncloud/android/utils/ErrorMessageAdapter.java b/src/com/owncloud/android/utils/ErrorMessageAdapter.java
new file mode 100644 (file)
index 0000000..e56e876
--- /dev/null
@@ -0,0 +1,249 @@
+/* ownCloud Android client application
+ *   Copyright (C) 2014 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.utils;
+
+import java.io.File;
+import java.net.SocketTimeoutException;
+
+import org.apache.commons.httpclient.ConnectTimeoutException;
+
+import android.content.res.Resources;
+
+import com.owncloud.android.R;
+import com.owncloud.android.lib.common.operations.RemoteOperation;
+import com.owncloud.android.lib.common.operations.RemoteOperationResult;
+import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;
+import com.owncloud.android.operations.CreateFolderOperation;
+import com.owncloud.android.operations.CreateShareOperation;
+import com.owncloud.android.operations.DownloadFileOperation;
+import com.owncloud.android.operations.MoveFileOperation;
+import com.owncloud.android.operations.RemoveFileOperation;
+import com.owncloud.android.operations.RenameFileOperation;
+import com.owncloud.android.operations.SynchronizeFileOperation;
+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
+ *
+ */
+
+public class ErrorMessageAdapter {
+
+    public ErrorMessageAdapter() {
+        
+    }
+
+    public static String getErrorCauseMessage(RemoteOperationResult result, RemoteOperation operation, Resources res) {
+        
+        String message = null;
+        
+        if (operation instanceof UploadFileOperation) {
+            
+            if (result.isSuccess()) {
+                message = String.format(res.getString(R.string.uploader_upload_succeeded_content_single), 
+                        ((UploadFileOperation) operation).getFileName());
+            } else {
+                if (result.getCode() == ResultCode.LOCAL_STORAGE_FULL
+                        || result.getCode() == ResultCode.LOCAL_STORAGE_NOT_COPIED) {
+                    message = String.format(res.getString(R.string.error__upload__local_file_not_copied), 
+                            ((UploadFileOperation) operation).getFileName(), 
+                            res.getString(R.string.app_name));
+                /*
+                } else if (result.getCode() == ResultCode.QUOTA_EXCEEDED) {
+                    message = res.getString(R.string.failed_upload_quota_exceeded_text);
+                    */
+                    
+                } else if (result.getCode() == ResultCode.FORBIDDEN) {
+                    message = String.format(res.getString(R.string.forbidden_permissions),
+                            res.getString(R.string.uploader_upload_forbidden_permissions));
+
+                } else {
+                    message = String.format(res.getString(R.string.uploader_upload_failed_content_single), 
+                            ((UploadFileOperation) operation).getFileName());
+                }
+            }
+            
+        } else if (operation instanceof DownloadFileOperation) {
+            
+            if (result.isSuccess()) {
+                message = String.format(res.getString(R.string.downloader_download_succeeded_content), 
+                        new File(((DownloadFileOperation) operation).getSavePath()).getName());
+                
+            } else {
+                if (result.getCode() == ResultCode.FILE_NOT_FOUND) {
+                    message = res.getString(R.string.downloader_download_file_not_found);
+
+                } else {
+                    message = String.format(res.getString(R.string.downloader_download_failed_content), new File(
+                            ((DownloadFileOperation) operation).getSavePath()).getName());
+                }
+            }
+            
+        } else if (operation instanceof RemoveFileOperation) {
+            if (result.isSuccess()) {
+                message = res.getString(R.string.remove_success_msg);
+                
+            } else {
+                if (result.getCode().equals(ResultCode.FORBIDDEN)) {
+                    // Error --> No permissions
+                    message = String.format(res.getString(R.string.forbidden_permissions),
+                            res.getString(R.string.forbidden_permissions_delete));
+                } else if (isNetworkError(result.getCode())) {
+                    message = getErrorMessage(result, res);
+                    
+                } else {
+                    message = res.getString(R.string.remove_fail_msg);
+                }
+            }
+
+        } else if (operation instanceof RenameFileOperation) {
+            if (result.getCode().equals(ResultCode.INVALID_LOCAL_FILE_NAME)) {
+                message = res.getString(R.string.rename_local_fail_msg);
+
+            } else if (result.getCode().equals(ResultCode.FORBIDDEN)) {
+                // Error --> No permissions
+                message = String.format(res.getString(R.string.forbidden_permissions),
+                        res.getString(R.string.forbidden_permissions_rename));
+
+            } else if (result.getCode().equals(ResultCode.INVALID_CHARACTER_IN_NAME)) {
+                message = res.getString(R.string.filename_forbidden_characters);
+
+            } else if (isNetworkError(result.getCode())) {
+                message = getErrorMessage(result, res);
+                
+            } else {
+                message = res.getString(R.string.rename_server_fail_msg); 
+            }
+            
+        } else if (operation instanceof SynchronizeFileOperation) {
+            if (!((SynchronizeFileOperation) operation).transferWasRequested()) {
+                message = res.getString(R.string.sync_file_nothing_to_do_msg);
+            }
+            
+        } else if (operation instanceof CreateFolderOperation) {
+            if (result.getCode() == ResultCode.INVALID_CHARACTER_IN_NAME) {
+                message = res.getString(R.string.filename_forbidden_characters);
+
+            } else if (result.getCode().equals(ResultCode.FORBIDDEN)) {
+                message = String.format(res.getString(R.string.forbidden_permissions),
+                        res.getString(R.string.forbidden_permissions_create));
+
+            } else if (isNetworkError(result.getCode())) {
+                message = getErrorMessage(result, res);
+                
+            } else {
+                message = res.getString(R.string.create_dir_fail_msg);
+            }
+        } else if (operation instanceof CreateShareOperation) {        
+            if (result.getCode() == ResultCode.SHARE_NOT_FOUND)  {        // Error --> SHARE_NOT_FOUND
+                message = res.getString(R.string.share_link_file_no_exist);
+                
+            } else if (result.getCode() == ResultCode.SHARE_FORBIDDEN) {
+                // Error --> No permissions
+                message = String.format(res.getString(R.string.forbidden_permissions),
+                        res.getString(R.string.share_link_forbidden_permissions));
+
+            } else if (isNetworkError(result.getCode())) {
+                message = getErrorMessage(result, res);
+                
+            } else {    // Generic error
+                // Show a Message, operation finished without success
+                message = res.getString(R.string.share_link_file_error);
+            }
+            
+        } else if (operation instanceof UnshareLinkOperation) {
+        
+            if (result.getCode() == ResultCode.SHARE_NOT_FOUND)  {        // Error --> SHARE_NOT_FOUND
+                message = res.getString(R.string.unshare_link_file_no_exist);
+                
+            } else if (result.getCode() == ResultCode.SHARE_FORBIDDEN) {
+                // Error --> No permissions
+                message = String.format(res.getString(R.string.forbidden_permissions),
+                        res.getString(R.string.unshare_link_forbidden_permissions));
+
+            } else if (isNetworkError(result.getCode())) {
+                message = getErrorMessage(result, res);
+                
+            } else {    // Generic error
+                // Show a Message, operation finished without success
+                message = res.getString(R.string.unshare_link_file_error);
+            }
+        } else if (operation instanceof MoveFileOperation) {
+
+            if (result.getCode() == ResultCode.FILE_NOT_FOUND) {
+                message = res.getString(R.string.move_file_not_found);
+                
+            } else if (result.getCode() == ResultCode.INVALID_MOVE_INTO_DESCENDANT)  {
+                message = res.getString(R.string.move_file_invalid_into_descendent);
+
+            } else if (result.getCode() == ResultCode.INVALID_OVERWRITE) {
+                message = res.getString(R.string.move_file_invalid_overwrite);
+
+            } else if (result.getCode() == ResultCode.FORBIDDEN) {
+                message = String.format(res.getString(R.string.forbidden_permissions),
+                        res.getString(R.string.forbidden_permissions_move));
+
+            }else {    // Generic error
+                // Show a Message, operation finished without success
+                message = res.getString(R.string.move_file_error);
+            }
+        }
+        
+        return message;
+    }
+    
+    private static String getErrorMessage(RemoteOperationResult result , Resources res) {
+        
+        String message = null;
+        
+        if (!result.isSuccess()) {
+            
+            if (result.getCode() == ResultCode.WRONG_CONNECTION) {
+                message = res.getString(R.string.network_error_socket_exception);
+                
+            } else if (result.getCode() == ResultCode.TIMEOUT) {
+                message = res.getString(R.string.network_error_socket_exception);
+                
+                if (result.getException() instanceof SocketTimeoutException) {
+                    message = res.getString(R.string.network_error_socket_timeout_exception);
+                } else if(result.getException() instanceof ConnectTimeoutException) {
+                    message = res.getString(R.string.network_error_connect_timeout_exception);
+                } 
+                
+            } else if (result.getCode() == ResultCode.HOST_NOT_AVAILABLE) {
+                message = res.getString(R.string.network_host_not_available);
+            }
+        }
+        
+        return message;
+    }
+    
+    private static boolean isNetworkError(RemoteOperationResult.ResultCode code) {
+        if (code == ResultCode.WRONG_CONNECTION || 
+                code == ResultCode.TIMEOUT || 
+                code == ResultCode.HOST_NOT_AVAILABLE) {
+            return true;
+        }
+        else
+            return false;
+    }
+}
index 0c7e991..3895821 100644 (file)
@@ -22,9 +22,12 @@ import java.io.File;
 import com.owncloud.android.MainApp;
 import com.owncloud.android.R;
 import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.lib.resources.files.RemoteFile;
 
 import android.annotation.SuppressLint;
 import android.content.Context;
+import android.content.SharedPreferences;
+import android.preference.PreferenceManager;
 import android.net.Uri;
 import android.os.Environment;
 import android.os.StatFs;
@@ -72,9 +75,53 @@ public class FileStorageUtils {
     }
 
     public static String getInstantUploadFilePath(Context context, String fileName) {
-        String uploadPath = context.getString(R.string.instant_upload_path);
+        SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(context);
+        String uploadPathdef = context.getString(R.string.instant_upload_path);
+        String uploadPath = pref.getString("instant_upload_path", uploadPathdef);
         String value = uploadPath + OCFile.PATH_SEPARATOR +  (fileName == null ? "" : fileName);
         return value;
     }
+    
+    public static String getParentPath(String remotePath) {
+        String parentPath = new File(remotePath).getParent();
+        parentPath = parentPath.endsWith(OCFile.PATH_SEPARATOR) ? parentPath : parentPath + OCFile.PATH_SEPARATOR;
+        return parentPath;
+    }
+    
+    /**
+     * Creates and populates a new {@link OCFile} object with the data read from the server.
+     * 
+     * @param remote    remote file read from the server (remote file or folder).
+     * @return          New OCFile instance representing the remote resource described by we.
+     */
+    public static OCFile fillOCFile(RemoteFile remote) {
+        OCFile file = new OCFile(remote.getRemotePath());
+        file.setCreationTimestamp(remote.getCreationTimestamp());
+        file.setFileLength(remote.getLength());
+        file.setMimetype(remote.getMimeType());
+        file.setModificationTimestamp(remote.getModifiedTimestamp());
+        file.setEtag(remote.getEtag());
+        file.setPermissions(remote.getPermissions());
+        file.setRemoteId(remote.getRemoteId());
+        return file;
+    }
+    
+    /**
+     * Creates and populates a new {@link RemoteFile} object with the data read from an {@link OCFile}.
+     * 
+     * @param oCFile    OCFile 
+     * @return          New RemoteFile instance representing the resource described by ocFile.
+     */
+    public static RemoteFile fillRemoteFile(OCFile ocFile){
+        RemoteFile file = new RemoteFile(ocFile.getRemotePath());
+        file.setCreationTimestamp(ocFile.getCreationTimestamp());
+        file.setLength(ocFile.getFileLength());
+        file.setMimeType(ocFile.getMimetype());
+        file.setModifiedTimestamp(ocFile.getModificationTimestamp());
+        file.setEtag(ocFile.getEtag());
+        file.setPermissions(ocFile.getPermissions());
+        file.setRemoteId(ocFile.getRemoteId());
+        return file;
+    }
   
-}
\ No newline at end of file
+}
diff --git a/src/com/owncloud/android/utils/OwnCloudSession.java b/src/com/owncloud/android/utils/OwnCloudSession.java
new file mode 100644 (file)
index 0000000..13ead88
--- /dev/null
@@ -0,0 +1,56 @@
+/* ownCloud Android client application\r
+ *   Copyright (C) 2011  Bartek Przybylski\r
+ *   Copyright (C) 2012-2013 ownCloud Inc.\r
+ *\r
+ *   This program is free software: you can redistribute it and/or modify\r
+ *   it under the terms of the GNU General Public License version 2,\r
+ *   as published by the Free Software Foundation.\r
+ *\r
+ *   This program is distributed in the hope that it will be useful,\r
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ *   GNU General Public License for more details.\r
+ *\r
+ *   You should have received a copy of the GNU General Public License\r
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.\r
+ *\r
+ */\r
+package com.owncloud.android.utils;\r
+\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
+    private String mSessionUrl;\r
+    private int mEntryId;\r
+\r
+    public OwnCloudSession(String name, String url, int entryId) {\r
+        mSessionName = name;\r
+        mSessionUrl = url;\r
+        mEntryId = entryId;\r
+    }\r
+\r
+    public void setName(String name) {\r
+        mSessionName = name;\r
+    }\r
+\r
+    public String getName() {\r
+        return mSessionName;\r
+    }\r
+\r
+    public void setUrl(String url) {\r
+        mSessionUrl = url;\r
+    }\r
+\r
+    public String getUrl() {\r
+        return mSessionUrl;\r
+    }\r
+\r
+    public int getEntryId() {\r
+        return mEntryId;\r
+    }\r
+}\r
diff --git a/src/com/owncloud/android/utils/OwnCloudVersion.java b/src/com/owncloud/android/utils/OwnCloudVersion.java
deleted file mode 100644 (file)
index 630e7ac..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012  Bartek Przybylski
- *   Copyright (C) 2012-2013 ownCloud Inc.
- *
- *   This program is free software: you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License version 2,
- *   as published by the Free Software Foundation.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-package com.owncloud.android.utils;
-
-public class OwnCloudVersion implements Comparable<OwnCloudVersion> {
-    public static final OwnCloudVersion owncloud_v1 = new OwnCloudVersion(
-            0x010000);
-    public static final OwnCloudVersion owncloud_v2 = new OwnCloudVersion(
-            0x020000);
-    public static final OwnCloudVersion owncloud_v3 = new OwnCloudVersion(
-            0x030000);
-    public static final OwnCloudVersion owncloud_v4 = new OwnCloudVersion(
-            0x040000);
-    public static final OwnCloudVersion owncloud_v4_5 = new OwnCloudVersion(
-            0x040500);
-
-    // format is in version
-    // 0xAABBCC
-    // for version AA.BB.CC
-    // ie version 2.0.3 will be stored as 0x030003
-    private int mVersion;
-    private boolean mIsValid;
-
-    public OwnCloudVersion(int version) {
-        mVersion = version;
-        mIsValid = true;
-    }
-
-    public OwnCloudVersion(String version) {
-        mVersion = 0;
-        mIsValid = false;
-        parseVersionString(version);
-    }
-
-    public String toString() {
-        return ((mVersion >> 16) % 256) + "." + ((mVersion >> 8) % 256) + "."
-                + ((mVersion) % 256);
-    }
-
-    public boolean isVersionValid() {
-        return mIsValid;
-    }
-
-    @Override
-    public int compareTo(OwnCloudVersion another) {
-        return another.mVersion == mVersion ? 0
-                : another.mVersion < mVersion ? 1 : -1;
-    }
-
-    private void parseVersionString(String version) {
-        try {
-            String[] nums = version.split("\\.");
-            if (nums.length > 0) {
-                mVersion += Integer.parseInt(nums[0]);
-            }
-            mVersion = mVersion << 8;
-            if (nums.length > 1) {
-                mVersion += Integer.parseInt(nums[1]);
-            }
-            mVersion = mVersion << 8;
-            if (nums.length > 2) {
-                mVersion += Integer.parseInt(nums[2]);
-            }
-            mIsValid = true;
-        } catch (Exception e) {
-            mIsValid = false;
-        }
-    }
-}
diff --git a/src/com/owncloud/android/utils/TouchImageViewCustom.java b/src/com/owncloud/android/utils/TouchImageViewCustom.java
new file mode 100644 (file)
index 0000000..a0f7b79
--- /dev/null
@@ -0,0 +1,1276 @@
+/*
+ * 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
diff --git a/src/eu/alefzero/webdav/ChunkFromFileChannelRequestEntity.java b/src/eu/alefzero/webdav/ChunkFromFileChannelRequestEntity.java
deleted file mode 100644 (file)
index a91b64e..0000000
+++ /dev/null
@@ -1,147 +0,0 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012-2013 ownCloud Inc.
- *
- *   This program is free software: you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License version 2,
- *   as published by the Free Software Foundation.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-package eu.alefzero.webdav;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.nio.ByteBuffer;
-import java.nio.channels.FileChannel;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Set;
-
-import org.apache.commons.httpclient.methods.RequestEntity;
-
-import com.owncloud.android.Log_OC;
-import com.owncloud.android.network.ProgressiveDataTransferer;
-
-
-import eu.alefzero.webdav.OnDatatransferProgressListener;
-
-
-/**
- * A RequestEntity that represents a PIECE of a file.
- * 
- * @author David A. Velasco
- */
-public class ChunkFromFileChannelRequestEntity implements RequestEntity, ProgressiveDataTransferer {
-
-    private static final String TAG = ChunkFromFileChannelRequestEntity.class.getSimpleName();
-    
-    //private final File mFile;
-    private final FileChannel mChannel;
-    private final String mContentType;
-    private final long mChunkSize;
-    private final File mFile;
-    private long mOffset;
-    private long mTransferred;
-    Set<OnDatatransferProgressListener> mDataTransferListeners = new HashSet<OnDatatransferProgressListener>();
-    private ByteBuffer mBuffer = ByteBuffer.allocate(4096);
-
-    public ChunkFromFileChannelRequestEntity(final FileChannel channel, final String contentType, long chunkSize, final File file) {
-        super();
-        if (channel == null) {
-            throw new IllegalArgumentException("File may not be null");
-        }
-        if (chunkSize <= 0) {
-            throw new IllegalArgumentException("Chunk size must be greater than zero");
-        }
-        mChannel = channel;
-        mContentType = contentType;
-        mChunkSize = chunkSize;
-        mFile = file;
-        mOffset = 0;
-        mTransferred = 0;
-    }
-    
-    public void setOffset(long offset) {
-        mOffset = offset;
-    }
-    
-    public long getContentLength() {
-        try {
-            return Math.min(mChunkSize, mChannel.size() - mChannel.position());
-        } catch (IOException e) {
-            return mChunkSize;
-        }
-    }
-
-    public String getContentType() {
-        return mContentType;
-    }
-
-    public boolean isRepeatable() {
-        return true;
-    }
-    
-    @Override
-    public void addDatatransferProgressListener(OnDatatransferProgressListener listener) {
-        synchronized (mDataTransferListeners) {
-            mDataTransferListeners.add(listener);
-        }
-    }
-    
-    @Override
-    public void addDatatransferProgressListeners(Collection<OnDatatransferProgressListener> listeners) {
-        synchronized (mDataTransferListeners) {
-            mDataTransferListeners.addAll(listeners);
-        }
-    }
-    
-    @Override
-    public void removeDatatransferProgressListener(OnDatatransferProgressListener listener) {
-        synchronized (mDataTransferListeners) {
-            mDataTransferListeners.remove(listener);
-        }
-    }
-    
-    
-    public void writeRequest(final OutputStream out) throws IOException {
-        int readCount = 0;
-        Iterator<OnDatatransferProgressListener> it = null;
-        
-       try {
-            mChannel.position(mOffset);
-            long size = mFile.length();
-            if (size == 0) size = -1;
-            long maxCount = Math.min(mOffset + mChunkSize, mChannel.size());
-            while (mChannel.position() < maxCount) {
-                readCount = mChannel.read(mBuffer);
-                out.write(mBuffer.array(), 0, readCount);
-                mBuffer.clear();
-                if (mTransferred < maxCount) {  // condition to avoid accumulate progress for repeated chunks
-                    mTransferred += readCount;
-                }
-                synchronized (mDataTransferListeners) {
-                    it = mDataTransferListeners.iterator();
-                    while (it.hasNext()) {
-                        it.next().onTransferProgress(readCount, mTransferred, size, mFile.getName());
-                    }
-                }
-            }
-            
-        } catch (IOException io) {
-            Log_OC.e(TAG, io.getMessage());
-            throw new RuntimeException("Ugly solution to workaround the default policy of retries when the server falls while uploading ; temporal fix; really", io);   
-            
-        }
-    }
-
-}
\ No newline at end of file
diff --git a/src/eu/alefzero/webdav/FileRequestEntity.java b/src/eu/alefzero/webdav/FileRequestEntity.java
deleted file mode 100644 (file)
index 1d525c4..0000000
+++ /dev/null
@@ -1,134 +0,0 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012 Bartek Przybylski
- *   Copyright (C) 2012-2013 ownCloud Inc.
- *
- *   This program is free software: you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License version 2,
- *   as published by the Free Software Foundation.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-package eu.alefzero.webdav;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.RandomAccessFile;
-import java.nio.ByteBuffer;
-import java.nio.channels.FileChannel;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Set;
-
-import org.apache.commons.httpclient.methods.RequestEntity;
-
-import com.owncloud.android.Log_OC;
-import com.owncloud.android.network.ProgressiveDataTransferer;
-
-
-import eu.alefzero.webdav.OnDatatransferProgressListener;
-
-
-/**
- * A RequestEntity that represents a File.
- * 
- */
-public class FileRequestEntity implements RequestEntity, ProgressiveDataTransferer {
-
-    final File mFile;
-    final String mContentType;
-    Set<OnDatatransferProgressListener> mDataTransferListeners = new HashSet<OnDatatransferProgressListener>();
-
-    public FileRequestEntity(final File file, final String contentType) {
-        super();
-        this.mFile = file;
-        this.mContentType = contentType;
-        if (file == null) {
-            throw new IllegalArgumentException("File may not be null");
-        }
-    }
-    
-    @Override
-    public long getContentLength() {
-        return mFile.length();
-    }
-
-    @Override
-    public String getContentType() {
-        return mContentType;
-    }
-
-    @Override
-    public boolean isRepeatable() {
-        return true;
-    }
-
-    @Override
-    public void addDatatransferProgressListener(OnDatatransferProgressListener listener) {
-        synchronized (mDataTransferListeners) {
-            mDataTransferListeners.add(listener);
-        }
-    }
-    
-    @Override
-    public void addDatatransferProgressListeners(Collection<OnDatatransferProgressListener> listeners) {
-        synchronized (mDataTransferListeners) {
-            mDataTransferListeners.addAll(listeners);
-        }
-    }
-    
-    @Override
-    public void removeDatatransferProgressListener(OnDatatransferProgressListener listener) {
-        synchronized (mDataTransferListeners) {
-            mDataTransferListeners.remove(listener);
-        }
-    }
-    
-    
-    @Override
-    public void writeRequest(final OutputStream out) throws IOException {
-        //byte[] tmp = new byte[4096];
-        ByteBuffer tmp = ByteBuffer.allocate(4096);
-        int readResult = 0;
-        
-        // TODO(bprzybylski): each mem allocation can throw OutOfMemoryError we need to handle it
-        //                    globally in some fashionable manner
-        RandomAccessFile raf = new RandomAccessFile(mFile, "r");
-        FileChannel channel = raf.getChannel();
-        Iterator<OnDatatransferProgressListener> it = null;
-        long transferred = 0;
-        long size = mFile.length();
-        if (size == 0) size = -1;
-        try {
-            while ((readResult = channel.read(tmp)) >= 0) {
-                out.write(tmp.array(), 0, readResult);
-                tmp.clear();
-                transferred += readResult;
-                synchronized (mDataTransferListeners) {
-                    it = mDataTransferListeners.iterator();
-                    while (it.hasNext()) {
-                        it.next().onTransferProgress(readResult, transferred, size, mFile.getName());
-                    }
-                }
-            }
-            
-        } catch (IOException io) {
-            Log_OC.e("FileRequestException", io.getMessage());
-            throw new RuntimeException("Ugly solution to workaround the default policy of retries when the server falls while uploading ; temporal fix; really", io);   
-            
-        } finally {
-            channel.close();
-            raf.close();
-        }
-    }
-
-}
diff --git a/src/eu/alefzero/webdav/OnDatatransferProgressListener.java b/src/eu/alefzero/webdav/OnDatatransferProgressListener.java
deleted file mode 100644 (file)
index 5c4783a..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012 Bartek Przybylski
- *   Copyright (C) 2012-2013 ownCloud Inc.
- *
- *   This program is free software: you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License version 2,
- *   as published by the Free Software Foundation.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-package eu.alefzero.webdav;
-
-public interface OnDatatransferProgressListener {
-    public void onTransferProgress(long progressRate);
-    public void onTransferProgress(long progressRate, long totalTransferredSoFar, long totalToTransfer, String fileName);
-}
diff --git a/src/eu/alefzero/webdav/WebdavClient.java b/src/eu/alefzero/webdav/WebdavClient.java
deleted file mode 100644 (file)
index 5120928..0000000
+++ /dev/null
@@ -1,257 +0,0 @@
-/* ownCloud Android client application
- *   Copyright (C) 2011  Bartek Przybylski
- *   Copyright (C) 2012-2013 ownCloud Inc.
- *
- *   This program is free software: you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License version 2,
- *   as published by the Free Software Foundation.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-package eu.alefzero.webdav;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.commons.httpclient.Credentials;
-import org.apache.commons.httpclient.Header;
-import org.apache.commons.httpclient.HttpClient;
-import org.apache.commons.httpclient.HttpConnectionManager;
-import org.apache.commons.httpclient.HttpException;
-import org.apache.commons.httpclient.HttpMethod;
-import org.apache.commons.httpclient.HttpMethodBase;
-import org.apache.commons.httpclient.HttpVersion;
-import org.apache.commons.httpclient.URI;
-import org.apache.commons.httpclient.UsernamePasswordCredentials;
-import org.apache.commons.httpclient.auth.AuthPolicy;
-import org.apache.commons.httpclient.auth.AuthScope;
-import org.apache.commons.httpclient.cookie.CookiePolicy;
-import org.apache.commons.httpclient.methods.HeadMethod;
-import org.apache.commons.httpclient.params.HttpMethodParams;
-import org.apache.http.HttpStatus;
-import org.apache.http.params.CoreProtocolPNames;
-
-import com.owncloud.android.Log_OC;
-import com.owncloud.android.MainApp;
-import com.owncloud.android.network.BearerAuthScheme;
-import com.owncloud.android.network.BearerCredentials;
-
-
-
-import android.net.Uri;
-
-public class WebdavClient extends HttpClient {
-    private static final int MAX_REDIRECTIONS_COUNT = 3;
-    
-    private Uri mUri;
-    private Credentials mCredentials;
-    private boolean mFollowRedirects;
-    private String mSsoSessionCookie;
-    private String mAuthTokenType;
-    final private static String TAG = "WebdavClient";
-    public static final String USER_AGENT = "Android-ownCloud";
-    
-    static private byte[] sExhaustBuffer = new byte[1024];
-    
-    /**
-     * Constructor
-     */
-    public WebdavClient(HttpConnectionManager connectionMgr) {
-        super(connectionMgr);
-        Log_OC.d(TAG, "Creating WebdavClient");
-        getParams().setParameter(HttpMethodParams.USER_AGENT, USER_AGENT);
-        getParams().setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1);
-        mFollowRedirects = true;
-        mSsoSessionCookie = null;
-        mAuthTokenType = MainApp.getAuthTokenTypePass();
-    }
-
-    public void setBearerCredentials(String accessToken) {
-        AuthPolicy.registerAuthScheme(BearerAuthScheme.AUTH_POLICY, BearerAuthScheme.class);
-        
-        List<String> authPrefs = new ArrayList<String>(1);
-        authPrefs.add(BearerAuthScheme.AUTH_POLICY);
-        getParams().setParameter(AuthPolicy.AUTH_SCHEME_PRIORITY, authPrefs);        
-        
-        mCredentials = new BearerCredentials(accessToken);
-        getState().setCredentials(AuthScope.ANY, mCredentials);
-        mSsoSessionCookie = null;
-        mAuthTokenType = MainApp.getAuthTokenTypeAccessToken();
-    }
-
-    public void setBasicCredentials(String username, String password) {
-        List<String> authPrefs = new ArrayList<String>(1);
-        authPrefs.add(AuthPolicy.BASIC);
-        getParams().setParameter(AuthPolicy.AUTH_SCHEME_PRIORITY, authPrefs);        
-        
-        getParams().setAuthenticationPreemptive(true);
-        mCredentials = new UsernamePasswordCredentials(username, password);
-        getState().setCredentials(AuthScope.ANY, mCredentials);
-        mSsoSessionCookie = null;
-        mAuthTokenType = MainApp.getAuthTokenTypePass();
-    }
-    
-    public void setSsoSessionCookie(String accessToken) {
-        getParams().setAuthenticationPreemptive(false);
-        getParams().setCookiePolicy(CookiePolicy.IGNORE_COOKIES);
-        mSsoSessionCookie = accessToken;
-        mCredentials = null;
-        mAuthTokenType = MainApp.getAuthTokenTypeSamlSessionCookie();
-    }
-    
-    
-    /**
-     * Check if a file exists in the OC server
-     * 
-     * TODO replace with ExistenceOperation
-     * 
-     * @return              'true' if the file exists; 'false' it doesn't exist
-     * @throws  Exception   When the existence could not be determined
-     */
-    public boolean existsFile(String path) throws IOException, HttpException {
-        HeadMethod head = new HeadMethod(mUri.toString() + WebdavUtils.encodePath(path));
-        try {
-            int status = executeMethod(head);
-            Log_OC.d(TAG, "HEAD to " + path + " finished with HTTP status " + status + ((status != HttpStatus.SC_OK)?"(FAIL)":""));
-            exhaustResponse(head.getResponseBodyAsStream());
-            return (status == HttpStatus.SC_OK);
-            
-        } finally {
-            head.releaseConnection();    // let the connection available for other methods
-        }
-    }
-    
-    /**
-     * Requests the received method with the received timeout (milliseconds).
-     * 
-     * Executes the method through the inherited HttpClient.executedMethod(method).
-     * 
-     * Sets the socket and connection timeouts only for the method received.
-     * 
-     * The timeouts are both in milliseconds; 0 means 'infinite'; < 0 means 'do not change the default'
-     * 
-     * @param method            HTTP method request.
-     * @param readTimeout       Timeout to set for data reception
-     * @param conntionTimout    Timeout to set for connection establishment
-     */
-    public int executeMethod(HttpMethodBase method, int readTimeout, int connectionTimeout) throws HttpException, IOException {
-        int oldSoTimeout = getParams().getSoTimeout();
-        int oldConnectionTimeout = getHttpConnectionManager().getParams().getConnectionTimeout();
-        try {
-            if (readTimeout >= 0) { 
-                method.getParams().setSoTimeout(readTimeout);   // this should be enough...
-                getParams().setSoTimeout(readTimeout);          // ... but this looks like necessary for HTTPS
-            }
-            if (connectionTimeout >= 0) {
-                getHttpConnectionManager().getParams().setConnectionTimeout(connectionTimeout);
-            }
-            return executeMethod(method);
-        } finally {
-            getParams().setSoTimeout(oldSoTimeout);
-            getHttpConnectionManager().getParams().setConnectionTimeout(oldConnectionTimeout);
-        }
-    }
-    
-    
-    @Override
-    public int executeMethod(HttpMethod method) throws IOException, HttpException {
-        boolean customRedirectionNeeded = false;
-        try {
-            method.setFollowRedirects(mFollowRedirects);
-        } catch (Exception e) {
-            //if (mFollowRedirects) Log_OC.d(TAG, "setFollowRedirects failed for " + method.getName() + " method, custom redirection will be used if needed");
-            customRedirectionNeeded = mFollowRedirects;
-        }
-        if (mSsoSessionCookie != null && mSsoSessionCookie.length() > 0) {
-            method.setRequestHeader("Cookie", mSsoSessionCookie);
-        }
-        int status = super.executeMethod(method);
-        int redirectionsCount = 0;
-        while (customRedirectionNeeded &&
-                redirectionsCount < MAX_REDIRECTIONS_COUNT &&
-                (   status == HttpStatus.SC_MOVED_PERMANENTLY || 
-                    status == HttpStatus.SC_MOVED_TEMPORARILY ||
-                    status == HttpStatus.SC_TEMPORARY_REDIRECT)
-                ) {
-            
-            Header location = method.getResponseHeader("Location");
-            if (location != null) {
-                Log_OC.d(TAG,  "Location to redirect: " + location.getValue());
-                method.setURI(new URI(location.getValue(), true));
-                status = super.executeMethod(method);
-                redirectionsCount++;
-                
-            } else {
-                Log_OC.d(TAG,  "No location to redirect!");
-                status = HttpStatus.SC_NOT_FOUND;
-            }
-        }
-        
-        return status;
-    }
-
-
-    /**
-     * Exhausts a not interesting HTTP response. Encouraged by HttpClient documentation.
-     * 
-     * @param responseBodyAsStream      InputStream with the HTTP response to exhaust.
-     */
-    public void exhaustResponse(InputStream responseBodyAsStream) {
-        if (responseBodyAsStream != null) {
-            try {
-                while (responseBodyAsStream.read(sExhaustBuffer) >= 0);
-                responseBodyAsStream.close();
-            
-            } catch (IOException io) {
-                Log_OC.e(TAG, "Unexpected exception while exhausting not interesting HTTP response; will be IGNORED", io);
-            }
-        }
-    }
-
-    /**
-     * Sets the connection and wait-for-data timeouts to be applied by default to the methods performed by this client.
-     */
-    public void setDefaultTimeouts(int defaultDataTimeout, int defaultConnectionTimeout) {
-            getParams().setSoTimeout(defaultDataTimeout);
-            getHttpConnectionManager().getParams().setConnectionTimeout(defaultConnectionTimeout);
-    }
-
-    /**
-     * Sets the base URI for the helper methods that receive paths as parameters, instead of full URLs
-     * @param uri
-     */
-    public void setBaseUri(Uri uri) {
-        mUri = uri;
-    }
-
-    public Uri getBaseUri() {
-        return mUri;
-    }
-
-    public final Credentials getCredentials() {\r
-        return mCredentials;\r
-    }
-    
-    public final String getSsoSessionCookie() {
-        return mSsoSessionCookie;
-    }
-
-    public void setFollowRedirects(boolean followRedirects) {
-        mFollowRedirects = followRedirects;
-    }
-
-    public String getAuthTokenType() {
-        return mAuthTokenType;
-    }
-
-}
diff --git a/src/eu/alefzero/webdav/WebdavEntry.java b/src/eu/alefzero/webdav/WebdavEntry.java
deleted file mode 100644 (file)
index 1c6ba69..0000000
+++ /dev/null
@@ -1,150 +0,0 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012  ownCloud
- *
- *   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 eu.alefzero.webdav;
-
-import java.util.Date;
-
-import org.apache.jackrabbit.webdav.MultiStatusResponse;
-import org.apache.jackrabbit.webdav.property.DavProperty;
-import org.apache.jackrabbit.webdav.property.DavPropertyName;
-import org.apache.jackrabbit.webdav.property.DavPropertySet;
-
-import com.owncloud.android.Log_OC;
-
-
-import android.net.Uri;
-
-public class WebdavEntry {
-    private String mName, mPath, mUri, mContentType, mEtag;
-    private long mContentLength, mCreateTimestamp, mModifiedTimestamp;
-
-    public WebdavEntry(MultiStatusResponse ms, String splitElement) {
-        resetData();
-        if (ms.getStatus().length != 0) {
-            mUri = ms.getHref();
-
-            mPath = mUri.split(splitElement, 2)[1];
-
-            int status = ms.getStatus()[0].getStatusCode();
-            DavPropertySet propSet = ms.getProperties(status);
-            @SuppressWarnings("rawtypes")
-            DavProperty prop = propSet.get(DavPropertyName.DISPLAYNAME);
-            if (prop != null) {
-                mName = (String) prop.getName().toString();
-                mName = mName.substring(1, mName.length()-1);
-            }
-            else {
-                String[] tmp = mPath.split("/");
-                if (tmp.length > 0)
-                    mName = tmp[tmp.length - 1];
-            }
-
-            // use unknown mimetype as default behavior
-            mContentType = "application/octet-stream";
-            prop = propSet.get(DavPropertyName.GETCONTENTTYPE);
-            if (prop != null) {
-                mContentType = (String) prop.getValue();
-                // dvelasco: some builds of ownCloud server 4.0.x added a trailing ';' to the MIME type ; if looks fixed, but let's be cautious
-                if (mContentType.indexOf(";") >= 0) {
-                    mContentType = mContentType.substring(0, mContentType.indexOf(";"));
-                }
-            }
-            
-            // check if it's a folder in the standard way: see RFC2518 12.2 . RFC4918 14.3 
-            prop = propSet.get(DavPropertyName.RESOURCETYPE);
-            if (prop!= null) {
-                Object value = prop.getValue();
-                if (value != null) {
-                    mContentType = "DIR";   // a specific attribute would be better, but this is enough; unless while we have no reason to distinguish MIME types for folders
-                }
-            }
-
-            prop = propSet.get(DavPropertyName.GETCONTENTLENGTH);
-            if (prop != null)
-                mContentLength = Long.parseLong((String) prop.getValue());
-
-            prop = propSet.get(DavPropertyName.GETLASTMODIFIED);
-            if (prop != null) {
-                Date d = WebdavUtils
-                        .parseResponseDate((String) prop.getValue());
-                mModifiedTimestamp = (d != null) ? d.getTime() : 0;
-            }
-
-            prop = propSet.get(DavPropertyName.CREATIONDATE);
-            if (prop != null) {
-                Date d = WebdavUtils
-                        .parseResponseDate((String) prop.getValue());
-                mCreateTimestamp = (d != null) ? d.getTime() : 0;
-            }
-            
-            prop = propSet.get(DavPropertyName.GETETAG);
-            if (prop != null) {
-                mEtag = (String) prop.getValue();
-                mEtag = mEtag.substring(1, mEtag.length()-1);
-            }
-
-        } else {
-            Log_OC.e("WebdavEntry",
-                    "General fuckup, no status for webdav response");
-        }
-    }
-
-    public String path() {
-        return mPath;
-    }
-    
-    public String decodedPath() {
-        return Uri.decode(mPath);
-    }
-
-    public String name() {
-        return mName;
-    }
-
-    public boolean isDirectory() {
-        return mContentType.equals("DIR");
-    }
-
-    public String contentType() {
-        return mContentType;
-    }
-
-    public String uri() {
-        return mUri;
-    }
-
-    public long contentLength() {
-        return mContentLength;
-    }
-
-    public long createTimestamp() {
-        return mCreateTimestamp;
-    }
-
-    public long modifiedTimestamp() {
-        return mModifiedTimestamp;
-    }
-    
-    public String etag() {
-        return mEtag;
-    }
-
-    private void resetData() {
-        mName = mUri = mContentType = null;
-        mContentLength = mCreateTimestamp = mModifiedTimestamp = 0;
-    }
-}
diff --git a/src/eu/alefzero/webdav/WebdavUtils.java b/src/eu/alefzero/webdav/WebdavUtils.java
deleted file mode 100644 (file)
index 132a1f9..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012  Bartek Przybylski
- *   Copyright (C) 2012-2013 ownCloud Inc.
- *
- *   This program is free software: you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License version 2,
- *   as published by the Free Software Foundation.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-package eu.alefzero.webdav;
-
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.Locale;
-
-import android.net.Uri;
-
-public class WebdavUtils {
-    public static final SimpleDateFormat DISPLAY_DATE_FORMAT = new SimpleDateFormat(
-            "dd.MM.yyyy hh:mm");
-    private static final SimpleDateFormat DATETIME_FORMATS[] = {
-            new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US),
-            new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US),
-            new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.sss'Z'", Locale.US),
-            new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.US),
-            new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy", Locale.US),
-            new SimpleDateFormat("EEEEEE, dd-MMM-yy HH:mm:ss zzz", Locale.US),
-            new SimpleDateFormat("EEE MMMM d HH:mm:ss yyyy", Locale.US) };
-
-    public static String prepareXmlForPropFind() {
-        String ret = "<?xml version=\"1.0\" ?><D:propfind xmlns:D=\"DAV:\"><D:allprop/></D:propfind>";
-        return ret;
-    }
-
-    public static String prepareXmlForPatch() {
-        return "<?xml version=\"1.0\" ?><D:propertyupdate xmlns:D=\"DAV:\"></D:propertyupdate>";
-    }
-
-    public static Date parseResponseDate(String date) {
-        Date returnDate = null;
-        for (int i = 0; i < DATETIME_FORMATS.length; ++i) {
-            try {
-                returnDate = DATETIME_FORMATS[i].parse(date);
-                return returnDate;
-            } catch (ParseException e) {
-            }
-        }
-        return null;
-    }
-
-    /**
-     * Encodes a path according to URI RFC 2396. 
-     * 
-     * If the received path doesn't start with "/", the method adds it.
-     * 
-     * @param remoteFilePath    Path
-     * @return                  Encoded path according to RFC 2396, always starting with "/"
-     */
-    public static String encodePath(String remoteFilePath) {
-        String encodedPath = Uri.encode(remoteFilePath, "/");
-        if (!encodedPath.startsWith("/"))
-            encodedPath = "/" + encodedPath;
-        return encodedPath;
-    }
-    
-}
diff --git a/src/third_parties/daveKoeller/AlphanumComparator.java b/src/third_parties/daveKoeller/AlphanumComparator.java
new file mode 100644 (file)
index 0000000..e6bd6f3
--- /dev/null
@@ -0,0 +1,129 @@
+/*\r
+ * The Alphanum Algorithm is an improved sorting algorithm for strings\r
+ * containing numbers.  Instead of sorting numbers in ASCII order like\r
+ * a standard sort, this algorithm sorts numbers in numeric order.\r
+ *\r
+ * The Alphanum Algorithm is discussed at http://www.DaveKoelle.com\r
+ *\r
+ *\r
+ * This library is free software; you can redistribute it and/or\r
+ * modify it under the terms of the GNU Lesser General Public\r
+ * License as published by the Free Software Foundation; either\r
+ * version 2.1 of the License, or any later version.\r
+ *\r
+ * This library 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 GNU\r
+ * Lesser General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU Lesser General Public\r
+ * License along with this library; if not, write to the Free Software\r
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\r
+ *\r
+ */\r
+\r
+package third_parties.daveKoeller;\r
+import java.util.Comparator;\r
+\r
+import com.owncloud.android.datamodel.OCFile;\r
+\r
+/**\r
+ * This is an updated version with enhancements made by Daniel Migowski,\r
+ * Andre Bogus, and David Koelle\r
+ *\r
+ * To convert to use Templates (Java 1.5+):\r
+ *   - Change "implements Comparator" to "implements Comparator<String>"\r
+ *   - Change "compare(Object o1, Object o2)" to "compare(String s1, String s2)"\r
+ *   - Remove the type checking and casting in compare().\r
+ *\r
+ * To use this class:\r
+ *   Use the static "sort" method from the java.util.Collections class:\r
+ *   Collections.sort(your list, new AlphanumComparator());\r
+ */\r
+public class AlphanumComparator implements Comparator<OCFile>\r
+{\r
+    private final boolean isDigit(char ch)\r
+    {\r
+        return ch >= 48 && ch <= 57;\r
+    }\r
+\r
+    /** Length of string is passed in for improved efficiency (only need to calculate it once) **/\r
+    private final String getChunk(String s, int slength, int marker)\r
+    {\r
+        StringBuilder chunk = new StringBuilder();\r
+        char c = s.charAt(marker);\r
+        chunk.append(c);\r
+        marker++;\r
+        if (isDigit(c))\r
+        {\r
+            while (marker < slength)\r
+            {\r
+                c = s.charAt(marker);\r
+                if (!isDigit(c))\r
+                    break;\r
+                chunk.append(c);\r
+                marker++;\r
+            }\r
+        } else\r
+        {\r
+            while (marker < slength)\r
+            {\r
+                c = s.charAt(marker);\r
+                if (isDigit(c))\r
+                    break;\r
+                chunk.append(c);\r
+                marker++;\r
+            }\r
+        }\r
+        return chunk.toString();\r
+    }\r
+\r
+    public int compare(OCFile o1, OCFile o2)\r
+    {\r
+        String s1 = (String)o1.getRemotePath().toLowerCase();\r
+        String s2 = (String)o2.getRemotePath().toLowerCase();\r
+\r
+        int thisMarker = 0;\r
+        int thatMarker = 0;\r
+        int s1Length = s1.length();\r
+        int s2Length = s2.length();\r
+\r
+        while (thisMarker < s1Length && thatMarker < s2Length)\r
+        {\r
+            String thisChunk = getChunk(s1, s1Length, thisMarker);\r
+            thisMarker += thisChunk.length();\r
+\r
+            String thatChunk = getChunk(s2, s2Length, thatMarker);\r
+            thatMarker += thatChunk.length();\r
+\r
+            // If both chunks contain numeric characters, sort them numerically\r
+            int result = 0;\r
+            if (isDigit(thisChunk.charAt(0)) && isDigit(thatChunk.charAt(0)))\r
+            {\r
+                // Simple chunk comparison by length.\r
+                int thisChunkLength = thisChunk.length();\r
+                result = thisChunkLength - thatChunk.length();\r
+                // If equal, the first different number counts\r
+                if (result == 0)\r
+                {\r
+                    for (int i = 0; i < thisChunkLength; i++)\r
+                    {\r
+                        result = thisChunk.charAt(i) - thatChunk.charAt(i);\r
+                        if (result != 0)\r
+                        {\r
+                            return result;\r
+                        }\r
+                    }\r
+                }\r
+            } else\r
+            {\r
+                result = thisChunk.compareTo(thatChunk);\r
+            }\r
+\r
+            if (result != 0)\r
+                return result;\r
+        }\r
+\r
+        return s1Length - s2Length;\r
+    }\r
+}\r
diff --git a/src/third_parties/daveKoeller/lgpl-2.1.txt b/src/third_parties/daveKoeller/lgpl-2.1.txt
new file mode 100644 (file)
index 0000000..4362b49
--- /dev/null
@@ -0,0 +1,502 @@
+                  GNU LESSER GENERAL PUBLIC LICENSE
+                       Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL.  It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it.  You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+  When we speak of free software, we are referring to freedom of use,
+not price.  Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+  To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights.  These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  To protect each distributor, we want to make it very clear that
+there is no warranty for the free library.  Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+\f
+  Finally, software patents pose a constant threat to the existence of
+any free program.  We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder.  Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+  Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License.  This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License.  We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+  When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library.  The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom.  The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+  We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License.  It also provides other free software developers Less
+of an advantage over competing non-free programs.  These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries.  However, the Lesser license provides advantages in certain
+special circumstances.
+
+  For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard.  To achieve this, non-free programs must be
+allowed to use the library.  A more frequent case is that a free
+library does the same job as widely used non-free libraries.  In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+  In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software.  For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+  Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+\f
+                  GNU LESSER GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+\f
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+\f
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+\f
+  6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Use a suitable shared library mechanism for linking with the
+    Library.  A suitable mechanism is one that (1) uses at run time a
+    copy of the library already present on the user's computer system,
+    rather than copying library functions into the executable, and (2)
+    will operate properly with a modified version of the library, if
+    the user installs one, as long as the modified version is
+    interface-compatible with the version that the work was made with.
+
+    c) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    d) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    e) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+\f
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+\f
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+\f
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+                            NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+\f
+           How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library 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
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
index 6652724..9b141f6 100644 (file)
@@ -1,10 +1,10 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <classpath>
+       <classpathentry kind="src" path="src"/>
+       <classpathentry kind="src" path="gen"/>
+       <classpathentry combineaccessrules="false" kind="src" path="/owncloud-android"/>
        <classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
        <classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
        <classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.DEPENDENCIES"/>
-       <classpathentry combineaccessrules="false" kind="src" path="/owncloud-android"/>
-       <classpathentry kind="src" path="src"/>
-       <classpathentry kind="src" path="gen"/>
        <classpathentry kind="output" path="bin/classes"/>
 </classpath>
diff --git a/tests/ant.properties b/tests/ant.properties
new file mode 100644 (file)
index 0000000..1624402
--- /dev/null
@@ -0,0 +1,18 @@
+# This file is used to override default values used by the Ant build system.
+#
+# This file must be checked into Version Control Systems, as it is
+# integral to the build system of your project.
+
+# This file is only used by the Ant script.
+
+# You can use this to override default values such as
+#  'source.dir' for the location of your java source folder and
+#  'out.dir' for the location of your output folder.
+
+# You can also use it define how the release builds are signed by declaring
+# the following properties:
+#  'key.store' for the location of your keystore and
+#  'key.alias' for the name of the key to use.
+# The password will be asked during the build when you use the 'release' target.
+
+tested.project.dir=..
diff --git a/tests/build.xml b/tests/build.xml
new file mode 100644 (file)
index 0000000..3e82196
--- /dev/null
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project name="ownCloudTest" default="help">
+
+    <!-- The local.properties file is created and updated by the 'android' tool.
+         It contains the path to the SDK. It should *NOT* be checked into
+         Version Control Systems. -->
+    <property file="local.properties" />
+
+    <!-- The ant.properties file can be created by you. It is only edited by the
+         'android' tool to add properties to it.
+         This is the place to change some Ant specific build properties.
+         Here are some properties you may want to change/update:
+
+         source.dir
+             The name of the source directory. Default is 'src'.
+         out.dir
+             The name of the output directory. Default is 'bin'.
+
+         For other overridable properties, look at the beginning of the rules
+         files in the SDK, at tools/ant/build.xml
+
+         Properties related to the SDK location or the project target should
+         be updated using the 'android' tool with the 'update' action.
+
+         This file is an integral part of the build system for your
+         application and should be checked into Version Control Systems.
+
+         -->
+    <property file="ant.properties" />
+
+    <!-- if sdk.dir was not set from one of the property file, then
+         get it from the ANDROID_HOME env var.
+         This must be done before we load project.properties since
+         the proguard config can use sdk.dir -->
+    <property environment="env" />
+    <condition property="sdk.dir" value="${env.ANDROID_HOME}">
+        <isset property="env.ANDROID_HOME" />
+    </condition>
+
+    <!-- The project.properties file is created and updated by the 'android'
+         tool, as well as ADT.
+
+         This contains project specific properties such as project target, and library
+         dependencies. Lower level build properties are stored in ant.properties
+         (or in .classpath for Eclipse projects).
+
+         This file is an integral part of the build system for your
+         application and should be checked into Version Control Systems. -->
+    <loadproperties srcFile="project.properties" />
+
+    <!-- quick check on sdk.dir -->
+    <fail
+            message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through the ANDROID_HOME environment variable."
+            unless="sdk.dir"
+    />
+
+    <!--
+        Import per project custom build rules if present at the root of the project.
+        This is the place to put custom intermediary targets such as:
+            -pre-build
+            -pre-compile
+            -post-compile (This is typically used for code obfuscation.
+                           Compiled code location: ${out.classes.absolute.dir}
+                           If this is not done in place, override ${out.dex.input.absolute.dir})
+            -post-package
+            -post-build
+            -pre-clean
+    -->
+    <import file="custom_rules.xml" optional="true" />
+
+    <!-- Import the actual build file.
+
+         To customize existing targets, there are two options:
+         - Customize only one target:
+             - copy/paste the target into this file, *before* the
+               <import> task.
+             - customize it to your needs.
+         - Customize the whole content of build.xml
+             - copy/paste the content of the rules files (minus the top node)
+               into this file, replacing the <import> task.
+             - customize to your needs.
+
+         ***********************
+         ****** IMPORTANT ******
+         ***********************
+         In all cases you must update the value of version-tag below to read 'custom' instead of an integer,
+         in order to avoid having your file be overridden by tools such as "android update project"
+    -->
+    <!-- version-tag: 1 -->
+    <import file="${sdk.dir}/tools/ant/build.xml" />
+
+</project>
index a3ee5ab..4ab1256 100644 (file)
@@ -11,4 +11,4 @@
 #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
 
 # Project target.
-target=android-17
+target=android-19
index 529776b..fc6dc21 100644 (file)
 
 package com.owncloud.android.test;
 
+import com.owncloud.android.lib.common.accounts.AccountUtils;
+import com.owncloud.android.lib.resources.status.OwnCloudVersion;
+
 import android.test.AndroidTestCase;
 
-import com.owncloud.android.authentication.AccountUtils;
-import com.owncloud.android.utils.OwnCloudVersion;
 
 public class AccountUtilsTest extends AndroidTestCase {
     
index feaf44f..187bdf4 100644 (file)
Binary files a/third_party/android-support-library/android-support-v4.jar and b/third_party/android-support-library/android-support-v4.jar differ
diff --git a/third_party/touch-image-view/LICENSE b/third_party/touch-image-view/LICENSE
new file mode 100644 (file)
index 0000000..f60f212
--- /dev/null
@@ -0,0 +1,7 @@
+opyright (c) 2012 Michael Ortiz
+
+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
diff --git a/third_party/transifex-client/.gitignore b/third_party/transifex-client/.gitignore
deleted file mode 100644 (file)
index 72bd50c..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-.tx
-*pyc
-*pyo
-*~
-*egg-info*
diff --git a/third_party/transifex-client/DEVELOPMENT.rst b/third_party/transifex-client/DEVELOPMENT.rst
deleted file mode 100644 (file)
index 992e518..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-Releasing
-=========
-
-To create a new release:
-
-1. Update local rep and update the version in ``setup.py``::
-
-    $ hg pull -u
-    $ vim setup.py
-
-2. Test::
-
-    $ python setup.py clean sdist
-    $ cd dist
-    $ tar zxf ...
-    $ cd transifex-client
-    ...test
-
-3. Package and upload on PyPI::
-
-    $ python setup.py clean sdist bdist_egg upload
diff --git a/third_party/transifex-client/LICENSE b/third_party/transifex-client/LICENSE
deleted file mode 100644 (file)
index db860a3..0000000
+++ /dev/null
@@ -1,343 +0,0 @@
-                   GNU GENERAL PUBLIC LICENSE
-                      Version 2, June 1991
-
- Copyright (C) 1989, 1991 Free Software Foundation, Inc.
-                       51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
-                           Preamble
-
-  The licenses for most software are designed to take away your
-freedom to share and change it.  By contrast, the GNU General Public
-License is intended to guarantee your freedom to share and change free
-software--to make sure the software is free for all its users.  This
-General Public License applies to most of the Free Software
-Foundation's software and to any other program whose authors commit to
-using it.  (Some other Free Software Foundation software is covered by
-the GNU Library General Public License instead.)  You can apply it to
-your programs, too.
-
-  When we speak of free software, we are referring to freedom, not
-price.  Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-this service if you wish), that you receive source code or can get it
-if you want it, that you can change the software or use pieces of it
-in new free programs; and that you know you can do these things.
-
-  To protect your rights, we need to make restrictions that forbid
-anyone to deny you these rights or to ask you to surrender the rights.
-These restrictions translate to certain responsibilities for you if you
-distribute copies of the software, or if you modify it.
-
-  For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must give the recipients all the rights that
-you have.  You must make sure that they, too, receive or can get the
-source code.  And you must show them these terms so they know their
-rights.
-
-  We protect your rights with two steps: (1) copyright the software, and
-(2) offer you this license which gives you legal permission to copy,
-distribute and/or modify the software.
-
-  Also, for each author's protection and ours, we want to make certain
-that everyone understands that there is no warranty for this free
-software.  If the software is modified by someone else and passed on, we
-want its recipients to know that what they have is not the original, so
-that any problems introduced by others will not reflect on the original
-authors' reputations.
-
-  Finally, any free program is threatened constantly by software
-patents.  We wish to avoid the danger that redistributors of a free
-program will individually obtain patent licenses, in effect making the
-program proprietary.  To prevent this, we have made it clear that any
-patent must be licensed for everyone's free use or not licensed at all.
-
-  The precise terms and conditions for copying, distribution and
-modification follow.
-
-                   GNU GENERAL PUBLIC LICENSE
-   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
-  0. This License applies to any program or other work which contains
-a notice placed by the copyright holder saying it may be distributed
-under the terms of this General Public License.  The "Program", below,
-refers to any such program or work, and a "work based on the Program"
-means either the Program or any derivative work under copyright law:
-that is to say, a work containing the Program or a portion of it,
-either verbatim or with modifications and/or translated into another
-language.  (Hereinafter, translation is included without limitation in
-the term "modification".)  Each licensee is addressed as "you".
-
-Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope.  The act of
-running the Program is not restricted, and the output from the Program
-is covered only if its contents constitute a work based on the
-Program (independent of having been made by running the Program).
-Whether that is true depends on what the Program does.
-
-  1. You may copy and distribute verbatim copies of the Program's
-source code as you receive it, in any medium, provided that you
-conspicuously and appropriately publish on each copy an appropriate
-copyright notice and disclaimer of warranty; keep intact all the
-notices that refer to this License and to the absence of any warranty;
-and give any other recipients of the Program a copy of this License
-along with the Program.
-
-You may charge a fee for the physical act of transferring a copy, and
-you may at your option offer warranty protection in exchange for a fee.
-
-  2. You may modify your copy or copies of the Program or any portion
-of it, thus forming a work based on the Program, and copy and
-distribute such modifications or work under the terms of Section 1
-above, provided that you also meet all of these conditions:
-
-    a) You must cause the modified files to carry prominent notices
-    stating that you changed the files and the date of any change.
-
-    b) You must cause any work that you distribute or publish, that in
-    whole or in part contains or is derived from the Program or any
-    part thereof, to be licensed as a whole at no charge to all third
-    parties under the terms of this License.
-
-    c) If the modified program normally reads commands interactively
-    when run, you must cause it, when started running for such
-    interactive use in the most ordinary way, to print or display an
-    announcement including an appropriate copyright notice and a
-    notice that there is no warranty (or else, saying that you provide
-    a warranty) and that users may redistribute the program under
-    these conditions, and telling the user how to view a copy of this
-    License.  (Exception: if the Program itself is interactive but
-    does not normally print such an announcement, your work based on
-    the Program is not required to print an announcement.)
-
-These requirements apply to the modified work as a whole.  If
-identifiable sections of that work are not derived from the Program,
-and can be reasonably considered independent and separate works in
-themselves, then this License, and its terms, do not apply to those
-sections when you distribute them as separate works.  But when you
-distribute the same sections as part of a whole which is a work based
-on the Program, the distribution of the whole must be on the terms of
-this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote it.
-
-Thus, it is not the intent of this section to claim rights or contest
-your rights to work written entirely by you; rather, the intent is to
-exercise the right to control the distribution of derivative or
-collective works based on the Program.
-
-In addition, mere aggregation of another work not based on the Program
-with the Program (or with a work based on the Program) on a volume of
-a storage or distribution medium does not bring the other work under
-the scope of this License.
-
-  3. You may copy and distribute the Program (or a work based on it,
-under Section 2) in object code or executable form under the terms of
-Sections 1 and 2 above provided that you also do one of the following:
-
-    a) Accompany it with the complete corresponding machine-readable
-    source code, which must be distributed under the terms of Sections
-    1 and 2 above on a medium customarily used for software
-    interchange; or,
-
-    b) Accompany it with a written offer, valid for at least three
-    years, to give any third party, for a charge no more than your
-    cost of physically performing source distribution, a complete
-    machine-readable copy of the corresponding source code, to be
-    distributed under the terms of Sections 1 and 2 above on a medium
-    customarily used for software interchange; or,
-
-    c) Accompany it with the information you received as to the offer
-    to distribute corresponding source code.  (This alternative is
-    allowed only for noncommercial distribution and only if you
-    received the program in object code or executable form with such
-    an offer, in accord with Subsection b above.)
-
-The source code for a work means the preferred form of the work for
-making modifications to it.  For an executable work, complete source
-code means all the source code for all modules it contains, plus any
-associated interface definition files, plus the scripts used to
-control compilation and installation of the executable.  However, as a
-special exception, the source code distributed need not include
-anything that is normally distributed (in either source or binary
-form) with the major components (compiler, kernel, and so on) of the
-operating system on which the executable runs, unless that component
-itself accompanies the executable.
-
-If distribution of executable or object code is made by offering
-access to copy from a designated place, then offering equivalent
-access to copy the source code from the same place counts as
-distribution of the source code, even though third parties are not
-compelled to copy the source along with the object code.
-
-  4. You may not copy, modify, sublicense, or distribute the Program
-except as expressly provided under this License.  Any attempt
-otherwise to copy, modify, sublicense or distribute the Program is
-void, and will automatically terminate your rights under this License.
-However, parties who have received copies, or rights, from you under
-this License will not have their licenses terminated so long as such
-parties remain in full compliance.
-
-  5. You are not required to accept this License, since you have not
-signed it.  However, nothing else grants you permission to modify or
-distribute the Program or its derivative works.  These actions are
-prohibited by law if you do not accept this License.  Therefore, by
-modifying or distributing the Program (or any work based on the
-Program), you indicate your acceptance of this License to do so, and
-all its terms and conditions for copying, distributing or modifying
-the Program or works based on it.
-
-  6. Each time you redistribute the Program (or any work based on the
-Program), the recipient automatically receives a license from the
-original licensor to copy, distribute or modify the Program subject to
-these terms and conditions.  You may not impose any further
-restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties to
-this License.
-
-  7. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues),
-conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License.  If you cannot
-distribute so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you
-may not distribute the Program at all.  For example, if a patent
-license would not permit royalty-free redistribution of the Program by
-all those who receive copies directly or indirectly through you, then
-the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Program.
-
-If any portion of this section is held invalid or unenforceable under
-any particular circumstance, the balance of the section is intended to
-apply and the section as a whole is intended to apply in other
-circumstances.
-
-It is not the purpose of this section to induce you to infringe any
-patents or other property right claims or to contest validity of any
-such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system, which is
-implemented by public license practices.  Many people have made
-generous contributions to the wide range of software distributed
-through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing
-to distribute software through any other system and a licensee cannot
-impose that choice.
-
-This section is intended to make thoroughly clear what is believed to
-be a consequence of the rest of this License.
-
-  8. If the distribution and/or use of the Program is restricted in
-certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Program under this License
-may add an explicit geographical distribution limitation excluding
-those countries, so that distribution is permitted only in or among
-countries not thus excluded.  In such case, this License incorporates
-the limitation as if written in the body of this License.
-
-  9. The Free Software Foundation may publish revised and/or new versions
-of the General Public License from time to time.  Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
-Each version is given a distinguishing version number.  If the Program
-specifies a version number of this License which applies to it and
-"any later version", you have the option of following the terms and
-conditions either of that version or of any later version published by
-the Free Software Foundation.  If the Program does not specify a
-version number of this License, you may choose any version ever
-published by the Free Software Foundation.
-
-  10. If you wish to incorporate parts of the Program into other free
-programs whose distribution conditions are different, write to the author
-to ask for permission.  For software which is copyrighted by the Free
-Software Foundation, write to the Free Software Foundation; we sometimes
-make exceptions for this.  Our decision will be guided by the two goals
-of preserving the free status of all derivatives of our free software and
-of promoting the sharing and reuse of software generally.
-
-                           NO WARRANTY
-
-  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO
-WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
-EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
-OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY
-KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
-PROGRAM IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME
-THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
-
-  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
-WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
-AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU
-FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
-CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
-PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
-RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
-FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF
-SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
-DAMAGES.
-
-                    END OF TERMS AND CONDITIONS
-
-           How to Apply These Terms to Your New Programs
-
-  If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these
-terms.
-
-  To do so, attach the following notices to the program.  It is safest
-to attach them to the start of each source file to most effectively
-convey the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
-    <one line to give the program's name and a brief idea of what it does.>
-    Copyright (C) <year>  <name of author>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-  
-    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, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
-
-
-Also add information on how to contact you by electronic and paper mail.
-
-If the program is interactive, make it output a short notice like this
-when it starts in an interactive mode:
-
-    Gnomovision version 69, Copyright (C) year name of author
-    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
-    This is free software, and you are welcome to redistribute it
-    under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License.  Of course, the commands you use may
-be called something other than `show w' and `show c'; they could even be
-mouse-clicks or menu items--whatever suits your program.
-
-You should also get your employer (if you work as a programmer) or your
-school, if any, to sign a "copyright disclaimer" for the program, if
-necessary.  Here is a sample; alter the names:
-
-  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
-  `Gnomovision' (which makes passes at compilers) written by James Hacker.
-
-  <signature of Ty Coon>, 1 April 1989
-  Ty Coon, President of Vice
-
-This General Public License does not permit incorporating your program into
-proprietary programs.  If your program is a subroutine library, you may
-consider it more useful to permit linking proprietary applications with the
-library.  If this is what you want to do, use the GNU Library General
-Public License instead of this License.
-
diff --git a/third_party/transifex-client/MANIFEST.in b/third_party/transifex-client/MANIFEST.in
deleted file mode 100644 (file)
index 83126ac..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-include tx
-
-# Docs
-include LICENSE README.rst
-recursive-include docs *
-
diff --git a/third_party/transifex-client/README.rst b/third_party/transifex-client/README.rst
deleted file mode 100644 (file)
index bb88750..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-
-=============================
- Transifex Command-Line Tool
-=============================
-
-The Transifex Command-line Client is a command line tool that enables
-you to easily manage your translations within a project without the need
-of an elaborate UI system.
-
-You can use the command line client to easily create new resources, map
-locale files to translations and synchronize your Transifex project with
-your local repository and vice verca. Translators and localization
-managers can also use it to handle large volumes of translation files
-easily and without much hassle.
-
-Check the full documentation at
-http://help.transifex.com/user-guide/client/
-
-
-Installing
-==========
-
-You can install the latest version of transifex-client running ``pip
-install transifex-client`` or ``easy_install transifex-client``
-You can also install the `in-development version`_ of transifex-client
-with ``pip install transifex-client==dev`` or ``easy_install
-transifex-client==dev``.
-
-.. _in-development version: http://code.transifex.com/transifex-client/
-
diff --git a/third_party/transifex-client/setup.py b/third_party/transifex-client/setup.py
deleted file mode 100755 (executable)
index 626303d..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-
-import os
-import glob
-from codecs import BOM
-
-from setuptools import setup, find_packages
-from setuptools.command.build_py import build_py as _build_py
-
-from txclib import get_version
-
-readme_file = open(u'README.rst')
-long_description = readme_file.read()
-readme_file.close()
-if long_description.startswith(BOM):
-    long_description = long_description.lstrip(BOM)
-long_description = long_description.decode('utf-8')
-
-package_data = {
-    '': ['LICENSE', 'README.rst'],
-}
-
-scripts = ['tx']
-
-install_requires = []
-try:
-    import json
-except ImportError:
-    install_requires.append('simplejson')
-
-setup(
-    name="transifex-client",
-    version=get_version(),
-    scripts=scripts,
-    description="A command line interface for Transifex",
-    long_description=long_description,
-    author="Transifex",
-    author_email="info@transifex.com",
-    url="https://www.transifex.com",
-    license="GPLv2",
-    dependency_links = [
-    ],
-    setup_requires = [
-    ],
-    install_requires = install_requires,
-    tests_require = ["mock", ],
-    data_files=[
-    ],
-    test_suite="tests",
-    zip_safe=False,
-    packages=['txclib', ],
-    include_package_data=True,
-    package_data = package_data,
-    keywords = ('translation', 'localization', 'internationalization',),
-)
diff --git a/third_party/transifex-client/tests/__init__.py b/third_party/transifex-client/tests/__init__.py
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/third_party/transifex-client/tests/test_processors.py b/third_party/transifex-client/tests/test_processors.py
deleted file mode 100644 (file)
index dd7d7d9..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-# -*- coding: utf-8 -*-
-
-"""
-Unit tests for processor functions.
-"""
-
-import unittest
-from urlparse import urlparse
-from txclib.processors import hostname_tld_migration, hostname_ssl_migration
-
-
-class TestHostname(unittest.TestCase):
-    """Test for hostname processors."""
-
-    def test_tld_migration_needed(self):
-        """
-        Test the tld migration of Transifex, when needed.
-        """
-        hostnames = [
-            'http://transifex.net', 'http://www.transifex.net',
-            'https://fedora.transifex.net',
-        ]
-        for h in hostnames:
-            hostname = hostname_tld_migration(h)
-            self.assertTrue(hostname.endswith('com'))
-        orig_hostname = 'http://www.transifex.net/path/'
-        hostname = hostname_tld_migration(orig_hostname)
-        self.assertEqual(hostname, orig_hostname.replace('net', 'com', 1))
-
-    def test_tld_migration_needed(self):
-        """
-        Test that unneeded tld migrations are detected correctly.
-        """
-        hostnames = [
-            'https://www.transifex.com', 'http://fedora.transifex.com',
-            'http://www.example.net/path/'
-        ]
-        for h in hostnames:
-            hostname = hostname_tld_migration(h)
-            self.assertEqual(hostname, h)
-
-    def test_no_scheme_specified(self):
-        """
-        Test that, if no scheme has been specified, the https one will be used.
-        """
-        hostname = '//transifex.net'
-        hostname = hostname_ssl_migration(hostname)
-        self.assertTrue(hostname.startswith('https://'))
-
-    def test_http_replacement(self):
-        """Test the replacement of http with https."""
-        hostnames = [
-            'http://transifex.com', 'http://transifex.net/http/',
-            'http://www.transifex.com/path/'
-        ]
-        for h in hostnames:
-            hostname = hostname_ssl_migration(h)
-            self.assertEqual(hostname[:8], 'https://')
-            self.assertEqual(hostname[7:], h[6:])
-
-    def test_no_http_replacement_needed(self):
-        """Test that http will not be replaces with https, when not needed."""
-        for h in ['http://example.com', 'http://example.com/http/']:
-            hostname = hostname_ssl_migration(h)
-            self.assertEqual(hostname, hostname)
diff --git a/third_party/transifex-client/tests/test_project.py b/third_party/transifex-client/tests/test_project.py
deleted file mode 100644 (file)
index 3b42121..0000000
+++ /dev/null
@@ -1,531 +0,0 @@
-# -*- coding: utf-8 -*-
-
-from __future__ import with_statement
-import unittest
-import contextlib
-import itertools
-try:
-    import json
-except ImportError:
-    import simplejson as json
-from mock import Mock, patch
-
-from txclib.project import Project
-from txclib.config import Flipdict
-
-
-class TestProject(unittest.TestCase):
-
-    def test_extract_fields(self):
-        """Test the functions that extract a field from a stats object."""
-        stats = {
-            'completed': '80%',
-            'last_update': '00:00',
-            'foo': 'bar',
-        }
-        self.assertEqual(
-            stats['completed'], '%s%%' % Project._extract_completed(stats)
-        )
-        self.assertEqual(stats['last_update'], Project._extract_updated(stats))
-
-    def test_specifying_resources(self):
-        """Test the various ways to specify resources in a project."""
-        p = Project(init=False)
-        resources = [
-            'proj1.res1',
-            'proj2.res2',
-            'transifex.txn',
-            'transifex.txo',
-        ]
-        with patch.object(p, 'get_resource_list') as mock:
-            mock.return_value = resources
-            cmd_args = [
-                'proj1.res1', '*1*', 'transifex*', '*r*',
-                '*o', 'transifex.tx?', 'transifex.txn',
-            ]
-            results = [
-                ['proj1.res1', ],
-                ['proj1.res1', ],
-                ['transifex.txn', 'transifex.txo', ],
-                ['proj1.res1', 'proj2.res2', 'transifex.txn', 'transifex.txo', ],
-                ['transifex.txo', ],
-                ['transifex.txn', 'transifex.txo', ],
-                ['transifex.txn', ],
-                [],
-            ]
-
-            for i, arg in enumerate(cmd_args):
-                resources = [arg]
-                self.assertEqual(p.get_chosen_resources(resources), results[i])
-
-            # wrong argument
-            resources = ['*trasnifex*', ]
-            self.assertRaises(Exception, p.get_chosen_resources, resources)
-
-
-class TestProjectMinimumPercent(unittest.TestCase):
-    """Test the minimum-perc option."""
-
-    def setUp(self):
-        super(TestProjectMinimumPercent, self).setUp()
-        self.p = Project(init=False)
-        self.p.minimum_perc = None
-        self.p.resource = "resource"
-
-    def test_cmd_option(self):
-        """Test command-line option."""
-        self.p.minimum_perc = 20
-        results = itertools.cycle([80, 90 ])
-        def side_effect(*args):
-            return results.next()
-
-        with patch.object(self.p, "get_resource_option") as mock:
-            mock.side_effect = side_effect
-            self.assertFalse(self.p._satisfies_min_translated({'completed': '12%'}))
-            self.assertTrue(self.p._satisfies_min_translated({'completed': '20%'}))
-            self.assertTrue(self.p._satisfies_min_translated({'completed': '30%'}))
-
-    def test_global_only(self):
-        """Test only global option."""
-        results = itertools.cycle([80, None ])
-        def side_effect(*args):
-            return results.next()
-
-        with patch.object(self.p, "get_resource_option") as mock:
-            mock.side_effect = side_effect
-            self.assertFalse(self.p._satisfies_min_translated({'completed': '70%'}))
-            self.assertTrue(self.p._satisfies_min_translated({'completed': '80%'}))
-            self.assertTrue(self.p._satisfies_min_translated({'completed': '90%'}))
-
-    def test_local_lower_than_global(self):
-        """Test the case where the local option is lower than the global."""
-        results = itertools.cycle([80, 70 ])
-        def side_effect(*args):
-            return results.next()
-
-        with patch.object(self.p, "get_resource_option") as mock:
-            mock.side_effect = side_effect
-            self.assertFalse(self.p._satisfies_min_translated({'completed': '60%'}))
-            self.assertTrue(self.p._satisfies_min_translated({'completed': '70%'}))
-            self.assertTrue(self.p._satisfies_min_translated({'completed': '80%'}))
-            self.assertTrue(self.p._satisfies_min_translated({'completed': '90%'}))
-
-    def test_local_higher_than_global(self):
-        """Test the case where the local option is lower than the global."""
-        results = itertools.cycle([60, 70 ])
-        def side_effect(*args):
-            return results.next()
-
-        with patch.object(self.p, "get_resource_option") as mock:
-            mock.side_effect = side_effect
-            self.assertFalse(self.p._satisfies_min_translated({'completed': '60%'}))
-            self.assertTrue(self.p._satisfies_min_translated({'completed': '70%'}))
-            self.assertTrue(self.p._satisfies_min_translated({'completed': '80%'}))
-            self.assertTrue(self.p._satisfies_min_translated({'completed': '90%'}))
-
-    def test_local_only(self):
-        """Test the case where the local option is lower than the global."""
-        results = itertools.cycle([None, 70 ])
-        def side_effect(*args):
-            return results.next()
-
-        with patch.object(self.p, "get_resource_option") as mock:
-            mock.side_effect = side_effect
-            self.assertFalse(self.p._satisfies_min_translated({'completed': '60%'}))
-            self.assertTrue(self.p._satisfies_min_translated({'completed': '70%'}))
-            self.assertTrue(self.p._satisfies_min_translated({'completed': '80%'}))
-            self.assertTrue(self.p._satisfies_min_translated({'completed': '90%'}))
-
-    def test_no_option(self):
-        """"Test the case there is nothing defined."""
-        results = itertools.cycle([None, None ])
-        def side_effect(*args):
-            return results.next()
-
-        with patch.object(self.p, "get_resource_option") as mock:
-            mock.side_effect = side_effect
-            self.assertTrue(self.p._satisfies_min_translated({'completed': '0%'}))
-            self.assertTrue(self.p._satisfies_min_translated({'completed': '10%'}))
-            self.assertTrue(self.p._satisfies_min_translated({'completed': '90%'}))
-
-
-class TestProjectFilters(unittest.TestCase):
-    """Test filters used to decide whether to push/pull a translation or not."""
-
-    def setUp(self):
-        super(TestProjectFilters, self).setUp()
-        self.p = Project(init=False)
-        self.p.minimum_perc = None
-        self.p.resource = "resource"
-        self.stats = {
-            'en': {
-                'completed': '100%', 'last_update': '2011-11-01 15:00:00',
-            }, 'el': {
-                'completed': '60%', 'last_update': '2011-11-01 15:00:00',
-            }, 'pt': {
-                'completed': '70%', 'last_update': '2011-11-01 15:00:00',
-            },
-        }
-        self.langs = self.stats.keys()
-
-    def test_add_translation(self):
-        """Test filters for adding translations.
-
-        We do not test here for minimum percentages.
-        """
-        with patch.object(self.p, "get_resource_option") as mock:
-            mock.return_value = None
-            should_add = self.p._should_add_translation
-            for force in [True, False]:
-                for lang in self.langs:
-                    self.assertTrue(should_add(lang, self.stats, force))
-
-            # unknown language
-            self.assertFalse(should_add('es', self.stats))
-
-    def test_update_translation(self):
-        """Test filters for updating a translation.
-
-        We do not test here for minimum percentages.
-        """
-        with patch.object(self.p, "get_resource_option") as mock:
-            mock.return_value = None
-
-            should_update = self.p._should_update_translation
-            force = True
-            for lang in self.langs:
-                self.assertTrue(should_update(lang, self.stats, 'foo', force))
-
-            force = False       # reminder
-            local_file = 'foo'
-
-            # unknown language
-            self.assertFalse(should_update('es', self.stats, local_file))
-
-            # no local file
-            with patch.object(self.p, "_get_time_of_local_file") as time_mock:
-                time_mock.return_value = None
-                with patch.object(self.p, "get_full_path") as path_mock:
-                    path_mock.return_value = "foo"
-                    for lang in self.langs:
-                        self.assertTrue(
-                            should_update(lang, self.stats, local_file)
-                        )
-
-            # older local files
-            local_times = [self.p._generate_timestamp('2011-11-01 14:00:59')]
-            results = itertools.cycle(local_times)
-            def side_effect(*args):
-                return results.next()
-
-            with patch.object(self.p, "_get_time_of_local_file") as time_mock:
-                time_mock.side_effect = side_effect
-                with patch.object(self.p, "get_full_path") as path_mock:
-                    path_mock.return_value = "foo"
-                    for lang in self.langs:
-                        self.assertTrue(
-                            should_update(lang, self.stats, local_file)
-                        )
-
-            # newer local files
-            local_times = [self.p._generate_timestamp('2011-11-01 15:01:59')]
-            results = itertools.cycle(local_times)
-            def side_effect(*args):
-                return results.next()
-
-            with patch.object(self.p, "_get_time_of_local_file") as time_mock:
-                time_mock.side_effect = side_effect
-                with patch.object(self.p, "get_full_path") as path_mock:
-                    path_mock.return_value = "foo"
-                    for lang in self.langs:
-                        self.assertFalse(
-                            should_update(lang, self.stats, local_file)
-                        )
-
-    def test_push_translation(self):
-        """Test filters for pushing a translation file."""
-        with patch.object(self.p, "get_resource_option") as mock:
-            mock.return_value = None
-
-            local_file = 'foo'
-            should_push = self.p._should_push_translation
-            force = True
-            for lang in self.langs:
-                self.assertTrue(should_push(lang, self.stats, local_file, force))
-
-            force = False       # reminder
-
-            # unknown language
-            self.assertTrue(should_push('es', self.stats, local_file))
-
-            # older local files
-            local_times = [self.p._generate_timestamp('2011-11-01 14:00:59')]
-            results = itertools.cycle(local_times)
-            def side_effect(*args):
-                return results.next()
-
-            with patch.object(self.p, "_get_time_of_local_file") as time_mock:
-                time_mock.side_effect = side_effect
-                with patch.object(self.p, "get_full_path") as path_mock:
-                    path_mock.return_value = "foo"
-                    for lang in self.langs:
-                        self.assertFalse(
-                            should_push(lang, self.stats, local_file)
-                        )
-
-            # newer local files
-            local_times = [self.p._generate_timestamp('2011-11-01 15:01:59')]
-            results = itertools.cycle(local_times)
-            def side_effect(*args):
-                return results.next()
-
-            with patch.object(self.p, "_get_time_of_local_file") as time_mock:
-                time_mock.side_effect = side_effect
-                with patch.object(self.p, "get_full_path") as path_mock:
-                    path_mock.return_value = "foo"
-                    for lang in self.langs:
-                        self.assertTrue(
-                            should_push(lang, self.stats, local_file)
-                        )
-
-
-class TestProjectPull(unittest.TestCase):
-    """Test bits & pieces of the pull method."""
-
-    def setUp(self):
-        super(TestProjectPull, self).setUp()
-        self.p = Project(init=False)
-        self.p.minimum_perc = None
-        self.p.resource = "resource"
-        self.p.host = 'foo'
-        self.p.project_slug = 'foo'
-        self.p.resource_slug = 'foo'
-        self.stats = {
-            'en': {
-                'completed': '100%', 'last_update': '2011-11-01 15:00:00',
-            }, 'el': {
-                'completed': '60%', 'last_update': '2011-11-01 15:00:00',
-            }, 'pt': {
-                'completed': '70%', 'last_update': '2011-11-01 15:00:00',
-            },
-        }
-        self.langs = self.stats.keys()
-        self.files = dict(zip(self.langs, itertools.repeat(None)))
-        self.details = {'available_languages': []}
-        for lang in self.langs:
-            self.details['available_languages'].append({'code': lang})
-        self.slang = 'en'
-        self.lang_map = Flipdict()
-
-    def test_new_translations(self):
-        """Test finding new transaltions to add."""
-        with patch.object(self.p, 'do_url_request') as resource_mock:
-            resource_mock.return_value = json.dumps(self.details)
-            files_keys = self.langs
-            new_trans = self.p._new_translations_to_add
-            for force in [True, False]:
-                res = new_trans(
-                    self.files, self.slang, self.lang_map, self.stats, force
-                )
-                self.assertEquals(res, set([]))
-
-            with patch.object(self.p, '_should_add_translation') as filter_mock:
-                filter_mock.return_value = True
-                for force in [True, False]:
-                    res = new_trans(
-                        {'el': None}, self.slang, self.lang_map, self.stats, force
-                    )
-                    self.assertEquals(res, set(['pt']))
-                for force in [True, False]:
-                    res = new_trans(
-                        {}, self.slang, self.lang_map, self.stats, force
-                    )
-                    self.assertEquals(res, set(['el', 'pt']))
-
-                files = {}
-                files['pt_PT'] = None
-                lang_map = {'pt': 'pt_PT'}
-                for force in [True, False]:
-                    res = new_trans(
-                        files, self.slang, lang_map, self.stats, force
-                    )
-                    self.assertEquals(res, set(['el']))
-
-    def test_languages_to_pull_empty_initial_list(self):
-        """Test determining the languages to pull, when the initial
-        list is empty.
-        """
-        languages = []
-        force = False
-
-        res = self.p._languages_to_pull(
-            languages, self.files, self.lang_map, self.stats, force
-        )
-        existing = res[0]
-        new = res[1]
-        self.assertEquals(existing, set(['el', 'en', 'pt']))
-        self.assertFalse(new)
-
-        del self.files['el']
-        self.files['el-gr'] = None
-        self.lang_map['el'] = 'el-gr'
-        res = self.p._languages_to_pull(
-            languages, self.files, self.lang_map, self.stats, force
-        )
-        existing = res[0]
-        new = res[1]
-        self.assertEquals(existing, set(['el', 'en', 'pt']))
-        self.assertFalse(new)
-
-    def test_languages_to_pull_with_initial_list(self):
-        """Test determining the languages to pull, then there is a
-        language selection from the user.
-        """
-        languages = ['el', 'en']
-        self.lang_map['el'] = 'el-gr'
-        del self.files['el']
-        self.files['el-gr'] = None
-        force = False
-
-        with patch.object(self.p, '_should_add_translation') as mock:
-            mock.return_value = True
-            res = self.p._languages_to_pull(
-                languages, self.files, self.lang_map, self.stats, force
-            )
-            existing = res[0]
-            new = res[1]
-            self.assertEquals(existing, set(['en', 'el-gr', ]))
-            self.assertFalse(new)
-
-            mock.return_value = False
-            res = self.p._languages_to_pull(
-                languages, self.files, self.lang_map, self.stats, force
-            )
-            existing = res[0]
-            new = res[1]
-            self.assertEquals(existing, set(['en', 'el-gr', ]))
-            self.assertFalse(new)
-
-            del self.files['el-gr']
-            mock.return_value = True
-            res = self.p._languages_to_pull(
-                languages, self.files, self.lang_map, self.stats, force
-            )
-            existing = res[0]
-            new = res[1]
-            self.assertEquals(existing, set(['en', ]))
-            self.assertEquals(new, set(['el', ]))
-
-            mock.return_value = False
-            res = self.p._languages_to_pull(
-                languages, self.files, self.lang_map, self.stats, force
-            )
-            existing = res[0]
-            new = res[1]
-            self.assertEquals(existing, set(['en', ]))
-            self.assertEquals(new, set([]))
-
-    def test_in_combination_with_force_option(self):
-        """Test the minumum-perc option along with -f."""
-        with patch.object(self.p, 'get_resource_option') as mock:
-            mock.return_value = 70
-
-            res = self.p._should_download('de', self.stats, None, False)
-            self.assertEquals(res, False)
-            res = self.p._should_download('el', self.stats, None, False)
-            self.assertEquals(res, False)
-            res = self.p._should_download('el', self.stats, None, True)
-            self.assertEquals(res, False)
-            res = self.p._should_download('en', self.stats, None, False)
-            self.assertEquals(res, True)
-            res = self.p._should_download('en', self.stats, None, True)
-            self.assertEquals(res, True)
-
-            with patch.object(self.p, '_remote_is_newer') as local_file_mock:
-                local_file_mock = False
-                res = self.p._should_download('pt', self.stats, None, False)
-                self.assertEquals(res, True)
-                res = self.p._should_download('pt', self.stats, None, True)
-                self.assertEquals(res, True)
-
-
-class TestFormats(unittest.TestCase):
-    """Tests for the supported formats."""
-
-    def setUp(self):
-        self.p = Project(init=False)
-
-    def test_extensions(self):
-        """Test returning the correct extension for a format."""
-        sample_formats = {
-            'PO': {'file-extensions': '.po, .pot'},
-            'QT': {'file-extensions': '.ts'},
-        }
-        extensions = ['.po', '.ts', '', ]
-        with patch.object(self.p, "do_url_request") as mock:
-            mock.return_value = json.dumps(sample_formats)
-            for (type_, ext) in zip(['PO', 'QT', 'NONE', ], extensions):
-                extension = self.p._extension_for(type_)
-                self.assertEquals(extension, ext)
-
-
-class TestOptions(unittest.TestCase):
-    """Test the methods related to parsing the configuration file."""
-
-    def setUp(self):
-        self.p = Project(init=False)
-
-    def test_get_option(self):
-        """Test _get_option method."""
-        with contextlib.nested(
-            patch.object(self.p, 'get_resource_option'),
-            patch.object(self.p, 'config', create=True)
-        ) as (rmock, cmock):
-            rmock.return_value = 'resource'
-            cmock.has_option.return_value = 'main'
-            cmock.get.return_value = 'main'
-            self.assertEqual(self.p._get_option(None, None), 'resource')
-            rmock.return_value = None
-            cmock.has_option.return_value = 'main'
-            cmock.get.return_value = 'main'
-            self.assertEqual(self.p._get_option(None, None), 'main')
-            cmock.has_option.return_value = None
-            self.assertIs(self.p._get_option(None, None), None)
-
-
-class TestConfigurationOptions(unittest.TestCase):
-    """Test the various configuration options."""
-
-    def test_i18n_type(self):
-        p = Project(init=False)
-        type_string = 'type'
-        i18n_type = 'PO'
-        with patch.object(p, 'config', create=True) as config_mock:
-            p.set_i18n_type([], i18n_type)
-            calls = config_mock.method_calls
-            self.assertEquals('set', calls[0][0])
-            self.assertEquals('main', calls[0][1][0])
-            p.set_i18n_type(['transifex.txo'], 'PO')
-            calls = config_mock.method_calls
-            self.assertEquals('set', calls[0][0])
-            p.set_i18n_type(['transifex.txo', 'transifex.txn'], 'PO')
-            calls = config_mock.method_calls
-            self.assertEquals('set', calls[0][0])
-            self.assertEquals('set', calls[1][0])
-
-
-class TestStats(unittest.TestCase):
-    """Test the access to the stats objects."""
-
-    def setUp(self):
-        self.stats = Mock()
-        self.stats.__getitem__ = Mock()
-        self.stats.__getitem__.return_value = '12%'
-
-    def test_field_used_per_mode(self):
-        """Test the fields used for each mode."""
-        Project._extract_completed(self.stats, 'translate')
-        self.stats.__getitem__.assert_called_with('completed')
-        Project._extract_completed(self.stats, 'reviewed')
-        self.stats.__getitem__.assert_called_with('reviewed_percentage')
-
diff --git a/third_party/transifex-client/tx b/third_party/transifex-client/tx
deleted file mode 100755 (executable)
index dfb4a4c..0000000
+++ /dev/null
@@ -1,109 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-
-from optparse import OptionParser, OptionValueError
-import os
-import sys
-
-from txclib import utils
-from txclib import get_version
-from txclib.log import set_log_level, logger
-
-reload(sys) # WTF? Otherwise setdefaultencoding doesn't work
-
-# This block ensures that ^C interrupts are handled quietly.
-try:
-    import signal
-
-    def exithandler(signum,frame):
-        signal.signal(signal.SIGINT, signal.SIG_IGN)
-        signal.signal(signal.SIGTERM, signal.SIG_IGN)
-        sys.exit(1)
-
-    signal.signal(signal.SIGINT, exithandler)
-    signal.signal(signal.SIGTERM, exithandler)
-    if hasattr(signal, 'SIGPIPE'):
-        signal.signal(signal.SIGPIPE, signal.SIG_DFL)
-
-except KeyboardInterrupt:
-    sys.exit(1)
-
-# When we open file with f = codecs.open we specifi FROM what encoding to read
-# This sets the encoding for the strings which are created with f.read()
-sys.setdefaultencoding('utf-8')
-
-
-def main(argv):
-    """
-    Here we parse the flags (short, long) and we instantiate the classes.
-    """
-    usage = "usage: %prog [options] command [cmd_options]"
-    description = "This is the Transifex command line client which"\
-               " allows you to manage your translations locally and sync"\
-               " them with the master Transifex server.\nIf you'd like to"\
-               " check the available commands issue `%prog help` or if you"\
-               " just want help with a specific command issue `%prog help"\
-               " command`"
-
-    parser = OptionParser(
-        usage=usage, version=get_version(), description=description
-    )
-    parser.disable_interspersed_args()
-    parser.add_option(
-        "-d", "--debug", action="store_true", dest="debug",
-        default=False, help=("enable debug messages")
-    )
-    parser.add_option(
-        "-q", "--quiet", action="store_true", dest="quiet",
-        default=False, help="don't print status messages to stdout"
-    )
-    parser.add_option(
-        "-r", "--root", action="store", dest="root_dir", type="string",
-        default=None, help="change root directory (default is cwd)"
-    )
-    parser.add_option(
-        "--traceback", action="store_true", dest="trace", default=False,
-        help="print full traceback on exceptions"
-    )
-    parser.add_option(
-        "--disable-colors", action="store_true", dest="color_disable",
-        default=(os.name == 'nt' or not sys.stdout.isatty()),
-        help="disable colors in the output of commands"
-    )
-    (options, args) = parser.parse_args()
-
-    if len(args) < 1:
-        parser.error("No command was given")
-
-    utils.DISABLE_COLORS = options.color_disable
-
-    # set log level
-    if options.quiet:
-        set_log_level('WARNING')
-    elif options.debug:
-        set_log_level('DEBUG')
-
-    # find .tx
-    path_to_tx = options.root_dir or utils.find_dot_tx()
-
-
-    cmd = args[0]
-    try:
-        utils.exec_command(cmd, args[1:], path_to_tx)
-    except utils.UnknownCommandError:
-        logger.error("tx: Command %s not found" % cmd)
-    except SystemExit:
-        sys.exit()
-    except:
-        import traceback
-        if options.trace:
-            traceback.print_exc()
-        else:
-            formatted_lines = traceback.format_exc().splitlines()
-            logger.error(formatted_lines[-1])
-        sys.exit(1)
-
-# Run baby :) ... run
-if __name__ == "__main__":
-    # sys.argv[0] is the name of the script that we’re running.
-    main(sys.argv[1:])
diff --git a/third_party/transifex-client/txclib/__init__.py b/third_party/transifex-client/txclib/__init__.py
deleted file mode 100644 (file)
index 814773c..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-# -*- coding: utf-8 -*-
-
-"""
-Copyright (C) 2010 by Indifex (www.indifex.com), see AUTHORS.
-License: BSD, see LICENSE for details.
-
-For further information visit http://code.indifex.com/transifex-client
-"""
-
-
-VERSION = (0, 9, 0, 'devel')
-
-def get_version():
-    version = '%s.%s' % (VERSION[0], VERSION[1])
-    if VERSION[2]:
-        version = '%s.%s' % (version, VERSION[2])
-    if VERSION[3] != 'final':
-        version = '%s %s' % (version, VERSION[3])
-    return version
diff --git a/third_party/transifex-client/txclib/commands.py b/third_party/transifex-client/txclib/commands.py
deleted file mode 100644 (file)
index 282287f..0000000
+++ /dev/null
@@ -1,576 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
-In this file we have all the top level commands for the transifex client.
-Since we're using a way to automatically list them and execute them, when
-adding code to this file you must take care of the following:
- * Added functions must begin with 'cmd_' followed by the actual name of the
-   command being used in the command line (eg cmd_init)
- * The description for each function that we display to the user is read from
-   the func_doc attribute which reads the doc string. So, when adding
-   docstring to a new function make sure you add an oneliner which is
-   descriptive and is meant to be seen by the user.
- * When including libraries, it's best if you include modules instead of
-   functions because that way our function resolution will work faster and the
-   chances of overlapping are minimal
- * All functions should use the OptionParser and should have a usage and
-   descripition field.
-"""
-import os
-import re, shutil
-import sys
-from optparse import OptionParser, OptionGroup
-import ConfigParser
-
-
-from txclib import utils, project
-from txclib.utils import parse_json, compile_json, relpath
-from txclib.config import OrderedRawConfigParser
-from txclib.exceptions import UnInitializedError
-from txclib.parsers import delete_parser, help_parser, parse_csv_option, \
-        status_parser, pull_parser, set_parser, push_parser, init_parser
-from txclib.log import logger
-
-
-def cmd_init(argv, path_to_tx):
-    "Initialize a new transifex project."
-    parser = init_parser()
-    (options, args) = parser.parse_args(argv)
-    if len(args) > 1:
-        parser.error("Too many arguments were provided. Aborting...")
-    if args:
-        path_to_tx = args[0]
-    else:
-        path_to_tx = os.getcwd()
-
-    if os.path.isdir(os.path.join(path_to_tx,".tx")):
-        logger.info("tx: There is already a tx folder!")
-        reinit = raw_input("Do you want to delete it and reinit the project? [y/N]: ")
-        while (reinit != 'y' and reinit != 'Y' and reinit != 'N' and reinit != 'n' and reinit != ''):
-            reinit = raw_input("Do you want to delete it and reinit the project? [y/N]: ")
-        if not reinit or reinit in ['N', 'n', 'NO', 'no', 'No']:
-            return
-        # Clean the old settings
-        # FIXME: take a backup
-        else:
-            rm_dir = os.path.join(path_to_tx, ".tx")
-            shutil.rmtree(rm_dir)
-
-    logger.info("Creating .tx folder...")
-    os.mkdir(os.path.join(path_to_tx,".tx"))
-
-    # Handle the credentials through transifexrc
-    home = os.path.expanduser("~")
-    txrc = os.path.join(home, ".transifexrc")
-    config = OrderedRawConfigParser()
-
-    default_transifex = "https://www.transifex.com"
-    transifex_host = options.host or raw_input("Transifex instance [%s]: " % default_transifex)
-
-    if not transifex_host:
-        transifex_host = default_transifex
-    if not transifex_host.startswith(('http://', 'https://')):
-        transifex_host = 'https://' + transifex_host
-
-    config_file = os.path.join(path_to_tx, ".tx", "config")
-    if not os.path.exists(config_file):
-        # The path to the config file (.tx/config)
-        logger.info("Creating skeleton...")
-        config = OrderedRawConfigParser()
-        config.add_section('main')
-        config.set('main', 'host', transifex_host)
-        # Touch the file if it doesn't exist
-        logger.info("Creating config file...")
-        fh = open(config_file, 'w')
-        config.write(fh)
-        fh.close()
-
-    prj = project.Project(path_to_tx)
-    prj.getset_host_credentials(transifex_host, user=options.user,
-        password=options.password)
-    prj.save()
-    logger.info("Done.")
-
-
-def cmd_set(argv, path_to_tx):
-    "Add local or remote files under transifex"
-    parser = set_parser()
-    (options, args) = parser.parse_args(argv)
-
-    # Implement options/args checks
-    # TODO !!!!!!!
-    if options.local:
-        try:
-            expression = args[0]
-        except IndexError:
-            parser.error("Please specify an expression.")
-        if not options.resource:
-            parser.error("Please specify a resource")
-        if not options.source_language:
-            parser.error("Please specify a source language.")
-        if not '<lang>' in expression:
-            parser.error("The expression you have provided is not valid.")
-        if not utils.valid_slug(options.resource):
-            parser.error("Invalid resource slug. The format is <project_slug>"\
-                ".<resource_slug> and the valid characters include [_-\w].")
-        _auto_local(path_to_tx, options.resource,
-            source_language=options.source_language,
-            expression = expression, source_file=options.source_file,
-            execute=options.execute, regex=False)
-        if options.execute:
-            _set_minimum_perc(options.resource, options.minimum_perc, path_to_tx)
-            _set_mode(options.resource, options.mode, path_to_tx)
-            _set_type(options.resource, options.i18n_type, path_to_tx)
-        return
-
-    if options.remote:
-        try:
-            url = args[0]
-        except IndexError:
-            parser.error("Please specify an remote url")
-        _auto_remote(path_to_tx, url)
-        _set_minimum_perc(options.resource, options.minimum_perc, path_to_tx)
-        _set_mode(options.resource, options.mode, path_to_tx)
-        return
-
-    if options.is_source:
-        resource = options.resource
-        if not resource:
-            parser.error("You must specify a resource name with the"
-                " -r|--resource flag.")
-
-        lang = options.language
-        if not lang:
-            parser.error("Please specify a source language.")
-
-        if len(args) != 1:
-            parser.error("Please specify a file.")
-
-        if not utils.valid_slug(resource):
-            parser.error("Invalid resource slug. The format is <project_slug>"\
-                ".<resource_slug> and the valid characters include [_-\w].")
-
-        file = args[0]
-        # Calculate relative path
-        path_to_file = relpath(file, path_to_tx)
-        _set_source_file(path_to_tx, resource, options.language, path_to_file)
-    elif options.resource or options.language:
-        resource = options.resource
-        lang = options.language
-
-        if len(args) != 1:
-            parser.error("Please specify a file")
-
-        # Calculate relative path
-        path_to_file = relpath(args[0], path_to_tx)
-
-        try:
-            _go_to_dir(path_to_tx)
-        except UnInitializedError, e:
-            utils.logger.error(e)
-            return
-
-        if not utils.valid_slug(resource):
-            parser.error("Invalid resource slug. The format is <project_slug>"\
-                ".<resource_slug> and the valid characters include [_-\w].")
-        _set_translation(path_to_tx, resource, lang, path_to_file)
-
-    _set_mode(options.resource, options.mode, path_to_tx)
-    _set_type(options.resource, options.i18n_type, path_to_tx)
-    _set_minimum_perc(options.resource, options.minimum_perc, path_to_tx)
-
-    logger.info("Done.")
-    return
-
-
-def _auto_local(path_to_tx, resource, source_language, expression, execute=False,
-                source_file=None, regex=False):
-    """Auto configure local project."""
-    # The path everything will be relative to
-    curpath = os.path.abspath(os.curdir)
-
-    # Force expr to be a valid regex expr (escaped) but keep <lang> intact
-    expr_re = utils.regex_from_filefilter(expression, curpath)
-    expr_rec = re.compile(expr_re)
-
-    if not execute:
-        logger.info("Only printing the commands which will be run if the "
-                  "--execute switch is specified.")
-
-    # First, let's construct a dictionary of all matching files.
-    # Note: Only the last matching file of a language will be stored.
-    translation_files = {}
-    for root, dirs, files in os.walk(curpath):
-        for f in files:
-            f_path = os.path.abspath(os.path.join(root, f))
-            match = expr_rec.match(f_path)
-            if match:
-                lang = match.group(1)
-                f_path = os.path.abspath(f_path)
-                if lang == source_language and not source_file:
-                    source_file = f_path
-                else:
-                    translation_files[lang] = f_path
-
-    if not source_file:
-        raise Exception("Could not find a source language file. Please run"
-            " set --source manually and then re-run this command or provide"
-            " the source file with the -s flag.")
-    if execute:
-        logger.info("Updating source for resource %s ( %s -> %s )." % (resource,
-            source_language, relpath(source_file, path_to_tx)))
-        _set_source_file(path_to_tx, resource, source_language,
-            relpath(source_file, path_to_tx))
-    else:
-        logger.info('\ntx set --source -r %(res)s -l %(lang)s %(file)s\n' % {
-            'res': resource,
-            'lang': source_language,
-            'file': relpath(source_file, curpath)})
-
-    prj = project.Project(path_to_tx)
-    root_dir = os.path.abspath(path_to_tx)
-
-    if execute:
-        try:
-            prj.config.get("%s" % resource, "source_file")
-        except ConfigParser.NoSectionError:
-            raise Exception("No resource with slug \"%s\" was found.\nRun 'tx set --auto"
-                "-local -r %s \"expression\"' to do the initial configuration." % resource)
-
-    # Now let's handle the translation files.
-    if execute:
-        logger.info("Updating file expression for resource %s ( %s )." % (resource,
-            expression))
-        # Eval file_filter relative to root dir
-        file_filter = relpath(os.path.join(curpath, expression),
-            path_to_tx)
-        prj.config.set("%s" % resource, "file_filter", file_filter)
-    else:
-        for (lang, f_path) in sorted(translation_files.items()):
-            logger.info('tx set -r %(res)s -l %(lang)s %(file)s' % {
-                'res': resource,
-                'lang': lang,
-                'file': relpath(f_path, curpath)})
-
-    if execute:
-        prj.save()
-
-
-def _auto_remote(path_to_tx, url):
-    """
-    Initialize a remote release/project/resource to the current directory.
-    """
-    logger.info("Auto configuring local project from remote URL...")
-
-    type, vars = utils.parse_tx_url(url)
-    prj = project.Project(path_to_tx)
-    username, password = prj.getset_host_credentials(vars['hostname'])
-
-    if type == 'project':
-        logger.info("Getting details for project %s" % vars['project'])
-        proj_info = utils.get_details('project_details',
-            username, password,
-            hostname = vars['hostname'], project = vars['project'])
-        resources = [ '.'.join([vars['project'], r['slug']]) for r in proj_info['resources'] ]
-        logger.info("%s resources found. Configuring..." % len(resources))
-    elif type == 'release':
-        logger.info("Getting details for release %s" % vars['release'])
-        rel_info = utils.get_details('release_details',
-            username, password, hostname = vars['hostname'],
-            project = vars['project'], release = vars['release'])
-        resources = []
-        for r in rel_info['resources']:
-            if r.has_key('project'):
-                resources.append('.'.join([r['project']['slug'], r['slug']]))
-            else:
-                resources.append('.'.join([vars['project'], r['slug']]))
-        logger.info("%s resources found. Configuring..." % len(resources))
-    elif type == 'resource':
-        logger.info("Getting details for resource %s" % vars['resource'])
-        resources = [ '.'.join([vars['project'], vars['resource']]) ]
-    else:
-        raise("Url '%s' is not recognized." % url)
-
-    for resource in resources:
-        logger.info("Configuring resource %s." % resource)
-        proj, res = resource.split('.')
-        res_info = utils.get_details('resource_details',
-             username, password, hostname = vars['hostname'],
-             project = proj, resource=res)
-        try:
-            source_lang = res_info['source_language_code']
-            i18n_type = res_info['i18n_type']
-        except KeyError:
-            raise Exception("Remote server seems to be running an unsupported version"
-                " of Transifex. Either update your server software of fallback"
-                " to a previous version of transifex-client.")
-        prj.set_remote_resource(
-            resource=resource,
-            host = vars['hostname'],
-            source_lang = source_lang,
-            i18n_type = i18n_type)
-
-    prj.save()
-
-
-def cmd_push(argv, path_to_tx):
-    "Push local files to remote server"
-    parser = push_parser()
-    (options, args) = parser.parse_args(argv)
-    force_creation = options.force_creation
-    languages = parse_csv_option(options.languages)
-    resources = parse_csv_option(options.resources)
-    skip = options.skip_errors
-    prj = project.Project(path_to_tx)
-    if not (options.push_source or options.push_translations):
-        parser.error("You need to specify at least one of the -s|--source,"
-            " -t|--translations flags with the push command.")
-
-    prj.push(
-        force=force_creation, resources=resources, languages=languages,
-        skip=skip, source=options.push_source,
-        translations=options.push_translations,
-        no_interactive=options.no_interactive
-    )
-    logger.info("Done.")
-
-
-def cmd_pull(argv, path_to_tx):
-    "Pull files from remote server to local repository"
-    parser = pull_parser()
-    (options, args) = parser.parse_args(argv)
-    if options.fetchall and options.languages:
-        parser.error("You can't user a language filter along with the"\
-            " -a|--all option")
-    languages = parse_csv_option(options.languages)
-    resources = parse_csv_option(options.resources)
-    skip = options.skip_errors
-    minimum_perc = options.minimum_perc or None
-
-    try:
-        _go_to_dir(path_to_tx)
-    except UnInitializedError, e:
-        utils.logger.error(e)
-        return
-
-    # instantiate the project.Project
-    prj = project.Project(path_to_tx)
-    prj.pull(
-        languages=languages, resources=resources, overwrite=options.overwrite,
-        fetchall=options.fetchall, fetchsource=options.fetchsource,
-        force=options.force, skip=skip, minimum_perc=minimum_perc,
-        mode=options.mode
-    )
-    logger.info("Done.")
-
-
-def _set_source_file(path_to_tx, resource, lang, path_to_file):
-    """Reusable method to set source file."""
-    proj, res = resource.split('.')
-    if not proj or not res:
-        raise Exception("\"%s.%s\" is not a valid resource identifier. It should"
-            " be in the following format project_slug.resource_slug." %
-            (proj, res))
-    if not lang:
-        raise Exception("You haven't specified a source language.")
-
-    try:
-        _go_to_dir(path_to_tx)
-    except UnInitializedError, e:
-        utils.logger.error(e)
-        return
-
-    if not os.path.exists(path_to_file):
-        raise Exception("tx: File ( %s ) does not exist." %
-            os.path.join(path_to_tx, path_to_file))
-
-    # instantiate the project.Project
-    prj = project.Project(path_to_tx)
-    root_dir = os.path.abspath(path_to_tx)
-
-    if root_dir not in os.path.normpath(os.path.abspath(path_to_file)):
-        raise Exception("File must be under the project root directory.")
-
-    logger.info("Setting source file for resource %s.%s ( %s -> %s )." % (
-        proj, res, lang, path_to_file))
-
-    path_to_file = relpath(path_to_file, root_dir)
-
-    prj = project.Project(path_to_tx)
-
-    # FIXME: Check also if the path to source file already exists.
-    try:
-        try:
-            prj.config.get("%s.%s" % (proj, res), "source_file")
-        except ConfigParser.NoSectionError:
-            prj.config.add_section("%s.%s" % (proj, res))
-        except ConfigParser.NoOptionError:
-            pass
-    finally:
-        prj.config.set("%s.%s" % (proj, res), "source_file",
-           path_to_file)
-        prj.config.set("%s.%s" % (proj, res), "source_lang",
-            lang)
-
-    prj.save()
-
-
-def _set_translation(path_to_tx, resource, lang, path_to_file):
-    """Reusable method to set translation file."""
-
-    proj, res = resource.split('.')
-    if not project or not resource:
-        raise Exception("\"%s\" is not a valid resource identifier. It should"
-            " be in the following format project_slug.resource_slug." %
-            resource)
-
-    try:
-        _go_to_dir(path_to_tx)
-    except UnInitializedError, e:
-        utils.logger.error(e)
-        return
-
-    # Warn the user if the file doesn't exist
-    if not os.path.exists(path_to_file):
-        logger.info("Warning: File '%s' doesn't exist." % path_to_file)
-
-    # instantiate the project.Project
-    prj = project.Project(path_to_tx)
-    root_dir = os.path.abspath(path_to_tx)
-
-    if root_dir not in os.path.normpath(os.path.abspath(path_to_file)):
-        raise Exception("File must be under the project root directory.")
-
-    if lang ==  prj.config.get("%s.%s" % (proj, res), "source_lang"):
-        raise Exception("tx: You cannot set translation file for the source language."
-            " Source languages contain the strings which will be translated!")
-
-    logger.info("Updating translations for resource %s ( %s -> %s )." % (resource,
-        lang, path_to_file))
-    path_to_file = relpath(path_to_file, root_dir)
-    prj.config.set("%s.%s" % (proj, res), "trans.%s" % lang,
-        path_to_file)
-
-    prj.save()
-
-
-def cmd_status(argv, path_to_tx):
-    "Print status of current project"
-    parser = status_parser()
-    (options, args) = parser.parse_args(argv)
-    resources = parse_csv_option(options.resources)
-    prj = project.Project(path_to_tx)
-    resources = prj.get_chosen_resources(resources)
-    resources_num = len(resources)
-    for idx, res in enumerate(resources):
-        p, r = res.split('.')
-        logger.info("%s -> %s (%s of %s)" % (p, r, idx + 1, resources_num))
-        logger.info("Translation Files:")
-        slang = prj.get_resource_option(res, 'source_lang')
-        sfile = prj.get_resource_option(res, 'source_file') or "N/A"
-        lang_map = prj.get_resource_lang_mapping(res)
-        logger.info(" - %s: %s (%s)" % (utils.color_text(slang, "RED"),
-            sfile, utils.color_text("source", "YELLOW")))
-        files = prj.get_resource_files(res)
-        fkeys = files.keys()
-        fkeys.sort()
-        for lang in fkeys:
-            local_lang = lang
-            if lang in lang_map.values():
-                local_lang = lang_map.flip[lang]
-            logger.info(" - %s: %s" % (utils.color_text(local_lang, "RED"),
-                files[lang]))
-        logger.info("")
-
-
-def cmd_help(argv, path_to_tx):
-    """List all available commands"""
-    parser = help_parser()
-    (options, args) = parser.parse_args(argv)
-    if len(args) > 1:
-        parser.error("Multiple arguments received. Exiting...")
-
-    # Get all commands
-    fns = utils.discover_commands()
-
-    # Print help for specific command
-    if len(args) == 1:
-        try:
-            fns[argv[0]](['--help'], path_to_tx)
-        except KeyError:
-            utils.logger.error("Command %s not found" % argv[0])
-    # or print summary of all commands
-
-    # the code below will only be executed if the KeyError exception is thrown
-    # becuase in all other cases the function called with --help will exit
-    # instead of return here
-    keys = fns.keys()
-    keys.sort()
-
-    logger.info("Transifex command line client.\n")
-    logger.info("Available commands are:")
-    for key in keys:
-        logger.info("  %-15s\t%s" % (key, fns[key].func_doc))
-    logger.info("\nFor more information run %s command --help" % sys.argv[0])
-
-
-def cmd_delete(argv, path_to_tx):
-    "Delete an accessible resource or translation in a remote server."
-    parser = delete_parser()
-    (options, args) = parser.parse_args(argv)
-    languages = parse_csv_option(options.languages)
-    resources = parse_csv_option(options.resources)
-    skip = options.skip_errors
-    force = options.force_delete
-    prj = project.Project(path_to_tx)
-    prj.delete(resources, languages, skip, force)
-    logger.info("Done.")
-
-
-def _go_to_dir(path):
-    """Change the current working directory to the directory specified as
-    argument.
-
-    Args:
-        path: The path to chdor to.
-    Raises:
-        UnInitializedError, in case the directory has not been initialized.
-    """
-    if path is None:
-        raise UnInitializedError(
-            "Directory has not been initialzied. "
-            "Did you forget to run 'tx init' first?"
-        )
-    os.chdir(path)
-
-
-def _set_minimum_perc(resource, value, path_to_tx):
-    """Set the minimum percentage in the .tx/config file."""
-    args = (resource, 'minimum_perc', value, path_to_tx, 'set_min_perc')
-    _set_project_option(*args)
-
-
-def _set_mode(resource, value, path_to_tx):
-    """Set the mode in the .tx/config file."""
-    args = (resource, 'mode', value, path_to_tx, 'set_default_mode')
-    _set_project_option(*args)
-
-
-def _set_type(resource, value, path_to_tx):
-    """Set the i18n type in the .tx/config file."""
-    args = (resource, 'type', value, path_to_tx, 'set_i18n_type')
-    _set_project_option(*args)
-
-
-def _set_project_option(resource, name, value, path_to_tx, func_name):
-    """Save the option to the project config file."""
-    if value is None:
-        return
-    if not resource:
-        logger.debug("Setting the %s for all resources." % name)
-        resources = []
-    else:
-        logger.debug("Setting the %s for resource %s." % (name, resource))
-        resources = [resource, ]
-    prj = project.Project(path_to_tx)
-    getattr(prj, func_name)(resources, value)
-    prj.save()
diff --git a/third_party/transifex-client/txclib/config.py b/third_party/transifex-client/txclib/config.py
deleted file mode 100644 (file)
index a9d055f..0000000
+++ /dev/null
@@ -1,115 +0,0 @@
-import ConfigParser
-
-
-class OrderedRawConfigParser( ConfigParser.RawConfigParser ):
-    """
-    Overload standard Class ConfigParser.RawConfigParser
-    """
-    def write(self, fp):
-        """Write an .ini-format representation of the configuration state."""
-        if self._defaults:
-            fp.write("[%s]\n" % DEFAULTSECT)
-            for key in sorted( self._defaults ):
-                fp.write( "%s = %s\n" % (key, str( self._defaults[ key ]
-                    ).replace('\n', '\n\t')) )
-            fp.write("\n")
-        for section in self._sections:
-            fp.write("[%s]\n" % section)
-            for key in sorted( self._sections[section] ):
-                if key != "__name__":
-                    fp.write("%s = %s\n" %
-                        (key, str( self._sections[section][ key ]
-                        ).replace('\n', '\n\t')))
-            fp.write("\n")
-
-    optionxform = str
-
-
-_NOTFOUND = object()
-
-
-class Flipdict(dict):
-    """An injective (one-to-one) python dict.  Ensures that each key maps
-    to a unique value, and each value maps back to that same key.
-
-    Code mostly taken from here:
-    http://code.activestate.com/recipes/576968-flipdict-python-dict-that-also-maintains-a-one-to-/
-    """
-
-    def __init__(self, *args, **kw):
-        self._flip = dict.__new__(self.__class__)
-        setattr(self._flip, "_flip", self)
-        for key, val in dict(*args, **kw).iteritems():
-            self[key] = val
-
-    @property
-    def flip(self):
-        """The inverse mapping."""
-        return self._flip
-
-    def __repr__(self):
-        return "%s(%r)" % (self.__class__.__name__, dict(self))
-
-    __str__ = __repr__
-
-    def copy(self):
-        return self.__class__(self)
-
-    @classmethod
-    def fromkeys(cls, keys, value=None):
-        return cls(dict.fromkeys(keys, value))
-
-    def __setitem__(self, key, val):
-        k = self._flip.get(val, _NOTFOUND)
-        if not (k is _NOTFOUND or k==key):
-            raise KeyError('(key,val) would erase mapping for value %r' % val)
-
-        v = self.get(key, _NOTFOUND)
-        if v is not _NOTFOUND:
-            dict.__delitem__(self._flip, v)
-
-        dict.__setitem__(self,       key, val)
-        dict.__setitem__(self._flip, val, key)
-
-    def setdefault(self, key, default = None):
-        # Copied from python's UserDict.DictMixin code.
-        try:
-            return self[key]
-        except KeyError:
-            self[key] = default
-            return default
-
-    def update(self, other = None, **kwargs):
-        # Copied from python's UserDict.DictMixin code.
-        # Make progressively weaker assumptions about "other"
-        if other is None:
-            pass
-        elif hasattr(other, 'iteritems'):  # iteritems saves memory and lookups
-            for k, v in other.iteritems():
-                self[k] = v
-        elif hasattr(other, 'keys'):
-            for k in other.keys():
-                self[k] = other[k]
-        else:
-            for k, v in other:
-                self[k] = v
-        if kwargs:
-            self.update(kwargs)
-
-    def __delitem__(self, key):
-        val = dict.pop(self, key)
-        dict.__delitem__(self._flip, val)
-
-    def pop(self, key, *args):
-        val = dict.pop(self, key, *args)
-        dict.__delitem__(self._flip, val)
-        return val
-
-    def popitem(self):
-        key, val = dict.popitem(self)
-        dict.__delitem__(self._flip, val)
-        return key, val
-
-    def clear(self):
-        dict.clear(self)
-        dict.clear(self._flip)
diff --git a/third_party/transifex-client/txclib/exceptions.py b/third_party/transifex-client/txclib/exceptions.py
deleted file mode 100644 (file)
index 8766a01..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-# -*- coding: utf-8 -*-
-
-"""
-Exception classes for the tx client.
-"""
-
-
-class UnInitializedError(Exception):
-    """The project directory has not been initialized."""
-
-
-class UnknownCommandError(Exception):
-    """The provided command is not supported."""
diff --git a/third_party/transifex-client/txclib/http_utils.py b/third_party/transifex-client/txclib/http_utils.py
deleted file mode 100644 (file)
index 3243149..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-# -*- coding: utf-8 -*-
-
-"""
-HTTP-related utility functions.
-"""
-
-from __future__ import with_statement
-import gzip
-try:
-    import cStringIO as StringIO
-except ImportError:
-    import StringIO
-
-
-def _gzip_decode(gzip_data):
-    """
-    Unzip gzipped data and return them.
-
-    :param gzip_data: Gzipped data.
-    :returns: The actual data.
-    """
-    try:
-        gzip_data = StringIO.StringIO(gzip_data)
-        gzip_file = gzip.GzipFile(fileobj=gzip_data)
-        data = gzip_file.read()
-        return data
-    finally:
-        gzip_data.close()
-
-
-def http_response(response):
-    """
-    Return the response of a HTTP request.
-
-    If the response has been gzipped, gunzip it first.
-
-    :param response: The raw response of a HTTP request.
-    :returns: A response suitable to be used by clients.
-    """
-    metadata = response.info()
-    data = response.read()
-    response.close()
-    if metadata.get('content-encoding') == 'gzip':
-        return _gzip_decode(data)
-    else:
-        return data
diff --git a/third_party/transifex-client/txclib/log.py b/third_party/transifex-client/txclib/log.py
deleted file mode 100644 (file)
index 9baf322..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-# -*- coding: utf-8 -*-
-
-"""
-Add logging capabilities to tx-client.
-"""
-
-import sys
-import logging
-
-_logger = logging.getLogger('txclib')
-_logger.setLevel(logging.INFO)
-
-_formatter = logging.Formatter('%(message)s')
-
-_error_handler = logging.StreamHandler(sys.stderr)
-_error_handler.setLevel(logging.ERROR)
-_error_handler.setFormatter(_formatter)
-_logger.addHandler(_error_handler)
-
-_msg_handler = logging.StreamHandler(sys.stdout)
-_msg_handler.setLevel(logging.DEBUG)
-_msg_handler.setFormatter(_formatter)
-_msg_filter = logging.Filter()
-_msg_filter.filter = lambda r: r.levelno < logging.ERROR
-_msg_handler.addFilter(_msg_filter)
-_logger.addHandler(_msg_handler)
-
-logger = _logger
-
-
-def set_log_level(level):
-    """Set the level for the logger.
-
-    Args:
-        level: A string among DEBUG, INFO, WARNING, ERROR, CRITICAL.
-    """
-    logger.setLevel(getattr(logging, level))
diff --git a/third_party/transifex-client/txclib/parsers.py b/third_party/transifex-client/txclib/parsers.py
deleted file mode 100644 (file)
index fd3237d..0000000
+++ /dev/null
@@ -1,241 +0,0 @@
-# -*- coding: utf-8 -*-
-
-from optparse import OptionParser, OptionGroup
-
-
-class EpilogParser(OptionParser):
-    def format_epilog(self, formatter):
-        return self.epilog
-
-
-def delete_parser():
-    """Return the command-line parser for the delete command."""
-    usage = "usage: %prog [tx_options] delete OPTION [OPTIONS]"
-    description = (
-        "This command deletes translations for a resource in the remote server."
-    )
-    epilog = (
-        "\nExamples:\n"
-        " To delete a translation:\n  "
-        "$ tx delete -r project.resource -l <lang_code>\n\n"
-        " To delete a resource:\n  $ tx delete -r project.resource\n"
-    )
-    parser = EpilogParser(usage=usage, description=description, epilog=epilog)
-    parser.add_option(
-        "-r", "--resource", action="store", dest="resources", default=None,
-        help="Specify the resource you want to delete (defaults to all)"
-    )
-    parser.add_option(
-        "-l","--language", action="store", dest="languages",
-        default=None, help="Specify the translation you want to delete"
-    )
-    parser.add_option(
-        "--skip", action="store_true", dest="skip_errors", default=False,
-        help="Don't stop on errors."
-    )
-    parser.add_option(
-        "-f","--force", action="store_true", dest="force_delete",
-        default=False, help="Delete an entity forcefully."
-    )
-    return parser
-
-
-def help_parser():
-    """Return the command-line parser for the help command."""
-    usage="usage: %prog help command"
-    description="Lists all available commands in the transifex command"\
-        " client. If a command is specified, the help page of the specific"\
-        " command is displayed instead."
-
-    parser = OptionParser(usage=usage, description=description)
-    return parser
-
-
-def init_parser():
-    """Return the command-line parser for the init command."""
-    usage="usage: %prog [tx_options] init <path>"
-    description="This command initializes a new project for use with"\
-        " transifex. It is recommended to execute this command in the"\
-        " top level directory of your project so that you can include"\
-        " all files under it in transifex. If no path is provided, the"\
-        " current working dir will be used."
-    parser = OptionParser(usage=usage, description=description)
-    parser.add_option("--host", action="store", dest="host",
-        default=None, help="Specify a default Transifex host.")
-    parser.add_option("--user", action="store", dest="user",
-        default=None, help="Specify username for Transifex server.")
-    parser.add_option("--pass", action="store", dest="password",
-        default=None, help="Specify password for Transifex server.")
-    return parser
-
-
-def pull_parser():
-    """Return the command-line parser for the pull command."""
-    usage="usage: %prog [tx_options] pull [options]"
-    description="This command pulls all outstanding changes from the remote"\
-        " Transifex server to the local repository. By default, only the"\
-        " files that are watched by Transifex will be updated but if you"\
-        " want to fetch the translations for new languages as well, use the"\
-        " -a|--all option. (Note: new translations are saved in the .tx folder"\
-        " and require the user to manually rename them and add then in "\
-        " transifex using the set_translation command)."
-    parser = OptionParser(usage=usage,description=description)
-    parser.add_option("-l","--language", action="store", dest="languages",
-        default=[], help="Specify which translations you want to pull"
-        " (defaults to all)")
-    parser.add_option("-r","--resource", action="store", dest="resources",
-        default=[], help="Specify the resource for which you want to pull"
-        " the translations (defaults to all)")
-    parser.add_option("-a","--all", action="store_true", dest="fetchall",
-        default=False, help="Fetch all translation files from server (even new"
-        " ones)")
-    parser.add_option("-s","--source", action="store_true", dest="fetchsource",
-        default=False, help="Force the fetching of the source file (default:"
-        " False)")
-    parser.add_option("-f","--force", action="store_true", dest="force",
-        default=False, help="Force download of translations files.")
-    parser.add_option("--skip", action="store_true", dest="skip_errors",
-        default=False, help="Don't stop on errors. Useful when pushing many"
-        " files concurrently.")
-    parser.add_option("--disable-overwrite", action="store_false",
-        dest="overwrite", default=True,
-        help="By default transifex will fetch new translations files and"\
-            " replace existing ones. Use this flag if you want to disable"\
-            " this feature")
-    parser.add_option("--minimum-perc", action="store", type="int",
-        dest="minimum_perc", default=0,
-        help="Specify the minimum acceptable percentage of a translation "
-             "in order to download it.")
-    parser.add_option(
-        "--mode", action="store", dest="mode", help=(
-            "Specify the mode of the translation file to pull (e.g. "
-            "'reviewed'). See http://bit.ly/txcmod1 for available values."
-        )
-    )
-    return parser
-
-
-def push_parser():
-    """Return the command-line parser for the push command."""
-    usage="usage: %prog [tx_options] push [options]"
-    description="This command pushes all local files that have been added to"\
-        " Transifex to the remote server. All new translations are merged"\
-        " with existing ones and if a language doesn't exists then it gets"\
-        " created. If you want to push the source file as well (either"\
-        " because this is your first time running the client or because"\
-        " you just have updated with new entries), use the -f|--force option."\
-        " By default, this command will push all files which are watched by"\
-        " Transifex but you can filter this per resource or/and language."
-    parser = OptionParser(usage=usage, description=description)
-    parser.add_option("-l","--language", action="store", dest="languages",
-        default=None, help="Specify which translations you want to push"
-        " (defaults to all)")
-    parser.add_option("-r","--resource", action="store", dest="resources",
-        default=None, help="Specify the resource for which you want to push"
-        " the translations (defaults to all)")
-    parser.add_option("-f","--force", action="store_true", dest="force_creation",
-        default=False, help="Push source files without checking modification"
-        " times.")
-    parser.add_option("--skip", action="store_true", dest="skip_errors",
-        default=False, help="Don't stop on errors. Useful when pushing many"
-        " files concurrently.")
-    parser.add_option("-s", "--source", action="store_true", dest="push_source",
-        default=False, help="Push the source file to the server.")
-
-    parser.add_option("-t", "--translations", action="store_true", dest="push_translations",
-        default=False, help="Push the translation files to the server")
-    parser.add_option("--no-interactive", action="store_true", dest="no_interactive",
-        default=False, help="Don't require user input when forcing a push.")
-    return parser
-
-
-def set_parser():
-    """Return the command-line parser for the set command."""
-    usage="usage: %prog [tx_options] set [options] [args]"
-    description="This command can be used to create a mapping between files"\
-        " and projects either using local files or using files from a remote"\
-        " Transifex server."
-    epilog="\nExamples:\n"\
-        " To set the source file:\n  $ tx set -r project.resource --source -l en <file>\n\n"\
-        " To set a single translation file:\n  $ tx set -r project.resource -l de <file>\n\n"\
-        " To automatically detect and assign the source files and translations:\n"\
-        "  $ tx set --auto-local -r project.resource 'expr' --source-lang en\n\n"\
-        " To set a specific file as a source and auto detect translations:\n"\
-        "  $ tx set --auto-local -r project.resource 'expr' --source-lang en"\
-        " --source-file <file>\n\n"\
-        " To set a remote release/resource/project:\n"\
-        "  $ tx set --auto-remote <transifex-url>\n"
-    parser = EpilogParser(usage=usage, description=description, epilog=epilog)
-    parser.add_option("--auto-local", action="store_true", dest="local",
-        default=False, help="Used when auto configuring local project.")
-    parser.add_option("--auto-remote", action="store_true", dest="remote",
-        default=False, help="Used when adding remote files from Transifex"
-        " server.")
-    parser.add_option("-r","--resource", action="store", dest="resource",
-        default=None, help="Specify the slug of the resource that you're"
-            " setting up (This must be in the following format:"
-            " `project_slug.resource_slug`).")
-    parser.add_option(
-        "--source", action="store_true", dest="is_source", default=False,
-        help=(
-            "Specify that the given file is a source file "
-            "[doesn't work with the --auto-* commands]."
-        )
-    )
-    parser.add_option("-l","--language", action="store", dest="language",
-        default=None, help="Specify which translations you want to pull"
-        " [doesn't work with the --auto-* commands].")
-    parser.add_option("-t", "--type", action="store", dest="i18n_type",
-        help=(
-            "Specify the i18n type of the resource(s). This is only needed, if "
-            "the resource(s) does not exist yet in Transifex. For a list of "
-            "available i18n types, see "
-            "http://help.transifex.com/features/formats.html"
-        )
-    )
-    parser.add_option("--minimum-perc", action="store", dest="minimum_perc",
-        help=(
-            "Specify the minimum acceptable percentage of a translation "
-            "in order to download it."
-        )
-    )
-    parser.add_option(
-        "--mode", action="store", dest="mode", help=(
-            "Specify the mode of the translation file to pull (e.g. "
-            "'reviewed'). See http://help.transifex.com/features/client/"
-            "index.html#defining-the-mode-of-the-translated-file for the"
-            "available values."
-        )
-    )
-    group = OptionGroup(parser, "Extended options", "These options can only be"
-        " used with the --auto-local command.")
-    group.add_option("-s","--source-language", action="store",
-        dest="source_language",
-        default=None, help="Specify the source language of a resource"
-        " [requires --auto-local].")
-    group.add_option("-f","--source-file", action="store", dest="source_file",
-        default=None, help="Specify the source file of a resource [requires"
-        " --auto-local].")
-    group.add_option("--execute", action="store_true", dest="execute",
-        default=False, help="Execute commands [requires --auto-local].")
-    parser.add_option_group(group)
-    return parser
-
-
-def status_parser():
-    """Return the command-line parser for the status command."""
-    usage="usage: %prog [tx_options] status [options]"
-    description="Prints the status of the current project by reading the"\
-        " data in the configuration file."
-    parser = OptionParser(usage=usage,description=description)
-    parser.add_option("-r","--resource", action="store", dest="resources",
-        default=[], help="Specify resources")
-    return parser
-
-
-def parse_csv_option(option):
-    """Return a list out of the comma-separated option or an empty list."""
-    if option:
-        return option.split(',')
-    else:
-        return []
diff --git a/third_party/transifex-client/txclib/processors.py b/third_party/transifex-client/txclib/processors.py
deleted file mode 100644 (file)
index dc3a73f..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-# -*- coding: utf-8 -*-
-
-"""
-Module for API-related calls.
-"""
-
-import urlparse
-
-
-def hostname_tld_migration(hostname):
-    """
-    Migrate transifex.net to transifex.com.
-
-    :param hostname: The hostname to migrate (if needed).
-    :returns: A hostname with the transifex.com domain (if needed).
-    """
-    parts = urlparse.urlparse(hostname)
-    if parts.hostname.endswith('transifex.net'):
-        hostname = hostname.replace('transifex.net', 'transifex.com', 1)
-    return hostname
-
-
-def hostname_ssl_migration(hostname):
-    """
-    Migrate Transifex hostnames to use HTTPS.
-
-    :param hostname: The hostname to migrate (if needed).
-    :returns: A https hostname (if needed).
-    """
-    parts = urlparse.urlparse(hostname)
-    is_transifex = (
-        parts.hostname[-14:-3] == '.transifex.' or
-        parts.hostname == 'transifex.net' or
-        parts.hostname == 'transifex.com'
-    )
-    is_https = parts.scheme == 'https'
-    if is_transifex and not is_https:
-        if not parts.scheme:
-            hostname = 'https:' + hostname
-        else:
-            hostname = hostname.replace(parts.scheme, 'https', 1)
-    return hostname
-
-
-def visit_hostname(hostname):
-    """
-    Have a chance to visit a hostname before actually using it.
-
-    :param hostname: The original hostname.
-    :returns: The hostname with the necessary changes.
-    """
-    for processor in [hostname_ssl_migration, hostname_tld_migration, ]:
-        hostname = processor(hostname)
-    return hostname
diff --git a/third_party/transifex-client/txclib/project.py b/third_party/transifex-client/txclib/project.py
deleted file mode 100644 (file)
index 88bb46b..0000000
+++ /dev/null
@@ -1,1233 +0,0 @@
-# -*- coding: utf-8 -*-
-import base64
-import copy
-import getpass
-import os
-import re
-import fnmatch
-import urllib2
-import datetime, time
-import ConfigParser
-
-from txclib.web import *
-from txclib.utils import *
-from txclib.urls import API_URLS
-from txclib.config import OrderedRawConfigParser, Flipdict
-from txclib.log import logger
-from txclib.http_utils import http_response
-from txclib.processors import visit_hostname
-
-
-class ProjectNotInit(Exception):
-    pass
-
-
-class Project(object):
-    """
-    Represents an association between the local and remote project instances.
-    """
-
-    def __init__(self, path_to_tx=None, init=True):
-        """
-        Initialize the Project attributes.
-        """
-        if init:
-            self._init(path_to_tx)
-
-    def _init(self, path_to_tx=None):
-        instructions = "Run 'tx init' to initialize your project first!"
-        try:
-            self.root = self._get_tx_dir_path(path_to_tx)
-            self.config_file = self._get_config_file_path(self.root)
-            self.config = self._read_config_file(self.config_file)
-            self.txrc_file = self._get_transifex_file()
-            self.txrc = self._get_transifex_config(self.txrc_file)
-        except ProjectNotInit, e:
-            logger.error('\n'.join([unicode(e), instructions]))
-            raise
-
-    def _get_config_file_path(self, root_path):
-        """Check the .tx/config file exists."""
-        config_file = os.path.join(root_path, ".tx", "config")
-        logger.debug("Config file is %s" % config_file)
-        if not os.path.exists(config_file):
-            msg = "Cannot find the config file (.tx/config)!"
-            raise ProjectNotInit(msg)
-        return config_file
-
-    def _get_tx_dir_path(self, path_to_tx):
-        """Check the .tx directory exists."""
-        root_path = path_to_tx or find_dot_tx()
-        logger.debug("Path to tx is %s." % root_path)
-        if not root_path:
-            msg = "Cannot find any .tx directory!"
-            raise ProjectNotInit(msg)
-        return root_path
-
-    def _read_config_file(self, config_file):
-        """Parse the config file and return its contents."""
-        config = OrderedRawConfigParser()
-        try:
-            config.read(config_file)
-        except Exception, err:
-            msg = "Cannot open/parse .tx/config file: %s" % err
-            raise ProjectNotInit(msg)
-        return config
-
-    def _get_transifex_config(self, txrc_file):
-        """Read the configuration from the .transifexrc file."""
-        txrc = OrderedRawConfigParser()
-        try:
-            txrc.read(txrc_file)
-        except Exception, e:
-            msg = "Cannot read global configuration file: %s" % e
-            raise ProjectNotInit(msg)
-        self._migrate_txrc_file(txrc)
-        return txrc
-
-    def _migrate_txrc_file(self, txrc):
-        """Migrate the txrc file, if needed."""
-        for section in txrc.sections():
-            orig_hostname = txrc.get(section, 'hostname')
-            hostname = visit_hostname(orig_hostname)
-            if hostname != orig_hostname:
-                msg = "Hostname %s should be changed to %s."
-                logger.info(msg % (orig_hostname, hostname))
-                if (sys.stdin.isatty() and sys.stdout.isatty() and
-                    confirm('Change it now? ', default=True)):
-                    txrc.set(section, 'hostname', hostname)
-                    msg = 'Hostname changed'
-                    logger.info(msg)
-                else:
-                    hostname = orig_hostname
-            self._save_txrc_file(txrc)
-        return txrc
-
-    def _get_transifex_file(self, directory=None):
-        """Fetch the path of the .transifexrc file.
-
-        It is in the home directory ofthe user by default.
-        """
-        if directory is None:
-            directory = os.path.expanduser('~')
-        txrc_file = os.path.join(directory, ".transifexrc")
-        logger.debug(".transifexrc file is at %s" % directory)
-        if not os.path.exists(txrc_file):
-            msg = "No authentication data found."
-            logger.info(msg)
-            mask = os.umask(077)
-            open(txrc_file, 'w').close()
-            os.umask(mask)
-        return txrc_file
-
-    def validate_config(self):
-        """
-        To ensure the json structure is correctly formed.
-        """
-        pass
-
-    def getset_host_credentials(self, host, user=None, password=None):
-        """
-        Read .transifexrc and report user,pass for a specific host else ask the
-        user for input.
-        """
-        try:
-            username = self.txrc.get(host, 'username')
-            passwd = self.txrc.get(host, 'password')
-        except (ConfigParser.NoOptionError, ConfigParser.NoSectionError):
-            logger.info("No entry found for host %s. Creating..." % host)
-            username = user or raw_input("Please enter your transifex username: ")
-            while (not username):
-                username = raw_input("Please enter your transifex username: ")
-            passwd = password
-            while (not passwd):
-                passwd = getpass.getpass()
-
-            logger.info("Updating %s file..." % self.txrc_file)
-            self.txrc.add_section(host)
-            self.txrc.set(host, 'username', username)
-            self.txrc.set(host, 'password', passwd)
-            self.txrc.set(host, 'token', '')
-            self.txrc.set(host, 'hostname', host)
-
-        return username, passwd
-
-    def set_remote_resource(self, resource, source_lang, i18n_type, host,
-            file_filter="translations<sep>%(proj)s.%(res)s<sep><lang>.%(extension)s"):
-        """
-        Method to handle the add/conf of a remote resource.
-        """
-        if not self.config.has_section(resource):
-            self.config.add_section(resource)
-
-        p_slug, r_slug = resource.split('.')
-        file_filter = file_filter.replace("<sep>", r"%s" % os.path.sep)
-        self.url_info = {
-            'host': host,
-            'project': p_slug,
-            'resource': r_slug
-        }
-        extension = self._extension_for(i18n_type)[1:]
-
-        self.config.set(resource, 'source_lang', source_lang)
-        self.config.set(
-            resource, 'file_filter',
-            file_filter % {'proj': p_slug, 'res': r_slug, 'extension': extension}
-        )
-        if host != self.config.get('main', 'host'):
-            self.config.set(resource, 'host', host)
-
-    def get_resource_host(self, resource):
-        """
-        Returns the host that the resource is configured to use. If there is no
-        such option we return the default one
-        """
-        if self.config.has_option(resource, 'host'):
-            return self.config.get(resource, 'host')
-        return self.config.get('main', 'host')
-
-    def get_resource_lang_mapping(self, resource):
-        """
-        Get language mappings for a specific resource.
-        """
-        lang_map = Flipdict()
-        try:
-            args = self.config.get("main", "lang_map")
-            for arg in args.replace(' ', '').split(','):
-                k,v = arg.split(":")
-                lang_map.update({k:v})
-        except ConfigParser.NoOptionError:
-            pass
-        except (ValueError, KeyError):
-            raise Exception("Your lang map configuration is not correct.")
-
-        if self.config.has_section(resource):
-            res_lang_map = Flipdict()
-            try:
-                args = self.config.get(resource, "lang_map")
-                for arg in args.replace(' ', '').split(','):
-                    k,v = arg.split(":")
-                    res_lang_map.update({k:v})
-            except ConfigParser.NoOptionError:
-                pass
-            except (ValueError, KeyError):
-                raise Exception("Your lang map configuration is not correct.")
-
-        # merge the lang maps and return result
-        lang_map.update(res_lang_map)
-
-        return lang_map
-
-
-    def get_resource_files(self, resource):
-        """
-        Get a dict for all files assigned to a resource. First we calculate the
-        files matching the file expression and then we apply all translation
-        excpetions. The resulting dict will be in this format:
-
-        { 'en': 'path/foo/en/bar.po', 'de': 'path/foo/de/bar.po', 'es': 'path/exceptions/es.po'}
-
-        NOTE: All paths are relative to the root of the project
-        """
-        tr_files = {}
-        if self.config.has_section(resource):
-            try:
-                file_filter = self.config.get(resource, "file_filter")
-            except ConfigParser.NoOptionError:
-                file_filter = "$^"
-            source_lang = self.config.get(resource, "source_lang")
-            source_file = self.get_resource_option(resource, 'source_file') or None
-            expr_re = regex_from_filefilter(file_filter, self.root)
-            expr_rec = re.compile(expr_re)
-            for root, dirs, files in os.walk(self.root):
-                for f in files:
-                    f_path = os.path.abspath(os.path.join(root, f))
-                    match = expr_rec.match(f_path)
-                    if match:
-                        lang = match.group(1)
-                        if lang != source_lang:
-                            f_path = relpath(f_path, self.root)
-                            if f_path != source_file:
-                                tr_files.update({lang: f_path})
-
-            for (name, value) in self.config.items(resource):
-                if name.startswith("trans."):
-                    lang = name.split('.')[1]
-                    # delete language which has same file
-                    if value in tr_files.values():
-                        keys = []
-                        for k, v in tr_files.iteritems():
-                            if v == value:
-                                keys.append(k)
-                        if len(keys) == 1:
-                            del tr_files[keys[0]]
-                        else:
-                            raise Exception("Your configuration seems wrong."\
-                                " You have multiple languages pointing to"\
-                                " the same file.")
-                    # Add language with correct file
-                    tr_files.update({lang:value})
-
-            return tr_files
-
-        return None
-
-    def get_resource_option(self, resource, option):
-        """
-        Return the requested option for a specific resource
-
-        If there is no such option, we return None
-        """
-
-        if self.config.has_section(resource):
-            if self.config.has_option(resource, option):
-                return self.config.get(resource, option)
-        return None
-
-    def get_resource_list(self, project=None):
-        """
-        Parse config file and return tuples with the following format
-
-        [ (project_slug, resource_slug), (..., ...)]
-        """
-
-        resource_list= []
-        for r in self.config.sections():
-            if r == 'main':
-                continue
-            p_slug, r_slug = r.split('.', 1)
-            if project and p_slug != project:
-                continue
-            resource_list.append(r)
-
-        return resource_list
-
-    def save(self):
-        """
-        Store the config dictionary in the .tx/config file of the project.
-        """
-        self._save_tx_config()
-        self._save_txrc_file()
-
-    def _save_tx_config(self, config=None):
-        """Save the local config file."""
-        if config is None:
-            config = self.config
-        fh = open(self.config_file,"w")
-        config.write(fh)
-        fh.close()
-
-    def _save_txrc_file(self, txrc=None):
-        """Save the .transifexrc file."""
-        if txrc is None:
-            txrc = self.txrc
-        mask = os.umask(077)
-        fh = open(self.txrc_file, 'w')
-        txrc.write(fh)
-        fh.close()
-        os.umask(mask)
-
-    def get_full_path(self, relpath):
-        if relpath[0] == "/":
-            return relpath
-        else:
-            return os.path.join(self.root, relpath)
-
-    def pull(self, languages=[], resources=[], overwrite=True, fetchall=False,
-        fetchsource=False, force=False, skip=False, minimum_perc=0, mode=None):
-        """Pull all translations file from transifex server."""
-        self.minimum_perc = minimum_perc
-        resource_list = self.get_chosen_resources(resources)
-
-        if mode == 'reviewed':
-            url = 'pull_reviewed_file'
-        elif mode == 'translator':
-            url = 'pull_translator_file'
-        elif mode == 'developer':
-            url = 'pull_developer_file'
-        else:
-            url = 'pull_file'
-
-        for resource in resource_list:
-            logger.debug("Handling resource %s" % resource)
-            self.resource = resource
-            project_slug, resource_slug = resource.split('.')
-            files = self.get_resource_files(resource)
-            slang = self.get_resource_option(resource, 'source_lang')
-            sfile = self.get_resource_option(resource, 'source_file')
-            lang_map = self.get_resource_lang_mapping(resource)
-            host = self.get_resource_host(resource)
-            logger.debug("Language mapping is: %s" % lang_map)
-            if mode is None:
-                mode = self._get_option(resource, 'mode')
-            self.url_info = {
-                'host': host,
-                'project': project_slug,
-                'resource': resource_slug
-            }
-            logger.debug("URL data are: %s" % self.url_info)
-
-            stats = self._get_stats_for_resource()
-
-
-            try:
-                file_filter = self.config.get(resource, 'file_filter')
-            except ConfigParser.NoOptionError:
-                file_filter = None
-
-            # Pull source file
-            pull_languages = set([])
-            new_translations = set([])
-
-            if fetchall:
-                new_translations = self._new_translations_to_add(
-                    files, slang, lang_map, stats, force
-                )
-                if new_translations:
-                    msg = "New translations found for the following languages: %s"
-                    logger.info(msg % ', '.join(new_translations))
-
-            existing, new = self._languages_to_pull(
-                languages, files, lang_map, stats, force
-            )
-            pull_languages |= existing
-            new_translations |= new
-            logger.debug("Adding to new translations: %s" % new)
-
-            if fetchsource:
-                if sfile and slang not in pull_languages:
-                    pull_languages.add(slang)
-                elif slang not in new_translations:
-                    new_translations.add(slang)
-
-            if pull_languages:
-                logger.debug("Pulling languages for: %s" % pull_languages)
-                msg = "Pulling translations for resource %s (source: %s)"
-                logger.info(msg % (resource, sfile))
-
-            for lang in pull_languages:
-                local_lang = lang
-                if lang in lang_map.values():
-                    remote_lang = lang_map.flip[lang]
-                else:
-                    remote_lang = lang
-                if languages and lang not in pull_languages:
-                    logger.debug("Skipping language %s" % lang)
-                    continue
-                if lang != slang:
-                    local_file = files.get(lang, None) or files[lang_map[lang]]
-                else:
-                    local_file = sfile
-                logger.debug("Using file %s" % local_file)
-
-                kwargs = {
-                    'lang': remote_lang,
-                    'stats': stats,
-                    'local_file': local_file,
-                    'force': force,
-                    'mode': mode,
-                }
-                if not self._should_update_translation(**kwargs):
-                    msg = "Skipping '%s' translation (file: %s)."
-                    logger.info(
-                        msg % (color_text(remote_lang, "RED"), local_file)
-                    )
-                    continue
-
-                if not overwrite:
-                    local_file = ("%s.new" % local_file)
-                logger.warning(
-                    " -> %s: %s" % (color_text(remote_lang, "RED"), local_file)
-                )
-                try:
-                    r = self.do_url_request(url, language=remote_lang)
-                except Exception,e:
-                    if not skip:
-                        raise e
-                    else:
-                        logger.error(e)
-                        continue
-                base_dir = os.path.split(local_file)[0]
-                mkdir_p(base_dir)
-                fd = open(local_file, 'wb')
-                fd.write(r)
-                fd.close()
-
-            if new_translations:
-                msg = "Pulling new translations for resource %s (source: %s)"
-                logger.info(msg % (resource, sfile))
-                for lang in new_translations:
-                    if lang in lang_map.keys():
-                        local_lang = lang_map[lang]
-                    else:
-                        local_lang = lang
-                    remote_lang = lang
-                    if file_filter:
-                        local_file = relpath(os.path.join(self.root,
-                            file_filter.replace('<lang>', local_lang)), os.curdir)
-                    else:
-                        trans_dir = os.path.join(self.root, ".tx", resource)
-                        if not os.path.exists(trans_dir):
-                            os.mkdir(trans_dir)
-                        local_file = relpath(os.path.join(trans_dir, '%s_translation' %
-                            local_lang, os.curdir))
-
-                    if lang != slang:
-                        satisfies_min = self._satisfies_min_translated(
-                            stats[remote_lang], mode
-                        )
-                        if not satisfies_min:
-                            msg = "Skipping language %s due to used options."
-                            logger.info(msg % lang)
-                            continue
-                    logger.warning(
-                        " -> %s: %s" % (color_text(remote_lang, "RED"), local_file)
-                    )
-                    r = self.do_url_request(url, language=remote_lang)
-
-                    base_dir = os.path.split(local_file)[0]
-                    mkdir_p(base_dir)
-                    fd = open(local_file, 'wb')
-                    fd.write(r)
-                    fd.close()
-
-    def push(self, source=False, translations=False, force=False, resources=[], languages=[],
-        skip=False, no_interactive=False):
-        """
-        Push all the resources
-        """
-        resource_list = self.get_chosen_resources(resources)
-        self.skip = skip
-        self.force = force
-        for resource in resource_list:
-            push_languages = []
-            project_slug, resource_slug = resource.split('.')
-            files = self.get_resource_files(resource)
-            slang = self.get_resource_option(resource, 'source_lang')
-            sfile = self.get_resource_option(resource, 'source_file')
-            lang_map = self.get_resource_lang_mapping(resource)
-            host = self.get_resource_host(resource)
-            logger.debug("Language mapping is: %s" % lang_map)
-            logger.debug("Using host %s" % host)
-            self.url_info = {
-                'host': host,
-                'project': project_slug,
-                'resource': resource_slug
-            }
-
-            logger.info("Pushing translations for resource %s:" % resource)
-
-            stats = self._get_stats_for_resource()
-
-            if force and not no_interactive:
-                answer = raw_input("Warning: By using --force, the uploaded"
-                    " files will overwrite remote translations, even if they"
-                    " are newer than your uploaded files.\nAre you sure you"
-                    " want to continue? [y/N] ")
-
-                if not answer in ["", 'Y', 'y', "yes", 'YES']:
-                    return
-
-            if source:
-                if sfile == None:
-                    logger.error("You don't seem to have a proper source file"
-                        " mapping for resource %s. Try without the --source"
-                        " option or set a source file first and then try again." %
-                        resource)
-                    continue
-                # Push source file
-                try:
-                    logger.warning("Pushing source file (%s)" % sfile)
-                    if not self._resource_exists(stats):
-                        logger.info("Resource does not exist.  Creating...")
-                        fileinfo = "%s;%s" % (resource_slug, slang)
-                        filename = self.get_full_path(sfile)
-                        self._create_resource(resource, project_slug, fileinfo, filename)
-                    self.do_url_request(
-                        'push_source', multipart=True, method="PUT",
-                        files=[(
-                                "%s;%s" % (resource_slug, slang)
-                                , self.get_full_path(sfile)
-                        )],
-                    )
-                except Exception, e:
-                    if not skip:
-                        raise
-                    else:
-                        logger.error(e)
-            else:
-                try:
-                    self.do_url_request('resource_details')
-                except Exception, e:
-                    code = getattr(e, 'code', None)
-                    if code == 404:
-                        msg = "Resource %s doesn't exist on the server."
-                        logger.error(msg % resource)
-                        continue
-
-            if translations:
-                # Check if given language codes exist
-                if not languages:
-                    push_languages = files.keys()
-                else:
-                    push_languages = []
-                    f_langs = files.keys()
-                    for l in languages:
-                        if l in lang_map.keys():
-                            l = lang_map[l]
-                        push_languages.append(l)
-                        if l not in f_langs:
-                            msg = "Warning: No mapping found for language code '%s'."
-                            logger.error(msg % color_text(l,"RED"))
-                logger.debug("Languages to push are %s" % push_languages)
-
-                # Push translation files one by one
-                for lang in push_languages:
-                    local_lang = lang
-                    if lang in lang_map.values():
-                        remote_lang = lang_map.flip[lang]
-                    else:
-                        remote_lang = lang
-
-                    local_file = files[local_lang]
-
-                    kwargs = {
-                        'lang': remote_lang,
-                        'stats': stats,
-                        'local_file': local_file,
-                        'force': force,
-                    }
-                    if not self._should_push_translation(**kwargs):
-                        msg = "Skipping '%s' translation (file: %s)."
-                        logger.info(msg % (color_text(lang, "RED"), local_file))
-                        continue
-
-                    msg = "Pushing '%s' translations (file: %s)"
-                    logger.warning(
-                         msg % (color_text(remote_lang, "RED"), local_file)
-                    )
-                    try:
-                        self.do_url_request(
-                            'push_translation', multipart=True, method='PUT',
-                            files=[(
-                                    "%s;%s" % (resource_slug, remote_lang),
-                                    self.get_full_path(local_file)
-                            )], language=remote_lang
-                        )
-                        logger.debug("Translation %s pushed." % remote_lang)
-                    except Exception, e:
-                        if not skip:
-                            raise e
-                        else:
-                            logger.error(e)
-
-    def delete(self, resources=[], languages=[], skip=False, force=False):
-        """Delete translations."""
-        resource_list = self.get_chosen_resources(resources)
-        self.skip = skip
-        self.force = force
-
-        if not languages:
-            delete_func = self._delete_resource
-        else:
-            delete_func = self._delete_translations
-
-        for resource in resource_list:
-            project_slug, resource_slug = resource.split('.')
-            host = self.get_resource_host(resource)
-            self.url_info = {
-                'host': host,
-                'project': project_slug,
-                'resource': resource_slug
-            }
-            logger.debug("URL data are: %s" % self.url_info)
-            project_details = parse_json(
-                self.do_url_request('project_details', project=self)
-            )
-            teams = project_details['teams']
-            stats = self._get_stats_for_resource()
-            delete_func(project_details, resource, stats, languages)
-
-    def _delete_resource(self, project_details, resource, stats, *args):
-        """Delete a resource from Transifex."""
-        project_slug, resource_slug = resource.split('.')
-        project_resource_slugs = [
-            r['slug'] for r in project_details['resources']
-        ]
-        logger.info("Deleting resource %s:" % resource)
-        if resource_slug not in project_resource_slugs:
-            if not self.skip:
-                msg = "Skipping: %s : Resource does not exist."
-                logger.info(msg % resource)
-            return
-        if not self.force:
-            slang = self.get_resource_option(resource, 'source_lang')
-            for language in stats:
-                if language == slang:
-                    continue
-                if int(stats[language]['translated_entities']) > 0:
-                    msg = (
-                        "Skipping: %s : Unable to delete resource because it "
-                        "has a not empty %s translation.\nPlease use -f or "
-                        "--force option to delete this resource."
-                    )
-                    logger.info(msg % (resource, language))
-                    return
-        try:
-            self.do_url_request('delete_resource', method="DELETE")
-            self.config.remove_section(resource)
-            self.save()
-            msg = "Deleted resource %s of project %s."
-            logger.info(msg % (resource_slug, project_slug))
-        except Exception, e:
-            msg = "Unable to delete resource %s of project %s."
-            logger.error(msg % (resource_slug, project_slug))
-            if not self.skip:
-                raise
-
-    def _delete_translations(self, project_details, resource, stats, languages):
-        """Delete the specified translations for the specified resource."""
-        logger.info("Deleting translations from resource %s:" % resource)
-        for language in languages:
-            self._delete_translation(project_details, resource, stats, language)
-
-    def _delete_translation(self, project_details, resource, stats, language):
-        """Delete a specific translation from the specified resource."""
-        project_slug, resource_slug = resource.split('.')
-        if language not in stats:
-            if not self.skip:
-                msg = "Skipping %s: Translation does not exist."
-                logger.warning(msg % (language))
-            return
-        if not self.force:
-            teams = project_details['teams']
-            if language in teams:
-                msg = (
-                    "Skipping %s: Unable to delete translation because it is "
-                    "associated with a team.\nPlease use -f or --force option "
-                    "to delete this translation."
-                )
-                logger.warning(msg % language)
-                return
-            if int(stats[language]['translated_entities']) > 0:
-                msg = (
-                    "Skipping %s: Unable to delete translation because it "
-                    "is not empty.\nPlease use -f or --force option to delete "
-                    "this translation."
-                )
-                logger.warning(msg % language)
-                return
-        try:
-            self.do_url_request(
-                'delete_translation', language=language, method="DELETE"
-            )
-            msg = "Deleted language %s from resource %s of project %s."
-            logger.info(msg % (language, resource_slug, project_slug))
-        except Exception, e:
-            msg = "Unable to delete translation %s"
-            logger.error(msg % language)
-            if not self.skip:
-                raise
-
-    def do_url_request(self, api_call, multipart=False, data=None,
-                       files=[], encoding=None, method="GET", **kwargs):
-        """
-        Issues a url request.
-        """
-        # Read the credentials from the config file (.transifexrc)
-        host = self.url_info['host']
-        try:
-            username = self.txrc.get(host, 'username')
-            passwd = self.txrc.get(host, 'password')
-            token = self.txrc.get(host, 'token')
-            hostname = self.txrc.get(host, 'hostname')
-        except ConfigParser.NoSectionError:
-            raise Exception("No user credentials found for host %s. Edit"
-                " ~/.transifexrc and add the appropriate info in there." %
-                host)
-
-        # Create the Url
-        kwargs['hostname'] = hostname
-        kwargs.update(self.url_info)
-        url = (API_URLS[api_call] % kwargs).encode('UTF-8')
-        logger.debug(url)
-
-        opener = None
-        headers = None
-        req = None
-
-        if multipart:
-            opener = urllib2.build_opener(MultipartPostHandler)
-            for info,filename in files:
-                data = { "resource" : info.split(';')[0],
-                         "language" : info.split(';')[1],
-                         "uploaded_file" :  open(filename,'rb') }
-
-            urllib2.install_opener(opener)
-            req = RequestWithMethod(url=url, data=data, method=method)
-        else:
-            req = RequestWithMethod(url=url, data=data, method=method)
-            if encoding:
-                req.add_header("Content-Type",encoding)
-
-        base64string = base64.encodestring('%s:%s' % (username, passwd))[:-1]
-        authheader = "Basic %s" % base64string
-        req.add_header("Authorization", authheader)
-        req.add_header("Accept-Encoding", "gzip,deflate")
-        req.add_header("User-Agent", user_agent_identifier())
-
-        try:
-            response = urllib2.urlopen(req, timeout=300)
-            return http_response(response)
-        except urllib2.HTTPError, e:
-            if e.code in [401, 403, 404]:
-                raise e
-            elif 200 <= e.code < 300:
-                return None
-            else:
-                # For other requests, we should print the message as well
-                raise Exception("Remote server replied: %s" % e.read())
-        except urllib2.URLError, e:
-            error = e.args[0]
-            raise Exception("Remote server replied: %s" % error[1])
-
-
-    def _should_update_translation(self, lang, stats, local_file, force=False,
-                                   mode=None):
-        """Whether a translation should be udpated from Transifex.
-
-        We use the following criteria for that:
-        - If user requested to force the download.
-        - If language exists in Transifex.
-        - If the local file is older than the Transifex's file.
-        - If the user requested a x% completion.
-
-        Args:
-            lang: The language code to check.
-            stats: The (global) statistics object.
-            local_file: The local translation file.
-            force: A boolean flag.
-            mode: The mode for the translation.
-        Returns:
-            True or False.
-        """
-        return self._should_download(lang, stats, local_file, force)
-
-    def _should_add_translation(self, lang, stats, force=False, mode=None):
-        """Whether a translation should be added from Transifex.
-
-        We use the following criteria for that:
-        - If user requested to force the download.
-        - If language exists in Transifex.
-        - If the user requested a x% completion.
-
-        Args:
-            lang: The language code to check.
-            stats: The (global) statistics object.
-            force: A boolean flag.
-            mode: The mode for the translation.
-        Returns:
-            True or False.
-        """
-        return self._should_download(lang, stats, None, force)
-
-    def _should_download(self, lang, stats, local_file=None, force=False,
-                         mode=None):
-        """Return whether a translation should be downloaded.
-
-        If local_file is None, skip the timestamps check (the file does
-        not exist locally).
-        """
-        try:
-            lang_stats = stats[lang]
-        except KeyError, e:
-            logger.debug("No lang %s in statistics" % lang)
-            return False
-
-        satisfies_min = self._satisfies_min_translated(lang_stats, mode)
-        if not satisfies_min:
-            return False
-
-        if force:
-            logger.debug("Downloading translation due to -f")
-            return True
-
-        if local_file is not None:
-            remote_update = self._extract_updated(lang_stats)
-            if not self._remote_is_newer(remote_update, local_file):
-                logger.debug("Local is newer than remote for lang %s" % lang)
-                return False
-        return True
-
-    def _should_push_translation(self, lang, stats, local_file, force=False):
-        """Return whether a local translation file should be
-        pushed to Trasnifex.
-
-        We use the following criteria for that:
-        - If user requested to force the upload.
-        - If language exists in Transifex.
-        - If local file is younger than the remote file.
-
-        Args:
-            lang: The language code to check.
-            stats: The (global) statistics object.
-            local_file: The local translation file.
-            force: A boolean flag.
-        Returns:
-            True or False.
-        """
-        if force:
-            logger.debug("Push translation due to -f.")
-            return True
-        try:
-            lang_stats = stats[lang]
-        except KeyError, e:
-            logger.debug("Language %s does not exist in Transifex." % lang)
-            return True
-        if local_file is not None:
-            remote_update = self._extract_updated(lang_stats)
-            if self._remote_is_newer(remote_update, local_file):
-                msg  = "Remote translation is newer than local file for lang %s"
-                logger.debug(msg % lang)
-                return False
-        return True
-
-    def _generate_timestamp(self, update_datetime):
-        """Generate a UNIX timestamp from the argument.
-
-        Args:
-            update_datetime: The datetime in the format used by Transifex.
-        Returns:
-            A float, representing the timestamp that corresponds to the
-            argument.
-        """
-        time_format = "%Y-%m-%d %H:%M:%S"
-        return time.mktime(
-            datetime.datetime(
-                *time.strptime(update_datetime, time_format)[0:5]
-            ).utctimetuple()
-        )
-
-    def _get_time_of_local_file(self, path):
-        """Get the modified time of the path_.
-
-        Args:
-            path: The path we want the mtime for.
-        Returns:
-            The time as a timestamp or None, if the file does not exist
-        """
-        if not os.path.exists(path):
-            return None
-        return time.mktime(time.gmtime(os.path.getmtime(path)))
-
-    def _satisfies_min_translated(self, stats, mode=None):
-        """Check whether a translation fulfills the filter used for
-        minimum translated percentage.
-
-        Args:
-            perc: The current translation percentage.
-        Returns:
-            True or False
-        """
-        cur = self._extract_completed(stats, mode)
-        option_name = 'minimum_perc'
-        if self.minimum_perc is not None:
-            minimum_percent = self.minimum_perc
-        else:
-            global_minimum = int(
-                self.get_resource_option('main', option_name) or 0
-            )
-            resource_minimum = int(
-                self.get_resource_option(
-                    self.resource, option_name
-                ) or global_minimum
-            )
-            minimum_percent = resource_minimum
-        return cur >= minimum_percent
-
-    def _remote_is_newer(self, remote_updated, local_file):
-        """Check whether the remote translation is newer that the local file.
-
-        Args:
-            remote_updated: The date and time the translation was last
-                updated remotely.
-            local_file: The local file.
-        Returns:
-            True or False.
-        """
-        if remote_updated is None:
-            logger.debug("No remote time")
-            return False
-        remote_time = self._generate_timestamp(remote_updated)
-        local_time = self._get_time_of_local_file(
-            self.get_full_path(local_file)
-        )
-        logger.debug(
-            "Remote time is %s and local %s" % (remote_time, local_time)
-        )
-        if local_time is not None and remote_time < local_time:
-            return False
-        return True
-
-    @classmethod
-    def _extract_completed(cls, stats, mode=None):
-        """Extract the information for the translated percentage from the stats.
-
-        Args:
-            stats: The stats object for a language as returned by Transifex.
-            mode: The mode of translations requested.
-        Returns:
-            The percentage of translation as integer.
-        """
-        if mode == 'reviewed':
-            key = 'reviewed_percentage'
-        else:
-            key = 'completed'
-        try:
-            return int(stats[key][:-1])
-        except KeyError, e:
-            return 0
-
-    @classmethod
-    def _extract_updated(cls, stats):
-        """Extract the  information for the last update of a translation.
-
-        Args:
-            stats: The stats object for a language as returned by Transifex.
-        Returns:
-            The last update field.
-        """
-        try:
-            return stats['last_update']
-        except KeyError, e:
-            return None
-
-    def _new_translations_to_add(self, files, slang, lang_map,
-                                 stats, force=False):
-        """Return a list of translations which are new to the
-        local installation.
-        """
-        new_translations = []
-        timestamp = time.time()
-        langs = stats.keys()
-        logger.debug("Available languages are: %s" % langs)
-
-        for lang in langs:
-            lang_exists = lang in files.keys()
-            lang_is_source = lang == slang
-            mapped_lang_exists = (
-                lang in lang_map and lang_map[lang] in files.keys()
-            )
-            if lang_exists or lang_is_source or mapped_lang_exists:
-                continue
-            if self._should_add_translation(lang, stats, force):
-                new_translations.append(lang)
-        return set(new_translations)
-
-    def _get_stats_for_resource(self):
-        """Get the statistics information for a resource."""
-        try:
-            r = self.do_url_request('resource_stats')
-            logger.debug("Statistics response is %s" % r)
-            stats = parse_json(r)
-        except urllib2.HTTPError, e:
-            logger.debug("Resource not found: %s" % e)
-            stats = {}
-        except Exception,e:
-            logger.debug("Network error: %s" % e)
-            raise
-        return stats
-
-    def get_chosen_resources(self, resources):
-        """Get the resources the user selected.
-
-        Support wildcards in the resources specified by the user.
-
-        Args:
-            resources: A list of resources as specified in command-line or
-                an empty list.
-        Returns:
-            A list of resources.
-        """
-        configured_resources = self.get_resource_list()
-        if not resources:
-            return configured_resources
-
-        selected_resources = []
-        for resource in resources:
-            found = False
-            for full_name in configured_resources:
-                if fnmatch.fnmatch(full_name, resource):
-                    selected_resources.append(full_name)
-                    found = True
-            if not found:
-                msg = "Specified resource '%s' does not exist."
-                raise Exception(msg % resource)
-        logger.debug("Operating on resources: %s" % selected_resources)
-        return selected_resources
-
-    def _languages_to_pull(self, languages, files, lang_map, stats, force):
-        """Get a set of langauges to pull.
-
-        Args:
-            languages: A list of languages the user selected in cmd.
-            files: A dictionary of current local translation files.
-        Returns:
-            A tuple of a set of existing languages and new translations.
-        """
-        if not languages:
-            pull_languages = set([])
-            pull_languages |= set(files.keys())
-            mapped_files = []
-            for lang in pull_languages:
-                if lang in lang_map.flip:
-                    mapped_files.append(lang_map.flip[lang])
-            pull_languages -= set(lang_map.flip.keys())
-            pull_languages |= set(mapped_files)
-            return (pull_languages, set([]))
-        else:
-            pull_languages = []
-            new_translations = []
-            f_langs = files.keys()
-            for l in languages:
-                if l not in f_langs and not (l in lang_map and lang_map[l] in f_langs):
-                    if self._should_add_translation(l, stats, force):
-                        new_translations.append(l)
-                else:
-                    if l in lang_map.keys():
-                        l = lang_map[l]
-                    pull_languages.append(l)
-            return (set(pull_languages), set(new_translations))
-
-    def _extension_for(self, i18n_type):
-        """Return the extension used for the specified type."""
-        try:
-            res = parse_json(self.do_url_request('formats'))
-            return res[i18n_type]['file-extensions'].split(',')[0]
-        except Exception,e:
-            logger.error(e)
-            return ''
-
-    def _resource_exists(self, stats):
-        """Check if resource exists.
-
-        Args:
-            stats: The statistics dict as returned by Tx.
-        Returns:
-            True, if the resource exists in the server.
-        """
-        return bool(stats)
-
-    def _create_resource(self, resource, pslug, fileinfo, filename, **kwargs):
-        """Create a resource.
-
-        Args:
-            resource: The full resource name.
-            pslug: The slug of the project.
-            fileinfo: The information of the resource.
-            filename: The name of the file.
-        Raises:
-            URLError, in case of a problem.
-        """
-        multipart = True
-        method = "POST"
-        api_call = 'create_resource'
-
-        host = self.url_info['host']
-        try:
-            username = self.txrc.get(host, 'username')
-            passwd = self.txrc.get(host, 'password')
-            token = self.txrc.get(host, 'token')
-            hostname = self.txrc.get(host, 'hostname')
-        except ConfigParser.NoSectionError:
-            raise Exception("No user credentials found for host %s. Edit"
-                " ~/.transifexrc and add the appropriate info in there." %
-                host)
-
-        # Create the Url
-        kwargs['hostname'] = hostname
-        kwargs.update(self.url_info)
-        kwargs['project'] = pslug
-        url = (API_URLS[api_call] % kwargs).encode('UTF-8')
-
-        opener = None
-        headers = None
-        req = None
-
-        i18n_type = self._get_option(resource, 'type')
-        if i18n_type is None:
-            logger.error(
-                "Please define the resource type in .tx/config (eg. type = PO)."
-                " More info: http://bit.ly/txcl-rt"
-            )
-
-        opener = urllib2.build_opener(MultipartPostHandler)
-        data = {
-            "slug": fileinfo.split(';')[0],
-            "name": fileinfo.split(';')[0],
-            "uploaded_file":  open(filename,'rb'),
-            "i18n_type": i18n_type
-        }
-        urllib2.install_opener(opener)
-        req = RequestWithMethod(url=url, data=data, method=method)
-
-        base64string = base64.encodestring('%s:%s' % (username, passwd))[:-1]
-        authheader = "Basic %s" % base64string
-        req.add_header("Authorization", authheader)
-
-        try:
-            fh = urllib2.urlopen(req)
-        except urllib2.HTTPError, e:
-            if e.code in [401, 403, 404]:
-                raise e
-            else:
-                # For other requests, we should print the message as well
-                raise Exception("Remote server replied: %s" % e.read())
-        except urllib2.URLError, e:
-            error = e.args[0]
-            raise Exception("Remote server replied: %s" % error[1])
-
-        raw = fh.read()
-        fh.close()
-        return raw
-
-    def _get_option(self, resource, option):
-        """Get the value for the option in the config file.
-
-        If the option is not in the resource section, look for it in
-        the project.
-
-        Args:
-            resource: The resource name.
-            option: The option the value of which we are interested in.
-        Returns:
-            The option value or None, if it does not exist.
-        """
-        value = self.get_resource_option(resource, option)
-        if value is None:
-            if self.config.has_option('main', option):
-                return self.config.get('main', option)
-        return value
-
-    def set_i18n_type(self, resources, i18n_type):
-        """Set the type for the specified resources."""
-        self._set_resource_option(resources, key='type', value=i18n_type)
-
-    def set_min_perc(self, resources, perc):
-        """Set the minimum percentage for the resources."""
-        self._set_resource_option(resources, key='minimum_perc', value=perc)
-
-    def set_default_mode(self, resources, mode):
-        """Set the default mode for the specified resources."""
-        self._set_resource_option(resources, key='mode', value=mode)
-
-    def _set_resource_option(self, resources, key, value):
-        """Set options in the config file.
-
-        If resources is empty. set the option globally.
-        """
-        if not resources:
-            self.config.set('main', key, value)
-            return
-        for r in resources:
-            self.config.set(r, key, value)
diff --git a/third_party/transifex-client/txclib/urls.py b/third_party/transifex-client/txclib/urls.py
deleted file mode 100644 (file)
index 0bb74fd..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-# These are the Transifex API urls
-
-API_URLS = {
-    'get_resources': '%(hostname)s/api/2/project/%(project)s/resources/',
-    'project_details': '%(hostname)s/api/2/project/%(project)s/?details',
-    'resource_details': '%(hostname)s/api/2/project/%(project)s/resource/%(resource)s/',
-    'release_details': '%(hostname)s/api/2/project/%(project)s/release/%(release)s/',
-    'pull_file': '%(hostname)s/api/2/project/%(project)s/resource/%(resource)s/translation/%(language)s/?file',
-    'pull_reviewed_file': '%(hostname)s/api/2/project/%(project)s/resource/%(resource)s/translation/%(language)s/?file&mode=reviewed',
-    'pull_translator_file': '%(hostname)s/api/2/project/%(project)s/resource/%(resource)s/translation/%(language)s/?file&mode=translated',
-    'pull_developer_file': '%(hostname)s/api/2/project/%(project)s/resource/%(resource)s/translation/%(language)s/?file&mode=default',
-    'resource_stats': '%(hostname)s/api/2/project/%(project)s/resource/%(resource)s/stats/',
-    'create_resource': '%(hostname)s/api/2/project/%(project)s/resources/',
-    'push_source': '%(hostname)s/api/2/project/%(project)s/resource/%(resource)s/content/',
-    'push_translation': '%(hostname)s/api/2/project/%(project)s/resource/%(resource)s/translation/%(language)s/',
-    'delete_translation': '%(hostname)s/api/2/project/%(project)s/resource/%(resource)s/translation/%(language)s/',
-    'formats': '%(hostname)s/api/2/formats/',
-    'delete_resource': '%(hostname)s/api/2/project/%(project)s/resource/%(resource)s/',
-}
-
-
diff --git a/third_party/transifex-client/txclib/utils.py b/third_party/transifex-client/txclib/utils.py
deleted file mode 100644 (file)
index 318bee9..0000000
+++ /dev/null
@@ -1,259 +0,0 @@
-import os, sys, re, errno
-try:
-    from json import loads as parse_json, dumps as compile_json
-except ImportError:
-    from simplejson import loads as parse_json, dumps as compile_json
-import urllib2 # This should go and instead use do_url_request everywhere
-
-from urls import API_URLS
-from txclib.log import logger
-from txclib.exceptions import UnknownCommandError
-
-
-def find_dot_tx(path = os.path.curdir, previous = None):
-    """
-    Return the path where .tx folder is found.
-
-    The 'path' should be a DIRECTORY.
-    This process is functioning recursively from the current directory to each
-    one of the ancestors dirs.
-    """
-    path = os.path.abspath(path)
-    if path == previous:
-        return None
-    joined = os.path.join(path, ".tx")
-    if os.path.isdir(joined):
-        return path
-    else:
-        return find_dot_tx(os.path.dirname(path), path)
-
-
-#################################################
-# Parse file filter expressions and create regex
-
-def regex_from_filefilter(file_filter, root_path = os.path.curdir):
-    """
-    Create proper regex from <lang> expression
-    """
-    # Force expr to be a valid regex expr (escaped) but keep <lang> intact
-    expr_re = re.escape(os.path.join(root_path, file_filter))
-    expr_re = expr_re.replace("\\<lang\\>", '<lang>').replace(
-        '<lang>', '([^%(sep)s]+)' % { 'sep': re.escape(os.path.sep)})
-
-    return "^%s$" % expr_re
-
-
-TX_URLS = {
-    'resource': '(?P<hostname>https?://(\w|\.|:|-)+)/projects/p/(?P<project>(\w|-)+)/resource/(?P<resource>(\w|-)+)/?$',
-    'release': '(?P<hostname>https?://(\w|\.|:|-)+)/projects/p/(?P<project>(\w|-)+)/r/(?P<release>(\w|-)+)/?$',
-    'project': '(?P<hostname>https?://(\w|\.|:|-)+)/projects/p/(?P<project>(\w|-)+)/?$',
-}
-
-
-def parse_tx_url(url):
-    """
-    Try to match given url to any of the valid url patterns specified in
-    TX_URLS. If not match is found, we raise exception
-    """
-    for type in TX_URLS.keys():
-        pattern = TX_URLS[type]
-        m = re.match(pattern, url)
-        if m:
-            return type, m.groupdict()
-
-    raise Exception("tx: Malformed url given. Please refer to our docs: http://bit.ly/txautor")
-
-
-def get_details(api_call, username, password, *args, **kwargs):
-    """
-    Get the tx project info through the API.
-
-    This function can also be used to check the existence of a project.
-    """
-    import base64
-    url = (API_URLS[api_call] % (kwargs)).encode('UTF-8')
-
-    req = urllib2.Request(url=url)
-    base64string = base64.encodestring('%s:%s' % (username, password))[:-1]
-    authheader = "Basic %s" % base64string
-    req.add_header("Authorization", authheader)
-
-    try:
-        fh = urllib2.urlopen(req)
-        raw = fh.read()
-        fh.close()
-        remote_project = parse_json(raw)
-    except urllib2.HTTPError, e:
-        if e.code in [401, 403, 404]:
-            raise e
-        else:
-            # For other requests, we should print the message as well
-            raise Exception("Remote server replied: %s" % e.read())
-    except urllib2.URLError, e:
-        error = e.args[0]
-        raise Exception("Remote server replied: %s" % error[1])
-
-    return remote_project
-
-
-def valid_slug(slug):
-    """
-    Check if a slug contains only valid characters.
-
-    Valid chars include [-_\w]
-    """
-    try:
-        a, b = slug.split('.')
-    except ValueError:
-        return False
-    else:
-        if re.match("^[A-Za-z0-9_-]*$", a) and re.match("^[A-Za-z0-9_-]*$", b):
-            return True
-        return False
-
-
-def discover_commands():
-    """
-    Inspect commands.py and find all available commands
-    """
-    import inspect
-    from txclib import commands
-
-    command_table = {}
-    fns = inspect.getmembers(commands, inspect.isfunction)
-
-    for name, fn in fns:
-        if name.startswith("cmd_"):
-            command_table.update({
-                name.split("cmd_")[1]:fn
-            })
-
-    return command_table
-
-
-def exec_command(command, *args, **kwargs):
-    """
-    Execute given command
-    """
-    commands = discover_commands()
-    try:
-        cmd_fn = commands[command]
-    except KeyError:
-        raise UnknownCommandError
-    cmd_fn(*args,**kwargs)
-
-
-def mkdir_p(path):
-    try:
-        if path:
-            os.makedirs(path)
-    except OSError, exc: # Python >2.5
-        if exc.errno == errno.EEXIST:
-            pass
-        else:
-            raise
-
-
-def confirm(prompt='Continue?', default=True):
-    """
-    Prompt the user for a Yes/No answer.
-
-    Args:
-        prompt: The text displayed to the user ([Y/n] will be appended)
-        default: If the default value will be yes or no
-    """
-    valid_yes = ['Y', 'y', 'Yes', 'yes', ]
-    valid_no = ['N', 'n', 'No', 'no', ]
-    if default:
-        prompt = prompt + '[Y/n]'
-        valid_yes.append('')
-    else:
-        prompt = prompt + '[y/N]'
-        valid_no.append('')
-
-    ans = raw_input(prompt)
-    while (ans not in valid_yes and ans not in valid_no):
-        ans = raw_input(prompt)
-
-    return ans in valid_yes
-
-
-# Stuff for command line colored output
-
-COLORS = [
-    'BLACK', 'RED', 'GREEN', 'YELLOW',
-    'BLUE', 'MAGENTA', 'CYAN', 'WHITE'
-]
-
-DISABLE_COLORS = False
-
-
-def color_text(text, color_name, bold=False):
-    """
-    This command can be used to colorify command line output. If the shell
-    doesn't support this or the --disable-colors options has been set, it just
-    returns the plain text.
-
-    Usage:
-        print "%s" % color_text("This text is red", "RED")
-    """
-    if color_name in COLORS and not DISABLE_COLORS:
-        return '\033[%s;%sm%s\033[0m' % (
-            int(bold), COLORS.index(color_name) + 30, text)
-    else:
-        return text
-
-
-##############################################
-# relpath implementation taken from Python 2.7
-
-if not hasattr(os.path, 'relpath'):
-    if os.path is sys.modules.get('ntpath'):
-        def relpath(path, start=os.path.curdir):
-            """Return a relative version of a path"""
-
-            if not path:
-                raise ValueError("no path specified")
-            start_list = os.path.abspath(start).split(os.path.sep)
-            path_list = os.path.abspath(path).split(os.path.sep)
-            if start_list[0].lower() != path_list[0].lower():
-                unc_path, rest = os.path.splitunc(path)
-                unc_start, rest = os.path.splitunc(start)
-                if bool(unc_path) ^ bool(unc_start):
-                    raise ValueError("Cannot mix UNC and non-UNC paths (%s and %s)"
-                                                                        % (path, start))
-                else:
-                    raise ValueError("path is on drive %s, start on drive %s"
-                                                        % (path_list[0], start_list[0]))
-            # Work out how much of the filepath is shared by start and path.
-            for i in range(min(len(start_list), len(path_list))):
-                if start_list[i].lower() != path_list[i].lower():
-                    break
-            else:
-                i += 1
-
-            rel_list = [os.path.pardir] * (len(start_list)-i) + path_list[i:]
-            if not rel_list:
-                return os.path.curdir
-            return os.path.join(*rel_list)
-
-    else:
-        # default to posixpath definition
-        def relpath(path, start=os.path.curdir):
-            """Return a relative version of a path"""
-
-            if not path:
-                raise ValueError("no path specified")
-
-            start_list = os.path.abspath(start).split(os.path.sep)
-            path_list = os.path.abspath(path).split(os.path.sep)
-
-            # Work out how much of the filepath is shared by start and path.
-            i = len(os.path.commonprefix([start_list, path_list]))
-
-            rel_list = [os.path.pardir] * (len(start_list)-i) + path_list[i:]
-            if not rel_list:
-                return os.path.curdir
-            return os.path.join(*rel_list)
-else:
-    from os.path import relpath
diff --git a/third_party/transifex-client/txclib/web.py b/third_party/transifex-client/txclib/web.py
deleted file mode 100644 (file)
index a3cb3f0..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-# -*- coding: utf-8 -*-
-import urllib2
-import itertools, mimetools, mimetypes
-import platform
-from txclib import get_version
-
-# Helper class to enable urllib2 to handle PUT/DELETE requests as well
-class RequestWithMethod(urllib2.Request):
-    """Workaround for using DELETE with urllib2"""
-    def __init__(self, url, method, data=None, headers={},
-        origin_req_host=None, unverifiable=False):
-        self._method = method
-        urllib2.Request.__init__(self, url, data=data, headers=headers,
-                 origin_req_host=None, unverifiable=False)
-
-    def get_method(self):
-        return self._method
-
-import urllib
-import os, stat
-from cStringIO import StringIO
-
-class Callable:
-    def __init__(self, anycallable):
-        self.__call__ = anycallable
-
-# Controls how sequences are uncoded. If true, elements may be given multiple
-# values by assigning a sequence.
-doseq = 1
-
-class MultipartPostHandler(urllib2.BaseHandler):
-    handler_order = urllib2.HTTPHandler.handler_order - 10 # needs to run first
-
-    def http_request(self, request):
-        data = request.get_data()
-        if data is not None and type(data) != str:
-            v_files = []
-            v_vars = []
-            try:
-                 for(key, value) in data.items():
-                     if type(value) == file:
-                         v_files.append((key, value))
-                     else:
-                         v_vars.append((key, value))
-            except TypeError:
-                systype, value, traceback = sys.exc_info()
-                raise TypeError, "not a valid non-string sequence or mapping object", traceback
-
-            if len(v_files) == 0:
-                data = urllib.urlencode(v_vars, doseq)
-            else:
-                boundary, data = self.multipart_encode(v_vars, v_files)
-
-                contenttype = 'multipart/form-data; boundary=%s' % boundary
-                if(request.has_header('Content-Type')
-                   and request.get_header('Content-Type').find('multipart/form-data') != 0):
-                    print "Replacing %s with %s" % (request.get_header('content-type'), 'multipart/form-data')
-                request.add_unredirected_header('Content-Type', contenttype)
-
-            request.add_data(data)
-
-        return request
-
-    def multipart_encode(vars, files, boundary = None, buf = None):
-        if boundary is None:
-            boundary = mimetools.choose_boundary()
-        if buf is None:
-            buf = StringIO()
-        for(key, value) in vars:
-            buf.write('--%s\r\n' % boundary)
-            buf.write('Content-Disposition: form-data; name="%s"' % key)
-            buf.write('\r\n\r\n' + value + '\r\n')
-        for(key, fd) in files:
-            file_size = os.fstat(fd.fileno())[stat.ST_SIZE]
-            filename = fd.name.split('/')[-1]
-            contenttype = mimetypes.guess_type(filename)[0] or 'application/octet-stream'
-            buf.write('--%s\r\n' % boundary)
-            buf.write('Content-Disposition: form-data; name="%s"; filename="%s"\r\n' % (key, filename))
-            buf.write('Content-Type: %s\r\n' % contenttype)
-            # buffer += 'Content-Length: %s\r\n' % file_size
-            fd.seek(0)
-            buf.write('\r\n' + fd.read() + '\r\n')
-        buf.write('--' + boundary + '--\r\n\r\n')
-        buf = buf.getvalue()
-        return boundary, buf
-    multipart_encode = Callable(multipart_encode)
-
-    https_request = http_request
-
-
-def user_agent_identifier():
-    """Return the user agent for the client."""
-    client_info = (get_version(), platform.system(), platform.machine())
-    return "txclient/%s (%s %s)" % client_info