Merge branch 'develop' into fixForCrashedSharedContents
authorzerginator <thorstenvomsee@gmx.de>
Sun, 28 Apr 2013 09:40:40 +0000 (11:40 +0200)
committerzerginator <thorstenvomsee@gmx.de>
Sun, 28 Apr 2013 09:40:40 +0000 (11:40 +0200)
83 files changed:
.tx/config
AndroidManifest.xml
res/drawable-hdpi/image_fail.png [new file with mode: 0644]
res/drawable-ldpi/image_fail.png [new file with mode: 0644]
res/drawable-mdpi/image_fail.png [new file with mode: 0644]
res/layout/audio_player.xml [new file with mode: 0644]
res/layout/file_details_fragment.xml
res/layout/file_download_fragment.xml [new file with mode: 0644]
res/layout/file_preview.xml [new file with mode: 0644]
res/layout/media_control.xml [new file with mode: 0644]
res/layout/preview_image_activity.xml [new file with mode: 0644]
res/layout/preview_image_fragment.xml [new file with mode: 0644]
res/layout/uploader_layout.xml
res/layout/video_layout.xml [new file with mode: 0644]
res/menu/file_actions_menu.xml [new file with mode: 0644]
res/menu/file_context_menu.xml [deleted file]
res/menu/main_menu.xml [new file with mode: 0644]
res/menu/menu.xml [deleted file]
res/values-af-rZA/strings.xml [new file with mode: 0644]
res/values-be/strings.xml [new file with mode: 0644]
res/values-bg-rBG/strings.xml
res/values-de-rDE/strings.xml
res/values-de/strings.xml
res/values-eu/strings.xml
res/values-fa/strings.xml
res/values-fi-rFI/strings.xml
res/values-gl/strings.xml
res/values-hi/strings.xml
res/values-hu-rHU/strings.xml
res/values-ka/strings.xml [new file with mode: 0644]
res/values-lv/strings.xml
res/values-my/strings.xml [new file with mode: 0644]
res/values-nb-rNO/strings.xml
res/values-pl/strings.xml
res/values-pt-rBR/strings.xml
res/values-pt-rPT/strings.xml
res/values-sk-rSK/strings.xml
res/values-sk/strings.xml [new file with mode: 0644]
res/values-sr/strings.xml
res/values-sw-rKE/strings.xml [new file with mode: 0644]
res/values-tr/strings.xml
res/values-uk/strings.xml
res/values-ur-rPK/strings.xml [new file with mode: 0644]
res/values-vi/strings.xml
res/values-zh-rBG/strings.xml
res/values-zh-rCN/strings.xml
res/values-zh-rTW/strings.xml
res/values/strings.xml
src/com/owncloud/android/AccountUtils.java
src/com/owncloud/android/DisplayUtils.java
src/com/owncloud/android/Uploader.java
src/com/owncloud/android/datamodel/DataStorageManager.java
src/com/owncloud/android/datamodel/FileDataStorageManager.java
src/com/owncloud/android/datamodel/OCFile.java
src/com/owncloud/android/files/services/FileDownloader.java
src/com/owncloud/android/files/services/FileUploader.java
src/com/owncloud/android/media/MediaControlView.java [new file with mode: 0644]
src/com/owncloud/android/media/MediaService.java [new file with mode: 0644]
src/com/owncloud/android/media/MediaServiceBinder.java [new file with mode: 0644]
src/com/owncloud/android/network/ProgressiveDataTransferer.java [new file with mode: 0644]
src/com/owncloud/android/operations/ChunkedUploadFileOperation.java
src/com/owncloud/android/operations/DownloadFileOperation.java
src/com/owncloud/android/operations/SynchronizeFileOperation.java
src/com/owncloud/android/operations/UploadFileOperation.java
src/com/owncloud/android/ui/activity/FileDetailActivity.java
src/com/owncloud/android/ui/activity/FileDisplayActivity.java
src/com/owncloud/android/ui/activity/InstantUploadActivity.java
src/com/owncloud/android/ui/activity/UploadFilesActivity.java
src/com/owncloud/android/ui/dialog/ChangelogDialog.java
src/com/owncloud/android/ui/dialog/IndeterminateProgressDialog.java
src/com/owncloud/android/ui/fragment/ConfirmationDialogFragment.java
src/com/owncloud/android/ui/fragment/FileDetailFragment.java
src/com/owncloud/android/ui/fragment/FileFragment.java [new file with mode: 0644]
src/com/owncloud/android/ui/fragment/OCFileListFragment.java
src/com/owncloud/android/ui/preview/FileDownloadFragment.java [new file with mode: 0644]
src/com/owncloud/android/ui/preview/PreviewImageActivity.java [new file with mode: 0644]
src/com/owncloud/android/ui/preview/PreviewImageFragment.java [new file with mode: 0644]
src/com/owncloud/android/ui/preview/PreviewImagePagerAdapter.java [new file with mode: 0644]
src/com/owncloud/android/ui/preview/PreviewMediaFragment.java [new file with mode: 0644]
src/com/owncloud/android/ui/preview/PreviewVideoActivity.java [new file with mode: 0644]
src/eu/alefzero/webdav/ChunkFromFileChannelRequestEntity.java
src/eu/alefzero/webdav/FileRequestEntity.java
src/eu/alefzero/webdav/WebdavClient.java

index 5abe130..f30f5ef 100644 (file)
@@ -5,4 +5,4 @@ host = https://www.transifex.com
 file_filter = res/values-<lang>/strings.xml
 source_file = res/values/strings.xml
 source_lang = en
-lang_map = af_ZA: af-rZA, am_ET: am-rET, ar_AE: ar-rAE, ar_BH: ar-rBH, ar_DZ: ar-rDZ, ar_EG: ar-rEG, ar_IQ: ar-rIQ, ar_JO: ar-rJO, ar_KW: ar-rKW, ar_LB: ar-rLB, ar_LY: ar-rLY, ar_MA: ar-rMA, ar_OM: ar-rOM, ar_QA: ar-rQA, ar_SA: ar-rSA, ar_SY: ar-rSY, ar_TN: ar-rTN, ar_YE: ar-rYE, arn_CL: arn-rCL, as_IN: as-rIN, az_AZ: az-rAZ, ba_RU: ba-rRU, be_BY: be-rBY, bg_BG: bg-rBG, bn_BD: bn-rBD, bn_IN: bn-rIN, bo_CN: bo-rCN, br_FR: br-rFR, bs_BA: bs-rBA, ca_ES: ca-rES, co_FR: co-rFR, cs_CZ: cs-rCZ, cy_GB: cy-rGB, da_DK: da-rDK, de_AT: de-rAT, de_CH: de-rCH, de_DE: de-rDE, de_LI: de-rLI, de_LU: de-rLU, dsb_DE: dsb-rDE, dv_MV: dv-rMV, el_GR: el-rGR, en_AU: en-rAU, en_BZ: en-rBZ, en_CA: en-rCA, en_GB: en-rGB, en_IE: en-rIE, en_IN: en-rIN, en_JM: en-rJM, en_MY: en-rMY, en_NZ: en-rNZ, en_PH: en-rPH, en_SG: en-rSG, en_TT: en-rTT, en_US: en-rUS, en_ZA: en-rZA, en_ZW: en-rZW, es_AR: es-rAR, es_BO: es-rBO, es_CL: es-rCL, es_CO: es-rCO, es_CR: es-rCR, es_DO: es-rDO, es_EC: es-rEC, es_ES: es-rES, es_GT: es-rGT, es_HN: es-rHN, es_MX: es-rMX, es_NI: es-rNI, es_PA: es-rPA, es_PE: es-rPE, es_PR: es-rPR, es_PY: es-rPY, es_SV: es-rSV, es_US: es-rUS, es_UY: es-rUY, es_VE: es-rVE, et_EE: et-rEE, eu_ES: eu-rES, fa_IR: fa-rIR, fi_FI: fi-rFI, fil_PH: fil-rPH, fo_FO: fo-rFO, fr_BE: fr-rBE, fr_CA: fr-rCA, fr_CH: fr-rCH, fr_FR: fr-rFR, fr_LU: fr-rLU, fr_MC: fr-rMC, fy_NL: fy-rNL, ga_IE: ga-rIE, gd_GB: gd-rGB, gl_ES: gl-rES, gsw_FR: gsw-rFR, gu_IN: gu-rIN, ha_NG: ha-rNG, he_IL: he-rIL, hi_IN: hi-rIN, hr_BA: hr-rBA, hr_HR: hr-rHR, hsb_DE: hsb-rDE, hu_HU: hu-rHU, hy_AM: hy-rAM, id_ID: id-rID, ig_NG: ig-rNG, ii_CN: ii-rCN, is_IS: is-rIS, it_CH: it-rCH, it_IT: it-rIT, iu_CA: iu-rCA, ja_JP: ja-rJP, ka_GE: ka-rGE, kk_KZ: kk-rKZ, kl_GL: kl-rGL, km_KH: km-rKH, kn_IN: kn-rIN, ko_KR: ko-rKR, kok_IN: kok-rIN, ku_IQ: ku-rIQ, ky_KG: ky-rKG, lb_LU: lb-rLU, lo_LA: lo-rLA, lt_LT: lt-rLT, lv_LV: lv-rLV, mi_NZ: mi-rNZ, mk_MK: mk-rMK, ml_IN: ml-rIN, mn_CN: mn-rCN, mn_MN: mn-rMN, moh_CA: moh-rCA, mr_IN: mr-rIN, ms_BN: ms-rBN, ms_MY: ms-rMY, mt_MT: mt-rMT, nb_NO: nb-rNO, ne_NP: ne-rNP, nl_BE: nl-rBE, nl_NL: nl-rNL, nn_NO: nn-rNO, nso_ZA: nso-rZA, oc_FR: oc-rFR, or_IN: or-rIN, pa_IN: pa-rIN, pl_PL: pl-rPL, prs_AF: prs-rAF, ps_AF: ps-rAF, pt_BR: pt-rBR, pt_PT: pt-rPT, qut_GT: qut-rGT, quz_BO: quz-rBO, quz_EC: quz-rEC, quz_PE: quz-rPE, rm_CH: rm-rCH, ro_RO: ro-rRO, ru_RU: ru-rRU, rw_RW: rw-rRW, sa_IN: sa-rIN, sah_RU: sah-rRU, se_FI: se-rFI, se_NO: se-rNO, se_SE: se-rSE, si_LK: si-rLK, sk_SK: sk-rSK, sl_SI: sl-rSI, sma_NO: sma-rNO, sma_SE: sma-rSE, smj_NO: smj-rNO, smj_SE: smj-rSE, smn_FI: smn-rFI, sms_FI: sms-rFI, sq_AL: sq-rAL, sr_BA: sr-rBA, sr_CS: sr-rCS, sr_ME: sr-rME, sr_RS: sr-rRS, sr@latin: sr-rSP, sv_FI: sv-rFI, sv_SE: sv-rSE, sw_KE: sw-rKE, syr_SY: syr-rSY, ta_IN: ta-rIN, ta_LK: ta-rLK, te_IN: te-rIN, tg_TJ: tg-rTJ, th_TH: th-rTH, tk_TM: tk-rTM, tn_ZA: tn-rZA, tr_TR: tr-rTR, tt_RU: tt-rRU, tzm_DZ: tzm-rDZ, ug_CN: ug-rCN, uk_UA: uk-rUA, ur_PK: ur-rPK, uz_UZ: uz-rUZ, vi_VN: vi-rVN, wo_SN: wo-rSN, xh_ZA: xh-rZA, yo_NG: yo-rNG, zh_CN: zh-rCN, zh_CN.GB2312:zh-rBG, zh_HK: zh-rHK, zh_MO: zh-rMO, zh_SG: zh-rSG, zh_TW: zh-rTW, zu_ZA: zu-rZA
+lang_map = af_ZA: af-rZA, am_ET: am-rET, ar_AE: ar-rAE, ar_BH: ar-rBH, ar_DZ: ar-rDZ, ar_EG: ar-rEG, ar_IQ: ar-rIQ, ar_JO: ar-rJO, ar_KW: ar-rKW, ar_LB: ar-rLB, ar_LY: ar-rLY, ar_MA: ar-rMA, ar_OM: ar-rOM, ar_QA: ar-rQA, ar_SA: ar-rSA, ar_SY: ar-rSY, ar_TN: ar-rTN, ar_YE: ar-rYE, arn_CL: arn-rCL, as_IN: as-rIN, az_AZ: az-rAZ, ba_RU: ba-rRU, be_BY: be-rBY, bg_BG: bg-rBG, bn_BD: bn-rBD, bn_IN: bn-rIN, bo_CN: bo-rCN, br_FR: br-rFR, bs_BA: bs-rBA, ca_ES: ca-rES, co_FR: co-rFR, cs_CZ: cs-rCZ, cy_GB: cy-rGB, da_DK: da-rDK, de_AT: de-rAT, de_CH: de-rCH, de_DE: de-rDE, de_LI: de-rLI, de_LU: de-rLU, dsb_DE: dsb-rDE, dv_MV: dv-rMV, el_GR: el-rGR, en_AU: en-rAU, en_BZ: en-rBZ, en_CA: en-rCA, en_GB: en-rGB, en_IE: en-rIE, en_IN: en-rIN, en_JM: en-rJM, en_MY: en-rMY, en_NZ: en-rNZ, en_PH: en-rPH, en_SG: en-rSG, en_TT: en-rTT, en_US: en-rUS, en_ZA: en-rZA, en_ZW: en-rZW, es_AR: es-rAR, es_BO: es-rBO, es_CL: es-rCL, es_CO: es-rCO, es_CR: es-rCR, es_DO: es-rDO, es_EC: es-rEC, es_ES: es-rES, es_GT: es-rGT, es_HN: es-rHN, es_MX: es-rMX, es_NI: es-rNI, es_PA: es-rPA, es_PE: es-rPE, es_PR: es-rPR, es_PY: es-rPY, es_SV: es-rSV, es_US: es-rUS, es_UY: es-rUY, es_VE: es-rVE, et_EE: et-rEE, eu_ES: eu-rES, fa_IR: fa-rIR, fi_FI: fi-rFI, fil_PH: fil-rPH, fo_FO: fo-rFO, fr_BE: fr-rBE, fr_CA: fr-rCA, fr_CH: fr-rCH, fr_FR: fr-rFR, fr_LU: fr-rLU, fr_MC: fr-rMC, fy_NL: fy-rNL, ga_IE: ga-rIE, gd_GB: gd-rGB, gl_ES: gl-rES, gsw_FR: gsw-rFR, gu_IN: gu-rIN, ha_NG: ha-rNG, he_IL: he-rIL, hi_IN: hi-rIN, hr_BA: hr-rBA, hr_HR: hr-rHR, hsb_DE: hsb-rDE, hu_HU: hu-rHU, hy_AM: hy-rAM, id_ID: id-rID, ig_NG: ig-rNG, ii_CN: ii-rCN, is_IS: is-rIS, it_CH: it-rCH, it_IT: it-rIT, iu_CA: iu-rCA, ja_JP: ja-rJP, ka_GE: ka-rGE, kk_KZ: kk-rKZ, kl_GL: kl-rGL, km_KH: km-rKH, kn_IN: kn-rIN, ko_KR: ko-rKR, kok_IN: kok-rIN, ku_IQ: ku-rIQ, ky_KG: ky-rKG, lb_LU: lb-rLU, lo_LA: lo-rLA, lt_LT: lt-rLT, lv_LV: lv-rLV, mi_NZ: mi-rNZ, mk_MK: mk-rMK, ml_IN: ml-rIN, mn_CN: mn-rCN, mn_MN: mn-rMN, moh_CA: moh-rCA, mr_IN: mr-rIN, ms_BN: ms-rBN, ms_MY: ms-rMY, my_MM: my, mt_MT: mt-rMT, nb_NO: nb-rNO, ne_NP: ne-rNP, nl_BE: nl-rBE, nl_NL: nl-rNL, nn_NO: nn-rNO, nso_ZA: nso-rZA, oc_FR: oc-rFR, or_IN: or-rIN, pa_IN: pa-rIN, pl_PL: pl-rPL, prs_AF: prs-rAF, ps_AF: ps-rAF, pt_BR: pt-rBR, pt_PT: pt-rPT, qut_GT: qut-rGT, quz_BO: quz-rBO, quz_EC: quz-rEC, quz_PE: quz-rPE, rm_CH: rm-rCH, ro_RO: ro-rRO, ru_RU: ru-rRU, rw_RW: rw-rRW, sa_IN: sa-rIN, sah_RU: sah-rRU, se_FI: se-rFI, se_NO: se-rNO, se_SE: se-rSE, si_LK: si-rLK, sk_SK: sk-rSK, sl_SI: sl-rSI, sma_NO: sma-rNO, sma_SE: sma-rSE, smj_NO: smj-rNO, smj_SE: smj-rSE, smn_FI: smn-rFI, sms_FI: sms-rFI, sq_AL: sq-rAL, sr_BA: sr-rBA, sr_CS: sr-rCS, sr_ME: sr-rME, sr_RS: sr-rRS, sr@latin: sr-rSP, sv_FI: sv-rFI, sv_SE: sv-rSE, sw_KE: sw-rKE, syr_SY: syr-rSY, ta_IN: ta-rIN, ta_LK: ta-rLK, te_IN: te-rIN, tg_TJ: tg-rTJ, th_TH: th-rTH, tk_TM: tk-rTM, tn_ZA: tn-rZA, tr_TR: tr-rTR, tt_RU: tt-rRU, tzm_DZ: tzm-rDZ, ug_CN: ug-rCN, uk_UA: uk-rUA, ur_PK: ur-rPK, uz_UZ: uz-rUZ, vi_VN: vi-rVN, wo_SN: wo-rSN, xh_ZA: xh-rZA, yo_NG: yo-rNG, zh_CN: zh-rCN, zh_CN.GB2312:zh-rBG, zh_HK: zh-rHK, zh_MO: zh-rMO, zh_SG: zh-rSG, zh_TW: zh-rTW, zu_ZA: zu-rZA
index 32c4655..e5e4a05 100644 (file)
@@ -19,8 +19,8 @@
   along with this program.  If not, see <http://www.gnu.org/licenses/>.\r
  -->\r
 <manifest package="com.owncloud.android"\r
-    android:versionCode="103020"\r
-    android:versionName="1.3.20" xmlns:android="http://schemas.android.com/apk/res/android">\r
+    android:versionCode="104000"\r
+    android:versionName="1.4.0" xmlns:android="http://schemas.android.com/apk/res/android">\r
 \r
     <uses-permission android:name="android.permission.GET_ACCOUNTS" />\r
     <uses-permission android:name="android.permission.USE_CREDENTIALS" />\r
@@ -35,7 +35,8 @@
     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />\r
     <uses-permission android:name="android.permission.READ_PHONE_STATE" />\r
     <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>\r
-\r
+    <uses-permission android:name="android.permission.WAKE_LOCK"/>\r
+    \r
     <uses-sdk\r
         android:minSdkVersion="8"\r
         android:targetSdkVersion="13" />\r
         </activity>\r
         <activity android:name=".ui.activity.PreferencesNewSessionewSession" >\r
         </activity>\r
+        \r
+               <activity       android:name="com.owncloud.android.ui.preview.PreviewImageActivity" />\r
+                       \r
+        <activity      android:name="com.owncloud.android.ui.preview.PreviewVideoActivity"\r
+                                       android:label="@string/app_name"\r
+                                       android:theme="@android:style/Theme.NoTitleBar.Fullscreen" >\r
+               </activity>        \r
 \r
         <service\r
             android:name=".authenticator.AccountAuthenticatorService"\r
             </intent-filter>\r
         </activity>\r
 \r
-        <service android:name=".files.services.FileDownloader" >\r
-        </service>\r
+        <service android:name=".files.services.FileDownloader" />\r
+        <service android:name=".files.services.FileUploader" />\r
+        <service android:name=".media.MediaService" />\r
 \r
         <activity android:name=".ui.activity.FileDetailActivity" />\r
         <activity android:name=".ui.activity.PinCodeActivity" />\r
         <activity android:name=".ui.activity.ConflictsResolveActivity"/>\r
         <activity android:name=".ui.activity.GenericExplanationActivity"/>\r
         <activity android:name=".ui.activity.ErrorsWhileCopyingHandlerActivity"/>\r
-        \r
-        <service android:name=".files.services.FileUploader" >\r
-        </service>\r
-        <service android:name=".files.services.InstantUploadService" />\r
+        
+        <service android:name=".files.services.InstantUploadService" />
         <receiver android:name=".files.InstantUploadBroadcastReceiver">\r
             <intent-filter>\r
                 <action android:name="com.android.camera.NEW_PICTURE" />\r
diff --git a/res/drawable-hdpi/image_fail.png b/res/drawable-hdpi/image_fail.png
new file mode 100644 (file)
index 0000000..3866741
Binary files /dev/null and b/res/drawable-hdpi/image_fail.png differ
diff --git a/res/drawable-ldpi/image_fail.png b/res/drawable-ldpi/image_fail.png
new file mode 100644 (file)
index 0000000..77513ad
Binary files /dev/null and b/res/drawable-ldpi/image_fail.png differ
diff --git a/res/drawable-mdpi/image_fail.png b/res/drawable-mdpi/image_fail.png
new file mode 100644 (file)
index 0000000..8e650cd
Binary files /dev/null and b/res/drawable-mdpi/image_fail.png differ
diff --git a/res/layout/audio_player.xml b/res/layout/audio_player.xml
new file mode 100644 (file)
index 0000000..bee0f87
--- /dev/null
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:id="@+id/main_audio_view"
+              android:layout_width="fill_parent"
+              android:layout_height="wrap_content"
+              android:layout_gravity="center"
+              android:orientation="vertical">
+  <TextView
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:layout_gravity="center"
+    android:text="Now playing:"
+    android:textSize="25sp"
+    android:textStyle="bold"
+    />
+  <TextView
+    android:id="@+id/now_playing_text"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:layout_marginTop="20dip"
+    android:layout_marginLeft="10dip"
+    android:layout_marginRight="10dip"
+    android:layout_gravity="center"
+    android:text="Now playing.."
+    android:textSize="16sp"
+    android:textStyle="italic"
+    />
+</LinearLayout>
\ No newline at end of file
index dcce819..c2b8af3 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/>.
 -->
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="fill_parent"
-    android:layout_height="fill_parent"
-    android:background="@color/owncloud_white" >
-
-    <ScrollView
-        android:id="@+id/fdScrollView"
-        android:layout_width="fill_parent"
-        android:layout_height="fill_parent" >
-
-        <RelativeLayout
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content" >
-
-            <RelativeLayout
-                android:id="@+id/fdFileHeaderContainer"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:layout_marginLeft="16dp"
-                android:layout_marginTop="4dp" >
-
-                <ImageView
-                    android:id="@+id/fdIcon"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:src="@drawable/file" />
-
-                <TextView
-                    android:id="@+id/fdFilename"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:layout_centerVertical="true"
-                    android:layout_toRightOf="@+id/fdIcon"
-                    android:text="file.name"
-                    android:textAppearance="?android:attr/textAppearanceLarge" />
-            </RelativeLayout>
-
-            <RelativeLayout
-                android:id="@+id/fdDetailsContainer"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:layout_below="@+id/fdFileHeaderContainer" >
-
-                <RelativeLayout
-                    android:id="@+id/fdLabelContainer"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:layout_alignParentLeft="true"
-                    android:layout_alignParentTop="true"
-                    android:layout_marginLeft="16dp" >
-
-                    <TextView
-                        android:id="@+id/fdTypeLabel"
-                        android:layout_width="wrap_content"
-                        android:layout_height="wrap_content"
-                        android:layout_marginTop="24dp"
-                        android:text="@string/filedetails_type"
-                        android:textAppearance="?android:attr/textAppearanceMedium" />
-
-                    <TextView
-                        android:id="@+id/fdSizeLabel"
-                        android:layout_width="wrap_content"
-                        android:layout_height="wrap_content"
-                        android:layout_below="@+id/fdTypeLabel"
-                        android:layout_marginTop="12dp"
-                        android:text="@string/filedetails_size"
-                        android:textAppearance="?android:attr/textAppearanceMedium" />
-
-                    <TextView
-                        android:id="@+id/fdCreatedLabel"
-                        android:layout_width="wrap_content"
-                        android:layout_height="wrap_content"
-                        android:layout_below="@+id/fdSizeLabel"
-                        android:layout_marginTop="12dp"
-                        android:text="@string/filedetails_created"
-                        android:visibility="gone"
-                        android:textAppearance="?android:attr/textAppearanceMedium" />
-                    
-                    <TextView
-                        android:id="@+id/fdModifiedLabel"
-                        android:layout_width="wrap_content"
-                        android:layout_height="wrap_content"
-                        android:layout_below="@+id/fdCreatedLabel"
-                        android:layout_marginTop="12dp"
-                        android:text="@string/filedetails_modified"
-                        android:textAppearance="?android:attr/textAppearanceMedium" />
-                </RelativeLayout>
-
-                <RelativeLayout
-                    android:id="@+id/fdValueContainer"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:layout_alignParentTop="true"
-                    android:layout_marginLeft="12dp"
-                    android:layout_toRightOf="@+id/fdLabelContainer" >
-
-                    <TextView
-                        android:id="@+id/fdType"
-                        android:layout_width="wrap_content"
-                        android:layout_height="wrap_content"
-                        android:layout_marginTop="24dp"
-                        android:text="JPG Image"
-                        android:textAppearance="?android:attr/textAppearanceMedium" />
-
-                    <TextView
-                        android:id="@+id/fdSize"
-                        android:layout_width="wrap_content"
-                        android:layout_height="wrap_content"
-                        android:layout_below="@+id/fdType"
-                        android:layout_marginTop="12dp"
-                        android:text="389 KB"
-                        android:textAppearance="?android:attr/textAppearanceMedium" />
-
-                    <TextView
-                        android:id="@+id/fdCreated"
-                        android:layout_width="wrap_content"
-                        android:layout_height="wrap_content"
-                        android:layout_below="@+id/fdSize"
-                        android:layout_marginTop="12dp"
-                        android:visibility="gone"
-                        android:text="2012/05/18 12:23 PM"
-                        android:textAppearance="?android:attr/textAppearanceMedium" />
-
-                    <TextView
-                        android:id="@+id/fdModified"
-                        android:layout_width="wrap_content"
-                        android:layout_height="wrap_content"
-                        android:layout_below="@+id/fdCreated"
-                        android:layout_marginTop="12dp"
-                        android:text="2012/05/19 02:56 PM"
-                        android:textAppearance="?android:attr/textAppearanceMedium" />
-                </RelativeLayout>
-
-            </RelativeLayout>
-
-            <RelativeLayout
-                android:id="@+id/fdPreviewAndDL"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:layout_below="@+id/fdDetailsContainer"
-                android:gravity="center_horizontal" >
-
-                <CheckBox
-                    android:id="@+id/fdKeepInSync"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:layout_centerHorizontal="true"
-                    android:text="@string/fd_keep_in_sync" />
-
-                <ImageView
-                    android:id="@+id/fdPreview"
-                    android:layout_width="match_parent"
-                    android:layout_height="match_parent"
-                    android:layout_below="@id/fdKeepInSync"
-                    android:layout_centerHorizontal="true"
-                    android:layout_marginTop="16dp"
-                    android:src="@drawable/owncloud_logo" />
-
-                <LinearLayout
-                    android:layout_width="match_parent"
-                    android:layout_height="wrap_content"
-                    android:layout_below="@id/fdPreview"
-                    android:orientation="vertical" >
-
-                    <LinearLayout
-                        android:layout_width="match_parent"
-                        android:layout_height="wrap_content"
-                        android:gravity="center_horizontal" >
-
-                        <Button
-                            android:id="@+id/fdRemoveBtn"
-                            android:layout_width="wrap_content"
-                            android:layout_height="wrap_content"
-                            android:layout_marginTop="12dp"
-                            android:text="@string/common_remove" />
-
-                        <Button
-                            android:id="@+id/fdOpenBtn"
-                            android:layout_width="wrap_content"
-                            android:layout_height="wrap_content"
-                            android:layout_marginTop="12dp"
-                            android:text="@string/filedetails_open" />
-
-                    </LinearLayout>
-
-                    <LinearLayout
-                        android:layout_width="match_parent"
-                        android:layout_height="wrap_content"
-                        android:gravity="center_horizontal">
-
-                        <Button
-                            android:id="@+id/fdDownloadBtn"
-                            android:layout_width="wrap_content"
-                            android:layout_height="wrap_content"
-                            android:layout_marginTop="12dp"
-                            android:text="@string/filedetails_download" />
-
-                        <Button
-                            android:id="@+id/fdRenameBtn"
-                            android:layout_width="wrap_content"
-                            android:layout_height="wrap_content"
-                            android:layout_marginTop="12dp"
-                            android:text="@string/common_rename" />
-
-                    </LinearLayout>
-<!-- 
-                    <Button
-                        android:id="@+id/fdShareBtn"
-                        android:layout_width="wrap_content"
-                        android:layout_height="wrap_content"
-                        android:layout_marginTop="12dp"
-                        android:text="@string/common_share" />
- -->
-
-                </LinearLayout>
-            </RelativeLayout>
-
-        </RelativeLayout>
-    </ScrollView>
-
-</RelativeLayout>
\ No newline at end of file
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+       android:id="@+id/fdScrollView"
+       android:layout_width="fill_parent"
+       android:layout_height="fill_parent" >
+
+       <RelativeLayout
+               android:layout_width="match_parent"
+               android:layout_height="wrap_content" >
+
+               <RelativeLayout
+                       android:id="@+id/fdFileHeaderContainer"
+                       android:layout_width="match_parent"
+                       android:layout_height="wrap_content"
+                       android:layout_marginLeft="16dp"
+                       android:layout_marginTop="4dp" >
+       
+                       <ImageView
+                               android:id="@+id/fdIcon"
+                               android:layout_width="wrap_content"
+                               android:layout_height="wrap_content"
+                               android:src="@drawable/file" />
+                               
+                       <TextView
+                           android:id="@+id/fdFilename"
+                           android:layout_width="wrap_content"
+                           android:layout_height="wrap_content"
+                           android:layout_centerVertical="true"
+                           android:layout_toRightOf="@+id/fdIcon"
+                           android:text="@string/placeholder_filename"
+                           android:textAppearance="?android:attr/textAppearanceLarge" />
+                       
+               </RelativeLayout>
+       
+               <RelativeLayout
+                       android:id="@+id/fdDetailsContainer"
+                       android:layout_width="match_parent"
+                       android:layout_height="wrap_content"
+                       android:layout_below="@id/fdFileHeaderContainer" >
+               
+                       <RelativeLayout
+                               android:id="@+id/fdLabelContainer"
+                               android:layout_width="wrap_content"
+                               android:layout_height="wrap_content"
+                               android:layout_alignParentLeft="true"
+                               android:layout_alignParentTop="true"
+                               android:layout_marginLeft="16dp" >
+                               
+                               <TextView
+                                       android:id="@+id/fdTypeLabel"
+                                       android:layout_width="wrap_content"
+                                       android:layout_height="wrap_content"
+                                       android:layout_marginTop="24dp"
+                                       android:text="@string/filedetails_type"
+                                       android:textAppearance="?android:attr/textAppearanceMedium" />
+                                       
+                               <TextView
+                                       android:id="@+id/fdSizeLabel"
+                                       android:layout_width="wrap_content"
+                                       android:layout_height="wrap_content"
+                                       android:layout_below="@+id/fdTypeLabel"
+                                       android:layout_marginTop="12dp"
+                                       android:text="@string/filedetails_size"
+                                       android:textAppearance="?android:attr/textAppearanceMedium" />
+                                       
+                               <TextView
+                                       android:id="@+id/fdCreatedLabel"
+                                       android:layout_width="wrap_content"
+                                       android:layout_height="wrap_content"
+                                       android:layout_below="@+id/fdSizeLabel"
+                                       android:layout_marginTop="12dp"
+                                       android:text="@string/filedetails_created"
+                                       android:visibility="gone"
+                                       android:textAppearance="?android:attr/textAppearanceMedium" />
+                                         
+                               <TextView
+                                       android:id="@+id/fdModifiedLabel"
+                                       android:layout_width="wrap_content"
+                                       android:layout_height="wrap_content"
+                                       android:layout_below="@+id/fdCreatedLabel"
+                                       android:layout_marginTop="12dp"
+                                       android:text="@string/filedetails_modified"
+                                       android:textAppearance="?android:attr/textAppearanceMedium" />
+                       </RelativeLayout>
+       
+                       <RelativeLayout
+                               android:id="@+id/fdValueContainer"
+                               android:layout_width="wrap_content"
+                               android:layout_height="wrap_content"
+                               android:layout_alignParentTop="true"
+                               android:layout_marginLeft="12dp"
+                               android:layout_toRightOf="@+id/fdLabelContainer" >
+                               
+                               <TextView
+                                       android:id="@+id/fdType"
+                                       android:layout_width="wrap_content"
+                                       android:layout_height="wrap_content"
+                                       android:layout_marginTop="24dp"
+                                       android:text="@string/placeholder_filetype"
+                                       android:textAppearance="?android:attr/textAppearanceMedium" />
+                                       
+                               <TextView
+                                       android:id="@+id/fdSize"
+                                       android:layout_width="wrap_content"
+                                       android:layout_height="wrap_content"
+                                       android:layout_below="@+id/fdType"
+                                       android:layout_marginTop="12dp"
+                                       android:text="@string/placeholder_filesize"
+                                       android:textAppearance="?android:attr/textAppearanceMedium" />
+                                       
+                               <TextView
+                                       android:id="@+id/fdCreated"
+                                       android:layout_width="wrap_content"
+                                       android:layout_height="wrap_content"
+                                       android:layout_below="@+id/fdSize"
+                                       android:layout_marginTop="12dp"
+                                       android:visibility="gone"
+                                       android:text="@string/placeholder_timestamp"
+                                       android:textAppearance="?android:attr/textAppearanceMedium" />
+                                       
+                               <TextView
+                                       android:id="@+id/fdModified"
+                                       android:layout_width="wrap_content"
+                                       android:layout_height="wrap_content"
+                                       android:layout_below="@+id/fdCreated"
+                                       android:layout_marginTop="12dp"
+                                       android:text="@string/placeholder_timestamp"
+                                       android:textAppearance="?android:attr/textAppearanceMedium" />
+               
+                       </RelativeLayout>
+       
+               </RelativeLayout>
+       
+               <RelativeLayout
+                       android:id="@+id/fdProgressAndControl"
+                       android:layout_width="match_parent"
+                       android:layout_height="wrap_content"
+                       android:layout_below="@+id/fdDetailsContainer"
+                       android:gravity="center_horizontal" 
+                       android:layout_margin="16dp"
+                       >
+                       
+                       <CheckBox
+                               android:id="@+id/fdKeepInSync"
+                               android:layout_width="wrap_content"
+                               android:layout_height="wrap_content"
+                               android:layout_centerHorizontal="true"
+                               android:text="@string/fd_keep_in_sync" />
+
+                       <LinearLayout
+                               android:layout_width="match_parent"
+                               android:layout_height="wrap_content"
+                               android:layout_below="@id/fdKeepInSync"
+                               android:orientation="vertical" >
+                               
+                       <TextView 
+                           android:id="@+id/fdProgressText" 
+                           android:layout_width="match_parent"
+                               android:layout_height="wrap_content" 
+                               android:text="@string/downloader_download_in_progress_ticker"
+                               />
+                       
+                       <ProgressBar android:id="@+id/fdProgressBar"
+                                       android:layout_width="match_parent" 
+                                       android:layout_height="wrap_content"
+                                       android:progressDrawable="@android:drawable/progress_horizontal"
+                                       android:indeterminate="false" 
+                                       android:indeterminateOnly="false" 
+                                       />
+                                                                                               
+                           <LinearLayout
+                                       android:layout_width="match_parent"
+                                       android:layout_height="wrap_content"
+                                       android:gravity="center_horizontal"
+                                       android:layout_marginTop="12dp"
+                                       >
+                                                               
+                                       <Button
+                                               android:id="@+id/fdDownloadBtn"
+                                               android:layout_width="0dp"
+                                               android:layout_height="wrap_content"
+                                               android:layout_weight="1"
+                                               android:text="@string/filedetails_download" />
+                                               
+                                       <Button
+                                               android:id="@+id/fdOpenBtn"
+                                               android:layout_width="0dp"
+                                               android:layout_height="wrap_content"
+                                               android:layout_weight="1"
+                                               android:text="@string/filedetails_open" />
+                                               
+                               </LinearLayout>
+               
+                               <LinearLayout
+                                       android:layout_width="match_parent"
+                                       android:layout_height="wrap_content"
+                                       android:gravity="center_horizontal"
+                                       android:layout_marginTop="12dp"
+                                       >
+                                       
+                                       <Button
+                                               android:id="@+id/fdRenameBtn"
+                                               android:layout_width="0dp"
+                                               android:layout_height="wrap_content"
+                                               android:layout_weight="1"
+                                               android:text="@string/common_rename" />
+                                               
+                                   <Button
+                                               android:id="@+id/fdRemoveBtn"
+                                               android:layout_width="0dp"
+                                               android:layout_height="wrap_content"
+                                               android:layout_weight="1"
+                                               android:text="@string/common_remove" />
+                                               
+                               </LinearLayout>
+       
+                       </LinearLayout>
+                       
+               </RelativeLayout>
+
+       </RelativeLayout>
+       
+</ScrollView>
diff --git a/res/layout/file_download_fragment.xml b/res/layout/file_download_fragment.xml
new file mode 100644 (file)
index 0000000..aea16d0
--- /dev/null
@@ -0,0 +1,72 @@
+<?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 as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+       android:layout_width="match_parent"
+       android:layout_height="match_parent"
+       android:orientation="vertical" 
+       android:layout_gravity="center"
+       android:gravity="center_vertical"
+       android:padding="20dp"
+       >
+       
+       <TextView 
+           android:id="@+id/progressText" 
+           android:layout_width="match_parent"
+               android:layout_height="wrap_content" 
+               android:text="@string/downloader_not_downloaded_yet"
+               android:layout_marginBottom="15dp"
+       />
+       
+       <ProgressBar android:id="@+id/progressBar"
+               android:layout_width="match_parent" 
+               android:layout_height="wrap_content"
+               android:progressDrawable="@android:drawable/progress_horizontal"
+               android:indeterminate="false" 
+               android:indeterminateOnly="false" 
+               android:layout_marginBottom="15dp"
+       />
+       
+       <Button
+               android:id="@+id/cancelBtn"
+               android:layout_width="wrap_content"
+               android:layout_height="wrap_content"
+               android:text="@string/common_cancel" 
+               android:layout_marginBottom="15dp"
+       />
+       
+       <ImageView
+               android:id="@+id/error_image"
+               android:layout_width="wrap_content"
+               android:layout_height="wrap_content"
+               android:layout_margin="0dp"
+               android:layout_gravity="center_horizontal"
+               android:contentDescription="@string/downloader_download_failed_ticker"
+               android:src="@drawable/image_fail" />
+                                                                               
+       <TextView 
+           android:id="@+id/errorText" 
+           android:layout_width="wrap_content"
+               android:layout_height="wrap_content"
+               android:layout_gravity="center_horizontal"
+               android:layout_margin="40dp"
+               android:text="@string/downloader_download_failed_ticker"
+       />
+       
+</LinearLayout>
+
diff --git a/res/layout/file_preview.xml b/res/layout/file_preview.xml
new file mode 100644 (file)
index 0000000..82163cd
--- /dev/null
@@ -0,0 +1,65 @@
+<?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 as published by
+  the Free Software Foundation, either version 2 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  
+-->
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:id="@+id/top"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="@color/owncloud_white"
+    android:gravity="center"
+    tools:context=".ui.fragment.FilePreviewFragment" >
+
+    <FrameLayout 
+        android:id="@+id/visual_area"
+           android:layout_width="match_parent"
+           android:layout_height="0dp"
+           android:layout_alignParentTop="true"
+           android:layout_above="@+id/media_controller"
+        >
+    
+           <ImageView
+               android:id="@+id/image_preview"
+               android:layout_width="match_parent"
+               android:layout_height="match_parent"
+               android:layout_margin="16dp"
+               android:layout_gravity="center"
+               android:contentDescription="@string/preview_image_description"
+               android:src="@drawable/owncloud_logo" />
+           
+               <VideoView  
+                   android:id="@+id/video_preview"
+                       android:layout_width="match_parent"
+                       android:layout_height="match_parent"  
+                       android:layout_gravity="center" 
+                       android:visibility="gone"
+                       />
+               
+       </FrameLayout>
+       
+       <com.owncloud.android.media.MediaControlView 
+           android:id="@id/media_controller"
+           android:layout_width="match_parent"
+           android:layout_height="wrap_content"
+           android:layout_alignParentBottom="true"
+           />
+
+</RelativeLayout>
\ No newline at end of file
diff --git a/res/layout/media_control.xml b/res/layout/media_control.xml
new file mode 100644 (file)
index 0000000..070ae8c
--- /dev/null
@@ -0,0 +1,94 @@
+<?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 as published by
+  the Free Software Foundation, either version 2 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="vertical">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:gravity="center"
+        android:paddingTop="4dip"
+        android:orientation="horizontal"
+        >
+
+        <ImageButton 
+            android:id="@+id/rewindBtn" 
+            style="@android:style/MediaButton.Rew" 
+            android:contentDescription="@string/media_rewind_description"
+            />
+        <ImageButton 
+            android:id="@+id/playBtn" 
+            style="@android:style/MediaButton.Play" 
+            android:contentDescription="@string/media_play_pause_description"
+            />
+        <ImageButton 
+            android:id="@+id/forwardBtn" 
+            style="@android:style/MediaButton.Ffwd" 
+            android:contentDescription="@string/media_forward_description"
+            />
+
+    </LinearLayout>
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal">
+
+        <TextView 
+            android:id="@+id/currentTimeText"
+            android:textSize="14sp"
+            android:textStyle="bold"
+            android:paddingTop="4dip"
+            android:paddingStart="4dip"
+            android:layout_gravity="center_horizontal"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:paddingEnd="4dip"
+            android:text="@string/placeholder_media_time"
+            />
+
+        <SeekBar
+            android:id="@+id/progressBar"
+            style="?android:attr/progressBarStyleHorizontal"
+            android:layout_width="0dip"
+            android:layout_weight="1"
+            android:layout_height="32dip"
+            android:layout_alignParentStart="true"
+            android:layout_alignParentEnd="true" />
+
+        <TextView android:id="@+id/totalTimeText"
+            android:textSize="14sp"
+            android:textStyle="bold"
+            android:paddingTop="4dip"
+            android:paddingEnd="4dip"
+            android:layout_gravity="center_horizontal"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:paddingStart="4dip"
+            android:text="@string/placeholder_media_time"
+            />
+        
+    </LinearLayout>
+
+</LinearLayout>
diff --git a/res/layout/preview_image_activity.xml b/res/layout/preview_image_activity.xml
new file mode 100644 (file)
index 0000000..23af485
--- /dev/null
@@ -0,0 +1,38 @@
+<?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 as published by
+  the Free Software Foundation, either version 2 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical" >
+
+    <android.support.v4.view.ViewPager 
+        android:id="@+id/fragmentPager"
+               android:layout_width="match_parent"
+               android:layout_height="match_parent" 
+               />
+    
+    <!-- LinearLayout
+        android:id="@+id/fragment"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent" >
+            <!- - Preview: layout=@layout/preview_image_fragment - ->
+    </LinearLayout -->
+
+</LinearLayout>
\ No newline at end of file
diff --git a/res/layout/preview_image_fragment.xml b/res/layout/preview_image_fragment.xml
new file mode 100644 (file)
index 0000000..1cd8e04
--- /dev/null
@@ -0,0 +1,67 @@
+<?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 as published by
+  the Free Software Foundation, either version 2 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  
+-->
+
+<!--
+     ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/fdScrollView"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    android:background="@color/owncloud_white" 
+    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/owncloud_white"
+    tools:context=".ui.fragment.PreviewImageFragment" >
+
+    <ProgressBar 
+        android:id="@+id/progressWheel"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:indeterminate="true"
+        android:indeterminateOnly="true"
+        android:layout_centerInParent="true"
+        />
+    
+    <ImageView
+        android:id="@+id/image"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_margin="0dp"
+        android:layout_centerInParent="true"
+        android:contentDescription="@string/preview_image_description"
+        android:src="@drawable/image_fail" />
+    
+    <TextView
+        android:id="@+id/message"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_centerHorizontal="true"
+        android:layout_below="@id/image"
+        android:layout_margin="40dp"
+        android:text="@string/placeholder_sentence"
+        />
+    
+</RelativeLayout>
\ No newline at end of file
index 89d49ab..da5e74b 100644 (file)
@@ -22,7 +22,7 @@
        android:layout_height="wrap_content" android:orientation="vertical"
        android:layout_width="wrap_content" android:background="#fefefe"
        android:gravity="center">
-       <TextView android:layout_width="fill_parent" android:text="Choose upload directory"
+       <TextView android:layout_width="fill_parent" android:text="@string/uploader_top_message"
                android:layout_height="wrap_content" android:id="@+id/textView1" android:textColor="@android:color/black"
                android:gravity="center_horizontal"></TextView>
        <FrameLayout android:layout_height="fill_parent"
diff --git a/res/layout/video_layout.xml b/res/layout/video_layout.xml
new file mode 100644 (file)
index 0000000..8781ad8
--- /dev/null
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<FrameLayout   xmlns:android="http://schemas.android.com/apk/res/android"
+                               android:layout_width="fill_parent"
+                               android:layout_height="fill_parent" >
+
+       <VideoView  android:id="@+id/videoPlayer"
+                               android:layout_width="wrap_content"
+                               android:layout_height="wrap_content"  
+                               android:layout_gravity="center" />
+       
+</FrameLayout>
\ No newline at end of file
diff --git a/res/menu/file_actions_menu.xml b/res/menu/file_actions_menu.xml
new file mode 100644 (file)
index 0000000..bce33eb
--- /dev/null
@@ -0,0 +1,31 @@
+<?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 as published by
+  the Free Software Foundation, either version 2 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+-->
+<menu  xmlns:android="http://schemas.android.com/apk/res/android">
+    
+       <item   android:id="@+id/action_open_file_with"                 android:title="@string/filedetails_open"                        android:icon="@android:drawable/ic_menu_edit"                                   android:orderInCategory="1" />
+       <item   android:id="@+id/action_download_file"                  android:title="@string/filedetails_download"                                                                                                                                            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_remove_file"                    android:title="@string/common_remove"                           android:icon="@android:drawable/ic_menu_delete"                                 android:orderInCategory="1" />
+    <item      android:id="@+id/action_see_details"                    android:title="@string/actionbar_see_details"           android:icon="@android:drawable/ic_menu_view"                                   android:orderInCategory="1" />
+    
+</menu>
diff --git a/res/menu/file_context_menu.xml b/res/menu/file_context_menu.xml
deleted file mode 100644 (file)
index b9bfdb7..0000000
+++ /dev/null
@@ -1,52 +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 as published by
-  the Free Software Foundation, either version 2 of the License, or
-  (at your option) any later version.
-
-  This program is distributed in the hope that it will be useful,
-  but WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-  GNU General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with this program.  If not, see <http://www.gnu.org/licenses/>.
--->
-<menu  xmlns:android="http://schemas.android.com/apk/res/android">
-    
-       <item   android:id="@+id/open_file_item" 
-               android:title="@string/filedetails_open" 
-               android:icon="@android:drawable/ic_menu_edit"
-       />
-       
-       <item   android:id="@+id/download_file_item" 
-               android:title="@string/filedetails_download" 
-       />
-       
-       <item   android:id="@+id/cancel_download_item" 
-               android:title="@string/common_cancel_download" 
-               android:icon="@android:drawable/ic_menu_close_clear_cancel"
-       />
-       
-       <item   android:id="@+id/cancel_upload_item" 
-               android:title="@string/common_cancel_upload" 
-               android:icon="@android:drawable/ic_menu_close_clear_cancel"
-       />
-       
-       <item   android:id="@+id/rename_file_item" 
-               android:title="@string/common_rename" 
-               android:icon="@android:drawable/ic_menu_set_as"
-       />
-       
-    <item      android:id="@+id/remove_file_item" 
-               android:title="@string/common_remove" 
-               android:icon="@android:drawable/ic_menu_delete"
-       />
-    
-</menu>
diff --git a/res/menu/main_menu.xml b/res/menu/main_menu.xml
new file mode 100644 (file)
index 0000000..a3b8d5e
--- /dev/null
@@ -0,0 +1,30 @@
+<?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 as published by
+  the Free Software Foundation, either version 2 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+-->
+<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/action_about_app"           android:title="@string/about_title"             android:icon="@android:drawable/ic_menu_info_details"   android:orderInCategory="2" />
+    
+    <!--  <item android:id="@+id/search" android:title="@string/actionbar_search" android:icon="@drawable/ic_action_search"></item>-->
+</menu>
diff --git a/res/menu/menu.xml b/res/menu/menu.xml
deleted file mode 100644 (file)
index 9ff7342..0000000
+++ /dev/null
@@ -1,30 +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 as published by
-  the Free Software Foundation, either version 2 of the License, or
-  (at your option) any later version.
-
-  This program is distributed in the hope that it will be useful,
-  but WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-  GNU General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with this program.  If not, see <http://www.gnu.org/licenses/>.
--->
-<menu
-  xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:id="@+id/startSync" android:title="@string/actionbar_sync" android:icon="@drawable/ic_action_refresh"></item>
-    <item android:id="@+id/createDirectoryItem" android:title="@string/actionbar_mkdir" android:icon="@drawable/ic_action_create_dir"></item>
-    
-    <!--  <item android:id="@+id/search" android:title="@string/actionbar_search" android:icon="@drawable/ic_action_search"></item>-->
-    <item android:id="@+id/action_upload" android:title="@string/actionbar_upload" android:icon="@drawable/ic_action_upload"></item>
-    <item android:id="@+id/action_settings" android:title="@string/actionbar_settings" android:icon="@android:drawable/ic_menu_preferences"></item>
-    <item android:id="@+id/about_app" android:title="@string/about_title" android:icon="@android:drawable/ic_menu_info_details"></item>
-</menu>
diff --git a/res/values-af-rZA/strings.xml b/res/values-af-rZA/strings.xml
new file mode 100644 (file)
index 0000000..6834437
--- /dev/null
@@ -0,0 +1,9 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<resources>
+  <string name="main_settings">Instellings</string>
+  <string name="actionbar_settings">Instellings</string>
+  <string name="auth_username">Gebruikersnaam</string>
+  <string name="auth_password">Wagwoord</string>
+  <string name="setup_hint_username">Gebruikersnaam</string>
+  <string name="setup_hint_password">Wagwoord</string>
+</resources>
diff --git a/res/values-be/strings.xml b/res/values-be/strings.xml
new file mode 100644 (file)
index 0000000..c757504
--- /dev/null
@@ -0,0 +1,2 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<resources/>
index ff667b7..aec32fd 100644 (file)
@@ -14,6 +14,7 @@
   <string name="actionbar_upload">Качване</string>
   <string name="actionbar_upload_files">Файлове</string>
   <string name="actionbar_settings">Настройки</string>
+  <string name="prefs_category_general">Общи</string>
   <string name="auth_host_url">Уеб адрес</string>
   <string name="auth_password">Парола</string>
   <string name="sync_string_files">Файлове</string>
@@ -21,6 +22,7 @@
   <string name="uploader_btn_upload_text">Качване</string>
   <string name="uploader_wrn_no_account_quit_btn_text">Изход</string>
   <string name="filedetails_download">Изтегляне</string>
+  <string name="common_cancel_upload">Спри качването</string>
   <string name="common_error">Грешка</string>
   <string name="sync_string_contacts">Контакти</string>
   <string name="common_share">Споделяне</string>
index 0646f11..77a5a82 100644 (file)
@@ -53,6 +53,7 @@
   <string name="setup_title">Mit Ihrer %1$s verbinden</string>
   <string name="setup_btn_connect">Verbinden</string>
   <string name="uploader_btn_upload_text">Hochladen</string>
+  <string name="uploader_top_message">Wähle Zielverzeichnis:</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>
@@ -82,6 +83,8 @@
   <string name="common_save_exit">Speichern &amp; Schließen</string>
   <string name="common_exit">%1$s verlassen</string>
   <string name="common_error">Fehler</string>
+  <string name="common_loading">Wird geladen &#8230;</string>
+  <string name="common_error_unknown">Unbekannter Fehler</string>
   <string name="about_title">Über</string>
   <string name="delete_account">Account löschen</string>
   <string name="create_account">Account erstellen</string>
   <string name="downloader_download_succeeded_content">%1$s wurde erfolgreich heruntergeladen</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="common_choose_account">Konto auswählen</string>
   <string name="sync_string_contacts">Kontakte</string>
   <string name="sync_fail_ticker">Synchronisation fehlgeschlagen</string>
   <string name="pincode_wrong">Falsche App-PIN</string>
   <string name="pincode_removed">Die App-PIN wurde entfernt</string>
   <string name="pincode_stored">Die App-PIN wurde gespeichert</string>
+  <string name="media_notif_ticker">"%1$s Musik Player"</string>
+  <string name="media_state_playing">"%1$s (wird abgespielt)"</string>
+  <string name="media_state_loading">"%1$s (wird geladen)"</string>
+  <string name="media_event_done">"%1$s Wiedergabe beendet"</string>
+  <string name="media_err_nothing_to_play">Keine Media-Datei gefunden</string>
+  <string name="media_err_no_account">Ungültiger Account</string>
+  <string name="media_err_not_in_owncloud">Datei ist nicht in einem gültigen Account</string>
+  <string name="media_err_unsupported">Nicht unterstützter Medien-Codec</string>
+  <string name="media_err_io">Media-Datei konnte nicht gelesen werden</string>
+  <string name="media_err_malformed">Die Media-Datei ist noch nicht kodiert</string>
+  <string name="media_err_timeout">Zeitüberschreitung ist beim Abspielen aufgetreten</string>
+  <string name="media_err_invalid_progressive_playback">Media-Datei konnte nicht gestreamt werden</string>
+  <string name="media_err_unknown">Media-Datei kann nicht vom Standard Player wiedergegeben werden</string>
+  <string name="media_err_security_ex">Sicherheits-Fehler ist beim Abspielen aufgetreten %1$s</string>
+  <string name="media_err_io_ex">Eingabe-Fehler ist beim Abspielen aufgetreten %1$s</string>
+  <string name="media_err_unexpected">Unerwarteter Fehler bei der Wiedergabe %1$s</string>
+  <string name="media_rewind_description">Zurückspulen</string>
+  <string name="media_play_pause_description">Wiedergabe oder Pause</string>
+  <string name="media_forward_description">Vorspulen</string>
+       
   <string-array name="prefs_trackmydevice_intervall_keys">
     <item>15 Minuten</item>
     <item>30 Minuten</item>
   <string name="extensions_avail_title">Erweiterung verfügbar!</string>
   <string name="extensions_avail_message">Scheinbar unterstützt Ihr Server weitere Erweiterungen. Möchten Sie die verfügbaren Erweiterungen für Android sehen?</string>
   <string name="fd_keep_in_sync">Datei aktuell halten</string>
-  <string name="common_share">Freigeben</string>
+  <string name="common_share">Teilen</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="conflict_keep_both">Beide behalten</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">Das Bild kann nicht angezeigt werden</string>
+  <string name="preview_image_error_out_of_memory">"Nicht genug Speicherplatz um das Bild anzuzeigen</string>
   
   <string name="actionbar_failed_instant_upload">Fehlgeschlagene Sofortuploads</string>  
   <string name="failed_upload_headline_text">Fehlgeschlagene Sofortuploads</string>
index 98f042f..8013575 100644 (file)
@@ -53,6 +53,7 @@
   <string name="setup_title">Mit Deiner %1$s verbinden</string>
   <string name="setup_btn_connect">Verbinden</string>
   <string name="uploader_btn_upload_text">Hochladen</string>
+  <string name="uploader_top_message">Wähle Zielverzeichnis:</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>
   <string name="sync_fail_ticker">Synchronisation fehlgeschlagen</string>
   <string name="sync_fail_content">Bei der Synchronisation konnte %1$s nicht übertragen werden</string>
   <string name="sync_conflicts_in_favourites_ticker">Konflikte gefunden</string>
-  <string name="sync_conflicts_in_favourites_content">%1$d synchrongehaltene Dateien konnte nicht synchronisiert werden.</string>
-  <string name="sync_fail_in_favourites_ticker">Synchronhalten schlug fehl.</string>
+  <string name="sync_conflicts_in_favourites_content">%1$d synchron zu haltende Dateien konnte nicht synchronisiert werden.</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="use_ssl">Sichere Verbindung benutzen</string>
   <string name="location_no_provider">%1$s kann Dein Gerät nicht verfolgen. Bitte überprüfe Deine Standorteinstellungen</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="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="ssl_validator_title">Warnung</string>
index 94e7fd9..7b3f760 100644 (file)
@@ -59,7 +59,7 @@
   <string name="uploader_wrn_no_account_quit_btn_text">Irten</string>
   <string name="uploader_wrn_no_content_title">Ez dago igotzeko edukirik</string>
   <string name="uploader_wrn_no_content_text">Ez da edukirik jaso. Ez dago ezer igotzeko.</string>
-  <string name="uploader_error_forbidden_content">ownCloudek ez du baimenik partekatutako edukian sartzeko</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="uploader_btn_create_dir_text">Sortu igotzeko karpeta bat</string>
   <string name="file_list_empty">Ez dago fitxategirik karpeta honetan.\nFitxategi berriak \"Igo\" menu aukerarekin gehi daitezke.</string>
   <string name="ssl_validator_label_ST">Estatua:</string>
   <string name="ssl_validator_label_L">Kokapena:</string>
   <string name="ssl_validator_label_validity">Baliozkotasuna:</string>
+  <string name="ssl_validator_label_validity_from">Noiztik:</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="text_placeholder">Hau leku-marka da</string>
index e51845b..50fb8e3 100644 (file)
   <string name="main_settings">تنظیمات</string>
   <string name="main_tit_accsetup">نصب حساب کاربری</string>
   <string name="main_wrn_accsetup">حساب کاربری ownCloud در دستگاه شما وجود ندارد. برای استفاده از این برنامه می‌بایست یکی ایجاد کنید.</string>
+  <string name="actionbar_sync">بازنمایی</string>
   <string name="actionbar_upload">بارگزاری</string>
   <string name="actionbar_upload_files">پرونده‌ها</string>
   <string name="actionbar_mkdir">ایجاد پوشه</string>
   <string name="actionbar_search">جست‌و‌جو</string>
   <string name="actionbar_settings">تنظیمات</string>
   <string name="prefs_category_general">عمومی</string>
+  <string name="prefs_category_trackmydevice">ردیابی دستگاه</string>
+  <string name="prefs_add_session">ایجاد جلسه جدید</string>
+  <string name="prefs_create_img_thumbnails">ایجاد پیش نمایش تصاویر</string>
   <string name="prefs_select_oc_account">انتخاب یک حساب</string>
+  <string name="prefs_trackmydevice">ردیابی دستگاه</string>
+  <string name="prefs_trackmydevice_summary_off">برنامه را فعال کنید تا محل دستگاه شما پیگیری شود</string>
+  <string name="prefs_trackmydevice_interval">به روز رسانی بازه</string>
   <string name="prefs_accounts">حساب‌ها</string>
   <string name="auth_host_url">آدرس ownCloud </string>
   <string name="auth_username">نام کاربری</string>
   <string name="uploader_wrn_no_content_title">هیچ مطلبی بارگزاری نشده‌ است</string>
   <string name="uploader_wrn_no_content_text">هیچ مطلبی دریافت نشده است. هیچ‌‌چیزی بارگزاری نشده.</string>
   <string name="uploader_info_uploading">در حال بارگزاری</string>
+  <string name="uploader_btn_create_dir_text">ایجاد دایرکتوری برای بارگذاری</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_redownload">بارگزاری دوباره</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="downloader_download_succeeded_ticker">بارگیری موفقیت‌آمیز بود</string>
   <string name="downloader_download_failed_ticker">بارگیری ناموفق بود</string>
   <string name="sync_string_contacts">ارتباط‌ها</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_login_details">جزئیات ورود</string>
   <string name="crashlog_send_report">ارسال گزارش</string>
   <string name="crashlog_dont_send_report">گزارش را ارسال نکن</string>
   <string name="common_share">اشتراک‌گزاری</string>
   <string name="common_rename">تغییرنام</string>
   <string name="common_remove">حذف</string>
+  <string name="confirmation_remove_remote">پاک کردن از سرور</string>
   <string name="wait_a_moment">لحظه‌ای صبر کنید</string>
   <string name="filedisplay_no_file_selected">هیچ پرونده‌ای انتخاب نشده است</string>
   <string name="ssl_validator_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="instant_upload_on_wifi">تصاویر را فقط از طریق wifi بارگذاری کن</string>
 </resources>
index ab6541d..280ca69 100644 (file)
@@ -72,6 +72,7 @@
   <string name="filedetails_sync_file">Päivitä</string>
   <string name="filedetails_redownload">Lataa uudelleen</string>
   <string name="filedetails_open">Avaa</string>
+  <string name="filedetails_renamed_in_upload_msg">Tiedoston nimeksi muutettiin %1$s siirron yhteydessä</string>
   <string name="common_yes">Kyllä</string>
   <string name="common_no">Ei</string>
   <string name="common_ok">OK</string>
   <string name="sync_fail_ticker">Synkronointi epäonnistui</string>
   <string name="sync_fail_content">Kohteen %1$s synkronointia ei voitu suorittaa loppuun</string>
   <string name="sync_conflicts_in_favourites_ticker">Ristiriitoja löytynyt</string>
+  <string name="sync_conflicts_in_favourites_content">%1$d \"pidä synkronoituna\" tiedostoja ei voitu synkronoida</string>
+  <string name="sync_fail_in_favourites_ticker">\"Pidä synkronoituna\" epäonnistui</string>
+  <string name="sync_fail_in_favourites_content">Hakemiston %1$d tiedostoja ei voitu synkronoida (%2$d konfliktia)</string>
   <string name="use_ssl">Käytä salattua yhteyttä</string>
   <string name="location_no_provider">ownCloud ei voi jäljittää laitettasi. Tarkista laitteesi sijaintiasetukset</string>
   <string name="pincode_enter_pin_code">Aseta sovelluksesi PIN</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_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="confirmation_remove_remote_and_local">Sekä etä- että paikallinen</string>
   <string name="remove_success_msg">Poistettu onnistuneesti</string>
   <string name="rename_dialog_title">Anna uusi nimi</string>
   <string name="rename_local_fail_msg">Paikallista kopiota ei voitu uudelleennimetä; yritä eri nimellä</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="wait_a_moment">Odota hetki</string>
   <string name="filedisplay_unexpected_bad_get_content">Odottamaton ongelma; kokeile valita tiedosto toisella sovelluksella</string>
   <string name="ssl_validator_header">Sivuston identiteetin vahvistaminen ei onnistunut</string>
   <string name="ssl_validator_reason_cert_not_trusted">- Palvelimen varmenteeseen ei luoteta</string>
   <string name="ssl_validator_reason_cert_expired">- Palvelimen varmenne on vanhentunut</string>
+  <string name="ssl_validator_reason_cert_not_yet_valid">- Palvelimen varmenteen kelvolliset päivät ovat tulevaisuudessa</string>
+  <string name="ssl_validator_reason_hostname_not_verified">- Osoite ei vastaa sertifikaatissa mainittua isäntänimeä</string>
   <string name="ssl_validator_certificate_not_available">Palvelimen varmenteen noutaminen epäonnistui</string>
   <string name="ssl_validator_question">Haluatko silti luottaa tähän varmenteeseen?</string>
   <string name="ssl_validator_not_saved">Varmenteen tallennus epäonnistui</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="text_placeholder">Tämä on paikkavaraus</string>
   <string name="instant_upload_on_wifi">Lähetä kuvat vain WiFi-verkossa</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>
index f5d0dfd..4cf5de2 100644 (file)
@@ -4,7 +4,7 @@
   <string name="main_password">Contrasinal:</string>
   <string name="main_login">Nome de usuario:</string>
   <string name="main_button_login">Acceso</string>
-  <string name="main_welcome">Benvido/a a ownCloud</string>
+  <string name="main_welcome">Benvido/a</string>
   <string name="main_files">Ficheiros</string>
   <string name="main_music">Música</string>
   <string name="main_contacts">Contactos</string>
   <string name="main_bookmarks">Marcadores</string>
   <string name="main_settings">Preferencias</string>
   <string name="main_tit_accsetup">Activar a conta</string>
-  <string name="main_wrn_accsetup">Non hai contas de ownCloud no teu dispositivo. Para empregar o aplicativos necesitas crear unha.</string>
-  <string name="about_message">O cliente de ownCloud para Android\n\nversion: %1$s</string>
+  <string name="main_wrn_accsetup">Non hai ningunha conta configurada no seu dispositivo. Para empregar o aplicativo necesita crear unha.</string>
+  <string name="about_message">O aplicativo  %1$s para Android\n\nversión: %2$s</string>
   <string name="actionbar_sync">Actualizar</string>
-  <string name="actionbar_upload">Subir</string>
+  <string name="actionbar_upload">Enviar</string>
   <string name="actionbar_upload_from_apps">Contido doutros aplicativos</string>
   <string name="actionbar_upload_files">Ficheiros</string>
   <string name="actionbar_mkdir">Crear un directorio</string>
   <string name="prefs_add_session">Engadir unha nova sesión</string>
   <string name="prefs_create_img_thumbnails">Crear miniaturas das imaxes</string>
   <string name="prefs_select_oc_account">Escoller unha conta</string>
-  <string name="prefs_summary_select_oc_account">Escolle cal das túas contas ten que usar o aplicativo.</string>
+  <string name="prefs_summary_select_oc_account">Escolla cal das súas contas ten que usar o aplicativo.</string>
   <string name="prefs_trackmydevice">Rastrexamento do dispositivo</string>
-  <string name="prefs_trackmydevice_summary_off">Permitir que ownCloud rexistre as posicións do teu dispositivo</string>
-  <string name="prefs_trackmydevice_summary_on">O teu ownCloud mantén o rexistro de posicións do teu dispositivo</string>
+  <string name="prefs_trackmydevice_summary_off">Permitir que este aplicativo rexistre as posicións do seu dispositivo</string>
+  <string name="prefs_trackmydevice_summary_on">Este aplicativo mantén o rexistro de posicións do seu dispositivo</string>
   <string name="prefs_trackmydevice_interval">Intervalo de actualizacións</string>
   <string name="prefs_trackmydevice_interval_summary">Actualizar cada %1$s minutos</string>
   <string name="prefs_accounts">Contas</string>
   <string name="prefs_manage_accounts">Xestionar as contas</string>
-  <string name="prefs_pincode">PIN do aplicativo ownCloud</string>
-  <string name="prefs_pincode_summary">Protexe o teu cliente de ownCloud</string>
-  <string name="prefs_instant_upload">Activar a subida instantánea</string>
-  <string name="prefs_instant_upload_summary">Subir instantaneamente as fotos sacadas coa cámara</string>
-  <string name="auth_host_url">URL de ownCloud</string>
+  <string name="prefs_pincode">PIN do aplicativo</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_summary">Enviar instantaneamente as fotos tiradas coa cámara</string>
+  <string name="auth_host_url">URL</string>
   <string name="auth_username">Nome de usuario</string>
   <string name="auth_password">Contrasinal</string>
-  <string name="auth_register">Son novo en ownCloud</string>
-  <string name="new_session_uri_error">Deuse unha URL errada</string>
-  <string name="new_session_session_name_error">Usuario de sesión errado</string>
+  <string name="auth_register">Son novo en  %1$s</string>
+  <string name="new_session_uri_error">Deuse un enderezo incorrecto</string>
+  <string name="new_session_session_name_error">Nome de sesión incorrecto</string>
   <string name="sync_string_files">Ficheiros</string>
-  <string name="uploader_no_file_selected">Non se escolleron ficheiros para subir</string>
+  <string name="uploader_no_file_selected">Non se escolleron ficheiros para enviar</string>
   <string name="setup_hint_username">Nome de usuario</string>
   <string name="setup_hint_password">Contrasinal</string>
-  <string name="setup_hint_address">Dirección web</string>
-  <string name="setup_hint_show_password">Mostrar o contrasinal?</string>
-  <string name="setup_title">Conectar co teu ownCloud</string>
+  <string name="setup_hint_address">Enderezo web</string>
+  <string name="setup_hint_show_password">Amosar o contrasinal?</string>
+  <string name="setup_title">Conectar co seu %1$s</string>
   <string name="setup_btn_connect">Conectar</string>
-  <string name="uploader_btn_upload_text">Subir</string>
+  <string name="uploader_btn_upload_text">Enviar</string>
   <string name="uploader_wrn_no_account_title">Non se atoparon contas</string>
-  <string name="uploader_wrn_no_account_text">Non hai contas de ownCloud no teu dispositivo. Crea unha nova conta primeiro.</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>
   <string name="uploader_wrn_no_account_quit_btn_text">Saír</string>
-  <string name="uploader_wrn_no_content_title">Non hai contido para subir</string>
+  <string name="uploader_wrn_no_content_title">Non hai contido para enviar</string>
   <string name="uploader_wrn_no_content_text">Non se recibiu contido. Non hai nada para enviar.</string>
-  <string name="uploader_error_forbidden_content">Non se lle permite a ownCloud a que acceda ao contido compartido</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="uploader_btn_create_dir_text">Crear un directorio para os envíos</string>
-  <string name="file_list_empty">Non hai ficheiros neste cartafol.\nOs novos ficheiros pódense engadir ca opción do menú «Subir»</string>
-  <string name="filedetails_select_file">Déalle a un ficheiro para que mostre a información adicional</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="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>
   <string name="filedetails_created">Creado:</string>
   <string name="filedetails_modified">Modificado:</string>
-  <string name="filedetails_download">Baixar</string>
+  <string name="filedetails_download">Descargar</string>
   <string name="filedetails_sync_file">Actualizar</string>
-  <string name="filedetails_redownload">Actualizar</string>
+  <string name="filedetails_redownload">Descargar de novo</string>
   <string name="filedetails_open">Abrir</string>
-  <string name="filedetails_renamed_in_upload_msg">O ficheiroi renomeouse a %1$s durante a subida</string>
+  <string name="filedetails_renamed_in_upload_msg">O ficheiro foi renomeado a %1$s durante o envío</string>
   <string name="common_yes">Si</string>
   <string name="common_no">Non</string>
   <string name="common_ok">Aceptar</string>
   <string name="common_cancel_download">Cancelar a descarga</string>
-  <string name="common_cancel_upload">Cancelar a subida</string>
+  <string name="common_cancel_upload">Cancelar o envío</string>
   <string name="common_cancel">Cancelar</string>
-  <string name="common_save_exit">Gardar &amp; Saír</string>
-  <string name="common_exit">Saír de ownCloud</string>
+  <string name="common_save_exit">Gardar e saír</string>
+  <string name="common_exit">Abandonar %1$s</string>
   <string name="common_error">Erro</string>
-  <string name="about_title">Acerca de</string>
+  <string name="about_title">Sobre</string>
   <string name="delete_account">Eliminar a conta</string>
-  <string name="create_account">Crear a conta</string>
-  <string name="upload_chooser_title">Subir desde...</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_upload_in_progress_ticker">Subindo...</string>
-  <string name="uploader_upload_in_progress_content">%1$d%% Subindo %2$s</string>
-  <string name="uploader_upload_succeeded_ticker">Subiuse correctamente</string>
-  <string name="uploader_upload_succeeded_content_single">%1$s subiuse correctamente</string>
-  <string name="uploader_upload_succeeded_content_multiple">Os ficheiros %1$d subíronse correctamente</string>
-  <string name="uploader_upload_failed_ticker">Fallou o envío</string>
-  <string name="uploader_upload_failed_content_single">O envío de %1$s non se puido completar</string>
-  <string name="uploader_upload_failed_content_multiple">Fallou o envío: subíronse %1$d/%2$d ficheiros</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="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_succeeded_content_multiple">%1$d ficheiros foron enviados 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_content_multiple">Produciuse un fallou no envío: enviáronse %1$d/%2$d ficheiros</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_succeeded_content">%1$s descargouse correctamente</string>
-  <string name="downloader_download_failed_ticker">Fallou a descarga</string>
-  <string name="downloader_download_failed_content">Non se puido completar a descarga de %1$s</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="common_choose_account">Escoller unha conta</string>
   <string name="sync_string_contacts">Contactos</string>
-  <string name="sync_fail_ticker">Fallou a sincronización</string>
-  <string name="sync_fail_content">Non se puido rematar a sincronización de %1$s</string>
+  <string name="sync_fail_ticker">Produciuse un fallo na sincronización</string>
+  <string name="sync_fail_content">Non foi posíbel completar a sincronización de %1$s</string>
   <string name="sync_conflicts_in_favourites_ticker">Atopáronse conflictos</string>
-  <string name="sync_conflicts_in_favourites_content">%1$d ficheiros de kept-in-sync non se puideron sincronizar</string>
-  <string name="sync_fail_in_favourites_ticker">Fallou a sincronización de ficheiros Kept-in-sync</string>
-  <string name="sync_fail_in_favourites_content">Os contidos dos ficheiros %1$d non se puideron sincronizar (%1$d conflictos)</string>
+  <string name="sync_conflicts_in_favourites_content">Non foi posíbel sincronizar %1$d ficheiros «kept-in-sync»</string>
+  <string name="sync_fail_in_favourites_ticker">Produciuse un fallou ao sincronizar ficheiros «kept-in-sync»</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="use_ssl">Empregar a conexión segura</string>
-  <string name="location_no_provider">ownCloud non pode seguir o teu dispositivo. Comproba as configuracións de de localización.</string>
-  <string name="pincode_enter_pin_code">Introduce o teu PIN de aplicación</string>
-  <string name="pincode_enter_new_pin_code">Introduce o teu PIN da app</string>
-  <string name="pincode_configure_your_pin">Introduce o PIN da app ownCloud</string>
-  <string name="pincode_configure_your_pin_explanation">Pedirase o PIN cada vez que se inicie o aplicativo</string>
-  <string name="pincode_reenter_your_pincode">Volve a introducir o PIN da app ownCloud</string>
-  <string name="pincode_remove_your_pincode">Elimina o PIN da app ownCloud</string>
-  <string name="pincode_mismatch">Os dous PIN da app ownCloud non son iguais</string>
-  <string name="pincode_wrong">PIN incorrecto da app ownCloud</string>
-  <string name="pincode_removed">Eliminouse o PIN da app ownCloud</string>
-  <string name="pincode_stored">Almacenouse o PIN da app ownCloud</string>
+  <string name="location_no_provider">%1$s non pode rastrexar o seu dispositivo. Comprobe as configuracións de localización.</string>
+  <string name="pincode_enter_pin_code">Insira o seu PIN do aplicativo</string>
+  <string name="pincode_enter_new_pin_code">Insira o seu novo 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-array name="prefs_trackmydevice_intervall_keys">
     <item>15 minutos</item>
     <item>30 minutos</item>
     <item>30</item>
     <item>60</item>
   </string-array>
-  <string name="auth_trying_to_login">Intentando acceder...</string>
+  <string name="auth_trying_to_login">Tentando acceder…</string>
   <string name="auth_no_net_conn_title">Sen conexión de rede</string>
-  <string name="auth_no_net_conn_message">Non se detectaron conexións a rede. Comproba a conexión a internet e proba de novo.</string>
+  <string name="auth_no_net_conn_message">Non se detectaron conexións de rede. Comprobe a conexión a Internet e tenteo de novo.</string>
   <string name="auth_connect_anyway">Conectar igualmente</string>
   <string name="auth_nossl_plain_ok_title">Non hai conexión seguras dispoñíbeis.</string>
-  <string name="auth_nossl_plain_ok_message">O aplicativo non puido facer unha conexión segura co servidor. Inda que non é segura, hai unha conexión posíbel. Podes continuar ou cancelala.</string>
+  <string name="auth_nossl_plain_ok_message">O aplicativo non puido facer unha conexión segura co servidor. Inda que non é segura, hai unha conexión posíbel. Pode continuar ou cancelala.</string>
   <string name="auth_connection_established">Estabeleceuse a conexión</string>
-  <string name="auth_testing_connection">Comprobando a conexión...</string>
-  <string name="auth_not_configured_title">Configuración errada de ownCloud</string>
-  <string name="auth_not_configured_message">Semella que a túa instancia de ownCloud non está configurada correctamente. Contacta co teu administrador para máis detalles.</string>
-  <string name="auth_unknown_error_title">Ocorreu un erro descoñecido!</string>
-  <string name="auth_unknown_error_message">Ocorreu un erro descoñecido. Contacta cos autores e infórmaos do fallo cos rexistros de erro do teu dispositivo.</string>
-  <string name="auth_unknown_host_title">Non atopou o servidor</string>
-  <string name="auth_unknown_host_message">Non se puido atopar o servidor que se indicou. Comproba o nome do host e proba de novo.</string>
-  <string name="auth_incorrect_path_title">Non se atopa unha instancia de ownCloud</string>
-  <string name="auth_incorrect_path_message">O aplicativo non atopou instancias de ownCloud na rua que se indicou. Comproba a ruta e proba de novo.</string>
-  <string name="auth_timeout_title">O servidor tardou en responder</string>
-  <string name="auth_incorrect_address_title">URL mal formada</string>
-  <string name="auth_ssl_general_error_title">Fallou a inicialización de SSL</string>
-  <string name="auth_ssl_unverified_server_title">Non se verificou a identidade do servidor SSL</string>
-  <string name="auth_bad_oc_version_title">Versión do servidor de ownCloud non recoñecida</string>
-  <string name="auth_wrong_connection_title">Non se pode establecer a conexión</string>
-  <string name="auth_secure_connection">Fíxose unha conexión segura</string>
+  <string name="auth_testing_connection">Comprobando a conexión</string>
+  <string name="auth_not_configured_title">Configuración errada do servidor</string>
+  <string name="auth_not_configured_message">Semella que a súa instancia do servidor non está configurada correctamente. Contacte co seu administrador para máis detalles.</string>
+  <string name="auth_unknown_error_title">Produciuse un erro descoñecido!</string>
+  <string name="auth_unknown_error_message">Produciuse un erro descoñecido. Contacte cos autores e infórmeos do fallo cos rexistros de erro do seu dispositivo.</string>
+  <string name="auth_unknown_host_title">Non foi posíbel atopar a máquina</string>
+  <string name="auth_unknown_host_message">Non foi posíbel atopar a máquina indicada. Comprobe o nome da máquina e tenteo de novo.</string>
+  <string name="auth_incorrect_path_title">Non se atopou unha instancia do servidor</string>
+  <string name="auth_incorrect_path_message">O aplicativo non atopou instancias do servidor na ruta indicada. Comprobe a ruta e tenteo de novo.</string>
+  <string name="auth_timeout_title">O servidor tardou demasiado en responder</string>
+  <string name="auth_incorrect_address_title">URL incorrecto</string>
+  <string name="auth_ssl_general_error_title">Produciuse un fallo ao iniciar o SSL</string>
+  <string name="auth_ssl_unverified_server_title">A identidade SSL do servidor non foi verficada</string>
+  <string name="auth_bad_oc_version_title">Versión do servidor non recoñecida</string>
+  <string name="auth_wrong_connection_title">Non é posíbel estabelecer a conexión</string>
+  <string name="auth_secure_connection">Estabeleceuse unha conexión segura</string>
   <string name="auth_login_details">Detalles do acceso</string>
   <string name="auth_unauthorized">Usuario ou contrasinal incorrectos</string>
-  <string name="auth_not_found">Deuse unha ruta errada</string>
-  <string name="auth_internal">Erro interno do servidor, código %1$d</string>
-  <string name="crashlog_message">O aplicativo deixou de funcionar de xeito inesperado. Queres enviar un informe desta quebra?</string>
-  <string name="crashlog_send_report">Envíar un informe</string>
-  <string name="crashlog_dont_send_report">Non envíar un informe</string>
-  <string name="extensions_avail_title">Engadido dispoñíbel!</string>
-  <string name="extensions_avail_message">Semella que a túa instancia de ownCloud non soporta engadidos avanzados. Queres ver se hai engadidos dispoñíbeis para Android?</string>
-  <string name="fd_keep_in_sync">Manter o ficheiro ao día</string>
+  <string name="auth_not_found">Deuse unha ruta incorrecta</string>
+  <string name="auth_internal">Produciuse un erro interno do servidor, código %1$d</string>
+  <string name="crashlog_message">O aplicativo deixou de funcionar de xeito inesperado. Quere enviar un informe desta quebra?</string>
+  <string name="crashlog_send_report">Enviar un informe</string>
+  <string name="crashlog_dont_send_report">Non enviar un informe</string>
+  <string name="extensions_avail_title">Extensión dispoñíbel!</string>
+  <string name="extensions_avail_message">Semella que a súa instancia do servidor admite extensións avanzadas. Quere ver se hai extensións dispoñíbeis para Android ?</string>
+  <string name="fd_keep_in_sync">Manter actualizado o ficheiro</string>
   <string name="common_share">Compartir</string>
   <string name="common_rename">Renomear</string>
-  <string name="common_remove">Eliminar</string>
-  <string name="confirmation_remove_alert">Queres eliminar %1$s ?</string>
-  <string name="confirmation_remove_folder_alert">Seguro que queres eliminar %1$s e o seu contido?</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_local">Só local</string>
   <string name="confirmation_remove_folder_local">Só contidos locais</string>
-  <string name="confirmation_remove_remote">Eliminar do servidor</string>
+  <string name="confirmation_remove_remote">Retirar do servidor</string>
   <string name="confirmation_remove_remote_and_local">Remoto e local</string>
-  <string name="remove_success_msg">Eliminouse correctamente</string>
-  <string name="remove_fail_msg">Non se puido eliminar completamente</string>
-  <string name="rename_dialog_title">Inrtoducir un novo nome</string>
-  <string name="rename_local_fail_msg">Non se lle puido cambiar o nome a copia local. Proba con outro nome diferente.</string>
-  <string name="rename_server_fail_msg">Non se rematou o cambio de nome</string>
-  <string name="sync_file_fail_msg">Non se puido comprobar o ficheiro remoto</string>
+  <string name="remove_success_msg">Retirado correctamente</string>
+  <string name="remove_fail_msg">Non foi posíbel retiralo</string>
+  <string name="rename_dialog_title">Introducir un novo nome</string>
+  <string name="rename_local_fail_msg">Non foi posíbel cambiarlle o nome á copia local. Proba con outro nome diferente.</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 se puido crear o directorio</string>
-  <string name="wait_a_moment">Agarda un momento</string>
-  <string name="filedisplay_unexpected_bad_get_content">Erro inesperado. Escolle outro aplicativo para seleccionar o ficheiro.</string>
+  <string name="create_dir_fail_msg">Non foi posíbel crear o directorio</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_no_file_selected">Non se escolleu ningún ficheiro</string>
-  <string name="ssl_validator_title">Advertencia</string>
-  <string name="ssl_validator_header">A identidade do sitio non se puido verificar</string>
-  <string name="ssl_validator_reason_cert_not_trusted">Non se confía no certificado do servidor</string>
-  <string name="ssl_validator_reason_cert_expired">O certificado do servidor caducou</string>
-  <string name="ssl_validator_reason_cert_not_yet_valid">O certificado do servidor é moi novo</string>
-  <string name="ssl_validator_reason_hostname_not_verified">A URL non coincide co nome de host do certificado</string>
-  <string name="ssl_validator_certificate_not_available">Non se puido obter o certificado do servidor</string>
-  <string name="ssl_validator_question">Queres confiar neste certificado igualmente?</string>
-  <string name="ssl_validator_not_saved">Non se puido gardar o certificado</string>
+  <string name="ssl_validator_title">Aviso</string>
+  <string name="ssl_validator_header">Non foi posíbel verificar a identidade do sitio</string>
+  <string name="ssl_validator_reason_cert_not_trusted">- O certificado do servidor non é de confianza</string>
+  <string name="ssl_validator_reason_cert_expired">O certificado do servidor caducou</string>
+  <string name="ssl_validator_reason_cert_not_yet_valid">- As datas de validez do certificado están son do futuro</string>
+  <string name="ssl_validator_reason_hostname_not_verified">- O URL non coincide co nome de máquina no certificado</string>
+  <string name="ssl_validator_certificate_not_available">Non foi posíbel obter o certificado do servidor</string>
+  <string name="ssl_validator_question">Aínda así, quere fiar neste certificado igualmente?</string>
+  <string name="ssl_validator_not_saved">Non foi posíbel gardar o certificado</string>
   <string name="ssl_validator_btn_details_see">Detalles</string>
   <string name="ssl_validator_btn_details_hide">Agochar</string>
   <string name="ssl_validator_label_subject">Emitido para:</string>
   <string name="ssl_validator_label_signature">Sinatura:</string>
   <string name="ssl_validator_label_signature_algorithm">Algoritmo:</string>
   <string name="text_placeholder">Isto é unha marca de posición</string>
-  <string name="instant_upload_on_wifi">Subir imaxes só con WiFi</string>
-  <string name="instant_upload_path">/SubidaInstantánea</string>
-  <string name="conflict_title">Actualizar o conflito</string>
+  <string name="instant_upload_on_wifi">Enviar imaxes só medinte 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_keep_both">Manter ambos</string>
   <string name="conflict_overwrite">Sobrescribir</string>
-  <string name="conflict_dont_upload">Non subir</string>
+  <string name="conflict_dont_upload">Non enviar</string>
 </resources>
index 3daa83c..e70625e 100644 (file)
@@ -1,5 +1,7 @@
 <?xml version='1.0' encoding='UTF-8'?>
 <resources>
+  <string name="main_settings">सेटिंग्स</string>
+  <string name="actionbar_settings">सेटिंग्स</string>
   <string name="auth_username">प्रयोक्ता का नाम</string>
   <string name="auth_password">पासवर्ड</string>
   <string name="setup_hint_username">प्रयोक्ता का नाम</string>
index 0b609e5..396995f 100644 (file)
@@ -4,42 +4,44 @@
   <string name="main_password">Jelszó:</string>
   <string name="main_login">Felhasználói név:</string>
   <string name="main_button_login">Belépés</string>
-  <string name="main_welcome">Üdvözlünk a ownCloud-ban</string>
+  <string name="main_welcome">Üdv</string>
   <string name="main_files">Fájlok</string>
   <string name="main_music">Zene</string>
-  <string name="main_contacts">Kapcsolat</string>
+  <string name="main_contacts">Címjegyzék</string>
   <string name="main_calendar">Naptár</string>
   <string name="main_bookmarks">Könyvjelzők</string>
   <string name="main_settings">Beállítások</string>
   <string name="main_tit_accsetup">Fiók beállítása</string>
-  <string name="main_wrn_accsetup">Nincs beállított fiók a készülékén. Ahhoz hogy használja ezt az App-ot használja, létre kell hozzon egyet.</string>
-  <string name="about_message">%1$s Android alkalmazás⏎ ⏎ verzió: %2$s</string>
+  <string name="main_wrn_accsetup">Nincs beállított fiók a készülékén. Ahhoz, hogy használja ezt a programot, létre kell hozzon egyet.</string>
+  <string name="about_message">%1$s Android alkalmazás\nverzió: %2$s</string>
   <string name="actionbar_sync">Frissítés</string>
   <string name="actionbar_upload">Feltöltés</string>
+  <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_mkdir">Könyvtár létrahozása</string>
+  <string name="actionbar_mkdir">Mappa létrehozása</string>
   <string name="actionbar_search">Keresés</string>
-  <string name="actionbar_settings">beállítások</string>
+  <string name="actionbar_settings">Beállítások</string>
   <string name="prefs_category_general">Általános</string>
   <string name="prefs_category_trackmydevice">Eszközkövetés</string>
   <string name="prefs_add_session">Új munkafolyamat létrehozása</string>
   <string name="prefs_create_img_thumbnails">Bélyegkép készítése</string>
-  <string name="prefs_select_oc_account">Válassz egy felhasználó nevet</string>
-  <string name="prefs_summary_select_oc_account">Válassza ki, hogy az App milyen fiókot használjon.</string>
+  <string name="prefs_select_oc_account">Válasszon egy felhasználónevet</string>
+  <string name="prefs_summary_select_oc_account">Válassza ki, hogy a program milyen fiókot használjon.</string>
   <string name="prefs_trackmydevice">Eszközkövetés</string>
-  <string name="prefs_trackmydevice_summary_off">Engedélyezze ennek az App-nak a helykövetést</string>
-  <string name="prefs_trackmydevice_summary_on">Ez az App eltárolja ennek a készüléknek az útvonalát</string>
-  <string name="prefs_trackmydevice_interval">Frissítés gyakorisága</string>
+  <string name="prefs_trackmydevice_summary_off">Engedélyezze ennek a programnak a helykövetést</string>
+  <string name="prefs_trackmydevice_summary_on">Ez a program eltárolja ennek a készüléknek az útvonalát</string>
+  <string name="prefs_trackmydevice_interval">A frissítés gyakorisága</string>
   <string name="prefs_trackmydevice_interval_summary">Minden %1$s percben</string>
   <string name="prefs_accounts">Fiókok</string>
   <string name="prefs_manage_accounts">Fiókok kezelése</string>
-  <string name="prefs_pincode">ownCloud App PIN</string>
-  <string name="prefs_pincode_summary">Védje meg az ügyfeleit</string>
-  <string name="prefs_instant_upload">Az instant feltöltés engedélyezése</string>
-  <string name="auth_host_url">ownCloud URL</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="auth_host_url">URL</string>
   <string name="auth_username">Felhasználói név</string>
   <string name="auth_password">Jelszó</string>
-  <string name="auth_register">Új vagyok ehhez: %1$s</string>
+  <string name="auth_register">Új kapcsolat: %1$s</string>
   <string name="new_session_uri_error">A megadott cím helytelen</string>
   <string name="new_session_session_name_error">A megadott munkafolyamatnév érvénytelen</string>
   <string name="sync_string_files">Fájlok</string>
@@ -48,7 +50,7 @@
   <string name="setup_hint_password">Jelszó</string>
   <string name="setup_hint_address">Web cím</string>
   <string name="setup_hint_show_password">A jelszó megjelenjen?</string>
-  <string name="setup_title">Kapcsolódás az ownCloud-hoz</string>
+  <string name="setup_title">Kapcsolódás ehhez: %1$s</string>
   <string name="setup_btn_connect">Kapcsolódás</string>
   <string name="uploader_btn_upload_text">Feltöltés</string>
   <string name="uploader_wrn_no_account_title">Nincs ilyen felhasználói fiók</string>
   <string name="uploader_wrn_no_account_setup_btn_text">Beállítás</string>
   <string name="uploader_wrn_no_account_quit_btn_text">Kilépés</string>
   <string name="uploader_wrn_no_content_title">Nincs feltölthető tartalom</string>
-  <string name="uploader_wrn_no_content_text">Nem lett tartalom fogadva. Nincs mit feltölteni.</string>
+  <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="uploader_btn_create_dir_text">Könyvtár létrehozása a feltöltésekhez</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="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>
   <string name="filedetails_modified">Módosítva:</string>
   <string name="filedetails_download">Letöltés</string>
   <string name="filedetails_sync_file">Frissítés</string>
-  <string name="filedetails_redownload">Frissítés</string>
+  <string name="filedetails_redownload">Ismételt letöltés</string>
   <string name="filedetails_open">Megnyitás</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="common_yes">Igen</string>
   <string name="common_no">Nem</string>
   <string name="common_ok">OK</string>
-  <string name="common_cancel_download">Letöltés megszakítása</string>
-  <string name="common_cancel_upload">Feltöltés megszakítása</string>
+  <string name="common_cancel_download">A letöltés megszakítása</string>
+  <string name="common_cancel_upload">A feltöltés megszakítása</string>
   <string name="common_cancel">Mégsem</string>
   <string name="common_save_exit">Mentés &amp; Kilépés</string>
+  <string name="common_exit">%1$s elhagyása</string>
   <string name="common_error">Hiba</string>
   <string name="about_title">Rólunk</string>
   <string name="delete_account">Fiók törlése</string>
   <string name="create_account">Fiók létrehozása</string>
   <string name="upload_chooser_title">Feltöltés innen ...</string>
-  <string name="uploader_info_dirname">Mappa név</string>
-  <string name="uploader_upload_in_progress_ticker">Feltöltve ...</string>
+  <string name="uploader_info_dirname">Mappanév</string>
+  <string name="uploader_upload_in_progress_ticker">Feltöltés ...</string>
   <string name="uploader_upload_in_progress_content">%1$d%% Feltöltés %2$s</string>
-  <string name="uploader_upload_succeeded_ticker">Feltöltés sikerült</string>
+  <string name="uploader_upload_succeeded_ticker">A feltöltés sikerült</string>
   <string name="uploader_upload_succeeded_content_single">%1$s sikeresen fel lett töltve</string>
   <string name="uploader_upload_succeeded_content_multiple">%1$d fájl 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_content_multiple">Hibás feltöltés: %1$d/%2$d fájl feltöltve</string>
-  <string name="downloader_download_in_progress_ticker">Letöltése ...</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_succeeded_content">%1$s sikeresen letöltve</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="common_choose_account">Válasz azonosítót</string>
-  <string name="sync_string_contacts">Kapcsolat</string>
+  <string name="common_choose_account">Válasszon azonosítót</string>
+  <string name="sync_string_contacts">Címtár</string>
   <string name="sync_fail_ticker">A szinkronizálás sikertelen</string>
+  <string name="sync_fail_content">%1$s szinkronizációját nem sikerült befejezni</string>
+  <string name="sync_conflicts_in_favourites_ticker">Ütközések vannak</string>
+  <string name="sync_conflicts_in_favourites_content">%1$d szinkronizálandó állományokat nem sikerült szinkronizálni</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="use_ssl">Biztonságos kapcsolat használata</string>
   <string name="location_no_provider">%1$s nem tudja követni az eszközét. Kérem ellenőrizze a helybeállításait</string>
-  <string name="pincode_enter_pin_code">Kérlek add meg az App PIN kódját</string>
-  <string name="pincode_enter_new_pin_code">Kérlek add meg az új APP PIN kódját</string>
-  <string name="pincode_configure_your_pin">ownCloud App PIN kója</string>
-  <string name="pincode_reenter_your_pincode">Kérlek, hogy add meg újra az alkalmazás PIN-edet</string>
-  <string name="pincode_remove_your_pincode">Alkalmazás PIN eltávolítása</string>
-  <string name="pincode_mismatch">Az alkalmazás PIN-ek nem egyeznek meg</string>
-  <string name="pincode_wrong">Helytelen alkalmazás PIN</string>
-  <string name="pincode_removed">Alkalmazás PIN eltávolítva</string>
-  <string name="pincode_stored">Alkalmazás PIN eltárolva</string>
+  <string name="pincode_enter_pin_code">Kérem adja meg az alkalmazás PIN-kódját</string>
+  <string name="pincode_enter_new_pin_code">Kérem adja meg az alkalmazás új 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="pincode_reenter_your_pincode">Kérem, adja meg újra az alkalmazás PIN-kódját</string>
+  <string name="pincode_remove_your_pincode">Az alkalmazás PIN-kódjának eltávolítása</string>
+  <string name="pincode_mismatch">A megadott PIN-ek nem egyeznek meg</string>
+  <string name="pincode_wrong">Rossz a megadott PIN</string>
+  <string name="pincode_removed">Az alkalmazás PIN-ját eltávolítottuk</string>
+  <string name="pincode_stored">Az alkalmazás PIN-jét eltároltuk</string>
   <string-array name="prefs_trackmydevice_intervall_keys">
     <item>15 perc</item>
     <item>30 perc</item>
   <string name="auth_no_net_conn_message">Nem található hálózati kapcsolat, ellenőrizze az internetkapcsolatát, és próbálja újra.</string>
   <string name="auth_connect_anyway">Csatlakozás mindenképpen</string>
   <string name="auth_nossl_plain_ok_title">Nem érhető el biztonságos kapcsolat.</string>
-  <string name="auth_nossl_plain_ok_message">Az Alkalmazás nem tudott titkos kapcsolatot kialakítani a kiszolgálóval. A titkosítatlan kapcsolat elérhető. Folytathatja vagy kiléphet.</string>
+  <string name="auth_nossl_plain_ok_message">Az alkalmazás nem tudott titkosított kapcsolatot kialakítani a kiszolgálóval. A nem titkosított kapcsolat elérhető. Folytathatja vagy kiléphet.</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 kiszolgáló beállítása</string>
+  <string name="auth_not_configured_title">Hibás kiszolgáló beállítása</string>
   <string name="auth_not_configured_message">Úgy tűnik a kiszolgáló nincs megfelelően beállítva. Lépjen kapcsolatba a rendszergazdával további információkért.</string>
   <string name="auth_unknown_error_title">Ismeretlen hiba történt!</string>
   <string name="auth_unknown_error_message">Ismeretlen hiba történt. Értesítse a terméktámogatást csatolva a az eszközének a naplóbejegyzéseit.</string>
+  <string name="auth_unknown_host_title">A kiszolgáló nem található</string>
+  <string name="auth_unknown_host_message">Nem található a keresett kiszolgáló. Ellenőrizze a nevét és a szerver elérhetőségét majd próbálja újra.</string>
   <string name="auth_incorrect_path_title">Kiszolgáló nem található</string>
   <string name="auth_incorrect_path_message">A program nem találta a kiszolgálót a megadott útvonalon. Kérem ellenőrizze az útvonalat, majd próbálja újra.</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">Nem ellenőrizhető az kiszolgáló biztonsági tanúsítványa</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_login_details">Belépési adatok</string>
   <string name="auth_unauthorized">Érvénytelen felhasználónév / jelszó</string>
+  <string name="auth_not_found">Rossz a megadott útvonal</string>
+  <string name="auth_internal">Belső hiba történt a kiszolgálón, hibakód: %1$d</string>
   <string name="crashlog_message">A program összeomlott. El akar küldeni egy összeomlási jelentést?</string>
   <string name="crashlog_send_report">Jelentés küldése</string>
   <string name="crashlog_dont_send_report">Ne küldjön jelentést</string>
-  <string name="extensions_avail_title">Kiegészítők elérhetők!</string>
+  <string name="extensions_avail_title">Kiegészítők állnak rendelkezésre!</string>
   <string name="extensions_avail_message">Úgy tűnik a programja támogatja a haladó kiterjesztéseket. Látni akarja az androidon elérhető kiterjesztéseket?</string>
-  <string name="fd_keep_in_sync">Frissítse a fájlokat</string>
+  <string name="fd_keep_in_sync">Automatikusan frissítse a fájlokat</string>
   <string name="common_share">Megosztás</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éd törölni  %1$s ?</string>
-  <string name="confirmation_remove_local">Csak helyből</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_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="confirmation_remove_remote_and_local">Törlés a szerverről és helyből</string>
-  <string name="remove_success_msg">Az eltávolítás sikertelen</string>
-  <string name="remove_fail_msg">Az eltávolítás meghiúsult</string>
+  <string name="confirmation_remove_remote_and_local">A szerveren levő és a helyi példány törlése</string>
+  <string name="remove_success_msg">Az eltávolítás sikerült</string>
+  <string name="remove_fail_msg">Az eltávolítás nem sikerült</string>
   <string name="rename_dialog_title">Adj meg egy új nevet</string>
+  <string name="rename_local_fail_msg">A helyi példány nem nevezhető át, adjon másik nevet</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="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="ssl_validator_title">Figyelmeztetés</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_reason_cert_expired">- A kiszolgáló tanúsítványának lejárt az érvényessége</string>
+  <string name="ssl_validator_reason_cert_not_yet_valid">- A kiszolgáló tanúsítványa most még nem érvényes</string>
+  <string name="ssl_validator_reason_hostname_not_verified">- Az URL nem egyezik a tanúsítványban szereplő kiszolgálónévvel</string>
+  <string name="ssl_validator_certificate_not_available">A kiszolgáló tanúsítványa nem érhető el</string>
+  <string name="ssl_validator_question">Mégis megbízik ebben a tanúsítványban?</string>
+  <string name="ssl_validator_not_saved">A tanúsítvány nem menthető el</string>
   <string name="ssl_validator_btn_details_see">Részletek</string>
   <string name="ssl_validator_btn_details_hide">Elrejtés</string>
+  <string name="ssl_validator_label_subject">A tanúsítvány birtokosa:</string>
+  <string name="ssl_validator_label_issuer">Kiadta:</string>
+  <string name="ssl_validator_label_CN">Név:</string>
   <string name="ssl_validator_label_O">Szervezet:</string>
   <string name="ssl_validator_label_OU">Szervezeti egység:</string>
   <string name="ssl_validator_label_C">Ország:</string>
   <string name="ssl_validator_label_ST">Állam:</string>
   <string name="ssl_validator_label_L">Hely:</string>
+  <string name="ssl_validator_label_validity">Érvényesség:</string>
+  <string name="ssl_validator_label_validity_from">Ettől a dátumtól:</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="conflict_title">Frissítési konfliktus</string>
+  <string name="text_placeholder">Ez egy helykitöltő</string>
+  <string name="instant_upload_on_wifi">Képeket csak WiFi kapcsolaton keresztül töltsünk föl</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_keep_both">Mindkettő megtartása</string>
   <string name="conflict_overwrite">Felülírás</string>
-  <string name="conflict_dont_upload">Ne töltse fel</string>
+  <string name="conflict_dont_upload">Ne töltsük föl</string>
 </resources>
diff --git a/res/values-ka/strings.xml b/res/values-ka/strings.xml
new file mode 100644 (file)
index 0000000..09a564b
--- /dev/null
@@ -0,0 +1,9 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<resources>
+  <string name="main_files">ფაილები</string>
+  <string name="actionbar_upload_files">ფაილები</string>
+  <string name="auth_password">პაროლი</string>
+  <string name="sync_string_files">ფაილები</string>
+  <string name="setup_hint_password">პაროლი</string>
+  <string name="filedetails_download">გადმოწერა</string>
+</resources>
index 2af673d..b449d66 100644 (file)
 <?xml version='1.0' encoding='UTF-8'?>
 <resources>
-  <string name="main_files">Faili</string>
+  <string name="app_name">ownCloud</string>
+  <string name="main_password">Parole:</string>
+  <string name="main_login">Lietotājvārds:</string>
+  <string name="main_button_login">Ierakstīties</string>
+  <string name="main_welcome">Laipni lūgti</string>
+  <string name="main_files">Datnes</string>
   <string name="main_music">Mūzika</string>
+  <string name="main_contacts">Kontakti</string>
   <string name="main_calendar">Kalendārs</string>
+  <string name="main_bookmarks">Grāmatzīmes</string>
   <string name="main_settings">Iestatījumi</string>
-  <string name="actionbar_upload">Augšuplādet</string>
-  <string name="actionbar_upload_files">Faili</string>
+  <string name="main_tit_accsetup">Iestatīt kontu</string>
+  <string name="main_wrn_accsetup">Uz šīs ierīces nav iestatīta konta. Lai lietotu šo lietotni, tāds ir jāizveido.</string>
+  <string name="about_message">%1$s Android lietotne\n\nversija: %2$s</string>
+  <string name="actionbar_sync">Atsvaidzināt</string>
+  <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_search">Meklēt</string>
   <string name="actionbar_settings">Iestatījumi</string>
+  <string name="prefs_category_general">Vispārīgi</string>
+  <string name="prefs_category_trackmydevice">Ierīces izsekošana</string>
+  <string name="prefs_add_session">Pievienot jaunu sesiju</string>
+  <string name="prefs_create_img_thumbnails">Izveidot attēlu sīktēlus</string>
+  <string name="prefs_select_oc_account">Izvēlieties kontu</string>
+  <string name="prefs_summary_select_oc_account">Izvēlieties, kuru no kontiem jūsu lietotnei vajadzētu izmantot</string>
+  <string name="prefs_trackmydevice">Ierīču izsekošana</string>
+  <string name="prefs_trackmydevice_summary_off">Aktivējiet šo lietotni, lai izsekotu savas ierīces atrašanās vietu</string>
+  <string name="prefs_trackmydevice_summary_on">Šī lietotne izseko šo ierīci</string>
+  <string name="prefs_trackmydevice_interval">Atjaunināšanas intervāls</string>
+  <string name="prefs_trackmydevice_interval_summary">Atjaunināt katras %1$s minūtes</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="auth_host_url">URL</string>
   <string name="auth_username">Lietotājvārds</string>
   <string name="auth_password">Parole</string>
-  <string name="sync_string_files">Faili</string>
+  <string name="auth_register">Esmu %1$s iesācējs</string>
+  <string name="new_session_uri_error">Ir dota nepareiza adrese</string>
+  <string name="new_session_session_name_error">Nepareizs sesijas nosaukums</string>
+  <string name="sync_string_files">Datnes</string>
+  <string name="uploader_no_file_selected">Neviena datne nav izvēlēta augšupielādei</string>
   <string name="setup_hint_username">Lietotājvārds</string>
   <string name="setup_hint_password">Parole</string>
-  <string name="uploader_btn_upload_text">Augšuplādet</string>
-  <string name="filedetails_download">Lejuplādēt</string>
-  <string name="common_cancel_upload">Atcelt augšuplādi</string>
+  <string name="setup_hint_address">Tīmekļa adrese</string>
+  <string name="setup_hint_show_password">Rādīt paroli?</string>
+  <string name="setup_title">Savienoties ar savu %1$s</string>
+  <string name="setup_btn_connect">Savienoties</string>
+  <string name="uploader_btn_upload_text">Augšupielādēt</string>
+  <string name="uploader_wrn_no_account_title">Nav atrastu kontu</string>
+  <string name="uploader_wrn_no_account_text">Uz šīs ierīces nav %1$s kontu. Lūdzu, vispirms iestatiet kontu.</string>
+  <string name="uploader_wrn_no_account_setup_btn_text">Iestatīt</string>
+  <string name="uploader_wrn_no_account_quit_btn_text">Iziet</string>
+  <string name="uploader_wrn_no_content_title">Nav satura, ko augšupielādēt</string>
+  <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="uploader_btn_create_dir_text">Izveidot direktoriju augšupielādēšanai</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="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="filedetails_created">Izveidota:</string>
+  <string name="filedetails_modified">Modificēta:</string>
+  <string name="filedetails_download">Lejupielādēt</string>
+  <string name="filedetails_sync_file">Atsvaidzināt</string>
+  <string name="filedetails_redownload">Atkārtoti lejupielādēt</string>
+  <string name="filedetails_open">Atvērt</string>
+  <string name="filedetails_renamed_in_upload_msg">Datne tika pārsaukta uz %1$s augšupielādes laikā</string>
+  <string name="common_yes">Jā</string>
+  <string name="common_no">Nē</string>
+  <string name="common_ok">Labi</string>
+  <string name="common_cancel_download">Atcelt lejupielādi</string>
+  <string name="common_cancel_upload">Atcelt augšupielādi</string>
   <string name="common_cancel">Atcelt</string>
-  <string name="common_error">Kļūme</string>
-  <string name="common_share">Līdzdalīt</string>
-  <string name="common_rename">Pārdēvēt</string>
+  <string name="common_save_exit">Saglabāt un iziet</string>
+  <string name="common_exit">Pamest %1$s</string>
+  <string name="common_error">Kļūda</string>
+  <string name="about_title">Par</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_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="uploader_upload_succeeded_content_single">%1$s tika veiksmīgi augšupielādēts</string>
+  <string name="uploader_upload_succeeded_content_multiple">%1$d datnes tika veiksmīgi augšupielādētas</string>
+  <string name="uploader_upload_failed_ticker">Neizdevās augšupielādēt</string>
+  <string name="uploader_upload_failed_content_single">Nevarēja pabeigt %1$s augšupielādēšanu</string>
+  <string name="uploader_upload_failed_content_multiple">Neizdevās augšupielādēt: tika augšupielādētas %1$d/%2$d datnes</string>
+  <string name="downloader_download_in_progress_ticker">Lejupielādē ...</string>
+  <string name="downloader_download_in_progress_content">%1$d%% lejupielādē %2$s</string>
+  <string name="downloader_download_succeeded_ticker">Lejupielāde beidzās veiksmīgi</string>
+  <string name="downloader_download_succeeded_content">%1$s tika veiksmīgi lejupielādēts</string>
+  <string name="downloader_download_failed_ticker">Neizdevās lejupielādēt</string>
+  <string name="downloader_download_failed_content">Nevarēja pabeigt %1$s lejupielādēšanu</string>
+  <string name="common_choose_account">Izvēlieties kontu</string>
+  <string name="sync_string_contacts">Kontakti</string>
+  <string name="sync_fail_ticker">Neizdevās sinhronizēties</string>
+  <string name="sync_fail_content">Nevarēja pabeigt %1$s sinhronizēšanu</string>
+  <string name="sync_conflicts_in_favourites_ticker">Ir atrasti konflikti</string>
+  <string name="sync_conflicts_in_favourites_content">Nevarēja sinhronizēt %1$d kept-in-sync datnes</string>
+  <string name="sync_fail_in_favourites_ticker">Kept-in-sync datnes cieta neveiksmi</string>
+  <string name="sync_fail_in_favourites_content">Nevarēja sinhronizēt %1$d datņu saturu (%2$d konflikti)</string>
+  <string name="use_ssl">Lietot drošo savienojumu</string>
+  <string name="location_no_provider">%1$s nevar izsekot šo ierīci. Lūdzu, pārbaudiet savus vietas iestatījumus</string>
+  <string name="pincode_enter_pin_code">Lūdzu, ierakstiet savu lietotnes PIN</string>
+  <string name="pincode_enter_new_pin_code">Lūdzu, ierakstiet savu jauno lietotnes PIN</string>
+  <string name="pincode_configure_your_pin">Ievadiet savu lietotnes PIN</string>
+  <string name="pincode_configure_your_pin_explanation">PIN tiks pieprasīts katrā lietotnes palaišanas reizē</string>
+  <string name="pincode_reenter_your_pincode">Lūdzu, vēlreiz ievadiet savu lietotnes PIN</string>
+  <string name="pincode_remove_your_pincode">Izņemt savu lietotnes PIN</string>
+  <string name="pincode_mismatch">Lietotņu PIN nav vienādi</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-array name="prefs_trackmydevice_intervall_keys">
+    <item>15 minūtes</item>
+    <item>30 minūtes</item>
+    <item>60 minūtes</item>
+  </string-array>
+  <string-array name="prefs_trackmydevice_intervall_values">
+    <item>15</item>
+    <item>30</item>
+    <item>60</item>
+  </string-array>
+  <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_no_net_conn_message">Nav atklātu tīkla savienojumu. Pārbaudiet interneta savienojumus un mēģiniet vēlreiz.</string>
+  <string name="auth_connect_anyway">Tomēr savienoties</string>
+  <string name="auth_nossl_plain_ok_title">Nav pieejams drošs savienojums.</string>
+  <string name="auth_nossl_plain_ok_message">Lietotne nevar izveidot drošu savienojumu ar serveri. Ir pieejams nedrošs savienojums. Jūs varat turpināt vai atcelt.</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_not_configured_message">Izskatās, ka jūsu servera instance nav pareizi konfigurēta. Sazinieties ar servera administratoru, lai uzzinātu vairāk.</string>
+  <string name="auth_unknown_error_title">Gadījās nezināma kļūda!</string>
+  <string name="auth_unknown_error_message">Gadījās nezināma kļūda. Lūdzu, sazinieties ar atbalstu un pievienojiet žurnālus no savas ierīces.</string>
+  <string name="auth_unknown_host_title">Nevarēja atrast datoru</string>
+  <string name="auth_unknown_host_message">Nevarēja atrast ievadīto datoru. Lūdzu, pārliecinieties ka datora nosaukums ir ievadīts pareizi un ka serveris ir pieejams.</string>
+  <string name="auth_incorrect_path_title">Servera instance nav atrasta</string>
+  <string name="auth_incorrect_path_message">Lietotne uz dotā ceļa nevarēja atrast servera instanci. Lūdzu, pārbaudiet ceļu un mēģiniet vēlreiz.</string>
+  <string name="auth_timeout_title">Serveris pārāk ilgi neatbildēja</string>
+  <string name="auth_incorrect_address_title">Slikti formatēts URL</string>
+  <string name="auth_ssl_general_error_title">Neizdevās inicializēt SSL</string>
+  <string name="auth_ssl_unverified_server_title">Nepārbaudīta SSL servera identitāte</string>
+  <string name="auth_bad_oc_version_title">Neatpazīta servera versija</string>
+  <string name="auth_wrong_connection_title">Nevarēja izveidot savienojumu</string>
+  <string name="auth_secure_connection">Ir izveidots drošs savienojums</string>
+  <string name="auth_login_details">Sīkāka informācija par ierakstīšanos</string>
+  <string name="auth_unauthorized">Nederīgs lietotājvārds/parole</string>
+  <string name="auth_not_found">Dots nepareizs ceļš</string>
+  <string name="auth_internal">Iekšējā servera kļūda, kods %1$d</string>
+  <string name="crashlog_message">Lietotne negaidīti beidza darbu. Vai vēlaties iesniegt kļūdas ziņojumu?</string>
+  <string name="crashlog_send_report">Sūtīt ziņojumu</string>
+  <string name="crashlog_dont_send_report">Nesūtīt ziņojumu</string>
+  <string name="extensions_avail_title">Ir pieejams paplašinājums!</string>
+  <string name="extensions_avail_message">Izskatās, ka jūsu servera instance atbalsta papildu paplašinājumus. Vai vēlaties redzēt paplašinājumus, kas ir pieejami uz android?</string>
+  <string name="fd_keep_in_sync">Uzturēt datni aktuālu</string>
+  <string name="common_share">Dalīties</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="confirmation_remove_remote_and_local">Attālinātās un lokālās</string>
+  <string name="remove_success_msg">Veiksmīgi izņemts</string>
+  <string name="remove_fail_msg">Neizdevās izņemt</string>
+  <string name="rename_dialog_title">Ievadīt jaunu nosaukumu</string>
+  <string name="rename_local_fail_msg">Nevarēja pārsaukt lokālo kopiju; pamēģiniet citu nosaukumu</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="ssl_validator_title">Brīdinājums</string>
+  <string name="ssl_validator_header">Šīs vietnes identitāti nevarēja pārbaudīt</string>
+  <string name="ssl_validator_reason_cert_not_trusted">- Nav uzticības servera sertifikātam</string>
+  <string name="ssl_validator_reason_cert_expired">- Servera sertifikātam ir beidzies termiņš</string>
+  <string name="ssl_validator_reason_cert_not_yet_valid">- Servera sertifikāta datumi ir nākotnē</string>
+  <string name="ssl_validator_reason_hostname_not_verified">- URL sertifikātā neatbilst datora nosaukumam</string>
+  <string name="ssl_validator_certificate_not_available">Nevarēja saņemt sertifikātu</string>
+  <string name="ssl_validator_question">Vai tomēr uzticēties sertifikātam?</string>
+  <string name="ssl_validator_not_saved">Nevarēja saglabāt sertifikātu</string>
+  <string name="ssl_validator_btn_details_see">Sīkāka informācija</string>
+  <string name="ssl_validator_btn_details_hide">Slēpt</string>
+  <string name="ssl_validator_label_subject">Izsniegts:</string>
+  <string name="ssl_validator_label_issuer">Izsniedza:</string>
+  <string name="ssl_validator_label_CN">Kopīgais nosaukums:</string>
+  <string name="ssl_validator_label_O">Organizācija:</string>
+  <string name="ssl_validator_label_OU">Organizācijas vienība:</string>
+  <string name="ssl_validator_label_C">Valsts:</string>
+  <string name="ssl_validator_label_ST">Štats:</string>
+  <string name="ssl_validator_label_L">Vieta:</string>
+  <string name="ssl_validator_label_validity">Derīgums:</string>
+  <string name="ssl_validator_label_validity_from">No:</string>
+  <string name="ssl_validator_label_validity_to">Kam:</string>
+  <string name="ssl_validator_label_signature">Paraksts:</string>
+  <string name="ssl_validator_label_signature_algorithm">Algoritms:</string>
+  <string name="text_placeholder">Šis ir vietturis</string>
+  <string name="instant_upload_on_wifi">Attēlus augšupielādēt tikai caur WiFi</string>
+  <string name="instant_upload_path">/TūlītējaAugšupielāde</string>
+  <string name="conflict_title">Atjaunināšanas konflikts</string>
+  <string name="conflict_message">Attālinātā datne %s nav sinhronizēta ar lokālo datni. Turpināšana aizstās datņu servera saturu.</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>
 </resources>
diff --git a/res/values-my/strings.xml b/res/values-my/strings.xml
new file mode 100644 (file)
index 0000000..b304e63
--- /dev/null
@@ -0,0 +1,15 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<resources>
+  <string name="main_files">ဖိုင်များ</string>
+  <string name="main_calendar">ပြက္ခဒိန်</string>
+  <string name="actionbar_upload_files">ဖိုင်များ</string>
+  <string name="auth_username">သုံးစွဲသူအမည်</string>
+  <string name="auth_password">စကားဝှက်</string>
+  <string name="sync_string_files">ဖိုင်များ</string>
+  <string name="setup_hint_username">သုံးစွဲသူအမည်</string>
+  <string name="setup_hint_password">စကားဝှက်</string>
+  <string name="filedetails_download">ဒေါင်းလုတ်</string>
+  <string name="common_yes">ဟုတ်</string>
+  <string name="common_no">မဟုတ်ဘူး</string>
+  <string name="common_cancel">ပယ်ဖျက်မည်</string>
+</resources>
index 2eacd46..d86ae9d 100644 (file)
   <string name="main_contacts">Kontakter</string>
   <string name="main_calendar">Kalender</string>
   <string name="main_bookmarks">Bokmerker</string>
-  <string name="main_settings">Innstilinger</string>
+  <string name="main_settings">Innstillinger</string>
   <string name="main_tit_accsetup">Sett opp konto</string>
   <string name="main_wrn_accsetup">Det finnes ingen ownClound kontoer for din enhent. For å bruker denne appen må du opprette en,</string>
   <string name="actionbar_sync">Oppdater</string>
-  <string name="actionbar_upload">Opplasting</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_search">Søk</string>
   <string name="actionbar_settings">Innstillinger</string>
-  <string name="prefs_category_general">Generellt</string>
-  <string name="prefs_category_trackmydevice">Enherssporing</string>
-  <string name="prefs_create_img_thumbnails">Lag minityrbilder</string>
+  <string name="prefs_category_general">Generelt</string>
+  <string name="prefs_category_trackmydevice">Enhetssporing</string>
+  <string name="prefs_add_session">Legg til ny sesjon</string>
+  <string name="prefs_create_img_thumbnails">Opprett miniatyrbilder</string>
   <string name="prefs_select_oc_account">Velg konto</string>
   <string name="prefs_trackmydevice">Enhetssporing</string>
   <string name="prefs_trackmydevice_interval">Oppdateringsfrekvens</string>
+  <string name="prefs_trackmydevice_interval_summary">Oppdater hvert %1$s minutt</string>
   <string name="prefs_accounts">Kontoer</string>
+  <string name="prefs_instant_upload_summary">Last opp bilder tatt med kamera øyeblikkelig</string>
   <string name="auth_host_url">URL</string>
   <string name="auth_username">Brukernavn</string>
   <string name="auth_password">Passord</string>
   <string name="sync_string_files">Filer</string>
+  <string name="uploader_no_file_selected">Ingen fil valgt for opplasting</string>
   <string name="setup_hint_username">Brukernavn</string>
   <string name="setup_hint_password">Passord</string>
   <string name="setup_hint_address">Internettadresse</string>
   <string name="setup_hint_show_password">Vise passord?</string>
-  <string name="setup_btn_connect">Kople til</string>
-  <string name="uploader_btn_upload_text">Last op</string>
+  <string name="setup_btn_connect">Koble til</string>
+  <string name="uploader_btn_upload_text">Last opp</string>
   <string name="uploader_wrn_no_account_title">Ingen konto funnet</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_info_uploading">Laster opp</string>
   <string name="uploader_btn_create_dir_text">Opprett mappe for opplasting</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">Opprette:</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</string>
   <string name="common_cancel_download">Avbryt nedlasting</string>
   <string name="common_cancel_upload">Avbryt opplasting</string>
   <string name="common_cancel">Avbryt</string>
-  <string name="common_save_exit">Lager og avslutt</string>
+  <string name="common_save_exit">Lagre og avslutt</string>
   <string name="common_error">Feil</string>
   <string name="about_title">Om</string>
   <string name="delete_account">Slett konto</string>
-  <string name="create_account">Opprett 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_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_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_content_multiple">Opplasting feilet: %1$d/%2$d filer ble lastet opp</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_failed_ticker">Nedlasting feilet</string>
+  <string name="downloader_download_failed_content">Nedlasting av %1$s kunne ikke fullføres</string>
   <string name="common_choose_account">Velg konto</string>
   <string name="sync_string_contacts">Kontakter</string>
+  <string name="sync_fail_ticker">Synkronisering feilet</string>
+  <string name="sync_fail_content">Synkronisering av %1$s kunne ikke fullføres</string>
   <string name="sync_conflicts_in_favourites_ticker">Konflikter funnet</string>
   <string name="use_ssl">Bruk sikker tilkobling</string>
+  <string name="pincode_enter_pin_code">Vennligst tast inn din App-PIN</string>
+  <string name="pincode_enter_new_pin_code">Vennligst tast inn ny App-PIN</string>
+  <string-array name="prefs_trackmydevice_intervall_keys">
+    <item>15 minutter</item>
+    <item>30 minutter</item>
+    <item>60 minutter</item>
+  </string-array>
+  <string-array name="prefs_trackmydevice_intervall_values">
+    <item>15</item>
+    <item>30</item>
+    <item>60</item>
+  </string-array>
   <string name="auth_trying_to_login">Prøver å logge inn...</string>
-  <string name="auth_no_net_conn_title">Ingen nettverkstilgang</string>
+  <string name="auth_no_net_conn_title">Ingen nettverkstilkobling</string>
   <string name="auth_connect_anyway">Koble til likevel</string>
-  <string name="auth_testing_connection">Tester tilgang...</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 tilkobling...</string>
+  <string name="auth_unknown_error_title">Ukjent feil oppstod!</string>
+  <string name="auth_unknown_host_title">Fant ikke tjener</string>
+  <string name="auth_unknown_host_message">Fant ikke spesifisert tjener.  Vennligst sjekk tjenernavnet og server-tilgjengeligheten, og prøv på nytt.</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">Uverifisert SSL-servers identitet</string>
+  <string name="auth_wrong_connection_title">Klarte ikke å opprette tilkobling</string>
+  <string name="auth_secure_connection">Sikker tilkobling opprettet</string>
+  <string name="auth_login_details">Innloggingsdetaljer</string>
   <string name="auth_unauthorized">Ugyldig brukernavn / passord</string>
   <string name="crashlog_send_report">Send rapport</string>
   <string name="crashlog_dont_send_report">Ikke send rapport</string>
+  <string name="extensions_avail_title">Utvidelser tilgjengelig!</string>
+  <string name="fd_keep_in_sync">Hold filen oppdatert</string>
   <string name="common_share">Del</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_local">Kun lokalt</string>
+  <string name="confirmation_remove_remote">Fjern fra server</string>
+  <string name="rename_server_fail_msg">Klarte ikke å endre navn</string>
+  <string name="create_dir_fail_msg">Mappe kunne ikke opprettes</string>
+  <string name="wait_a_moment">Vent et øyeblikk</string>
+  <string name="filedisplay_no_file_selected">Ingen fil ble valgt</string>
   <string name="ssl_validator_title">Advarsel</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_btn_details_see">Detaljer</string>
   <string name="ssl_validator_btn_details_hide">Skjul</string>
   <string name="ssl_validator_label_C">Land:</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="text_placeholder">Dette er en plassholder</string>
   <string name="conflict_keep_both">Behold begge</string>
 </resources>
index 2902afb..0c07126 100644 (file)
@@ -3,8 +3,8 @@
   <string name="app_name">ownCloud</string>
   <string name="main_password">Hasło:</string>
   <string name="main_login">Nazwa użytkownika:</string>
-  <string name="main_button_login">Login</string>
-  <string name="main_welcome">Witaj w ownCloud</string>
+  <string name="main_button_login">Zaloguj</string>
+  <string name="main_welcome">Witaj</string>
   <string name="main_files">Pliki</string>
   <string name="main_music">Muzyka</string>
   <string name="main_contacts">Kontakty</string>
   <string name="main_bookmarks">Zakładki</string>
   <string name="main_settings">Ustawienia</string>
   <string name="main_tit_accsetup">Załóż konto</string>
-  <string name="main_wrn_accsetup">Nie wykryto kont ownCloud, załóż konto w celu używania aplikacji.</string>
-  <string name="about_message">ownCloud Android klient⏎ ⏎ wersja: %2$s</string>
+  <string name="main_wrn_accsetup">Nie wykryto kont ownCloud. Aby korzystać z tej aplikacji, musisz utworzyć konto.</string>
+  <string name="about_message">%1$s Android App⏎ ⏎ wersja: %2$s</string>
   <string name="actionbar_sync">Odśwież</string>
   <string name="actionbar_upload">Wyślij plik</string>
-  <string name="actionbar_upload_from_apps">Zasoby innej aplikacji</string>
-  <string name="actionbar_upload_files">Pliki z telefonu</string>
+  <string name="actionbar_upload_from_apps">Zasoby innych aplikacji</string>
+  <string name="actionbar_upload_files">Pliki</string>
   <string name="actionbar_mkdir">Nowy katalog</string>
   <string name="actionbar_search">Szukaj</string>
   <string name="actionbar_settings">Ustawienia</string>
   <string name="prefs_category_general">Ogólne</string>
-  <string name="prefs_category_trackmydevice">Śledzenie urządzeń</string>
-  <string name="prefs_add_session">Dodaj sesje</string>
-  <string name="prefs_create_img_thumbnails">Nie można utworzyć podglądu</string>
+  <string name="prefs_category_trackmydevice">Śledzenie urządzenia</string>
+  <string name="prefs_add_session">Dodaj nową sesję</string>
+  <string name="prefs_create_img_thumbnails">Utwórz miniaturki obrazów</string>
   <string name="prefs_select_oc_account">Wybierz konto</string>
-  <string name="prefs_summary_select_oc_account">Wybierz aplikację, której chcesz użyć.</string>
+  <string name="prefs_summary_select_oc_account">Wybierz konto, z którego ma korzystać aplikacja.</string>
   <string name="prefs_trackmydevice">Śledzenie urządzeń</string>
-  <string name="prefs_trackmydevice_summary_off">Włącz śledzenie lokalizacji urządzenia w ownCloud</string>
-  <string name="prefs_trackmydevice_summary_on">Twój ownCloud trzyma informacje o tym urządzeniu</string>
+  <string name="prefs_trackmydevice_summary_off">Włącz śledzenie lokalizacji urządzenia przez tę aplikację</string>
+  <string name="prefs_trackmydevice_summary_on">Ta aplikacja śledzi to urządzenie</string>
   <string name="prefs_trackmydevice_interval">Odstęp aktualizacji</string>
   <string name="prefs_trackmydevice_interval_summary">Aktualizuj co %1$ minut</string>
   <string name="prefs_accounts">Konta</string>
   <string name="prefs_manage_accounts">Zarządzaj kontami</string>
-  <string name="prefs_pincode">Pin aplikacji ownCloud</string>
-  <string name="prefs_pincode_summary">Chroni klienta ownCloud</string>
-  <string name="prefs_instant_upload">Włącz automatyczne wysyłanie</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="auth_host_url">URL ownCloud</string>
+  <string name="auth_host_url">URL</string>
   <string name="auth_username">Nazwa użytkownika</string>
   <string name="auth_password">Hasło</string>
-  <string name="auth_register">Jestem nowy na ownCloud</string>
-  <string name="new_session_uri_error">Podano niepoprawny URL</string>
-  <string name="new_session_session_name_error">a nazwa sesji</string>
+  <string name="auth_register">Jestem nowym użytkownikiem %1$s</string>
+  <string name="new_session_uri_error">Podano niepoprawny adres</string>
+  <string name="new_session_session_name_error">Niepoprawna nazwa sesji</string>
   <string name="sync_string_files">Pliki</string>
   <string name="uploader_no_file_selected">Nie wybrano plików do wysłania</string>
   <string name="setup_hint_username">Nazwa użytkownika</string>
   <string name="setup_hint_password">Hasło</string>
-  <string name="setup_hint_address">Adres sieciowy</string>
-  <string name="setup_hint_show_password">Pokaż hasło</string>
-  <string name="setup_title">Połącz do ownCloud</string>
+  <string name="setup_hint_address">Adres internetowy</string>
+  <string name="setup_hint_show_password">Wyświetlić hasło?</string>
+  <string name="setup_title">Połącz z %1$s</string>
   <string name="setup_btn_connect">Połącz</string>
-  <string name="uploader_btn_upload_text">Wyslij</string>
-  <string name="uploader_wrn_no_account_title">Nie znaleziono kont</string>
-  <string name="uploader_wrn_no_account_text">Nie wykryto kont ownCloud, załóż konto w celu używania aplikacji.</string>
+  <string name="uploader_btn_upload_text">Wyślij</string>
+  <string name="uploader_wrn_no_account_title">Nie znaleziono konta</string>
+  <string name="uploader_wrn_no_account_text">Nie wykryto kont %1$s na twoim urządzeniu. Załóż konto.</string>
   <string name="uploader_wrn_no_account_setup_btn_text">Ustawienia</string>
   <string name="uploader_wrn_no_account_quit_btn_text">Wyjdź</string>
   <string name="uploader_wrn_no_content_title">Brak danych do wysłania</string>
   <string name="uploader_wrn_no_content_text">Nie otrzymano danych. Nie ma nic do wysłania.</string>
-  <string name="uploader_error_forbidden_content">ownCloud niema dostępu do udostępnionych zawartości</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="uploader_btn_create_dir_text">Stwórz katalog do wysyłania</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="filedetails_select_file">Dotknij po dodatkowe informacje</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>
   <string name="filedetails_created">Utworzono:</string>
@@ -80,7 +80,7 @@
   <string name="common_cancel_upload">Anuluj wysyłanie</string>
   <string name="common_cancel">Anuluj</string>
   <string name="common_save_exit">Zapisz i wyjdź</string>
-  <string name="common_exit">Opuść ownCloud</string>
+  <string name="common_exit">Opuść %1$s</string>
   <string name="common_error">Błąd</string>
   <string name="about_title">O aplikacji</string>
   <string name="delete_account">Usuń konto</string>
   <string name="uploader_info_dirname">Nazwa katalogu</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</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_succeeded_content_multiple">Wysłano %1$d plików</string>
-  <string name="uploader_upload_failed_ticker">Wysyłanie nieudane</string>
-  <string name="uploader_upload_failed_content_single">Wysyłanie %1$s plików nie powiodło się</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_content_multiple">Wysyłanie nieudane: wysłano %1$d/%2$d plików</string>
-  <string name="downloader_download_in_progress_ticker">Pobieram …</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 plików nie powiodło się</string>
+  <string name="downloader_download_failed_content">Pobieranie %1$s nie powiodło się</string>
   <string name="common_choose_account">Wybierz konto</string>
   <string name="sync_string_contacts">Kontakty</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_conflicts_in_favourites_ticker">Znaleziono konflikty</string>
-  <string name="sync_conflicts_in_favourites_content">%1$d nie może zostać zsynchronizowany</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="use_ssl">Użyj bezpiecznego połączenia</string>
-  <string name="location_no_provider">ownCloud nie może śledzić urządzenia. Sprawdź ustawienia lokalizacji</string>
-  <string name="pincode_enter_pin_code">Podaj PIN</string>
-  <string name="pincode_enter_new_pin_code">Podaj nowy PIN</string>
-  <string name="pincode_configure_your_pin">Wpisz PIN</string>
-  <string name="pincode_configure_your_pin_explanation">Kod PIN bedzie wymagany za każdym razem, gdy aplikacja będzie uruchamiana.</string>
-  <string name="pincode_reenter_your_pincode">Podaj PIN ponownie</string>
-  <string name="pincode_remove_your_pincode">Usuń PIN</string>
+  <string name="location_no_provider">%1$s nie może śledzić urządzenia. Sprawdź ustawienia lokalizacji</string>
+  <string name="pincode_enter_pin_code">Podaj PIN aplikacji</string>
+  <string name="pincode_enter_new_pin_code">Podaj nowy PIN aplikacji</string>
+  <string name="pincode_configure_your_pin">Wpisz PIN aplikacji</string>
+  <string name="pincode_configure_your_pin_explanation">Kod PIN będzie wymagany za każdym razem, gdy aplikacja będzie uruchamiana.</string>
+  <string name="pincode_reenter_your_pincode">Ponownie wpisz PIN aplikacji</string>
+  <string name="pincode_remove_your_pincode">Usuń PIN aplikacji</string>
   <string name="pincode_mismatch">Podane numery PIN są różne</string>
-  <string name="pincode_wrong">Niepoprawny PIN</string>
-  <string name="pincode_removed">Usunięto PIN</string>
-  <string name="pincode_stored">Zapisano PIN</string>
+  <string name="pincode_wrong">Niepoprawny PIN aplikacji</string>
+  <string name="pincode_removed">Usunięto PIN aplikacji</string>
+  <string name="pincode_stored">Zapisano PIN aplikacji</string>
   <string-array name="prefs_trackmydevice_intervall_keys">
-    <item>15 Minut</item>
-    <item>30 Minut</item>
-    <item>60 Minut</item>
+    <item>15 minut</item>
+    <item>30 minut</item>
+    <item>60 minut</item>
   </string-array>
   <string-array name="prefs_trackmydevice_intervall_values">
     <item>15</item>
   </string-array>
   <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_no_net_conn_message">Wykryto brak połączenia z siecią, sprawdź połączenie internetowe i spróbuj ponownie.</string>
+  <string name="auth_no_net_conn_message">Nie znaleziono połączenia sieciowego. Sprawdź połączenie internetowe i spróbuj ponownie.</string>
   <string name="auth_connect_anyway">Połącz mimo wszystko</string>
   <string name="auth_nossl_plain_ok_title">Nie można nawiązać bezpiecznego połączenia.</string>
-  <string name="auth_nossl_plain_ok_message">Aplikacji nie można ustanowić bezpiecznego połączenia z serwerem. Niezabezpieczone połączenie jest dostępne. Możesz kontynuować lub anuluować.</string>
+  <string name="auth_nossl_plain_ok_message">Aplikacja nie można ustanowić bezpiecznego połączenia z serwerem. Niezabezpieczone połączenie jest dostępne. Możesz kontynuować lub anulować.</string>
   <string name="auth_connection_established">Połączenie nawiązane</string>
   <string name="auth_testing_connection">Testowanie połączenia…</string>
-  <string name="auth_not_configured_title">Uszkodzona configuracja ownCloud</string>
-  <string name="auth_not_configured_message">Wydaje się, że Twoja instalacja ownCloud nie jest poprawnie skonfigurowana. Aby uzyskać więcej informacji, skontaktuj się z administratorem.</string>
-  <string name="auth_unknown_error_title">Napotkano nieznany błąd</string>
-  <string name="auth_unknown_error_message">Wystąpił nieznany błąd. Proszę skontaktować się z autorem i dodać dzienniki z urządzenia.</string>
+  <string name="auth_not_configured_title">Uszkodzona konfiguracja serwera</string>
+  <string name="auth_not_configured_message">Wygląda na to, że twoja instancja ownCloud nie jest poprawnie skonfigurowana. Aby uzyskać więcej informacji, skontaktuj się z administratorem.</string>
+  <string name="auth_unknown_error_title">Wystąpił nieznany błąd!</string>
+  <string name="auth_unknown_error_message">Wystąpił nieznany błąd. Proszę skontaktować się z autorami i dodać dzienniki z urządzenia.</string>
   <string name="auth_unknown_host_title">Nie mogę znaleźć hosta</string>
   <string name="auth_unknown_host_message">Nie można znaleźć podanego hosta. Sprawdź nazwę hosta oraz dostępność serwera i spróbuj ponownie.</string>
-  <string name="auth_incorrect_path_title">Nie znaleziono instalacji ownCloud</string>
-  <string name="auth_incorrect_path_message">Aplikacja nie odnalazła  instalacji ownCloud. Sprawdź URL i spróbuj ponownie.</string>
+  <string name="auth_incorrect_path_title">Nie znaleziono instancji ownCloud</string>
+  <string name="auth_incorrect_path_message">Aplikacja nie odnalazła instancji serwera pod podaną ścieżką. Sprawdź ścieżkę i spróbuj ponownie.</string>
   <string name="auth_timeout_title">Serwer zbyt długo nie odpowiadał</string>
   <string name="auth_incorrect_address_title">Zły format adresu URL</string>
   <string name="auth_ssl_general_error_title">Inicjowanie SSL nie powiodło się</string>
   <string name="auth_ssl_unverified_server_title">Tożsamość SSL serwera niezweryfikowana</string>
-  <string name="auth_bad_oc_version_title">Nie rozpoznano wersji serwera ownCloud</string>
+  <string name="auth_bad_oc_version_title">Nie rozpoznano wersji serwera</string>
   <string name="auth_wrong_connection_title">Nie można ustanowić połączenia</string>
   <string name="auth_secure_connection">Nawiązano bezpieczne połączenie</string>
   <string name="auth_login_details">Szczegóły logowania</string>
   <string name="crashlog_send_report">Wyślij raport</string>
   <string name="crashlog_dont_send_report">Nie wysyłaj raportu</string>
   <string name="extensions_avail_title">Rozszerzenie dostępne!</string>
-  <string name="extensions_avail_message">Twoja instalacja ownCloud wspiera zaawansowane rozszerzenia. Czy chcesz zobaczyć rozszerzenia dostępne dla Androida?</string>
+  <string name="extensions_avail_message">Twoja instancja serwera wspiera zaawansowane rozszerzenia. Czy chcesz zobaczyć rozszerzenia dostępne dla systemu Android?</string>
   <string name="fd_keep_in_sync">Automatyczne aktualizuj plik</string>
   <string name="common_share">Udostępnij</string>
   <string name="common_rename">Zmień nazwę</string>
   <string name="common_remove">Usuń</string>
-  <string name="confirmation_remove_alert">Czy chcesz usunąć %1$s ?</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_local">Tylko lokalnie</string>
-  <string name="confirmation_remove_folder_local">Tylko zasoby lokalna</string>
+  <string name="confirmation_remove_folder_local">Tylko zasoby lokalne</string>
   <string name="confirmation_remove_remote">Usuń z serwera</string>
   <string name="confirmation_remove_remote_and_local">Z serwera i telefonu</string>
   <string name="remove_success_msg">Usunięto</string>
-  <string name="remove_fail_msg">Nie można usunąć pliku</string>
+  <string name="remove_fail_msg">Nie można usunąć</string>
   <string name="rename_dialog_title">Wprowadź nową nazwę</string>
-  <string name="rename_local_fail_msg">Nie można zmienić nazwy lokalnej kopii; Spróbuj wybrać inną nazwę </string>
-  <string name="rename_server_fail_msg">Nie można zmienić nazwy</string>
+  <string name="rename_local_fail_msg">Nie można zmienić nazwy kopii lokalnej; spróbuj wybrać inną nazwę </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="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 żadnego pliku</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="ssl_validator_title">Uwaga</string>
   <string name="ssl_validator_header">Nie można zweryfikować tożsamości strony</string>
   <string name="ssl_validator_reason_cert_not_trusted">- Certyfikat serwera jest niezaufany</string>
   <string name="ssl_validator_question">Zaakceptować certyfikat mimo wszystko?</string>
   <string name="ssl_validator_not_saved">Nie można zapisać certyfikatu</string>
   <string name="ssl_validator_btn_details_see">Szczegóły</string>
-  <string name="ssl_validator_btn_details_hide">Schowaj</string>
-  <string name="ssl_validator_label_subject">Wydane dla:</string>
-  <string name="ssl_validator_label_issuer">Wydane przez:</string>
+  <string name="ssl_validator_btn_details_hide">Ukryj</string>
+  <string name="ssl_validator_label_subject">Wydany dla:</string>
+  <string name="ssl_validator_label_issuer">Wydany przez:</string>
   <string name="ssl_validator_label_CN">Nazwa:</string>
   <string name="ssl_validator_label_O">Organizacja:</string>
   <string name="ssl_validator_label_OU">Jednostka organizacyjna:</string>
-  <string name="ssl_validator_label_C">Państwo:</string>
-  <string name="ssl_validator_label_ST">Województwo:</string>
+  <string name="ssl_validator_label_C">Kraj:</string>
+  <string name="ssl_validator_label_ST">Stan:</string>
   <string name="ssl_validator_label_L">Lokalizacja:</string>
   <string name="ssl_validator_label_validity">Ważność:</string>
-  <string name="ssl_validator_label_validity_from">Z:</string>
+  <string name="ssl_validator_label_validity_from">Od:</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>
index 6262585..8851c6c 100644 (file)
@@ -1,13 +1,13 @@
 <?xml version='1.0' encoding='UTF-8'?>
 <resources>
   <string name="app_name">ownCloud</string>
-  <string name="main_password">Senha</string>
-  <string name="main_login">Nome de usuário</string>
+  <string name="main_password">Senha:</string>
+  <string name="main_login">Nome de usuário:</string>
   <string name="main_button_login">Login</string>
-  <string name="main_welcome">Bem-vindo ao seu ownCloud</string>
+  <string name="main_welcome">Bem-vindo</string>
   <string name="main_files">Arquivos</string>
   <string name="main_music">Música</string>
-  <string name="main_contacts">Contato</string>
+  <string name="main_contacts">Contatos</string>
   <string name="main_calendar">Calendário</string>
   <string name="main_bookmarks">Favoritos</string>
   <string name="main_settings">Ajustes</string>
   <string name="about_title">Sobre</string>
   <string name="delete_account">Remover conta</string>
   <string name="create_account">Criar conta</string>
-  <string name="upload_chooser_title">Enviando de ...</string>
+  <string name="upload_chooser_title">Enviar de …</string>
   <string name="uploader_info_dirname">Nome do diretório</string>
-  <string name="uploader_upload_in_progress_ticker">Enviando ...</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_succeeded_content_multiple">%1$d arquivos foram enviados com sucesso</string>
-  <string name="uploader_upload_failed_ticker">Envio falhou</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_multiple">Envio falhou: %1$d/%2$d arquivos foram enviados</string>
-  <string name="downloader_download_in_progress_ticker">Baixando ...</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_succeeded_content">%1$s foi baixado com sucesso</string>
   <string name="sync_fail_ticker">Sincronização falhou</string>
   <string name="sync_fail_content">Sincronização de %1$s não pôde ser completada</string>
   <string name="sync_conflicts_in_favourites_ticker">Conflitos encontrados</string>
+  <string name="sync_conflicts_in_favourites_content">%1$d arquivos \"manter sincronizados\" não puderam ser sincronizados</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="use_ssl">Usar Conexão Segura</string>
-  <string name="location_no_provider">ownCloud não pode rastrear seu dispositivo. Por favor verifique suas configurações de localização</string>
-  <string name="pincode_enter_pin_code">Por favor insira o PIN da sua aplicação</string>
-  <string name="pincode_enter_new_pin_code">Por favor, insira seu novo App PIN</string>
-  <string name="pincode_configure_your_pin">Digite ownCloud App PIN</string>
+  <string name="location_no_provider">%1$s não pode rastrear seu dispositivo. Por favor verifique suas configurações de localização</string>
+  <string name="pincode_enter_pin_code">Por favor, insira o seu PIN de Aplicativo</string>
+  <string name="pincode_enter_new_pin_code">Por favor, insira seu novo 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="pincode_reenter_your_pincode">Redigite ownCloud App PIN, por favor</string>
-  <string name="pincode_remove_your_pincode">Remova seu ownCloud App PIN</string>
-  <string name="pincode_mismatch">Ambos ownCloud App PIN não são o mesmo</string>
-  <string name="pincode_wrong">ownCloud App PIN incorreto</string>
-  <string name="pincode_removed">ownCloud App PIN removido</string>
-  <string name="pincode_stored">ownCloud App PIN armazenado</string>
+  <string name="pincode_reenter_your_pincode">Por favor, reinsira seu PIN de Aplicativo</string>
+  <string name="pincode_remove_your_pincode">Remova seu PIN de Aplicativo</string>
+  <string name="pincode_mismatch">Os PINs de Aplicativo não são iguais</string>
+  <string name="pincode_wrong">PIN de Aplicativo incorreto</string>
+  <string name="pincode_removed">PIN de Aplicativo removido</string>
+  <string name="pincode_stored">PIN de Aplicativo armazenado</string>
   <string-array name="prefs_trackmydevice_intervall_keys">
-    <item>15 Minutos</item>
-    <item>30 Minutos</item>
-    <item>60 Minutos</item>
+    <item>15 minutos</item>
+    <item>30 minutos</item>
+    <item>60 minutos</item>
   </string-array>
   <string-array name="prefs_trackmydevice_intervall_values">
     <item>15</item>
   <string name="auth_no_net_conn_message">Nenhuma conexão foi detectada, verifique sua conexão com a Internet e tente novamente.</string>
   <string name="auth_connect_anyway">Conectar mesmo assim</string>
   <string name="auth_nossl_plain_ok_title">Conexão segura indisponível.</string>
-  <string name="auth_nossl_plain_ok_message">Aplicação não pôde estabelecer uma conexão segura. Entretanto conexão não-segura está disponível. Você pode continuar ou cancelar.</string>
+  <string name="auth_nossl_plain_ok_message">O aplicativo não pôde estabelecer uma conexão segura. Uma conexão não-segura está disponível. Você pode continuar ou cancelar.</string>
   <string name="auth_connection_established">Conexão estabelecida</string>
   <string name="auth_testing_connection">Testando conexão...</string>
-  <string name="auth_not_configured_title">Configuração ownCloud mal formada</string>
-  <string name="auth_not_configured_message">Parece que sua instância ownCloud não está corretamente configurada. Contate seu administrador para mais detalhes.</string>
-  <string name="auth_unknown_error_title">Erro desconhecido ocorreu!</string>
-  <string name="auth_unknown_error_message">Erro desconhecido ocorreu. Por favor contate os desenvolvedores e inclua dos logs do seu dispositivo.</string>
+  <string name="auth_not_configured_title">Configuração do servidor mal formada</string>
+  <string name="auth_not_configured_message">Parece que a instância do seu servidor não está corretamente configurada. Contate seu administrador para mais detalhes.</string>
+  <string name="auth_unknown_error_title">Ocorreu um erro desconhecido!</string>
+  <string name="auth_unknown_error_message">Ocorreu um erro desconhecido. Por favor contate o suporte e inclua registros do seu dispositivo.</string>
   <string name="auth_unknown_host_title">Não pôde encontrar host</string>
   <string name="auth_unknown_host_message">Couldn\'t find the entered host. Por favor verifique o nome de host, disponibilidade do servidor e tente novamente.</string>
-  <string name="auth_incorrect_path_title">Instância ownCloud não encontrada</string>
-  <string name="auth_incorrect_path_message">Aplicação não pôde encontrar uma instância ownCloud no caminho dado. Por favor, verifique e tente novamente.</string>
+  <string name="auth_incorrect_path_title">Instância de servidor não encontrada</string>
+  <string name="auth_incorrect_path_message">O aplicativo não pôde encontrar uma instância de servidor no caminho indicado. Por favor, verifique-o e tente novamente.</string>
   <string name="auth_timeout_title">O servidor demorou demais a responder</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_unauthorized">Login / senha inválida</string>
   <string name="auth_not_found">Caminho dado está errado</string>
   <string name="auth_internal">Erro interno do servidor, código %1$d</string>
-  <string name="crashlog_message">Aplicação terminou inesperadamente. Gostaria de submeter um relatório de erros?</string>
+  <string name="crashlog_message">O aplicativo terminou inesperadamente. Gostaria de enviar um relatório de erros?</string>
   <string name="crashlog_send_report">Enviar relatório</string>
   <string name="crashlog_dont_send_report">Não enviar relatório</string>
   <string name="extensions_avail_title">Extensões disponíveis!</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="wait_a_moment">Aguarde um momento</string>
-  <string name="filedisplay_unexpected_bad_get_content">Problema inesperado ; por favor, tente usar outro app para selecionar o arquivo</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="ssl_validator_title">Aviso</string>
   <string name="ssl_validator_header">A identidade do site não pode ser verificada</string>
index fcc85f2..8b54214 100644 (file)
@@ -1,6 +1,6 @@
 <?xml version='1.0' encoding='UTF-8'?>
 <resources>
-  <string name="app_name">%1$s</string>
+  <string name="app_name">ownCloud</string>
   <string name="main_password">Palavra-passe:</string>
   <string name="main_login">Nome de Utilizador:</string>
   <string name="main_button_login">Login</string>
@@ -12,7 +12,7 @@
   <string name="main_bookmarks">Marcadores</string>
   <string name="main_settings">Definições</string>
   <string name="main_tit_accsetup">Configurar conta</string>
-  <string name="main_wrn_accsetup">Não há contas ownCloud no seu aparelho. Para usar esta Aplicação, precisa de criar uma.</string>
+  <string name="main_wrn_accsetup">Não há contas no seu aparelho. Para usar esta Aplicação, precisa de criar uma.</string>
   <string name="about_message">cliente Android  %1$s\n\nversão: %1$s</string>
   <string name="actionbar_sync">Actualizar</string>
   <string name="actionbar_upload">Enviar</string>
index cafa2d6..1ccdd0b 100644 (file)
@@ -3,7 +3,7 @@
   <string name="app_name">ownCloud</string>
   <string name="main_password">Heslo:</string>
   <string name="main_login">Meno:</string>
-  <string name="main_button_login">Login</string>
+  <string name="main_button_login">Prihlásenie</string>
   <string name="main_welcome">Vitajte vo svojom ownCloud</string>
   <string name="main_files">Súbory</string>
   <string name="main_music">Hudba</string>
@@ -12,7 +12,7 @@
   <string name="main_bookmarks">Záložky</string>
   <string name="main_settings">Nastavenia</string>
   <string name="main_tit_accsetup">Nastavenie účtu</string>
-  <string name="main_wrn_accsetup">Vo vašom zariadení nie sú žiadne účty ownCloud. Vytvorte si účet ak chcete používať túto aplikáciu.</string>
+  <string name="main_wrn_accsetup">Vo vašom zariadení nie sú žiadne účty. Vytvorte si účet ak chcete používať túto aplikáciu.</string>
   <string name="about_message">%1$s Android App\n\nverzia: %2$s</string>
   <string name="actionbar_sync">Obnoviť</string>
   <string name="actionbar_upload">Nahraj súbor</string>
@@ -25,7 +25,7 @@
   <string name="prefs_category_trackmydevice">Sledovanie zariadenia</string>
   <string name="prefs_add_session">Vytvoriť nové sedenie</string>
   <string name="prefs_create_img_thumbnails">Vytvor náhľad obrázku</string>
-  <string name="prefs_select_oc_account">Výbor účet</string>
+  <string name="prefs_select_oc_account">Vyber účet</string>
   <string name="prefs_summary_select_oc_account">Vyberte účet pre túto aplikáciu.</string>
   <string name="prefs_trackmydevice">Sledovanie zariadenia</string>
   <string name="prefs_trackmydevice_summary_off">Povoliť sledovanie polohy zariadenia</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="auth_host_url">ownCloud URL</string>
-  <string name="auth_username">Používateľská meno</string>
+  <string name="auth_username">Používateľské meno</string>
   <string name="auth_password">Heslo</string>
-  <string name="auth_register">Som nový v ownCloud</string>
-  <string name="new_session_uri_error">Zadané nesprávne URL</string>
+  <string name="auth_register">Som nový v %1$s</string>
+  <string name="new_session_uri_error">Zadaná nesprávna URL</string>
   <string name="new_session_session_name_error">Nesprávny názov sedenia</string>
   <string name="sync_string_files">Súbory</string>
   <string name="uploader_no_file_selected">Nebol označený žiadny súbor pre odoslanie</string>
-  <string name="setup_hint_username">Meno užívateľa</string>
+  <string name="setup_hint_username">Meno používateľa</string>
   <string name="setup_hint_password">Heslo</string>
   <string name="setup_hint_address">Web adresa</string>
   <string name="setup_hint_show_password">Zobraziť heslo?</string>
   <string name="setup_title">Pripojiť k ownCloud</string>
   <string name="setup_btn_connect">Pripoj</string>
   <string name="uploader_btn_upload_text">Nahrať</string>
-  <string name="uploader_wrn_no_account_title">Účet sa nenašie</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 ownCloud účet. Zadajte ho prosím.</string>
   <string name="uploader_wrn_no_account_setup_btn_text">Nastavenie</string>
   <string name="uploader_wrn_no_account_quit_btn_text">Koniec</string>
@@ -61,7 +61,7 @@
   <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="uploader_btn_create_dir_text">Vytvoriť adresár pre nahrávanie</string>
+  <string name="uploader_btn_create_dir_text">Vytvoriť priečinok pre nahrávanie</string>
   <string name="file_list_empty">Priečinok neobsahuje súbory.\nNové súbory môžete pridať cez \"Upload\".</string>
   <string name="filedetails_select_file">Viac informácií získate kliknutím na súbor.</string>
   <string name="filedetails_size">Veľkosť:</string>
@@ -86,7 +86,7 @@
   <string name="delete_account">Zmazať účet</string>
   <string name="create_account">Vytvoriť účet</string>
   <string name="upload_chooser_title">Odoslať z ...</string>
-  <string name="uploader_info_dirname">Názov adresára</string>
+  <string name="uploader_info_dirname">Názov priečinka</string>
   <string name="uploader_upload_in_progress_ticker">Odosielam ...</string>
   <string name="uploader_upload_in_progress_content">%1$d%% Odosielam %2$s</string>
   <string name="uploader_upload_succeeded_ticker">Odoslanie bolo úspešné</string>
   <string name="use_ssl">Použiť zabezpečené pripojenie</string>
   <string name="location_no_provider">ownCloud nemôže sledovať polohu vášho zariadenia. Skontrolujte nastavenia umiestnenia.</string>
   <string name="pincode_enter_pin_code">Zadajte PIN aplikácie</string>
-  <string name="pincode_enter_new_pin_code">Zadajte nové PIN aplikácie</string>
-  <string name="pincode_configure_your_pin">Zadajte PIN ownCloud aplikácie</string>
+  <string name="pincode_enter_new_pin_code">Zadajte nový 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 ownCloud aplikácie</string>
-  <string name="pincode_remove_your_pincode">Zrušiť PIN pre ownCloud aplikáciu</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_wrong">Nesprávny PIN aplikácie</string>
   <string name="pincode_removed">PIN aplikácie bol odstránený</string>
     <item>60</item>
   </string-array>
   <string name="auth_trying_to_login">Pokus o pripojenie...</string>
-  <string name="auth_no_net_conn_title">Bez siete</string>
+  <string name="auth_no_net_conn_title">Bez sieťového pripojenia</string>
   <string name="auth_no_net_conn_message">Skontrolujte pripojenie k sieti a opakujte pripojenie znovu.</string>
   <string name="auth_connect_anyway">Aj tak pripojiť</string>
   <string name="auth_nossl_plain_ok_title">Nie je k dispozícii bezpečné pripojenie</string>
   <string name="auth_connection_established">Pripojenie vytvorené</string>
   <string name="auth_testing_connection">Testovane pripojenia...</string>
   <string name="auth_not_configured_title">Nesprávna konfigurácia ownCloud</string>
-  <string name="auth_not_configured_message">Nastavenie ownCloud nie je správne. Kontaktujte správcu pre získanie viac informácií.</string>
+  <string name="auth_not_configured_message">Nastavenie ownCloud nie je správne. Kontaktujte administrátora pre získanie viac informácií.</string>
   <string name="auth_unknown_error_title">Nastala neznáma chyba!</string>
   <string name="auth_unknown_error_message">Nastala neznáma chyba. Kontaktujte podporu a pripojte záznam z Vášho zariadenia.</string>
   <string name="auth_unknown_host_title">Nemožno nájsť hosta</string>
   <string name="auth_unknown_host_message">Nemôžm sa pripojiť k serveru. Skontrolujte nastavenia servera, či beží a skúste to znovu.</string>
-  <string name="auth_incorrect_path_title">ownCloud instance not found</string>
+  <string name="auth_incorrect_path_title">ownCloud inštancia nebola nájdená</string>
   <string name="auth_incorrect_path_message">Aplikácia na zadanej adrese nenašla inštanciu ownCloud. Skontrolujte cestu a skúste to znovu.</string>
   <string name="auth_timeout_title">Serveru trvá odpoveď príliš dlho</string>
   <string name="auth_incorrect_address_title">Poškodená URL</string>
diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml
new file mode 100644 (file)
index 0000000..c757504
--- /dev/null
@@ -0,0 +1,2 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<resources/>
index 11f0268..81124e8 100644 (file)
 <?xml version='1.0' encoding='UTF-8'?>
 <resources>
+  <string name="app_name">ownCloud</string>
+  <string name="main_password">Лозинка:</string>
   <string name="main_login">Корисничко име:</string>
-  <string name="main_button_login">Ð\9fÑ\80иÑ\98ава</string>
-  <string name="main_files">ФаÑ\98лови</string>
+  <string name="main_button_login">Ð\9fÑ\80иÑ\98ави Ð¼Ðµ</string>
+  <string name="main_files">Ð\94аÑ\82оÑ\82еке</string>
   <string name="main_music">Музика</string>
   <string name="main_contacts">Контакти</string>
-  <string name="main_settings">Подешавања</string>
-  <string name="actionbar_upload">Пошаљи</string>
-  <string name="actionbar_upload_files">Фајлови</string>
-  <string name="actionbar_settings">Подешавања</string>
+  <string name="main_calendar">Календар</string>
+  <string name="main_bookmarks">Обележивачи</string>
+  <string name="main_settings">Поставке</string>
+  <string name="main_tit_accsetup">Подешавање налога</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_search">Претражи</string>
+  <string name="actionbar_settings">Поставке</string>
   <string name="prefs_category_general">Опште</string>
+  <string name="prefs_category_trackmydevice">Праћење уређаја</string>
+  <string name="prefs_add_session">Додај нову сесију</string>
+  <string name="prefs_create_img_thumbnails">Направи умањене приказе слика</string>
+  <string name="prefs_select_oc_account">Изаберите налог</string>
+  <string name="prefs_trackmydevice_interval_summary">Ажурирај на %1$s мин.</string>
+  <string name="prefs_accounts">Налози</string>
+  <string name="prefs_instant_upload_summary">Тренутно отпремај фотографије сликане камером</string>
   <string name="auth_username">Корисничко име</string>
   <string name="auth_password">Лозинка</string>
   <string name="sync_string_files">Фајлови</string>
+  <string name="uploader_no_file_selected">Нисте изабрали датотеку за отпремање</string>
   <string name="setup_hint_username">Корисничко име</string>
   <string name="setup_hint_password">Лозинка</string>
-  <string name="uploader_btn_upload_text">Пошаљи</string>
-  <string name="filedetails_download">Преузимање</string>
+  <string name="setup_hint_address">Веб адреса</string>
+  <string name="setup_hint_show_password">Приказати лозинку?</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_wrn_no_content_title">Нема садржаја за отпремање</string>
+  <string name="uploader_wrn_no_content_text">Садржај није примљен. Нема ништа да се отпреми.</string>
+  <string name="uploader_info_uploading">Отпремање</string>
+  <string name="uploader_btn_create_dir_text">Направи фасциклу за отпремање</string>
+  <string name="file_list_empty">Нема датотека у овој фасцикли.\nНове датотеке можете да додате путем опције „Отпреми“.</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_open">Отвори</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_save_exit">Сачувај и изађи</string>
   <string name="common_error">Грешка</string>
+  <string name="about_title">О програму</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_failed_ticker">Отпремање није успело</string>
+  <string name="uploader_upload_failed_content_single">Не могу да довршим отпремање датотеке %1$s</string>
+  <string name="uploader_upload_failed_content_multiple">Отпремање није успело. Отпремљено датотека: %1$d/%2$d</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_string_contacts">Контакти</string>
-  <string name="common_share">Дељење</string>
+  <string name="sync_fail_ticker">Синхронизовање није успело</string>
+  <string name="sync_fail_content">Не могу да довршим синхронизацију датотеке %1$s</string>
+  <string name="use_ssl">Безбедна веза</string>
+  <string name="pincode_enter_pin_code">Унесите PIN апликације</string>
+  <string name="pincode_enter_new_pin_code">Унесите нови PIN апликације</string>
+  <string name="pincode_configure_your_pin_explanation">Са сваким покретањем апликације мораћете да унесете PIN</string>
+  <string-array name="prefs_trackmydevice_intervall_keys">
+    <item>15 минута</item>
+    <item>30 минута</item>
+    <item>60 минута</item>
+  </string-array>
+  <string-array name="prefs_trackmydevice_intervall_values">
+    <item>15</item>
+    <item>30</item>
+    <item>60</item>
+  </string-array>
+  <string name="auth_trying_to_login">Покушавам да вас пријавим…</string>
+  <string name="auth_no_net_conn_title">Нема мрежне везе</string>
+  <string name="auth_connect_anyway">Ипак ме повежи</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_unknown_host_message">Не могу да пронађем наведеног домаћина. Проверите име домаћина и доступност сервера па покушајте поново.</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_wrong_connection_title">Не могу да успоставим везу</string>
+  <string name="auth_secure_connection">Безбедна веза је успостављена</string>
+  <string name="auth_login_details">Подаци за пријаву</string>
+  <string name="crashlog_send_report">Пошаљи извештај</string>
+  <string name="crashlog_dont_send_report">Не шаљи извештај</string>
+  <string name="extensions_avail_title">Доступна су проширења.</string>
+  <string name="fd_keep_in_sync">Редовно ажурирај датотеку</string>
+  <string name="common_share">Дели</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_server_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_title">Упозорење</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_hostname_not_verified">– Адреса се не поклапа са именом домаћина у сертификату</string>
+  <string name="ssl_validator_certificate_not_available">Не могу да прибавим сертификат сервера</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="text_placeholder">Ово је чувар места</string>
+  <string name="instant_upload_on_wifi">Отпремај слике само путем бежичне мреже</string>
+  <string name="conflict_title">Ажурирај сукоб</string>
 </resources>
diff --git a/res/values-sw-rKE/strings.xml b/res/values-sw-rKE/strings.xml
new file mode 100644 (file)
index 0000000..c757504
--- /dev/null
@@ -0,0 +1,2 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<resources/>
index 905a8ae..be221b2 100644 (file)
@@ -15,6 +15,7 @@
   <string name="main_wrn_accsetup">Cihazınızda ownCloud hesabı bulunmamaktadır. Bu uygulamayı kullanabilmeniz için ownCloud hesabı oluşturmalısınız.</string>
   <string name="actionbar_sync">Eşitleme hesabi</string>
   <string name="actionbar_upload">Dosya 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_mkdir">Klasör yarat</string>
   <string name="actionbar_search">Arama</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">ownCloud, paylaşılan içeriğe erişim izni vermiyor</string>
   <string name="uploader_info_uploading">Yükleniyor</string>
   <string name="uploader_btn_create_dir_text">Yükleme için dizin oluştur</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="filedetails_size">Boyut:</string>
   <string name="filedetails_type">Tür:</string>
   <string name="common_choose_account">Hesap seçiniz</string>
   <string name="sync_string_contacts">Kontaklar</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_conflicts_in_favourites_ticker">Çakışma bulundu</string>
   <string name="use_ssl">Güvenli bağlanti kullan</string>
   <string name="location_no_provider">ownCloud cihazınızı takip edemiyor. Lütfen konum ayarlarınızı kontrol ediniz</string>
   <string name="pincode_enter_pin_code">Lütfen uygulama PIN\'ınızı giriniz</string>
   <string name="pincode_enter_new_pin_code">Lütfen yeni uygulama PIN\'ınızı giriniz</string>
   <string name="pincode_configure_your_pin">ownCloud App PIN giriniz</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, ownCloud App PIN ni tekrar giriniz</string>
   <string name="pincode_remove_your_pincode">ownCloud App PIN\'nizi kaldırınız.</string>
   <string name="pincode_mismatch">Her iki ownCloud App PIN aynı değil.</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_no_file_selected">Hiçbir dosya seçilmedi</string>
   <string name="ssl_validator_title">Uyarı</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_hostname_not_verified">- URL adresi sunucu isminin sertifikası ile uyuşmuyor</string>
   <string name="ssl_validator_certificate_not_available">Sunucu sertifikası elde edilemedi</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_label_signature_algorithm">Algoritma:</string>
   <string name="text_placeholder">Bu bir yer tutucudur</string>
   <string name="instant_upload_on_wifi">Resimleri sadece WiFi bağlantısında yükle</string>
+  <string name="instant_upload_path">/AnındaYükle</string>
   <string name="conflict_title">Çakışmayı güncelle</string>
   <string name="conflict_keep_both">İkisini de koru</string>
   <string name="conflict_overwrite">Üzerine yaz</string>
index b7f4c4d..a835f25 100644 (file)
@@ -13,7 +13,7 @@
   <string name="main_settings">Налаштування</string>
   <string name="main_tit_accsetup">Налаштування облікового запису</string>
   <string name="main_wrn_accsetup">На Вашому пристрої відсутні облікові запси ownCloud. Для того, щоб користуватися цим ПО, Вам потрібно створити обліковий запис.</string>
-  <string name="about_message">ownCloud Android клієнт\n\nверсія: %1$s</string>
+  <string name="about_message">%1$s Android клієнт\n\nверсія: %2$s</string>
   <string name="actionbar_sync">Оновити</string>
   <string name="actionbar_upload">Відвантажити</string>
   <string name="actionbar_upload_from_apps">Вміст із інших програм</string>
@@ -31,7 +31,7 @@
   <string name="prefs_trackmydevice_summary_off">Дозволити ownCloud стежити за місцезнаходженням Вашого пристрою</string>
   <string name="prefs_trackmydevice_summary_on">Ваш ownCloud стежить за цим пристроєм</string>
   <string name="prefs_trackmydevice_interval">Інтервал оновлення</string>
-  <string name="prefs_trackmydevice_interval_summary">Оновлювати кожні %1$ хвилин</string>
+  <string name="prefs_trackmydevice_interval_summary">Оновлювати кожні %1$s хвилин</string>
   <string name="prefs_accounts">Облікові записи</string>
   <string name="prefs_manage_accounts">Управління обліковими записами</string>
   <string name="prefs_pincode">ownCloud програмний PIN</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$ успішно завантажено</string>
+  <string name="downloader_download_succeeded_content">%1$s успішно завантажено</string>
   <string name="downloader_download_failed_ticker">Завантаження не вдалося</string>
-  <string name="downloader_download_failed_content">Завантаження %1$ не вдається завершити</string>
+  <string name="downloader_download_failed_content">Завантаження %1$s не вдається завершити</string>
   <string name="common_choose_account">Оберіть обліковий запис</string>
   <string name="sync_string_contacts">Контакти</string>
   <string name="sync_fail_ticker">Помилка синхронізації</string>
-  <string name="sync_fail_content">Синхронізація %1$не вдалась</string>
+  <string name="sync_fail_content">Синхронізація %1$не вдалась</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>
diff --git a/res/values-ur-rPK/strings.xml b/res/values-ur-rPK/strings.xml
new file mode 100644 (file)
index 0000000..1f54d77
--- /dev/null
@@ -0,0 +1,9 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<resources>
+  <string name="main_settings">سیٹینگز</string>
+  <string name="actionbar_settings">سیٹینگز</string>
+  <string name="auth_username">یوزر نیم</string>
+  <string name="auth_password">پاسورڈ</string>
+  <string name="setup_hint_username">یوزر نیم</string>
+  <string name="setup_hint_password">پاسورڈ</string>
+</resources>
index 86092fc..5875531 100644 (file)
   <string name="sync_fail_ticker">Đồng bộ thất bại</string>
   <string name="sync_fail_content">Đồng bộ %1$s không thể hoàn thành</string>
   <string name="sync_conflicts_in_favourites_ticker">Tìm thấy xung đột</string>
+  <string name="sync_conflicts_in_favourites_content">%1$d file trong hàng đợi đồng bộ không thể được đồng bộ</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="use_ssl">Sử dụng kết nối an toàn</string>
   <string name="location_no_provider">ownCloud không thể theo dõi điện thoại của bạn. Vui lòng kiểm tra cài đặt vị trí của bạn</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_login_details">Chi tiết đăng nhập</string>
+  <string name="auth_unauthorized">Sai tên đăng nhập/ mật khẩu</string>
   <string name="auth_not_found">Đường dẫn đã cho không đúng</string>
   <string name="auth_internal">Lỗi máy chủ nội bộ, mã lỗi %1$d</string>
   <string name="crashlog_message">Ứng dụng chấm dứt đột ngột. Bạn có muốn gửi báo cáo sự cố?</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="confirmation_remove_remote_and_local">Remote và local</string>
   <string name="remove_success_msg">Xóa thành công</string>
   <string name="ssl_validator_label_signature_algorithm">Thuật toán :</string>
   <string name="text_placeholder">Vị trí này đã được đặt chỗ trước</string>
   <string name="instant_upload_on_wifi">Tải hình ảnh lên thông qua WiFi</string>
+  <string name="instant_upload_path">/Upload tức thì</string>
   <string name="conflict_title">Cập nhật xung đột</string>
   <string name="conflict_message">%s là tập tin từ xa nó không đồng bộ với tập tin máy bạn . Nếu bạn tiếp tục sẽ thay đổi nội dung của tập tin trên máy chủ.</string>
   <string name="conflict_keep_both">Giữ cho cả hai</string>
index b45ca46..c56e4ca 100644 (file)
   <string name="filedetails_sync_file">刷新</string>
   <string name="filedetails_redownload">重新下载</string>
   <string name="filedetails_open">打开</string>
+  <string name="filedetails_renamed_in_upload_msg">文件在上传过程中被重命名为 %1$s </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="sync_string_contacts">联系人</string>
   <string name="sync_fail_ticker">同步失败</string>
   <string name="sync_fail_content">不能完成 %1$s 的同步</string>
+  <string name="sync_conflicts_in_favourites_ticker">存在冲突</string>
+  <string name="sync_conflicts_in_favourites_content">%1$d 计划同步文件无法同步</string>
   <string name="use_ssl">使用安全连接</string>
   <string name="location_no_provider">ownCloud 不能跟踪您的设备。请检查您的位置设置</string>
   <string name="pincode_enter_pin_code">请插入您的应用 PIN</string>
index e85f14a..a0437a5 100644 (file)
   <string name="sync_fail_ticker">同步失败</string>
   <string name="sync_fail_content"> %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="use_ssl">使用安全链接</string>
   <string name="location_no_provider">ownCloud不能跟踪你的设备。请检查你的位置设置。</string>
   <string name="ssl_validator_label_signature_algorithm">算法:</string>
   <string name="text_placeholder">占位符一枚</string>
   <string name="instant_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>
index 5da0767..7e3df8d 100644 (file)
@@ -4,7 +4,7 @@
   <string name="main_password">密碼:</string>
   <string name="main_login">使用者名稱:</string>
   <string name="main_button_login">登入</string>
-  <string name="main_welcome">歡迎來到您的ownCloud</string>
+  <string name="main_welcome">歡迎</string>
   <string name="main_files">檔案</string>
   <string name="main_music">音樂</string>
   <string name="main_contacts">通訊錄</string>
   <string name="main_bookmarks">書籤</string>
   <string name="main_settings">設定</string>
   <string name="main_tit_accsetup">設定帳號</string>
-  <string name="main_wrn_accsetup">您尚未在裝置上設定您的ownCloud帳號. 您必需建立一組帳號才能繼續使用.</string>
-  <string name="actionbar_sync">更新</string>
+  <string name="main_wrn_accsetup">您尚未在裝置上設定您的 ownCloud 帳號,您必需建立一組帳號才能繼續使用。</string>
+  <string name="actionbar_sync">重新整理</string>
   <string name="actionbar_upload">上傳檔案</string>
   <string name="actionbar_upload_files">檔案</string>
   <string name="actionbar_mkdir">建立目錄</string>
   <string name="actionbar_search">搜尋</string>
   <string name="actionbar_settings">設定</string>
   <string name="prefs_category_general">一般</string>
+  <string name="prefs_category_trackmydevice">裝置追蹤</string>
+  <string name="prefs_add_session">增加新連線</string>
   <string name="prefs_create_img_thumbnails">建立圖片縮圖</string>
   <string name="prefs_select_oc_account">選擇一個帳號</string>
+  <string name="prefs_summary_select_oc_account">您要使用哪幾個帳號?</string>
+  <string name="prefs_trackmydevice">裝置追蹤</string>
+  <string name="prefs_trackmydevice_summary_off">啓用此應用程式以追蹤所在位置</string>
+  <string name="prefs_trackmydevice_summary_on">此應用程式會追蹤這個裝置</string>
   <string name="prefs_trackmydevice_interval">更新間隔</string>
   <string name="prefs_trackmydevice_interval_summary">每 %1$s 分鐘更新</string>
   <string name="prefs_accounts">帳號</string>
   <string name="prefs_manage_accounts">管理帳號</string>
   <string name="prefs_pincode_summary">保護您的ownCloud用戶端</string>
   <string name="prefs_instant_upload">啟用即時上傳</string>
-  <string name="auth_host_url">網址URL</string>
+  <string name="auth_host_url">URL</string>
   <string name="auth_username">使用者名稱</string>
   <string name="auth_password">密碼</string>
-  <string name="new_session_uri_error">錯誤的URL</string>
+  <string name="new_session_uri_error">錯誤的位址</string>
+  <string name="new_session_session_name_error">錯誤的連線名稱</string>
   <string name="sync_string_files">檔案</string>
+  <string name="uploader_no_file_selected">未選擇任何要上傳的檔案</string>
   <string name="setup_hint_username">使用者名稱</string>
   <string name="setup_hint_password">密碼</string>
-  <string name="setup_title">連線至您的ownCloud</string>
+  <string name="setup_hint_address">網頁位址</string>
+  <string name="setup_hint_show_password">顯示密碼?</string>
+  <string name="setup_title">連線至您的 %1$s</string>
   <string name="setup_btn_connect">連線</string>
   <string name="uploader_btn_upload_text">上傳</string>
   <string name="uploader_wrn_no_account_title">找不到帳號</string>
@@ -44,6 +54,7 @@
   <string name="uploader_wrn_no_account_quit_btn_text">離開</string>
   <string name="uploader_info_uploading">上傳中</string>
   <string name="uploader_btn_create_dir_text">建立上傳目錄</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_open">開啟</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_save_exit">儲存並離開</string>
   <string name="common_exit">離開ownCloud</string>
   <string name="common_error">錯誤</string>
   <string name="about_title">關於</string>
   <string name="downloader_download_failed_ticker">下載失敗</string>
   <string name="common_choose_account">選擇帳號</string>
   <string name="sync_string_contacts">通訊錄</string>
+  <string name="use_ssl">使用安全連線</string>
+  <string name="location_no_provider">%1$s 無法追蹤您的裝置,請檢查定位服務設定</string>
+  <string name="pincode_enter_pin_code">請輸入您的 App PIN</string>
+  <string name="pincode_enter_new_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-array name="prefs_trackmydevice_intervall_keys">
+    <item>15 分鐘</item>
+    <item>30 分鐘</item>
+    <item>60 分鐘</item>
+  </string-array>
   <string-array name="prefs_trackmydevice_intervall_values">
     <item>15</item>
     <item>30</item>
     <item>60</item>
   </string-array>
+  <string name="auth_trying_to_login">嘗試登入...</string>
+  <string name="auth_no_net_conn_title">沒有網際網路連線</string>
+  <string name="auth_no_net_conn_message">沒有偵測到網際網路連線,請檢查您的連線然後再試一次。</string>
+  <string name="auth_connect_anyway">繼續連線</string>
+  <string name="auth_nossl_plain_ok_title">安全連線不可用。</string>
+  <string name="auth_nossl_plain_ok_message">無法與伺服器建立安全連線,可以使用不安全連線(未加密)以繼續,您可以繼續或取消。</string>
+  <string name="auth_connection_established">連線已建立</string>
+  <string name="auth_testing_connection">測試連線...</string>
+  <string name="auth_not_configured_title">伺服器設定有問題</string>
+  <string name="auth_not_configured_message">看起來您的伺服器並未被正確設定,請聯絡服務管理者以取得協助。</string>
+  <string name="auth_unknown_error_title">發生未知的錯誤!</string>
+  <string name="auth_unknown_error_message">發生未知的錯誤,請聯絡支援服務並附上您的記錄檔。</string>
+  <string name="auth_incorrect_path_title">找不到伺服器</string>
+  <string name="auth_incorrect_path_message">在指定的路徑找不到伺服器,請檢查您的路徑然後再試一次。</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">無法辨識的ownCloud伺服器版本</string>
   <string name="auth_wrong_connection_title">無法建立連線</string>
+  <string name="auth_secure_connection">安全連線已建立</string>
+  <string name="auth_login_details">登入細節</string>
   <string name="fd_keep_in_sync">讓檔案保持最新的</string>
   <string name="common_share">分享</string>
   <string name="common_rename">重新命名</string>
index 644e618..f54a5d5 100644 (file)
@@ -2,7 +2,6 @@
 <resources>
 
     <string name="app_name">ownCloud</string>
-    <string name="whats_new">What\'s new</string>
     <string name="main_password">Password:</string>
     <string name="main_login">Username:</string>
     <string name="main_button_login">Login</string>
@@ -23,8 +22,9 @@
     <string name="actionbar_mkdir">Create directory</string>
     <string name="actionbar_search">Search</string>
     <string name="actionbar_settings">Settings</string>
+    <string name="actionbar_see_details">Details</string>
+    
     <string name="prefs_category_general">General</string>
-    <string name="prefs_category_trackmydevice">Device tracking</string>
     <string name="prefs_add_session">Add new session</string>
     <string name="prefs_create_img_thumbnails">Create image thumbnails</string>
     <string name="prefs_select_oc_account">Select an account</string>
@@ -55,6 +55,7 @@
     <string name="setup_title">Connect to your %1$s</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_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>
@@ -84,6 +85,8 @@
     <string name="common_save_exit">Save &amp; Exit</string>
     <string name="common_exit">Leave %1$s</string>
     <string name="common_error">Error</string>
+    <string name="common_loading">Loading &#8230;</string>
+    <string name="common_error_unknown">Unknown error</string>
     <string name="about_title">About</string>
     <string name="delete_account">Delete account</string>
     <string name="create_account">Create account</string>
     <string name="downloader_download_succeeded_content">%1$s was successfully downloaded</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="common_choose_account">Choose account</string>
     <string name="sync_string_contacts">Contacts</string>
     <string name="sync_fail_ticker">Synchronization failed</string>
     <string name="pincode_wrong">Incorrect App PIN</string>
     <string name="pincode_removed">App PIN removed</string>
     <string name="pincode_stored">App PIN stored</string>
-
+    
+    <string name="media_notif_ticker">"%1$s music player"</string>
+    <string name="media_state_playing">"%1$s (playing)"</string>
+    <string name="media_state_loading">"%1$s (loading)"</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">Too much time 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_previous_description">Previous track button</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="media_next_description">Next track button</string>
     <string-array name="prefs_trackmydevice_intervall_keys">
         <item>15 Minutes</item>
         <item>30 Minutes</item>
     <string name="ssl_validator_label_L">Location:</string>
     <string name="ssl_validator_label_validity">Validity:</string>
     <string name="ssl_validator_label_validity_from">From:</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="text_placeholder">This is a placeholder</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="placeholder_sentence">This is a placeholder</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">Upload pictures via WiFi only</string>
     <string name="instant_upload_path">/InstantUpload</string>
     <string name="conflict_title">Update conflict</string>
     <string name="conflict_keep_both">Keep both</string>
     <string name="conflict_overwrite">Overwrite</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_out_of_memory">"Not enough memory to show this image</string>
+    
     <!-- we need to improve the communication of errors to the user -->
     <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_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>
-</resources>
\ No newline at end of file
+</resources>
index f38b2e7..dd1893a 100644 (file)
@@ -61,7 +61,9 @@ public class AccountUtils {
                     break;\r
                 }\r
             }\r
-        } else if (ocAccounts.length != 0) {\r
+        }\r
+        \r
+        if (defaultAccount == null && ocAccounts.length != 0) {\r
             // we at least need to take first account as fallback\r
             defaultAccount = ocAccounts[0];\r
         }\r
@@ -84,11 +86,26 @@ public class AccountUtils {
     }\r
     \r
     \r
-    public static void setCurrentOwnCloudAccount(Context context, String name) {\r
-        SharedPreferences.Editor appPrefs = PreferenceManager\r
-                .getDefaultSharedPreferences(context).edit();\r
-        appPrefs.putString("select_oc_account", name);\r
-        appPrefs.commit();\r
+    public static boolean setCurrentOwnCloudAccount(Context context, String accountName) {\r
+        boolean result = false;\r
+        if (accountName != null) {\r
+            Account[] ocAccounts = AccountManager.get(context).getAccountsByType(\r
+                    AccountAuthenticator.ACCOUNT_TYPE);\r
+            boolean found = false;\r
+            for (Account account : ocAccounts) {\r
+                found = (account.name.equals(accountName));\r
+                if (found) {\r
+                    SharedPreferences.Editor appPrefs = PreferenceManager\r
+                            .getDefaultSharedPreferences(context).edit();\r
+                    appPrefs.putString("select_oc_account", accountName);\r
+    \r
+                    appPrefs.commit();\r
+                    result = true;\r
+                    break;\r
+                }\r
+            }\r
+        }\r
+        return result;\r
     }\r
 \r
     /**\r
index 12b615e..70a9672 100644 (file)
@@ -145,7 +145,7 @@ public class DisplayUtils {
         } else {\r
             String [] parts = mimetype.split("/");\r
             String type = parts[0];\r
-            String subtype = parts[1];\r
+            String subtype = (parts.length > 1) ? parts[1] : "";\r
             \r
             if(TYPE_TXT.equals(type)) {\r
                 return R.drawable.file_doc;\r
index 6f9dc6d..2a83179 100644 (file)
-/* ownCloud Android client application\r
- *   Copyright (C) 2012  Bartek Przybylski\r
- *   Copyright (C) 2012-2013 ownCloud Inc.\r
- *\r
- *   This program is free software: you can redistribute it and/or modify\r
- *   it under the terms of the GNU General Public License as published by\r
- *   the Free Software Foundation, either version 2 of the License, or\r
- *   (at your option) any later version.\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
-import java.io.File;\r
-import java.util.ArrayList;\r
-import java.util.HashMap;\r
-import java.util.LinkedList;\r
-import java.util.List;\r
-import java.util.Stack;\r
-import java.util.Vector;\r
-\r
-import com.owncloud.android.authenticator.AccountAuthenticator;\r
-import com.owncloud.android.datamodel.DataStorageManager;\r
-import com.owncloud.android.datamodel.FileDataStorageManager;\r
-import com.owncloud.android.datamodel.OCFile;\r
-import com.owncloud.android.files.services.FileUploader;\r
-import com.owncloud.android.network.OwnCloudClientUtils;\r
-\r
-import android.accounts.Account;\r
-import android.accounts.AccountManager;\r
-import android.app.AlertDialog;\r
-import android.app.AlertDialog.Builder;\r
-import android.app.Dialog;\r
-import android.app.ListActivity;\r
-import android.app.ProgressDialog;\r
-import android.content.Context;\r
-import android.content.DialogInterface;\r
-import android.content.DialogInterface.OnCancelListener;\r
-import android.content.DialogInterface.OnClickListener;\r
-import android.content.Intent;\r
-import android.database.Cursor;\r
-import android.net.Uri;\r
-import android.os.Bundle;\r
-import android.os.Parcelable;\r
-import android.provider.MediaStore.Images.Media;\r
-import android.util.Log;\r
-import android.view.View;\r
-import android.view.Window;\r
-import android.widget.AdapterView;\r
-import android.widget.AdapterView.OnItemClickListener;\r
-import android.widget.Button;\r
-import android.widget.EditText;\r
-import android.widget.SimpleAdapter;\r
-import android.widget.Toast;\r
-\r
-import com.owncloud.android.R;\r
-import eu.alefzero.webdav.WebdavClient;\r
-\r
-/**\r
- * This can be used to upload things to an ownCloud instance.\r
- * \r
- * @author Bartek Przybylski\r
- * \r
- */\r
-public class Uploader extends ListActivity implements OnItemClickListener, android.view.View.OnClickListener {\r
-    private static final String TAG = "ownCloudUploader";\r
-\r
-    private Account mAccount;\r
-    private AccountManager mAccountManager;\r
-    private Stack<String> mParents;\r
-    private ArrayList<Parcelable> mStreamsToUpload;\r
-    private boolean mCreateDir;\r
-    private String mUploadPath;\r
-    private static final String[] CONTENT_PROJECTION = { Media.DATA, Media.DISPLAY_NAME, Media.MIME_TYPE, Media.SIZE };\r
-    private DataStorageManager mStorageManager;\r
-    private OCFile mFile;\r
-\r
-    private final static int DIALOG_NO_ACCOUNT = 0;\r
-    private final static int DIALOG_WAITING = 1;\r
-    private final static int DIALOG_NO_STREAM = 2;\r
-    private final static int DIALOG_MULTIPLE_ACCOUNT = 3;\r
-    //private final static int DIALOG_GET_DIRNAME = 4;\r
-\r
-    private final static int REQUEST_CODE_SETUP_ACCOUNT = 0;\r
-\r
-    @Override\r
-    protected void onCreate(Bundle savedInstanceState) {\r
-        super.onCreate(savedInstanceState);\r
-        getWindow().requestFeature(Window.FEATURE_NO_TITLE);\r
-        mParents = new Stack<String>();\r
-        mParents.add("");\r
-        /*if (getIntent().hasExtra(Intent.EXTRA_STREAM)) {\r
-            prepareStreamsToUpload();*/\r
-        if (prepareStreamsToUpload()) {\r
-            mAccountManager = (AccountManager) getSystemService(Context.ACCOUNT_SERVICE);\r
-            Account[] accounts = mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE);\r
-            if (accounts.length == 0) {\r
-                Log.i(TAG, "No ownCloud account is available");\r
-                showDialog(DIALOG_NO_ACCOUNT);\r
-            } else if (accounts.length > 1) {\r
-                Log.i(TAG, "More then one ownCloud is available");\r
-                showDialog(DIALOG_MULTIPLE_ACCOUNT);\r
-            } else {\r
-                mAccount = accounts[0];\r
-                mStorageManager = new FileDataStorageManager(mAccount, getContentResolver());\r
-                populateDirectoryList();\r
-            }\r
-        } else {\r
-            showDialog(DIALOG_NO_STREAM);\r
-        }\r
-    }\r
-    \r
-    @Override\r
-    protected Dialog onCreateDialog(final int id) {\r
-        final AlertDialog.Builder builder = new Builder(this);\r
-        switch (id) {\r
-        case DIALOG_WAITING:\r
-            ProgressDialog pDialog = new ProgressDialog(this);\r
-            pDialog.setIndeterminate(false);\r
-            pDialog.setCancelable(false);\r
-            pDialog.setMessage(getResources().getString(R.string.uploader_info_uploading));\r
-            return pDialog;\r
-        case DIALOG_NO_ACCOUNT:\r
-            builder.setIcon(android.R.drawable.ic_dialog_alert);\r
-            builder.setTitle(R.string.uploader_wrn_no_account_title);\r
-            builder.setMessage(String.format(getString(R.string.uploader_wrn_no_account_text), getString(R.string.app_name)));\r
-            builder.setCancelable(false);\r
-            builder.setPositiveButton(R.string.uploader_wrn_no_account_setup_btn_text, new OnClickListener() {\r
-                @Override\r
-                public void onClick(DialogInterface dialog, int which) {\r
-                    if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.ECLAIR_MR1) {\r
-                        // using string value since in API7 this\r
-                        // constatn is not defined\r
-                        // in API7 < this constatant is defined in\r
-                        // Settings.ADD_ACCOUNT_SETTINGS\r
-                        // and Settings.EXTRA_AUTHORITIES\r
-                        Intent intent = new Intent("android.settings.ADD_ACCOUNT_SETTINGS");\r
-                        intent.putExtra("authorities", new String[] { AccountAuthenticator.AUTH_TOKEN_TYPE });\r
-                        startActivityForResult(intent, REQUEST_CODE_SETUP_ACCOUNT);\r
-                    } else {\r
-                        // since in API7 there is no direct call for\r
-                        // account setup, so we need to\r
-                        // show our own AccountSetupAcricity, get\r
-                        // desired results and setup\r
-                        // everything for ourself\r
-                        Intent intent = new Intent(getBaseContext(), AccountAuthenticator.class);\r
-                        startActivityForResult(intent, REQUEST_CODE_SETUP_ACCOUNT);\r
-                    }\r
-                }\r
-            });\r
-            builder.setNegativeButton(R.string.uploader_wrn_no_account_quit_btn_text, new OnClickListener() {\r
-                @Override\r
-                public void onClick(DialogInterface dialog, int which) {\r
-                    finish();\r
-                }\r
-            });\r
-            return builder.create();\r
-        /*case DIALOG_GET_DIRNAME:\r
-            final EditText dirName = new EditText(getBaseContext());\r
-            builder.setView(dirName);\r
-            builder.setTitle(R.string.uploader_info_dirname);\r
-            String pathToUpload;\r
-            if (mParents.empty()) {\r
-                pathToUpload = "/";\r
-            } else {\r
-                mCursor = managedQuery(Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_FILE, mParents.peek()), null,\r
-                        null, null, null);\r
-                mCursor.moveToFirst();\r
-                pathToUpload = mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_PATH))\r
-                        + mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_NAME)).replace(" ", "%20");   // TODO don't make this ; use WebdavUtils.encode in the right moment\r
-            }\r
-            a a = new a(pathToUpload, dirName);\r
-            builder.setPositiveButton(R.string.common_ok, a);\r
-            builder.setNegativeButton(R.string.common_cancel, new OnClickListener() {\r
-                public void onClick(DialogInterface dialog, int which) {\r
-                    dialog.cancel();\r
-                }\r
-            });\r
-            return builder.create();*/\r
-        case DIALOG_MULTIPLE_ACCOUNT:\r
-            CharSequence ac[] = new CharSequence[mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE).length];\r
-            for (int i = 0; i < ac.length; ++i) {\r
-                ac[i] = mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE)[i].name;\r
-            }\r
-            builder.setTitle(R.string.common_choose_account);\r
-            builder.setItems(ac, new OnClickListener() {\r
-                @Override\r
-                public void onClick(DialogInterface dialog, int which) {\r
-                    mAccount = mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE)[which];\r
-                    mStorageManager = new FileDataStorageManager(mAccount, getContentResolver());\r
-                    populateDirectoryList();\r
-                }\r
-            });\r
-            builder.setCancelable(true);\r
-            builder.setOnCancelListener(new OnCancelListener() {\r
-                @Override\r
-                public void onCancel(DialogInterface dialog) {\r
-                    dialog.cancel();\r
-                    finish();\r
-                }\r
-            });\r
-            return builder.create();\r
-        case DIALOG_NO_STREAM:\r
-            builder.setIcon(android.R.drawable.ic_dialog_alert);\r
-            builder.setTitle(R.string.uploader_wrn_no_content_title);\r
-            builder.setMessage(R.string.uploader_wrn_no_content_text);\r
-            builder.setCancelable(false);\r
-            builder.setNegativeButton(R.string.common_cancel, new OnClickListener() {\r
-                @Override\r
-                public void onClick(DialogInterface dialog, int which) {\r
-                    finish();\r
-                }\r
-            });\r
-            return builder.create();\r
-        default:\r
-            throw new IllegalArgumentException("Unknown dialog id: " + id);\r
-        }\r
-    }\r
-\r
-    class a implements OnClickListener {\r
-        String mPath;\r
-        EditText mDirname;\r
-\r
-        public a(String path, EditText dirname) {\r
-            mPath = path; \r
-            mDirname = dirname;\r
-        }\r
-\r
-        @Override\r
-        public void onClick(DialogInterface dialog, int which) {\r
-            Uploader.this.mUploadPath = mPath + mDirname.getText().toString();\r
-            Uploader.this.mCreateDir = true;\r
-            uploadFiles();\r
-        }\r
-    }\r
-\r
-    @Override\r
-    public void onBackPressed() {\r
-\r
-        if (mParents.size() <= 1) {\r
-            super.onBackPressed();\r
-            return;\r
-        } else {\r
-            mParents.pop();\r
-            populateDirectoryList();\r
-        }\r
-    }\r
-\r
-    @Override\r
-    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {\r
-        // click on folder in the list\r
-        Log.d(TAG, "on item click");\r
-        Vector<OCFile> tmpfiles = mStorageManager.getDirectoryContent(mFile);\r
-        if (tmpfiles.size() <= 0) return;\r
-        // filter on dirtype\r
-        Vector<OCFile> files = new Vector<OCFile>();\r
-        for (OCFile f : tmpfiles)\r
-            if (f.isDirectory())\r
-                files.add(f);\r
-        if (files.size() < position) {\r
-            throw new IndexOutOfBoundsException("Incorrect item selected");\r
-        }\r
-        mParents.push(files.get(position).getFileName());\r
-        populateDirectoryList();\r
-    }\r
-\r
-    @Override\r
-    public void onClick(View v) {\r
-        // click on button\r
-        switch (v.getId()) {\r
-        case R.id.uploader_choose_folder:\r
-            mUploadPath = "";   // first element in mParents is root dir, represented by ""; init mUploadPath with "/" results in a "//" prefix\r
-            for (String p : mParents)\r
-                mUploadPath += p + OCFile.PATH_SEPARATOR;\r
-            Log.d(TAG, "Uploading file to dir " + mUploadPath);\r
-\r
-            uploadFiles();\r
-\r
-            break;\r
-        /*case android.R.id.button1: // dynamic action for create aditional dir\r
-            showDialog(DIALOG_GET_DIRNAME);\r
-            break;*/\r
-        default:\r
-            throw new IllegalArgumentException("Wrong element clicked");\r
-        }\r
-    }\r
-\r
-    @Override\r
-    protected void onActivityResult(int requestCode, int resultCode, Intent data) {\r
-        super.onActivityResult(requestCode, resultCode, data);\r
-        Log.i(TAG, "result received. req: " + requestCode + " res: " + resultCode);\r
-        if (requestCode == REQUEST_CODE_SETUP_ACCOUNT) {\r
-            dismissDialog(DIALOG_NO_ACCOUNT);\r
-            if (resultCode == RESULT_CANCELED) {\r
-                finish();\r
-            }\r
-            Account[] accounts = mAccountManager.getAccountsByType(AccountAuthenticator.AUTH_TOKEN_TYPE);\r
-            if (accounts.length == 0) {\r
-                showDialog(DIALOG_NO_ACCOUNT);\r
-            } else {\r
-                // there is no need for checking for is there more then one\r
-                // account at this point\r
-                // since account setup can set only one account at time\r
-                mAccount = accounts[0];\r
-                populateDirectoryList();\r
-            }\r
-        }\r
-    }\r
-\r
-    private void populateDirectoryList() {\r
-        setContentView(R.layout.uploader_layout);\r
-\r
-        String full_path = "";\r
-        for (String a : mParents)\r
-            full_path += a + "/";\r
-        \r
-        Log.d(TAG, "Populating view with content of : " + full_path);\r
-        \r
-        mFile = mStorageManager.getFileByPath(full_path);\r
-        if (mFile != null) {\r
-            Vector<OCFile> files = mStorageManager.getDirectoryContent(mFile);\r
-            List<HashMap<String, Object>> data = new LinkedList<HashMap<String,Object>>();\r
-            for (OCFile f : files) {\r
-                HashMap<String, Object> h = new HashMap<String, Object>();\r
-                if (f.isDirectory()) {\r
-                    h.put("dirname", f.getFileName());\r
-                    data.add(h);\r
-                }\r
-            }\r
-            SimpleAdapter sa = new SimpleAdapter(this,\r
-                                                data,\r
-                                                R.layout.uploader_list_item_layout,\r
-                                                new String[] {"dirname"},\r
-                                                new int[] {R.id.textView1});\r
-            setListAdapter(sa);\r
-            Button btn = (Button) findViewById(R.id.uploader_choose_folder);\r
-            btn.setOnClickListener(this);\r
-            getListView().setOnItemClickListener(this);\r
-        }\r
-    }\r
-\r
-    private boolean prepareStreamsToUpload() {\r
-        if (getIntent().getAction().equals(Intent.ACTION_SEND)) {\r
-            mStreamsToUpload = new ArrayList<Parcelable>();\r
-            mStreamsToUpload.add(getIntent().getParcelableExtra(Intent.EXTRA_STREAM));\r
-        } else if (getIntent().getAction().equals(Intent.ACTION_SEND_MULTIPLE)) {\r
-            mStreamsToUpload = getIntent().getParcelableArrayListExtra(Intent.EXTRA_STREAM);\r
-        }\r
-        return (mStreamsToUpload != null && mStreamsToUpload.get(0) != null);\r
-    }\r
-\r
-    public void uploadFiles() {\r
-        try {\r
-            WebdavClient wdc = OwnCloudClientUtils.createOwnCloudClient(mAccount, getApplicationContext());\r
-\r
-            // create last directory in path if necessary\r
-            if (mCreateDir) {\r
-                wdc.createDirectory(mUploadPath);\r
-            }\r
-\r
-            String[] local = new String[mStreamsToUpload.size()], remote = new String[mStreamsToUpload.size()];\r
-\r
-            for (int i = 0; i < mStreamsToUpload.size(); ++i) {\r
-                Uri uri = (Uri) mStreamsToUpload.get(i);\r
-                if (uri.getScheme().equals("content")) {\r
-                    Cursor c = getContentResolver().query((Uri) mStreamsToUpload.get(i),\r
-                                                      CONTENT_PROJECTION,\r
-                                                      null,\r
-                                                      null,\r
-                                                      null);\r
-\r
-                    if (!c.moveToFirst())\r
-                        continue;\r
-\r
-                    final String display_name = c.getString(c.getColumnIndex(Media.DISPLAY_NAME)),\r
-                                data = c.getString(c.getColumnIndex(Media.DATA));\r
-                    local[i] = data;\r
-                    remote[i] = mUploadPath + display_name;\r
-                } else if (uri.getScheme().equals("file")) {\r
-                    final File file = new File(Uri.decode(uri.toString()).replace(uri.getScheme() + "://", ""));\r
-                    local[i] = file.getAbsolutePath();\r
-                    remote[i] = mUploadPath + file.getName();\r
-                }\r
-\r
-            }\r
-            Intent intent = new Intent(getApplicationContext(), FileUploader.class);\r
-            intent.putExtra(FileUploader.KEY_UPLOAD_TYPE, FileUploader.UPLOAD_MULTIPLE_FILES);\r
-            intent.putExtra(FileUploader.KEY_LOCAL_FILE, local);\r
-            intent.putExtra(FileUploader.KEY_REMOTE_FILE, remote);\r
-            intent.putExtra(FileUploader.KEY_ACCOUNT, mAccount);\r
-            startService(intent);\r
-            finish();\r
-            \r
-        } catch (SecurityException e) {\r
-            String message = String.format(getString(R.string.uploader_error_forbidden_content), getString(R.string.app_name));\r
-            Toast.makeText(this, message, Toast.LENGTH_LONG).show();            \r
-        }\r
-    }\r
-\r
-}\r
+/* 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 as published by
+ *   the Free Software Foundation, either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+package 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 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.util.Log;
+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;
+
+import com.owncloud.android.authenticator.AccountAuthenticator;
+import com.owncloud.android.datamodel.DataStorageManager;
+import com.owncloud.android.datamodel.FileDataStorageManager;
+import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.files.services.FileUploader;
+import com.owncloud.android.network.OwnCloudClientUtils;
+
+import eu.alefzero.webdav.WebdavClient;
+
+/**
+ * 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 DataStorageManager 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 DIALOG_GET_DIRNAME = 4;
+
+    private final static int REQUEST_CODE_SETUP_ACCOUNT = 0;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        getWindow().requestFeature(Window.FEATURE_NO_TITLE);
+        mParents = new Stack<String>();
+        mParents.add("");
+        /*if (getIntent().hasExtra(Intent.EXTRA_STREAM)) {
+            prepareStreamsToUpload();*/
+        if (prepareStreamsToUpload()) {
+            mAccountManager = (AccountManager) getSystemService(Context.ACCOUNT_SERVICE);
+            Account[] accounts = mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE);
+            if (accounts.length == 0) {
+                Log.i(TAG, "No ownCloud account is available");
+                showDialog(DIALOG_NO_ACCOUNT);
+            } else if (accounts.length > 1) {
+                Log.i(TAG, "More then one ownCloud is available");
+                showDialog(DIALOG_MULTIPLE_ACCOUNT);
+            } else {
+                mAccount = accounts[0];
+                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.settings.ADD_ACCOUNT_SETTINGS");
+                        intent.putExtra("authorities", new String[] { AccountAuthenticator.AUTH_TOKEN_TYPE });
+                        startActivityForResult(intent, REQUEST_CODE_SETUP_ACCOUNT);
+                    } else {
+                        // since in API7 there is no direct call for
+                        // account setup, so we need to
+                        // show our own AccountSetupAcricity, get
+                        // desired results and setup
+                        // everything for ourself
+                        Intent intent = new Intent(getBaseContext(), AccountAuthenticator.class);
+                        startActivityForResult(intent, REQUEST_CODE_SETUP_ACCOUNT);
+                    }
+                }
+            });
+            builder.setNegativeButton(R.string.uploader_wrn_no_account_quit_btn_text, new OnClickListener() {
+                @Override
+                public void onClick(DialogInterface dialog, int which) {
+                    finish();
+                }
+            });
+            return builder.create();
+        case DIALOG_MULTIPLE_ACCOUNT:
+            CharSequence ac[] = new CharSequence[mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE).length];
+            for (int i = 0; i < ac.length; ++i) {
+                ac[i] = mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE)[i].name;
+            }
+            builder.setTitle(R.string.common_choose_account);
+            builder.setItems(ac, new OnClickListener() {
+                @Override
+                public void onClick(DialogInterface dialog, int which) {
+                    mAccount = mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE)[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.d(TAG, "on item click");
+        Vector<OCFile> tmpfiles = mStorageManager.getDirectoryContent(mFile);
+        if (tmpfiles.size() <= 0) return;
+        // filter on dirtype
+        Vector<OCFile> files = new Vector<OCFile>();
+        for (OCFile f : tmpfiles)
+            if (f.isDirectory())
+                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.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.i(TAG, "result received. req: " + requestCode + " res: " + resultCode);
+        if (requestCode == REQUEST_CODE_SETUP_ACCOUNT) {
+            dismissDialog(DIALOG_NO_ACCOUNT);
+            if (resultCode == RESULT_CANCELED) {
+                finish();
+            }
+            Account[] accounts = mAccountManager.getAccountsByType(AccountAuthenticator.AUTH_TOKEN_TYPE);
+            if (accounts.length == 0) {
+                showDialog(DIALOG_NO_ACCOUNT);
+            } else {
+                // there is no need for checking for is there more then one
+                // account at this point
+                // since account setup can set only one account at time
+                mAccount = accounts[0];
+                populateDirectoryList();
+            }
+        }
+    }
+
+    private void populateDirectoryList() {
+        setContentView(R.layout.uploader_layout);
+
+        String full_path = "";
+        for (String a : mParents)
+            full_path += a + "/";
+        
+        Log.d(TAG, "Populating view with content of : " + full_path);
+        
+        mFile = mStorageManager.getFileByPath(full_path);
+        if (mFile != null) {
+            Vector<OCFile> files = mStorageManager.getDirectoryContent(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.isDirectory()) {
+                    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>();
+            
+            // create last directory in path if necessary
+            if (mCreateDir) {
+                webdav.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 3775347..14b69c7 100644 (file)
@@ -45,4 +45,6 @@ public interface DataStorageManager {
     public void removeDirectory(OCFile dir, boolean removeDBData, boolean removeLocalContent);
 
     public void moveDirectory(OCFile dir, String newPath);
+
+    public Vector<OCFile> getDirectoryImages(OCFile mParentFolder);
 }
index aa914c4..41aad01 100644 (file)
@@ -567,4 +567,21 @@ public class FileDataStorageManager implements DataStorageManager {
         }
     }
 
+    @Override
+    public Vector<OCFile> getDirectoryImages(OCFile directory) {
+        Vector<OCFile> ret = new Vector<OCFile>(); 
+        if (directory != null) {
+            // TODO better implementation, filtering in the access to database (if possible) instead of here 
+            Vector<OCFile> tmp = getDirectoryContent(directory);
+            OCFile current = null; 
+            for (int i=0; i<tmp.size(); i++) {
+                current = tmp.get(i);
+                if (current.isImage()) {
+                    ret.add(current);
+                }
+            }
+        }
+        return ret;
+    }
+
 }
index 668e991..8b07996 100644 (file)
@@ -21,9 +21,12 @@ package com.owncloud.android.datamodel;
 
 import java.io.File;
 
+import android.content.Intent;
+import android.net.Uri;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.Log;
+import android.webkit.MimeTypeMap;
 
 public class OCFile implements Parcelable, Comparable<OCFile> {
 
@@ -455,4 +458,30 @@ public class OCFile implements Parcelable, Comparable<OCFile> {
         return 0;
     }
 
+    /** @return  'True' if the file contains audio */
+    public boolean isAudio() {
+        return (mMimeType != null && mMimeType.startsWith("audio/"));
+    }
+
+    /** @return  'True' if the file contains video */
+    public boolean isVideo() {
+        return (mMimeType != null && mMimeType.startsWith("video/"));
+    }
+
+    /** @return  'True' if the file contains an image */
+    public boolean isImage() {
+        return ((mMimeType != null && mMimeType.startsWith("image/")) ||
+                 getMimeTypeFromName().startsWith("image/"));
+    }
+    
+    public String getMimeTypeFromName() {
+        String extension = "";
+        int pos = mRemotePath.lastIndexOf('.');
+        if (pos >= 0) {
+            extension = mRemotePath.substring(pos + 1);
+        }
+        String result = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension.toLowerCase());
+        return (result != null) ? result : "";
+    }
+
 }
index ac70e39..aa5583d 100644 (file)
@@ -21,7 +21,9 @@ package com.owncloud.android.files.services;
 \r
 import java.io.File;\r
 import java.util.AbstractList;\r
+import java.util.HashMap;\r
 import java.util.Iterator;\r
+import java.util.Map;\r
 import java.util.Vector;\r
 import java.util.concurrent.ConcurrentHashMap;\r
 import java.util.concurrent.ConcurrentMap;\r
@@ -35,6 +37,8 @@ import com.owncloud.android.operations.DownloadFileOperation;
 import com.owncloud.android.operations.RemoteOperationResult;\r
 import com.owncloud.android.ui.activity.FileDetailActivity;\r
 import com.owncloud.android.ui.fragment.FileDetailFragment;\r
+import com.owncloud.android.ui.preview.PreviewImageActivity;\r
+import com.owncloud.android.ui.preview.PreviewImageFragment;\r
 \r
 import android.accounts.Account;\r
 import android.app.Notification;\r
@@ -52,6 +56,7 @@ import android.os.Process;
 import android.util.Log;\r
 import android.widget.RemoteViews;\r
 \r
+import com.owncloud.android.AccountUtils;\r
 import com.owncloud.android.R;\r
 import eu.alefzero.webdav.WebdavClient;\r
 \r
@@ -136,6 +141,7 @@ public class FileDownloader extends Service implements OnDatatransferProgressLis
             DownloadFileOperation newDownload = new DownloadFileOperation(account, file); \r
             mPendingDownloads.putIfAbsent(downloadKey, newDownload);\r
             newDownload.addDatatransferProgressListener(this);\r
+            newDownload.addDatatransferProgressListener((FileDownloaderBinder)mBinder);\r
             requestedDownloads.add(downloadKey);\r
             sendBroadcastNewDownload(newDownload);\r
             \r
@@ -165,13 +171,29 @@ public class FileDownloader extends Service implements OnDatatransferProgressLis
         return mBinder;\r
     }\r
 \r
+\r
+    /**\r
+     * Called when ALL the bound clients were onbound.\r
+     */\r
+    @Override\r
+    public boolean onUnbind(Intent intent) {\r
+        ((FileDownloaderBinder)mBinder).clearListeners();\r
+        return false;   // not accepting rebinding (default behaviour)\r
+    }\r
+\r
     \r
     /**\r
      *  Binder to let client components to perform operations on the queue of downloads.\r
      * \r
      *  It provides by itself the available operations.\r
      */\r
-    public class FileDownloaderBinder extends Binder {\r
+    public class FileDownloaderBinder extends Binder implements OnDatatransferProgressListener {\r
+        \r
+        /** \r
+         * Map of listeners that will be reported about progress of downloads from a {@link FileDownloaderBinder} instance \r
+         */\r
+        private Map<String, OnDatatransferProgressListener> mBoundListeners = new HashMap<String, OnDatatransferProgressListener>();\r
+        \r
         \r
         /**\r
          * Cancels a pending or current download of a remote file.\r
@@ -190,6 +212,11 @@ public class FileDownloader extends Service implements OnDatatransferProgressLis
         }\r
         \r
         \r
+        public void clearListeners() {\r
+            mBoundListeners.clear();\r
+        }\r
+\r
+\r
         /**\r
          * Returns True when the file described by 'file' in the ownCloud account 'account' is downloading or waiting to download.\r
          * \r
@@ -215,6 +242,55 @@ public class FileDownloader extends Service implements OnDatatransferProgressLis
                 }\r
             }\r
         }\r
+\r
+        \r
+        /**\r
+         * Adds a listener interested in the progress of the download for a concrete file.\r
+         * \r
+         * @param listener      Object to notify about progress of transfer.    \r
+         * @param account       ownCloud account holding the file of interest.\r
+         * @param file          {@link OCfile} of interest for listener. \r
+         */\r
+        public void addDatatransferProgressListener (OnDatatransferProgressListener listener, Account account, OCFile file) {\r
+            if (account == null || file == null || listener == null) return;\r
+            String targetKey = buildRemoteName(account, file);\r
+            mBoundListeners.put(targetKey, listener);\r
+        }\r
+        \r
+        \r
+        \r
+        /**\r
+         * Removes a listener interested in the progress of the download for a concrete file.\r
+         * \r
+         * @param listener      Object to notify about progress of transfer.    \r
+         * @param account       ownCloud account holding the file of interest.\r
+         * @param file          {@link OCfile} of interest for listener. \r
+         */\r
+        public void removeDatatransferProgressListener (OnDatatransferProgressListener listener, Account account, OCFile file) {\r
+            if (account == null || file == null || listener == null) return;\r
+            String targetKey = buildRemoteName(account, file);\r
+            if (mBoundListeners.get(targetKey) == listener) {\r
+                mBoundListeners.remove(targetKey);\r
+            }\r
+        }\r
+\r
+\r
+        @Override\r
+        public void onTransferProgress(long progressRate) {\r
+            // old way, should not be in use any more\r
+        }\r
+\r
+\r
+        @Override\r
+        public void onTransferProgress(long progressRate, long totalTransferredSoFar, long totalToTransfer,\r
+                String fileName) {\r
+            String key = buildRemoteName(mCurrentDownload.getAccount(), mCurrentDownload.getFile());\r
+            OnDatatransferProgressListener boundListener = mBoundListeners.get(key);\r
+            if (boundListener != null) {\r
+                boundListener.onTransferProgress(progressRate, totalTransferredSoFar, totalToTransfer, fileName);\r
+            }\r
+        }\r
+        \r
     }\r
     \r
     \r
@@ -328,7 +404,12 @@ public class FileDownloader extends Service implements OnDatatransferProgressLis
         mNotification.contentView.setImageViewResource(R.id.status_icon, R.drawable.icon);\r
         \r
         /// includes a pending intent in the notification showing the details view of the file\r
-        Intent showDetailsIntent = new Intent(this, FileDetailActivity.class);\r
+        Intent showDetailsIntent = null;\r
+        if (PreviewImageFragment.canBePreviewed(download.getFile())) {\r
+            showDetailsIntent = new Intent(this, PreviewImageActivity.class);\r
+        } else {\r
+            showDetailsIntent = new Intent(this, FileDetailActivity.class);\r
+        }\r
         showDetailsIntent.putExtra(FileDetailFragment.EXTRA_FILE, download.getFile());\r
         showDetailsIntent.putExtra(FileDetailFragment.EXTRA_ACCOUNT, download.getAccount());\r
         showDetailsIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);\r
@@ -376,8 +457,22 @@ public class FileDownloader extends Service implements OnDatatransferProgressLis
             int contentId = (downloadResult.isSuccess()) ? R.string.downloader_download_succeeded_content : R.string.downloader_download_failed_content;\r
             Notification finalNotification = new Notification(R.drawable.icon, getString(tickerId), System.currentTimeMillis());\r
             finalNotification.flags |= Notification.FLAG_AUTO_CANCEL;\r
-            // TODO put something smart in the contentIntent below\r
-            finalNotification.contentIntent = PendingIntent.getActivity(getApplicationContext(), (int)System.currentTimeMillis(), new Intent(), 0);\r
+            Intent showDetailsIntent = null;\r
+            if (downloadResult.isSuccess()) {\r
+                if (PreviewImageFragment.canBePreviewed(download.getFile())) {\r
+                    showDetailsIntent = new Intent(this, PreviewImageActivity.class);\r
+                } else {\r
+                    showDetailsIntent = new Intent(this, FileDetailActivity.class);\r
+                }\r
+                showDetailsIntent.putExtra(FileDetailFragment.EXTRA_FILE, download.getFile());\r
+                showDetailsIntent.putExtra(FileDetailFragment.EXTRA_ACCOUNT, download.getAccount());\r
+                showDetailsIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);\r
+                \r
+            } else {\r
+                // TODO put something smart in showDetailsIntent\r
+                showDetailsIntent = new Intent();\r
+            }\r
+            finalNotification.contentIntent = PendingIntent.getActivity(getApplicationContext(), (int)System.currentTimeMillis(), showDetailsIntent, 0);\r
             finalNotification.setLatestEventInfo(getApplicationContext(), getString(tickerId), String.format(getString(contentId), new File(download.getSavePath()).getName()), finalNotification.contentIntent);\r
             mNotificationManager.notify(tickerId, finalNotification);\r
         }\r
@@ -407,8 +502,8 @@ public class FileDownloader extends Service implements OnDatatransferProgressLis
      */\r
     private void sendBroadcastNewDownload(DownloadFileOperation download) {\r
         Intent added = new Intent(DOWNLOAD_ADDED_MESSAGE);\r
-        /*added.putExtra(ACCOUNT_NAME, download.getAccount().name);\r
-        added.putExtra(EXTRA_REMOTE_PATH, download.getRemotePath());*/\r
+        added.putExtra(ACCOUNT_NAME, download.getAccount().name);\r
+        added.putExtra(EXTRA_REMOTE_PATH, download.getRemotePath());\r
         added.putExtra(EXTRA_FILE_PATH, download.getSavePath());\r
         sendStickyBroadcast(added);\r
     }\r
index 3de51b6..9d2bbcf 100644 (file)
@@ -21,7 +21,9 @@ package com.owncloud.android.files.services;
 
 import java.io.File;
 import java.util.AbstractList;
+import java.util.HashMap;
 import java.util.Iterator;
+import java.util.Map;
 import java.util.Vector;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
@@ -63,6 +65,8 @@ import com.owncloud.android.ui.activity.FailedUploadActivity;
 import com.owncloud.android.ui.activity.FileDetailActivity;
 import com.owncloud.android.ui.activity.InstantUploadActivity;
 import com.owncloud.android.ui.fragment.FileDetailFragment;
+import com.owncloud.android.ui.preview.PreviewImageActivity;
+import com.owncloud.android.ui.preview.PreviewImageFragment;
 import com.owncloud.android.utils.OwnCloudVersion;
 
 import eu.alefzero.webdav.OnDatatransferProgressListener;
@@ -118,8 +122,8 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
     /**
      * Builds a key for mPendingUploads from the account and file to upload
      * 
-     * @param account Account where the file to download is stored
-     * @param file File to download
+     * @param account   Account where the file to upload is stored
+     * @param file      File to upload
      */
     private String buildRemoteName(Account account, OCFile file) {
         return account.name + file.getRemotePath();
@@ -271,6 +275,7 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
                 }
                 mPendingUploads.putIfAbsent(uploadKey, newUpload);
                 newUpload.addDatatransferProgressListener(this);
+                newUpload.addDatatransferProgressListener((FileUploaderBinder)mBinder);
                 requestedUploads.add(uploadKey);
             }
 
@@ -309,6 +314,16 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
     public IBinder onBind(Intent arg0) {
         return mBinder;
     }
+    
+    /**
+     * Called when ALL the bound clients were onbound.
+     */
+    @Override
+    public boolean onUnbind(Intent intent) {
+        ((FileUploaderBinder)mBinder).clearListeners();
+        return false;   // not accepting rebinding (default behaviour)
+    }
+    
 
     /**
      * Binder to let client components to perform operations on the queue of
@@ -316,8 +331,13 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
      * 
      * It provides by itself the available operations.
      */
-    public class FileUploaderBinder extends Binder {
-
+    public class FileUploaderBinder extends Binder implements OnDatatransferProgressListener {
+        
+        /** 
+         * Map of listeners that will be reported about progress of uploads from a {@link FileUploaderBinder} instance 
+         */
+        private Map<String, OnDatatransferProgressListener> mBoundListeners = new HashMap<String, OnDatatransferProgressListener>();
+        
         /**
          * Cancels a pending or current upload of a remote file.
          * 
@@ -333,13 +353,21 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
                 upload.cancel();
             }
         }
+        
+        
+        
+        public void clearListeners() {
+            mBoundListeners.clear();
+        }
+
 
+        
+        
         /**
          * Returns True when the file described by 'file' is being uploaded to
          * the ownCloud account 'account' or waiting for it
          * 
-         * If 'file' is a directory, returns 'true' if some of its descendant
-         * files is downloading or waiting to download.
+         * If 'file' is a directory, returns 'true' if some of its descendant files is uploading or waiting to upload. 
          * 
          * @param account Owncloud account where the remote file will be stored.
          * @param file A file that could be in the queue of pending uploads
@@ -350,7 +378,7 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
             String targetKey = buildRemoteName(account, file);
             synchronized (mPendingUploads) {
                 if (file.isDirectory()) {
-                    // this can be slow if there are many downloads :(
+                    // this can be slow if there are many uploads :(
                     Iterator<String> it = mPendingUploads.keySet().iterator();
                     boolean found = false;
                     while (it.hasNext() && !found) {
@@ -362,6 +390,55 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
                 }
             }
         }
+
+
+        /**
+         * Adds a listener interested in the progress of the upload for a concrete file.
+         * 
+         * @param listener      Object to notify about progress of transfer.    
+         * @param account       ownCloud account holding the file of interest.
+         * @param file          {@link OCfile} of interest for listener. 
+         */
+        public void addDatatransferProgressListener (OnDatatransferProgressListener listener, Account account, OCFile file) {
+            if (account == null || file == null || listener == null) return;
+            String targetKey = buildRemoteName(account, file);
+            mBoundListeners.put(targetKey, listener);
+        }
+        
+        
+        
+        /**
+         * Removes a listener interested in the progress of the upload for a concrete file.
+         * 
+         * @param listener      Object to notify about progress of transfer.    
+         * @param account       ownCloud account holding the file of interest.
+         * @param file          {@link OCfile} of interest for listener. 
+         */
+        public void removeDatatransferProgressListener (OnDatatransferProgressListener listener, Account account, OCFile file) {
+            if (account == null || file == null || listener == null) return;
+            String targetKey = buildRemoteName(account, file);
+            if (mBoundListeners.get(targetKey) == listener) {
+                mBoundListeners.remove(targetKey);
+            }
+        }
+
+
+        @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());
+            OnDatatransferProgressListener boundListener = mBoundListeners.get(key);
+            if (boundListener != null) {
+                boundListener.onTransferProgress(progressRate, totalTransferredSoFar, totalToTransfer, fileName);
+            }
+        }
+        
     }
 
     /**
@@ -520,8 +597,7 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
         file.setMimetype(we.contentType());
         file.setModificationTimestamp(we.modifiedTimestamp());
         file.setModificationTimestampAtLastSyncForData(we.modifiedTimestamp());
-        // file.setEtag(mCurrentDownload.getEtag()); // TODO Etag, where
-        // available
+        // file.setEtag(mCurrentUpload.getEtag());    // TODO Etag, where available
     }
 
     private boolean checkAndFixInstantUploadDirectory(FileDataStorageManager storageManager) {
@@ -597,6 +673,7 @@ 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;
@@ -610,10 +687,15 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
         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);
-
-        // / includes a pending intent in the notification showing the details
-        // view of the file
-        Intent showDetailsIntent = new Intent(this, FileDetailActivity.class);
+        
+        /// 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, FileDetailActivity.class);
+            showDetailsIntent.putExtra(FileDetailActivity.EXTRA_MODE, FileDetailActivity.MODE_DETAILS);
+        }
         showDetailsIntent.putExtra(FileDetailFragment.EXTRA_FILE, upload.getFile());
         showDetailsIntent.putExtra(FileDetailFragment.EXTRA_ACCOUNT, upload.getAccount());
         showDetailsIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
@@ -668,10 +750,15 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
                                                                     // flag
             mNotification.flags |= Notification.FLAG_AUTO_CANCEL;
             mNotification.contentView = mDefaultNotificationContentView;
-
-            // / includes a pending intent in the notification showing the
-            // details view of the file
-            Intent showDetailsIntent = new Intent(this, FileDetailActivity.class);
+            
+            /// 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, FileDetailActivity.class); 
+                showDetailsIntent.putExtra(FileDetailActivity.EXTRA_MODE, FileDetailActivity.MODE_DETAILS);
+            }
             showDetailsIntent.putExtra(FileDetailFragment.EXTRA_FILE, upload.getFile());
             showDetailsIntent.putExtra(FileDetailFragment.EXTRA_ACCOUNT, upload.getAccount());
             showDetailsIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
@@ -714,7 +801,7 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
             // we add only for instant-uploads the InstantUploadActivity and the
             // db entry
             Intent detailUploadIntent = null;
-            if (upload.isInstant()) {
+            if (upload.isInstant() && InstantUploadActivity.IS_ENABLED) {
                 detailUploadIntent = new Intent(this, InstantUploadActivity.class);
                 detailUploadIntent.putExtra(FileUploader.KEY_ACCOUNT, upload.getAccount());
             } else {
diff --git a/src/com/owncloud/android/media/MediaControlView.java b/src/com/owncloud/android/media/MediaControlView.java
new file mode 100644 (file)
index 0000000..9f48123
--- /dev/null
@@ -0,0 +1,473 @@
+/* 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 as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+package com.owncloud.android.media;
+
+import android.content.Context;
+import android.media.MediaPlayer;
+import android.os.Handler;
+import android.os.Message;
+import android.util.AttributeSet;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.widget.FrameLayout;
+import android.widget.ImageButton;
+import android.widget.MediaController.MediaPlayerControl;
+import android.widget.ProgressBar;
+import android.widget.SeekBar;
+import android.widget.SeekBar.OnSeekBarChangeListener;
+import android.widget.TextView;
+
+import java.util.Formatter;
+import java.util.Locale;
+
+import com.owncloud.android.R;
+
+/**
+ * View containing controls for a {@link MediaPlayer}. 
+ * 
+ * Holds buttons "play / pause", "rewind", "fast forward" 
+ * and a progress slider. 
+ * 
+ * It synchronizes itself with the state of the 
+ * {@link MediaPlayer}.
+ * 
+ * @author David A. Velasco
+ */
+
+public class MediaControlView extends FrameLayout /* implements OnLayoutChangeListener, OnTouchListener */ implements OnClickListener, OnSeekBarChangeListener {
+
+    private MediaPlayerControl  mPlayer;
+    private Context             mContext;
+    private View                mRoot;
+    private ProgressBar         mProgress;
+    private TextView            mEndTime, mCurrentTime;
+    private boolean             mDragging;
+    private static final int    SHOW_PROGRESS = 1;
+    StringBuilder               mFormatBuilder;
+    Formatter                   mFormatter;
+    private ImageButton         mPauseButton;
+    private ImageButton         mFfwdButton;
+    private ImageButton         mRewButton;
+    
+    public MediaControlView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        mContext = context;
+        
+        FrameLayout.LayoutParams frameParams = new FrameLayout.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                ViewGroup.LayoutParams.MATCH_PARENT
+        );
+        LayoutInflater inflate = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+        mRoot = inflate.inflate(R.layout.media_control, null);
+        initControllerView(mRoot);
+        addView(mRoot, frameParams);
+        
+        setFocusable(true);
+        setFocusableInTouchMode(true);
+        setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
+        requestFocus();
+    }
+
+    @Override
+    public void onFinishInflate() {
+        /*
+        if (mRoot != null)
+            initControllerView(mRoot);
+         */
+    }
+
+    /* TODO REMOVE
+    public MediaControlView(Context context, boolean useFastForward) {
+        super(context);
+        mContext = context;
+        mUseFastForward = useFastForward;
+        initFloatingWindowLayout();
+        //initFloatingWindow();
+    }
+    */
+
+    /* TODO REMOVE
+    public MediaControlView(Context context) {
+        this(context, true);
+    }
+    */
+    
+    /* T
+    private void initFloatingWindow() {
+        mWindowManager = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
+        mWindow = PolicyManager.makeNewWindow(mContext);
+        mWindow.setWindowManager(mWindowManager, null, null);
+        mWindow.requestFeature(Window.FEATURE_NO_TITLE);
+        mDecor = mWindow.getDecorView();
+        mDecor.setOnTouchListener(mTouchListener);
+        mWindow.setContentView(this);
+        mWindow.setBackgroundDrawableResource(android.R.color.transparent);
+        
+        // While the media controller is up, the volume control keys should
+        // affect the media stream type
+        mWindow.setVolumeControlStream(AudioManager.STREAM_MUSIC);
+
+        setFocusable(true);
+        setFocusableInTouchMode(true);
+        setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
+        requestFocus();
+    }
+    */
+
+    /*
+    // Allocate and initialize the static parts of mDecorLayoutParams. Must
+    // also call updateFloatingWindowLayout() to fill in the dynamic parts
+    // (y and width) before mDecorLayoutParams can be used.
+    private void initFloatingWindowLayout() {
+        mDecorLayoutParams = new WindowManager.LayoutParams();
+        WindowManager.LayoutParams p = mDecorLayoutParams;
+        p.gravity = Gravity.TOP;
+        p.height = LayoutParams.WRAP_CONTENT;
+        p.x = 0;
+        p.format = PixelFormat.TRANSLUCENT;
+        p.type = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
+        p.flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
+                | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+                | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH;
+        p.token = null;
+        p.windowAnimations = 0; // android.R.style.DropDownAnimationDown;
+    }
+    */
+
+    // Update the dynamic parts of mDecorLayoutParams
+    // Must be called with mAnchor != NULL.
+    /*
+    private void updateFloatingWindowLayout() {
+        int [] anchorPos = new int[2];
+        mAnchor.getLocationOnScreen(anchorPos);
+
+        WindowManager.LayoutParams p = mDecorLayoutParams;
+        p.width = mAnchor.getWidth();
+        p.y = anchorPos[1] + mAnchor.getHeight();
+    }
+    */
+
+    /*
+    // This is called whenever mAnchor's layout bound changes
+    public void onLayoutChange(View v, int left, int top, int right,
+            int bottom, int oldLeft, int oldTop, int oldRight,
+            int oldBottom) {
+        //updateFloatingWindowLayout();
+        if (mShowing) {
+            mWindowManager.updateViewLayout(mDecor, mDecorLayoutParams);
+        }
+    }
+    */
+    
+    /*
+    public boolean onTouch(View v, MotionEvent event) {
+        if (event.getAction() == MotionEvent.ACTION_DOWN) {
+            if (mShowing) {
+                hide();
+            }
+        }
+            return false;
+    }
+    */
+    
+    
+    public void setMediaPlayer(MediaPlayerControl player) {
+        mPlayer = player;
+        mHandler.sendEmptyMessage(SHOW_PROGRESS);
+        updatePausePlay();
+    }
+
+    
+    private void initControllerView(View v) {
+        mPauseButton = (ImageButton) v.findViewById(R.id.playBtn);
+        if (mPauseButton != null) {
+            mPauseButton.requestFocus();
+            mPauseButton.setOnClickListener(this);
+        }
+
+        mFfwdButton = (ImageButton) v.findViewById(R.id.forwardBtn);
+        if (mFfwdButton != null) {
+            mFfwdButton.setOnClickListener(this);
+        }
+
+        mRewButton = (ImageButton) v.findViewById(R.id.rewindBtn);
+        if (mRewButton != null) {
+            mRewButton.setOnClickListener(this);
+        }
+
+        mProgress = (ProgressBar) v.findViewById(R.id.progressBar);
+        if (mProgress != null) {
+            if (mProgress instanceof SeekBar) {
+                SeekBar seeker = (SeekBar) mProgress;
+                seeker.setOnSeekBarChangeListener(this);
+            }
+            mProgress.setMax(1000);
+        }
+
+        mEndTime = (TextView) v.findViewById(R.id.totalTimeText);
+        mCurrentTime = (TextView) v.findViewById(R.id.currentTimeText);
+        mFormatBuilder = new StringBuilder();
+        mFormatter = new Formatter(mFormatBuilder, Locale.getDefault());
+
+    }
+
+    
+    /**
+     * Disable pause or seek buttons if the stream cannot be paused or seeked.
+     * This requires the control interface to be a MediaPlayerControlExt
+     */
+    private void disableUnsupportedButtons() {
+        try {
+            if (mPauseButton != null && !mPlayer.canPause()) {
+                mPauseButton.setEnabled(false);
+            }
+            if (mRewButton != null && !mPlayer.canSeekBackward()) {
+                mRewButton.setEnabled(false);
+            }
+            if (mFfwdButton != null && !mPlayer.canSeekForward()) {
+                mFfwdButton.setEnabled(false);
+            }
+        } catch (IncompatibleClassChangeError ex) {
+            // We were given an old version of the interface, that doesn't have
+            // the canPause/canSeekXYZ methods. This is OK, it just means we
+            // assume the media can be paused and seeked, and so we don't disable
+            // the buttons.
+        }
+    }
+    
+    
+    private Handler mHandler = new Handler() {
+        @Override
+        public void handleMessage(Message msg) {
+            int pos;
+            switch (msg.what) {
+                case SHOW_PROGRESS:
+                    pos = setProgress();
+                    if (!mDragging) {
+                        msg = obtainMessage(SHOW_PROGRESS);
+                        sendMessageDelayed(msg, 1000 - (pos % 1000));
+                    }
+                    break;
+            }
+        }
+    };
+
+    private String stringForTime(int timeMs) {
+        int totalSeconds = timeMs / 1000;
+
+        int seconds = totalSeconds % 60;
+        int minutes = (totalSeconds / 60) % 60;
+        int hours   = totalSeconds / 3600;
+
+        mFormatBuilder.setLength(0);
+        if (hours > 0) {
+            return mFormatter.format("%d:%02d:%02d", hours, minutes, seconds).toString();
+        } else {
+            return mFormatter.format("%02d:%02d", minutes, seconds).toString();
+        }
+    }
+
+    private int setProgress() {
+        if (mPlayer == null || mDragging) {
+            return 0;
+        }
+        int position = mPlayer.getCurrentPosition();
+        int duration = mPlayer.getDuration();
+        if (mProgress != null) {
+            if (duration > 0) {
+                // use long to avoid overflow
+                long pos = 1000L * position / duration;
+                mProgress.setProgress( (int) pos);
+            }
+            int percent = mPlayer.getBufferPercentage();
+            mProgress.setSecondaryProgress(percent * 10);
+        }
+
+        if (mEndTime != null)
+            mEndTime.setText(stringForTime(duration));
+        if (mCurrentTime != null)
+            mCurrentTime.setText(stringForTime(position));
+
+        return position;
+    }
+    
+
+    @Override
+    public boolean dispatchKeyEvent(KeyEvent event) {
+        int keyCode = event.getKeyCode();
+        final boolean uniqueDown = event.getRepeatCount() == 0
+                && event.getAction() == KeyEvent.ACTION_DOWN;
+        if (keyCode ==  KeyEvent.KEYCODE_HEADSETHOOK
+                || keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE
+                || keyCode == KeyEvent.KEYCODE_SPACE) {
+            if (uniqueDown) {
+                doPauseResume();
+                //show(sDefaultTimeout);
+                if (mPauseButton != null) {
+                    mPauseButton.requestFocus();
+                }
+            }
+            return true;
+        } else if (keyCode == KeyEvent.KEYCODE_MEDIA_PLAY) {
+            if (uniqueDown && !mPlayer.isPlaying()) {
+                mPlayer.start();
+                updatePausePlay();
+                //show(sDefaultTimeout);
+            }
+            return true;
+        } else if (keyCode == KeyEvent.KEYCODE_MEDIA_STOP
+                || keyCode == KeyEvent.KEYCODE_MEDIA_PAUSE) {
+            if (uniqueDown && mPlayer.isPlaying()) {
+                mPlayer.pause();
+                updatePausePlay();
+                //show(sDefaultTimeout);
+            }
+            return true;
+        }
+
+        //show(sDefaultTimeout);
+        return super.dispatchKeyEvent(event);
+    }
+
+    public void updatePausePlay() {
+        if (mRoot == null || mPauseButton == null)
+            return;
+
+        if (mPlayer.isPlaying()) {
+            mPauseButton.setImageResource(android.R.drawable.ic_media_pause);
+        } else {
+            mPauseButton.setImageResource(android.R.drawable.ic_media_play);
+        }
+    }
+
+    private void doPauseResume() {
+        if (mPlayer.isPlaying()) {
+            mPlayer.pause();
+        } else {
+            mPlayer.start();
+        }
+        updatePausePlay();
+    }
+
+    @Override
+    public void setEnabled(boolean enabled) {
+        if (mPauseButton != null) {
+            mPauseButton.setEnabled(enabled);
+        }
+        if (mFfwdButton != null) {
+            mFfwdButton.setEnabled(enabled);
+        }
+        if (mRewButton != null) {
+            mRewButton.setEnabled(enabled);
+        }
+        if (mProgress != null) {
+            mProgress.setEnabled(enabled);
+        }
+        disableUnsupportedButtons();
+        super.setEnabled(enabled);
+    }
+
+    @Override
+    public void onClick(View v) {
+        int pos;
+        boolean playing = mPlayer.isPlaying();
+        switch (v.getId()) {
+        
+        case R.id.playBtn: 
+            doPauseResume();
+            break;
+
+        case R.id.rewindBtn:
+            pos = mPlayer.getCurrentPosition();
+            pos -= 5000;
+            mPlayer.seekTo(pos);
+            if (!playing) mPlayer.pause();  // necessary in some 2.3.x devices 
+            setProgress();
+            break;
+
+        case R.id.forwardBtn:
+            pos = mPlayer.getCurrentPosition();
+            pos += 15000;
+            mPlayer.seekTo(pos);
+            if (!playing) mPlayer.pause(); // necessary in some 2.3.x devices
+            setProgress();
+            break;
+        
+        }
+    }
+    
+    
+    @Override
+    public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+        if (!fromUser) {
+            // We're not interested in programmatically generated changes to
+            // the progress bar's position.
+            return;
+        }
+
+        long duration = mPlayer.getDuration();
+        long newposition = (duration * progress) / 1000L;
+        mPlayer.seekTo( (int) newposition);
+        if (mCurrentTime != null)
+            mCurrentTime.setText(stringForTime( (int) newposition));
+    }
+    
+    /**
+     * Called in devices with touchpad when the user starts to adjust the 
+     * position of the seekbar's thumb.
+     * 
+     * Will be followed by several onProgressChanged notifications.
+     */
+    @Override
+    public void onStartTrackingTouch(SeekBar seekBar) {
+        mDragging = true;                           // monitors the duration of dragging 
+        mHandler.removeMessages(SHOW_PROGRESS);     // grants no more updates with media player progress while dragging 
+    }
+
+    
+    /**
+     * Called in devices with touchpad when the user finishes the
+     * adjusting of the seekbar.
+     */
+    @Override
+    public void onStopTrackingTouch(SeekBar seekBar) {
+        mDragging = false;
+        setProgress();
+        updatePausePlay();
+        mHandler.sendEmptyMessage(SHOW_PROGRESS);    // grants future updates with media player progress 
+    }
+
+    @Override
+    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
+        super.onInitializeAccessibilityEvent(event);
+        event.setClassName(MediaControlView.class.getName());
+    }
+
+    @Override
+    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
+        super.onInitializeAccessibilityNodeInfo(info);
+        info.setClassName(MediaControlView.class.getName());
+    }
+    
+}
diff --git a/src/com/owncloud/android/media/MediaService.java b/src/com/owncloud/android/media/MediaService.java
new file mode 100644 (file)
index 0000000..9fd0037
--- /dev/null
@@ -0,0 +1,706 @@
+/* ownCloud Android client application
+ *   Copyright 2013 ownCloud Inc.
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.media;
+
+import android.accounts.Account;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.media.AudioManager;
+import android.media.MediaPlayer;
+import android.media.MediaPlayer.OnCompletionListener;
+import android.media.MediaPlayer.OnErrorListener;
+import android.media.MediaPlayer.OnPreparedListener;
+import android.net.wifi.WifiManager;
+import android.net.wifi.WifiManager.WifiLock;
+import android.os.IBinder;
+import android.os.PowerManager;
+import android.util.Log;
+import android.widget.Toast;
+
+import java.io.IOException;
+
+import com.owncloud.android.R;
+import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.ui.activity.FileDetailActivity;
+import com.owncloud.android.ui.fragment.FileDetailFragment;
+
+/**
+ * Service that handles media playback, both audio and video. 
+ * 
+ * Waits for Intents which signal the service to perform specific operations: Play, Pause,
+ * Rewind, etc.
+ * 
+ * @author David A. Velasco
+ */
+public class MediaService extends Service implements OnCompletionListener, OnPreparedListener,
+                OnErrorListener, AudioManager.OnAudioFocusChangeListener {
+
+    private static final String TAG = MediaService.class.getSimpleName();
+
+    private static final String MY_PACKAGE = MediaService.class.getPackage() != null ? MediaService.class.getPackage().getName() : "com.owncloud.android.media";
+    
+    /// Intent actions that we are prepared to handle
+    public static final String ACTION_PLAY_FILE = MY_PACKAGE + ".action.PLAY_FILE";
+    public static final String ACTION_STOP_ALL = MY_PACKAGE + ".action.STOP_ALL";
+
+    /// Keys to add extras to the action
+    public static final String EXTRA_FILE = MY_PACKAGE + ".extra.FILE";
+    public static final String EXTRA_ACCOUNT = MY_PACKAGE + ".extra.ACCOUNT";
+    public static String EXTRA_START_POSITION = MY_PACKAGE + ".extra.START_POSITION";
+    public static final String EXTRA_PLAY_ON_LOAD = MY_PACKAGE + ".extra.PLAY_ON_LOAD";
+
+
+    /** Error code for specific messages - see regular error codes at {@link MediaPlayer} */
+    public static final int OC_MEDIA_ERROR = 0;
+
+    /** Time To keep the control panel visible when the user does not use it */
+    public static final int MEDIA_CONTROL_SHORT_LIFE = 4000;
+    
+    /** Time To keep the control panel visible when the user does not use it */
+    public static final int MEDIA_CONTROL_PERMANENT = 0;
+    
+    /** Volume to set when audio focus is lost and ducking is allowed */
+    private static final float DUCK_VOLUME = 0.1f;
+
+    /** Media player instance */
+    private MediaPlayer mPlayer = null;
+    
+    /** Reference to the system AudioManager */
+    private AudioManager mAudioManager = null;
+
+    
+    /** Values to indicate the state of the service */
+    enum State {
+        STOPPED,
+        PREPARING,      
+        PLAYING,        
+        PAUSED 
+    };
+    
+
+    /** Current state */
+    private State mState = State.STOPPED;
+    
+    /** Possible focus values */
+    enum AudioFocus {
+        NO_FOCUS,            
+        NO_FOCUS_CAN_DUCK,   
+        FOCUS           
+    }
+    
+    /** Current focus state */
+    private AudioFocus mAudioFocus = AudioFocus.NO_FOCUS;
+    
+
+    /** 'True' when the current song is streaming from the network */
+    private boolean mIsStreaming = false;
+
+    /** Wifi lock kept to prevents the device from shutting off the radio when streaming a file. */
+    private WifiLock mWifiLock;
+    
+    private static final String MEDIA_WIFI_LOCK_TAG = MY_PACKAGE + ".WIFI_LOCK";
+
+    /** Notification to keep in the notification bar while a song is playing */
+    private NotificationManager mNotificationManager;
+    private Notification mNotification = null;
+
+    /** File being played */
+    private OCFile mFile;
+    
+    /** Account holding the file being played */
+    private Account mAccount;
+
+    /** Flag signaling if the audio should be played immediately when the file is prepared */ 
+    protected boolean mPlayOnPrepared;
+
+    /** Position, in miliseconds, where the audio should be started */
+    private int mStartPosition;
+    
+    /** Interface to access the service through binding */
+    private IBinder mBinder;
+
+    /** Control panel shown to the user to control the playback, to register through binding */
+    private MediaControlView mMediaController;
+    
+
+    
+    /**
+     * Helper method to get an error message suitable to show to users for errors occurred in media playback,
+     * 
+     * @param context   A context to access string resources.
+     * @param what      See {@link MediaPlayer.OnErrorListener#onError(MediaPlayer, int, int)
+     * @param extra     See {@link MediaPlayer.OnErrorListener#onError(MediaPlayer, int, int)
+     * @return          Message suitable to users.
+     */
+    public static String getMessageForMediaError(Context context, int what, int extra) {
+        int messageId;
+        
+        if (what == OC_MEDIA_ERROR) {
+            messageId = extra;
+                
+        } else if (extra == MediaPlayer.MEDIA_ERROR_UNSUPPORTED) {
+            /*  Added in API level 17
+                Bitstream is conforming to the related coding standard or file spec, but the media framework does not support the feature.
+                Constant Value: -1010 (0xfffffc0e)
+             */
+            messageId = R.string.media_err_unsupported;
+
+        } else if (extra == MediaPlayer.MEDIA_ERROR_IO) {
+            /*  Added in API level 17
+                File or network related operation errors.
+                Constant Value: -1004 (0xfffffc14) 
+             */
+            messageId = R.string.media_err_io;
+            
+        } else if (extra == MediaPlayer.MEDIA_ERROR_MALFORMED) {
+            /*  Added in API level 17
+                Bitstream is not conforming to the related coding standard or file spec.
+                Constant Value: -1007 (0xfffffc11) 
+             */
+            messageId = R.string.media_err_malformed;
+            
+        } else if (extra == MediaPlayer.MEDIA_ERROR_TIMED_OUT) {
+            /*  Added in API level 17
+                Some operation takes too long to complete, usually more than 3-5 seconds.
+                Constant Value: -110 (0xffffff92)
+            */
+            messageId = R.string.media_err_timeout;
+
+        } else if (what == MediaPlayer.MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK) {
+            /*  Added in API level 3
+                The video is streamed and its container is not valid for progressive playback i.e the video's index (e.g moov atom) is not at the start of the file.
+                Constant Value: 200 (0x000000c8)
+            */
+            messageId = R.string.media_err_invalid_progressive_playback;
+                
+        } else {
+            /*  MediaPlayer.MEDIA_ERROR_UNKNOWN
+                Added in API level 1
+                Unspecified media player error.
+                Constant Value: 1 (0x00000001)
+            */
+            /*  MediaPlayer.MEDIA_ERROR_SERVER_DIED)
+                Added in API level 1
+                Media server died. In this case, the application must release the MediaPlayer object and instantiate a new one.
+                Constant Value: 100 (0x00000064) 
+             */
+            messageId = R.string.media_err_unknown;
+        }
+        return context.getString(messageId);
+    }
+
+
+    
+    /**
+     * Initialize a service instance
+     * 
+     * {@inheritDoc}
+     */
+    @Override
+    public void onCreate() {
+        Log.d(TAG, "Creating ownCloud media service");
+
+        mWifiLock = ((WifiManager) getSystemService(Context.WIFI_SERVICE)).
+                createWifiLock(WifiManager.WIFI_MODE_FULL, MEDIA_WIFI_LOCK_TAG);
+
+        mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
+        mAudioManager = (AudioManager) getSystemService(AUDIO_SERVICE);
+        mBinder = new MediaServiceBinder(this);
+    }
+
+    
+    /**
+     * Entry point for Intents requesting actions, sent here via startService.
+     * 
+     * {@inheritDoc}
+     */
+    @Override
+    public int onStartCommand(Intent intent, int flags, int startId) {
+        String action = intent.getAction();
+        if (action.equals(ACTION_PLAY_FILE)) { 
+            processPlayFileRequest(intent);
+            
+        } else if (action.equals(ACTION_STOP_ALL)) {
+            processStopRequest(true);
+        }
+
+        return START_NOT_STICKY; // don't want it to restart in case it's killed.
+    }
+
+
+    /**
+     * Processes a request to play a media file received as a parameter
+     * 
+     * TODO If a new request is received when a file is being prepared, it is ignored. Is this what we want? 
+     * 
+     * @param intent    Intent received in the request with the data to identify the file to play. 
+     */
+    private void processPlayFileRequest(Intent intent) {
+        if (mState != State.PREPARING) {
+            mFile = intent.getExtras().getParcelable(EXTRA_FILE);
+            mAccount = intent.getExtras().getParcelable(EXTRA_ACCOUNT);
+            mPlayOnPrepared = intent.getExtras().getBoolean(EXTRA_PLAY_ON_LOAD, false);
+            mStartPosition = intent.getExtras().getInt(EXTRA_START_POSITION, 0);
+            tryToGetAudioFocus();
+            playMedia();
+        }
+    }
+
+    
+    /**
+     * Processes a request to play a media file.
+     */
+    protected void processPlayRequest() {
+        // request audio focus
+        tryToGetAudioFocus();
+
+        // actually play the song
+        if (mState == State.STOPPED) {
+            // (re)start playback
+            playMedia();
+            
+        } else if (mState == State.PAUSED) {
+            // continue playback
+            mState = State.PLAYING;
+            setUpAsForeground(String.format(getString(R.string.media_state_playing), mFile.getFileName()));
+            configAndStartMediaPlayer();
+            
+        }
+    }
+
+    
+    /**
+     * Makes sure the media player exists and has been reset. This will create the media player
+     * if needed, or reset the existing media player if one already exists.
+     */
+    protected void createMediaPlayerIfNeeded() {
+        if (mPlayer == null) {
+            mPlayer = new MediaPlayer();
+
+            // make sure the CPU won't go to sleep while media is playing
+            mPlayer.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);
+
+            // the media player will notify the service when it's ready preparing, and when it's done playing
+            mPlayer.setOnPreparedListener(this);
+            mPlayer.setOnCompletionListener(this);
+            mPlayer.setOnErrorListener(this);
+            
+        } else {
+            mPlayer.reset();
+        }
+    }
+
+    /**
+     * Processes a request to pause the current playback 
+     */
+    protected void processPauseRequest() {
+        if (mState == State.PLAYING) {
+            mState = State.PAUSED;
+            mPlayer.pause();
+            releaseResources(false); // retain media player in pause
+            // TODO polite audio focus, instead of keep it owned; or not?
+        }
+    }
+    
+    
+    /**
+     * Processes a request to stop the playback.
+     * 
+     * @param   force       When 'true', the playback is stopped no matter the value of mState
+     */
+    protected void processStopRequest(boolean force) {
+        if (mState != State.PREPARING || force) {
+            mState = State.STOPPED;
+            mFile = null;
+            mAccount = null;
+            releaseResources(true);
+            giveUpAudioFocus();
+            stopSelf();     // service is no longer necessary
+        }
+    }
+    
+
+    /**
+     * Releases resources used by the service for playback. This includes the "foreground service"
+     * status and notification, the wake locks and possibly the MediaPlayer.
+     *
+     * @param releaseMediaPlayer    Indicates whether the Media Player should also be released or not
+     */
+    protected void releaseResources(boolean releaseMediaPlayer) {
+        // stop being a foreground service
+        stopForeground(true);
+
+        // stop and release the Media Player, if it's available
+        if (releaseMediaPlayer && mPlayer != null) {
+            mPlayer.reset();
+            mPlayer.release();
+            mPlayer = null;
+        }
+
+        // release the Wifi lock, if holding it
+        if (mWifiLock.isHeld()) {
+            mWifiLock.release();
+        }
+    }
+
+    
+    /**
+     * Fully releases the audio focus.
+     */
+    private void giveUpAudioFocus() {
+        if (mAudioFocus == AudioFocus.FOCUS 
+                && mAudioManager != null  
+                && AudioManager.AUDIOFOCUS_REQUEST_GRANTED == mAudioManager.abandonAudioFocus(this))  {
+            
+            mAudioFocus = AudioFocus.NO_FOCUS;
+        }
+    }
+
+    
+    /**
+     * Reconfigures MediaPlayer according to audio focus settings and starts/restarts it. 
+     */
+    protected void configAndStartMediaPlayer() {
+        if (mPlayer == null) {
+            throw new IllegalStateException("mPlayer is NULL");
+        }
+        
+        if (mAudioFocus == AudioFocus.NO_FOCUS) {
+            if (mPlayer.isPlaying()) {
+                mPlayer.pause();        // have to be polite; but mState is not changed, to resume when focus is received again
+            }
+            
+        }  else { 
+            if (mAudioFocus == AudioFocus.NO_FOCUS_CAN_DUCK) {
+                mPlayer.setVolume(DUCK_VOLUME, DUCK_VOLUME);
+                
+            } else {
+                mPlayer.setVolume(1.0f, 1.0f); // full volume
+            }
+    
+            if (!mPlayer.isPlaying()) {
+                mPlayer.start();
+            }
+        }
+    }
+
+    
+    /**
+     * Requests the audio focus to the Audio Manager 
+     */
+    private void tryToGetAudioFocus() {
+        if (mAudioFocus != AudioFocus.FOCUS 
+                && mAudioManager != null 
+                && (AudioManager.AUDIOFOCUS_REQUEST_GRANTED == mAudioManager.requestAudioFocus( this,
+                                                                                                AudioManager.STREAM_MUSIC, 
+                                                                                                AudioManager.AUDIOFOCUS_GAIN))
+                ) {
+            mAudioFocus = AudioFocus.FOCUS;
+        }
+    }
+
+    
+    /**
+     * Starts playing the current media file. 
+     */
+    protected void playMedia() {
+        mState = State.STOPPED;
+        releaseResources(false); // release everything except MediaPlayer
+
+        try {
+            if (mFile == null) { 
+                Toast.makeText(this, R.string.media_err_nothing_to_play, Toast.LENGTH_LONG).show();
+                processStopRequest(true);
+                return;
+                
+            } else if (mAccount == null) {
+                Toast.makeText(this, R.string.media_err_not_in_owncloud, Toast.LENGTH_LONG).show();
+                processStopRequest(true);
+                return;
+            }
+
+            createMediaPlayerIfNeeded();
+            mPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
+            String url = mFile.getStoragePath();
+            /* Streaming is not possible right now
+            if (url == null || url.length() <= 0) {
+                url = AccountUtils.constructFullURLForAccount(this, mAccount) + mFile.getRemotePath();
+            }
+            mIsStreaming = url.startsWith("http:") || url.startsWith("https:");
+            */
+            mIsStreaming = false;
+            
+            mPlayer.setDataSource(url);
+
+            mState = State.PREPARING;
+            setUpAsForeground(String.format(getString(R.string.media_state_loading), mFile.getFileName()));
+
+            // starts preparing the media player in background
+            mPlayer.prepareAsync();
+
+            // prevent the Wifi from going to sleep when streaming
+            if (mIsStreaming) { 
+                mWifiLock.acquire();
+            } else if (mWifiLock.isHeld()) {
+                mWifiLock.release();
+            }
+            
+        } catch (SecurityException e) {
+            Log.e(TAG, "SecurityException playing " + mAccount.name + mFile.getRemotePath(), e);
+            Toast.makeText(this, String.format(getString(R.string.media_err_security_ex), mFile.getFileName()), Toast.LENGTH_LONG).show();
+            processStopRequest(true);
+            
+        } catch (IOException e) {
+            Log.e(TAG, "IOException playing " + mAccount.name + mFile.getRemotePath(), e);
+            Toast.makeText(this, String.format(getString(R.string.media_err_io_ex), mFile.getFileName()), Toast.LENGTH_LONG).show();
+            processStopRequest(true);
+            
+        } catch (IllegalStateException e) {
+            Log.e(TAG, "IllegalStateException " + mAccount.name + mFile.getRemotePath(), e);
+            Toast.makeText(this, String.format(getString(R.string.media_err_unexpected), mFile.getFileName()), Toast.LENGTH_LONG).show();
+            processStopRequest(true);
+            
+        } catch (IllegalArgumentException e) {
+            Log.e(TAG, "IllegalArgumentException " + mAccount.name + mFile.getRemotePath(), e);
+            Toast.makeText(this, String.format(getString(R.string.media_err_unexpected), mFile.getFileName()), Toast.LENGTH_LONG).show();
+            processStopRequest(true);
+        }
+    }
+
+    
+    /** Called when media player is done playing current song. */
+    public void onCompletion(MediaPlayer player) {
+        Toast.makeText(this, String.format(getString(R.string.media_event_done, mFile.getFileName())), Toast.LENGTH_LONG).show();
+        if (mMediaController != null) {
+            // somebody is still bound to the service
+            player.seekTo(0);
+            processPauseRequest();
+            mMediaController.updatePausePlay();
+        } else {
+            // nobody is bound
+            processStopRequest(true);
+        }
+        return;
+    }
+    
+
+    /** 
+     * Called when media player is done preparing. 
+     *
+     * Time to start.
+     */
+    public void onPrepared(MediaPlayer player) {
+        mState = State.PLAYING;
+        updateNotification(String.format(getString(R.string.media_state_playing), mFile.getFileName()));
+        if (mMediaController != null) {
+            mMediaController.setEnabled(true);
+        }
+        player.seekTo(mStartPosition);
+        configAndStartMediaPlayer();
+        if (!mPlayOnPrepared) {
+            processPauseRequest();
+        }
+        
+        if (mMediaController != null) {
+            mMediaController.updatePausePlay();
+        }
+    }
+    
+
+    /** 
+     * Updates the status notification
+     */
+    @SuppressWarnings("deprecation")
+    private void updateNotification(String content) {
+        // TODO check if updating the Intent is really necessary
+        Intent showDetailsIntent = new Intent(this, FileDetailActivity.class);
+        showDetailsIntent.putExtra(FileDetailFragment.EXTRA_FILE, mFile);
+        showDetailsIntent.putExtra(FileDetailFragment.EXTRA_ACCOUNT, mAccount);
+        showDetailsIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+        mNotification.contentIntent = PendingIntent.getActivity(getApplicationContext(), 
+                                                                (int)System.currentTimeMillis(), 
+                                                                showDetailsIntent, 
+                                                                PendingIntent.FLAG_UPDATE_CURRENT);
+        mNotification.when = System.currentTimeMillis();
+        //mNotification.contentView.setTextViewText(R.id.status_text, content);
+        String ticker = String.format(getString(R.string.media_notif_ticker), getString(R.string.app_name));
+        mNotification.setLatestEventInfo(getApplicationContext(), ticker, content, mNotification.contentIntent);
+        mNotificationManager.notify(R.string.media_notif_ticker, mNotification);
+    }
+
+    
+    /**
+     * Configures the service as a foreground service.
+     * 
+     * The system will avoid finishing the service as much as possible when resources as low.
+     * 
+     * A notification must be created to keep the user aware of the existance of the service.
+     */
+    @SuppressWarnings("deprecation")
+    private void setUpAsForeground(String content) {
+        /// creates status notification
+        // TODO put a progress bar to follow the playback progress
+        mNotification = new Notification();
+        mNotification.icon = android.R.drawable.ic_media_play;
+        //mNotification.tickerText = text;
+        mNotification.when = System.currentTimeMillis();
+        mNotification.flags |= Notification.FLAG_ONGOING_EVENT;
+        //mNotification.contentView.setTextViewText(R.id.status_text, "ownCloud Music Player");     // NULL POINTER
+        //mNotification.contentView.setTextViewText(R.id.status_text, getString(R.string.downloader_download_in_progress_content));
+
+        
+        /// includes a pending intent in the notification showing the details view of the file
+        Intent showDetailsIntent = new Intent(this, FileDetailActivity.class);
+        showDetailsIntent.putExtra(FileDetailFragment.EXTRA_FILE, mFile);
+        showDetailsIntent.putExtra(FileDetailFragment.EXTRA_ACCOUNT, mAccount);
+        showDetailsIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+        mNotification.contentIntent = PendingIntent.getActivity(getApplicationContext(), 
+                                                                (int)System.currentTimeMillis(), 
+                                                                showDetailsIntent, 
+                                                                PendingIntent.FLAG_UPDATE_CURRENT);
+        
+        
+        //mNotificationManager.notify(R.string.downloader_download_in_progress_ticker, mNotification);
+        String ticker = String.format(getString(R.string.media_notif_ticker), getString(R.string.app_name));
+        mNotification.setLatestEventInfo(getApplicationContext(), ticker, content, mNotification.contentIntent);
+        startForeground(R.string.media_notif_ticker, mNotification);
+        
+    }
+
+    /**
+     * Called when there's an error playing media. 
+     * 
+     * Warns the user about the error and resets the media player.
+     */
+    public boolean onError(MediaPlayer mp, int what, int extra) {
+        Log.e(TAG, "Error in audio playback, what = " + what + ", extra = " + extra);
+        
+        String message = getMessageForMediaError(this, what, extra);
+        Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show();
+        
+        processStopRequest(true);
+        return true; 
+    }
+
+    /**
+     * Called by the system when another app tries to play some sound.
+     * 
+     * {@inheritDoc}
+     */
+    @Override
+    public void onAudioFocusChange(int focusChange) {
+        if (focusChange > 0) {
+            // focus gain; check AudioManager.AUDIOFOCUS_* values
+            mAudioFocus = AudioFocus.FOCUS;
+            // restart media player with new focus settings
+            if (mState == State.PLAYING)
+                configAndStartMediaPlayer();
+            
+        } else if (focusChange < 0) {
+            // focus loss; check AudioManager.AUDIOFOCUS_* values
+            boolean canDuck = AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK == focusChange;
+                mAudioFocus = canDuck ? AudioFocus.NO_FOCUS_CAN_DUCK : AudioFocus.NO_FOCUS;
+                // start/restart/pause media player with new focus settings
+                if (mPlayer != null && mPlayer.isPlaying())
+                    configAndStartMediaPlayer();
+        }
+        
+    }
+
+    /**
+     * Called when the service is finished for final clean-up.
+     * 
+     * {@inheritDoc}
+     */
+    @Override
+    public void onDestroy() {
+        mState = State.STOPPED;
+        releaseResources(true);
+        giveUpAudioFocus();
+    }
+    
+
+    /**
+     * Provides a binder object that clients can use to perform operations on the MediaPlayer managed by the MediaService. 
+     */
+    @Override
+    public IBinder onBind(Intent arg) {
+        return mBinder;
+    }
+    
+    
+    /**
+     * Called when ALL the bound clients were onbound.
+     * 
+     * The service is destroyed if playback stopped or paused
+     */
+    @Override
+    public boolean onUnbind(Intent intent) {
+        if (mState == State.PAUSED || mState == State.STOPPED)  {
+            processStopRequest(false);
+        }
+        return false;   // not accepting rebinding (default behaviour)
+    }
+
+
+    /**
+     * Accesses the current MediaPlayer instance in the service.
+     * 
+     * To be handled carefully. Visibility is protected to be accessed only 
+     * 
+     * @return Current MediaPlayer instance handled by MediaService.
+     */
+    protected MediaPlayer getPlayer() {
+        return mPlayer;
+    }
+
+
+    /**
+     * Accesses the current OCFile loaded in the service.
+     * 
+     * @return  The current OCFile loaded in the service.
+     */
+    protected OCFile getCurrentFile() {
+        return mFile;
+    }
+
+    
+    /**
+     * Accesses the current {@link State} of the MediaService.
+     * 
+     * @return  The current {@link State} of the MediaService.
+     */
+    protected State getState() {
+        return mState;
+    }
+
+
+    protected void setMediaContoller(MediaControlView mediaController) {
+        mMediaController = mediaController;
+    }
+
+    protected MediaControlView getMediaController() {
+        return mMediaController;
+    }
+
+}
diff --git a/src/com/owncloud/android/media/MediaServiceBinder.java b/src/com/owncloud/android/media/MediaServiceBinder.java
new file mode 100644 (file)
index 0000000..7b401ed
--- /dev/null
@@ -0,0 +1,182 @@
+/* ownCloud Android client application
+ *   Copyright (C) 2013 ownCloud Inc.
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.media;
+
+
+import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.media.MediaService.State;
+
+import android.accounts.Account;
+import android.content.Intent;
+import android.media.MediaPlayer;
+import android.os.Binder;
+import android.util.Log;
+import android.widget.MediaController;
+
+
+/**
+ *  Binder allowing client components to perform operations on on the MediaPlayer managed by a MediaService instance.
+ * 
+ *  Provides the operations of {@link MediaController.MediaPlayerControl}, and an extra method to check if
+ *  an {@link OCFile} instance is handled by the MediaService.
+ *  
+ *  @author David A. Velasco
+ */
+public class MediaServiceBinder extends Binder implements MediaController.MediaPlayerControl {
+
+    private static final String TAG = MediaServiceBinder.class.getSimpleName();
+    /**
+     * {@link MediaService} instance to access with the binder
+     */
+    private MediaService mService = null;
+    
+    /**
+     * Public constructor
+     * 
+     * @param service       A {@link MediaService} instance to access with the binder 
+     */
+    public MediaServiceBinder(MediaService service) {
+        if (service == null) {
+            throw new IllegalArgumentException("Argument 'service' can not be null");
+        }
+        mService = service;
+    }
+    
+    
+    public boolean isPlaying(OCFile mFile) {
+        return (mFile != null && mFile.equals(mService.getCurrentFile())); 
+    }
+
+    
+    @Override
+    public boolean canPause() {
+        return true;
+    }
+
+    @Override
+    public boolean canSeekBackward() {
+        return true;
+    }
+
+    @Override
+    public boolean canSeekForward() {
+        return true;
+    }
+
+    @Override
+    public int getBufferPercentage() {
+        MediaPlayer currentPlayer = mService.getPlayer();
+        if (currentPlayer != null) {
+            return 100;
+            // TODO update for streamed playback; add OnBufferUpdateListener in MediaService
+        } else {
+            return 0;
+        }
+    }
+
+    @Override
+    public int getCurrentPosition() {
+        MediaPlayer currentPlayer = mService.getPlayer();
+        if (currentPlayer != null) {
+            int pos = currentPlayer.getCurrentPosition();
+            return pos;
+        } else {
+            return 0;
+        }
+    }
+
+    @Override
+    public int getDuration() {
+        MediaPlayer currentPlayer = mService.getPlayer();
+        if (currentPlayer != null) {
+            int dur = currentPlayer.getDuration();
+            return dur;
+        } else {
+            return 0;
+        }
+    }
+
+    
+    /**
+     * Reports if the MediaService is playing a file or not.
+     * 
+     * Considers that the file is being played when it is in preparation because the expected
+     * client of this method is a {@link MediaController} , and we do not want that the 'play'
+     * button is shown when the file is being prepared by the MediaService.
+     */
+    @Override
+    public boolean isPlaying() {
+        MediaService.State currentState = mService.getState();
+        return (currentState == State.PLAYING || (currentState == State.PREPARING && mService.mPlayOnPrepared));
+    }
+
+    
+    @Override
+    public void pause() {
+        Log.d(TAG, "Pausing through binder...");
+        mService.processPauseRequest();
+    }
+
+    @Override
+    public void seekTo(int pos) {
+        Log.d(TAG, "Seeking " + pos + " through binder...");
+        MediaPlayer currentPlayer = mService.getPlayer();
+        MediaService.State currentState = mService.getState();
+        if (currentPlayer != null && currentState != State.PREPARING && currentState != State.STOPPED) {
+            currentPlayer.seekTo(pos);
+        }
+    }
+
+    @Override
+    public void start() {
+        Log.d(TAG, "Starting through binder...");
+        mService.processPlayRequest();  // this will finish the service if there is no file preloaded to play
+    }
+    
+    public void start(Account account, OCFile file, boolean playImmediately, int position) {
+        Log.d(TAG, "Loading and starting through binder...");
+        Intent i = new Intent(mService, MediaService.class);
+        i.putExtra(MediaService.EXTRA_ACCOUNT, account);
+        i.putExtra(MediaService.EXTRA_FILE, file);
+        i.putExtra(MediaService.EXTRA_PLAY_ON_LOAD, playImmediately);
+        i.putExtra(MediaService.EXTRA_START_POSITION, position);
+        i.setAction(MediaService.ACTION_PLAY_FILE);
+        mService.startService(i);
+    }
+
+
+    public void registerMediaController(MediaControlView mediaController) {
+        mService.setMediaContoller(mediaController);
+    }
+    
+    public void unregisterMediaController(MediaControlView mediaController) {
+        if (mediaController != null && mediaController == mService.getMediaController()) {
+            mService.setMediaContoller(null);
+        }
+        
+    }
+
+    public boolean isInPlaybackState() {
+        MediaService.State currentState = mService.getState();
+        return (currentState == MediaService.State.PLAYING || currentState == MediaService.State.PAUSED);
+    }
+
+}
+
+
diff --git a/src/com/owncloud/android/network/ProgressiveDataTransferer.java b/src/com/owncloud/android/network/ProgressiveDataTransferer.java
new file mode 100644 (file)
index 0000000..81a5f4c
--- /dev/null
@@ -0,0 +1,33 @@
+/* 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 as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package 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);
+
+}
index c01ee46..d421803 100644 (file)
@@ -29,6 +29,7 @@ import org.apache.commons.httpclient.HttpException;
 import org.apache.commons.httpclient.methods.PutMethod;
 
 import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.network.ProgressiveDataTransferer;
 
 import android.accounts.Account;
 import android.util.Log;
@@ -62,16 +63,16 @@ public class ChunkedUploadFileOperation extends UploadFileOperation {
             File file = new File(getStoragePath());
             raf = new RandomAccessFile(file, "r");
             channel = raf.getChannel();
-            ChunkFromFileChannelRequestEntity entity = new ChunkFromFileChannelRequestEntity(channel, getMimeType(), CHUNK_SIZE, file);
-            entity.addOnDatatransferProgressListeners(getDataTransferListeners());
+            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) {
                 mPutMethod = new PutMethod(uriPrefix + chunkCount + "-" + chunkIndex);
                 mPutMethod.addRequestHeader(OC_CHUNKED_HEADER, OC_CHUNKED_HEADER);
-                entity.setOffset(offset);
-                mPutMethod.setRequestEntity(entity);
+                ((ChunkFromFileChannelRequestEntity)mEntity).setOffset(offset);
+                mPutMethod.setRequestEntity(mEntity);
                 status = client.executeMethod(mPutMethod);
                 client.exhaustResponse(mPutMethod.getResponseBodyAsStream());
                 Log.d(TAG, "Upload of " + getStoragePath() + " to " + getRemotePath() + ", chunk index " + chunkIndex + ", count " + chunkCount + ", HTTP result status " + status);
index 75bf923..da6b270 100644 (file)
@@ -123,9 +123,17 @@ public class DownloadFileOperation extends RemoteOperation {
     
     
     public void addDatatransferProgressListener (OnDatatransferProgressListener listener) {
-        mDataTransferListeners.add(listener);
+        synchronized (mDataTransferListeners) {
+            mDataTransferListeners.add(listener);
+        }
     }
     
+    public void removeDatatransferProgressListener(OnDatatransferProgressListener listener) {
+        synchronized (mDataTransferListeners) {
+            mDataTransferListeners.remove(listener);
+        }
+    }
+
     @Override
     protected RemoteOperationResult run(WebdavClient client) {
         RemoteOperationResult result = null;
@@ -190,9 +198,11 @@ public class DownloadFileOperation extends RemoteOperation {
                     }
                     fos.write(bytes, 0, readResult);
                     transferred += readResult;
-                    it = mDataTransferListeners.iterator();
-                    while (it.hasNext()) {
-                        it.next().onTransferProgress(readResult, transferred, mFile.getFileLength(), targetFile.getName());
+                    synchronized (mDataTransferListeners) {
+                        it = mDataTransferListeners.iterator();
+                        while (it.hasNext()) {
+                            it.next().onTransferProgress(readResult, transferred, mFile.getFileLength(), targetFile.getName());
+                        }
                     }
                 }
                 savedFile = true;
@@ -221,4 +231,5 @@ public class DownloadFileOperation extends RemoteOperation {
         mCancellationRequested.set(true);   // atomic set; there is no need of synchronizing it
     }
 
+
 }
index 606017a..4ed56d7 100644 (file)
@@ -162,7 +162,7 @@ public class SynchronizeFileOperation extends RemoteOperation {
           
         } catch (Exception e) {
             result = new RemoteOperationResult(e);
-            Log.e(TAG, "Synchronizing " + mAccount.name + ", file " + mLocalFile.getRemotePath() + ": " + result.getLogMessage(), result.getException());
+            Log.e(TAG, "Synchronizing " + mAccount.name + ", file " + (mLocalFile != null ? mLocalFile.getRemotePath() : "NULL") + ": " + result.getLogMessage(), result.getException());
 
         } finally {
             if (propfind != null)
index 5bf9cc0..0dfb72c 100644 (file)
@@ -30,6 +30,7 @@ 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 android.accounts.Account;
@@ -37,6 +38,9 @@ import android.util.Log;
 
 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.utils.FileStorageUtils;
 
@@ -69,8 +73,14 @@ public class UploadFileOperation extends RemoteOperation {
     private Set<OnDatatransferProgressListener> mDataTransferListeners = new HashSet<OnDatatransferProgressListener>();
     private final AtomicBoolean mCancellationRequested = new AtomicBoolean(false);
 
-    public UploadFileOperation(Account account, OCFile file, boolean isInstant, boolean forceOverwrite,
-            int localBehaviour) {
+    protected RequestEntity mEntity = null;
+
+    
+    public UploadFileOperation( Account account,
+                                OCFile file,
+                                boolean isInstant, 
+                                boolean forceOverwrite,
+                                int localBehaviour) {
         if (account == null)
             throw new IllegalArgumentException("Illegal NULL account in UploadFileOperation creation");
         if (file == null)
@@ -147,9 +157,23 @@ public class UploadFileOperation extends RemoteOperation {
     public Set<OnDatatransferProgressListener> getDataTransferListeners() {
         return mDataTransferListeners;
     }
-
-    public void addDatatransferProgressListener(OnDatatransferProgressListener listener) {
-        mDataTransferListeners.add(listener);
+    
+    public void addDatatransferProgressListener (OnDatatransferProgressListener listener) {
+        synchronized (mDataTransferListeners) {
+            mDataTransferListeners.add(listener);
+        }
+        if (mEntity != null) {
+            ((ProgressiveDataTransferer)mEntity).addDatatransferProgressListener(listener);
+        }
+    }
+    
+    public void removeDatatransferProgressListener(OnDatatransferProgressListener listener) {
+        synchronized (mDataTransferListeners) {
+            mDataTransferListeners.remove(listener);
+        }
+        if (mEntity != null) {
+            ((ProgressiveDataTransferer)mEntity).removeDatatransferProgressListener(listener);
+        }
     }
 
     @Override
@@ -348,9 +372,11 @@ public class UploadFileOperation extends RemoteOperation {
         int status = -1;
         try {
             File f = new File(mFile.getStoragePath());
-            FileRequestEntity entity = new FileRequestEntity(f, getMimeType());
-            entity.addOnDatatransferProgressListeners(mDataTransferListeners);
-            mPutMethod.setRequestEntity(entity);
+            mEntity  = new FileRequestEntity(f, getMimeType());
+            synchronized (mDataTransferListeners) {
+                ((ProgressiveDataTransferer)mEntity).addDatatransferProgressListeners(mDataTransferListeners);
+            }
+            mPutMethod.setRequestEntity(mEntity);
             status = client.executeMethod(mPutMethod);
             client.exhaustResponse(mPutMethod.getResponseBodyAsStream());
 
index cd68c89..1933735 100644 (file)
@@ -21,26 +21,33 @@ package com.owncloud.android.ui.activity;
 import android.accounts.Account;\r
 import android.app.Dialog;\r
 import android.app.ProgressDialog;\r
+import android.content.BroadcastReceiver;\r
 import android.content.ComponentName;\r
 import android.content.Context;\r
 import android.content.Intent;\r
+import android.content.IntentFilter;\r
 import android.content.ServiceConnection;\r
 import android.content.res.Configuration;\r
 import android.os.Bundle;\r
 import android.os.IBinder;\r
+import android.support.v4.app.Fragment;\r
 import android.support.v4.app.FragmentTransaction;\r
 import android.util.Log;\r
 \r
 import com.actionbarsherlock.app.ActionBar;\r
 import com.actionbarsherlock.app.SherlockFragmentActivity;\r
 import com.actionbarsherlock.view.MenuItem;\r
+import com.owncloud.android.datamodel.FileDataStorageManager;\r
 import com.owncloud.android.datamodel.OCFile;\r
 import com.owncloud.android.files.services.FileDownloader;\r
 import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder;\r
 import com.owncloud.android.files.services.FileUploader;\r
 import com.owncloud.android.files.services.FileUploader.FileUploaderBinder;\r
 import com.owncloud.android.ui.fragment.FileDetailFragment;\r
+import com.owncloud.android.ui.fragment.FileFragment;\r
+import com.owncloud.android.ui.preview.PreviewMediaFragment;\r
 \r
+import com.owncloud.android.AccountUtils;\r
 import com.owncloud.android.R;\r
 \r
 /**\r
@@ -48,24 +55,41 @@ import com.owncloud.android.R;
  * on.\r
  * \r
  * @author Bartek Przybylski\r
- * \r
+ * @author David A. Velasco\r
  */\r
-public class FileDetailActivity extends SherlockFragmentActivity implements FileDetailFragment.ContainerActivity {\r
+public class FileDetailActivity extends SherlockFragmentActivity implements FileFragment.ContainerActivity {\r
     \r
     public static final int DIALOG_SHORT_WAIT = 0;\r
 \r
     public static final String TAG = FileDetailActivity.class.getSimpleName();\r
     \r
+    public static final String EXTRA_MODE = "MODE";\r
+    public static final int MODE_DETAILS = 0;\r
+    public static final int MODE_PREVIEW = 1;\r
+\r
+    public static final String KEY_WAITING_TO_PREVIEW = "WAITING_TO_PREVIEW";\r
+    \r
     private boolean mConfigurationChangedToLandscape = false;\r
     private FileDownloaderBinder mDownloaderBinder = null;\r
     private ServiceConnection mDownloadConnection, mUploadConnection = null;\r
     private FileUploaderBinder mUploaderBinder = null;\r
+    private boolean mWaitingToPreview;\r
+    \r
+    private OCFile mFile;\r
+    private Account mAccount;\r
 \r
+    private FileDataStorageManager mStorageManager;\r
+    private DownloadFinishReceiver mDownloadFinishReceiver;\r
+    \r
 \r
     @Override\r
     protected void onCreate(Bundle savedInstanceState) {\r
         super.onCreate(savedInstanceState);\r
 \r
+        mFile = getIntent().getParcelableExtra(FileDetailFragment.EXTRA_FILE);\r
+        mAccount = getIntent().getParcelableExtra(FileDetailFragment.EXTRA_ACCOUNT);\r
+        mStorageManager = new FileDataStorageManager(mAccount, getContentResolver());\r
+        \r
         // check if configuration changed to large-land ; for a tablet being changed from portrait to landscape when in FileDetailActivity \r
         Configuration conf = getResources().getConfiguration();\r
         mConfigurationChangedToLandscape = (conf.orientation == Configuration.ORIENTATION_LANDSCAPE && \r
@@ -73,30 +97,90 @@ public class FileDetailActivity extends SherlockFragmentActivity implements File
                                            );\r
 \r
         if (!mConfigurationChangedToLandscape) {\r
-            mDownloadConnection = new DetailsServiceConnection();\r
-            bindService(new Intent(this, FileDownloader.class), mDownloadConnection, Context.BIND_AUTO_CREATE);\r
-            mUploadConnection = new DetailsServiceConnection();\r
-            bindService(new Intent(this, FileUploader.class), mUploadConnection, Context.BIND_AUTO_CREATE);\r
-            \r
             setContentView(R.layout.file_activity_details);\r
         \r
             ActionBar actionBar = getSupportActionBar();\r
             actionBar.setDisplayHomeAsUpEnabled(true);\r
 \r
-            OCFile file = getIntent().getParcelableExtra(FileDetailFragment.EXTRA_FILE);\r
-            Account account = getIntent().getParcelableExtra(FileDetailFragment.EXTRA_ACCOUNT);\r
-            FileDetailFragment mFileDetail = new FileDetailFragment(file, account);\r
-        \r
-            FragmentTransaction ft = getSupportFragmentManager().beginTransaction();\r
-            ft.replace(R.id.fragment, mFileDetail, FileDetailFragment.FTAG);\r
-            ft.commit();\r
+            if (savedInstanceState == null) {\r
+                mWaitingToPreview = false;\r
+                createChildFragment();\r
+            } else {\r
+                mWaitingToPreview = savedInstanceState.getBoolean(KEY_WAITING_TO_PREVIEW);\r
+            }\r
+            \r
+            mDownloadConnection = new DetailsServiceConnection();\r
+            bindService(new Intent(this, FileDownloader.class), mDownloadConnection, Context.BIND_AUTO_CREATE);\r
+            mUploadConnection = new DetailsServiceConnection();\r
+            bindService(new Intent(this, FileUploader.class), mUploadConnection, Context.BIND_AUTO_CREATE);\r
+            \r
             \r
         }  else {\r
-            backToDisplayActivity();   // the 'back' won't be effective until this.onStart() and this.onResume() are completed;\r
+            backToDisplayActivity(false);   // the 'back' won't be effective until this.onStart() and this.onResume() are completed;\r
         }\r
         \r
         \r
     }\r
+\r
+    /**\r
+     * Creates the proper fragment depending upon the state of the handled {@link OCFile} and\r
+     * the requested {@link Intent}.\r
+     */\r
+    private void createChildFragment() {\r
+        int mode = getIntent().getIntExtra(EXTRA_MODE, MODE_PREVIEW); \r
+        \r
+        Fragment newFragment = null;\r
+        if (PreviewMediaFragment.canBePreviewed(mFile) && mode == MODE_PREVIEW) {\r
+            if (mFile.isDown()) {\r
+                newFragment = new PreviewMediaFragment(mFile, mAccount);\r
+            \r
+            } else {\r
+                newFragment = new FileDetailFragment(mFile, mAccount);\r
+                mWaitingToPreview = true;\r
+            }\r
+            \r
+        } else {\r
+            newFragment = new FileDetailFragment(mFile, mAccount);\r
+        }\r
+        FragmentTransaction ft = getSupportFragmentManager().beginTransaction();\r
+        ft.replace(R.id.fragment, newFragment, FileDetailFragment.FTAG);\r
+        ft.commit();\r
+    }\r
+    \r
+\r
+    @Override\r
+    protected void onSaveInstanceState(Bundle outState) {\r
+        super.onSaveInstanceState(outState);\r
+        outState.putBoolean(KEY_WAITING_TO_PREVIEW, mWaitingToPreview);\r
+    }\r
+    \r
+    \r
+    @Override\r
+    public void onPause() {\r
+        super.onPause();\r
+        if (mDownloadFinishReceiver != null) {\r
+            unregisterReceiver(mDownloadFinishReceiver);\r
+            mDownloadFinishReceiver = null;\r
+        }\r
+    }\r
+    \r
+    \r
+    @Override\r
+    public void onResume() {\r
+        super.onResume();\r
+        if (!mConfigurationChangedToLandscape) {\r
+            // TODO this is probably unnecessary\r
+            Fragment fragment = getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);\r
+            if (fragment != null && fragment instanceof FileDetailFragment) {\r
+                ((FileDetailFragment) fragment).updateFileDetails(false, false);\r
+            }\r
+        }\r
+        // Listen for download messages\r
+        IntentFilter downloadIntentFilter = new IntentFilter(FileDownloader.DOWNLOAD_ADDED_MESSAGE);\r
+        downloadIntentFilter.addAction(FileDownloader.DOWNLOAD_FINISH_MESSAGE);\r
+        mDownloadFinishReceiver = new DownloadFinishReceiver();\r
+        registerReceiver(mDownloadFinishReceiver, downloadIntentFilter);\r
+    }\r
     \r
     \r
     /** Defines callbacks for service binding, passed to bindService() */\r
@@ -104,18 +188,27 @@ public class FileDetailActivity extends SherlockFragmentActivity implements File
 \r
         @Override\r
         public void onServiceConnected(ComponentName component, IBinder service) {\r
+                \r
             if (component.equals(new ComponentName(FileDetailActivity.this, FileDownloader.class))) {\r
                 Log.d(TAG, "Download service connected");\r
                 mDownloaderBinder = (FileDownloaderBinder) service;\r
+                if (mWaitingToPreview) {\r
+                    requestForDownload();\r
+                }\r
+                    \r
             } else if (component.equals(new ComponentName(FileDetailActivity.this, FileUploader.class))) {\r
                 Log.d(TAG, "Upload service connected");\r
                 mUploaderBinder = (FileUploaderBinder) service;\r
             } else {\r
                 return;\r
             }\r
-            FileDetailFragment fragment = (FileDetailFragment) getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);\r
-            if (fragment != null)\r
-                fragment.updateFileDetails(false);   // let the fragment gets the mDownloadBinder through getDownloadBinder() (see FileDetailFragment#updateFileDetais())\r
+            \r
+            Fragment fragment = getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);\r
+            FileDetailFragment detailsFragment = (fragment instanceof FileDetailFragment) ? (FileDetailFragment) fragment : null;\r
+            if (detailsFragment != null) {\r
+                detailsFragment.listenForTransferProgress();\r
+                detailsFragment.updateFileDetails(mWaitingToPreview, false);   // let the fragment gets the mDownloadBinder through getDownloadBinder() (see FileDetailFragment#updateFileDetais())\r
+            }\r
         }\r
 \r
         @Override\r
@@ -130,7 +223,7 @@ public class FileDetailActivity extends SherlockFragmentActivity implements File
         }\r
     };    \r
     \r
-\r
+    \r
     @Override\r
     public void onDestroy() {\r
         super.onDestroy();\r
@@ -151,7 +244,7 @@ public class FileDetailActivity extends SherlockFragmentActivity implements File
         \r
         switch(item.getItemId()){\r
         case android.R.id.home:\r
-            backToDisplayActivity();\r
+            backToDisplayActivity(true);\r
             returnValue = true;\r
             break;\r
         default:\r
@@ -163,22 +256,15 @@ public class FileDetailActivity extends SherlockFragmentActivity implements File
 \r
 \r
 \r
-    @Override\r
-    protected void onResume() {\r
-        \r
-        super.onResume();\r
-        if (!mConfigurationChangedToLandscape) { \r
-            FileDetailFragment fragment = (FileDetailFragment) getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);\r
-            fragment.updateFileDetails(false);\r
-        }\r
-    }\r
-    \r
-\r
-    private void backToDisplayActivity() {\r
+    private void backToDisplayActivity(boolean moveToParent) {\r
         Intent intent = new Intent(this, FileDisplayActivity.class);\r
         intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);\r
-        intent.putExtra(FileDetailFragment.EXTRA_FILE, getIntent().getParcelableExtra(FileDetailFragment.EXTRA_FILE));\r
-        intent.putExtra(FileDetailFragment.EXTRA_ACCOUNT, getIntent().getParcelableExtra(FileDetailFragment.EXTRA_ACCOUNT));\r
+        OCFile targetFile = null;\r
+        if (mFile != null) {\r
+            targetFile = moveToParent ? mStorageManager.getFileById(mFile.getParentId()) : mFile;\r
+        }\r
+        intent.putExtra(FileDetailFragment.EXTRA_FILE, targetFile);\r
+        intent.putExtra(FileDetailFragment.EXTRA_ACCOUNT, mAccount);\r
         startActivity(intent);\r
         finish();\r
     }\r
@@ -226,5 +312,84 @@ public class FileDetailActivity extends SherlockFragmentActivity implements File
     public FileUploaderBinder getFileUploaderBinder() {\r
         return mUploaderBinder;\r
     }\r
+\r
+\r
+    @Override\r
+    public void showFragmentWithDetails(OCFile file) {\r
+        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();\r
+        transaction.replace(R.id.fragment, new FileDetailFragment(file, mAccount), FileDetailFragment.FTAG); \r
+        transaction.commit();\r
+    }\r
+\r
+    \r
+    private void requestForDownload() {\r
+        if (!mDownloaderBinder.isDownloading(mAccount, mFile)) {\r
+            Intent i = new Intent(this, FileDownloader.class);\r
+            i.putExtra(FileDownloader.EXTRA_ACCOUNT, mAccount);\r
+            i.putExtra(FileDownloader.EXTRA_FILE, mFile);\r
+            startService(i);\r
+        }\r
+    }\r
+\r
     \r
+    /**\r
+     * Class waiting for broadcast events from the {@link FielDownloader} service.\r
+     * \r
+     * Updates the UI when a download is started or finished, provided that it is relevant for the\r
+     * current file.\r
+     */\r
+    private class DownloadFinishReceiver extends BroadcastReceiver {\r
+        @Override\r
+        public void onReceive(Context context, Intent intent) {\r
+            boolean sameAccount = isSameAccount(context, intent);\r
+            String downloadedRemotePath = intent.getStringExtra(FileDownloader.EXTRA_REMOTE_PATH);\r
+            boolean samePath = (mFile != null && mFile.getRemotePath().equals(downloadedRemotePath));\r
+            \r
+            if (sameAccount && samePath) {\r
+                updateChildFragment(intent.getAction(), downloadedRemotePath, intent.getBooleanExtra(FileDownloader.EXTRA_DOWNLOAD_RESULT, false));\r
+            }\r
+            \r
+            removeStickyBroadcast(intent);\r
+        }\r
+\r
+        private boolean isSameAccount(Context context, Intent intent) {\r
+            String accountName = intent.getStringExtra(FileDownloader.ACCOUNT_NAME);\r
+            return (accountName != null && accountName.equals(AccountUtils.getCurrentOwnCloudAccount(context).name));\r
+        }\r
+    }\r
+\r
+\r
+    public void updateChildFragment(String downloadEvent, String downloadedRemotePath, boolean success) {\r
+        Fragment fragment = getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);\r
+        if (fragment != null && fragment instanceof FileDetailFragment) {\r
+            FileDetailFragment detailsFragment = (FileDetailFragment) fragment;\r
+            OCFile fileInFragment = detailsFragment.getFile();\r
+            if (fileInFragment != null && !downloadedRemotePath.equals(fileInFragment.getRemotePath())) {\r
+                // this never should happen; fileInFragment should be always equals to mFile, that was compared to downloadedRemotePath in DownloadReceiver \r
+                mWaitingToPreview = false;\r
+                \r
+            } else if (downloadEvent.equals(FileDownloader.DOWNLOAD_ADDED_MESSAGE)) {\r
+                // grants that the progress bar is updated\r
+                detailsFragment.listenForTransferProgress();\r
+                detailsFragment.updateFileDetails(true, false);\r
+                \r
+            } else if (downloadEvent.equals(FileDownloader.DOWNLOAD_FINISH_MESSAGE)) {\r
+                //  refresh the details fragment \r
+                if (success && mWaitingToPreview) {\r
+                    mFile = mStorageManager.getFileById(mFile.getFileId());   // update the file from database, for the local storage path\r
+                    FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();\r
+                    transaction.replace(R.id.fragment, new PreviewMediaFragment(mFile, mAccount), FileDetailFragment.FTAG);\r
+                    transaction.commit();\r
+                    mWaitingToPreview = false;\r
+                    \r
+                } else {\r
+                    detailsFragment.updateFileDetails(false, (success));\r
+                    // TODO error message if !success ¿?\r
+                }\r
+            }\r
+        } // TODO else if (fragment != null && fragment )\r
+        \r
+        \r
+    }\r
+\r
 }\r
index 46ed65e..8e36b9a 100644 (file)
@@ -4,7 +4,7 @@
  *
  *   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
+ *   the Free Software Foundation, either version 3 of the License, or
  *   (at your option) any later version.
  *
  *   This program is distributed in the hope that it will be useful,
@@ -23,9 +23,9 @@ import java.io.File;
 
 import android.accounts.Account;
 import android.app.AlertDialog;
+import android.app.ProgressDialog;
 import android.app.AlertDialog.Builder;
 import android.app.Dialog;
-import android.app.ProgressDialog;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.ContentResolver;
@@ -49,6 +49,7 @@ 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.FragmentTransaction;
 import android.util.Log;
 import android.view.View;
@@ -66,7 +67,6 @@ import com.actionbarsherlock.view.MenuInflater;
 import com.actionbarsherlock.view.MenuItem;
 import com.actionbarsherlock.view.Window;
 import com.owncloud.android.AccountUtils;
-import com.owncloud.android.R;
 import com.owncloud.android.authenticator.AccountAuthenticator;
 import com.owncloud.android.datamodel.DataStorageManager;
 import com.owncloud.android.datamodel.FileDataStorageManager;
@@ -80,29 +80,36 @@ import com.owncloud.android.network.OwnCloudClientUtils;
 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.RemoveFileOperation;
 import com.owncloud.android.operations.RenameFileOperation;
 import com.owncloud.android.operations.SynchronizeFileOperation;
+import com.owncloud.android.operations.RemoteOperationResult.ResultCode;
 import com.owncloud.android.syncadapter.FileSyncService;
 import com.owncloud.android.ui.dialog.ChangelogDialog;
+import com.owncloud.android.ui.dialog.EditNameDialog;
 import com.owncloud.android.ui.dialog.SslValidatorDialog;
+import com.owncloud.android.ui.dialog.EditNameDialog.EditNameDialogListener;
 import com.owncloud.android.ui.dialog.SslValidatorDialog.OnSslValidatorListener;
 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.R;
 import eu.alefzero.webdav.WebdavClient;
 
 /**
  * Displays, what files the user has available in his ownCloud.
  * 
  * @author Bartek Przybylski
- * 
+ * @author David A. Velasco
  */
 
-public class FileDisplayActivity extends SherlockFragmentActivity implements OCFileListFragment.ContainerActivity,
-        FileDetailFragment.ContainerActivity, OnNavigationListener, OnSslValidatorListener, OnRemoteOperationListener {
-
+public class FileDisplayActivity extends SherlockFragmentActivity implements
+    OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNavigationListener, OnSslValidatorListener, OnRemoteOperationListener, EditNameDialogListener {
+    
     private ArrayAdapter<String> mDirectories;
     private OCFile mCurrentDir = null;
     private OCFile mCurrentFile = null;
@@ -119,6 +126,7 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements OCF
     private OCFileListFragment mFileList;
     
     private boolean mDualPane;
+    private boolean mBackFromCreatingFirstAccount;
     
     private static final int DIALOG_SETUP_ACCOUNT = 0;
     private static final int DIALOG_CREATE_DIR = 1;
@@ -132,11 +140,14 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements OCF
     
     private static final int ACTION_SELECT_CONTENT_FROM_APPS = 1;
     private static final int ACTION_SELECT_MULTIPLE_FILES = 2;
-    private static final int ACTION_SELECT_FAILED_INSTANT_UPLOAD = 2;
-
+    
     private static final String TAG = "FileDisplayActivity";
 
-    private static int[] mMenuIdentifiersToPatch = {R.id.about_app};
+    private static int[] mMenuIdentifiersToPatch = {R.id.action_about_app};
+    
+    private OCFile mWaitingToPreview;
+    private Handler mHandler;
+
     
     @Override
     public void onCreate(Bundle savedInstanceState) {
@@ -144,28 +155,30 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements OCF
         super.onCreate(savedInstanceState);
 
         /// Load of parameters from received intent
-        mCurrentDir = getIntent().getParcelableExtra(FileDetailFragment.EXTRA_FILE); // no check necessary, mCurrenDir == null if the parameter is not in the intent
         Account account = getIntent().getParcelableExtra(FileDetailFragment.EXTRA_ACCOUNT);
-        if (account != null)
-            AccountUtils.setCurrentOwnCloudAccount(this, account.name);
+        if (account != null && AccountUtils.setCurrentOwnCloudAccount(this, account.name)) {
+            mCurrentDir = getIntent().getParcelableExtra(FileDetailFragment.EXTRA_FILE); 
+        }
         
         /// Load of saved instance state: keep this always before initDataFromCurrentAccount()
         if(savedInstanceState != null) {
             // TODO - test if savedInstanceState should take precedence over file in the intent ALWAYS (now), NEVER, or SOME TIMES
             mCurrentDir = savedInstanceState.getParcelable(FileDetailFragment.EXTRA_FILE);
+            mWaitingToPreview = (OCFile) savedInstanceState.getParcelable(FileDetailActivity.KEY_WAITING_TO_PREVIEW);
+
+        } else {
+            mWaitingToPreview = null;
         }
         
         if (!AccountUtils.accountsAreSetup(this)) {
             /// no account available: FORCE ACCOUNT CREATION
             mStorageManager = null;
             createFirstAccount();
-
-        } else { // / at least an account is available
-
-            initDataFromCurrentAccount(); // it checks mCurrentDir and
-                                          // mCurrentFile with the current
-                                          // account
-
+            
+        } else {    /// at least an account is available
+            
+            initDataFromCurrentAccount();   // it checks mCurrentDir and mCurrentFile with the current account
+            
         }
         
         mUploadConnection = new ListServiceConnection(); 
@@ -190,7 +203,7 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements OCF
         // Drop-down navigation 
         mDirectories = new CustomArrayAdapter<String>(this, R.layout.sherlock_spinner_dropdown_item);
         OCFile currFile = mCurrentDir;
-        while (currFile != null && currFile.getFileName() != OCFile.PATH_SEPARATOR) {
+        while(mStorageManager != null && currFile != null && currFile.getFileName() != OCFile.PATH_SEPARATOR) {
             mDirectories.add(currFile.getFileName());
             currFile = mStorageManager.getFileById(currFile.getParentId());
         }
@@ -201,7 +214,20 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements OCF
         mFileList = (OCFileListFragment) getSupportFragmentManager().findFragmentById(R.id.fileList);
         mDualPane = (findViewById(R.id.file_details_container) != null);
         if (mDualPane) {
-            initFileDetailsInDualPane();
+            if (savedInstanceState == null) initFileDetailsInDualPane();
+        } else {
+            // quick patchES to fix problem in turn from landscape to portrait, when a file is selected in the right pane
+            // TODO serious refactorization in activities and fragments providing file browsing and handling 
+            if (mCurrentFile != null) {
+                onFileClick(mCurrentFile);
+                mCurrentFile = null;
+            }
+            Fragment rightPanel = getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);
+            if (rightPanel != null) {
+                FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
+                transaction.remove(rightPanel);
+                transaction.commit();
+            }
         }
             
         // Action bar setup
@@ -215,7 +241,8 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements OCF
         
         
         // show changelog, if needed
-        showChangeLog();
+        //showChangeLog();
+        mBackFromCreatingFirstAccount = false;
         
         Log.d(getClass().toString(), "onCreate() end");
     }
@@ -256,7 +283,7 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements OCF
         startActivity(intent);  // the new activity won't be created until this.onStart() and this.onResume() are finished;
     }
 
-
+    
     /**
      *  Load of state dependent of the existence of an ownCloud account
      */
@@ -293,13 +320,20 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements OCF
         if (mDualPane && getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG) == null) {
             FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
             if (mCurrentFile != null) {
-                transaction.replace(R.id.file_details_container,
-                        new FileDetailFragment(mCurrentFile, AccountUtils.getCurrentOwnCloudAccount(this)),
-                        FileDetailFragment.FTAG); // empty FileDetailFragment
+                if (PreviewMediaFragment.canBePreviewed(mCurrentFile)) {
+                    if (mCurrentFile.isDown()) {
+                        transaction.replace(R.id.file_details_container, new PreviewMediaFragment(mCurrentFile, AccountUtils.getCurrentOwnCloudAccount(this)), FileDetailFragment.FTAG);
+                    } else {
+                        transaction.replace(R.id.file_details_container, new FileDetailFragment(mCurrentFile, AccountUtils.getCurrentOwnCloudAccount(this)), FileDetailFragment.FTAG);
+                        mWaitingToPreview = mCurrentFile;
+                    }
+                } else {
+                    transaction.replace(R.id.file_details_container, new FileDetailFragment(mCurrentFile, AccountUtils.getCurrentOwnCloudAccount(this)), FileDetailFragment.FTAG);
+                }
                 mCurrentFile = null;
+                
             } else {
-                transaction.replace(R.id.file_details_container, new FileDetailFragment(null, null),
-                        FileDetailFragment.FTAG); // empty FileDetailFragment
+                transaction.replace(R.id.file_details_container, new FileDetailFragment(null, null), FileDetailFragment.FTAG); // empty FileDetailFragment
             }
             transaction.commit();
         }
@@ -319,7 +353,7 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements OCF
     @Override
     public boolean onCreateOptionsMenu(Menu menu) {
         MenuInflater inflater = getSherlock().getMenuInflater();
-            inflater.inflate(R.menu.menu, menu);
+            inflater.inflate(R.menu.main_menu, menu);
             
             patchHiddenAccents(menu);
             
@@ -350,35 +384,36 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements OCF
     public boolean onOptionsItemSelected(MenuItem item) {
         boolean retval = true;
         switch (item.getItemId()) {
-        case R.id.createDirectoryItem: {
-            showDialog(DIALOG_CREATE_DIR);
-            break;
-        }
-        case R.id.startSync: {
-            startSynchronization();
-            break;
-        }
-        case R.id.action_upload: {
-            showDialog(DIALOG_CHOOSE_UPLOAD_SOURCE);
-            break;
-        }
-        case R.id.action_settings: {
-            Intent settingsIntent = new Intent(this, Preferences.class);
-            startActivity(settingsIntent);
-            break;
-        }
-        case R.id.about_app: {
-            showDialog(DIALOG_ABOUT_APP);
-            break;
-        }
-        case android.R.id.home: {
-            if (mCurrentDir != null && mCurrentDir.getParentId() != 0) {
-                onBackPressed();
+            case R.id.action_create_dir: {
+                EditNameDialog dialog = EditNameDialog.newInstance(getString(R.string.uploader_info_dirname), "", this);
+                dialog.show(getSupportFragmentManager(), "createdirdialog");
+                break;
             }
-            break;
-        }
-        default:
-            retval = super.onOptionsItemSelected(item);
+            case R.id.action_sync_account: {
+                startSynchronization();
+                break;
+            }
+            case R.id.action_upload: {
+                showDialog(DIALOG_CHOOSE_UPLOAD_SOURCE);
+                break;
+            }
+            case R.id.action_settings: {
+                Intent settingsIntent = new Intent(this, Preferences.class);
+                startActivity(settingsIntent);
+                break;
+            }
+            case R.id.action_about_app: {
+                showDialog(DIALOG_ABOUT_APP);
+                break;
+            }
+            case android.R.id.home: {
+                if(mCurrentDir != null && mCurrentDir.getParentId() != 0){
+                    onBackPressed(); 
+                }
+                break;
+            }
+            default:
+                retval = super.onOptionsItemSelected(item);
         }
         return retval;
     }
@@ -411,13 +446,11 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements OCF
      * Called, when the user selected something for uploading
      */
     public void onActivityResult(int requestCode, int resultCode, Intent data) {
-
-        if (requestCode == ACTION_SELECT_CONTENT_FROM_APPS
-                && (resultCode == RESULT_OK || resultCode == UploadFilesActivity.RESULT_OK_AND_MOVE)) {
+        
+        if (requestCode == ACTION_SELECT_CONTENT_FROM_APPS && (resultCode == RESULT_OK || resultCode == UploadFilesActivity.RESULT_OK_AND_MOVE)) {
             requestSimpleUpload(data, resultCode);
-
-        } else if (requestCode == ACTION_SELECT_MULTIPLE_FILES
-                && (resultCode == RESULT_OK || resultCode == UploadFilesActivity.RESULT_OK_AND_MOVE)) {
+            
+        } else if (requestCode == ACTION_SELECT_MULTIPLE_FILES && (resultCode == RESULT_OK || resultCode == UploadFilesActivity.RESULT_OK_AND_MOVE)) {
             requestMultipleUpload(data, resultCode);
             
         }
@@ -433,7 +466,7 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements OCF
             }
             if (!remotePathBase.endsWith(OCFile.PATH_SEPARATOR))
                 remotePathBase += OCFile.PATH_SEPARATOR;
-            for (int j = 0; j < remotePaths.length; j++) {
+            for (int j = 0; j< remotePaths.length; j++) {
                 remotePaths[j] = remotePathBase + (new File(filePaths[j])).getName();
             }
 
@@ -482,7 +515,8 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements OCF
         }
 
         Intent i = new Intent(this, FileUploader.class);
-        i.putExtra(FileUploader.KEY_ACCOUNT, AccountUtils.getCurrentOwnCloudAccount(this));
+        i.putExtra(FileUploader.KEY_ACCOUNT,
+                AccountUtils.getCurrentOwnCloudAccount(this));
         String remotepath = new String();
         for (int j = mDirectories.getCount() - 2; j >= 0; --j) {
             remotepath += OCFile.PATH_SEPARATOR + mDirectories.getItem(j);
@@ -511,23 +545,19 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements OCF
         mCurrentDir = mFileList.getCurrentFile();
         
         if (mDualPane) {
-            // Resets the FileDetailsFragment on Tablets so that it always
-            // displays
-            FileDetailFragment fileDetails = (FileDetailFragment) getSupportFragmentManager().findFragmentByTag(
-                    FileDetailFragment.FTAG);
-            if (fileDetails != null && !fileDetails.isEmpty()) {
+            // Resets the FileDetailsFragment on Tablets so that it always displays
+            Fragment fileFragment = getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);
+            if (fileFragment != null && (fileFragment instanceof PreviewMediaFragment || !((FileDetailFragment) fileFragment).isEmpty())) {
                 FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
-                transaction.remove(fileDetails);
-                transaction.add(R.id.file_details_container, new FileDetailFragment(null, null),
-                        FileDetailFragment.FTAG);
+                transaction.replace(R.id.file_details_container, new FileDetailFragment(null, null), FileDetailFragment.FTAG); // empty FileDetailFragment                
                 transaction.commit();
             }
         }
-
-        if (mCurrentDir.getParentId() == 0) {
-            ActionBar actionBar = getSupportActionBar();
+        
+        if(mCurrentDir.getParentId() == 0){
+            ActionBar actionBar = getSupportActionBar(); 
             actionBar.setDisplayHomeAsUpEnabled(false);
-        }
+        } 
     }
 
     @Override
@@ -537,19 +567,21 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements OCF
         super.onSaveInstanceState(outState);
         outState.putParcelable(FileDetailFragment.EXTRA_FILE, mCurrentDir);
         if (mDualPane) {
-            FileDetailFragment fragment = (FileDetailFragment) getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);
+            FileFragment fragment = (FileFragment) getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);
             if (fragment != null) {
-                OCFile file = fragment.getDisplayedFile();
+                OCFile file = fragment.getFile();
                 if (file != null) {
                     outState.putParcelable(FileDetailFragment.EXTRA_FILE, file);
                 }
             }
         }
+        outState.putParcelable(FileDetailActivity.KEY_WAITING_TO_PREVIEW, mWaitingToPreview);
         Log.d(getClass().toString(), "onSaveInstanceState() end");
     }
 
+    
     @Override
-    protected void onResume() {
+    public void onResume() {
         Log.d(getClass().toString(), "onResume() start");
         super.onResume();
 
@@ -561,6 +593,7 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements OCF
                 if (mDualPane) {
                     initFileDetailsInDualPane();
                 }
+                mBackFromCreatingFirstAccount = true;
             }
             
             // Listen for sync messages
@@ -574,7 +607,8 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements OCF
             registerReceiver(mUploadFinishReceiver, uploadIntentFilter);
             
             // Listen for download messages
-            IntentFilter downloadIntentFilter = new IntentFilter(FileDownloader.DOWNLOAD_FINISH_MESSAGE);
+            IntentFilter downloadIntentFilter = new IntentFilter(FileDownloader.DOWNLOAD_ADDED_MESSAGE);
+            downloadIntentFilter.addAction(FileDownloader.DOWNLOAD_FINISH_MESSAGE);
             mDownloadFinishReceiver = new DownloadFinishReceiver();
             registerReceiver(mDownloadFinishReceiver, downloadIntentFilter);
         
@@ -592,7 +626,7 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements OCF
 
     
     @Override
-    protected void onPause() {
+    public void onPause() {
         Log.d(getClass().toString(), "onPause() start");
         super.onPause();
         if (mSyncBroadcastReceiver != null) {
@@ -673,57 +707,71 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements OCF
             builder.setTitle(R.string.uploader_info_dirname);
             int typed_color = getResources().getColor(R.color.setup_text_typed);
             dirNameInput.setTextColor(typed_color);
-            builder.setPositiveButton(android.R.string.ok, new OnClickListener() {
-                public void onClick(DialogInterface dialog, int which) {
-                    String directoryName = dirNameInput.getText().toString();
-                    if (directoryName.trim().length() == 0) {
-                        dialog.cancel();
-                        return;
-                    }
-
-                    // Figure out the path where the dir needs to be created
-                    String path;
-                    if (mCurrentDir == null) {
-                        // this is just a patch; we should ensure that
-                        // mCurrentDir never is null
-                        if (!mStorageManager.fileExists(OCFile.PATH_SEPARATOR)) {
-                            OCFile file = new OCFile(OCFile.PATH_SEPARATOR);
-                            mStorageManager.saveFile(file);
+            builder.setPositiveButton(android.R.string.ok,
+                    new OnClickListener() {
+                        public void onClick(DialogInterface dialog, int which) {
+                            String directoryName = dirNameInput.getText().toString();
+                            if (directoryName.trim().length() == 0) {
+                                dialog.cancel();
+                                return;
+                            }
+    
+                            // Figure out the path where the dir needs to be created
+                            String path;
+                            if (mCurrentDir == null) {
+                                // this is just a patch; we should ensure that mCurrentDir never is null
+                                if (!mStorageManager.fileExists(OCFile.PATH_SEPARATOR)) {
+                                    OCFile file = new OCFile(OCFile.PATH_SEPARATOR);
+                                    mStorageManager.saveFile(file);
+                                }
+                                mCurrentDir = mStorageManager.getFileByPath(OCFile.PATH_SEPARATOR);
+                            }
+                            path = FileDisplayActivity.this.mCurrentDir.getRemotePath();
+                            
+                            // Create directory
+                            path += directoryName + OCFile.PATH_SEPARATOR;
+                            Thread thread = new Thread(new DirectoryCreator(path,  AccountUtils.getCurrentOwnCloudAccount(FileDisplayActivity.this), new Handler()));
+                            thread.start();
+                            
+                            dialog.dismiss();
+                            
+                            showDialog(DIALOG_SHORT_WAIT);
                         }
-                        mCurrentDir = mStorageManager.getFileByPath(OCFile.PATH_SEPARATOR);
-                    }
-                    path = FileDisplayActivity.this.mCurrentDir.getRemotePath();
-
-                    // Create directory
-                    path += directoryName + OCFile.PATH_SEPARATOR;
-                    Thread thread = new Thread(new DirectoryCreator(path, AccountUtils
-                            .getCurrentOwnCloudAccount(FileDisplayActivity.this), new Handler()));
-                    thread.start();
-
-                    dialog.dismiss();
-
-                    showDialog(DIALOG_SHORT_WAIT);
-                }
-            });
-            builder.setNegativeButton(R.string.common_cancel, new OnClickListener() {
-                public void onClick(DialogInterface dialog, int which) {
-                    dialog.cancel();
-                }
-            });
+                    });
+            builder.setNegativeButton(R.string.common_cancel,
+                    new OnClickListener() {
+                        public void onClick(DialogInterface dialog, int which) {
+                            dialog.cancel();
+                        }
+                    });
             dialog = builder.create();
             break;
         }
         case DIALOG_SHORT_WAIT: {
             ProgressDialog working_dialog = new ProgressDialog(this);
-            working_dialog.setMessage(getResources().getString(R.string.wait_a_moment));
+            working_dialog.setMessage(getResources().getString(
+                    R.string.wait_a_moment));
             working_dialog.setIndeterminate(true);
             working_dialog.setCancelable(false);
             dialog = working_dialog;
             break;
         }
         case DIALOG_CHOOSE_UPLOAD_SOURCE: {
-            final String[] items = { getString(R.string.actionbar_upload_files),
-                    getString(R.string.actionbar_upload_from_apps), getString(R.string.actionbar_failed_instant_upload) };
+            
+            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() {
@@ -743,7 +791,7 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements OCF
                         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) {
+                    } else if (item == 2 && InstantUploadActivity.IS_ENABLED) {
                         Account account = AccountUtils.getCurrentOwnCloudAccount(FileDisplayActivity.this);
                         Intent action = new Intent(FileDisplayActivity.this, InstantUploadActivity.class);
                         action.putExtra(FileUploader.KEY_ACCOUNT, account);
@@ -763,11 +811,11 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements OCF
             builder.setMessage(getResources().getString(R.string.ssl_validator_not_saved));
             builder.setCancelable(false);
             builder.setPositiveButton(R.string.common_ok, new DialogInterface.OnClickListener() {
-                @Override
-                public void onClick(DialogInterface dialog, int which) {
-                    dialog.dismiss();
-                };
-            });
+                    @Override
+                    public void onClick(DialogInterface dialog, int which) {
+                        dialog.dismiss();
+                    };
+                });
             dialog = builder.create();
             break;
         }
@@ -789,10 +837,11 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements OCF
         String[] projection = { MediaStore.Images.Media.DATA };
         Cursor cursor = managedQuery(uri, projection, null, null, null);
         if (cursor != null) {
-            int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
+            int column_index = cursor
+                    .getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
             cursor.moveToFirst();
             return cursor.getString(column_index);
-        }
+        } 
         return null;
     }
     
@@ -856,12 +905,11 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements OCF
                     public void run() {
                         dismissDialog(DIALOG_SHORT_WAIT);
                         try {
-                            Toast msg = Toast.makeText(FileDisplayActivity.this, R.string.create_dir_fail_msg,
-                                    Toast.LENGTH_LONG);
+                            Toast msg = Toast.makeText(FileDisplayActivity.this, R.string.create_dir_fail_msg, Toast.LENGTH_LONG); 
                             msg.show();
                         
                         } catch (NotFoundException e) {
-                            Log.e(TAG, "Error while trying to show fail message ", e);
+                            Log.e(TAG, "Error while trying to show fail message " , e);
                         }
                     }
                 });
@@ -879,16 +927,19 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements OCF
     
         public View getView(int position, View convertView, ViewGroup parent) {
             View v = super.getView(position, convertView, parent);
-
-            ((TextView) v).setTextColor(getResources().getColorStateList(android.R.color.white));
+    
+            ((TextView) v).setTextColor(getResources().getColorStateList(
+                    android.R.color.white));
             return v;
         }
-
-        public View getDropDownView(int position, View convertView, ViewGroup parent) {
+    
+        public View getDropDownView(int position, View convertView,
+                ViewGroup parent) {
             View v = super.getDropDownView(position, convertView, parent);
-
-            ((TextView) v).setTextColor(getResources().getColorStateList(android.R.color.white));
-
+    
+            ((TextView) v).setTextColor(getResources().getColorStateList(
+                    android.R.color.white));
+    
             return v;
         }
     
@@ -901,24 +952,27 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements OCF
          */
         @Override
         public void onReceive(Context context, Intent intent) {
-            boolean inProgress = intent.getBooleanExtra(FileSyncService.IN_PROGRESS, false);
-            String accountName = intent.getStringExtra(FileSyncService.ACCOUNT_NAME);
-
-            Log.d("FileDisplay", "sync of account " + accountName + " is in_progress: " + inProgress);
+            boolean inProgress = intent.getBooleanExtra(
+                    FileSyncService.IN_PROGRESS, false);
+            String accountName = intent
+                    .getStringExtra(FileSyncService.ACCOUNT_NAME);
 
-            if (accountName.equals(AccountUtils.getCurrentOwnCloudAccount(context).name)) {
-
-                String synchFolderRemotePath = intent.getStringExtra(FileSyncService.SYNC_FOLDER_REMOTE_PATH);
+            Log.d("FileDisplay", "sync of account " + accountName
+                    + " is in_progress: " + inProgress);
 
+            if (accountName.equals(AccountUtils.getCurrentOwnCloudAccount(context).name)) {  
+            
+                String synchFolderRemotePath = intent.getStringExtra(FileSyncService.SYNC_FOLDER_REMOTE_PATH); 
+                 
                 boolean fillBlankRoot = false;
                 if (mCurrentDir == null) {
                     mCurrentDir = mStorageManager.getFileByPath("/");
                     fillBlankRoot = (mCurrentDir != null);
                 }
 
-                if ((synchFolderRemotePath != null && mCurrentDir != null && (mCurrentDir.getRemotePath()
-                        .equals(synchFolderRemotePath))) || fillBlankRoot) {
-                    if (!fillBlankRoot)
+                if ((synchFolderRemotePath != null && mCurrentDir != null && (mCurrentDir.getRemotePath().equals(synchFolderRemotePath)))
+                        || fillBlankRoot ) {
+                    if (!fillBlankRoot) 
                         mCurrentDir = getStorageManager().getFileByPath(synchFolderRemotePath);
                     OCFileListFragment fileListFragment = (OCFileListFragment) getSupportFragmentManager()
                             .findFragmentById(R.id.fileList);
@@ -928,16 +982,22 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements OCF
                 }
                 
                 setSupportProgressBarIndeterminateVisibility(inProgress);
+                if (mBackFromCreatingFirstAccount) {
+                    // awful patch to fix problem with visibility of progress circle with the first refresh of the first account
+                    // TODO - kill this Activity when the first account has to be created instead of stack the account creation on it
+                    getSupportActionBar().hide();
+                    getSupportActionBar().show();
+                    mBackFromCreatingFirstAccount = false;
+                }
                 removeStickyBroadcast(intent);
                 
             }
-
-            RemoteOperationResult synchResult = (RemoteOperationResult) intent
-                    .getSerializableExtra(FileSyncService.SYNC_RESULT);
+            
+            RemoteOperationResult synchResult = (RemoteOperationResult)intent.getSerializableExtra(FileSyncService.SYNC_RESULT);
             if (synchResult != null) {
                 if (synchResult.getCode().equals(RemoteOperationResult.ResultCode.SSL_RECOVERABLE_PEER_UNVERIFIED)) {
                     mLastSslUntrustedServerResult = synchResult;
-                    showDialog(DIALOG_SSL_VALIDATOR);
+                    showDialog(DIALOG_SSL_VALIDATOR); 
                 }
             }
         }
@@ -955,12 +1015,10 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements OCF
             String uploadedRemotePath = intent.getStringExtra(FileDownloader.EXTRA_REMOTE_PATH);
             String accountName = intent.getStringExtra(FileUploader.ACCOUNT_NAME);
             boolean sameAccount = accountName.equals(AccountUtils.getCurrentOwnCloudAccount(context).name);
-            boolean isDescendant = (mCurrentDir != null) && (uploadedRemotePath != null)
-                    && (uploadedRemotePath.startsWith(mCurrentDir.getRemotePath()));
+            boolean isDescendant = (mCurrentDir != null) && (uploadedRemotePath != null) && (uploadedRemotePath.startsWith(mCurrentDir.getRemotePath()));
             if (sameAccount && isDescendant) {
-                OCFileListFragment fileListFragment = (OCFileListFragment) getSupportFragmentManager()
-                        .findFragmentById(R.id.fileList);
-                if (fileListFragment != null) {
+                OCFileListFragment fileListFragment = (OCFileListFragment) getSupportFragmentManager().findFragmentById(R.id.fileList);
+                if (fileListFragment != null) { 
                     fileListFragment.listDirectory();
                 }
             }
@@ -970,29 +1028,78 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements OCF
     
     
     /**
-     * Once the file download has finished -> update view
+     * Class waiting for broadcast events from the {@link FielDownloader} service.
+     * 
+     * Updates the UI when a download is started or finished, provided that it is relevant for the
+     * current folder.
      */
     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);
-            String accountName = intent.getStringExtra(FileDownloader.ACCOUNT_NAME);
-            boolean sameAccount = accountName.equals(AccountUtils.getCurrentOwnCloudAccount(context).name);
-            boolean isDescendant = (mCurrentDir != null) && (downloadedRemotePath != null)
-                    && (downloadedRemotePath.startsWith(mCurrentDir.getRemotePath()));
+            boolean isDescendant = isDescendant(downloadedRemotePath);
+            
             if (sameAccount && isDescendant) {
-                OCFileListFragment fileListFragment = (OCFileListFragment) getSupportFragmentManager()
-                        .findFragmentById(R.id.fileList);
-                if (fileListFragment != null) {
-                    fileListFragment.listDirectory();
+                updateLeftPanel();
+                if (mDualPane) {
+                    updateRightPanel(intent.getAction(), downloadedRemotePath, intent.getBooleanExtra(FileDownloader.EXTRA_DOWNLOAD_RESULT, false));
                 }
             }
+            
+            removeStickyBroadcast(intent);
+        }
+
+        private boolean isDescendant(String downloadedRemotePath) {
+            return (mCurrentDir != null && downloadedRemotePath != null && downloadedRemotePath.startsWith(mCurrentDir.getRemotePath()));
+        }
+
+        private boolean isSameAccount(Context context, Intent intent) {
+            String accountName = intent.getStringExtra(FileDownloader.ACCOUNT_NAME);
+            return (accountName != null && accountName.equals(AccountUtils.getCurrentOwnCloudAccount(context).name));
         }
     }
     
     
-    
-    
+    protected void updateLeftPanel() {
+        OCFileListFragment fileListFragment = (OCFileListFragment) getSupportFragmentManager().findFragmentById(R.id.fileList);
+        if (fileListFragment != null) { 
+            fileListFragment.listDirectory();
+        }
+    }
+
+    protected void updateRightPanel(String downloadEvent, String downloadedRemotePath, boolean success) {
+        Fragment fragment = getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);
+        boolean waitedPreview = (mWaitingToPreview != null && mWaitingToPreview.getRemotePath().equals(downloadedRemotePath));
+        if (fragment != null && fragment instanceof FileDetailFragment) {
+            FileDetailFragment detailsFragment = (FileDetailFragment) fragment;
+            OCFile fileInFragment = detailsFragment.getFile();
+            if (fileInFragment != null && !downloadedRemotePath.equals(fileInFragment.getRemotePath())) {
+                // the user browsed to other file ; forget the automatic preview 
+                mWaitingToPreview = null;
+                
+            } else if (downloadEvent.equals(FileDownloader.DOWNLOAD_ADDED_MESSAGE)) {
+                // grant that the right panel updates the progress bar
+                detailsFragment.listenForTransferProgress();
+                detailsFragment.updateFileDetails(true, false);
+                
+            } else if (downloadEvent.equals(FileDownloader.DOWNLOAD_FINISH_MESSAGE)) {
+                //  update the right panel 
+                if (success && waitedPreview) {
+                    mWaitingToPreview = mStorageManager.getFileById(mWaitingToPreview.getFileId());   // update the file from database, for the local storage path
+                    FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
+                    transaction.replace(R.id.file_details_container, new PreviewMediaFragment(mWaitingToPreview, AccountUtils.getCurrentOwnCloudAccount(this)), FileDetailFragment.FTAG);
+                    transaction.commit();
+                    mWaitingToPreview = null;
+                    
+                } else {
+                    detailsFragment.updateFileDetails(false, (success));
+                }
+            }
+        }
+    }
+
+
     /**
      * {@inheritDoc}
      */
@@ -1001,7 +1108,7 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements OCF
         return mStorageManager;
     }
     
-    
+
     /**
      * {@inheritDoc}
      */
@@ -1013,12 +1120,10 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements OCF
         
         if (mDualPane) {
             // Resets the FileDetailsFragment on Tablets so that it always displays
-            FileDetailFragment fileDetails = (FileDetailFragment) getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);
-            if (fileDetails != null && !fileDetails.isEmpty()) {
+            Fragment fileFragment = getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);
+            if (fileFragment != null && (fileFragment instanceof PreviewMediaFragment || !((FileDetailFragment) fileFragment).isEmpty())) {
                 FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
-                transaction.remove(fileDetails);
-                transaction.add(R.id.file_details_container, new FileDetailFragment(null, null),
-                        FileDetailFragment.FTAG);
+                transaction.replace(R.id.file_details_container, new FileDetailFragment(null, null), FileDetailFragment.FTAG); // empty FileDetailFragment                
                 transaction.commit();
             }
         }
@@ -1030,19 +1135,40 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements OCF
      */
     @Override
     public void onFileClick(OCFile file) {
-        
-        // If we are on a large device -> update fragment
+        if (file != null && PreviewImageFragment.canBePreviewed(file)) {
+            // preview image - it handles the download, if needed
+            startPreviewImage(file);
+            
+        } else if (file != null && PreviewMediaFragment.canBePreviewed(file)) {
+            if (file.isDown()) {
+                // general preview
+                startMediaPreview(file);
+                
+            } else {
+                // automatic download, preview on finish
+                startDownloadForPreview(file);
+                
+            }
+        } else {
+            // details view
+            startDetails(file);
+        }
+    }
+
+    private void startPreviewImage(OCFile file) {
+        Intent showDetailsIntent = new Intent(this, PreviewImageActivity.class);
+        showDetailsIntent.putExtra(FileDetailFragment.EXTRA_FILE, file);
+        showDetailsIntent.putExtra(FileDetailFragment.EXTRA_ACCOUNT, AccountUtils.getCurrentOwnCloudAccount(this));
+        startActivity(showDetailsIntent);
+    }
+    
+    private void startMediaPreview(OCFile file) {
         if (mDualPane) {
-            // buttons in the details view are problematic when trying to reuse an existing fragment; create always a new one solves some of them, BUT no all; downloads are 'dangerous'
             FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
-            transaction
-                    .replace(R.id.file_details_container,
-                            new FileDetailFragment(file, AccountUtils.getCurrentOwnCloudAccount(this)),
-                            FileDetailFragment.FTAG);
-            transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
+            transaction.replace(R.id.file_details_container, new PreviewMediaFragment(file, AccountUtils.getCurrentOwnCloudAccount(this)), FileDetailFragment.FTAG);
             transaction.commit();
-
-        } else { // small or medium screen device -> new Activity
+            
+        } else {
             Intent showDetailsIntent = new Intent(this, FileDetailActivity.class);
             showDetailsIntent.putExtra(FileDetailFragment.EXTRA_FILE, file);
             showDetailsIntent.putExtra(FileDetailFragment.EXTRA_ACCOUNT, AccountUtils.getCurrentOwnCloudAccount(this));
@@ -1050,7 +1176,37 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements OCF
         }
     }
     
+    private void startDownloadForPreview(OCFile file) {
+        if (mDualPane) {
+            FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
+            transaction.replace(R.id.file_details_container, new FileDetailFragment(file, AccountUtils.getCurrentOwnCloudAccount(this)), FileDetailFragment.FTAG);
+            transaction.commit();
+            mWaitingToPreview = file;
+            requestForDownload();
+            
+        } else {
+            Intent showDetailsIntent = new Intent(this, FileDetailActivity.class);
+            showDetailsIntent.putExtra(FileDetailFragment.EXTRA_FILE, file);
+            showDetailsIntent.putExtra(FileDetailFragment.EXTRA_ACCOUNT, AccountUtils.getCurrentOwnCloudAccount(this));
+            startActivity(showDetailsIntent);
+        }
+    }
+
     
+    private void startDetails(OCFile file) {
+        if (mDualPane && !file.isImage()) {
+            FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
+            transaction.replace(R.id.file_details_container, new FileDetailFragment(file, AccountUtils.getCurrentOwnCloudAccount(this)), FileDetailFragment.FTAG);
+            transaction.commit();
+        } else {
+            Intent showDetailsIntent = new Intent(this, FileDetailActivity.class);
+            showDetailsIntent.putExtra(FileDetailFragment.EXTRA_FILE, file);
+            showDetailsIntent.putExtra(FileDetailFragment.EXTRA_ACCOUNT, AccountUtils.getCurrentOwnCloudAccount(this));
+            startActivity(showDetailsIntent);
+        }
+    }
+
+
     /**
      * {@inheritDoc}
      */
@@ -1065,9 +1221,8 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements OCF
      */
     @Override
     public void onFileStateChanged() {
-        OCFileListFragment fileListFragment = (OCFileListFragment) getSupportFragmentManager().findFragmentById(
-                R.id.fileList);
-        if (fileListFragment != null) {
+        OCFileListFragment fileListFragment = (OCFileListFragment) getSupportFragmentManager().findFragmentById(R.id.fileList);
+        if (fileListFragment != null) { 
             fileListFragment.listDirectory();
         }
     }
@@ -1099,6 +1254,10 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements OCF
             if (component.equals(new ComponentName(FileDisplayActivity.this, FileDownloader.class))) {
                 Log.d(TAG, "Download service connected");
                 mDownloaderBinder = (FileDownloaderBinder) service;
+                if (mWaitingToPreview != null) {
+                    requestForDownload();
+                }
+                
             } else if (component.equals(new ComponentName(FileDisplayActivity.this, FileUploader.class))) {
                 Log.d(TAG, "Upload service connected");
                 mUploaderBinder = (FileUploaderBinder) service;
@@ -1109,10 +1268,12 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements OCF
             if (mFileList != null)
                 mFileList.listDirectory();
             if (mDualPane) {
-                FileDetailFragment fragment = (FileDetailFragment) getSupportFragmentManager().findFragmentByTag(
-                        FileDetailFragment.FTAG);
-                if (fragment != null)
-                    fragment.updateFileDetails(false);
+                Fragment fragment = getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);
+                if (fragment != null && fragment instanceof FileDetailFragment) {
+                    FileDetailFragment detailFragment = (FileDetailFragment)fragment;
+                    detailFragment.listenForTransferProgress();
+                    detailFragment.updateFileDetails(false, false);
+                }
             }
         }
 
@@ -1150,6 +1311,7 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements OCF
         startSynchronization();                
     }
 
+
     @Override
     public void onFailedSavingCertificate() {
         showDialog(DIALOG_CERT_NOT_SAVED);
@@ -1166,13 +1328,13 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements OCF
     @Override
     public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationResult result) {
         if (operation instanceof RemoveFileOperation) {
-            onRemoveFileOperationFinish((RemoveFileOperation) operation, result);
-
+            onRemoveFileOperationFinish((RemoveFileOperation)operation, result);
+                
         } else if (operation instanceof RenameFileOperation) {
-            onRenameFileOperationFinish((RenameFileOperation) operation, result);
-
+            onRenameFileOperationFinish((RenameFileOperation)operation, result);
+            
         } else if (operation instanceof SynchronizeFileOperation) {
-            onSynchronizeFileOperationFinish((SynchronizeFileOperation) operation, result);
+            onSynchronizeFileOperationFinish((SynchronizeFileOperation)operation, result);
         }
     }
 
@@ -1191,12 +1353,10 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements OCF
             msg.show();
             OCFile removedFile = operation.getFile();
             if (mDualPane) {
-                FileDetailFragment details = (FileDetailFragment) getSupportFragmentManager().findFragmentByTag(
-                        FileDetailFragment.FTAG);
-                if (details != null && removedFile.equals(details.getDisplayedFile())) {
+                FileFragment details = (FileFragment) getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);
+                if (details != null && removedFile.equals(details.getFile())) {
                     FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
-                    transaction.replace(R.id.file_details_container, new FileDetailFragment(null, null)); // empty
-                                                                                                          // FileDetailFragment
+                    transaction.replace(R.id.file_details_container, new FileDetailFragment(null, null)); // empty FileDetailFragment
                     transaction.commit();
                 }
             }
@@ -1205,11 +1365,11 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements OCF
             }
                 
         } else {
-            Toast msg = Toast.makeText(this, R.string.remove_fail_msg, Toast.LENGTH_LONG);
+            Toast msg = Toast.makeText(this, R.string.remove_fail_msg, Toast.LENGTH_LONG); 
             msg.show();
             if (result.isSslRecoverableException()) {
                 mLastSslUntrustedServerResult = result;
-                showDialog(DIALOG_SSL_VALIDATOR);
+                showDialog(DIALOG_SSL_VALIDATOR); 
             }
         }
     }
@@ -1226,10 +1386,9 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements OCF
         OCFile renamedFile = operation.getFile();
         if (result.isSuccess()) {
             if (mDualPane) {
-                FileDetailFragment details = (FileDetailFragment) getSupportFragmentManager().findFragmentByTag(
-                        FileDetailFragment.FTAG);
-                if (details != null && renamedFile.equals(details.getDisplayedFile())) {
-                    details.updateFileDetails(renamedFile, AccountUtils.getCurrentOwnCloudAccount(this));
+                FileFragment details = (FileFragment) getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);
+                if (details != null && details instanceof FileDetailFragment && renamedFile.equals(details.getFile()) ) {
+                    ((FileDetailFragment) details).updateFileDetails(renamedFile, AccountUtils.getCurrentOwnCloudAccount(this));
                 }
             }
             if (mStorageManager.getFileById(renamedFile.getParentId()).equals(mCurrentDir)) {
@@ -1238,20 +1397,21 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements OCF
             
         } else {
             if (result.getCode().equals(ResultCode.INVALID_LOCAL_FILE_NAME)) {
-                Toast msg = Toast.makeText(this, R.string.rename_local_fail_msg, Toast.LENGTH_LONG);
+                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);
+                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);
+                    showDialog(DIALOG_SSL_VALIDATOR); 
                 }
             }
         }
     }
 
+
     private void onSynchronizeFileOperationFinish(SynchronizeFileOperation operation, RemoteOperationResult result) {
         dismissDialog(DIALOG_SHORT_WAIT);
         OCFile syncedFile = operation.getLocalFile();
@@ -1263,7 +1423,7 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements OCF
                 startActivity(i);
                 
             } else {
-                Toast msg = Toast.makeText(this, R.string.sync_file_fail_msg, Toast.LENGTH_LONG);
+                Toast msg = Toast.makeText(this, R.string.sync_file_fail_msg, Toast.LENGTH_LONG); 
                 msg.show();
             }
             
@@ -1273,7 +1433,7 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements OCF
                 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, R.string.sync_file_nothing_to_do_msg, Toast.LENGTH_LONG); 
                 msg.show();
             }
         }
@@ -1290,20 +1450,70 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements OCF
             fileListFragment.listDirectory();
         }*/
         if (mDualPane) {
-            FileDetailFragment details = (FileDetailFragment) getSupportFragmentManager().findFragmentByTag(
-                    FileDetailFragment.FTAG);
-            if (details != null && file.equals(details.getDisplayedFile())) {
+            FileFragment details = (FileFragment) getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);
+            if (details != null && details instanceof FileDetailFragment && file.equals(details.getFile()) ) {
                 if (downloading || uploading) {
-                    details.updateFileDetails(file, AccountUtils.getCurrentOwnCloudAccount(this));
+                    ((FileDetailFragment)details).updateFileDetails(file, AccountUtils.getCurrentOwnCloudAccount(this));
                 } else {
-                    details.updateFileDetails(downloading || uploading);
+                    ((FileDetailFragment)details).updateFileDetails(false, true);
                 }
             }
         }
     }
 
 
-    
+    @Override
+    public void showFragmentWithDetails(OCFile file) {
+        if (mDualPane) {
+            FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
+            transaction.replace(R.id.file_details_container, new FileDetailFragment(file, AccountUtils.getCurrentOwnCloudAccount(this)), FileDetailFragment.FTAG); 
+            transaction.commit();
+            
+        } else {
+            Intent showDetailsIntent = new Intent(this, FileDetailActivity.class);
+            showDetailsIntent.putExtra(FileDetailFragment.EXTRA_FILE, file);
+            showDetailsIntent.putExtra(FileDetailFragment.EXTRA_ACCOUNT, AccountUtils.getCurrentOwnCloudAccount(this));
+            showDetailsIntent.putExtra(FileDetailActivity.EXTRA_MODE, FileDetailActivity.MODE_DETAILS);
+            startActivity(showDetailsIntent);
+        }
+    }
 
+    public void onDismiss(EditNameDialog dialog) {
+        //dialog.dismiss();
+        if (dialog.getResult()) {
+            String newDirectoryName = dialog.getNewFilename().trim();
+            Log.d(TAG, "'create directory' dialog dismissed with new name " + newDirectoryName);
+            if (newDirectoryName.length() > 0) {
+                String path;
+                if (mCurrentDir == null) {
+                    // this is just a patch; we should ensure that mCurrentDir never is null
+                    if (!mStorageManager.fileExists(OCFile.PATH_SEPARATOR)) {
+                        OCFile file = new OCFile(OCFile.PATH_SEPARATOR);
+                        mStorageManager.saveFile(file);
+                    }
+                    mCurrentDir = mStorageManager.getFileByPath(OCFile.PATH_SEPARATOR);
+                }
+                path = FileDisplayActivity.this.mCurrentDir.getRemotePath();
+                
+                // Create directory
+                path += newDirectoryName + OCFile.PATH_SEPARATOR;
+                Thread thread = new Thread(new DirectoryCreator(path,  AccountUtils.getCurrentOwnCloudAccount(FileDisplayActivity.this), new Handler()));
+                thread.start();
+                
+                showDialog(DIALOG_SHORT_WAIT);
+            }
+        }
+    }
+
+    private void requestForDownload() {
+        Account account = AccountUtils.getCurrentOwnCloudAccount(this);
+        if (!mDownloaderBinder.isDownloading(account, mWaitingToPreview)) {
+            Intent i = new Intent(this, FileDownloader.class);
+            i.putExtra(FileDownloader.EXTRA_ACCOUNT, account);
+            i.putExtra(FileDownloader.EXTRA_FILE, mWaitingToPreview);
+            startService(i);
+        }
+    }
 
+    
 }
index 7b964a6..910802f 100644 (file)
@@ -75,6 +75,7 @@ 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;
 
index a6d61d1..d16b263 100644 (file)
@@ -347,8 +347,7 @@ public class UploadFilesActivity extends SherlockFragmentActivity implements
                 String[] args = {getString(R.string.app_name)};
                 ConfirmationDialogFragment dialog = ConfirmationDialogFragment.newInstance(R.string.upload_query_move_foreign_files, args, R.string.common_yes, -1, R.string.common_no);
                 dialog.setOnConfirmationListener(UploadFilesActivity.this);
-                mCurrentDialog = dialog;
-                mCurrentDialog.show(getSupportFragmentManager(), QUERY_TO_MOVE_DIALOG_TAG);
+                dialog.show(getSupportFragmentManager(), QUERY_TO_MOVE_DIALOG_TAG);
             }
         }
     }
@@ -363,16 +362,12 @@ public class UploadFilesActivity extends SherlockFragmentActivity implements
             setResult(RESULT_OK_AND_MOVE, data);
             finish();
         }
-        mCurrentDialog.dismiss();
-        mCurrentDialog = null;
     }
 
 
     @Override
     public void onNeutral(String callerTag) {
         Log.d(TAG, "Phantom neutral button in dialog was clicked; dialog tag is " + callerTag);
-        mCurrentDialog.dismiss();
-        mCurrentDialog = null;
     }
 
 
@@ -380,8 +375,6 @@ public class UploadFilesActivity extends SherlockFragmentActivity implements
     public void onCancel(String callerTag) {
         /// nothing to do; don't finish, let the user change the selection
         Log.d(TAG, "Negative button in dialog was clicked; dialog tag is " + callerTag);
-        mCurrentDialog.dismiss();
-        mCurrentDialog = null;
     }    
 
     
index ab0e0a7..73dc98f 100644 (file)
@@ -68,9 +68,10 @@ public class ChangelogDialog extends SherlockDialogFragment {
         
         /// build the dialog
         AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+        
         Dialog dialog = builder.setView(webview)
                                 .setIcon(R.drawable.icon)
-                                .setTitle(R.string.whats_new)
+                                //.setTitle(R.string.whats_new)
                                 .setPositiveButton(R.string.common_ok,
                                         new DialogInterface.OnClickListener() {
                                     @Override
index c779623..314b606 100644 (file)
@@ -61,7 +61,7 @@ public class IndeterminateProgressDialog extends SherlockDialogFragment {
         dialog.setIndeterminate(true);
         
         /// set message
-        int messageId = getArguments().getInt(ARG_MESSAGE_ID, R.string.text_placeholder);
+        int messageId = getArguments().getInt(ARG_MESSAGE_ID, R.string.placeholder_sentence);
         dialog.setMessage(getString(messageId));
         
         /// set cancellation behavior
index e527d31..7a59bd6 100644 (file)
@@ -36,6 +36,8 @@ public class ConfirmationDialogFragment extends SherlockDialogFragment {
     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;
     
     /**
@@ -90,6 +92,7 @@ public class ConfirmationDialogFragment extends SherlockDialogFragment {
                     new DialogInterface.OnClickListener() {
                         public void onClick(DialogInterface dialog, int whichButton) {
                             mListener.onConfirmation(getTag()); 
+                            dialog.dismiss();
                         }
                     });
         if (neuBtn != -1)
@@ -97,6 +100,7 @@ public class ConfirmationDialogFragment extends SherlockDialogFragment {
                     new DialogInterface.OnClickListener() {
                         public void onClick(DialogInterface dialog, int whichButton) {
                             mListener.onNeutral(getTag()); 
+                            dialog.dismiss();
                         }
                     });
         if (negBtn != -1)
@@ -105,6 +109,7 @@ public class ConfirmationDialogFragment extends SherlockDialogFragment {
                         @Override
                         public void onClick(DialogInterface dialog, int which) {
                             mListener.onCancel(getTag());
+                            dialog.dismiss();
                         }
                     });
       return builder.create();
index 2d46a55..80dc426 100644 (file)
@@ -19,6 +19,7 @@
 package com.owncloud.android.ui.fragment;\r
 \r
 import java.io.File;\r
+import java.lang.ref.WeakReference;\r
 import java.util.ArrayList;\r
 import java.util.List;\r
 \r
@@ -36,25 +37,17 @@ import org.json.JSONObject;
 \r
 import android.accounts.Account;\r
 import android.accounts.AccountManager;\r
-import android.annotation.SuppressLint;\r
 import android.app.Activity;\r
 import android.content.ActivityNotFoundException;\r
 import android.content.BroadcastReceiver;\r
 import android.content.Context;\r
 import android.content.Intent;\r
 import android.content.IntentFilter;\r
-import android.graphics.Bitmap;\r
-import android.graphics.BitmapFactory;\r
-import android.graphics.BitmapFactory.Options;\r
-import android.graphics.Point;\r
 import android.net.Uri;\r
-import android.os.AsyncTask;\r
 import android.os.Bundle;\r
 import android.os.Handler;\r
-import android.support.v4.app.DialogFragment;\r
 import android.support.v4.app.FragmentTransaction;\r
 import android.util.Log;\r
-import android.view.Display;\r
 import android.view.LayoutInflater;\r
 import android.view.View;\r
 import android.view.View.OnClickListener;\r
@@ -63,6 +56,7 @@ import android.webkit.MimeTypeMap;
 import android.widget.Button;\r
 import android.widget.CheckBox;\r
 import android.widget.ImageView;\r
+import android.widget.ProgressBar;\r
 import android.widget.TextView;\r
 import android.widget.Toast;\r
 \r
@@ -72,7 +66,6 @@ import com.owncloud.android.DisplayUtils;
 import com.owncloud.android.authenticator.AccountAuthenticator;\r
 import com.owncloud.android.datamodel.FileDataStorageManager;\r
 import com.owncloud.android.datamodel.OCFile;\r
-import com.owncloud.android.files.services.FileDownloader;\r
 import com.owncloud.android.files.services.FileObserverService;\r
 import com.owncloud.android.files.services.FileUploader;\r
 import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder;\r
@@ -88,12 +81,13 @@ import com.owncloud.android.operations.SynchronizeFileOperation;
 import com.owncloud.android.ui.activity.ConflictsResolveActivity;\r
 import com.owncloud.android.ui.activity.FileDetailActivity;\r
 import com.owncloud.android.ui.activity.FileDisplayActivity;\r
-import com.owncloud.android.ui.activity.TransferServiceGetter;\r
 import com.owncloud.android.ui.dialog.EditNameDialog;\r
 import com.owncloud.android.ui.dialog.EditNameDialog.EditNameDialogListener;\r
 import com.owncloud.android.utils.OwnCloudVersion;\r
 \r
 import com.owncloud.android.R;\r
+\r
+import eu.alefzero.webdav.OnDatatransferProgressListener;\r
 import eu.alefzero.webdav.WebdavClient;\r
 import eu.alefzero.webdav.WebdavUtils;\r
 \r
@@ -101,30 +95,30 @@ import eu.alefzero.webdav.WebdavUtils;
  * This Fragment is used to display the details about a file.\r
  * \r
  * @author Bartek Przybylski\r
- * \r
+ * @author David A. Velasco\r
  */\r
 public class FileDetailFragment extends SherlockFragment implements\r
-        OnClickListener, ConfirmationDialogFragment.ConfirmationDialogFragmentListener, OnRemoteOperationListener, EditNameDialogListener {\r
+        OnClickListener, \r
+        ConfirmationDialogFragment.ConfirmationDialogFragmentListener, OnRemoteOperationListener, EditNameDialogListener,\r
+        FileFragment {\r
 \r
     public static final String EXTRA_FILE = "FILE";\r
     public static final String EXTRA_ACCOUNT = "ACCOUNT";\r
 \r
-    private FileDetailFragment.ContainerActivity mContainerActivity;\r
+    private FileFragment.ContainerActivity mContainerActivity;\r
     \r
     private int mLayout;\r
     private View mView;\r
     private OCFile mFile;\r
     private Account mAccount;\r
     private FileDataStorageManager mStorageManager;\r
-    private ImageView mPreview;\r
     \r
-    private DownloadFinishReceiver mDownloadFinishReceiver;\r
     private UploadFinishReceiver mUploadFinishReceiver;\r
+    public ProgressListener mProgressListener;\r
     \r
     private Handler mHandler;\r
     private RemoteOperation mLastRemoteOperation;\r
-    private DialogFragment mCurrentDialog;\r
-\r
+    \r
     private static final String TAG = FileDetailFragment.class.getSimpleName();\r
     public static final String FTAG = "FileDetails"; \r
     public static final String FTAG_CONFIRMATION = "REMOVE_CONFIRMATION_FRAGMENT";\r
@@ -140,6 +134,7 @@ public class FileDetailFragment extends SherlockFragment implements
         mAccount = null;\r
         mStorageManager = null;\r
         mLayout = R.layout.file_details_empty;\r
+        mProgressListener = null;\r
     }\r
     \r
     \r
@@ -156,6 +151,7 @@ public class FileDetailFragment extends SherlockFragment implements
         mAccount = ocAccount;\r
         mStorageManager = null; // we need a context to init this; the container activity is not available yet at this moment \r
         mLayout = R.layout.file_details_empty;\r
+        mProgressListener = null;\r
     }\r
     \r
     \r
@@ -191,10 +187,11 @@ public class FileDetailFragment extends SherlockFragment implements
             mView.findViewById(R.id.fdOpenBtn).setOnClickListener(this);\r
             mView.findViewById(R.id.fdRemoveBtn).setOnClickListener(this);\r
             //mView.findViewById(R.id.fdShareBtn).setOnClickListener(this);\r
-            mPreview = (ImageView)mView.findViewById(R.id.fdPreview);\r
+            ProgressBar progressBar = (ProgressBar)mView.findViewById(R.id.fdProgressBar);\r
+            mProgressListener = new ProgressListener(progressBar);\r
         }\r
         \r
-        updateFileDetails(false);\r
+        updateFileDetails(false, false);\r
         return view;\r
     }\r
     \r
@@ -207,6 +204,7 @@ public class FileDetailFragment extends SherlockFragment implements
         super.onAttach(activity);\r
         try {\r
             mContainerActivity = (ContainerActivity) activity;\r
+            \r
         } catch (ClassCastException e) {\r
             throw new ClassCastException(activity.toString() + " must implement " + FileDetailFragment.ContainerActivity.class.getSimpleName());\r
         }\r
@@ -220,59 +218,57 @@ public class FileDetailFragment extends SherlockFragment implements
     public void onActivityCreated(Bundle savedInstanceState) {\r
         super.onActivityCreated(savedInstanceState);\r
         if (mAccount != null) {\r
-            mStorageManager = new FileDataStorageManager(mAccount, getActivity().getApplicationContext().getContentResolver());;\r
+            mStorageManager = new FileDataStorageManager(mAccount, getActivity().getApplicationContext().getContentResolver());\r
         }\r
     }\r
         \r
 \r
     @Override\r
     public void onSaveInstanceState(Bundle outState) {\r
-        Log.i(getClass().toString(), "onSaveInstanceState() start");\r
         super.onSaveInstanceState(outState);\r
         outState.putParcelable(FileDetailFragment.EXTRA_FILE, mFile);\r
         outState.putParcelable(FileDetailFragment.EXTRA_ACCOUNT, mAccount);\r
-        Log.i(getClass().toString(), "onSaveInstanceState() end");\r
     }\r
 \r
+    @Override\r
+    public void onStart() {\r
+        super.onStart();\r
+        listenForTransferProgress();\r
+    }\r
     \r
     @Override\r
     public void onResume() {\r
         super.onResume();\r
-        \r
-        mDownloadFinishReceiver = new DownloadFinishReceiver();\r
-        IntentFilter filter = new IntentFilter(\r
-                FileDownloader.DOWNLOAD_FINISH_MESSAGE);\r
-        getActivity().registerReceiver(mDownloadFinishReceiver, filter);\r
-        \r
         mUploadFinishReceiver = new UploadFinishReceiver();\r
-        filter = new IntentFilter(FileUploader.UPLOAD_FINISH_MESSAGE);\r
+        IntentFilter filter = new IntentFilter(FileUploader.UPLOAD_FINISH_MESSAGE);\r
         getActivity().registerReceiver(mUploadFinishReceiver, filter);\r
-        \r
-        mPreview = (ImageView)mView.findViewById(R.id.fdPreview);\r
+\r
     }\r
 \r
+\r
     @Override\r
     public void onPause() {\r
         super.onPause();\r
-        \r
-        getActivity().unregisterReceiver(mDownloadFinishReceiver);\r
-        mDownloadFinishReceiver = null;\r
-        \r
-        getActivity().unregisterReceiver(mUploadFinishReceiver);\r
-        mUploadFinishReceiver = null;\r
-        \r
-        if (mPreview != null) {\r
-            mPreview = null;\r
+        if (mUploadFinishReceiver != null) {\r
+            getActivity().unregisterReceiver(mUploadFinishReceiver);\r
+            mUploadFinishReceiver = null;\r
         }\r
     }\r
 \r
+    \r
+    @Override\r
+    public void onStop() {\r
+        super.onStop();\r
+        leaveTransferProgress();\r
+    }\r
+\r
+    \r
     @Override\r
     public View getView() {\r
         return super.getView() == null ? mView : super.getView();\r
     }\r
 \r
     \r
-    \r
     @Override\r
     public void onClick(View v) {\r
         switch (v.getId()) {\r
@@ -315,7 +311,6 @@ public class FileDetailFragment extends SherlockFragment implements
                     // update ui \r
                     boolean inDisplayActivity = getActivity() instanceof FileDisplayActivity;\r
                     getActivity().showDialog((inDisplayActivity)? FileDisplayActivity.DIALOG_SHORT_WAIT : FileDetailActivity.DIALOG_SHORT_WAIT);\r
-                    setButtonsForTransferring(); // disable button immediately, although the synchronization does not result in a file transference\r
                     \r
                 }\r
                 break;\r
@@ -335,7 +330,6 @@ public class FileDetailFragment extends SherlockFragment implements
                                    FileObserverService.CMD_DEL_OBSERVED_FILE));\r
                 intent.putExtra(FileObserverService.KEY_CMD_ARG_FILE, mFile);\r
                 intent.putExtra(FileObserverService.KEY_CMD_ARG_ACCOUNT, mAccount);\r
-                Log.e(TAG, "starting observer service");\r
                 getActivity().startService(intent);\r
                 \r
                 if (mFile.keepInSync()) {\r
@@ -356,54 +350,11 @@ public class FileDetailFragment extends SherlockFragment implements
                         mFile.isDown() ? R.string.confirmation_remove_local : -1,\r
                         R.string.common_cancel);\r
                 confDialog.setOnConfirmationListener(this);\r
-                mCurrentDialog = confDialog;\r
-                mCurrentDialog.show(getFragmentManager(), FTAG_CONFIRMATION);\r
+                confDialog.show(getFragmentManager(), FTAG_CONFIRMATION);\r
                 break;\r
             }\r
             case R.id.fdOpenBtn: {\r
-                String storagePath = mFile.getStoragePath();\r
-                String encodedStoragePath = WebdavUtils.encodePath(storagePath);\r
-                try {\r
-                    Intent i = new Intent(Intent.ACTION_VIEW);\r
-                    i.setDataAndType(Uri.parse("file://"+ encodedStoragePath), mFile.getMimetype());\r
-                    i.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);\r
-                    startActivity(i);\r
-                    \r
-                } catch (Throwable t) {\r
-                    Log.e(TAG, "Fail when trying to open with the mimeType provided from the ownCloud server: " + mFile.getMimetype());\r
-                    boolean toastIt = true; \r
-                    String mimeType = "";\r
-                    try {\r
-                        Intent i = new Intent(Intent.ACTION_VIEW);\r
-                        mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(storagePath.substring(storagePath.lastIndexOf('.') + 1));\r
-                        if (mimeType == null || !mimeType.equals(mFile.getMimetype())) {\r
-                            if (mimeType != null) {\r
-                                i.setDataAndType(Uri.parse("file://"+ encodedStoragePath), mimeType);\r
-                            } else {\r
-                                // desperate try\r
-                                i.setDataAndType(Uri.parse("file://"+ encodedStoragePath), "*/*");\r
-                            }\r
-                            i.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);\r
-                            startActivity(i);\r
-                            toastIt = false;\r
-                        }\r
-                        \r
-                    } catch (IndexOutOfBoundsException e) {\r
-                        Log.e(TAG, "Trying to find out MIME type of a file without extension: " + storagePath);\r
-                        \r
-                    } catch (ActivityNotFoundException e) {\r
-                        Log.e(TAG, "No activity found to handle: " + storagePath + " with MIME type " + mimeType + " obtained from extension");\r
-                        \r
-                    } catch (Throwable th) {\r
-                        Log.e(TAG, "Unexpected problem when opening: " + storagePath, th);\r
-                        \r
-                    } finally {\r
-                        if (toastIt) {\r
-                            Toast.makeText(getActivity(), "There is no application to handle file " + mFile.getFileName(), Toast.LENGTH_SHORT).show();\r
-                        }\r
-                    }\r
-                    \r
-                }\r
+                openFile();\r
                 break;\r
             }\r
             default:\r
@@ -417,6 +368,57 @@ public class FileDetailFragment extends SherlockFragment implements
     }\r
     \r
     \r
+    /**\r
+     * Opens mFile.\r
+     */\r
+    private void openFile() {\r
+        \r
+        String storagePath = mFile.getStoragePath();\r
+        String encodedStoragePath = WebdavUtils.encodePath(storagePath);\r
+        try {\r
+            Intent i = new Intent(Intent.ACTION_VIEW);\r
+            i.setDataAndType(Uri.parse("file://"+ encodedStoragePath), mFile.getMimetype());\r
+            i.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);\r
+            startActivity(i);\r
+            \r
+        } catch (Throwable t) {\r
+            Log.e(TAG, "Fail when trying to open with the mimeType provided from the ownCloud server: " + mFile.getMimetype());\r
+            boolean toastIt = true; \r
+            String mimeType = "";\r
+            try {\r
+                Intent i = new Intent(Intent.ACTION_VIEW);\r
+                mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(storagePath.substring(storagePath.lastIndexOf('.') + 1));\r
+                if (mimeType == null || !mimeType.equals(mFile.getMimetype())) {\r
+                    if (mimeType != null) {\r
+                        i.setDataAndType(Uri.parse("file://"+ encodedStoragePath), mimeType);\r
+                    } else {\r
+                        // desperate try\r
+                        i.setDataAndType(Uri.parse("file://"+ encodedStoragePath), "*/*");\r
+                    }\r
+                    i.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);\r
+                    startActivity(i);\r
+                    toastIt = false;\r
+                }\r
+                \r
+            } catch (IndexOutOfBoundsException e) {\r
+                Log.e(TAG, "Trying to find out MIME type of a file without extension: " + storagePath);\r
+                \r
+            } catch (ActivityNotFoundException e) {\r
+                Log.e(TAG, "No activity found to handle: " + storagePath + " with MIME type " + mimeType + " obtained from extension");\r
+                \r
+            } catch (Throwable th) {\r
+                Log.e(TAG, "Unexpected problem when opening: " + storagePath, th);\r
+                \r
+            } finally {\r
+                if (toastIt) {\r
+                    Toast.makeText(getActivity(), "There is no application to handle file " + mFile.getFileName(), Toast.LENGTH_SHORT).show();\r
+                }\r
+            }\r
+            \r
+        }\r
+    }\r
+\r
+\r
     @Override\r
     public void onConfirmation(String callerTag) {\r
         if (callerTag.equals(FTAG_CONFIRMATION)) {\r
@@ -431,8 +433,6 @@ public class FileDetailFragment extends SherlockFragment implements
                 getActivity().showDialog((inDisplayActivity)? FileDisplayActivity.DIALOG_SHORT_WAIT : FileDetailActivity.DIALOG_SHORT_WAIT);\r
             }\r
         }\r
-        mCurrentDialog.dismiss();\r
-        mCurrentDialog = null;\r
     }\r
     \r
     @Override\r
@@ -444,15 +444,11 @@ public class FileDetailFragment extends SherlockFragment implements
             mStorageManager.saveFile(mFile);\r
             updateFileDetails(mFile, mAccount);\r
         }\r
-        mCurrentDialog.dismiss();\r
-        mCurrentDialog = null;\r
     }\r
     \r
     @Override\r
     public void onCancel(String callerTag) {\r
         Log.d(TAG, "REMOVAL CANCELED");\r
-        mCurrentDialog.dismiss();\r
-        mCurrentDialog = null;\r
     }\r
     \r
     \r
@@ -467,10 +463,9 @@ public class FileDetailFragment extends SherlockFragment implements
 \r
     \r
     /**\r
-     * Can be used to get the file that is currently being displayed.\r
-     * @return The file on the screen.\r
+     * {@inheritDoc}\r
      */\r
-    public OCFile getDisplayedFile(){\r
+    public OCFile getFile(){\r
         return mFile;\r
     }\r
     \r
@@ -488,7 +483,7 @@ public class FileDetailFragment extends SherlockFragment implements
             mStorageManager = new FileDataStorageManager(ocAccount, getActivity().getApplicationContext().getContentResolver());\r
         }\r
         mAccount = ocAccount;\r
-        updateFileDetails(false);\r
+        updateFileDetails(false, false);\r
     }\r
     \r
 \r
@@ -497,14 +492,21 @@ public class FileDetailFragment extends SherlockFragment implements
      *\r
      * TODO Remove parameter when the transferring state of files is kept in database. \r
      * \r
+     * TODO REFACTORING! this method called 5 times before every time the fragment is shown! \r
+     * \r
      * @param transferring      Flag signaling if the file should be considered as downloading or uploading, \r
      *                          although {@link FileDownloaderBinder#isDownloading(Account, OCFile)}  and \r
      *                          {@link FileUploaderBinder#isUploading(Account, OCFile)} return false.\r
-     * \r
+     *                          \r
+     * @param refresh           If 'true', try to refresh the hold file from the database\r
      */\r
-    public void updateFileDetails(boolean transferring) {\r
+    public void updateFileDetails(boolean transferring, boolean refresh) {\r
 \r
-        if (mFile != null && mAccount != null && mLayout == R.layout.file_details_fragment) {\r
+        if (readyToShow()) {\r
+            \r
+            if (refresh && mStorageManager != null) {\r
+                mFile = mStorageManager.getFileByPath(mFile.getRemotePath());\r
+            }\r
             \r
             // set file details\r
             setFilename(mFile.getFileName());\r
@@ -527,11 +529,6 @@ public class FileDetailFragment extends SherlockFragment implements
                 setButtonsForTransferring();\r
                 \r
             } else if (mFile.isDown()) {\r
-                // Update preview\r
-                if (mFile.getMimetype().startsWith("image/")) {\r
-                    BitmapLoader bl = new BitmapLoader();\r
-                    bl.execute(new String[]{mFile.getStoragePath()});\r
-                }\r
                 \r
                 setButtonsForDown();\r
                 \r
@@ -545,6 +542,17 @@ public class FileDetailFragment extends SherlockFragment implements
     \r
     \r
     /**\r
+     * Checks if the fragment is ready to show details of a OCFile\r
+     *  \r
+     * @return  'True' when the fragment is ready to show details of a file\r
+     */\r
+    private boolean readyToShow() {\r
+        return (mFile != null && mAccount != null && mLayout == R.layout.file_details_fragment);        \r
+    }\r
+\r
+\r
+\r
+    /**\r
      * Updates the filename in view\r
      * @param filename to set\r
      */\r
@@ -619,9 +627,23 @@ public class FileDetailFragment extends SherlockFragment implements
             ((Button) getView().findViewById(R.id.fdRenameBtn)).setEnabled(false);\r
             ((Button) getView().findViewById(R.id.fdRemoveBtn)).setEnabled(false);\r
             getView().findViewById(R.id.fdKeepInSync).setEnabled(false);\r
+            \r
+            // show the progress bar for the transfer\r
+            ProgressBar progressBar = (ProgressBar)getView().findViewById(R.id.fdProgressBar);\r
+            progressBar.setVisibility(View.VISIBLE);\r
+            TextView progressText = (TextView)getView().findViewById(R.id.fdProgressText);\r
+            progressText.setVisibility(View.VISIBLE);\r
+            FileDownloaderBinder downloaderBinder = mContainerActivity.getFileDownloaderBinder();\r
+            FileUploaderBinder uploaderBinder = mContainerActivity.getFileUploaderBinder();\r
+            if (downloaderBinder != null && downloaderBinder.isDownloading(mAccount, mFile)) {\r
+                progressText.setText(R.string.downloader_download_in_progress_ticker);\r
+            } else if (uploaderBinder != null && uploaderBinder.isUploading(mAccount, mFile)) {\r
+                progressText.setText(R.string.uploader_upload_in_progress_ticker);\r
+            }\r
         }\r
     }\r
     \r
+\r
     /**\r
      * Enables or disables buttons for a file locally available \r
      */\r
@@ -634,6 +656,12 @@ public class FileDetailFragment extends SherlockFragment implements
             ((Button) getView().findViewById(R.id.fdRenameBtn)).setEnabled(true);\r
             ((Button) getView().findViewById(R.id.fdRemoveBtn)).setEnabled(true);\r
             getView().findViewById(R.id.fdKeepInSync).setEnabled(true);\r
+            \r
+            // hides the progress bar\r
+            ProgressBar progressBar = (ProgressBar)getView().findViewById(R.id.fdProgressBar);\r
+            progressBar.setVisibility(View.GONE);\r
+            TextView progressText = (TextView)getView().findViewById(R.id.fdProgressText);\r
+            progressText.setVisibility(View.GONE);\r
         }\r
     }\r
 \r
@@ -649,6 +677,12 @@ public class FileDetailFragment extends SherlockFragment implements
             ((Button) getView().findViewById(R.id.fdRenameBtn)).setEnabled(true);\r
             ((Button) getView().findViewById(R.id.fdRemoveBtn)).setEnabled(true);\r
             getView().findViewById(R.id.fdKeepInSync).setEnabled(true);\r
+            \r
+            // hides the progress bar\r
+            ProgressBar progressBar = (ProgressBar)getView().findViewById(R.id.fdProgressBar);\r
+            progressBar.setVisibility(View.GONE);\r
+            TextView progressText = (TextView)getView().findViewById(R.id.fdProgressText);\r
+            progressText.setVisibility(View.GONE);\r
         }\r
     }\r
     \r
@@ -674,53 +708,6 @@ public class FileDetailFragment extends SherlockFragment implements
     \r
     \r
     /**\r
-     * Interface to implement by any Activity that includes some instance of FileDetailFragment\r
-     * \r
-     * @author David A. Velasco\r
-     */\r
-    public interface ContainerActivity extends TransferServiceGetter {\r
-\r
-        /**\r
-         * Callback method invoked when the detail fragment wants to notice its container \r
-         * activity about a relevant state the file shown by the fragment.\r
-         * \r
-         * Added to notify to FileDisplayActivity about the need of refresh the files list. \r
-         * \r
-         * Currently called when:\r
-         *  - a download is started;\r
-         *  - a rename is completed;\r
-         *  - a deletion is completed;\r
-         *  - the 'inSync' flag is changed;\r
-         */\r
-        public void onFileStateChanged();\r
-        \r
-    }\r
-    \r
-\r
-    /**\r
-     * Once the file download has finished -> update view\r
-     * @author Bartek Przybylski\r
-     */\r
-    private class DownloadFinishReceiver extends BroadcastReceiver {\r
-        @Override\r
-        public void onReceive(Context context, Intent intent) {\r
-            String accountName = intent.getStringExtra(FileDownloader.ACCOUNT_NAME);\r
-\r
-            if (!isEmpty() && accountName.equals(mAccount.name)) {\r
-                boolean downloadWasFine = intent.getBooleanExtra(FileDownloader.EXTRA_DOWNLOAD_RESULT, false);\r
-                String downloadedRemotePath = intent.getStringExtra(FileDownloader.EXTRA_REMOTE_PATH);\r
-                if (mFile.getRemotePath().equals(downloadedRemotePath)) {\r
-                    if (downloadWasFine) {\r
-                        mFile = mStorageManager.getFileByPath(downloadedRemotePath);\r
-                    }\r
-                    updateFileDetails(false);    // it updates the buttons; must be called although !downloadWasFine\r
-                }\r
-            }\r
-        }\r
-    }\r
-    \r
-    \r
-    /**\r
      * Once the file upload has finished -> update view\r
      * \r
      * Being notified about the finish of an upload is necessary for the next sequence:\r
@@ -750,7 +737,7 @@ public class FileDetailFragment extends SherlockFragment implements
                         msg.show();\r
                     }\r
                     getSherlockActivity().removeStickyBroadcast(intent);    // not the best place to do this; a small refactorization of BroadcastReceivers should be done\r
-                    updateFileDetails(false);    // it updates the buttons; must be called although !uploadWasFine; interrupted uploads still leave an incomplete file in the server\r
+                    updateFileDetails(false, false);    // it updates the buttons; must be called although !uploadWasFine; interrupted uploads still leave an incomplete file in the server\r
                 }\r
             }\r
         }\r
@@ -877,80 +864,6 @@ public class FileDetailFragment extends SherlockFragment implements
     }\r
     \r
     \r
-    class BitmapLoader extends AsyncTask<String, Void, Bitmap> {\r
-        @SuppressLint({ "NewApi", "NewApi", "NewApi" }) // to avoid Lint errors since Android SDK r20\r
-               @Override\r
-        protected Bitmap doInBackground(String... params) {\r
-            Bitmap result = null;\r
-            if (params.length != 1) return result;\r
-            String storagePath = params[0];\r
-            try {\r
-\r
-                BitmapFactory.Options options = new Options();\r
-                options.inScaled = true;\r
-                options.inPurgeable = true;\r
-                options.inJustDecodeBounds = true;\r
-                if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.GINGERBREAD_MR1) {\r
-                    options.inPreferQualityOverSpeed = false;\r
-                }\r
-                if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) {\r
-                    options.inMutable = false;\r
-                }\r
-\r
-                result = BitmapFactory.decodeFile(storagePath, options);\r
-                options.inJustDecodeBounds = false;\r
-\r
-                int width = options.outWidth;\r
-                int height = options.outHeight;\r
-                int scale = 1;\r
-                if (width >= 2048 || height >= 2048) {\r
-                    scale = (int) Math.ceil((Math.ceil(Math.max(height, width) / 2048.)));\r
-                    options.inSampleSize = scale;\r
-                }\r
-                Display display = getActivity().getWindowManager().getDefaultDisplay();\r
-                Point size = new Point();\r
-                int screenwidth;\r
-                if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB_MR2) {\r
-                    display.getSize(size);\r
-                    screenwidth = size.x;\r
-                } else {\r
-                    screenwidth = display.getWidth();\r
-                }\r
-\r
-                Log.e("ASD", "W " + width + " SW " + screenwidth);\r
-\r
-                if (width > screenwidth) {\r
-                    scale = (int) Math.ceil((float)width / screenwidth);\r
-                    options.inSampleSize = scale;\r
-                }\r
-\r
-                result = BitmapFactory.decodeFile(storagePath, options);\r
-\r
-                Log.e("ASD", "W " + options.outWidth + " SW " + options.outHeight);\r
-\r
-            } catch (OutOfMemoryError e) {\r
-                result = null;\r
-                Log.e(TAG, "Out of memory occured for file with size " + storagePath);\r
-                \r
-            } catch (NoSuchFieldError e) {\r
-                result = null;\r
-                Log.e(TAG, "Error from access to unexisting field despite protection " + storagePath);\r
-                \r
-            } catch (Throwable t) {\r
-                result = null;\r
-                Log.e(TAG, "Unexpected error while creating image preview " + storagePath, t);\r
-            }\r
-            return result;\r
-        }\r
-        @Override\r
-        protected void onPostExecute(Bitmap result) {\r
-            if (result != null && mPreview != null) {\r
-                mPreview.setImageBitmap(result);\r
-            }\r
-        }\r
-        \r
-    }\r
-\r
     /**\r
      * {@inheritDoc}\r
      */\r
@@ -1044,6 +957,7 @@ public class FileDetailFragment extends SherlockFragment implements
             \r
         } else {\r
             if (operation.transferWasRequested()) {\r
+                setButtonsForTransferring();\r
                 mContainerActivity.onFileStateChanged();    // this is not working; FileDownloader won't do NOTHING at all until this method finishes, so \r
                                                             // checking the service to see if the file is downloading results in FALSE\r
             } else {\r
@@ -1058,5 +972,66 @@ public class FileDetailFragment extends SherlockFragment implements
             }\r
         }\r
     }\r
+    \r
+    \r
+    public void listenForTransferProgress() {\r
+        if (mProgressListener != null) {\r
+            if (mContainerActivity.getFileDownloaderBinder() != null) {\r
+                mContainerActivity.getFileDownloaderBinder().addDatatransferProgressListener(mProgressListener, mAccount, mFile);\r
+            }\r
+            if (mContainerActivity.getFileUploaderBinder() != null) {\r
+                mContainerActivity.getFileUploaderBinder().addDatatransferProgressListener(mProgressListener, mAccount, mFile);\r
+            }\r
+        }\r
+    }\r
+    \r
+    \r
+    public void leaveTransferProgress() {\r
+        if (mProgressListener != null) {\r
+            if (mContainerActivity.getFileDownloaderBinder() != null) {\r
+                mContainerActivity.getFileDownloaderBinder().removeDatatransferProgressListener(mProgressListener, mAccount, mFile);\r
+            }\r
+            if (mContainerActivity.getFileUploaderBinder() != null) {\r
+                mContainerActivity.getFileUploaderBinder().removeDatatransferProgressListener(mProgressListener, mAccount, mFile);\r
+            }\r
+        }\r
+    }\r
+\r
+\r
+    \r
+    /**\r
+     * Helper class responsible for updating the progress bar shown for file uploading or downloading  \r
+     * \r
+     * @author David A. Velasco\r
+     */\r
+    private class ProgressListener implements OnDatatransferProgressListener {\r
+        int mLastPercent = 0;\r
+        WeakReference<ProgressBar> mProgressBar = null;\r
+        \r
+        ProgressListener(ProgressBar progressBar) {\r
+            mProgressBar = new WeakReference<ProgressBar>(progressBar);\r
+        }\r
+        \r
+        @Override\r
+        public void onTransferProgress(long progressRate) {\r
+            // old method, nothing here\r
+        };\r
+\r
+        @Override\r
+        public void onTransferProgress(long progressRate, long totalTransferredSoFar, long totalToTransfer, String filename) {\r
+            int percent = (int)(100.0*((double)totalTransferredSoFar)/((double)totalToTransfer));\r
+            if (percent != mLastPercent) {\r
+                ProgressBar pb = mProgressBar.get();\r
+                if (pb != null) {\r
+                    pb.setProgress(percent);\r
+                    pb.postInvalidate();\r
+                }\r
+            }\r
+            mLastPercent = percent;\r
+        }\r
+\r
+    };\r
+    \r
+\r
 \r
 }\r
diff --git a/src/com/owncloud/android/ui/fragment/FileFragment.java b/src/com/owncloud/android/ui/fragment/FileFragment.java
new file mode 100644 (file)
index 0000000..c489c52
--- /dev/null
@@ -0,0 +1,74 @@
+/* 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 as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.ui.fragment;
+
+import android.content.Intent;
+import android.support.v4.app.Fragment;
+
+import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.ui.activity.TransferServiceGetter;
+
+/**
+ * Common methods for {@link Fragment}s containing {@link OCFile}s
+ * 
+ * @author David A. Velasco
+ *
+ */
+public interface FileFragment {
+    
+    /**
+     * Getter for the hold {@link OCFile}
+     * 
+     * @return The {@link OCFile} hold
+     */
+    public OCFile getFile();
+    
+    
+    /**
+     * Interface to implement by any Activity that includes some instance of FileFragment
+     * 
+     * @author David A. Velasco
+     */
+    public interface ContainerActivity extends TransferServiceGetter {
+
+        /**
+         * 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();
+
+        /**
+         * Request the parent activity to show the details of an {@link OCFile}.
+         * 
+         * @param file      File to show details
+         */
+        public void showFragmentWithDetails(OCFile file);
+        
+        
+    }
+    
+}
index 34e156d..90a06c0 100644 (file)
@@ -81,8 +81,6 @@ public class OCFileListFragment extends FragmentListView implements EditNameDial
     private Handler mHandler;
     private OCFile mTargetFile;
     
-    private DialogFragment mCurrentDialog;
-    
     /**
      * {@inheritDoc}
      */
@@ -163,7 +161,7 @@ public class OCFileListFragment extends FragmentListView implements EditNameDial
     public void onCreateContextMenu (ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
         super.onCreateContextMenu(menu, v, menuInfo);
         MenuInflater inflater = getActivity().getMenuInflater();
-        inflater.inflate(R.menu.file_context_menu, menu);
+        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>();    
@@ -172,46 +170,47 @@ public class OCFileListFragment extends FragmentListView implements EditNameDial
         MenuItem item = null;
         if (targetFile.isDirectory()) {
             // contextual menu for folders
-            toHide.add(R.id.open_file_item);
-            toHide.add(R.id.download_file_item);
-            toHide.add(R.id.cancel_download_item);
-            toHide.add(R.id.cancel_upload_item);
+            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_see_details);
             if (    mContainerActivity.getFileDownloaderBinder().isDownloading(AccountUtils.getCurrentOwnCloudAccount(getActivity()), targetFile) ||
                     mContainerActivity.getFileUploaderBinder().isUploading(AccountUtils.getCurrentOwnCloudAccount(getActivity()), targetFile)           ) {
-                toDisable.add(R.id.rename_file_item);
-                toDisable.add(R.id.remove_file_item);
+                toDisable.add(R.id.action_rename_file);
+                toDisable.add(R.id.action_remove_file);
                 
             }
             
         } else {
             // contextual menu for regular files
             if (targetFile.isDown()) {
-                toHide.add(R.id.cancel_download_item);
-                toHide.add(R.id.cancel_upload_item);
-                item = menu.findItem(R.id.download_file_item);
+                toHide.add(R.id.action_cancel_download);
+                toHide.add(R.id.action_cancel_upload);
+                item = menu.findItem(R.id.action_download_file);
                 if (item != null) {
                     item.setTitle(R.string.filedetails_sync_file);
                 }
             } else {
-                toHide.add(R.id.open_file_item);
+                toHide.add(R.id.action_open_file_with);
             }
             if ( mContainerActivity.getFileDownloaderBinder().isDownloading(AccountUtils.getCurrentOwnCloudAccount(getActivity()), targetFile)) {
-                toHide.add(R.id.download_file_item);
-                toHide.add(R.id.cancel_upload_item);
-                toDisable.add(R.id.open_file_item);
-                toDisable.add(R.id.rename_file_item);
-                toDisable.add(R.id.remove_file_item);
+                toHide.add(R.id.action_download_file);
+                toHide.add(R.id.action_cancel_upload);
+                toDisable.add(R.id.action_open_file_with);
+                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.download_file_item);
-                toHide.add(R.id.cancel_download_item);
-                toDisable.add(R.id.open_file_item);
-                toDisable.add(R.id.rename_file_item);
-                toDisable.add(R.id.remove_file_item);
+                toHide.add(R.id.action_download_file);
+                toHide.add(R.id.action_cancel_download);
+                toDisable.add(R.id.action_open_file_with);
+                toDisable.add(R.id.action_rename_file);
+                toDisable.add(R.id.action_remove_file);
                     
             } else {
-                toHide.add(R.id.cancel_download_item);
-                toHide.add(R.id.cancel_upload_item);
+                toHide.add(R.id.action_cancel_download);
+                toHide.add(R.id.action_cancel_upload);
             }
         }
 
@@ -240,12 +239,12 @@ public class OCFileListFragment extends FragmentListView implements EditNameDial
         AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();        
         mTargetFile = (OCFile) mAdapter.getItem(info.position);
         switch (item.getItemId()) {
-            case R.id.rename_file_item: {
+            case R.id.action_rename_file: {
                 EditNameDialog dialog = EditNameDialog.newInstance(getString(R.string.rename_dialog_title), mTargetFile.getFileName(), this);
                 dialog.show(getFragmentManager(), EditNameDialog.TAG);
                 return true;
             }
-            case R.id.remove_file_item: {
+            case R.id.action_remove_file: {
                 int messageStringId = R.string.confirmation_remove_alert;
                 int posBtnStringId = R.string.confirmation_remove_remote;
                 int neuBtnStringId = -1;
@@ -264,11 +263,10 @@ public class OCFileListFragment extends FragmentListView implements EditNameDial
                         neuBtnStringId,
                         R.string.common_cancel);
                 confDialog.setOnConfirmationListener(this);
-                mCurrentDialog = confDialog;
-                mCurrentDialog.show(getFragmentManager(), FileDetailFragment.FTAG_CONFIRMATION);
+                confDialog.show(getFragmentManager(), FileDetailFragment.FTAG_CONFIRMATION);
                 return true;
             }
-            case R.id.open_file_item: {
+            case R.id.action_open_file_with: {
                 String storagePath = mTargetFile.getStoragePath();
                 String encodedStoragePath = WebdavUtils.encodePath(storagePath);
                 try {
@@ -314,7 +312,7 @@ public class OCFileListFragment extends FragmentListView implements EditNameDial
                 }
                 return true;
             }
-            case R.id.download_file_item: {
+            case R.id.action_download_file: {
                 Account account = AccountUtils.getCurrentOwnCloudAccount(getSherlockActivity());
                 RemoteOperation operation = new SynchronizeFileOperation(mTargetFile, null, mContainerActivity.getStorageManager(), account, true, false, getSherlockActivity());
                 WebdavClient wc = OwnCloudClientUtils.createOwnCloudClient(account, getSherlockActivity().getApplicationContext());
@@ -322,7 +320,7 @@ public class OCFileListFragment extends FragmentListView implements EditNameDial
                 getSherlockActivity().showDialog(FileDisplayActivity.DIALOG_SHORT_WAIT);
                 return true;
             }
-            case R.id.cancel_download_item: {
+            case R.id.action_cancel_download: {
                 FileDownloaderBinder downloaderBinder = mContainerActivity.getFileDownloaderBinder();
                 Account account = AccountUtils.getCurrentOwnCloudAccount(getActivity());
                 if (downloaderBinder != null && downloaderBinder.isDownloading(account, mTargetFile)) {
@@ -332,7 +330,7 @@ public class OCFileListFragment extends FragmentListView implements EditNameDial
                 }
                 return true;
             }
-            case R.id.cancel_upload_item: {
+            case R.id.action_cancel_upload: {
                 FileUploaderBinder uploaderBinder = mContainerActivity.getFileUploaderBinder();
                 Account account = AccountUtils.getCurrentOwnCloudAccount(getActivity());
                 if (uploaderBinder != null && uploaderBinder.isUploading(account, mTargetFile)) {
@@ -342,6 +340,10 @@ public class OCFileListFragment extends FragmentListView implements EditNameDial
                 }
                 return true;
             }
+            case R.id.action_see_details: {
+                ((FileFragment.ContainerActivity)getActivity()).showFragmentWithDetails(mTargetFile);
+                return true;
+            }
             default:
                 return super.onContextItemSelected(item); 
         }
@@ -499,10 +501,6 @@ public class OCFileListFragment extends FragmentListView implements EditNameDial
                 
                 getActivity().showDialog(FileDisplayActivity.DIALOG_SHORT_WAIT);
             }
-            if (mCurrentDialog != null) {
-                mCurrentDialog.dismiss();
-                mCurrentDialog = null;
-            }
         }
     }
     
@@ -518,10 +516,6 @@ public class OCFileListFragment extends FragmentListView implements EditNameDial
             mTargetFile.setStoragePath(null);
             mContainerActivity.getStorageManager().saveFile(mTargetFile);
         }
-        if (mCurrentDialog != null) {
-            mCurrentDialog.dismiss();
-            mCurrentDialog = null;
-        }
         listDirectory();
         mContainerActivity.onTransferStateChanged(mTargetFile, false, false);
     }
@@ -529,10 +523,6 @@ public class OCFileListFragment extends FragmentListView implements EditNameDial
     @Override
     public void onCancel(String callerTag) {
         Log.d(TAG, "REMOVAL CANCELED");
-        if (mCurrentDialog != null) {
-            mCurrentDialog.dismiss();
-            mCurrentDialog = null;
-        }
     }
 
 
diff --git a/src/com/owncloud/android/ui/preview/FileDownloadFragment.java b/src/com/owncloud/android/ui/preview/FileDownloadFragment.java
new file mode 100644 (file)
index 0000000..2279ff0
--- /dev/null
@@ -0,0 +1,397 @@
+/* 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 as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+package com.owncloud.android.ui.preview;
+
+import java.lang.ref.WeakReference;
+
+import android.accounts.Account;
+import android.app.Activity;
+import android.os.Bundle;
+import android.support.v4.app.FragmentStatePagerAdapter;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+
+import com.actionbarsherlock.app.SherlockFragment;
+import com.owncloud.android.datamodel.FileDataStorageManager;
+import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder;
+import com.owncloud.android.ui.fragment.FileFragment;
+
+import com.owncloud.android.R;
+
+import eu.alefzero.webdav.OnDatatransferProgressListener;
+
+/**
+ * This Fragment is used to monitor the progress of a file downloading.
+ * 
+ * @author David A. Velasco
+ */
+public class FileDownloadFragment extends SherlockFragment implements OnClickListener, FileFragment {
+
+    public static final String EXTRA_FILE = "FILE";
+    public static final String EXTRA_ACCOUNT = "ACCOUNT";
+    private static final String EXTRA_ERROR = "ERROR";
+
+    private FileFragment.ContainerActivity mContainerActivity;
+    
+    private View mView;
+    private OCFile mFile;
+    private Account mAccount;
+    private FileDataStorageManager mStorageManager;
+    
+    public ProgressListener mProgressListener;
+    private boolean mListening;
+    
+    private static final String TAG = FileDownloadFragment.class.getSimpleName();
+    
+    private boolean mIgnoreFirstSavedState;
+    private boolean mError;
+    
+
+    /**
+     * Creates an empty details fragment.
+     * 
+     * It's necessary to keep a public constructor without parameters; the system uses it when tries to reinstantiate a fragment automatically. 
+     */
+    public FileDownloadFragment() {
+        mFile = null;
+        mAccount = null;
+        mStorageManager = null;
+        mProgressListener = null;
+        mListening = false;
+        mIgnoreFirstSavedState = false;
+        mError = false;
+    }
+    
+    
+    /**
+     * Creates a details fragment.
+     * 
+     * When 'fileToDetail' or 'ocAccount' are null, creates a dummy layout (to use when a file wasn't tapped before).
+     * 
+     * @param fileToDetail      An {@link OCFile} to show in the fragment
+     * @param ocAccount         An ownCloud account; needed to start downloads
+     * @param ignoreFirstSavedState     Flag to work around an unexpected behaviour of {@link FragmentStatePagerAdapter}; TODO better solution 
+     */
+    public FileDownloadFragment(OCFile fileToDetail, Account ocAccount, boolean ignoreFirstSavedState) {
+        mFile = fileToDetail;
+        mAccount = ocAccount;
+        mStorageManager = null; // we need a context to init this; the container activity is not available yet at this moment 
+        mProgressListener = null;
+        mListening = false;
+        mIgnoreFirstSavedState = ignoreFirstSavedState;
+        mError = false;
+    }
+    
+    
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+    }
+    
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState) {
+        super.onCreateView(inflater, container, savedInstanceState);
+        
+        if (savedInstanceState != null) {
+            if (!mIgnoreFirstSavedState) {
+                mFile = savedInstanceState.getParcelable(FileDownloadFragment.EXTRA_FILE);
+                mAccount = savedInstanceState.getParcelable(FileDownloadFragment.EXTRA_ACCOUNT);
+                mError = savedInstanceState.getBoolean(FileDownloadFragment.EXTRA_ERROR);
+            } else {
+                mIgnoreFirstSavedState = false;
+            }
+        }
+        
+        View view = null;
+        view = inflater.inflate(R.layout.file_download_fragment, container, false);
+        mView = view;
+        
+        ProgressBar progressBar = (ProgressBar)mView.findViewById(R.id.progressBar);
+        mProgressListener = new ProgressListener(progressBar);
+        
+        ((Button)mView.findViewById(R.id.cancelBtn)).setOnClickListener(this);
+        
+        if (mError) {
+            setButtonsForRemote();
+        } else {
+            setButtonsForTransferring();
+        }
+        
+        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 " + 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);
+        outState.putParcelable(FileDownloadFragment.EXTRA_FILE, mFile);
+        outState.putParcelable(FileDownloadFragment.EXTRA_ACCOUNT, mAccount);
+        outState.putBoolean(FileDownloadFragment.EXTRA_ERROR, mError);
+    }
+
+    @Override
+    public void onStart() {
+        super.onStart();
+        listenForTransferProgress();
+    }
+    
+    @Override
+    public void onResume() {
+        super.onResume();
+    }
+
+
+    @Override
+    public void onPause() {
+        super.onPause();
+    }
+
+    
+    @Override
+    public void onStop() {
+        super.onStop();
+        leaveTransferProgress();
+    }
+    
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+    }
+    
+    
+    @Override
+    public View getView() {
+        if (!mListening) {
+            listenForTransferProgress();
+        }
+        return super.getView() == null ? mView : super.getView();
+    }
+
+    
+    @Override
+    public void onClick(View v) {
+        switch (v.getId()) {
+            case R.id.cancelBtn: {
+                FileDownloaderBinder downloaderBinder = mContainerActivity.getFileDownloaderBinder();
+                if (downloaderBinder != null && downloaderBinder.isDownloading(mAccount, mFile)) {
+                    downloaderBinder.cancel(mAccount, mFile);
+                    getActivity().finish(); // :)
+                    /*
+                    leaveTransferProgress();
+                    if (mFile.isDown()) {
+                        setButtonsForDown();
+                    } else {
+                        setButtonsForRemote();
+                    }
+                    */
+                }
+                break;
+            }
+            default:
+                Log.e(TAG, "Incorrect view clicked!");
+        }
+    }
+
+    
+    /**
+     * {@inheritDoc}
+     */
+    public OCFile getFile(){
+        return mFile;
+    }
+    
+    
+    /**
+     * Updates the view depending upon the state of the downloading file.
+     * 
+     * @param   transferring    When true, the view must be updated assuming that the holded file is 
+     *                          downloading, no matter what the downloaderBinder says.
+     */
+    public void updateView(boolean transferring) {
+        // configure UI for depending upon local state of the file
+        FileDownloaderBinder downloaderBinder = (mContainerActivity == null) ? null : mContainerActivity.getFileDownloaderBinder();
+        if (transferring || (downloaderBinder != null && downloaderBinder.isDownloading(mAccount, mFile))) {
+            setButtonsForTransferring();
+            
+        } else if (mFile.isDown()) {
+            
+            setButtonsForDown();
+            
+        } else {
+            setButtonsForRemote();
+        }
+        getView().invalidate();
+        
+    }
+
+
+    /**
+     * Enables or disables buttons for a file being downloaded
+     */
+    private void setButtonsForTransferring() {
+        getView().findViewById(R.id.cancelBtn).setVisibility(View.VISIBLE);
+    
+        // show the progress bar for the transfer
+        getView().findViewById(R.id.progressBar).setVisibility(View.VISIBLE);
+        TextView progressText = (TextView)getView().findViewById(R.id.progressText);
+        progressText.setText(R.string.downloader_download_in_progress_ticker);
+        progressText.setVisibility(View.VISIBLE);
+                
+        // hides the error icon
+        getView().findViewById(R.id.errorText).setVisibility(View.GONE);
+        getView().findViewById(R.id.error_image).setVisibility(View.GONE);
+    }
+    
+
+    /**
+     * Enables or disables buttons for a file locally available 
+     */
+    private void setButtonsForDown() {
+        getView().findViewById(R.id.cancelBtn).setVisibility(View.GONE);
+    
+        // hides the progress bar
+        getView().findViewById(R.id.progressBar).setVisibility(View.GONE);
+        
+        // updates the text message
+        TextView progressText = (TextView)getView().findViewById(R.id.progressText);
+        progressText.setText(R.string.common_loading);
+        progressText.setVisibility(View.VISIBLE);
+        
+        // hides the error icon
+        getView().findViewById(R.id.errorText).setVisibility(View.GONE);
+        getView().findViewById(R.id.error_image).setVisibility(View.GONE);
+    }
+
+    
+    /**
+     * Enables or disables buttons for a file not locally available 
+     * 
+     * Currently, this is only used when a download was failed
+     */
+    private void setButtonsForRemote() {
+        getView().findViewById(R.id.cancelBtn).setVisibility(View.GONE);
+        
+        // hides the progress bar and message
+        getView().findViewById(R.id.progressBar).setVisibility(View.GONE);
+        getView().findViewById(R.id.progressText).setVisibility(View.GONE);
+
+        // shows the error icon and message
+        getView().findViewById(R.id.errorText).setVisibility(View.VISIBLE);
+        getView().findViewById(R.id.error_image).setVisibility(View.VISIBLE);
+    }
+    
+
+    public void listenForTransferProgress() {
+        if (mProgressListener != null && !mListening) {
+            if (mContainerActivity.getFileDownloaderBinder() != null) {
+                mContainerActivity.getFileDownloaderBinder().addDatatransferProgressListener(mProgressListener, mAccount, mFile);
+                mListening = true;
+                setButtonsForTransferring();
+            }
+        }
+    }
+    
+    
+    public void leaveTransferProgress() {
+        if (mProgressListener != null) {
+            if (mContainerActivity.getFileDownloaderBinder() != null) {
+                mContainerActivity.getFileDownloaderBinder().removeDatatransferProgressListener(mProgressListener, mAccount, mFile);
+                mListening = false;
+            }
+        }
+    }
+
+    
+    /**
+     * Helper class responsible for updating the progress bar shown for file uploading or downloading  
+     * 
+     * @author David A. Velasco
+     */
+    private class ProgressListener implements OnDatatransferProgressListener {
+        int mLastPercent = 0;
+        WeakReference<ProgressBar> mProgressBar = null;
+        
+        ProgressListener(ProgressBar progressBar) {
+            mProgressBar = new WeakReference<ProgressBar>(progressBar);
+        }
+        
+        @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) {
+                ProgressBar pb = mProgressBar.get();
+                if (pb != null) {
+                    pb.setProgress(percent);
+                    pb.postInvalidate();
+                }
+            }
+            mLastPercent = percent;
+        }
+
+    }
+
+
+    public void setError(boolean error) {
+        mError = error;
+    };
+    
+
+
+}
diff --git a/src/com/owncloud/android/ui/preview/PreviewImageActivity.java b/src/com/owncloud/android/ui/preview/PreviewImageActivity.java
new file mode 100644 (file)
index 0000000..74ce769
--- /dev/null
@@ -0,0 +1,449 @@
+/* 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 as published by
+ *   the Free Software Foundation, either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+package com.owncloud.android.ui.preview;
+
+import org.apache.commons.httpclient.methods.PostMethod;
+
+import android.accounts.Account;
+import android.app.Dialog;
+import android.app.ProgressDialog;
+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.os.Bundle;
+import android.os.IBinder;
+import android.support.v4.app.Fragment;
+import android.support.v4.view.ViewPager;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.View.OnTouchListener;
+
+import com.actionbarsherlock.app.ActionBar;
+import com.actionbarsherlock.app.SherlockFragmentActivity;
+import com.actionbarsherlock.view.MenuItem;
+import com.actionbarsherlock.view.Window;
+import com.owncloud.android.datamodel.DataStorageManager;
+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.FileDownloader.FileDownloaderBinder;
+import com.owncloud.android.files.services.FileUploader;
+import com.owncloud.android.files.services.FileUploader.FileUploaderBinder;
+import com.owncloud.android.ui.activity.FileDetailActivity;
+import com.owncloud.android.ui.fragment.FileDetailFragment;
+import com.owncloud.android.ui.fragment.FileFragment;
+
+import com.owncloud.android.AccountUtils;
+import com.owncloud.android.R;
+
+/**
+ *  Used as an utility to preview image files contained in an ownCloud account.
+ *  
+ *  @author David A. Velasco
+ */
+public class PreviewImageActivity extends SherlockFragmentActivity implements FileFragment.ContainerActivity, ViewPager.OnPageChangeListener, OnTouchListener {
+    
+    public static final int DIALOG_SHORT_WAIT = 0;
+
+    public static final String TAG = PreviewImageActivity.class.getSimpleName();
+    
+    public static final String KEY_WAITING_TO_PREVIEW = "WAITING_TO_PREVIEW";
+    private static final String KEY_WAITING_FOR_BINDER = "WAITING_FOR_BINDER";
+    
+    private OCFile mFile;
+    private OCFile mParentFolder;  
+    private Account mAccount;
+    private DataStorageManager mStorageManager;
+    
+    private ViewPager 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;
+    
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        mFile = getIntent().getParcelableExtra(FileDetailFragment.EXTRA_FILE);
+        mAccount = getIntent().getParcelableExtra(FileDetailFragment.EXTRA_ACCOUNT);
+        if (mFile == null) {
+            throw new IllegalStateException("Instanced with a NULL OCFile");
+        }
+        if (mAccount == null) {
+            throw new IllegalStateException("Instanced with a NULL ownCloud Account");
+        }
+        if (!mFile.isImage()) {
+            throw new IllegalArgumentException("Non-image file passed as argument");
+        }
+        requestWindowFeature(Window.FEATURE_ACTION_BAR_OVERLAY);
+        setContentView(R.layout.preview_image_activity);
+    
+        ActionBar actionBar = getSupportActionBar();
+        actionBar.setDisplayHomeAsUpEnabled(true);
+        actionBar.setTitle(mFile.getFileName());
+        actionBar.hide();
+        
+        mFullScreen = true;
+        
+        mStorageManager = new FileDataStorageManager(mAccount, getContentResolver());
+        mParentFolder = mStorageManager.getFileById(mFile.getParentId());
+        if (mParentFolder == null) {
+            // should not be necessary
+            mParentFolder = mStorageManager.getFileByPath(OCFile.PATH_SEPARATOR);
+        }
+
+        if (savedInstanceState != null) {
+            mRequestWaitingForBinder = savedInstanceState.getBoolean(KEY_WAITING_FOR_BINDER);
+        } else {
+            mRequestWaitingForBinder = false;
+        }
+        
+        createViewPager();
+
+    }
+
+    private void createViewPager() {
+        mPreviewImagePagerAdapter = new PreviewImagePagerAdapter(getSupportFragmentManager(), mParentFolder, mAccount, mStorageManager);
+        mViewPager = (ViewPager) findViewById(R.id.fragmentPager);
+        int position = mPreviewImagePagerAdapter.getFilePosition(mFile);
+        position = (position >= 0) ? position : 0;
+        mViewPager.setAdapter(mPreviewImagePagerAdapter); 
+        mViewPager.setOnPageChangeListener(this);
+        mViewPager.setCurrentItem(position);
+        if (position == 0 && !mFile.isDown()) {
+            // this is necessary because mViewPager.setCurrentItem(0) just after setting the adapter does not result in a call to #onPageSelected(0) 
+            mRequestWaitingForBinder = true;
+        }
+    }
+    
+    
+    @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
+    protected void onSaveInstanceState(Bundle outState) {
+        super.onSaveInstanceState(outState);
+        outState.putBoolean(KEY_WAITING_FOR_BINDER, mRequestWaitingForBinder);    
+    }
+
+
+    /** Defines callbacks for service binding, passed to bindService() */
+    private class PreviewImageServiceConnection implements ServiceConnection {
+
+        @Override
+        public void onServiceConnected(ComponentName component, IBinder service) {
+                
+            if (component.equals(new ComponentName(PreviewImageActivity.this, FileDownloader.class))) {
+                mDownloaderBinder = (FileDownloaderBinder) service;
+                if (mRequestWaitingForBinder) {
+                    mRequestWaitingForBinder = false;
+                    Log.d(TAG, "Simulating reselection of current page after connection of download binder");
+                    onPageSelected(mViewPager.getCurrentItem());
+                }
+                    
+            } else if (component.equals(new ComponentName(PreviewImageActivity.this, FileUploader.class))) {
+                Log.d(TAG, "Upload service connected");
+                mUploaderBinder = (FileUploaderBinder) service;
+            } else {
+                return;
+            }
+            
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName component) {
+            if (component.equals(new ComponentName(PreviewImageActivity.this, FileDownloader.class))) {
+                Log.d(TAG, "Download service suddenly disconnected");
+                mDownloaderBinder = null;
+            } else if (component.equals(new ComponentName(PreviewImageActivity.this, FileUploader.class))) {
+                Log.d(TAG, "Upload service suddenly disconnected");
+                mUploaderBinder = null;
+            }
+        }
+    };    
+    
+    
+    @Override
+    public void onStop() {
+        super.onStop();
+        if (mDownloadConnection != null) {
+            unbindService(mDownloadConnection);
+            mDownloadConnection = null;
+        }
+        if (mUploadConnection != null) {
+            unbindService(mUploadConnection);
+            mUploadConnection = null;
+        }
+    }
+    
+    
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+    }
+    
+    
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        boolean returnValue = false;
+        
+        switch(item.getItemId()){
+        case android.R.id.home:
+            backToDisplayActivity();
+            returnValue = true;
+            break;
+        default:
+               returnValue = super.onOptionsItemSelected(item);
+        }
+        
+        return returnValue;
+    }
+
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+        //Log.e(TAG, "ACTIVITY, ONRESUME");
+        mDownloadFinishReceiver = new DownloadFinishReceiver();
+        IntentFilter filter = new IntentFilter(FileDownloader.DOWNLOAD_FINISH_MESSAGE);
+        filter.addAction(FileDownloader.DOWNLOAD_ADDED_MESSAGE);
+        registerReceiver(mDownloadFinishReceiver, filter);
+    }
+
+    @Override
+    protected void onPostResume() {
+        //Log.e(TAG, "ACTIVITY, ONPOSTRESUME");
+        super.onPostResume();
+    }
+    
+    @Override
+    public void onPause() {
+        super.onPause();
+        unregisterReceiver(mDownloadFinishReceiver);
+        mDownloadFinishReceiver = null;
+    }
+    
+
+    private void backToDisplayActivity() {
+        /*
+        Intent intent = new Intent(this, FileDisplayActivity.class);
+        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+        intent.putExtra(FileDetailFragment.EXTRA_FILE, mFile);
+        intent.putExtra(FileDetailFragment.EXTRA_ACCOUNT, mAccount);
+        startActivity(intent);
+        */
+        finish();
+    }
+    
+    
+    @Override
+    protected Dialog onCreateDialog(int id) {
+        Dialog dialog = null;
+        switch (id) {
+        case DIALOG_SHORT_WAIT: {
+            ProgressDialog working_dialog = new ProgressDialog(this);
+            working_dialog.setMessage(getResources().getString(
+                    R.string.wait_a_moment));
+            working_dialog.setIndeterminate(true);
+            working_dialog.setCancelable(false);
+            dialog = working_dialog;
+            break;
+        }
+        default:
+            dialog = null;
+        }
+        return dialog;
+    }
+    
+    
+    /**
+     * {@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 showFragmentWithDetails(OCFile file) {
+        Intent showDetailsIntent = new Intent(this, FileDetailActivity.class);
+        showDetailsIntent.putExtra(FileDetailFragment.EXTRA_FILE, file);
+        showDetailsIntent.putExtra(FileDetailFragment.EXTRA_ACCOUNT, AccountUtils.getCurrentOwnCloudAccount(this));
+        showDetailsIntent.putExtra(FileDetailActivity.EXTRA_MODE, FileDetailActivity.MODE_DETAILS);
+        startActivity(showDetailsIntent);
+        int pos = mPreviewImagePagerAdapter.getFilePosition(file);
+        file = mPreviewImagePagerAdapter.getFileAt(pos);
+        
+    }
+
+    
+    private void requestForDownload(OCFile file) {
+        if (mDownloaderBinder == null) {
+            Log.d(TAG, "requestForDownload called without binder to download service");
+            
+        } else if (!mDownloaderBinder.isDownloading(mAccount, file)) {
+            Intent i = new Intent(this, FileDownloader.class);
+            i.putExtra(FileDownloader.EXTRA_ACCOUNT, mAccount);
+            i.putExtra(FileDownloader.EXTRA_FILE, file);
+            startService(i);
+        }
+    }
+
+    /**
+     * This method will be invoked when a new page becomes selected. Animation is not necessarily complete.
+     * 
+     *  @param  Position        Position index of the new selected page
+     */
+    @Override
+    public void onPageSelected(int position) {
+        if (mDownloaderBinder == null) {
+            mRequestWaitingForBinder = true;
+            
+        } else {
+            OCFile currentFile = mPreviewImagePagerAdapter.getFileAt(position); 
+            getSupportActionBar().setTitle(currentFile.getFileName());
+            if (!currentFile.isDown()) {
+                if (!mPreviewImagePagerAdapter.pendingErrorAt(position)) {
+                    requestForDownload(currentFile);
+                }
+            }
+        }
+    }
+    
+    /**
+     * Called when the scroll state changes. Useful for discovering when the user begins dragging, 
+     * when the pager is automatically settling to the current page, or when it is fully stopped/idle.
+     * 
+     * @param   State       The new scroll state (SCROLL_STATE_IDLE, _DRAGGING, _SETTLING
+     */
+    @Override
+    public void onPageScrollStateChanged(int state) {
+    }
+
+    /**
+     * This method will be invoked when the current page is scrolled, either as part of a programmatically 
+     * initiated smooth scroll or a user initiated touch scroll.
+     * 
+     * @param   position                Position index of the first page currently being displayed. 
+     *                                  Page position+1 will be visible if positionOffset is nonzero.
+     *                                  
+     * @param   positionOffset          Value from [0, 1) indicating the offset from the page at position.
+     * @param   positionOffsetPixels    Value in pixels indicating the offset from position. 
+     */
+    @Override
+    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
+    }
+    
+
+    /**
+     * Class waiting for broadcast events from the {@link FielDownloader} service.
+     * 
+     * Updates the UI when a download is started or finished, provided that it is relevant for the
+     * folder displayed in the gallery.
+     */
+    private class DownloadFinishReceiver extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            String accountName = intent.getStringExtra(FileDownloader.ACCOUNT_NAME);
+            String downloadedRemotePath = intent.getStringExtra(FileDownloader.EXTRA_REMOTE_PATH);
+            if (mAccount.name.equals(accountName) && 
+                    downloadedRemotePath != null) {
+
+                OCFile file = mStorageManager.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();
+                
+                if (position >= 0 && intent.getAction().equals(FileDownloader.DOWNLOAD_FINISH_MESSAGE)) {
+                    if (downloadWasFine) {
+                        mPreviewImagePagerAdapter.updateFile(position, file);   
+                        
+                    } else {
+                        mPreviewImagePagerAdapter.updateWithDownloadError(position);
+                    }
+                    mPreviewImagePagerAdapter.notifyDataSetChanged();   // will trigger the creation of new fragments
+                    
+                } else {
+                    Log.d(TAG, "Download finished, but the fragment is offscreen");
+                }
+                
+            }
+            removeStickyBroadcast(intent);
+        }
+
+    }
+
+
+    @Override
+    public boolean onTouch(View v, MotionEvent event) {
+        if (event.getAction() == MotionEvent.ACTION_UP) {
+           toggleFullScreen();
+        }
+        return true;
+    }
+
+    
+    private void toggleFullScreen() {
+        ActionBar actionBar = getSupportActionBar();
+        if (mFullScreen) {
+            actionBar.show();
+            
+        } else {
+            actionBar.hide();
+            
+        }
+        mFullScreen = !mFullScreen;
+    }
+    
+    
+}
diff --git a/src/com/owncloud/android/ui/preview/PreviewImageFragment.java b/src/com/owncloud/android/ui/preview/PreviewImageFragment.java
new file mode 100644 (file)
index 0000000..77cbc49
--- /dev/null
@@ -0,0 +1,686 @@
+/* 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 as published by
+ *   the Free Software Foundation, either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+package com.owncloud.android.ui.preview;
+
+import java.io.File;
+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.util.Log;
+import android.view.Display;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.OnTouchListener;
+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.app.SherlockFragment;
+import com.actionbarsherlock.view.Menu;
+import com.actionbarsherlock.view.MenuInflater;
+import com.actionbarsherlock.view.MenuItem;
+import com.owncloud.android.datamodel.FileDataStorageManager;
+import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.network.OwnCloudClientUtils;
+import com.owncloud.android.operations.OnRemoteOperationListener;
+import com.owncloud.android.operations.RemoteOperation;
+import com.owncloud.android.operations.RemoteOperationResult;
+import com.owncloud.android.operations.RemoveFileOperation;
+import com.owncloud.android.ui.fragment.ConfirmationDialogFragment;
+import com.owncloud.android.ui.fragment.FileFragment;
+
+import com.owncloud.android.R;
+import eu.alefzero.webdav.WebdavClient;
+import eu.alefzero.webdav.WebdavUtils;
+
+
+/**
+ * This fragment shows a preview of a downloaded image.
+ * 
+ * Trying to get an instance with NULL {@link OCFile} or ownCloud {@link Account} values will produce an {@link IllegalStateException}.
+ * 
+ * If the {@link OCFile} passed is not downloaded, an {@link IllegalStateException} is generated on instantiation too.
+ * 
+ * @author David A. Velasco
+ */
+public class PreviewImageFragment extends SherlockFragment implements   FileFragment, 
+                                                                        OnRemoteOperationListener, 
+                                                                        ConfirmationDialogFragment.ConfirmationDialogFragmentListener {
+    public static final String EXTRA_FILE = "FILE";
+    public static final String EXTRA_ACCOUNT = "ACCOUNT";
+
+    private View mView;
+    private OCFile mFile;
+    private Account mAccount;
+    private FileDataStorageManager mStorageManager;
+    private ImageView 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;
+
+    
+    /**
+     * Creates a fragment to preview an image.
+     * 
+     * When 'imageFile' or 'ocAccount' are null
+     * 
+     * @param imageFile                 An {@link OCFile} to preview as an image in the fragment
+     * @param ocAccount                 An ownCloud account; needed to start downloads
+     * @param ignoreFirstSavedState     Flag to work around an unexpected behaviour of {@link FragmentStatePagerAdapter}; TODO better solution 
+     */
+    public PreviewImageFragment(OCFile fileToDetail, Account ocAccount, boolean ignoreFirstSavedState) {
+        mFile = fileToDetail;
+        mAccount = ocAccount;
+        mStorageManager = null; // we need a context to init this; the container activity is not available yet at this moment
+        mIgnoreFirstSavedState = ignoreFirstSavedState;
+    }
+    
+    
+    /**
+     *  Creates an empty fragment for image previews.
+     * 
+     *  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 
+     */
+    public PreviewImageFragment() {
+        mFile = null;
+        mAccount = null;
+        mStorageManager = null;
+        mIgnoreFirstSavedState = false;
+    }
+    
+    
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        mHandler = new Handler();
+        setHasOptionsMenu(true);
+    }
+    
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+            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.setVisibility(View.GONE);
+        mView.setOnTouchListener((OnTouchListener)getActivity());   // WATCH OUT THAT CAST
+        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) {
+                mFile = savedInstanceState.getParcelable(PreviewImageFragment.EXTRA_FILE);
+                mAccount = savedInstanceState.getParcelable(PreviewImageFragment.EXTRA_ACCOUNT);
+            } else {
+                mIgnoreFirstSavedState = false;
+            }
+        }
+        if (mFile == null) {
+            throw new IllegalStateException("Instanced with a NULL OCFile");
+        }
+        if (mAccount == null) {
+            throw new IllegalStateException("Instanced with a NULL ownCloud Account");
+        }
+        if (!mFile.isDown()) {
+            throw new IllegalStateException("There is no local file to preview");
+        }
+    }
+        
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void onSaveInstanceState(Bundle outState) {
+        super.onSaveInstanceState(outState);
+        outState.putParcelable(PreviewImageFragment.EXTRA_FILE, mFile);
+        outState.putParcelable(PreviewImageFragment.EXTRA_ACCOUNT, mAccount);
+    }
+    
+
+    @Override
+    public void onStart() {
+        super.onStart();
+        if (mFile != null) {
+           BitmapLoader bl = new BitmapLoader(mImageView, mMessageView, mProgressWheel);
+           bl.execute(new String[]{mFile.getStoragePath()});
+        }
+    }
+    
+    
+    /**
+     * {@inheritDoc}
+     */
+    @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>();    
+        
+        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);
+            }
+        }
+        
+    }
+
+    
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        switch (item.getItemId()) {
+            case R.id.action_open_file_with: {
+                openFile();
+                return true;
+            }
+            case R.id.action_remove_file: {
+                removeFile();
+                return true;
+            }
+            case R.id.action_see_details: {
+                seeDetails();
+                return true;
+            }
+            
+            default:
+                return false;
+        }
+    }
+
+    
+    private void seeDetails() {
+        ((FileFragment.ContainerActivity)getActivity()).showFragmentWithDetails(mFile);        
+    }
+
+
+    @Override
+    public void onResume() {
+        super.onResume();
+        //Log.e(TAG, "FRAGMENT, ONRESUME");
+        /*
+        mDownloadFinishReceiver = new DownloadFinishReceiver();
+        IntentFilter filter = new IntentFilter(
+                FileDownloader.DOWNLOAD_FINISH_MESSAGE);
+        getActivity().registerReceiver(mDownloadFinishReceiver, filter);
+        
+        mUploadFinishReceiver = new UploadFinishReceiver();
+        filter = new IntentFilter(FileUploader.UPLOAD_FINISH_MESSAGE);
+        getActivity().registerReceiver(mUploadFinishReceiver, filter);
+        */
+
+    }
+
+
+    @Override
+    public void onPause() {
+        super.onPause();
+        /*
+        if (mVideoPreview.getVisibility() == View.VISIBLE) {
+            mSavedPlaybackPosition = mVideoPreview.getCurrentPosition();
+        }*/
+        /*
+        getActivity().unregisterReceiver(mDownloadFinishReceiver);
+        mDownloadFinishReceiver = null;
+        
+        getActivity().unregisterReceiver(mUploadFinishReceiver);
+        mUploadFinishReceiver = null;
+        */
+    }
+
+
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        if (mBitmap != null) {
+            mBitmap.recycle();
+        }
+    }
+
+    
+    /**
+     * 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() {
+        String storagePath = mFile.getStoragePath();
+        String encodedStoragePath = WebdavUtils.encodePath(storagePath);
+        try {
+            Intent i = new Intent(Intent.ACTION_VIEW);
+            i.setDataAndType(Uri.parse("file://"+ encodedStoragePath), mFile.getMimetype());
+            i.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+            startActivity(i);
+            
+        } catch (Throwable t) {
+            Log.e(TAG, "Fail when trying to open with the mimeType provided from the ownCloud server: " + mFile.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(mFile.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.e(TAG, "Trying to find out MIME type of a file without extension: " + storagePath);
+                
+            } catch (ActivityNotFoundException e) {
+                Log.e(TAG, "No activity found to handle: " + storagePath + " with MIME type " + mimeType + " obtained from extension");
+                
+            } catch (Throwable th) {
+                Log.e(TAG, "Unexpected problem when opening: " + storagePath, th);
+                
+            } finally {
+                if (toastIt) {
+                    Toast.makeText(getActivity(), "There is no application to handle file " + mFile.getFileName(), Toast.LENGTH_SHORT).show();
+                }
+            }
+            
+        }
+        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[]{mFile.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(mFile.getFileId()) != null) {   // check that the file is still there;
+            mLastRemoteOperation = new RemoveFileOperation( mFile,      // TODO we need to review the interface with RemoteOperations, and use OCFile IDs instead of OCFile objects as parameters
+                                                            true, 
+                                                            mStorageManager);
+            WebdavClient wc = OwnCloudClientUtils.createOwnCloudClient(mAccount, getSherlockActivity().getApplicationContext());
+            mLastRemoteOperation.execute(wc, this, mHandler);
+            
+            getActivity().showDialog(PreviewImageActivity.DIALOG_SHORT_WAIT);
+        }
+    }
+    
+    
+    /**
+     * Removes the file from local storage
+     */
+    @Override
+    public void onNeutral(String callerTag) {
+        // TODO this code should be made in a secondary thread,
+        if (mFile.isDown()) {   // checks it is still there
+            File f = new File(mFile.getStoragePath());
+            f.delete();
+            mFile.setStoragePath(null);
+            mStorageManager.saveFile(mFile);
+            finish();
+        }
+    }
+    
+    /**
+     * User cancelled the removal action.
+     */
+    @Override
+    public void onCancel(String callerTag) {
+        // nothing to do here
+    }
+    
+
+    /**
+     * {@inheritDoc}
+     */
+    public OCFile getFile(){
+        return mFile;
+    }
+    
+    /*
+    /**
+     * Use this method to signal this Activity that it shall update its view.
+     * 
+     * @param file : An {@link OCFile}
+     *-/
+    public void updateFileDetails(OCFile file, Account ocAccount) {
+        mFile = file;
+        if (ocAccount != null && ( 
+                mStorageManager == null || 
+                (mAccount != null && !mAccount.equals(ocAccount))
+           )) {
+            mStorageManager = new FileDataStorageManager(ocAccount, getActivity().getApplicationContext().getContentResolver());
+        }
+        mAccount = ocAccount;
+        updateFileDetails(false);
+    }
+    */
+    
+
+    private class BitmapLoader extends AsyncTask<String, Void, Bitmap> {
+
+        /**
+         * Weak reference to the target {@link ImageView} where the bitmap will be loaded into.
+         * 
+         * 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;
+
+        /**
+         * Weak reference to the target {@link TextView} where error messages will be written.
+         * 
+         * Using a weak reference will avoid memory leaks if the target ImageView is retired from memory before the load finishes.
+         */
+        private final WeakReference<TextView> mMessageViewRef;
+
+        
+        /**
+         * Weak reference to the target {@link Progressbar} shown while the load is in progress.
+         * 
+         * Using a weak reference will avoid memory leaks if the target ImageView is retired from memory before the load finishes.
+         */
+        private final WeakReference<ProgressBar> mProgressWheelRef;
+
+        
+        /**
+         * Error message to show when a load fails 
+         */
+        private int mErrorMessageId;
+        
+        
+        /**
+         * Constructor.
+         * 
+         * @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);
+            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
+        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;
+
+                // really load the bitmap
+                options.inJustDecodeBounds = false; // the next decodeFile call will be real
+                result = BitmapFactory.decodeFile(storagePath, options);
+                //Log.d(TAG, "Image loaded - width: " + options.outWidth + ", loaded height: " + options.outHeight);
+
+                if (result == null) {
+                    mErrorMessageId = R.string.preview_image_error_unknown_format;
+                    Log.e(TAG, "File could not be loaded as a bitmap: " + storagePath);
+                }
+                
+            } catch (OutOfMemoryError e) {
+                mErrorMessageId = R.string.preview_image_error_unknown_format;
+                Log.e(TAG, "Out of memory occured for file " + storagePath, e);
+                    
+            } catch (NoSuchFieldError e) {
+                mErrorMessageId = R.string.common_error_unknown;
+                Log.e(TAG, "Error from access to unexisting field despite protection; file " + storagePath, e);
+                    
+            } catch (Throwable t) {
+                mErrorMessageId = R.string.common_error_unknown;
+                Log.e(TAG, "Unexpected error loading " + mFile.getStoragePath(), t);
+                
+            }
+            return result;
+        }
+        
+        @Override
+        protected void onPostExecute(Bitmap result) {
+            hideProgressWheel();
+            if (result != null) {
+                showLoadedImage(result);
+            } else {
+                showErrorMessage();
+            }
+        }
+        
+        private void showLoadedImage(Bitmap result) {
+            if (mImageViewRef != null) {
+                final ImageView imageView = mImageViewRef.get();
+                if (imageView != null) {
+                    imageView.setImageBitmap(result);
+                    imageView.setVisibility(View.VISIBLE);
+                    mBitmap  = result;
+                } // else , silently finish, the fragment was destroyed
+            }
+            if (mMessageViewRef != null) {
+                final TextView messageView = mMessageViewRef.get();
+                if (messageView != null) {
+                    messageView.setVisibility(View.GONE);
+                } // else , silently finish, the fragment was destroyed
+            }
+        }
+        
+        private void showErrorMessage() {
+            if (mImageViewRef != null) {
+                final ImageView imageView = mImageViewRef.get();
+                if (imageView != null) {
+                    // shows the default error icon
+                    imageView.setVisibility(View.VISIBLE);
+                } // else , silently finish, the fragment was destroyed
+            }
+            if (mMessageViewRef != null) {
+                final TextView messageView = mMessageViewRef.get();
+                if (messageView != null) {
+                    messageView.setText(mErrorMessageId);
+                    messageView.setVisibility(View.VISIBLE);
+                } // else , silently finish, the fragment was destroyed
+            }
+        }
+        
+        private void hideProgressWheel() {
+            if (mProgressWheelRef != null) {
+                final ProgressBar progressWheel = mProgressWheelRef.get();
+                if (progressWheel != null) {
+                    progressWheel.setVisibility(View.GONE);
+                }
+            }
+        }
+        
+    }
+
+    /**
+     * Helper method to test if an {@link OCFile} can be passed to a {@link PreviewImageFragment} to be previewed.
+     * 
+     * @param file      File to test if can be previewed.
+     * @return          'True' if the file can be handled by the fragment.
+     */
+    public static boolean canBePreviewed(OCFile file) {
+        return (file != null && file.isImage());
+    }
+
+    
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationResult result) {
+        if (operation.equals(mLastRemoteOperation) && operation instanceof RemoveFileOperation) {
+            onRemoveFileOperationFinish((RemoveFileOperation)operation, result);
+        }
+    }
+    
+    private void onRemoveFileOperationFinish(RemoveFileOperation operation, RemoteOperationResult result) {
+        getActivity().dismissDialog(PreviewImageActivity.DIALOG_SHORT_WAIT);
+        
+        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
+            }
+        }
+    }
+
+    /**
+     * Finishes the preview
+     */
+    private void finish() {
+        Activity container = getActivity();
+        container.finish();
+    }
+    
+    
+}
diff --git a/src/com/owncloud/android/ui/preview/PreviewImagePagerAdapter.java b/src/com/owncloud/android/ui/preview/PreviewImagePagerAdapter.java
new file mode 100644 (file)
index 0000000..54ed582
--- /dev/null
@@ -0,0 +1,353 @@
+/* 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 as published by
+ *   the Free Software Foundation, either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+package com.owncloud.android.ui.preview;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.Vector;
+
+import android.accounts.Account;
+import android.os.Bundle;
+import android.os.Parcelable;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentManager;
+import android.support.v4.app.FragmentStatePagerAdapter;
+import android.support.v4.app.FragmentTransaction;
+import android.support.v4.view.PagerAdapter;
+import android.support.v4.view.ViewPager;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.owncloud.android.datamodel.DataStorageManager;
+import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.ui.fragment.FileFragment;
+
+/**
+ * Adapter class that provides Fragment instances  
+ * 
+ * @author David A. Velasco
+ */
+//public class PreviewImagePagerAdapter extends PagerAdapter {
+public class PreviewImagePagerAdapter extends FragmentStatePagerAdapter {
+    
+    private static final String TAG = PreviewImagePagerAdapter.class.getSimpleName();
+            
+    private Vector<OCFile> mImageFiles;
+    private Account mAccount;
+    private Set<Object> mObsoleteFragments;
+    private Set<Integer> mObsoletePositions;
+    private Set<Integer> mDownloadErrors;
+    private DataStorageManager mStorageManager;
+    
+    private Map<Integer, FileFragment> mCachedFragments;
+
+    /*
+    private final FragmentManager mFragmentManager;
+    private FragmentTransaction mCurTransaction = null;
+    private ArrayList<Fragment.SavedState> mSavedState = new ArrayList<Fragment.SavedState>();
+    private ArrayList<Fragment> mFragments = new ArrayList<Fragment>();
+    private Fragment mCurrentPrimaryItem = null;
+    */
+
+    /**
+     * Constructor.
+     * 
+     * @param fragmentManager   {@link FragmentManager} instance that will handle the {@link Fragment}s provided by the adapter. 
+     * @param parentFolder      Folder where images will be searched for.
+     * @param storageManager    Bridge to database.
+     */
+    public PreviewImagePagerAdapter(FragmentManager fragmentManager, OCFile parentFolder, Account account, DataStorageManager storageManager) {
+        super(fragmentManager);
+        
+        if (fragmentManager == null) {
+            throw new IllegalArgumentException("NULL FragmentManager instance");
+        }
+        if (parentFolder == null) {
+            throw new IllegalArgumentException("NULL parent folder");
+        } 
+        if (storageManager == null) {
+            throw new IllegalArgumentException("NULL storage manager");
+        }
+
+        mAccount = account;
+        mStorageManager = storageManager;
+        mImageFiles = mStorageManager.getDirectoryImages(parentFolder); 
+        mObsoleteFragments = new HashSet<Object>();
+        mObsoletePositions = new HashSet<Integer>();
+        mDownloadErrors = new HashSet<Integer>();
+        //mFragmentManager = fragmentManager;
+        mCachedFragments = new HashMap<Integer, FileFragment>();
+    }
+
+    
+    /**
+     * Returns the image files handled by the adapter.
+     * 
+     * @return  A vector with the image files handled by the adapter.
+     */
+    protected OCFile getFileAt(int position) {
+        return mImageFiles.get(position);
+    }
+
+    
+    public Fragment getItem(int i) {
+        OCFile file = mImageFiles.get(i);
+        Fragment fragment = null;
+        if (file.isDown()) {
+            fragment = new PreviewImageFragment(file, mAccount, mObsoletePositions.contains(Integer.valueOf(i)));
+            
+        } else if (mDownloadErrors.contains(Integer.valueOf(i))) {
+            fragment = new FileDownloadFragment(file, mAccount, true);
+            ((FileDownloadFragment)fragment).setError(true);
+            mDownloadErrors.remove(Integer.valueOf(i));
+            
+        } else {
+            fragment = new FileDownloadFragment(file, mAccount, mObsoletePositions.contains(Integer.valueOf(i)));
+        }
+        mObsoletePositions.remove(Integer.valueOf(i));
+        return fragment;
+    }
+
+    public int getFilePosition(OCFile file) {
+        return mImageFiles.indexOf(file);
+    }
+    
+    @Override
+    public int getCount() {
+        return mImageFiles.size();
+    }
+
+    @Override
+    public CharSequence getPageTitle(int position) {
+        return mImageFiles.get(position).getFileName();
+    }
+
+    
+    public void updateFile(int position, OCFile file) {
+        FileFragment fragmentToUpdate = mCachedFragments.get(Integer.valueOf(position));
+        if (fragmentToUpdate != null) {
+            mObsoleteFragments.add(fragmentToUpdate);
+        }
+        mObsoletePositions.add(Integer.valueOf(position));
+        mImageFiles.set(position, file);
+    }
+    
+    
+    public void updateWithDownloadError(int position) {
+        FileFragment fragmentToUpdate = mCachedFragments.get(Integer.valueOf(position));
+        if (fragmentToUpdate != null) {
+            mObsoleteFragments.add(fragmentToUpdate);
+        }
+        mDownloadErrors.add(Integer.valueOf(position));
+    }
+    
+    public void clearErrorAt(int position) {
+        FileFragment fragmentToUpdate = mCachedFragments.get(Integer.valueOf(position));
+        if (fragmentToUpdate != null) {
+            mObsoleteFragments.add(fragmentToUpdate);
+        }
+        mDownloadErrors.remove(Integer.valueOf(position));
+    }
+    
+    
+    @Override
+    public int getItemPosition(Object object) {
+        if (mObsoleteFragments.contains(object)) {
+            mObsoleteFragments.remove(object);
+            return POSITION_NONE;
+        }
+        return super.getItemPosition(object);
+    }
+
+
+    @Override
+    public Object instantiateItem(ViewGroup container, int position) {
+        Object fragment = super.instantiateItem(container, position);
+        mCachedFragments.put(Integer.valueOf(position), (FileFragment)fragment);
+        return fragment;
+    }
+    
+    @Override
+    public void destroyItem(ViewGroup container, int position, Object object) {
+       mCachedFragments.remove(Integer.valueOf(position));
+       super.destroyItem(container, position, object);
+    }
+
+
+    public boolean pendingErrorAt(int position) {
+        return mDownloadErrors.contains(Integer.valueOf(position));
+    }
+
+
+    
+    /* -*
+     * Called when a change in the shown pages is going to start being made.
+     * 
+     * @param   container   The containing View which is displaying this adapter's page views.
+     *- /
+    @Override
+    public void startUpdate(ViewGroup container) {
+        Log.e(TAG, "** startUpdate");
+    }
+
+    @Override
+    public Object instantiateItem(ViewGroup container, int position) {
+        Log.e(TAG, "** instantiateItem " + position);
+        
+        if (mFragments.size() > position) {
+            Fragment fragment = mFragments.get(position);
+            if (fragment != null) {
+                Log.e(TAG, "** \t returning cached item");
+                return fragment;
+            }
+        }
+
+        if (mCurTransaction == null) {
+            mCurTransaction = mFragmentManager.beginTransaction();
+        }
+
+        Fragment fragment = getItem(position);
+        if (mSavedState.size() > position) {
+            Fragment.SavedState savedState = mSavedState.get(position);
+            if (savedState != null) {
+                // TODO WATCH OUT:
+                // * The Fragment must currently be attached to the FragmentManager.
+                // * A new Fragment created using this saved state must be the same class type as the Fragment it was created from.
+                // * The saved state can not contain dependencies on other fragments -- that is it can't use putFragment(Bundle, String, Fragment) 
+                //   to store a fragment reference                 
+                fragment.setInitialSavedState(savedState);
+            }
+        }
+        while (mFragments.size() <= position) {
+            mFragments.add(null);
+        }
+        fragment.setMenuVisibility(false);
+        mFragments.set(position, fragment);
+        //Log.e(TAG, "** \t adding fragment at position " + position + ", containerId " + container.getId());
+        mCurTransaction.add(container.getId(), fragment);
+
+        return fragment;
+    }
+
+    @Override
+    public void destroyItem(ViewGroup container, int position, Object object) {
+        Log.e(TAG, "** destroyItem " + position);
+        Fragment fragment = (Fragment)object;
+        
+        if (mCurTransaction == null) {
+            mCurTransaction = mFragmentManager.beginTransaction();
+        }
+        Log.e(TAG, "** \t removing fragment at position " + position);
+        while (mSavedState.size() <= position) {
+            mSavedState.add(null);
+        }
+        mSavedState.set(position, mFragmentManager.saveFragmentInstanceState(fragment));
+        mFragments.set(position, null);
+
+        mCurTransaction.remove(fragment);
+    }
+
+    @Override
+    public void setPrimaryItem(ViewGroup container, int position, Object object) {
+        Fragment fragment = (Fragment)object;
+        if (fragment != mCurrentPrimaryItem) {
+            if (mCurrentPrimaryItem != null) {
+                mCurrentPrimaryItem.setMenuVisibility(false);
+            }
+            if (fragment != null) {
+                fragment.setMenuVisibility(true);
+            }
+            mCurrentPrimaryItem = fragment;
+        }
+    }
+
+    @Override
+    public void finishUpdate(ViewGroup container) {
+        Log.e(TAG, "** finishUpdate (start)");
+        if (mCurTransaction != null) {
+            mCurTransaction.commitAllowingStateLoss();
+            mCurTransaction = null;
+            mFragmentManager.executePendingTransactions();
+        }
+        Log.e(TAG, "** finishUpdate (end)");
+    }
+
+    @Override
+    public boolean isViewFromObject(View view, Object object) {
+        return ((Fragment)object).getView() == view;
+    }
+
+    @Override
+    public Parcelable saveState() {
+        Bundle state = null;
+        if (mSavedState.size() > 0) {
+            state = new Bundle();
+            Fragment.SavedState[] savedStates = new Fragment.SavedState[mSavedState.size()];
+            mSavedState.toArray(savedStates);
+            state.putParcelableArray("states", savedStates);
+        }
+        for (int i=0; i<mFragments.size(); i++) {
+            Fragment fragment = mFragments.get(i);
+            if (fragment != null) {
+                if (state == null) {
+                    state = new Bundle();
+                }
+                String key = "f" + i;
+                mFragmentManager.putFragment(state, key, fragment);
+            }
+        }
+        return state;
+    }
+
+    @Override
+    public void restoreState(Parcelable state, ClassLoader loader) {
+        if (state != null) {
+            Bundle bundle = (Bundle)state;
+            bundle.setClassLoader(loader);
+            Parcelable[] states = bundle.getParcelableArray("states");
+            mSavedState.clear();
+            mFragments.clear();
+            if (states != null) {
+                for (int i=0; i<states.length; i++) {
+                    mSavedState.add((Fragment.SavedState)states[i]);
+                }
+            }
+            Iterable<String> keys = bundle.keySet();
+            for (String key: keys) {
+                if (key.startsWith("f")) {
+                    int index = Integer.parseInt(key.substring(1));
+                    Fragment f = mFragmentManager.getFragment(bundle, key);
+                    if (f != null) {
+                        while (mFragments.size() <= index) {
+                            mFragments.add(null);
+                        }
+                        f.setMenuVisibility(false);
+                        mFragments.set(index, f);
+                    } else {
+                        Log.w(TAG, "Bad fragment at key " + key);
+                    }
+                }
+            }
+        }
+    }
+    */
+}
diff --git a/src/com/owncloud/android/ui/preview/PreviewMediaFragment.java b/src/com/owncloud/android/ui/preview/PreviewMediaFragment.java
new file mode 100644 (file)
index 0000000..35afe15
--- /dev/null
@@ -0,0 +1,756 @@
+/* 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 as published by
+ *   the Free Software Foundation, either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+package 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;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.media.MediaPlayer;
+import android.media.MediaPlayer.OnCompletionListener;
+import android.media.MediaPlayer.OnErrorListener;
+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.support.v4.app.FragmentTransaction;
+import android.util.Log;
+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;
+
+import com.actionbarsherlock.app.SherlockFragment;
+import com.actionbarsherlock.view.Menu;
+import com.actionbarsherlock.view.MenuInflater;
+import com.actionbarsherlock.view.MenuItem;
+import com.owncloud.android.datamodel.FileDataStorageManager;
+import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.media.MediaControlView;
+import com.owncloud.android.media.MediaService;
+import com.owncloud.android.media.MediaServiceBinder;
+import com.owncloud.android.network.OwnCloudClientUtils;
+import com.owncloud.android.operations.OnRemoteOperationListener;
+import com.owncloud.android.operations.RemoteOperation;
+import com.owncloud.android.operations.RemoteOperationResult;
+import com.owncloud.android.operations.RemoveFileOperation;
+import com.owncloud.android.ui.activity.FileDetailActivity;
+import com.owncloud.android.ui.activity.FileDisplayActivity;
+import com.owncloud.android.ui.fragment.ConfirmationDialogFragment;
+import com.owncloud.android.ui.fragment.FileDetailFragment;
+import com.owncloud.android.ui.fragment.FileFragment;
+
+import com.owncloud.android.R;
+import eu.alefzero.webdav.WebdavClient;
+import eu.alefzero.webdav.WebdavUtils;
+
+/**
+ * This fragment shows a preview of a downloaded media file (audio or video).
+ * 
+ * Trying to get an instance with NULL {@link OCFile} or ownCloud {@link Account} values will produce an {@link IllegalStateException}.
+ * 
+ * By now, if the {@link OCFile} passed is not downloaded, an {@link IllegalStateException} is generated on instantiation too.
+ * 
+ * @author David A. Velasco
+ */
+public class PreviewMediaFragment extends SherlockFragment implements
+        OnTouchListener , FileFragment,  
+        ConfirmationDialogFragment.ConfirmationDialogFragmentListener, OnRemoteOperationListener  {
+
+    public static final String EXTRA_FILE = "FILE";
+    public static final String EXTRA_ACCOUNT = "ACCOUNT";
+    private static final String EXTRA_PLAY_POSITION = "PLAY_POSITION";
+    private static final String EXTRA_PLAYING = "PLAYING";
+
+    private View mView;
+    private OCFile mFile;
+    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;
+    private VideoHelper mVideoHelper;
+    private boolean mAutoplay;
+    
+    private static final String TAG = PreviewMediaFragment.class.getSimpleName();
+
+    
+    /**
+     * Creates a fragment to preview a file.
+     * 
+     * When 'fileToDetail' or 'ocAccount' are null
+     * 
+     * @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) {
+        mFile = fileToDetail;
+        mAccount = ocAccount;
+        mSavedPlaybackPosition = 0;
+        mStorageManager = null; // we need a context to init this; the container activity is not available yet at this moment 
+        mAutoplay = true;
+    }
+    
+    
+    /**
+     *  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).
+     * 
+     *  DO NOT CALL IT: an {@link OCFile} and {@link Account} must be provided for a successful construction 
+     */
+    public PreviewMediaFragment() {
+        mFile = null;
+        mAccount = null;
+        mSavedPlaybackPosition = 0;
+        mStorageManager = null;
+        mAutoplay = true;
+    }
+    
+    
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        mHandler = new Handler();
+        setHasOptionsMenu(true);
+    }
+    
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState) {
+        super.onCreateView(inflater, container, savedInstanceState);
+        
+        mView = inflater.inflate(R.layout.file_preview, container, false);
+        
+        mImagePreview = (ImageView)mView.findViewById(R.id.image_preview);
+        mVideoPreview = (VideoView)mView.findViewById(R.id.video_preview);
+        mVideoPreview.setOnTouchListener(this);
+        
+        mMediaController = (MediaControlView)mView.findViewById(R.id.media_controller);
+        
+        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) {
+            mFile = savedInstanceState.getParcelable(PreviewMediaFragment.EXTRA_FILE);
+            mAccount = savedInstanceState.getParcelable(PreviewMediaFragment.EXTRA_ACCOUNT);
+            mSavedPlaybackPosition = savedInstanceState.getInt(PreviewMediaFragment.EXTRA_PLAY_POSITION);
+            mAutoplay = savedInstanceState.getBoolean(PreviewMediaFragment.EXTRA_PLAYING);
+            
+        }
+        if (mFile == null) {
+            throw new IllegalStateException("Instanced with a NULL OCFile");
+        }
+        if (mAccount == null) {
+            throw new IllegalStateException("Instanced with a NULL ownCloud Account");
+        }
+        if (!mFile.isDown()) {
+            throw new IllegalStateException("There is no local file to preview");
+        }
+        if (mFile.isVideo()) {
+            mVideoPreview.setVisibility(View.VISIBLE);
+            mImagePreview.setVisibility(View.GONE);
+            prepareVideo();
+            
+        } else {
+            mVideoPreview.setVisibility(View.GONE);
+            mImagePreview.setVisibility(View.VISIBLE);
+        }
+        
+    }
+        
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void onSaveInstanceState(Bundle outState) {
+        super.onSaveInstanceState(outState);
+        outState.putParcelable(PreviewMediaFragment.EXTRA_FILE, mFile);
+        outState.putParcelable(PreviewMediaFragment.EXTRA_ACCOUNT, mAccount);
+        
+        if (mFile.isVideo()) {
+            mSavedPlaybackPosition = mVideoPreview.getCurrentPosition();
+            mAutoplay = mVideoPreview.isPlaying();
+            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());
+        }
+    }
+    
+
+    @Override
+    public void onStart() {
+        super.onStart();
+
+        if (mFile != null) {
+           if (mFile.isAudio()) {
+               bindMediaService();
+               
+           } else if (mFile.isVideo()) {
+               stopAudio();
+               playVideo(); 
+           }
+        }
+    }
+    
+    
+    private void stopAudio() {
+        Intent i = new Intent(getSherlockActivity(), MediaService.class);
+        i.setAction(MediaService.ACTION_STOP_ALL);
+        getSherlockActivity().startService(i);
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @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>();    
+        
+        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);
+            }
+        }
+        
+    }
+
+    
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        switch (item.getItemId()) {
+            case R.id.action_open_file_with: {
+                openFile();
+                return true;
+            }
+            case R.id.action_remove_file: {
+                removeFile();
+                return true;
+            }
+            case R.id.action_see_details: {
+                seeDetails();
+                return true;
+            }
+            
+            default:
+                return false;
+        }
+    }
+
+    
+    private void seeDetails() {
+        stopPreview(false);
+        ((FileFragment.ContainerActivity)getActivity()).showFragmentWithDetails(mFile);        
+    }
+
+
+    private void prepareVideo() {
+        // create helper to get more control on the playback
+        mVideoHelper = new VideoHelper();
+        mVideoPreview.setOnPreparedListener(mVideoHelper);
+        mVideoPreview.setOnCompletionListener(mVideoHelper);
+        mVideoPreview.setOnErrorListener(mVideoHelper);
+    }
+    
+    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(mFile.getStoragePath()); 
+    }
+    
+
+    private class VideoHelper implements OnCompletionListener, OnPreparedListener, OnErrorListener {
+        
+        /** 
+         * Called when the file is ready to be played.
+         * 
+         * Just starts the playback.
+         * 
+         * @param   mp    {@link MediaPlayer} instance performing the playback.
+         */
+        @Override
+        public void onPrepared(MediaPlayer vp) {
+            Log.e(TAG, "onPrepared");
+            mVideoPreview.seekTo(mSavedPlaybackPosition);
+            if (mAutoplay) { 
+                mVideoPreview.start();
+            }
+            mMediaController.setEnabled(true);
+            mMediaController.updatePausePlay();
+        }
+        
+        
+        /**
+         * Called when the file is finished playing.
+         *  
+         * Finishes the activity.
+         * 
+         * @param   mp    {@link MediaPlayer} instance performing the playback.
+         */
+        @Override
+        public void onCompletion(MediaPlayer  mp) {
+            Log.e(TAG, "completed");
+            if (mp != null) {
+                mVideoPreview.seekTo(0);
+                // next lines are necessary to work around undesired video loops
+                if (Build.VERSION.SDK_INT == Build.VERSION_CODES.GINGERBREAD) {
+                    mVideoPreview.pause();   
+                    
+                } else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.GINGERBREAD_MR1) {
+                    // mVideePreview.pause() is not enough
+                    
+                    mMediaController.setEnabled(false);
+                    mVideoPreview.stopPlayback();
+                    mAutoplay = false;
+                    mSavedPlaybackPosition = 0;
+                    mVideoPreview.setVideoPath(mFile.getStoragePath());
+                }
+            } // else : called from onError()
+            mMediaController.updatePausePlay();
+        }
+        
+        
+        /**
+         * Called when an error in playback occurs.
+         * 
+         * @param   mp      {@link MediaPlayer} instance performing the playback.
+         * @param   what    Type of error
+         * @param   extra   Extra code specific to the error
+         */
+        @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())
+                        .setMessage(message)
+                        .setPositiveButton(android.R.string.VideoView_error_button,
+                                new DialogInterface.OnClickListener() {
+                                    public void onClick(DialogInterface dialog, int whichButton) {
+                                        dialog.dismiss();
+                                        VideoHelper.this.onCompletion(null);
+                                    }
+                                })
+                        .setCancelable(false)
+                        .show();
+            }
+            return true;
+        }
+        
+    }
+
+    
+    @Override
+    public void onStop() {
+        super.onStop();
+        
+        if (mMediaServiceConnection != null) {
+            Log.d(TAG, "Unbinding from MediaService ...");
+            if (mMediaServiceBinder != null && mMediaController != null) {
+                mMediaServiceBinder.unregisterMediaController(mMediaController);
+            }
+            getActivity().unbindService(mMediaServiceConnection);
+            mMediaServiceConnection = null;
+            mMediaServiceBinder = null;
+        }
+    }
+    
+    @Override
+    public boolean onTouch(View v, MotionEvent event) {
+        if (event.getAction() == MotionEvent.ACTION_DOWN && v == mVideoPreview) {
+            startFullScreenVideo();
+            return true;        
+        }
+        return false;
+    }
+
+    
+    private void startFullScreenVideo() {
+        Intent i = new Intent(getActivity(), PreviewVideoActivity.class);
+        i.putExtra(PreviewVideoActivity.EXTRA_ACCOUNT, mAccount);
+        i.putExtra(PreviewVideoActivity.EXTRA_FILE, mFile);
+        i.putExtra(PreviewVideoActivity.EXTRA_AUTOPLAY, mVideoPreview.isPlaying());
+        mVideoPreview.pause();
+        i.putExtra(PreviewVideoActivity.EXTRA_START_POSITION, mVideoPreview.getCurrentPosition());
+        startActivityForResult(i, 0);
+    }
+
+    
+    @Override
+    public void onActivityResult (int requestCode, int resultCode, Intent data) {
+        super.onActivityResult(requestCode, resultCode, data);
+        if (resultCode == Activity.RESULT_OK) {
+            mSavedPlaybackPosition = data.getExtras().getInt(PreviewVideoActivity.EXTRA_START_POSITION);
+            mAutoplay = data.getExtras().getBoolean(PreviewVideoActivity.EXTRA_AUTOPLAY); 
+        }
+    }
+    
+
+    private void playAudio() {
+        if (!mMediaServiceBinder.isPlaying(mFile)) {
+            Log.d(TAG, "starting playback of " + mFile.getStoragePath());
+            mMediaServiceBinder.start(mAccount, mFile, mAutoplay, mSavedPlaybackPosition);
+            
+        } else {
+            if (!mMediaServiceBinder.isPlaying() && mAutoplay) {
+                mMediaServiceBinder.start();
+                mMediaController.updatePausePlay();
+            }
+        }
+    }
+
+
+    private void bindMediaService() {
+        Log.d(TAG, "Binding to MediaService...");
+        if (mMediaServiceConnection == null) {
+            mMediaServiceConnection = new MediaServiceConnection();
+        }
+        getActivity().bindService(  new Intent(getActivity(), 
+                                    MediaService.class),
+                                    mMediaServiceConnection, 
+                                    Context.BIND_AUTO_CREATE);
+            // follow the flow in MediaServiceConnection#onServiceConnected(...)
+    }
+    
+    /** Defines callbacks for service binding, passed to bindService() */
+    private class MediaServiceConnection implements ServiceConnection {
+
+        @Override
+        public void onServiceConnected(ComponentName component, IBinder service) {
+            if (component.equals(new ComponentName(getActivity(), MediaService.class))) {
+                Log.d(TAG, "Media service connected");
+                mMediaServiceBinder = (MediaServiceBinder) service;
+                if (mMediaServiceBinder != null) {
+                    prepareMediaController();
+                    playAudio();    // do not wait for the touch of nobody to play audio
+                    
+                    Log.d(TAG, "Successfully bound to MediaService, MediaController ready");
+                    
+                } else {
+                    Log.e(TAG, "Unexpected response from MediaService while binding");
+                }
+            }
+        }
+
+        private void prepareMediaController() {
+            mMediaServiceBinder.registerMediaController(mMediaController);
+            if (mMediaController != null) {
+                mMediaController.setMediaPlayer(mMediaServiceBinder);
+                mMediaController.setEnabled(true);
+                mMediaController.updatePausePlay();
+            }
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName component) {
+            if (component.equals(new ComponentName(getActivity(), MediaService.class))) {
+                Log.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();
+                }
+                mMediaServiceBinder = null;
+                mMediaServiceConnection = null;
+            }
+        }
+    }    
+
+    
+
+    /**
+     * 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() {
+        stopPreview(true);
+        String storagePath = mFile.getStoragePath();
+        String encodedStoragePath = WebdavUtils.encodePath(storagePath);
+        try {
+            Intent i = new Intent(Intent.ACTION_VIEW);
+            i.setDataAndType(Uri.parse("file://"+ encodedStoragePath), mFile.getMimetype());
+            i.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+            startActivity(i);
+            
+        } catch (Throwable t) {
+            Log.e(TAG, "Fail when trying to open with the mimeType provided from the ownCloud server: " + mFile.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(mFile.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.e(TAG, "Trying to find out MIME type of a file without extension: " + storagePath);
+                
+            } catch (ActivityNotFoundException e) {
+                Log.e(TAG, "No activity found to handle: " + storagePath + " with MIME type " + mimeType + " obtained from extension");
+                
+            } catch (Throwable th) {
+                Log.e(TAG, "Unexpected problem when opening: " + storagePath, th);
+                
+            } finally {
+                if (toastIt) {
+                    Toast.makeText(getActivity(), "There is no application to handle file " + mFile.getFileName(), Toast.LENGTH_SHORT).show();
+                }
+            }
+            
+        }
+        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[]{mFile.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(mFile.getFileId()) != null) {   // check that the file is still there;
+            stopPreview(true);
+            mLastRemoteOperation = new RemoveFileOperation( mFile,      // TODO we need to review the interface with RemoteOperations, and use OCFile IDs instead of OCFile objects as parameters
+                                                            true, 
+                                                            mStorageManager);
+            WebdavClient wc = OwnCloudClientUtils.createOwnCloudClient(mAccount, getSherlockActivity().getApplicationContext());
+            mLastRemoteOperation.execute(wc, this, mHandler);
+            
+            boolean inDisplayActivity = getActivity() instanceof FileDisplayActivity;
+            getActivity().showDialog((inDisplayActivity)? FileDisplayActivity.DIALOG_SHORT_WAIT : FileDetailActivity.DIALOG_SHORT_WAIT);
+        }
+    }
+    
+    
+    /**
+     * Removes the file from local storage
+     */
+    @Override
+    public void onNeutral(String callerTag) {
+        // TODO this code should be made in a secondary thread,
+        if (mFile.isDown()) {   // checks it is still there
+            stopPreview(true);
+            File f = new File(mFile.getStoragePath());
+            f.delete();
+            mFile.setStoragePath(null);
+            mStorageManager.saveFile(mFile);
+            finish();
+        }
+    }
+    
+    /**
+     * User cancelled the removal action.
+     */
+    @Override
+    public void onCancel(String callerTag) {
+        // nothing to do here
+    }
+    
+
+    /**
+     * {@inheritDoc}
+     */
+    public OCFile getFile(){
+        return mFile;
+    }
+    
+    /*
+    /**
+     * Use this method to signal this Activity that it shall update its view.
+     * 
+     * @param file : An {@link OCFile}
+     *-/
+    public void updateFileDetails(OCFile file, Account ocAccount) {
+        mFile = file;
+        if (ocAccount != null && ( 
+                mStorageManager == null || 
+                (mAccount != null && !mAccount.equals(ocAccount))
+           )) {
+            mStorageManager = new FileDataStorageManager(ocAccount, getActivity().getApplicationContext().getContentResolver());
+        }
+        mAccount = ocAccount;
+        updateFileDetails(false);
+    }
+    */
+    
+
+    /**
+     * 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.
+     */
+    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) {
+        boolean inDisplayActivity = getActivity() instanceof FileDisplayActivity;
+        getActivity().dismissDialog((inDisplayActivity)? FileDisplayActivity.DIALOG_SHORT_WAIT : FileDetailActivity.DIALOG_SHORT_WAIT);
+        
+        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) {
+        if (mFile.isAudio() && stopAudio) {
+            mMediaServiceBinder.pause();
+            
+        } else if (mFile.isVideo()) {
+            mVideoPreview.stopPlayback();
+        }
+    }
+
+
+
+    /**
+     * Finishes the preview
+     */
+    private void finish() {
+        Activity container = getActivity();
+        if (container instanceof FileDisplayActivity) {
+            // double pane
+            FragmentTransaction transaction = getActivity().getSupportFragmentManager().beginTransaction();
+            transaction.replace(R.id.file_details_container, new FileDetailFragment(null, null), FileDetailFragment.FTAG); // empty FileDetailFragment
+            transaction.commit();
+            ((FileFragment.ContainerActivity)container).onFileStateChanged();
+        } else {
+            container.finish();
+        }
+    }
+    
+}
diff --git a/src/com/owncloud/android/ui/preview/PreviewVideoActivity.java b/src/com/owncloud/android/ui/preview/PreviewVideoActivity.java
new file mode 100644 (file)
index 0000000..106f918
--- /dev/null
@@ -0,0 +1,283 @@
+/* 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 as published by
+ *   the Free Software Foundation, either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.ui.preview;
+
+import android.accounts.Account;
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.media.MediaPlayer;
+import android.media.MediaPlayer.OnCompletionListener;
+import android.media.MediaPlayer.OnErrorListener;
+import android.media.MediaPlayer.OnPreparedListener;
+import android.net.Uri;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.widget.MediaController;
+import android.widget.VideoView;
+
+import com.owncloud.android.AccountUtils;
+import com.owncloud.android.R;
+import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.media.MediaService;
+
+/**
+ *  Activity implementing a basic video player.
+ * 
+ *  Used as an utility to preview video files contained in an ownCloud account.
+ *  
+ *  Currently, it always plays in landscape mode, full screen. When the playback ends,
+ *  the activity is finished. 
+ *  
+ *  @author David A. Velasco
+ */
+public class PreviewVideoActivity extends Activity implements OnCompletionListener, OnPreparedListener, OnErrorListener {
+
+    /** Key to receive an {@link OCFile} to play as an extra value in an {@link Intent} */
+    public static final String EXTRA_FILE = "FILE";
+    
+    /** Key to receive the ownCloud {@link Account} where the file to play is saved as an extra value in an {@link Intent} */
+    public static final String EXTRA_ACCOUNT = "ACCOUNT";
+    
+    /** Key to receive a flag signaling if the video should be started immediately */
+    public static final String EXTRA_AUTOPLAY = "AUTOPLAY";
+    
+    /** Key to receive the position of the playback where the video should be put at start */
+    public static final String EXTRA_START_POSITION = "START_POSITION";
+    
+    private static final String TAG = PreviewVideoActivity.class.getSimpleName();
+
+    private OCFile mFile;                       // video file to play
+    private Account mAccount;                   // ownCloud account holding mFile
+    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
+    private MediaController mMediaController;   // panel control used by the user to control the playback
+          
+    /** 
+     *  Called when the activity is first created.
+     *  
+     *  Searches for an {@link OCFile} and ownCloud {@link Account} holding it in the starting {@link Intent}.
+     *  
+     *  The {@link Account} is unnecessary if the file is downloaded; else, the {@link Account} is used to 
+     *  try to stream the remote file - TODO get the streaming works
+     * 
+     *  {@inheritDoc}
+     */
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        Log.e(TAG, "ACTIVITY\t\tonCreate");
+        
+        setContentView(R.layout.video_layout);
+    
+        if (savedInstanceState == null) {
+            Bundle extras = getIntent().getExtras();
+            mFile = extras.getParcelable(EXTRA_FILE);
+            mAccount = extras.getParcelable(EXTRA_ACCOUNT);
+            mSavedPlaybackPosition = extras.getInt(EXTRA_START_POSITION);
+            mAutoplay = extras.getBoolean(EXTRA_AUTOPLAY);
+            
+        } else {
+            mFile = savedInstanceState.getParcelable(EXTRA_FILE);
+            mAccount = savedInstanceState.getParcelable(EXTRA_ACCOUNT);
+            mSavedPlaybackPosition = savedInstanceState.getInt(EXTRA_START_POSITION);
+            mAutoplay = savedInstanceState.getBoolean(EXTRA_AUTOPLAY);
+        }
+          
+        mVideoPlayer = (VideoView) findViewById(R.id.videoPlayer);
+
+        // set listeners to get more contol on the playback
+        mVideoPlayer.setOnPreparedListener(this);
+        mVideoPlayer.setOnCompletionListener(this);
+        mVideoPlayer.setOnErrorListener(this);
+          
+        // keep the screen on while the playback is performed (prevents screen off by battery save)
+        mVideoPlayer.setKeepScreenOn(true);
+        
+        if (mFile != null) {
+            if (mFile.isDown()) {
+                mVideoPlayer.setVideoPath(mFile.getStoragePath());
+                
+            } else if (mAccount != null) {
+                // not working now
+                String url = AccountUtils.constructFullURLForAccount(this, mAccount) + mFile.getRemotePath();
+                mVideoPlayer.setVideoURI(Uri.parse(url));
+                
+            } else {
+                onError(null, MediaService.OC_MEDIA_ERROR, R.string.media_err_no_account);
+            }
+            
+            // create and prepare control panel for the user
+            mMediaController = new MediaController(this);
+            mMediaController.setMediaPlayer(mVideoPlayer);
+            mMediaController.setAnchorView(mVideoPlayer);
+            mVideoPlayer.setMediaController(mMediaController);
+            
+        } else {
+            onError(null, MediaService.OC_MEDIA_ERROR, R.string.media_err_nothing_to_play);
+        }
+    }    
+    
+    
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void onSaveInstanceState(Bundle outState) {
+        super.onSaveInstanceState(outState);
+        Log.e(TAG, "ACTIVITY\t\tonSaveInstanceState");
+        outState.putParcelable(PreviewVideoActivity.EXTRA_FILE, mFile);
+        outState.putParcelable(PreviewVideoActivity.EXTRA_ACCOUNT, mAccount);
+        outState.putInt(PreviewVideoActivity.EXTRA_START_POSITION, mVideoPlayer.getCurrentPosition());
+        outState.putBoolean(PreviewVideoActivity.EXTRA_AUTOPLAY , mVideoPlayer.isPlaying());
+    }
+
+    
+    @Override
+    public void onBackPressed() {
+        Log.e(TAG, "ACTIVTIY\t\tonBackPressed");
+        Intent i = new Intent();
+        i.putExtra(EXTRA_AUTOPLAY, mVideoPlayer.isPlaying());
+        i.putExtra(EXTRA_START_POSITION, mVideoPlayer.getCurrentPosition());
+        setResult(RESULT_OK, i);
+        super.onBackPressed();
+    }
+
+    
+    @Override
+    public void onResume() {
+        super.onResume();
+        Log.e(TAG, "ACTIVTIY\t\tonResume");
+    }
+
+    
+    @Override
+    public void onStart() {
+        super.onStart();
+        Log.e(TAG, "ACTIVTIY\t\tonStart");
+    }
+    
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        Log.e(TAG, "ACTIVITY\t\tonDestroy");
+    }
+    
+    @Override
+    public void onStop() {
+        super.onStop();
+        Log.e(TAG, "ACTIVTIY\t\tonStop");
+    }
+    
+    
+    @Override
+    public void onPause() {
+        super.onPause();
+        Log.e(TAG, "ACTIVTIY\t\tonPause");
+    }
+    
+    
+    /** 
+     * Called when the file is ready to be played.
+     * 
+     * Just starts the playback.
+     * 
+     * @param   mp    {@link MediaPlayer} instance performing the playback.
+     */
+    @Override
+    public void onPrepared(MediaPlayer mp) {
+        Log.e(TAG, "ACTIVITY\t\tonPrepare");
+        mVideoPlayer.seekTo(mSavedPlaybackPosition);
+        if (mAutoplay) { 
+            mVideoPlayer.start();
+        }
+        mMediaController.show(5000);  
+    }
+    
+    
+    /**
+     * Called when the file is finished playing.
+     *  
+     * Rewinds the video
+     * 
+     * @param   mp    {@link MediaPlayer} instance performing the playback.
+     */
+    @Override
+    public void onCompletion(MediaPlayer  mp) {
+        mVideoPlayer.seekTo(0);
+    }
+    
+    
+    /**
+     * Called when an error in playback occurs.
+     * 
+     * @param   mp      {@link MediaPlayer} instance performing the playback.
+     * @param   what    Type of error
+     * @param   extra   Extra code specific to the error
+     */
+    @Override
+    public boolean onError(MediaPlayer mp, int what, int extra) {
+        Log.e(TAG, "Error in video playback, what = " + what + ", extra = " + extra);
+        
+        if (mMediaController != null) {
+            mMediaController.hide();
+        }
+        
+        if (mVideoPlayer.getWindowToken() != null) {
+            String message = MediaService.getMessageForMediaError(this, what, extra);
+            new AlertDialog.Builder(this)
+                    .setMessage(message)
+                    .setPositiveButton(android.R.string.VideoView_error_button,
+                            new DialogInterface.OnClickListener() {
+                                public void onClick(DialogInterface dialog, int whichButton) {
+                                    PreviewVideoActivity.this.onCompletion(null);
+                                }
+                            })
+                    .setCancelable(false)
+                    .show();
+        }
+        return true;
+    }
+    
+    
+    /**  
+     * Screen touches trigger the appearance of the control panel for a limited time.
+     *
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean onTouchEvent (MotionEvent ev){ 
+        /*if (ev.getAction() == MotionEvent.ACTION_DOWN) {
+            if (mMediaController.isShowing()) {
+                mMediaController.hide();
+            } else {
+                mMediaController.show(MediaService.MEDIA_CONTROL_SHORT_LIFE);
+            }
+            return true;        
+        } else {
+            return false;
+        }*/
+        return false;
+    }
+
+
+}
\ No newline at end of file
index d39f8ce..8d3912d 100644 (file)
@@ -30,6 +30,8 @@ import java.util.Set;
 
 import org.apache.commons.httpclient.methods.RequestEntity;
 
+import com.owncloud.android.network.ProgressiveDataTransferer;
+
 import eu.alefzero.webdav.OnDatatransferProgressListener;
 
 import android.util.Log;
@@ -40,7 +42,7 @@ import android.util.Log;
  * 
  * @author David A. Velasco
  */
-public class ChunkFromFileChannelRequestEntity implements RequestEntity {
+public class ChunkFromFileChannelRequestEntity implements RequestEntity, ProgressiveDataTransferer {
 
     private static final String TAG = ChunkFromFileChannelRequestEntity.class.getSimpleName();
     
@@ -90,16 +92,25 @@ public class ChunkFromFileChannelRequestEntity implements RequestEntity {
         return true;
     }
     
-    public void addOnDatatransferProgressListener(OnDatatransferProgressListener listener) {
-        mDataTransferListeners.add(listener);
+    @Override
+    public void addDatatransferProgressListener(OnDatatransferProgressListener listener) {
+        synchronized (mDataTransferListeners) {
+            mDataTransferListeners.add(listener);
+        }
     }
     
-    public void addOnDatatransferProgressListeners(Collection<OnDatatransferProgressListener> listeners) {
-        mDataTransferListeners.addAll(listeners);
+    @Override
+    public void addDatatransferProgressListeners(Collection<OnDatatransferProgressListener> listeners) {
+        synchronized (mDataTransferListeners) {
+            mDataTransferListeners.addAll(listeners);
+        }
     }
     
-    public void removeOnDatatransferProgressListener(OnDatatransferProgressListener listener) {
-        mDataTransferListeners.remove(listener);
+    @Override
+    public void removeDatatransferProgressListener(OnDatatransferProgressListener listener) {
+        synchronized (mDataTransferListeners) {
+            mDataTransferListeners.remove(listener);
+        }
     }
     
     
@@ -116,9 +127,11 @@ public class ChunkFromFileChannelRequestEntity implements RequestEntity {
                 out.write(mBuffer.array(), 0, readCount);
                 mBuffer.clear();
                 mTransferred += readCount;
-                it = mDataTransferListeners.iterator();
-                while (it.hasNext()) {
-                    it.next().onTransferProgress(readCount, mTransferred, size, mFile.getName());
+                synchronized (mDataTransferListeners) {
+                    it = mDataTransferListeners.iterator();
+                    while (it.hasNext()) {
+                        it.next().onTransferProgress(readCount, mTransferred, size, mFile.getName());
+                    }
                 }
             }
             
index 3adaa3a..d60eabf 100644 (file)
@@ -32,6 +32,8 @@ import java.util.Set;
 
 import org.apache.commons.httpclient.methods.RequestEntity;
 
+import com.owncloud.android.network.ProgressiveDataTransferer;
+
 import eu.alefzero.webdav.OnDatatransferProgressListener;
 
 import android.util.Log;
@@ -41,7 +43,7 @@ import android.util.Log;
  * A RequestEntity that represents a File.
  * 
  */
-public class FileRequestEntity implements RequestEntity {
+public class FileRequestEntity implements RequestEntity, ProgressiveDataTransferer {
 
     final File mFile;
     final String mContentType;
@@ -70,17 +72,26 @@ public class FileRequestEntity implements RequestEntity {
     public boolean isRepeatable() {
         return true;
     }
-    
-    public void addOnDatatransferProgressListener(OnDatatransferProgressListener listener) {
-        mDataTransferListeners.add(listener);
+
+    @Override
+    public void addDatatransferProgressListener(OnDatatransferProgressListener listener) {
+        synchronized (mDataTransferListeners) {
+            mDataTransferListeners.add(listener);
+        }
     }
     
-    public void addOnDatatransferProgressListeners(Collection<OnDatatransferProgressListener> listeners) {
-        mDataTransferListeners.addAll(listeners);
+    @Override
+    public void addDatatransferProgressListeners(Collection<OnDatatransferProgressListener> listeners) {
+        synchronized (mDataTransferListeners) {
+            mDataTransferListeners.addAll(listeners);
+        }
     }
     
-    public void removeOnDatatransferProgressListener(OnDatatransferProgressListener listener) {
-        mDataTransferListeners.remove(listener);
+    @Override
+    public void removeDatatransferProgressListener(OnDatatransferProgressListener listener) {
+        synchronized (mDataTransferListeners) {
+            mDataTransferListeners.remove(listener);
+        }
     }
     
     
@@ -103,9 +114,11 @@ public class FileRequestEntity implements RequestEntity {
                 out.write(tmp.array(), 0, readResult);
                 tmp.clear();
                 transferred += readResult;
-                it = mDataTransferListeners.iterator();
-                while (it.hasNext()) {
-                    it.next().onTransferProgress(readResult, transferred, size, mFile.getName());
+                synchronized (mDataTransferListeners) {
+                    it = mDataTransferListeners.iterator();
+                    while (it.hasNext()) {
+                        it.next().onTransferProgress(readResult, transferred, size, mFile.getName());
+                    }
                 }
             }
             
index 1319a2b..df30dcb 100644 (file)
@@ -166,7 +166,7 @@ public class WebdavClient extends HttpClient {
         try {\r
             File f = new File(localFile);\r
             FileRequestEntity entity = new FileRequestEntity(f, contentType);\r
-            entity.addOnDatatransferProgressListener(mDataTransferListener);\r
+            entity.addDatatransferProgressListener(mDataTransferListener);\r
             put.setRequestEntity(entity);\r
             status = executeMethod(put);\r
             \r