From: David A. Velasco Date: Thu, 13 Feb 2014 11:26:47 +0000 (+0100) Subject: Merge pull request #367 from LukeOwncloud/renamed_oc_framework_to_android_library X-Git-Tag: oc-android-1.5.5~50 X-Git-Url: http://git.linex4red.de/pub/Android/ownCloud.git/commitdiff_plain/45780e79f2cc76ab7680d91da74a4c1a68172236?hp=32cf40d66f37b5854505b4fe9fb24ff89c51b298 Merge pull request #367 from LukeOwncloud/renamed_oc_framework_to_android_library Changed name of oc_framework to owncloud-android-library in setup.md and pom.xml --- diff --git a/AndroidManifest.xml b/AndroidManifest.xml index c1202e63..465dec84 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -54,7 +54,6 @@ > - @@ -81,9 +80,12 @@ - + - + + + + + diff --git a/owncloud-android-library b/owncloud-android-library index afb4ae1c..815fbba4 160000 --- a/owncloud-android-library +++ b/owncloud-android-library @@ -1 +1 @@ -Subproject commit afb4ae1c2e15dfc3b3f9a9861b75d375e38f2805 +Subproject commit 815fbba48677e40bff2c3c114c4ce8dd1e35bc17 diff --git a/res/drawable-hdpi/sharedlink.png b/res/drawable-hdpi/sharedlink.png new file mode 100644 index 00000000..222172a7 Binary files /dev/null and b/res/drawable-hdpi/sharedlink.png differ diff --git a/res/drawable-mdpi/sharedlink.png b/res/drawable-mdpi/sharedlink.png new file mode 100644 index 00000000..8300eacf Binary files /dev/null and b/res/drawable-mdpi/sharedlink.png differ diff --git a/res/drawable-xhdpi/sharedlink.png b/res/drawable-xhdpi/sharedlink.png new file mode 100644 index 00000000..3879663c Binary files /dev/null and b/res/drawable-xhdpi/sharedlink.png differ diff --git a/res/layout-v11/activity_row.xml b/res/layout-v11/activity_row.xml new file mode 100644 index 00000000..95c7dfc5 --- /dev/null +++ b/res/layout-v11/activity_row.xml @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/res/layout/activity_row.xml b/res/layout/activity_row.xml new file mode 100644 index 00000000..b917600c --- /dev/null +++ b/res/layout/activity_row.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/res/layout/list_item.xml b/res/layout/list_item.xml index ea738328..abe0e7f7 100644 --- a/res/layout/list_item.xml +++ b/res/layout/list_item.xml @@ -54,14 +54,14 @@ android:src="@drawable/ic_favorite" /> - + - + - + + + - + + diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml index ebdee27c..c29514dd 100644 --- a/res/values-ca/strings.xml +++ b/res/values-ca/strings.xml @@ -55,6 +55,7 @@ Baixa Actualitza el fitxer L\'arxiu s\'ha canviat de nom a %1$s durant la càrrega + Enllaç de compartició Sí No D\'acord diff --git a/res/values-cs-rCZ/strings.xml b/res/values-cs-rCZ/strings.xml index 9af81e4f..03bc06a3 100644 --- a/res/values-cs-rCZ/strings.xml +++ b/res/values-cs-rCZ/strings.xml @@ -55,6 +55,8 @@ Stáhnout Obnovit soubor Soubor byl v průběhu odesílání přejmenován na %1$s + Sdílet odkaz + ZruÅ¡it sdílení odkazu Ano Ne OK @@ -179,6 +181,7 @@ Počkejte chvíli Neočekávaný problém - zkuste zvolit soubor jinou aplikací Žádný soubor nebyl vybrán + Odeslat odkaz ... Přihlásit se s oAuth2 Připojuji se k oAuth2 serveru... Identitu stránky nelze ověřit @@ -230,4 +233,8 @@ nic nedělat nejste připojeni pro okamžité odeslání Chybová zpráva: Zkontrolujte prosím nastavení vaÅ¡eho serveru, možná jste překročili kvótu. + Je nám líto, ale sdílení není na vaÅ¡em serveru povoleno. Kontaktujte vaÅ¡eho administrátora. + Nepodařilo se sdílet tento soubor či složku. Ujistěte se, že existuje. + Při pokusu o sdílení tohoto souboru či složky nastala chyba + Při pokusu o zruÅ¡ení sdílení tohoto souboru či složky nastala chyba diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml index 1bf3ca28..71a7bff0 100644 --- a/res/values-da/strings.xml +++ b/res/values-da/strings.xml @@ -55,6 +55,8 @@ Hent Opdater fil Filen blev omdøbt til %1$s under upload + Del link + Ophæv deling Ja Nej OK @@ -179,6 +181,7 @@ Vent et øjeblik Uforventet problem; prøv venligst anden applikation til at vælge filen Ingen fil blev valgt + Send link til ... Log pÃ¥ med oAuth2 Forbinder til oAuth2 server... Sidens identitet kunne ikke verificeres @@ -230,4 +233,8 @@ gør intet, du er ikke online til øjeblikkelig upload Fejlmeddelelse Tjek din serverkonfiguration, mÃ¥ske er din kvota overskredet. + Beklager, deling er ikke slÃ¥et til pÃ¥ din server. Kontakt venligst din administrator. + Kan ikke dele denne fil eller mappe. Find venligst ud af om den eksisterer + Der opstod en fejl ved deling af denne fil eller mappe + Der opstod en fejl ved stopning af deling af denne mappe. diff --git a/res/values-de-rDE/strings.xml b/res/values-de-rDE/strings.xml index 63a2446a..ca43de3d 100644 --- a/res/values-de-rDE/strings.xml +++ b/res/values-de-rDE/strings.xml @@ -55,6 +55,8 @@ Herunterladen Datei aktualisieren Datei wurde wärend des Uploads zu %1$s umbenannt + Link teilen + Link nicht mehr freigeben Ja Nein OK @@ -179,6 +181,7 @@ Bitte warten Sie einen Moment. Ein unerwartetes Problem ist aufgetreten. Bitte versuchen Sie, die Datei in einer anderen App zu öffnen. Es wurde keine Datei ausgewählt. + Link senden an ... Anmelden mit oAuth2 Verbinde mit dem oAuth2-Server… Die Identität der Website konnte nicht überprüft werden @@ -230,4 +233,8 @@ Nicht durchgeführt - Nicht online für sofortigen Upload Fehlermeldung: Bitte überprüfen Sie Ihre Serverkonfiguration. Vielleicht ist Ihr Nutzungslimit überschritten. + Entschuldigung, Freigaben sind auf Ihrem Server nicht aktiviert. Bitte kontaktieren Sie Ihren Administrator. + Die Freigabe der Datei oder des Ordners ist nicht möglich. Bitte stellen Sie sicher, dass diese existiert. + Es ist ein Fehler beim Freigeben der Datei oder des Ordners aufgetreten. + Es ist ein Fehler beim Entfernen der Freigabe für diese Datei oder den Ordner aufgetreten. diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml index 588837a4..17b92e99 100644 --- a/res/values-de/strings.xml +++ b/res/values-de/strings.xml @@ -55,6 +55,8 @@ Herunterladen Datei aktualisieren Datei wurde wärend des Uploads zu %1$s umbenannt + Link Teilen + Link nicht mehr freigeben Ja Nein OK @@ -179,6 +181,7 @@ Bitte warte einen Moment. Ein unerwartetes Problem ist aufgetreten. Bitte versuche, die Datei in einer anderen App zu öffnen Es wurde keine Datei ausgewählt. + Link senden an ... Anmelden mit oAuth2 Verbinde mit dem oAuth2-Server. Die Identität der Website konnte nicht überprüft werden @@ -230,4 +233,8 @@ Nicht durchgeführt - Nicht online für sofortigen Upload Fehlermeldung: Bitte überprüfe Deine Servereinstellungen. Eventuell ist Dein Nutzungslimit überschritten. + Entschuldigung, Freigaben sind auf Deinem Server nicht aktiviert. Bitte kontaktiere Deinen Administrator. + Die Freigabe der Datei oder des Ordners ist nicht möglich. Bitte stelle sicher, dass diese existiert. + Es ist ein Fehler beim Freigeben der Datei oder des Ordners aufgetreten. + Es ist ein Fehler beim Entfernen der Freigabe für diese Datei oder den Ordner aufgetreten. diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml index 7f5fb583..da7c29de 100644 --- a/res/values-el/strings.xml +++ b/res/values-el/strings.xml @@ -55,6 +55,8 @@ Λήψη Ανανέωση αρχείου Το αρχείο μετονομάστηκε σε %1$s κατά την μεταφόρτωση + Διαμοιρασμός συνδέσμου + Ακύρωση διαμοιρασμού συνδέσμου Ναι Όχι ΟΚ @@ -179,6 +181,7 @@ Παρακαλούμε περιμένετε Απροσδόκητο σφάλμα, δοκιμάστε με άλλη εφαρμογή Δεν επιλέχθηκαν αρχεία + Αποστολή συνδέσμου σε ... Σύνδεση με oAuth2 Σύνδεση με το διακομιστή oAuth2 σε εξέλιξη... Η ταυτότητα της σελίδας δεν μπορεί να εγκριθεί @@ -229,4 +232,8 @@ Φόρτωση περισσότερων εικόνων Μήνυμα Αποτυχίας: Παρακαλώ ελέγξτε τις ρυθμίσεις του διακομιστή σας, ίσως έχετε υπερβεί τη διαθέσιμη μερίδα σας. + Λυπάμαι, ο διαμοιρασμός δεν είναι ενεργοποιημένος στο διακομιστή σας. Παρακαλώ επικοινωνήστε με το διαχειριστή σας. + Αδυναμία διαμοιρασμού αυτού του αρχείου ή φακέλου. Παρακαλώ βεβαιωθείτε ότι υπάρχει + Ένα σφάλμα προέκυψε κατά την προσπάθεια διαμοιρασμού αυτού του αρχείου ή φακέλου + Ένα σφάλμα προέκυψε κατά τη διάρκεια ακύρωσης διαμοιρασμού αυτού του αρχείου ή φακέλου diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml index 0562dd7c..e4b215ae 100644 --- a/res/values-en-rGB/strings.xml +++ b/res/values-en-rGB/strings.xml @@ -55,6 +55,8 @@ Download Refresh file File was renamed to %1$s during upload + Share link + Unshare link Yes No OK @@ -179,6 +181,7 @@ Wait a moment Unexpected problem; please select the file from a different app No file was selected + Send link to … Log in with oAuth2 Connecting to oAuth2 server… The identity of the site could not be verified @@ -230,4 +233,8 @@ do nothing you are not online for instant upload Failure Message: Please check your server configuration, perhaps your quota is exceeded. + Sorry, sharing is not enabled on your server. Please contact your administrator. + Unable to share this file or folder. Please, make sure it exists + An error occurred while trying to share this file or folder + An error occurred while trying to unshare this file or folder diff --git a/res/values-eo/strings.xml b/res/values-eo/strings.xml index c69e2c4e..cf19b74a 100644 --- a/res/values-eo/strings.xml +++ b/res/values-eo/strings.xml @@ -35,6 +35,7 @@ Modifita je: Elŝuti La dosiero alinomiĝis al %1$s dum alŝuto + Konhavigi ligilon Jes Ne Akcepti diff --git a/res/values-es-rAR/strings.xml b/res/values-es-rAR/strings.xml index 2743900a..4bc8c767 100644 --- a/res/values-es-rAR/strings.xml +++ b/res/values-es-rAR/strings.xml @@ -55,6 +55,7 @@ Descargar Actualizar archivo El archivo fue renombrado como %1$s durante la subida + Compartir vínculo Sí No Aceptar diff --git a/res/values-es-rMX/strings.xml b/res/values-es-rMX/strings.xml index aaaf3feb..b674ceaa 100644 --- a/res/values-es-rMX/strings.xml +++ b/res/values-es-rMX/strings.xml @@ -55,6 +55,7 @@ Descargar Actualizar archivo El archivo fue renombrado como %1$s durante la subida + Enlace compartido Sí No Aceptar diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml index b8e445e2..1e19c569 100644 --- a/res/values-es/strings.xml +++ b/res/values-es/strings.xml @@ -55,6 +55,8 @@ Descargar Actualizar archivo El fichero fue renombrado como %1$s durante la subida + Enlace compartido + Ya no compartir enlace Sí No Aceptar @@ -179,6 +181,7 @@ Espere un momento Problema inesperado; por favor, prueba otra app para seleccionar el archivo No hay ficheros seleccionados. + Enviar enlace a... Ingresar con oAuth2 Conectando al servidor oAuth2... La identidad del sitio no puede ser verificada @@ -230,4 +233,8 @@ No hacer nada no está conectado para subida instantánea Mensaje de error: Por favor revise su configuración de servidor, posiblemente su cuota se haya excedido. + Compartir archivos no está activado en su servidor. Sírvase contactar a su administrador de sistema. + No es posible compartir este archivo o carpeta. Asegúrese de que existe. + Ocurrió un error al tratar de compartir este archivo o carpeta + Ocurrió un error al tratar de ya no compartir este archivo o carpeta diff --git a/res/values-et-rEE/strings.xml b/res/values-et-rEE/strings.xml index ea088b76..eba96630 100644 --- a/res/values-et-rEE/strings.xml +++ b/res/values-et-rEE/strings.xml @@ -55,6 +55,7 @@ Lae alla Värskenda faili Fail nimetati üleslaadimise käigus ümber %1$ + Jaga linki Jah Ei OK @@ -179,6 +180,7 @@ Oota hetk Ootamatu tõrge ; palun kasuta faili valimiseks mõnda teist rakendust Ühtegi faili pole valitud + Saada link Logi sisse oAuth2-ga oAuth2 serveriga ühendumine... Saidi identiteeti ei suudetud kinnitada @@ -230,4 +232,6 @@ ära tee midagi, sa pole võrku ühendatud koheseks üleslaadimiseks Veateade: Palun kontrolli oma serveri seadeid, võib-olla on mahulimiit ületatud. + Faili või kausta jagamisel esines viga + Faili või kausta jagamise tühistamisel esines viga diff --git a/res/values-eu/strings.xml b/res/values-eu/strings.xml index 6a019fa6..6f476d9c 100644 --- a/res/values-eu/strings.xml +++ b/res/values-eu/strings.xml @@ -55,6 +55,7 @@ Deskargatu Freskatu fitxaegia Fitxategiaren izena %1$sra aldatu da igotzean + Elkarbanatu lotura Bai Ez Ados diff --git a/res/values-fi-rFI/strings.xml b/res/values-fi-rFI/strings.xml index a29c7cef..e81641dd 100644 --- a/res/values-fi-rFI/strings.xml +++ b/res/values-fi-rFI/strings.xml @@ -52,6 +52,7 @@ Lataa Päivitä tiedosto Tiedoston nimeksi muutettiin %1$s siirron yhteydessä + Jaa linkki Kyllä Ei OK diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml index 6c19d05e..8234d45d 100644 --- a/res/values-fr/strings.xml +++ b/res/values-fr/strings.xml @@ -55,6 +55,7 @@ Télécharger Actualiser le fichier Le fichier a été renommé en %s pendant le téléversement + Partager le lien Oui Non OK diff --git a/res/values-gl/strings.xml b/res/values-gl/strings.xml index e656654d..8820c201 100644 --- a/res/values-gl/strings.xml +++ b/res/values-gl/strings.xml @@ -55,6 +55,8 @@ Descargar Actualizar o ficheiro O ficheiro foi renomeado a %1$s durante o envío + Ligazón para compartir + Deixar de compartir a ligazón Si Non Aceptar @@ -179,6 +181,7 @@ Agarde un chisco Produciuse un erro non agardado. Seleccione o ficheiro con outro aplicativo diferente Non se escolleu ningún ficheiro + Enviar a ligazón a ... Acceder con oAuth2 Conectando co servidor oAuth2… Non foi posíbel verificar a identidade do sitio @@ -230,4 +233,8 @@ non facer nada que non estea en liña para o envío instantáneo Mensaxe de fallo: Comprobe a configuración do seu servidor. é probábel que xa excedera a cota. + O seu servidor non ten activada a opción de compartir. Póñase en contacto co administrador. + Non foi posíbel compartir este ficheiro ou cartafol. Asegurese de que existe. + Produciuse un erro ao tentar compartir este ficheiro ou cartafol. + Produciuse un erro ao tentar deixar de compartir este ficheiro ou cartafol diff --git a/res/values-hu-rHU/strings.xml b/res/values-hu-rHU/strings.xml index 24b3fd46..b341bb8a 100644 --- a/res/values-hu-rHU/strings.xml +++ b/res/values-hu-rHU/strings.xml @@ -55,6 +55,7 @@ Letöltés File frissítése A feltöltés során az állmányt erre neveztük át: %1$s + Megosztás hivatkozással Igen Nem OK diff --git a/res/values-id/strings.xml b/res/values-id/strings.xml index bd151ad1..e190c5c1 100644 --- a/res/values-id/strings.xml +++ b/res/values-id/strings.xml @@ -55,6 +55,7 @@ Unduh Segarkan berkas Berkas diubah namanya menjadi %1$s saat pengunggahan + Bagikan tautan Ya Tidak Oke diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml index 72061d2c..578ea5f8 100644 --- a/res/values-it/strings.xml +++ b/res/values-it/strings.xml @@ -55,6 +55,8 @@ Scarica Aggiorna file Il file è stato rinominato in %1$s durante il caricamento + Condividi collegamento + Rimuovi condivisione collegamento Sì No OK @@ -179,6 +181,7 @@ Attendi Problema inatteso; prova un\'altra applicazione per selezionare il file Non è stato selezionato alcun file + Invia collegamento a... Accesso con oAuth2. Connessione al server oAuth2 in corso... L\'identità del sito non può essere verificata @@ -230,4 +233,8 @@ non fare niente, non sei collegato per i caricamenti istantanei Messaggio d\'errore: Controlla la configurazione del server, forse hai superato la tua quota. + Spiacenti, la condivisione non è abilitata sul server. Contatta il tuo amministratore. + Impossibile condividere il file o la cartella. Assicurati che esista. + Si è verificato un errore durante il tentativo di condivisione del file o della cartella + Si è verificato un errore durante il tentativo di rimuovere la condivisione del file o della cartella diff --git a/res/values-ja-rJP/strings.xml b/res/values-ja-rJP/strings.xml index 3870de62..2c195477 100644 --- a/res/values-ja-rJP/strings.xml +++ b/res/values-ja-rJP/strings.xml @@ -18,9 +18,9 @@ クライアントを保護する 自動アップロードを有効 カメラで撮影した画像を自動アップロード - 記録を有効化 - これは問題を記録するのにつかわれます。 - 記録している履歴 + ログを有効にする + これは問題をログに記録するのに使用します。 + ログ履歴 これは記録されたログを表示します 履歴を削除 ヘルプ @@ -46,7 +46,7 @@ コンテンツを受信しませんでした。アップロードするものはありません。 %1$sで共有コンテンツへのアクセスが許可されていません。 アップロード中 - このフォルダにはファイルがありません。\n\"アップロード\" メニューで新しいファイルを追加することができます。 + このフォルダーにはファイルがありません。\n\"アップロード\" メニューで新しいファイルを追加することができます。 ファイルをタップすると追加情報が表示されます。 サイズ: タイプ: @@ -55,6 +55,7 @@ ダウンロード ファイルを同期 アップロード中にファイル名を %1$s に変更しました + URLで共有 はい いいえ OK @@ -92,16 +93,16 @@ %1$d 同期ファイルを同期できませんでした ファイルの同期に失敗しました %1$d ファイルのコンテンツを同期できませんでした(%2$d の競合) - いくつかのローカルファイルが忘れられています + 一部のローカルファイルが忘れられています %2$s ディレクトリ内の %1$d ファイルはコピーすることができませんでした - \"バージョン 1.3.16から、このデバイスからアップロードされたファイルは、単独のファイルが複数のアカウントと同期される時にデータの損失を防ぐため、ローカルの%1$sのフォルダにコピーされます。\n\nこの変更により、このアプリの以前のバージョンでアップロードされたすべてのファイルが%2$s フォルダにコピーされます。ただし、アカウント同期の際に、エラーがこの操作の完了を阻止しました。このままファイルを残し、%3$sへのリンクを削除するか、あるいは%1$s ディレクトリのファイルを移動し、%4$sへのリンクを維持することができます。\n\n以下にローカルのファイルと、それにリンクしていた%5$sのリモートファイルがリストされています - フォルダ %1$s はもう存在しません + \"バージョン 1.3.16から、このデバイスからアップロードされたファイルは、単独のファイルが複数のアカウントと同期される時にデータの損失を防ぐため、ローカルの%1$sのフォルダーにコピーされます。\n\nこの変更により、このアプリの以前のバージョンでアップロードされたすべてのファイルが%2$s フォルダーにコピーされます。ただし、アカウント同期の際に、エラーがこの操作の完了を阻止しました。このままファイルを残し、%3$sへのリンクを削除するか、あるいは%1$s ディレクトリのファイルを移動し、%4$sへのリンクを維持することができます。\n\n以下にローカルのファイルと、それにリンクしていた%5$sのリモートファイルがリストされています + フォルダー %1$s はもう存在しません 全て移動 全てのファイルは移動されました - いくつかのファイルは移動出来ませんでした + 一部のファイルは移動できませんでした ローカル: %1$s リモート: %1$s - %1$s フォルダに選択されたファイルをコピーするのに十分なスペースがありません。コピーする代わりに、それらを移動させますか? + %1$s フォルダーに選択されたファイルをコピーするのに十分な空き領域がありません。コピーする代わりに、それらを移動させますか? アプリのパスワードを入力してください アプリのパスワードを入力してください アプリ開始時に毎回PINが要求されます。 @@ -123,29 +124,29 @@ メディアファイルが正確にエンコードされていません 再生中にタイムアウトが発生しました メディアファイルをストリーミングできません - メディアファイルをStock Media Playerでプレイ出来ません - プレイに際してセキュリティエラー %1$s - プレイに際して入力エラー %1$s - プレイに際して予期しないエラー %1$s + メディアファイルをStock Media Playerで再生できません + 再生時にセキュリティエラー %1$s + 再生時に入力エラー %1$s + 再生時に予期しないエラー %1$s 巻き戻しボタン - プレイ/ポーズボタン + 再生/一時停止ボタン 早送りボタン ログイン中... ネットワークに接続されていません 暗号化通信が利用できません。 接続が確立しました 接続をテスト中... - サーバーの間違った設定 - 同じユーザとサーバのアカウントがデバイス上にすでに存在します - 入力されたユーザはこのアカウントのユーザと一致しません + サーバー設定が間違っています + 同じユーザーとサーバーのアカウントがデバイス上にすでに存在します + 入力されたユーザーはこのアカウントのユーザーと一致しません 不明なエラーに発生しました ホストが見つかりませんでした - のインスタンスが見つかりませんでした - サーバーからの反応がありません。 + サーバーのインスタンスが見つかりません + サーバーからの反応がありません 不明なURL形式 SSLの初期化に失敗しました - SSL サーバ識別子を確認できませんでした - 認識出来ないサーバのバージョンです + SSLサーバー識別子を確認できませんでした + 認識できないサーバーのバージョンです 接続を確立できませんでした 暗号化通信を確立しました 間違ったユーザー名もしくはパスワード @@ -155,8 +156,8 @@ 認証情報は有効期限切れです。再度認証を行ってください。 現在のパスワードを入力してください セッションの有効期限切れです。再度接続してください。 - 認証サーバに接続中 ... - サーバはこの認証方式をサポートしていません + 認証サーバーに接続中 ... + サーバーはこの認証方式をサポートしていません %1$s は複数アカウントをサポートしていません ファイルを最新に保つ 名前を変更 @@ -165,7 +166,7 @@ 本当に %1$s およびそのコンテンツを削除してもよろしいですか? ローカルのみ ローカルコンテンツのみ - サーバから削除 + サーバーから削除 リモートとローカルの両方 削除に成功しました 削除を完了できませんでした @@ -179,12 +180,12 @@ しばらくお待ちください 予期せぬ問題;他のアプリでファイルを選択してみてください。 ファイルは選択されていません - oAuth2 でログイン + oAuth2でログイン oAuth2サーバーに接続中... サイトの識別子を確認できませんでした - - サーバ証明書は信頼されていません - - サーバ証明書は有効期限切れです - - サーバ証明書は若すぎます + - サーバー証明書は信頼されていません + - サーバー証明書は有効期限切れです + - サーバー証明書の有効期限は未来のものです - URLは証明書内のホスト名と一致しません この証明書を信頼してもよろしいですか? 証明書は保存できませんでした @@ -211,14 +212,14 @@ 12:23:45 WiFi経由でのみ写真をアップロード /InstantUpload - 更新の競合 - リモートファイル %s はローカルファイルと同期していません。続行すると、サーバ上のファイルを置き換えます。 + 更新が競合 + リモートファイル %s はローカルファイルと同期していません。続行すると、サーバー上のファイルを置き換えます。 両方を保持 上書き アップロードしない イメージプレビュー この画像は表示できません - %1$s は %2$s ローカルディレクトリにコピー出来ませんでした + %1$s は %2$s ローカルディレクトリにコピーできませんでした インスタントアップロードに失敗 インスタントアップロードに失敗 全ての失敗したインスタントアップロードの要約 @@ -229,5 +230,5 @@ 更に画像を読み込む オンラインでなく、インスタントアップロードのために何もしません 失敗メッセージ: - サーバーの設定を確認してください。許容を超過している可能性があります。 + サーバー設定を確認してください。クォータサイズを超えている可能性があります。 diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml index c18708c9..112c57f8 100644 --- a/res/values-ko/strings.xml +++ b/res/values-ko/strings.xml @@ -55,6 +55,7 @@ 다운로드 파일 새로고침 업로드 중 파일 이름을 %1$s(으)로 변경하였습니다 + 링크 공유 예 아니요 확인 diff --git a/res/values-lb/strings.xml b/res/values-lb/strings.xml index 6031cfcf..7b6579d8 100644 --- a/res/values-lb/strings.xml +++ b/res/values-lb/strings.xml @@ -27,6 +27,7 @@ Erstallt: Geännert: Download + Link deelen Jo Nee OK diff --git a/res/values-lt-rLT/strings.xml b/res/values-lt-rLT/strings.xml index ed04b6aa..063cc849 100644 --- a/res/values-lt-rLT/strings.xml +++ b/res/values-lt-rLT/strings.xml @@ -53,6 +53,7 @@ Atsisiųsti Atnaujinti failą Ä®kėlimo metu failas buvo pervadintas į %1$s + Dalintis nuoroda Taip Ne Gerai diff --git a/res/values-mk/strings.xml b/res/values-mk/strings.xml index 2c514f52..10fa36af 100644 --- a/res/values-mk/strings.xml +++ b/res/values-mk/strings.xml @@ -29,6 +29,7 @@ Создадено: Изменето: Преземање + Сподели ја врската Да Не Во ред diff --git a/res/values-ml/strings.xml b/res/values-ml/strings.xml new file mode 100644 index 00000000..c757504a --- /dev/null +++ b/res/values-ml/strings.xml @@ -0,0 +1,2 @@ + + diff --git a/res/values-mn/strings.xml b/res/values-mn/strings.xml new file mode 100644 index 00000000..c757504a --- /dev/null +++ b/res/values-mn/strings.xml @@ -0,0 +1,2 @@ + + diff --git a/res/values-nb-rNO/strings.xml b/res/values-nb-rNO/strings.xml index 48b731b7..b1d1899a 100644 --- a/res/values-nb-rNO/strings.xml +++ b/res/values-nb-rNO/strings.xml @@ -1,32 +1,61 @@ + %1$s Andriod app + versjon %1$s + Oppdater konto Last opp Innhold fra andre applikasjoner Filer + Åpne med Opprett katalog Innstillinger + Detaljer Generelt Mer Kontoer + HÃ¥ndter kontoer + PIN kode + Beskytt klienten din + Aktiver direkte opplastinger Last opp bilder tatt med kamera øyeblikkelig + Aktiver loggføring + Denne er brukt til Ã¥ loggføre problemer + Loggføringshistorikk + Denne viser de lagrede loggene + Slett historikk Hjelp + Anbefal til en venn + Tilbakemelding + Avtrykk + Prøv %1$s pÃ¥ smarttelefonen din! + Jeg vil gjerne invitere deg til Ã¥ bruke %1$s pÃ¥ smarttelefonen din!\nLast ned her: %2$s + Sjekk server + Serveradresse https://... Brukernavn Passord + Ny med %1$s? Filer Koble til Last opp + Velg opplastingsmappe: Ingen konto funnet + Det finnes ingen %1$s kontoer for din enhent. For Ã¥ bruker denne appen mÃ¥ du først opprette en. Oppsett Avslutt Intet innhold Ã¥ laste opp Intet innhold ble mottatt. Intet Ã¥ laste opp. + %1$s har ikke tilgang til det delte innholdet Laster opp + Det finnes ikke filer i mappen.\nNye filer kan legges til med \"last opp\" i menyen. Trykk pÃ¥ en fil for Ã¥ vise ekstra informasjon. Størrelse: Type: Opprettet: Endret: Last ned + Oppdater fil + Filnavnet ble endret til %1$s under opplasting + Del lenke Ja Nei OK @@ -35,6 +64,8 @@ Avbryt Lagre og avslutt Feil + Laster... + Ukjent feil Om Endre passord Slett konto @@ -44,48 +75,160 @@ Laster opp... %1$d%% Laster opp %2$s Opplasting fullført + %1$s ble lastet opp Opplasting feilet Opplasting av %1$s kunne ikke fullføres Laster ned... %1$d%% Laster ned %2$s Nedlasting fullført + %1$s ble lastet ned Nedlasting feilet Nedlasting av %1$s kunne ikke fullføres + Ikke lastet ned enda Velg konto Synkronisering feilet Synkronisering av %1$s kunne ikke fullføres + Ugyldig passord for %1$s Konflikter funnet + %1$d hold-i-synk filer kunne ikke synkroniseres + Hold i synk filer mislyktes + Contents of %1$d files could not be sync\'ed (%2$d conflicts)\nInnhold av %1$d filer kunne ikke synkroniseres (%2$d konflikter) + Noen lokale filer ble glemt + %1$d filer av %2$s mappen kunne ikke kopieres til + Fra versjon 1.3.16 blir filer lastet opp fra denne enheten kopiert til den lokale %1$s mappen for Ã¥ forhindre tap av data nÃ¥r én fil blir synkronisert over flere kontoer.\n\nPÃ¥ grunn av denne forandringern ble alle filer lastet opp i tidligere versjoner av denne appen kopiert til %2$s mappen. Imidlertid ble fullføring av denne operasjonen forhindet av en feil, under kontosynkronisering. Du kan enten la filen(e) være som de er, og fjerne koblinken til  %3$s, eller flytte filen(e) til %1$s mappe, og opprettholde koblingen til %4$s.\n\nListet under er de lokale filen(e), og de eksterne filen(e) i %5$s de var kolet til. + Mappen %1$s finnes ikke lengere + Flytt alle + Alle filer ble flyttet + Noen filer kunne ikke fjernes + Lokal: %1$s + Ekstern: %1$s + Det er ikke nok plass til Ã¥ kopiere de valgte filene til %1$s mappe. Vil du flytte dem i stedet? Vennligst tast inn din App-PIN + Skriv inn din PIN kode + PIN koden vil bli ettersourt hver gang appen starter + Vennligst tast inn din PIN kode pÃ¥ nytt + Fjern din PIN kode + PIN kodene du tastet er ulike + Feil PIN kode + PIN kode fjernet + PIN kode lagret + %1$s musikkspiller + %1$s (spiller) + %1$s (laster) + %1$s avspilling avsluttet + Ingen mediafil funnet + Ingen konto angitt + Filen er ikke i en gyldig konto + Mediakodek er ikke støttet + Mediafilen kunne ikke leses + Mediafilen er ikke riktig kodet + Tidsavbrudd under avspillingsforsøk + Mediafilen kan ikke strømmes + Mediafilen kan ikke spilles med standard mediaspiller + Sikkerhetsfeil under avspilling av %1$s + Inputfeil under avspilling av %1$s + Uforventet feil under avspilling av %1$s + Spol tilbake + Spill eller pause + Spol fremover Prøver Ã¥ logge inn... Ingen nettverkstilkobling Sikker tilkobling ikke tilgjengelig. Tilkobling opprettet Tester tilgang... + Feil i server konfigurasjon + En konto for samme bruker og server finnes allerede pÃ¥ enheten + Den innskrevne brukeren matcher ikke brukeren av denne kontoen Ukjent feil oppstod! Fant ikke tjener + Finner ikke server instans Serveren brukte for lang tid pÃ¥ Ã¥ svare Feil formatert URL Oppstart av SSL feilet + Kunne ikke verifisere SSL-serverens identitet + Ukjent server versjon Klarte ikke Ã¥ opprette tilkobling Sikker tilkobling opprettet + Feil brukernavn eller passord + Mislykket autorisasjon + Tilgang nektet av autorisasjonsserver + Uforventet tilstand; vennligst skriv inn serveradressen en gang til + Autorisasjonen din har gÃ¥tt ut. Vennligt autoriser igjen + Vennligst skriv inn gjeldende passord + Sesjonen din har gÃ¥tt ut. Vennligst koble til igjen + Kobler til autorisasjonsserver... + Serveren støtter ikke denne autorisasjonsmetoden + %1$s støtter ikke flere kontoer Hold filen oppdatert Endre navn Fjern Er du sikker pÃ¥ at du vil fjerne %1$s ? + Vil du virkelig fjerne %1$s og dens innhold? Kun lokalt + Kun lokalt innhold Fjern fra server + Ekstern og lokal + Fjerning var vellykket + Fjerning mislyktes + Skriv inn et nytt navn + Lokal kopi kunne ikke endre navn; prøv et annet navn Klarte ikke Ã¥ endre navn + Eksterne filer kunne ikke sjekkes + filinnhold er allerede synkronisert Mappe kunne ikke opprettes + Forbudte tegn: / \\ < > : \" | ? * Vent et øyeblikk + Uforventet problem; vennligst velg filen fra en annen applikasjon Ingen fil ble valgt + Logg inn med oAuth2 + Kobler til oAuth2 server... Identiteten til siden kunne ikke verifiseres - Serverens sertifikat er ikke til Ã¥ stole pÃ¥ - Serverens sertifikat er utløpt + - Server-sertifikatets gyldige datoer er i fremtiden + - Nettadressen samsvarer ikke med vertsnavnet i sertifikatet + Vil du stole pÃ¥ dette sertifikatet likevel? + Sertifikatet kunne ikke lagres Detaljer Skjul + Utstedt til: + Utstedt av: + Vanlig navn: + Organisasjon: + Organisasjonsenhet: Land: + Stat: + Sted: + Gyldighet: Fra: Til: Signatur: + Algoritme: + Dette er en plassholder + placeholder.txt + PNG bilde + 389 KB + 18.05.2012 12:23 + 12:23:45 + Kun last opp bilder via WiFi + /Direkteopplasting + Oppdateringskonflikt + Ekstern fil %s er ikke synkronisert med lokal fil. Hvis du fortsetter vil det erstatte innhold pÃ¥ serveren. Behold begge + Overskriv + Ikke last opp + BildeforhÃ¥ndsvisning + Dette bildet kan ikke vises + %1$s kunne ikke kopieres til %2$s lokale mapper + Misslyktes direkteopplasting + Mislykket direkteopplastinger + Oppsumering av alle mislykkede direkteopplastinger + velg alle + forsøk alle valgte pÃ¥ nytt + slett alle valgte fra opplastingskø + forsøk Ã¥ laste opp bildet pÃ¥ nytt: + Last flere bilder + ikke gjør noe nÃ¥r du ikke er online for direkteopplasting + Feilmelding: + Vennligst sjekk serverkonfigurasjon, kanskje kvoten din er brukt opp. diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml index f60574b8..4cfbcebb 100644 --- a/res/values-nl/strings.xml +++ b/res/values-nl/strings.xml @@ -55,6 +55,8 @@ Download Bestand verversen Bestand was hernoemt naar %1$s tijdens het uploaden + Deel link + Link niet meer delen Ja Nee OK @@ -179,6 +181,7 @@ Even geduld Onverwacht probleem; probeer een andere app om het bestand te selecteren Er werd geen bestand geselecteerd + Verstuur link naar ... Inloggen met oAuth2 Verbinden met oAuth2-server. De identiteit van de site kan niet worden gecontroleerd @@ -230,4 +233,8 @@ doe niks, u bent niet online voor directe upload Mislukkings Bericht: Controleer uw server instellingen, misschien is uw quota overschreden. + Sorry, delen is niet mogelijk op uw server. Neem contact op met uw beheerder. + Kan dit bestand of deze map niet delen. Controleer of dit object wel bestaat. + Er trad een fout op bij uw poging dit bestand of deze map te delen + Er trad een fout op bij uw poging het delen van dit bestand of deze map te beëindigen diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml index de65dbf7..3d0e63d6 100644 --- a/res/values-pl/strings.xml +++ b/res/values-pl/strings.xml @@ -55,6 +55,8 @@ Pobierz Odśwież plik Podczas wysyłania nazwa pliku została zmieniona na %1$s + Udostępnij link + Anuluj udostępnianie Tak Nie OK @@ -179,6 +181,7 @@ Poczekaj chwilę Nieoczekiwany problem; spróbuj wybrać plik z innej aplikacji Nie wybrano żadnych plików + Wyślij link do ... Loguj przez oAuth2 Łączenie z serwerem oAuth2... Nie można zweryfikować tożsamości strony @@ -230,4 +233,8 @@ nic nie rób, ponieważ nie jesteś online, nie możesz przesyłać plików Komunikat błędu: Proszę sprawdź ustawienia serwera, możliwe że przekroczyłes limit wielkości pliku + Przepraszamy, udostępnianie jest wyłączone na twoim serwerze. Skontaktuj się z twoim administratorem. + Brak możliwości udostępnienia tego pliku lub folderu. Upewnij się, że istnieje. + Wystąpił błąd podczas udostępniania tego pliku lub folderu. + Wystąpił błąd podczas anulowania udostępniania tego pliku lub folderu. diff --git a/res/values-pt-rBR/strings.xml b/res/values-pt-rBR/strings.xml index 072c19d0..93d654de 100644 --- a/res/values-pt-rBR/strings.xml +++ b/res/values-pt-rBR/strings.xml @@ -55,6 +55,8 @@ Download Atualizar arquivo Arquivo foi renomeado para %1$s durante o upload + Compartilher link + Descompartilhar o link Sim Não OK @@ -179,6 +181,7 @@ Aguarde um momento Problema inesperado; por favor, tente selecionar o arquivo com outro app Nenhum arquivo foi selecionado + Enviar o link para Login com oAuth2 Conectando-se a oAuth2 servidor ... A identidade do site não pode ser verificada @@ -230,4 +233,8 @@ não fazer nada voce não está conectado para envio instantâneo Mensagem de Falha: Por favor verifique a configuração do servidor, talvez a sua cota esteja vencida. + Desculpe, compartilhamento não está habilitado para seu servidor. Por favor faça contato com o seu administrador. + Incapaz de compartilhar esse arquivo ou pasta. Por favor, certifique-se que existe + Ocorreu um erro durante a tentativa de compartilhar esse arquivo ou pasta + Ocorreu um erro ao tentar descompartilhar este arquivo ou pasta diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml index 8cc99853..0005cb4b 100644 --- a/res/values-pt-rPT/strings.xml +++ b/res/values-pt-rPT/strings.xml @@ -55,6 +55,7 @@ Descarregar Atualizar ficheiro O nome do ficheiro foi alterado para %1$s durante o envio. + Partilhar o link Sim Não OK diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml index ed9a7b84..1964f738 100644 --- a/res/values-ru/strings.xml +++ b/res/values-ru/strings.xml @@ -1,52 +1,52 @@ - %1$s Приложение Андроид + %1$s Приложение для Андроида Версия %1$s Обновить учетную запись - Загрузка - Содержимое от других приложений + Загрузить + Содержимое из других приложений Файлы Открыть с помощью - Создать директорию + Создать каталог Настройки - Детали - Главные + Подробно + Основные Больше - Аккаунты - Управление аккаунтами + Учётные записи + Управление учётными записями App PIN - Защитить ваш клиент применение - Включить моментальную загрузку - Моментально загружать фотографии, полученные с камеры - Включить запись журнала - Это используется для регистрации проблем - Записывать историю - Здесь показаны журналы - Удалить историю + Защитить ваш клиент + Включить режим немедленной загрузки + Немедленно загружать фотографии, полученные с камеры + Включить журналирование + Используется для регистрации ошибок + Журнал + Здесь показаны записи в журнал + Удалить историю записей Помощь Рекомендовать другу Обратная связь Штамп Попробуйте %1$s на вашем смартфоне! - Хочу предложить вам пользоваться %1$s на вашем смартфоне!\nДля загрузки: %2$s + Хочу предложить вам пользоваться %1$s на вашем смартфоне!\nСкачать: %2$s Проверить сервер Адрес сервера https://... - Пользователь + Имя пользователя Пароль - Впервые с %1$s? + Незнакомы с %1$s? Файлы Соединить - Загрузка - Выбрать место для загрузки: - Аккаунты не найдены - На вашем устройстве нет аккаунтов %1$s. Настройте сначала аккаунт. + Загрузить + Выбрать каталог для загрузок: + Учётная запись не найдена + На вашем устройстве нет учётных записей %1$s. Сначала нужно настроить учётную запись. Установка Выход Нет содержимого для загрузки - Контент не получен. Нечего загружать. + Содержимое не получено. Нечего загружать. %1$s не имеет доступа к опубликованным данным Загрузка - В этой папке нет файлов.\nНовые файлы могут быть добавлены с помощью пункта меню \"Загрузить\". + В этом каталоге нет файлов.\nНовые файлы могут быть добавлены с помощью пункта меню \"Загрузить\". Нажмите на файл для отображения дополнительной информации. Размер: Тип: @@ -55,75 +55,77 @@ Скачать Обновить файл Файл был переименован в %1$s во время загрузки + Поделиться ссылкой + Удалить ссылку Да Нет ОК Отменить скачивание - Отмена загрузки + Отменить загрузку Отмена Сохранить & Выйти Ошибка - Загружается... + Идёт загрузка... Неизвестная ошибка О программе Сменить пароль - Удалить аккаунт - Создать аккаунт + Удалить учётную запись + Создать учётную запись Загрузить из... - Имя директории + Имя каталога Загрузка... %1$d%% загрузки %2$s - Загрузка прошла успешно + Загрузка завершена %1$s был успешно загружен Ошибка загрузки Загрузка %1$s не может быть завершена Скачивание... %1$d%% скачивания %2$s - Скачивание прошло успешно + Скачивание завершено %1$s успешно скачан - Скачивание не удалась + Скачивание не удалось Скачивание %1$s не может быть завершено - Ещё не загружено - Выберите аккаунт + Ещё не скачано + Выберите учётную запись Синхронизация прошла неудачно Синхронизация %1$s не может быть завершена Неверный пароль для %1$s Обнаружены конфликты - %1$d файлы, которые должны быть синхронизированными не могут синхронизироваться + %1$d файлы не могут быть синхронизированы Не удалось синхронизировать файлы - Содержание %1$d файла(ов) не может быть синхронизировано (%2$d конфликта(ов)) + Содержимое %1$d файлов не может быть синхронизировано (конфликтов: %2$d) Несколько локальных файлов были забыты - %1$d файлы из %2$s папки не могут быть скопированы в - файлы, загруженные с этого устройства, скопированы в локальную папку %1$s для предотвращения потери данных, когда отдельный файл синхронизируется с нескольких учётных записей. По причине этого изменения, все файлы, загруженные в предыдущих версиях этого приложения, были скопированы в папку %2$s. Однако, ошибка помешала завершению этой операции при синхронизации учётной записи. Вы можете либо оставить файлы как есть, или переместить их в папку %1$s и сохранить ссылку в %4$s. \nВ списке указаны локальные файлы, привязанные к файлам на сервере в папке %5$s. + %1$d файлов из %2$s папок не могут быть скопированы в + Начиная с версии 1.3.16 файлы, загруженные с этого устройства, скопированы в локальный каталог %1$s для предотвращения потери данных, когда один и тот же файл синхронизируется с нескольких учётных записей.\n\nПо причине этого изменения, все файлы, загруженные в предыдущих версиях этого приложения, были скопированы в каталог %2$s. Однако, ошибка помешала завершению этой операции при синхронизации учётной записи. Вы можете либо оставить файлы как есть и удалить ссылку на %3$s, или переместить файлы в каталог %1$s и сохранить ссылку на %4$s.\n\nНиже перечислены локальные файлы и те удалённые файлы в %5$s, с которыми они связаны. Каталог %1$s больше не существует Переместить всё Все файлы были перемещены Некоторые файлы не могут быть перемещены Локально: %1$s Удаленно: %1$s - Отсутствует достаточное количество места для копирования выделенных файлов в папку %1$s. Хотите ли Вы переместить их в другое место? + Недостаточно места для копирования выделенных файлов в каталог %1$s. Переместить их в другое место? Вставьте PIN вашего приложения - Введите App PIN - ПИН-код будет запрашиваться каждый раз, когда вы запускаете приложение. - Повторите App PIN + Введите App PIN + PIN-код будет запрашиваться при каждом запуске приложения. + Повторите ввод App PIN Удалить App PIN - Два App PIN не совпадают + Введённые App PIN не совпадают Неверный App PIN App PIN удалён App PIN сохранён - %1$s музыкальный проигрыватель + %1$s аудиоплеер %1$s (проигрывается) %1$s (загружается) %1$s воспроизведение завершено - Не найден медиа-файл - Не настроена учётная запись + Медиафайлов не найдено + Учётная запись не настроена Файл в неверной учётной записи Неподдерживаемый кодек - Файл не может быть прочитан - Файл - Тайм аут при воспроизведении - Невозможно воспроизвести файл как поток - Файл не может быть проигран стандартным плеером + Медиафайл не может быть прочитан + Медиафайл некорректно закодирован + Время попыток воспроизведения вышло + Невозможно организовать потоковую передачу медиафайла + Медиафайл не может быть проигран стандартным плеером Ошибка безопасности при воспроизведении %1$s Ошибка ввода при воспроизведении %1$s Неожиданная ошибка при воспроизведении %1$s @@ -135,99 +137,104 @@ Защищённое соединение недоступно. Соединение установлено Тестирование соединения... - Неверная конфигурация сервер - Учётная запись для такого пользователя и сервера уже существует на устройстве - Введённый пользователь не соответсвует пользователю учётной записи + Конфигурация сервера задана неверно + Учётная запись такого пользователя и сервера уже существует на устройстве + Введённый пользователь не соответствует этой учётной записи Произошла неизвестная ошибка! Невозможно найти сервер - Экземпляр сервер не найден + Сервер не найден Сервер слишком долго не отвечает Неверный URL Ошибка инициализации SSL - Невозможно проверить сертификат SSL сервера + Невозможно проверить SSL-сертификат сервера Неизвестная версия сервера Невозможно установить соединение Защищённое соединение установлено Неверное имя пользователя или пароль Ошибка авторизации - Сервер отказал в доступе - Неожиданный ответ; пожалуйста, введите адрес сервера ещё раз - Ваша авторизация истекла. Пожалуйста, авторизуйтесь снова + Сервер авторизации отказал в доступе + Неожиданный ответ; введите адрес сервера ещё раз + Время авторизации истекло. Пожалуйста, авторизуйтесь снова Пожалуйста, введите пароль - Ваша сессия истекла. Пожалуйста, подключитесь снова + Время сессии истекло. Пожалуйста, подключитесь снова Подключение к серверу аутентификации... Сервер не поддерживает выбранный метод аутентификации - %1$s не поддерживает множественные учётные записи + %1$s не поддерживает сразу несколько учётных записей Обновлять файл Переименовать Удалить - Вы в самом деле хотите удалить %1$s ? - Вы действительно хотите удалить %1$s и его содержимое ? + Вы действительно хотите удалить %1$s ? + Вы действительно хотите удалить %1$s и его содержимое? Только локально Только локальные данные Удалить с сервера - И удалённо и локально - Успешное удаление - Удаление не может быть завершено + Удалённо и локально + Удаление завершено + Ошибка удаления Введите новое имя Локальная копия не может быть переименована; попробуйте другое имя Переименование не может быть завершено Удаленный файл не может быть проверен Содержимое файла уже синхронизировано - Директория не может быть создана - Запрещённые символы: / \\ < > : \" | ? * + Каталог не может быть создан + Недопустимые символы: / \\ < > : \" | ? * Подождите немного - Неизвестная ошибка; попробуйте другое приложение для выбора файла + Неизвестная ошибка; выберите этот файл из другого приложения Файлы не выбраны - Подключать через oAuth2 + Отправить ссылку... + Войти через oAuth2 Подключение к серверу oAuth2... Подлинность сайта не может быть проверена - Сертификат сервера не является доверенным - Срок действия сертификата сервера истёк - - Сертификат сервера слишком новый - - Адрес не совпадает с именем в сертификате - Все-равно доверять данному сертификату? + - Срок действия сертификата сервера ещё не начался + - URL не совпадает с именем сервера в сертификате + Вы хотите доверять данному сертификату в любом случае? Сертификат не может быть сохранён - Детали - Спрятать - Выдано для: - Выдан: + Подробно + Скрыть + Кому выдано: + Кем выдано: Имя: Организация: Организационное подразделение: Страна: - Статус: + Штат: Местонахождение: Срок действия: - От: - До: + Из: + В: Подпись: Алгоритм: Это заполнитель placeholder.txt Изображение PNG - 389 KB + 389 КБ 2012/05/18 12:23 PM 12:23:45 - Загружать изображения только через WiFi + Загружать изображения только через Wi-Fi /InstantUpload Конфликт обновления - Удаленный файл %s не синхронизирован с локальным. Завершение приведет к замене содержания файла на сервере. - Оставить оба + Удаленный файл %s не синхронизирован с локальным. Продолжение приведет к замене содержимого файла на сервере. + Сохранить оба Заменить Не загружать Предпросмотр - Это изображение не может быть отображено - %1$s не может быть скопирован в %2$s локальною папку - Быстрая загрузка не удалась - Быстрые загрузки не удались - Список всех неудачных загрузок + Это изображение не может быть показано + %1$s не может быть скопирован в локальный каталог %2$s + Сбой немедленной загрузки + Сбой немедленной загрузки + Сводка по всем сбойным немедленным загрузкам Выбрать всё Ещё раз попробовать всё выделенное - Удалить всё| выбранное из очереди загрузки - Попробовать ещё раз загрузить изображение + Удалить выбранное из очереди загрузки + попробовать ещё раз загрузить изображение: Загрузить больше картинок - Ничего не делать, если не в сети - Сообщение об ошибке - Проверьте настройки сервера, возможно ваш лимит превышен + Ничего не делать, если нет подключения к сети + Сообщение об ошибке: + Проверьте настройки сервера, возможно ваш лимит исчерпан + Механизм общего доступа не включен на вашем сервере. Свяжитесь с администратором. + Невозможно предоставить доступ к этому файлу или каталогу. Убедитесь, что он существует + Ошибка предоставления общего доступа к этому файлу или каталогу + Ошибка удаления общего доступа к этому файлу или каталогу diff --git a/res/values-sk-rSK/strings.xml b/res/values-sk-rSK/strings.xml index 996544ed..0b173702 100644 --- a/res/values-sk-rSK/strings.xml +++ b/res/values-sk-rSK/strings.xml @@ -55,6 +55,7 @@ StiahnuÅ¥ ObnoviÅ¥ súbor Súbor bol premenovaný na %1$s počas nahrávania + ZdieľaÅ¥ linku Áno Nie OK diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml index b951d634..d61395ab 100644 --- a/res/values-sl/strings.xml +++ b/res/values-sl/strings.xml @@ -55,6 +55,8 @@ Prejmi Osveži datoteko Datoteka je bila med nalaganjem preimenovana v %1$s + Povezava za souporabo + Odstrani možnost souporabe Da Ne V redu @@ -179,6 +181,7 @@ Počakajte trenutek ... PriÅ¡lo je do nepričakovane napake. Poskusite datoteko izbrati z drugim programom. Ni izbranih datotek + PoÅ¡lji povezavo ... Prijava z oAuth2 Poteka povezovanje s strežnikom oAuth2 ... Istovetnosti strani ni mogoče preveriti @@ -230,4 +233,7 @@ ne poÅ¡lji takoj, saj je povezava v omrežje ni dejavna Sporočilo o napaki: Preverite nastavitve strežnika. Morda je presežena vrednost količinske omejitve. + Ni mogoče omogočiti souporabe te datoteke ali mape. Prepričajte se, da obstaja ... + PriÅ¡lo je do napake med poskusom omogočanja souporabe te datoteke ali mape + PriÅ¡lo je do napake med poskusom odstranjevanja souporabe te datoteke ali mape diff --git a/res/values-su/strings.xml b/res/values-su/strings.xml new file mode 100644 index 00000000..c757504a --- /dev/null +++ b/res/values-su/strings.xml @@ -0,0 +1,2 @@ + + diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml index af6e2590..79c98877 100644 --- a/res/values-sv/strings.xml +++ b/res/values-sv/strings.xml @@ -54,6 +54,7 @@ Ladda ner Ladda om fil Filen bytte namn till %1$s under uppladdningen + Dela länk Ja Nej OK diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml index 5db0dd50..0e920b4f 100644 --- a/res/values-tr/strings.xml +++ b/res/values-tr/strings.xml @@ -55,6 +55,8 @@ İndir Dosyayı yenile Dosya adı, yükleme sırasında %1$s olarak değiştirildi + Paylaşma bağlantısı + Bağlantı paylaşımını kaldır Evet Hayır OK @@ -179,6 +181,7 @@ Bir süre bekleyin Beklenmeyen problem ; lütfen, dosya seçmek için diğer uygulamayı deneyin Hiçbir dosya seçilmedi + Bağlantıyı gönder ... oAuth2 ile oturum aç oAuth2 sunucusuna bağlanılıyor… Bu sitenin sertifikası doğrulanamadı @@ -230,4 +233,8 @@ anında yükleme için çevrimiçi değilsiniz, bir şey yapma Hata Mesajı: Sunucu yapılandırmanızı kontrol edin. Kotanızı aşmış olabilirsiniz. + Üzgünüz, paylaşım sunucunuzda etkin değil. Lütfen yöneticinizle iletişime geçin. + Bu dosya veya klasör paylaşılamıyor. Lütfen mevcut olup olmadığını denetleyin + Bu dosya veya klasörü paylaşmaya çalışılırken bir hata oluştu + Bu dosya veya klasör paylaşımı kaldırılmaya çalışılırken bir hata oluştu diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml index a3adb7db..d0f4dfd7 100644 --- a/res/values-uk/strings.xml +++ b/res/values-uk/strings.xml @@ -38,6 +38,7 @@ Змінено: Завантажити Файл був переіменований в %1$s протягом вивантаження + Опублікувати посилання Так Ні OK diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml index 868c564b..0f1c0eee 100644 --- a/res/values-vi/strings.xml +++ b/res/values-vi/strings.xml @@ -55,6 +55,7 @@ Tải về Cập nhật lại tập tin Tập tin đã bị đổi tên thành %1$s trong quá trình tải lên + Chia sẻ liên kết Yes Không Chấp nhận diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml index 2b83a782..3b4f8ebb 100644 --- a/res/values-zh-rCN/strings.xml +++ b/res/values-zh-rCN/strings.xml @@ -1,5 +1,6 @@ + %1$s 安卓应用 版本:%1$s 刷新帐户 上传 @@ -18,7 +19,9 @@ 开启即时上传 即时上传相机拍摄的照片 开启日志 + 这过去是日志问题 日志历史 + 这显示已经保存的日志 删除历史 帮助 反馈 @@ -26,6 +29,7 @@ 检查服务器 用户名 密码 + 新增到 %1$s? 文件 连接 上传 @@ -45,7 +49,10 @@ 创建于: 已修改: 下载 + 刷新文件 上传过程中文件被更名为了 %1$s + 分享链接 + 取消共享链接 是 否 OK @@ -135,6 +142,9 @@ 无法建立连接 加密连接已建立 用户名或密码错误! + 认证不成功 + 访问被认证服务器拒绝 + 意外状态;请再次输入服务器的地址 请输入当前密码: 保证文件更新 重命名 @@ -156,6 +166,8 @@ 请稍候 未知问题;请试试用其他程序选择此文件 未选择文件。 + 发送链接给 … + 连接oAuth2 服务器... 站点身份无法验证 不受信任的服务器证书 服务器证书过期 @@ -204,4 +216,8 @@ 不在线时不开启即时上传 失败消息 请检查服务器设置。可能走出配额。 + 对不起,共享服务功能未开启,请联系管理员 + 无法共享该文件或目录,请确定该文件或目录存在 + 共享文件或目录出错 + 解除文件或目录共享时出错 diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml index bc0a2554..51fd70b1 100644 --- a/res/values-zh-rTW/strings.xml +++ b/res/values-zh-rTW/strings.xml @@ -51,6 +51,7 @@ 下載 更新檔案列表 檔案名稱在上傳時已被更改為 %1$s + 分享連結 是 否 好 diff --git a/res/values/setup.xml b/res/values/setup.xml index 226b6182..2e07ae4b 100644 --- a/res/values/setup.xml +++ b/res/values/setup.xml @@ -8,12 +8,14 @@ ownCloud owncloud Owncloud_ + / true true "https://owncloud.com/mobile/new" + off diff --git a/res/values/strings.xml b/res/values/strings.xml index 2c06bb82..b86d6085 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -59,6 +59,8 @@ Download Refresh file File was renamed to %1$s during upload + Share link + Unshare link Yes No OK @@ -186,6 +188,7 @@ Wait a moment "Unexpected problem ; please select the file from a different app" No file was selected + Send link to … Login with oAuth2 Connecting to oAuth2 server… @@ -243,4 +246,9 @@ do nothing you are not online for instant upload Failure Message: Please check your server configuration,maybe your quota is exceeded. + + Sorry, sharing is not enabled on your server. Please contact your administrator. + Unable to share this file or folder. Please, make sure it exists + An error occurred while trying to share this file or folder + An error occurred while trying to unshare this file or folder diff --git a/src/com/owncloud/android/authentication/AuthenticatorActivity.java b/src/com/owncloud/android/authentication/AuthenticatorActivity.java index d132ea3f..3a817d67 100644 --- a/src/com/owncloud/android/authentication/AuthenticatorActivity.java +++ b/src/com/owncloud/android/authentication/AuthenticatorActivity.java @@ -59,13 +59,15 @@ import com.owncloud.android.lib.accounts.OwnCloudAccount; import com.owncloud.android.lib.network.OwnCloudClientFactory; import com.owncloud.android.lib.network.OwnCloudClient; import com.owncloud.android.operations.OAuth2GetAccessToken; + import com.owncloud.android.lib.operations.common.OnRemoteOperationListener; -import com.owncloud.android.operations.OwnCloudServerCheckOperation; +import com.owncloud.android.lib.operations.remote.OwnCloudServerCheckOperation; import com.owncloud.android.lib.operations.common.RemoteOperation; import com.owncloud.android.lib.operations.common.RemoteOperationResult; import com.owncloud.android.lib.operations.common.RemoteOperationResult.ResultCode; import com.owncloud.android.lib.operations.remote.ExistenceCheckRemoteOperation; import com.owncloud.android.lib.operations.remote.GetUserNameRemoteOperation; + import com.owncloud.android.ui.dialog.SamlWebViewDialog; import com.owncloud.android.ui.dialog.SslValidatorDialog; import com.owncloud.android.ui.dialog.SslValidatorDialog.OnSslValidatorListener; @@ -104,6 +106,7 @@ implements OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList private static final String KEY_AUTH_STATUS_TEXT = "AUTH_STATUS_TEXT"; private static final String KEY_AUTH_STATUS_ICON = "AUTH_STATUS_ICON"; private static final String KEY_REFRESH_BUTTON_ENABLED = "KEY_REFRESH_BUTTON_ENABLED"; + private static final String KEY_IS_SHARED_SUPPORTED = "KEY_IS_SHARE_SUPPORTED"; private static final String AUTH_ON = "on"; private static final String AUTH_OFF = "off"; @@ -121,6 +124,7 @@ implements OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList private String mHostBaseUrl; private OwnCloudVersion mDiscoveredVersion; + private boolean mIsSharedSupported; private String mAuthMessageText; private int mAuthMessageVisibility, mServerStatusText, mServerStatusIcon; @@ -231,6 +235,7 @@ implements OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList mServerIsChecked = false; mIsSslConn = false; mAuthStatusText = mAuthStatusIcon = 0; + mIsSharedSupported = false; /// retrieve extras from intent mAccount = getIntent().getExtras().getParcelable(EXTRA_ACCOUNT); @@ -243,6 +248,8 @@ implements OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList mHostUrlInput.setText(mHostBaseUrl); String userName = mAccount.name.substring(0, mAccount.name.lastIndexOf('@')); mUsernameInput.setText(userName); + mIsSharedSupported = Boolean.getBoolean(mAccountMgr.getUserData(mAccount, OwnCloudAccount.Constants.KEY_SUPPORTS_SHARE_API)); + } initAuthorizationMethod(); // checks intent and setup.xml to determine mCurrentAuthorizationMethod mJustCreated = true; @@ -269,6 +276,7 @@ implements OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList /// server data String ocVersion = savedInstanceState.getString(KEY_OC_VERSION); + mIsSharedSupported = savedInstanceState.getBoolean(KEY_IS_SHARED_SUPPORTED, false); if (ocVersion != null) { mDiscoveredVersion = new OwnCloudVersion(ocVersion); } @@ -448,6 +456,7 @@ implements OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList outState.putString(KEY_OC_VERSION, mDiscoveredVersion.toString()); } outState.putString(KEY_HOST_URL_TEXT, mHostBaseUrl); + outState.putBoolean(KEY_IS_SHARED_SUPPORTED, mIsSharedSupported); /// account data, if updating if (mAccount != null) { @@ -582,6 +591,7 @@ implements OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList mServerIsValid = false; mServerIsChecked = false; + mIsSharedSupported = false; mOkButton.setEnabled(false); mDiscoveredVersion = null; hideRefreshButton(); @@ -895,6 +905,9 @@ implements OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList /// allow or not the user try to access the server mOkButton.setEnabled(mServerIsValid); + + /// retrieve if is supported the Share API + mIsSharedSupported = operation.isSharedSupported(); } // else nothing ; only the last check operation is considered; // multiple can be triggered if the user amends a URL before a previous check can be triggered @@ -1288,6 +1301,7 @@ implements OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList /// add user data to the new account; TODO probably can be done in the last parameter addAccountExplicitly, or in KEY_USERDATA mAccountMgr.setUserData(mAccount, OwnCloudAccount.Constants.KEY_OC_VERSION, mDiscoveredVersion.toString()); mAccountMgr.setUserData(mAccount, OwnCloudAccount.Constants.KEY_OC_BASE_URL, mHostBaseUrl); + mAccountMgr.setUserData(mAccount, OwnCloudAccount.Constants.KEY_SUPPORTS_SHARE_API, Boolean.toString(mIsSharedSupported)); if (isSaml) { mAccountMgr.setUserData(mAccount, OwnCloudAccount.Constants.KEY_SUPPORTS_SAML_WEB_SSO, "TRUE"); } else if (isOAuth) { diff --git a/src/com/owncloud/android/datamodel/FileDataStorageManager.java b/src/com/owncloud/android/datamodel/FileDataStorageManager.java index 042709a1..d1e26034 100644 --- a/src/com/owncloud/android/datamodel/FileDataStorageManager.java +++ b/src/com/owncloud/android/datamodel/FileDataStorageManager.java @@ -27,6 +27,9 @@ import java.util.Vector; import com.owncloud.android.MainApp; import com.owncloud.android.db.ProviderMeta.ProviderTableMeta; +import com.owncloud.android.lib.operations.common.OCShare; +import com.owncloud.android.lib.operations.common.ShareType; +import com.owncloud.android.lib.utils.FileUtils; import com.owncloud.android.utils.FileStorageUtils; import com.owncloud.android.utils.Log_OC; @@ -181,7 +184,9 @@ public class FileDataStorageManager { cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA, file.getLastSyncDateForData()); cv.put(ProviderTableMeta.FILE_KEEP_IN_SYNC, file.keepInSync() ? 1 : 0); cv.put(ProviderTableMeta.FILE_ETAG, file.getEtag()); - + cv.put(ProviderTableMeta.FILE_SHARE_BY_LINK, file.isShareByLink() ? 1 : 0); + cv.put(ProviderTableMeta.FILE_PUBLIC_LINK, file.getPublicLink()); + boolean sameRemotePath = fileExists(file.getRemotePath()); if (sameRemotePath || fileExists(file.getFileId()) ) { // for renamed files; no more delete and create @@ -278,6 +283,8 @@ public class FileDataStorageManager { cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA, file.getLastSyncDateForData()); cv.put(ProviderTableMeta.FILE_KEEP_IN_SYNC, file.keepInSync() ? 1 : 0); cv.put(ProviderTableMeta.FILE_ETAG, file.getEtag()); + cv.put(ProviderTableMeta.FILE_SHARE_BY_LINK, file.isShareByLink() ? 1 : 0); + cv.put(ProviderTableMeta.FILE_PUBLIC_LINK, file.getPublicLink()); boolean existsByPath = fileExists(file.getRemotePath()); if (existsByPath || fileExists(file.getFileId())) { @@ -333,6 +340,9 @@ public class FileDataStorageManager { cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA, folder.getLastSyncDateForData()); cv.put(ProviderTableMeta.FILE_KEEP_IN_SYNC, folder.keepInSync() ? 1 : 0); cv.put(ProviderTableMeta.FILE_ETAG, folder.getEtag()); + cv.put(ProviderTableMeta.FILE_SHARE_BY_LINK, folder.isShareByLink() ? 1 : 0); + cv.put(ProviderTableMeta.FILE_PUBLIC_LINK, folder.getPublicLink()); + operations.add(ContentProviderOperation.newUpdate(ProviderTableMeta.CONTENT_URI). withValues(cv). withSelection( ProviderTableMeta._ID + "=?", @@ -663,6 +673,32 @@ public class FileDataStorageManager { } return c; } + + private Cursor getShareCursorForValue(String key, String value) { + Cursor c = null; + if (getContentResolver() != null) { + c = getContentResolver() + .query(ProviderTableMeta.CONTENT_URI_SHARE, + null, + key + "=? AND " + + ProviderTableMeta.OCSHARES_ACCOUNT_OWNER + + "=?", + new String[] { value, mAccount.name }, null); + } else { + try { + c = getContentProviderClient().query( + ProviderTableMeta.CONTENT_URI_SHARE, + null, + key + "=? AND " + ProviderTableMeta.OCSHARES_ACCOUNT_OWNER + + "=?", new String[] { value, mAccount.name }, + null); + } catch (RemoteException e) { + Log_OC.e(TAG, "Could not get file details: " + e.getMessage()); + c = null; + } + } + return c; + } private OCFile createFileInstance(Cursor c) { OCFile file = null; @@ -701,9 +737,529 @@ public class FileDataStorageManager { file.setKeepInSync(c.getInt( c.getColumnIndex(ProviderTableMeta.FILE_KEEP_IN_SYNC)) == 1 ? true : false); file.setEtag(c.getString(c.getColumnIndex(ProviderTableMeta.FILE_ETAG))); + file.setShareByLink(c.getInt( + c.getColumnIndex(ProviderTableMeta.FILE_SHARE_BY_LINK)) == 1 ? true : false); + file.setPublicLink(c.getString(c.getColumnIndex(ProviderTableMeta.FILE_PUBLIC_LINK))); } return file; } + + /** + * Returns if the file/folder is shared by link or not + * @param path Path of the file/folder + * @return + */ + public boolean isShareByLink(String path) { + Cursor c = getCursorForValue(ProviderTableMeta.FILE_STORAGE_PATH, path); + OCFile file = null; + if (c.moveToFirst()) { + file = createFileInstance(c); + } + c.close(); + return file.isShareByLink(); + } + + /** + * Returns the public link of the file/folder + * @param path Path of the file/folder + * @return + */ + public String getPublicLink(String path) { + Cursor c = getCursorForValue(ProviderTableMeta.FILE_STORAGE_PATH, path); + OCFile file = null; + if (c.moveToFirst()) { + file = createFileInstance(c); + } + c.close(); + return file.getPublicLink(); + } + + + // Methods for Shares + public boolean saveShare(OCShare share) { + boolean overriden = false; + ContentValues cv = new ContentValues(); + cv.put(ProviderTableMeta.OCSHARES_FILE_SOURCE, share.getFileSource()); + cv.put(ProviderTableMeta.OCSHARES_ITEM_SOURCE, share.getItemSource()); + cv.put(ProviderTableMeta.OCSHARES_SHARE_TYPE, share.getShareType().getValue()); + cv.put(ProviderTableMeta.OCSHARES_SHARE_WITH, share.getShareWith()); + cv.put(ProviderTableMeta.OCSHARES_PATH, share.getPath()); + cv.put(ProviderTableMeta.OCSHARES_PERMISSIONS, share.getPermissions()); + cv.put(ProviderTableMeta.OCSHARES_SHARED_DATE, share.getSharedDate()); + cv.put(ProviderTableMeta.OCSHARES_EXPIRATION_DATE, share.getExpirationDate()); + cv.put(ProviderTableMeta.OCSHARES_TOKEN, share.getToken()); + cv.put(ProviderTableMeta.OCSHARES_SHARE_WITH_DISPLAY_NAME, share.getSharedWithDisplayName()); + cv.put(ProviderTableMeta.OCSHARES_IS_DIRECTORY, share.isFolder() ? 1 : 0); + cv.put(ProviderTableMeta.OCSHARES_USER_ID, share.getUserId()); + cv.put(ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED, share.getIdRemoteShared()); + cv.put(ProviderTableMeta.OCSHARES_ACCOUNT_OWNER, mAccount.name); + + if (shareExists(share.getIdRemoteShared())) { // for renamed files; no more delete and create + + overriden = true; + if (getContentResolver() != null) { + getContentResolver().update(ProviderTableMeta.CONTENT_URI_SHARE, cv, + ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED + "=?", + new String[] { String.valueOf(share.getIdRemoteShared()) }); + } else { + try { + getContentProviderClient().update(ProviderTableMeta.CONTENT_URI_SHARE, + cv, ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED + "=?", + new String[] { String.valueOf(share.getIdRemoteShared()) }); + } catch (RemoteException e) { + Log_OC.e(TAG, + "Fail to insert insert file to database " + + e.getMessage()); + } + } + } else { + Uri result_uri = null; + if (getContentResolver() != null) { + result_uri = getContentResolver().insert( + ProviderTableMeta.CONTENT_URI_SHARE, cv); + } else { + try { + result_uri = getContentProviderClient().insert( + ProviderTableMeta.CONTENT_URI_SHARE, cv); + } catch (RemoteException e) { + Log_OC.e(TAG, + "Fail to insert insert file to database " + + e.getMessage()); + } + } + if (result_uri != null) { + long new_id = Long.parseLong(result_uri.getPathSegments() + .get(1)); + share.setId(new_id); + } + } + + return overriden; + } + + private OCShare getShareById(long id) { + Cursor c = getShareCursorForValue(ProviderTableMeta._ID, String.valueOf(id)); + OCShare share = null; + if (c.moveToFirst()) { + share = createShareInstance(c); + } + c.close(); + return share; + } + + private OCShare getShareByRemoteId(long remoteId) { + Cursor c = getShareCursorForValue(ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED, String.valueOf(remoteId)); + OCShare share = null; + if (c.moveToFirst()) { + share = createShareInstance(c); + } + c.close(); + return share; + } + + public OCShare getShareByPath(String path) { + Cursor c = getShareCursorForValue(ProviderTableMeta.OCSHARES_PATH, path); + OCShare share = null; + if (c.moveToFirst()) { + share = createShareInstance(c); + } + c.close(); + return share; + } + + private OCShare createShareInstance(Cursor c) { + OCShare share = null; + if (c != null) { + share = new OCShare(c.getString(c + .getColumnIndex(ProviderTableMeta.OCSHARES_PATH))); + share.setId(c.getLong(c.getColumnIndex(ProviderTableMeta._ID))); + share.setFileSource(c.getLong(c + .getColumnIndex(ProviderTableMeta.OCSHARES_ITEM_SOURCE))); + share.setShareType(ShareType.fromValue(c.getInt(c + .getColumnIndex(ProviderTableMeta.OCSHARES_SHARE_TYPE)))); + share.setPermissions(c.getInt(c + .getColumnIndex(ProviderTableMeta.OCSHARES_PERMISSIONS))); + share.setSharedDate(c.getLong(c + .getColumnIndex(ProviderTableMeta.OCSHARES_SHARED_DATE))); + share.setExpirationDate(c.getLong(c + .getColumnIndex(ProviderTableMeta.OCSHARES_EXPIRATION_DATE))); + share.setToken(c.getString(c + .getColumnIndex(ProviderTableMeta.OCSHARES_TOKEN))); + share.setSharedWithDisplayName(c.getString(c + .getColumnIndex(ProviderTableMeta.OCSHARES_SHARE_WITH_DISPLAY_NAME))); + share.setIsFolder(c.getInt( + c.getColumnIndex(ProviderTableMeta.OCSHARES_IS_DIRECTORY)) == 1 ? true : false); + share.setUserId(c.getLong(c.getColumnIndex(ProviderTableMeta.OCSHARES_USER_ID))); + share.setIdRemoteShared(c.getLong(c.getColumnIndex(ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED))); + + } + return share; + } + + private boolean shareExists(String cmp_key, String value) { + Cursor c; + if (getContentResolver() != null) { + c = getContentResolver() + .query(ProviderTableMeta.CONTENT_URI_SHARE, + null, + cmp_key + "=? AND " + + ProviderTableMeta.OCSHARES_ACCOUNT_OWNER + + "=?", + new String[] { value, mAccount.name }, null); + } else { + try { + c = getContentProviderClient().query( + ProviderTableMeta.CONTENT_URI_SHARE, + null, + cmp_key + "=? AND " + + ProviderTableMeta.OCSHARES_ACCOUNT_OWNER + "=?", + new String[] { value, mAccount.name }, null); + } catch (RemoteException e) { + Log_OC.e(TAG, + "Couldn't determine file existance, assuming non existance: " + + e.getMessage()); + return false; + } + } + boolean retval = c.moveToFirst(); + c.close(); + return retval; + } + + private boolean shareExists(long remoteId) { + return shareExists(ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED, String.valueOf(remoteId)); + } + + private void cleanSharedFiles() { + ContentValues cv = new ContentValues(); + cv.put(ProviderTableMeta.FILE_SHARE_BY_LINK, false); + cv.put(ProviderTableMeta.FILE_PUBLIC_LINK, ""); + String where = ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?"; + String [] whereArgs = new String[]{mAccount.name}; + + if (getContentResolver() != null) { + getContentResolver().update(ProviderTableMeta.CONTENT_URI, cv, where, whereArgs); + + } else { + try { + getContentProviderClient().update(ProviderTableMeta.CONTENT_URI, cv, where, whereArgs); + + } catch (RemoteException e) { + Log_OC.e(TAG, "Exception in cleanSharedFiles" + e.getMessage()); + } + } + } + + private void cleanSharedFilesInFolder(OCFile folder) { + ContentValues cv = new ContentValues(); + cv.put(ProviderTableMeta.FILE_SHARE_BY_LINK, false); + cv.put(ProviderTableMeta.FILE_PUBLIC_LINK, ""); + String where = ProviderTableMeta.FILE_ACCOUNT_OWNER + "=? AND " + ProviderTableMeta.FILE_PARENT + "=?"; + String [] whereArgs = new String[] { mAccount.name , String.valueOf(folder.getFileId()) }; + + if (getContentResolver() != null) { + getContentResolver().update(ProviderTableMeta.CONTENT_URI, cv, where, whereArgs); + + } else { + try { + getContentProviderClient().update(ProviderTableMeta.CONTENT_URI, cv, where, whereArgs); + + } catch (RemoteException e) { + Log_OC.e(TAG, "Exception in cleanSharedFilesInFolder " + e.getMessage()); + } + } + } + + private void cleanShares() { + String where = ProviderTableMeta.OCSHARES_ACCOUNT_OWNER + "=?"; + String [] whereArgs = new String[]{mAccount.name}; + + if (getContentResolver() != null) { + getContentResolver().delete(ProviderTableMeta.CONTENT_URI_SHARE, where, whereArgs); + + } else { + try { + getContentProviderClient().delete(ProviderTableMeta.CONTENT_URI_SHARE, where, whereArgs); + + } catch (RemoteException e) { + Log_OC.e(TAG, "Exception in cleanShares" + e.getMessage()); + } + } + } + + public void saveShares(Collection shares) { + cleanShares(); + if (shares != null) { + ArrayList operations = new ArrayList(shares.size()); + + // prepare operations to insert or update files to save in the given folder + for (OCShare share : shares) { + ContentValues cv = new ContentValues(); + cv.put(ProviderTableMeta.OCSHARES_FILE_SOURCE, share.getFileSource()); + cv.put(ProviderTableMeta.OCSHARES_ITEM_SOURCE, share.getItemSource()); + cv.put(ProviderTableMeta.OCSHARES_SHARE_TYPE, share.getShareType().getValue()); + cv.put(ProviderTableMeta.OCSHARES_SHARE_WITH, share.getShareWith()); + cv.put(ProviderTableMeta.OCSHARES_PATH, share.getPath()); + cv.put(ProviderTableMeta.OCSHARES_PERMISSIONS, share.getPermissions()); + cv.put(ProviderTableMeta.OCSHARES_SHARED_DATE, share.getSharedDate()); + cv.put(ProviderTableMeta.OCSHARES_EXPIRATION_DATE, share.getExpirationDate()); + cv.put(ProviderTableMeta.OCSHARES_TOKEN, share.getToken()); + cv.put(ProviderTableMeta.OCSHARES_SHARE_WITH_DISPLAY_NAME, share.getSharedWithDisplayName()); + cv.put(ProviderTableMeta.OCSHARES_IS_DIRECTORY, share.isFolder() ? 1 : 0); + cv.put(ProviderTableMeta.OCSHARES_USER_ID, share.getUserId()); + cv.put(ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED, share.getIdRemoteShared()); + cv.put(ProviderTableMeta.OCSHARES_ACCOUNT_OWNER, mAccount.name); + + if (shareExists(share.getIdRemoteShared())) { + // updating an existing file + operations.add(ContentProviderOperation.newUpdate(ProviderTableMeta.CONTENT_URI_SHARE). + withValues(cv). + withSelection( ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED + "=?", + new String[] { String.valueOf(share.getIdRemoteShared()) }) + .build()); + + } else { + // adding a new file + operations.add(ContentProviderOperation.newInsert(ProviderTableMeta.CONTENT_URI_SHARE).withValues(cv).build()); + } + } + + // apply operations in batch + if (operations.size() > 0) { + @SuppressWarnings("unused") + ContentProviderResult[] results = null; + Log_OC.d(TAG, "Sending " + operations.size() + " operations to FileContentProvider"); + try { + if (getContentResolver() != null) { + results = getContentResolver().applyBatch(MainApp.getAuthority(), operations); + + } else { + results = getContentProviderClient().applyBatch(operations); + } + + } catch (OperationApplicationException e) { + Log_OC.e(TAG, "Exception in batch of operations " + e.getMessage()); + + } catch (RemoteException e) { + Log_OC.e(TAG, "Exception in batch of operations " + e.getMessage()); + } + } + } + + } + + public void updateSharedFiles(Collection sharedFiles) { + cleanSharedFiles(); + + if (sharedFiles != null) { + ArrayList operations = new ArrayList(sharedFiles.size()); + + // prepare operations to insert or update files to save in the given folder + for (OCFile file : sharedFiles) { + ContentValues cv = new ContentValues(); + cv.put(ProviderTableMeta.FILE_MODIFIED, file.getModificationTimestamp()); + cv.put(ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA, file.getModificationTimestampAtLastSyncForData()); + cv.put(ProviderTableMeta.FILE_CREATION, file.getCreationTimestamp()); + cv.put(ProviderTableMeta.FILE_CONTENT_LENGTH, file.getFileLength()); + cv.put(ProviderTableMeta.FILE_CONTENT_TYPE, file.getMimetype()); + cv.put(ProviderTableMeta.FILE_NAME, file.getFileName()); + cv.put(ProviderTableMeta.FILE_PARENT, file.getParentId()); + cv.put(ProviderTableMeta.FILE_PATH, file.getRemotePath()); + if (!file.isFolder()) { + cv.put(ProviderTableMeta.FILE_STORAGE_PATH, file.getStoragePath()); + } + cv.put(ProviderTableMeta.FILE_ACCOUNT_OWNER, mAccount.name); + cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE, file.getLastSyncDateForProperties()); + cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA, file.getLastSyncDateForData()); + cv.put(ProviderTableMeta.FILE_KEEP_IN_SYNC, file.keepInSync() ? 1 : 0); + cv.put(ProviderTableMeta.FILE_ETAG, file.getEtag()); + cv.put(ProviderTableMeta.FILE_SHARE_BY_LINK, file.isShareByLink() ? 1 : 0); + cv.put(ProviderTableMeta.FILE_PUBLIC_LINK, file.getPublicLink()); + + boolean existsByPath = fileExists(file.getRemotePath()); + if (existsByPath || fileExists(file.getFileId())) { + // updating an existing file + operations.add(ContentProviderOperation.newUpdate(ProviderTableMeta.CONTENT_URI). + withValues(cv). + withSelection( ProviderTableMeta._ID + "=?", + new String[] { String.valueOf(file.getFileId()) }) + .build()); + } else { + // adding a new file + operations.add(ContentProviderOperation.newInsert(ProviderTableMeta.CONTENT_URI).withValues(cv).build()); + } + } + + // apply operations in batch + if (operations.size() > 0) { + @SuppressWarnings("unused") + ContentProviderResult[] results = null; + Log_OC.d(TAG, "Sending " + operations.size() + " operations to FileContentProvider"); + try { + if (getContentResolver() != null) { + results = getContentResolver().applyBatch(MainApp.getAuthority(), operations); + + } else { + results = getContentProviderClient().applyBatch(operations); + } + + } catch (OperationApplicationException e) { + Log_OC.e(TAG, "Exception in batch of operations " + e.getMessage()); + + } catch (RemoteException e) { + Log_OC.e(TAG, "Exception in batch of operations " + e.getMessage()); + } + } + } + + } + + + public void saveSharesDB(ArrayList shares) { + saveShares(shares); + + ArrayList sharedFiles = new ArrayList(); + + for (OCShare share : shares) { + // Get the path + String path = share.getPath(); + if (share.isFolder()) { + path = path + FileUtils.PATH_SEPARATOR; + } + + // Update OCFile with data from share: ShareByLink ¿and publicLink? + OCFile file = getFileByPath(path); + if (file != null) { + if (share.getShareType().equals(ShareType.PUBLIC_LINK)) { + file.setShareByLink(true); + sharedFiles.add(file); + } + } + } + + updateSharedFiles(sharedFiles); + } + + + public void saveSharesInFolder(ArrayList shares, OCFile folder) { + cleanSharedFilesInFolder(folder); + ArrayList operations = new ArrayList(); + operations = prepareRemoveSharesInFolder(folder, operations); + + if (shares != null) { + // prepare operations to insert or update files to save in the given folder + for (OCShare share : shares) { + ContentValues cv = new ContentValues(); + cv.put(ProviderTableMeta.OCSHARES_FILE_SOURCE, share.getFileSource()); + cv.put(ProviderTableMeta.OCSHARES_ITEM_SOURCE, share.getItemSource()); + cv.put(ProviderTableMeta.OCSHARES_SHARE_TYPE, share.getShareType().getValue()); + cv.put(ProviderTableMeta.OCSHARES_SHARE_WITH, share.getShareWith()); + cv.put(ProviderTableMeta.OCSHARES_PATH, share.getPath()); + cv.put(ProviderTableMeta.OCSHARES_PERMISSIONS, share.getPermissions()); + cv.put(ProviderTableMeta.OCSHARES_SHARED_DATE, share.getSharedDate()); + cv.put(ProviderTableMeta.OCSHARES_EXPIRATION_DATE, share.getExpirationDate()); + cv.put(ProviderTableMeta.OCSHARES_TOKEN, share.getToken()); + cv.put(ProviderTableMeta.OCSHARES_SHARE_WITH_DISPLAY_NAME, share.getSharedWithDisplayName()); + cv.put(ProviderTableMeta.OCSHARES_IS_DIRECTORY, share.isFolder() ? 1 : 0); + cv.put(ProviderTableMeta.OCSHARES_USER_ID, share.getUserId()); + cv.put(ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED, share.getIdRemoteShared()); + cv.put(ProviderTableMeta.OCSHARES_ACCOUNT_OWNER, mAccount.name); + + /* + if (shareExists(share.getIdRemoteShared())) { + // updating an existing share resource + operations.add(ContentProviderOperation.newUpdate(ProviderTableMeta.CONTENT_URI_SHARE). + withValues(cv). + withSelection( ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED + "=?", + new String[] { String.valueOf(share.getIdRemoteShared()) }) + .build()); + + } else { + */ + // adding a new share resource + operations.add(ContentProviderOperation.newInsert(ProviderTableMeta.CONTENT_URI_SHARE).withValues(cv).build()); + //} + } + } + + // apply operations in batch + if (operations.size() > 0) { + @SuppressWarnings("unused") + ContentProviderResult[] results = null; + Log_OC.d(TAG, "Sending " + operations.size() + " operations to FileContentProvider"); + try { + if (getContentResolver() != null) { + results = getContentResolver().applyBatch(MainApp.getAuthority(), operations); + + } else { + results = getContentProviderClient().applyBatch(operations); + } + + } catch (OperationApplicationException e) { + Log_OC.e(TAG, "Exception in batch of operations " + e.getMessage()); + + } catch (RemoteException e) { + Log_OC.e(TAG, "Exception in batch of operations " + e.getMessage()); + } + } + //} + + } + + private ArrayList prepareRemoveSharesInFolder(OCFile folder, ArrayList preparedOperations) { + if (folder != null) { + String where = ProviderTableMeta.OCSHARES_PATH + "=?" + " AND " + ProviderTableMeta.OCSHARES_ACCOUNT_OWNER + "=?"; + String [] whereArgs = new String[]{ "", mAccount.name }; + + Vector files = getFolderContent(folder); + + for (OCFile file : files) { + whereArgs[0] = file.getRemotePath(); + preparedOperations.add(ContentProviderOperation.newDelete(ProviderTableMeta.CONTENT_URI_SHARE) + .withSelection(where, whereArgs) + .build()); + } + } + return preparedOperations; + + /* + if (operations.size() > 0) { + try { + if (getContentResolver() != null) { + getContentResolver().applyBatch(MainApp.getAuthority(), operations); + + } else { + getContentProviderClient().applyBatch(operations); + } + + } catch (OperationApplicationException e) { + Log_OC.e(TAG, "Exception in batch of operations " + e.getMessage()); + + } catch (RemoteException e) { + Log_OC.e(TAG, "Exception in batch of operations " + e.getMessage()); + } + } + */ + + /* + if (getContentResolver() != null) { + + getContentResolver().delete(ProviderTableMeta.CONTENT_URI_SHARE, + where, + whereArgs); + } else { + try { + getContentProviderClient().delete( ProviderTableMeta.CONTENT_URI_SHARE, + where, + whereArgs); + + } catch (RemoteException e) { + Log_OC.e(TAG, "Exception deleting shares in a folder " + e.getMessage()); + } + } + */ + //} + } } diff --git a/src/com/owncloud/android/datamodel/OCFile.java b/src/com/owncloud/android/datamodel/OCFile.java index a6e6a546..82c341ca 100644 --- a/src/com/owncloud/android/datamodel/OCFile.java +++ b/src/com/owncloud/android/datamodel/OCFile.java @@ -61,6 +61,9 @@ public class OCFile implements Parcelable, Comparable { private boolean mKeepInSync; private String mEtag; + + private boolean mShareByLink; + private String mPublicLink; /** @@ -99,6 +102,8 @@ public class OCFile implements Parcelable, Comparable { mLastSyncDateForProperties = source.readLong(); mLastSyncDateForData = source.readLong(); mEtag = source.readString(); + mShareByLink = source.readInt() == 1; + mPublicLink = source.readString(); } @Override @@ -117,6 +122,8 @@ public class OCFile implements Parcelable, Comparable { dest.writeLong(mLastSyncDateForProperties); dest.writeLong(mLastSyncDateForData); dest.writeString(mEtag); + dest.writeInt(mShareByLink ? 1 : 0); + dest.writeString(mPublicLink); } /** @@ -325,6 +332,8 @@ public class OCFile implements Parcelable, Comparable { mKeepInSync = false; mNeedsUpdating = false; mEtag = null; + mShareByLink = false; + mPublicLink = null; } /** @@ -445,7 +454,7 @@ public class OCFile implements Parcelable, Comparable { @Override public String toString() { - String asString = "[id=%s, name=%s, mime=%s, downloaded=%s, local=%s, remote=%s, parentId=%s, keepInSinc=%s etag=%s]"; + String asString = "[id=%s, name=%s, mime=%s, downloaded=%s, local=%s, remote=%s, parentId=%s, keepInSync=%s etag=%s]"; asString = String.format(asString, Long.valueOf(mId), getFileName(), mMimeType, isDown(), mLocalPath, mRemotePath, Long.valueOf(mParentId), Boolean.valueOf(mKeepInSync), mEtag); return asString; } @@ -458,6 +467,23 @@ public class OCFile implements Parcelable, Comparable { this.mEtag = etag; } + + public boolean isShareByLink() { + return mShareByLink; + } + + public void setShareByLink(boolean shareByLink) { + this.mShareByLink = shareByLink; + } + + public String getPublicLink() { + return mPublicLink; + } + + public void setPublicLink(String publicLink) { + this.mPublicLink = publicLink; + } + public long getLocalModificationTimestamp() { if (mLocalPath != null && mLocalPath.length() > 0) { File f = new File(mLocalPath); diff --git a/src/com/owncloud/android/db/ProviderMeta.java b/src/com/owncloud/android/db/ProviderMeta.java index 8701ebd2..2101a688 100644 --- a/src/com/owncloud/android/db/ProviderMeta.java +++ b/src/com/owncloud/android/db/ProviderMeta.java @@ -30,28 +30,28 @@ import android.provider.BaseColumns; */ public class ProviderMeta { - /* These constants are now in MainApp - public static final String AUTHORITY_FILES = "org.owncloud"; - public static final String DB_FILE = "owncloud.db"; - */ public static final String DB_NAME = "filelist"; - public static final int DB_VERSION = 5; + public static final int DB_VERSION = 6; private ProviderMeta() { } static public class ProviderTableMeta implements BaseColumns { - public static final String DB_NAME = "filelist"; + public static final String FILE_TABLE_NAME = "filelist"; + public static final String OCSHARES_TABLE_NAME = "ocshares"; public static final Uri CONTENT_URI = Uri.parse("content://" + MainApp.getAuthority() + "/"); public static final Uri CONTENT_URI_FILE = Uri.parse("content://" + MainApp.getAuthority() + "/file"); public static final Uri CONTENT_URI_DIR = Uri.parse("content://" + MainApp.getAuthority() + "/dir"); + public static final Uri CONTENT_URI_SHARE = Uri.parse("content://" + + MainApp.getAuthority() + "/shares"); public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.owncloud.file"; public static final String CONTENT_TYPE_ITEM = "vnd.android.cursor.item/vnd.owncloud.file"; + // Columns of filelist table public static final String FILE_PARENT = "parent"; public static final String FILE_NAME = "filename"; public static final String FILE_CREATION = "created"; @@ -66,9 +66,31 @@ public class ProviderMeta { public static final String FILE_LAST_SYNC_DATE_FOR_DATA = "last_sync_date_for_data"; public static final String FILE_KEEP_IN_SYNC = "keep_in_sync"; public static final String FILE_ETAG = "etag"; + public static final String FILE_SHARE_BY_LINK = "share_by_link"; + public static final String FILE_PUBLIC_LINK = "public_link"; - public static final String DEFAULT_SORT_ORDER = FILE_NAME + public static final String FILE_DEFAULT_SORT_ORDER = FILE_NAME + " collate nocase asc"; + + // Columns of ocshares table + public static final String OCSHARES_FILE_SOURCE = "file_source"; + public static final String OCSHARES_ITEM_SOURCE = "item_source"; + public static final String OCSHARES_SHARE_TYPE = "share_type"; + public static final String OCSHARES_SHARE_WITH = "shate_with"; + public static final String OCSHARES_PATH = "path"; + public static final String OCSHARES_PERMISSIONS = "permissions"; + public static final String OCSHARES_SHARED_DATE = "shared_date"; + public static final String OCSHARES_EXPIRATION_DATE = "expiration_date"; + public static final String OCSHARES_TOKEN = "token"; + public static final String OCSHARES_SHARE_WITH_DISPLAY_NAME = "shared_with_display_name"; + public static final String OCSHARES_IS_DIRECTORY = "is_directory"; + public static final String OCSHARES_USER_ID = "user_id"; + public static final String OCSHARES_ID_REMOTE_SHARED = "id_remote_shared"; + public static final String OCSHARES_ACCOUNT_OWNER = "owner_share"; + + public static final String OCSHARES_DEFAULT_SORT_ORDER = OCSHARES_FILE_SOURCE + + " collate nocase asc"; + } } diff --git a/src/com/owncloud/android/files/FileHandler.java b/src/com/owncloud/android/files/FileHandler.java deleted file mode 100644 index 2eb754dd..00000000 --- a/src/com/owncloud/android/files/FileHandler.java +++ /dev/null @@ -1,30 +0,0 @@ -/* ownCloud Android client application - * Copyright (C) 2012-2013 ownCloud Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ - -package com.owncloud.android.files; - -import com.owncloud.android.datamodel.OCFile; - -public interface FileHandler { - - /** - * TODO - */ - public void openFile(OCFile file); - - -} diff --git a/src/com/owncloud/android/files/FileOperationsHelper.java b/src/com/owncloud/android/files/FileOperationsHelper.java new file mode 100644 index 00000000..ab8395cd --- /dev/null +++ b/src/com/owncloud/android/files/FileOperationsHelper.java @@ -0,0 +1,143 @@ +/* ownCloud Android client application + * Copyright (C) 2012-2014 ownCloud Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package com.owncloud.android.files; + +import org.apache.http.protocol.HTTP; + +import android.accounts.AccountManager; +import android.content.Intent; +import android.net.Uri; +import android.support.v4.app.DialogFragment; +import android.webkit.MimeTypeMap; +import android.widget.Toast; + +import com.owncloud.android.R; +import com.owncloud.android.datamodel.OCFile; +import com.owncloud.android.lib.accounts.OwnCloudAccount; +import com.owncloud.android.lib.network.webdav.WebdavUtils; +import com.owncloud.android.lib.operations.common.ShareType; +import com.owncloud.android.operations.CreateShareOperation; +import com.owncloud.android.ui.activity.FileActivity; +import com.owncloud.android.ui.dialog.ActivityChooserDialog; +import com.owncloud.android.utils.Log_OC; + +/** + * + * @author masensio + * @author David A. Velasco + */ +public class FileOperationsHelper { + + private static final String TAG = FileOperationsHelper.class.getName(); + + private static final String FTAG_CHOOSER_DIALOG = "CHOOSER_DIALOG"; + + + public void openFile(OCFile file, FileActivity callerActivity) { + if (file != null) { + String storagePath = file.getStoragePath(); + String encodedStoragePath = WebdavUtils.encodePath(storagePath); + + Intent intentForSavedMimeType = new Intent(Intent.ACTION_VIEW); + intentForSavedMimeType.setDataAndType(Uri.parse("file://"+ encodedStoragePath), file.getMimetype()); + intentForSavedMimeType.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); + + Intent intentForGuessedMimeType = null; + if (storagePath.lastIndexOf('.') >= 0) { + String guessedMimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(storagePath.substring(storagePath.lastIndexOf('.') + 1)); + if (guessedMimeType != null && !guessedMimeType.equals(file.getMimetype())) { + intentForGuessedMimeType = new Intent(Intent.ACTION_VIEW); + intentForGuessedMimeType.setDataAndType(Uri.parse("file://"+ encodedStoragePath), guessedMimeType); + intentForGuessedMimeType.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); + } + } + + Intent chooserIntent = null; + if (intentForGuessedMimeType != null) { + chooserIntent = Intent.createChooser(intentForGuessedMimeType, callerActivity.getString(R.string.actionbar_open_with)); + } else { + chooserIntent = Intent.createChooser(intentForSavedMimeType, callerActivity.getString(R.string.actionbar_open_with)); + } + + callerActivity.startActivity(chooserIntent); + + } else { + Log_OC.wtf(TAG, "Trying to open a NULL OCFile"); + } + } + + + public void shareFileWithLink(OCFile file, FileActivity callerActivity) { + + if (isSharedSupported(callerActivity)) { + if (file != null) { + String link = "https://fake.url"; + Intent intent = createShareWithLinkIntent(link); + String[] packagesToExclude = new String[] { callerActivity.getPackageName() }; + DialogFragment chooserDialog = ActivityChooserDialog.newInstance(intent, packagesToExclude, file); + chooserDialog.show(callerActivity.getSupportFragmentManager(), FTAG_CHOOSER_DIALOG); + + } else { + Log_OC.wtf(TAG, "Trying to share a NULL OCFile"); + } + + } else { + // Show a Message + Toast t = Toast.makeText(callerActivity, callerActivity.getString(R.string.share_link_no_support_share_api), Toast.LENGTH_LONG); + t.show(); + } + } + + + public void shareFileWithLinkToApp(OCFile file, Intent sendIntent, FileActivity callerActivity) { + + if (file != null) { + callerActivity.showLoadingDialog(); + CreateShareOperation createShare = new CreateShareOperation(file.getRemotePath(), ShareType.PUBLIC_LINK, "", false, "", 1, sendIntent); + createShare.execute(callerActivity.getStorageManager(), + callerActivity, + callerActivity.getRemoteOperationListener(), + callerActivity.getHandler(), + callerActivity); + + } else { + Log_OC.wtf(TAG, "Trying to open a NULL OCFile"); + } + } + + + private Intent createShareWithLinkIntent(String link) { + Intent intentToShareLink = new Intent(Intent.ACTION_SEND); + intentToShareLink.putExtra(Intent.EXTRA_TEXT, link); + intentToShareLink.setType(HTTP.PLAIN_TEXT_TYPE); + return intentToShareLink; + } + + + /** + * @return 'True' if the server supports the Share API + */ + public boolean isSharedSupported(FileActivity callerActivity) { + if (callerActivity.getAccount() != null) { + AccountManager accountManager = AccountManager.get(callerActivity); + return Boolean.parseBoolean(accountManager.getUserData(callerActivity.getAccount(), OwnCloudAccount.Constants.KEY_SUPPORTS_SHARE_API)); + } + return false; + } + +} diff --git a/src/com/owncloud/android/files/services/FileUploader.java b/src/com/owncloud/android/files/services/FileUploader.java index 9575a330..06400c06 100644 --- a/src/com/owncloud/android/files/services/FileUploader.java +++ b/src/com/owncloud/android/files/services/FileUploader.java @@ -605,7 +605,7 @@ public class FileUploader extends Service implements OnDatatransferProgressListe ReadRemoteFileOperation operation = new ReadRemoteFileOperation(mCurrentUpload.getRemotePath()); RemoteOperationResult result = operation.execute(mUploadClient); if (result.isSuccess()) { - updateOCFile(file, (RemoteFile)result.getData().get(0)); + updateOCFile(file, (RemoteFile) result.getData().get(0)); file.setLastSyncDateForProperties(syncDate); } diff --git a/src/com/owncloud/android/operations/CreateShareOperation.java b/src/com/owncloud/android/operations/CreateShareOperation.java new file mode 100644 index 00000000..bf462a2c --- /dev/null +++ b/src/com/owncloud/android/operations/CreateShareOperation.java @@ -0,0 +1,129 @@ +/* ownCloud Android client application + * Copyright (C) 2014 ownCloud Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package com.owncloud.android.operations; + +/** + * Creates a new share from a given file + * + * @author masensio + * + */ + +import android.content.Intent; + +import com.owncloud.android.datamodel.FileDataStorageManager; +import com.owncloud.android.datamodel.OCFile; +import com.owncloud.android.lib.network.OwnCloudClient; +import com.owncloud.android.lib.operations.common.OCShare; +import com.owncloud.android.lib.operations.common.RemoteOperationResult; +import com.owncloud.android.lib.operations.common.ShareType; +import com.owncloud.android.lib.operations.remote.CreateShareRemoteOperation; +import com.owncloud.android.lib.utils.FileUtils; +import com.owncloud.android.operations.common.SyncOperation; +import com.owncloud.android.utils.Log_OC; + +public class CreateShareOperation extends SyncOperation { + + private static final String TAG = CreateShareOperation.class.getSimpleName(); + + protected FileDataStorageManager mStorageManager; + + private String mPath; + private ShareType mShareType; + private String mShareWith; + private boolean mPublicUpload; + private String mPassword; + private int mPermissions; + private Intent mSendIntent; + + /** + * Constructor + * @param path Full path of the file/folder being shared. Mandatory argument + * @param shareType ‘0’ = user, ‘1’ = group, ‘3’ = Public link. Mandatory argument + * @param shareWith User/group ID with who the file should be shared. This is mandatory for shareType of 0 or 1 + * @param publicUpload If ‘false’ (default) public cannot upload to a public shared folder. + * If ‘true’ public can upload to a shared folder. Only available for public link shares + * @param password Password to protect a public link share. Only available for public link shares + * @param permissions 1 - Read only – Default for “public” shares + * 2 - Update + * 4 - Create + * 8 - Delete + * 16- Re-share + * 31- All above – Default for “private” shares + * For user or group shares. + * To obtain combinations, add the desired values together. + * For instance, for “Re-Share”, “delete”, “read”, “update”, add 16+8+2+1 = 27. + */ + public CreateShareOperation(String path, ShareType shareType, String shareWith, boolean publicUpload, + String password, int permissions, Intent sendIntent) { + + mPath = path; + mShareType = shareType; + mShareWith = shareWith; + mPublicUpload = publicUpload; + mPassword = password; + mPermissions = permissions; + mSendIntent = sendIntent; + } + + @Override + protected RemoteOperationResult run(OwnCloudClient client) { + CreateShareRemoteOperation operation = new CreateShareRemoteOperation(mPath, mShareType, mShareWith, mPublicUpload, mPassword, mPermissions); + RemoteOperationResult result = operation.execute(client); + + if (result.isSuccess()) { + + if (result.getData().size() > 0) { + OCShare share = (OCShare) result.getData().get(0); + + // Update DB with the response + if (mPath.endsWith(FileUtils.PATH_SEPARATOR)) { + share.setPath(mPath.substring(0, mPath.length()-1)); + share.setIsFolder(true); + + } else { + share.setPath(mPath); + share.setIsFolder(false); + } + share.setPermissions(mPermissions); + + getStorageManager().saveShare(share); + + // Update OCFile with data from share: ShareByLink and publicLink + OCFile file = getStorageManager().getFileByPath(mPath); + if (file!=null) { + mSendIntent.putExtra(Intent.EXTRA_TEXT, share.getShareLink()); + file.setPublicLink(share.getShareLink()); + file.setShareByLink(true); + getStorageManager().saveFile(file); + Log_OC.d(TAG, "Public Link = " + file.getPublicLink()); + + } + } + } + + + return result; + } + + + public Intent getSendIntent() { + return mSendIntent; + } + +} diff --git a/src/com/owncloud/android/operations/GetSharesForFileOperation.java b/src/com/owncloud/android/operations/GetSharesForFileOperation.java new file mode 100644 index 00000000..fd2dab74 --- /dev/null +++ b/src/com/owncloud/android/operations/GetSharesForFileOperation.java @@ -0,0 +1,79 @@ +/* ownCloud Android client application + * Copyright (C) 2012-2013 ownCloud Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + + +package com.owncloud.android.operations; + +import java.util.ArrayList; + +import com.owncloud.android.lib.network.OwnCloudClient; +import com.owncloud.android.lib.operations.common.OCShare; +import com.owncloud.android.lib.operations.common.RemoteOperationResult; +import com.owncloud.android.lib.operations.remote.GetSharesForFileRemoteOperation; +import com.owncloud.android.operations.common.SyncOperation; +import com.owncloud.android.utils.Log_OC; + +/** + * Provide a list shares for a specific file. + * + * @author masensio + * + */ +public class GetSharesForFileOperation extends SyncOperation { + + private static final String TAG = GetSharesForFileOperation.class.getSimpleName(); + + private String mPath; + private boolean mReshares; + private boolean mSubfiles; + + /** + * Constructor + * + * @param path Path to file or folder + * @param reshares If set to ‘false’ (default), only shares from the current user are returned + * If set to ‘true’, all shares from the given file are returned + * @param subfiles If set to ‘false’ (default), lists only the folder being shared + * If set to ‘true’, all shared files within the folder are returned. + */ + public GetSharesForFileOperation(String path, boolean reshares, boolean subfiles) { + mPath = path; + mReshares = reshares; + mSubfiles = subfiles; + } + + @Override + protected RemoteOperationResult run(OwnCloudClient client) { + GetSharesForFileRemoteOperation operation = new GetSharesForFileRemoteOperation(mPath, mReshares, mSubfiles); + RemoteOperationResult result = operation.execute(client); + + if (result.isSuccess()) { + + // Update DB with the response + Log_OC.d(TAG, "File = " + mPath + " Share list size " + result.getData().size()); + ArrayList shares = new ArrayList(); + for(Object obj: result.getData()) { + shares.add((OCShare) obj); + } + + getStorageManager().saveSharesDB(shares); + } + + return result; + } + +} diff --git a/src/com/owncloud/android/operations/GetSharesOperation.java b/src/com/owncloud/android/operations/GetSharesOperation.java new file mode 100644 index 00000000..8f7a2ae8 --- /dev/null +++ b/src/com/owncloud/android/operations/GetSharesOperation.java @@ -0,0 +1,61 @@ +/* ownCloud Android client application + * Copyright (C) 2012-2013 ownCloud Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package com.owncloud.android.operations; + +import java.util.ArrayList; + +import com.owncloud.android.lib.network.OwnCloudClient; +import com.owncloud.android.lib.operations.common.RemoteOperationResult; +import com.owncloud.android.lib.operations.common.OCShare; +import com.owncloud.android.lib.operations.remote.GetRemoteSharesOperation; +import com.owncloud.android.operations.common.SyncOperation; +import com.owncloud.android.utils.Log_OC; + +/** + * Access to remote operation to get the share files/folders + * Save the data in Database + * + * @author masensio + * @author David A. Velasco + */ + +public class GetSharesOperation extends SyncOperation { + + private static final String TAG = GetSharesOperation.class.getSimpleName(); + + @Override + protected RemoteOperationResult run(OwnCloudClient client) { + GetRemoteSharesOperation operation = new GetRemoteSharesOperation(); + RemoteOperationResult result = operation.execute(client); + + if (result.isSuccess()) { + + // Update DB with the response + Log_OC.d(TAG, "Share list size = " + result.getData().size()); + ArrayList shares = new ArrayList(); + for(Object obj: result.getData()) { + shares.add((OCShare) obj); + } + + getStorageManager().saveSharesDB(shares); + } + + return result; + } + +} diff --git a/src/com/owncloud/android/operations/OAuth2GetAccessToken.java b/src/com/owncloud/android/operations/OAuth2GetAccessToken.java index 57295ad6..45238ba2 100644 --- a/src/com/owncloud/android/operations/OAuth2GetAccessToken.java +++ b/src/com/owncloud/android/operations/OAuth2GetAccessToken.java @@ -70,7 +70,7 @@ public class OAuth2GetAccessToken extends RemoteOperation { nameValuePairs[3] = new NameValuePair(OAuth2Constants.KEY_CLIENT_ID, mClientId); //nameValuePairs[4] = new NameValuePair(OAuth2Constants.KEY_SCOPE, mOAuth2ParsedAuthorizationResponse.get(OAuth2Constants.KEY_SCOPE)); - postMethod = new PostMethod(client.getBaseUri().toString()); + postMethod = new PostMethod(client.getWebdavUri().toString()); postMethod.setRequestBody(nameValuePairs); int status = client.executeMethod(postMethod); @@ -99,16 +99,16 @@ public class OAuth2GetAccessToken extends RemoteOperation { postMethod.releaseConnection(); // let the connection available for other methods if (result.isSuccess()) { - Log_OC.i(TAG, "OAuth2 TOKEN REQUEST with auth code " + mOAuth2ParsedAuthorizationResponse.get("code") + " to " + client.getBaseUri() + ": " + result.getLogMessage()); + Log_OC.i(TAG, "OAuth2 TOKEN REQUEST with auth code " + mOAuth2ParsedAuthorizationResponse.get("code") + " to " + client.getWebdavUri() + ": " + result.getLogMessage()); } else if (result.getException() != null) { - Log_OC.e(TAG, "OAuth2 TOKEN REQUEST with auth code " + mOAuth2ParsedAuthorizationResponse.get("code") + " to " + client.getBaseUri() + ": " + result.getLogMessage(), result.getException()); + Log_OC.e(TAG, "OAuth2 TOKEN REQUEST with auth code " + mOAuth2ParsedAuthorizationResponse.get("code") + " to " + client.getWebdavUri() + ": " + result.getLogMessage(), result.getException()); } else if (result.getCode() == ResultCode.OAUTH2_ERROR) { - Log_OC.e(TAG, "OAuth2 TOKEN REQUEST with auth code " + mOAuth2ParsedAuthorizationResponse.get("code") + " to " + client.getBaseUri() + ": " + ((mResultTokenMap != null) ? mResultTokenMap.get(OAuth2Constants.KEY_ERROR) : "NULL")); + Log_OC.e(TAG, "OAuth2 TOKEN REQUEST with auth code " + mOAuth2ParsedAuthorizationResponse.get("code") + " to " + client.getWebdavUri() + ": " + ((mResultTokenMap != null) ? mResultTokenMap.get(OAuth2Constants.KEY_ERROR) : "NULL")); } else { - Log_OC.e(TAG, "OAuth2 TOKEN REQUEST with auth code " + mOAuth2ParsedAuthorizationResponse.get("code") + " to " + client.getBaseUri() + ": " + result.getLogMessage()); + Log_OC.e(TAG, "OAuth2 TOKEN REQUEST with auth code " + mOAuth2ParsedAuthorizationResponse.get("code") + " to " + client.getWebdavUri() + ": " + result.getLogMessage()); } } diff --git a/src/com/owncloud/android/operations/OwnCloudServerCheckOperation.java b/src/com/owncloud/android/operations/OwnCloudServerCheckOperation.java deleted file mode 100644 index f3eca9c2..00000000 --- a/src/com/owncloud/android/operations/OwnCloudServerCheckOperation.java +++ /dev/null @@ -1,139 +0,0 @@ -/* ownCloud Android client application - * Copyright (C) 2012-2013 ownCloud Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ - -package com.owncloud.android.operations; - -import org.apache.commons.httpclient.HttpStatus; -import org.apache.commons.httpclient.methods.GetMethod; -import org.json.JSONException; -import org.json.JSONObject; - -import com.owncloud.android.authentication.AccountUtils; -import com.owncloud.android.lib.network.OwnCloudClient; -import com.owncloud.android.lib.operations.common.RemoteOperation; -import com.owncloud.android.lib.operations.common.RemoteOperationResult; -import com.owncloud.android.lib.utils.OwnCloudVersion; -import com.owncloud.android.utils.Log_OC; - -import android.content.Context; -import android.net.ConnectivityManager; -import android.net.Uri; - -public class OwnCloudServerCheckOperation extends RemoteOperation { - - /** Maximum time to wait for a response from the server when the connection is being tested, in MILLISECONDs. */ - public static final int TRY_CONNECTION_TIMEOUT = 5000; - - private static final String TAG = OwnCloudServerCheckOperation.class.getSimpleName(); - - private String mUrl; - private RemoteOperationResult mLatestResult; - private Context mContext; - private OwnCloudVersion mOCVersion; - - public OwnCloudServerCheckOperation(String url, Context context) { - mUrl = url; - mContext = context; - mOCVersion = null; - } - - public OwnCloudVersion getDiscoveredVersion() { - return mOCVersion; - } - - private boolean tryConnection(OwnCloudClient wc, String urlSt) { - boolean retval = false; - GetMethod get = null; - try { - get = new GetMethod(urlSt); - int status = wc.executeMethod(get, TRY_CONNECTION_TIMEOUT, TRY_CONNECTION_TIMEOUT); - String response = get.getResponseBodyAsString(); - if (status == HttpStatus.SC_OK) { - JSONObject json = new JSONObject(response); - if (!json.getBoolean("installed")) { - mLatestResult = new RemoteOperationResult(RemoteOperationResult.ResultCode.INSTANCE_NOT_CONFIGURED); - } else { - mOCVersion = new OwnCloudVersion(json.getString("version")); - if (!mOCVersion.isVersionValid()) { - mLatestResult = new RemoteOperationResult(RemoteOperationResult.ResultCode.BAD_OC_VERSION); - - } else { - mLatestResult = new RemoteOperationResult(urlSt.startsWith("https://") ? - RemoteOperationResult.ResultCode.OK_SSL : - RemoteOperationResult.ResultCode.OK_NO_SSL - ); - - retval = true; - } - } - - } else { - mLatestResult = new RemoteOperationResult(false, status, get.getResponseHeaders()); - } - - } catch (JSONException e) { - mLatestResult = new RemoteOperationResult(RemoteOperationResult.ResultCode.INSTANCE_NOT_CONFIGURED); - - } catch (Exception e) { - mLatestResult = new RemoteOperationResult(e); - - } finally { - if (get != null) - get.releaseConnection(); - } - - if (mLatestResult.isSuccess()) { - Log_OC.i(TAG, "Connection check at " + urlSt + ": " + mLatestResult.getLogMessage()); - - } else if (mLatestResult.getException() != null) { - Log_OC.e(TAG, "Connection check at " + urlSt + ": " + mLatestResult.getLogMessage(), mLatestResult.getException()); - - } else { - Log_OC.e(TAG, "Connection check at " + urlSt + ": " + mLatestResult.getLogMessage()); - } - - return retval; - } - - private boolean isOnline() { - ConnectivityManager cm = (ConnectivityManager) mContext - .getSystemService(Context.CONNECTIVITY_SERVICE); - return cm != null && cm.getActiveNetworkInfo() != null - && cm.getActiveNetworkInfo().isConnectedOrConnecting(); - } - - @Override - protected RemoteOperationResult run(OwnCloudClient client) { - if (!isOnline()) { - return new RemoteOperationResult(RemoteOperationResult.ResultCode.NO_NETWORK_CONNECTION); - } - if (mUrl.startsWith("http://") || mUrl.startsWith("https://")) { - tryConnection(client, mUrl + AccountUtils.STATUS_PATH); - - } else { - client.setBaseUri(Uri.parse("https://" + mUrl + AccountUtils.STATUS_PATH)); - boolean httpsSuccess = tryConnection(client, "https://" + mUrl + AccountUtils.STATUS_PATH); - if (!httpsSuccess && !mLatestResult.isSslRecoverableException()) { - Log_OC.d(TAG, "establishing secure connection failed, trying non secure connection"); - client.setBaseUri(Uri.parse("http://" + mUrl + AccountUtils.STATUS_PATH)); - tryConnection(client, "http://" + mUrl + AccountUtils.STATUS_PATH); - } - } - return mLatestResult; - } - -} diff --git a/src/com/owncloud/android/operations/SynchronizeFileOperation.java b/src/com/owncloud/android/operations/SynchronizeFileOperation.java index 2f6d9142..2b948857 100644 --- a/src/com/owncloud/android/operations/SynchronizeFileOperation.java +++ b/src/com/owncloud/android/operations/SynchronizeFileOperation.java @@ -90,7 +90,7 @@ public class SynchronizeFileOperation extends RemoteOperation { ReadRemoteFileOperation operation = new ReadRemoteFileOperation(remotePath); result = operation.execute(client); if (result.isSuccess()){ - mServerFile = FileStorageUtils.fillOCFile((RemoteFile)result.getData().get(0)); + mServerFile = FileStorageUtils.fillOCFile((RemoteFile) result.getData().get(0)); mServerFile.setLastSyncDateForProperties(System.currentTimeMillis()); } } diff --git a/src/com/owncloud/android/operations/SynchronizeFolderOperation.java b/src/com/owncloud/android/operations/SynchronizeFolderOperation.java index 82d4d8c6..11ce41e5 100644 --- a/src/com/owncloud/android/operations/SynchronizeFolderOperation.java +++ b/src/com/owncloud/android/operations/SynchronizeFolderOperation.java @@ -33,17 +33,20 @@ import org.apache.http.HttpStatus; import android.accounts.Account; import android.content.Context; import android.content.Intent; +//import android.support.v4.content.LocalBroadcastManager; import com.owncloud.android.datamodel.FileDataStorageManager; import com.owncloud.android.datamodel.OCFile; import com.owncloud.android.lib.network.OwnCloudClient; +import com.owncloud.android.lib.operations.common.OCShare; import com.owncloud.android.lib.operations.common.RemoteOperation; import com.owncloud.android.lib.operations.common.RemoteOperationResult; import com.owncloud.android.lib.operations.common.RemoteOperationResult.ResultCode; +import com.owncloud.android.lib.operations.remote.GetSharesForFileRemoteOperation; import com.owncloud.android.lib.operations.remote.ReadRemoteFileOperation; import com.owncloud.android.lib.operations.remote.ReadRemoteFolderOperation; import com.owncloud.android.lib.operations.common.RemoteFile; -import com.owncloud.android.syncadapter.FileSyncService; +import com.owncloud.android.syncadapter.FileSyncAdapter; import com.owncloud.android.utils.FileStorageUtils; import com.owncloud.android.utils.Log_OC; @@ -64,6 +67,8 @@ public class SynchronizeFolderOperation extends RemoteOperation { private static final String TAG = SynchronizeFolderOperation.class.getSimpleName(); + public static final String EVENT_SINGLE_FOLDER_CONTENTS_SYNCED = SynchronizeFolderOperation.class.getName() + ".EVENT_SINGLE_FOLDER_CONTENTS_SYNCED"; + public static final String EVENT_SINGLE_FOLDER_SHARES_SYNCED = SynchronizeFolderOperation.class.getName() + ".EVENT_SINGLE_FOLDER_SHARES_SYNCED"; /** Time stamp for the synchronization process in progress */ private long mCurrentSyncTime; @@ -95,9 +100,12 @@ public class SynchronizeFolderOperation extends RemoteOperation { /** 'True' means that this operation is part of a full account synchronization */ private boolean mSyncFullAccount; + /** 'True' means that Share resources bound to the files into the folder should be refreshed also */ + private boolean mRefreshShares; + /** 'True' means that the remote folder changed from last synchronization and should be fetched */ private boolean mRemoteFolderChanged; - + /** * Creates a new instance of {@link SynchronizeFolderOperation}. @@ -114,12 +122,14 @@ public class SynchronizeFolderOperation extends RemoteOperation { public SynchronizeFolderOperation( OCFile folder, long currentSyncTime, boolean syncFullAccount, + boolean refreshShares, FileDataStorageManager dataStorageManager, Account account, Context context ) { mLocalFolder = folder; mCurrentSyncTime = currentSyncTime; mSyncFullAccount = syncFullAccount; + mRefreshShares = refreshShares; mStorageManager = dataStorageManager; mAccount = account; mContext = context; @@ -172,46 +182,57 @@ public class SynchronizeFolderOperation extends RemoteOperation { } if (!mSyncFullAccount) { - sendStickyBroadcast(false, mLocalFolder.getRemotePath(), result); + sendLocalBroadcast(EVENT_SINGLE_FOLDER_CONTENTS_SYNCED, mLocalFolder.getRemotePath(), result); } - + + if (result.isSuccess() && mRefreshShares) { + RemoteOperationResult shareResult = refreshSharesForFolder(client); + if (shareResult.getCode() != ResultCode.FILE_NOT_FOUND) { + result = shareResult; + } // else , keep the previous result ; being conservative for servers where Sharing API is supported, but disabled + } + + if (!mSyncFullAccount) { + sendLocalBroadcast(EVENT_SINGLE_FOLDER_SHARES_SYNCED, mLocalFolder.getRemotePath(), result); + } + return result; } - private RemoteOperationResult checkForChanges(OwnCloudClient client) { mRemoteFolderChanged = false; RemoteOperationResult result = null; String remotePath = null; - remotePath = mLocalFolder.getRemotePath(); - Log_OC.d(TAG, "Checking changes in " + mAccount.name + remotePath); - - // remote request - ReadRemoteFileOperation operation = new ReadRemoteFileOperation(remotePath); - result = operation.execute(client); - if (result.isSuccess()){ - OCFile remoteFolder = FileStorageUtils.fillOCFile((RemoteFile)result.getData().get(0)); - - // check if remote and local folder are different - mRemoteFolderChanged = !(remoteFolder.getEtag().equalsIgnoreCase(mLocalFolder.getEtag())); - - result = new RemoteOperationResult(ResultCode.OK); - - Log_OC.i(TAG, "Checked " + mAccount.name + remotePath + " : " + (mRemoteFolderChanged ? "changed" : "not changed")); + remotePath = mLocalFolder.getRemotePath(); + Log_OC.d(TAG, "Checking changes in " + mAccount.name + remotePath); + + // remote request + ReadRemoteFileOperation operation = new ReadRemoteFileOperation(remotePath); + result = operation.execute(client); + if (result.isSuccess()){ + OCFile remoteFolder = FileStorageUtils.fillOCFile((RemoteFile) result.getData().get(0)); + + // check if remote and local folder are different + mRemoteFolderChanged = !(remoteFolder.getEtag().equalsIgnoreCase(mLocalFolder.getEtag())); + + result = new RemoteOperationResult(ResultCode.OK); + + Log_OC.i(TAG, "Checked " + mAccount.name + remotePath + " : " + (mRemoteFolderChanged ? "changed" : "not changed")); + + } else { + // check failed + if (result.getCode() == ResultCode.FILE_NOT_FOUND) { + removeLocalFolder(); + } + if (result.isException()) { + Log_OC.e(TAG, "Checked " + mAccount.name + remotePath + " : " + result.getLogMessage(), result.getException()); } else { - // check failed - if (result.getCode() == ResultCode.FILE_NOT_FOUND) { - removeLocalFolder(); - } - if (result.isException()) { - Log_OC.e(TAG, "Checked " + mAccount.name + remotePath + " : " + result.getLogMessage(), result.getException()); - } else { - Log_OC.e(TAG, "Checked " + mAccount.name + remotePath + " : " + result.getLogMessage()); - } + Log_OC.e(TAG, "Checked " + mAccount.name + remotePath + " : " + result.getLogMessage()); } - + } + return result; } @@ -330,13 +351,7 @@ public class SynchronizeFolderOperation extends RemoteOperation { // request for the synchronization of file contents AFTER saving current remote properties startContentSynchronizations(filesToSyncContents, client); - // removal of obsolete files - //removeObsoleteFiles(); - - // must be done AFTER saving all the children information, so that eTag is not updated in the database in case of unexpected exceptions - //mStorageManager.saveFile(remoteFolder); mChildren = updatedFiles; - } /** @@ -451,6 +466,27 @@ public class SynchronizeFolderOperation extends RemoteOperation { } } } + + + private RemoteOperationResult refreshSharesForFolder(OwnCloudClient client) { + RemoteOperationResult result = null; + + // remote request + GetSharesForFileRemoteOperation operation = new GetSharesForFileRemoteOperation(mLocalFolder.getRemotePath(), false, true); + result = operation.execute(client); + + if (result.isSuccess()) { + // update local database + ArrayList shares = new ArrayList(); + for(Object obj: result.getData()) { + shares.add((OCShare) obj); + } + mStorageManager.saveSharesInFolder(shares, mLocalFolder); + } + + return result; + } + /** * Scans the default location for saving local copies of files searching for @@ -473,20 +509,20 @@ public class SynchronizeFolderOperation extends RemoteOperation { /** * Sends a message to any application component interested in the progress of the synchronization. * - * @param inProgress 'True' when the synchronization progress is not finished. + * @param event * @param dirRemotePath Remote path of a folder that was just synchronized (with or without success) + * @param result */ - private void sendStickyBroadcast(boolean inProgress, String dirRemotePath, RemoteOperationResult result) { - Intent i = new Intent(FileSyncService.getSyncMessage()); - i.putExtra(FileSyncService.IN_PROGRESS, inProgress); - i.putExtra(FileSyncService.ACCOUNT_NAME, mAccount.name); + private void sendLocalBroadcast(String event, String dirRemotePath, RemoteOperationResult result) { + Log_OC.d(TAG, "Send broadcast " + event); + Intent intent = new Intent(event); + intent.putExtra(FileSyncAdapter.EXTRA_ACCOUNT_NAME, mAccount.name); if (dirRemotePath != null) { - i.putExtra(FileSyncService.SYNC_FOLDER_REMOTE_PATH, dirRemotePath); - } - if (result != null) { - i.putExtra(FileSyncService.SYNC_RESULT, result); + intent.putExtra(FileSyncAdapter.EXTRA_FOLDER_PATH, dirRemotePath); } - mContext.sendStickyBroadcast(i); + intent.putExtra(FileSyncAdapter.EXTRA_RESULT, result); + mContext.sendStickyBroadcast(intent); + //LocalBroadcastManager.getInstance(mContext).sendBroadcast(intent); } diff --git a/src/com/owncloud/android/operations/UpdateOCVersionOperation.java b/src/com/owncloud/android/operations/UpdateOCVersionOperation.java index ca4387ce..a047f110 100644 --- a/src/com/owncloud/android/operations/UpdateOCVersionOperation.java +++ b/src/com/owncloud/android/operations/UpdateOCVersionOperation.java @@ -90,15 +90,15 @@ public class UpdateOCVersionOperation extends RemoteOperation { result = new RemoteOperationResult(RemoteOperationResult.ResultCode.INSTANCE_NOT_CONFIGURED); } } - Log_OC.i(TAG, "Check for update of ownCloud server version at " + client.getBaseUri() + ": " + result.getLogMessage()); + Log_OC.i(TAG, "Check for update of ownCloud server version at " + client.getWebdavUri() + ": " + result.getLogMessage()); } catch (JSONException e) { result = new RemoteOperationResult(RemoteOperationResult.ResultCode.INSTANCE_NOT_CONFIGURED); - Log_OC.e(TAG, "Check for update of ownCloud server version at " + client.getBaseUri() + ": " + result.getLogMessage(), e); + Log_OC.e(TAG, "Check for update of ownCloud server version at " + client.getWebdavUri() + ": " + result.getLogMessage(), e); } catch (Exception e) { result = new RemoteOperationResult(e); - Log_OC.e(TAG, "Check for update of ownCloud server version at " + client.getBaseUri() + ": " + result.getLogMessage(), e); + Log_OC.e(TAG, "Check for update of ownCloud server version at " + client.getWebdavUri() + ": " + result.getLogMessage(), e); } finally { if (get != null) diff --git a/src/com/owncloud/android/operations/common/SyncOperation.java b/src/com/owncloud/android/operations/common/SyncOperation.java new file mode 100644 index 00000000..7a8e356a --- /dev/null +++ b/src/com/owncloud/android/operations/common/SyncOperation.java @@ -0,0 +1,129 @@ +/* ownCloud Android client application + * Copyright (C) 2012-2014 ownCloud Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package com.owncloud.android.operations.common; + +import com.owncloud.android.datamodel.FileDataStorageManager; +import com.owncloud.android.lib.network.OwnCloudClient; +import com.owncloud.android.lib.operations.common.OnRemoteOperationListener; +import com.owncloud.android.lib.operations.common.RemoteOperation; +import com.owncloud.android.lib.operations.common.RemoteOperationResult; + +import android.app.Activity; +import android.content.Context; +import android.os.Handler; + + +/** + * Operation which execution involves both interactions with an ownCloud server and + * with local data in the device. + * + * Provides methods to execute the operation both synchronously or asynchronously. + * + * @author David A. Velasco + */ +public abstract class SyncOperation extends RemoteOperation { + + //private static final String TAG = SyncOperation.class.getSimpleName(); + + private FileDataStorageManager mStorageManager; + + public FileDataStorageManager getStorageManager() { + return mStorageManager; + } + + + /** + * Synchronously executes the operation on the received ownCloud account. + * + * Do not call this method from the main thread. + * + * This method should be used whenever an ownCloud account is available, instead of {@link #execute(OwnCloudClient)}. + * + * @param account ownCloud account in remote ownCloud server to reach during the execution of the operation. + * @param context Android context for the component calling the method. + * @return Result of the operation. + */ + public RemoteOperationResult execute(FileDataStorageManager storageManager, Context context) { + if (storageManager == null) { + throw new IllegalArgumentException("Trying to execute a sync operation with a NULL storage manager"); + } + if (storageManager.getAccount() == null) { + throw new IllegalArgumentException("Trying to execute a sync operation with a storage manager for a NULL account"); + } + mStorageManager = storageManager; + return super.execute(mStorageManager.getAccount(), context); + } + + + /** + * Synchronously executes the remote operation + * + * Do not call this method from the main thread. + * + * @param client Client object to reach an ownCloud server during the execution of the operation. + * @return Result of the operation. + */ + public RemoteOperationResult execute(OwnCloudClient client, FileDataStorageManager storageManager) { + if (storageManager == null) + throw new IllegalArgumentException("Trying to execute a sync operation with a NULL storage manager"); + mStorageManager = storageManager; + return super.execute(client); + } + + + /** + * Asynchronously executes the remote operation + * + * This method should be used whenever an ownCloud account is available, instead of {@link #execute(OwnCloudClient)}. + * + * @param account ownCloud account in remote ownCloud server to reach during the execution of the operation. + * @param context Android context for the component calling the method. + * @param listener Listener to be notified about the execution of the operation. + * @param listenerHandler Handler associated to the thread where the methods of the listener objects must be called. + * @return Thread were the remote operation is executed. + */ + public Thread execute(FileDataStorageManager storageManager, Context context, OnRemoteOperationListener listener, Handler listenerHandler, Activity callerActivity) { + if (storageManager == null) { + throw new IllegalArgumentException("Trying to execute a sync operation with a NULL storage manager"); + } + if (storageManager.getAccount() == null) { + throw new IllegalArgumentException("Trying to execute a sync operation with a storage manager for a NULL account"); + } + mStorageManager = storageManager; + return super.execute(storageManager.getAccount(), context, listener, listenerHandler, callerActivity); + } + + + /** + * Asynchronously executes the remote operation + * + * @param client Client object to reach an ownCloud server during the execution of the operation. + * @param listener Listener to be notified about the execution of the operation. + * @param listenerHandler Handler associated to the thread where the methods of the listener objects must be called. + * @return Thread were the remote operation is executed. + */ + public Thread execute(OwnCloudClient client, FileDataStorageManager storageManager, OnRemoteOperationListener listener, Handler listenerHandler) { + if (storageManager == null) { + throw new IllegalArgumentException("Trying to execute a sync operation with a NULL storage manager"); + } + mStorageManager = storageManager; + return super.execute(client, listener, listenerHandler); + } + + +} diff --git a/src/com/owncloud/android/providers/FileContentProvider.java b/src/com/owncloud/android/providers/FileContentProvider.java index 9e7cd3fd..36c03538 100644 --- a/src/com/owncloud/android/providers/FileContentProvider.java +++ b/src/com/owncloud/android/providers/FileContentProvider.java @@ -25,6 +25,7 @@ import com.owncloud.android.R; import com.owncloud.android.datamodel.FileDataStorageManager; import com.owncloud.android.db.ProviderMeta; import com.owncloud.android.db.ProviderMeta.ProviderTableMeta; +import com.owncloud.android.lib.operations.common.ShareType; import com.owncloud.android.utils.Log_OC; @@ -56,44 +57,85 @@ public class FileContentProvider extends ContentProvider { private DataBaseHelper mDbHelper; - private static HashMap mProjectionMap; + // Projection for filelist table + private static HashMap mFileProjectionMap; static { - mProjectionMap = new HashMap(); - mProjectionMap.put(ProviderTableMeta._ID, ProviderTableMeta._ID); - mProjectionMap.put(ProviderTableMeta.FILE_PARENT, + mFileProjectionMap = new HashMap(); + mFileProjectionMap.put(ProviderTableMeta._ID, ProviderTableMeta._ID); + mFileProjectionMap.put(ProviderTableMeta.FILE_PARENT, ProviderTableMeta.FILE_PARENT); - mProjectionMap.put(ProviderTableMeta.FILE_PATH, + mFileProjectionMap.put(ProviderTableMeta.FILE_PATH, ProviderTableMeta.FILE_PATH); - mProjectionMap.put(ProviderTableMeta.FILE_NAME, + mFileProjectionMap.put(ProviderTableMeta.FILE_NAME, ProviderTableMeta.FILE_NAME); - mProjectionMap.put(ProviderTableMeta.FILE_CREATION, + mFileProjectionMap.put(ProviderTableMeta.FILE_CREATION, ProviderTableMeta.FILE_CREATION); - mProjectionMap.put(ProviderTableMeta.FILE_MODIFIED, + mFileProjectionMap.put(ProviderTableMeta.FILE_MODIFIED, ProviderTableMeta.FILE_MODIFIED); - mProjectionMap.put(ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA, + mFileProjectionMap.put(ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA, ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA); - mProjectionMap.put(ProviderTableMeta.FILE_CONTENT_LENGTH, + mFileProjectionMap.put(ProviderTableMeta.FILE_CONTENT_LENGTH, ProviderTableMeta.FILE_CONTENT_LENGTH); - mProjectionMap.put(ProviderTableMeta.FILE_CONTENT_TYPE, + mFileProjectionMap.put(ProviderTableMeta.FILE_CONTENT_TYPE, ProviderTableMeta.FILE_CONTENT_TYPE); - mProjectionMap.put(ProviderTableMeta.FILE_STORAGE_PATH, + mFileProjectionMap.put(ProviderTableMeta.FILE_STORAGE_PATH, ProviderTableMeta.FILE_STORAGE_PATH); - mProjectionMap.put(ProviderTableMeta.FILE_LAST_SYNC_DATE, + mFileProjectionMap.put(ProviderTableMeta.FILE_LAST_SYNC_DATE, ProviderTableMeta.FILE_LAST_SYNC_DATE); - mProjectionMap.put(ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA, + mFileProjectionMap.put(ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA, ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA); - mProjectionMap.put(ProviderTableMeta.FILE_KEEP_IN_SYNC, + mFileProjectionMap.put(ProviderTableMeta.FILE_KEEP_IN_SYNC, ProviderTableMeta.FILE_KEEP_IN_SYNC); - mProjectionMap.put(ProviderTableMeta.FILE_ACCOUNT_OWNER, + mFileProjectionMap.put(ProviderTableMeta.FILE_ACCOUNT_OWNER, ProviderTableMeta.FILE_ACCOUNT_OWNER); - mProjectionMap.put(ProviderTableMeta.FILE_ETAG, + mFileProjectionMap.put(ProviderTableMeta.FILE_ETAG, ProviderTableMeta.FILE_ETAG); + mFileProjectionMap.put(ProviderTableMeta.FILE_SHARE_BY_LINK, + ProviderTableMeta.FILE_SHARE_BY_LINK); + mFileProjectionMap.put(ProviderTableMeta.FILE_PUBLIC_LINK, + ProviderTableMeta.FILE_PUBLIC_LINK); } private static final int SINGLE_FILE = 1; private static final int DIRECTORY = 2; private static final int ROOT_DIRECTORY = 3; - + private static final int SHARES = 4; + + // Projection for ocshares table + private static HashMap mOCSharesProjectionMap; + static { + mOCSharesProjectionMap = new HashMap(); + mOCSharesProjectionMap.put(ProviderTableMeta._ID, ProviderTableMeta._ID); + mOCSharesProjectionMap.put(ProviderTableMeta.OCSHARES_FILE_SOURCE, + ProviderTableMeta.OCSHARES_FILE_SOURCE); + mOCSharesProjectionMap.put(ProviderTableMeta.OCSHARES_ITEM_SOURCE, + ProviderTableMeta.OCSHARES_ITEM_SOURCE); + mOCSharesProjectionMap.put(ProviderTableMeta.OCSHARES_SHARE_TYPE, + ProviderTableMeta.OCSHARES_SHARE_TYPE); + mOCSharesProjectionMap.put(ProviderTableMeta.OCSHARES_SHARE_WITH, + ProviderTableMeta.OCSHARES_SHARE_WITH); + mOCSharesProjectionMap.put(ProviderTableMeta.OCSHARES_PATH, + ProviderTableMeta.OCSHARES_PATH); + mOCSharesProjectionMap.put(ProviderTableMeta.OCSHARES_PERMISSIONS, + ProviderTableMeta.OCSHARES_PERMISSIONS); + mOCSharesProjectionMap.put(ProviderTableMeta.OCSHARES_SHARED_DATE, + ProviderTableMeta.OCSHARES_SHARED_DATE); + mOCSharesProjectionMap.put(ProviderTableMeta.OCSHARES_EXPIRATION_DATE, + ProviderTableMeta.OCSHARES_EXPIRATION_DATE); + mOCSharesProjectionMap.put(ProviderTableMeta.OCSHARES_TOKEN, + ProviderTableMeta.OCSHARES_TOKEN); + mOCSharesProjectionMap.put(ProviderTableMeta.OCSHARES_SHARE_WITH_DISPLAY_NAME, + ProviderTableMeta.OCSHARES_SHARE_WITH_DISPLAY_NAME); + mOCSharesProjectionMap.put(ProviderTableMeta.OCSHARES_IS_DIRECTORY, + ProviderTableMeta.OCSHARES_IS_DIRECTORY); + mOCSharesProjectionMap.put(ProviderTableMeta.OCSHARES_USER_ID, + ProviderTableMeta.OCSHARES_USER_ID); + mOCSharesProjectionMap.put(ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED, + ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED); + mOCSharesProjectionMap.put(ProviderTableMeta.OCSHARES_ACCOUNT_OWNER, + ProviderTableMeta.OCSHARES_ACCOUNT_OWNER); + } + private UriMatcher mUriMatcher; @Override @@ -112,7 +154,6 @@ public class FileContentProvider extends ContentProvider { return count; } - private int delete(SQLiteDatabase db, Uri uri, String where, String[] whereArgs) { int count = 0; switch (mUriMatcher.match(uri)) { @@ -124,7 +165,7 @@ public class FileContentProvider extends ContentProvider { } Log_OC.d(TAG, "Removing FILE " + remotePath); */ - count = db.delete(ProviderTableMeta.DB_NAME, + count = db.delete(ProviderTableMeta.FILE_TABLE_NAME, ProviderTableMeta._ID + "=" + uri.getPathSegments().get(1) @@ -168,7 +209,7 @@ public class FileContentProvider extends ContentProvider { } Log_OC.d(TAG, "Removing DIRECTORY " + folderName + " (or maybe not) "); */ - count += db.delete(ProviderTableMeta.DB_NAME, + count += db.delete(ProviderTableMeta.FILE_TABLE_NAME, ProviderTableMeta._ID + "=" + uri.getPathSegments().get(1) @@ -181,7 +222,10 @@ public class FileContentProvider extends ContentProvider { break; case ROOT_DIRECTORY: //Log_OC.d(TAG, "Removing ROOT!"); - count = db.delete(ProviderTableMeta.DB_NAME, where, whereArgs); + count = db.delete(ProviderTableMeta.FILE_TABLE_NAME, where, whereArgs); + break; + case SHARES: + count = db.delete(ProviderTableMeta.OCSHARES_TABLE_NAME, where, whereArgs); break; default: //Log_OC.e(TAG, "Unknown uri " + uri); @@ -191,6 +235,7 @@ public class FileContentProvider extends ContentProvider { } + // TODO: switch(uri) @Override public String getType(Uri uri) { switch (mUriMatcher.match(uri)) { @@ -221,37 +266,77 @@ public class FileContentProvider extends ContentProvider { } private Uri insert(SQLiteDatabase db, Uri uri, ContentValues values) { - if (mUriMatcher.match(uri) != SINGLE_FILE && - mUriMatcher.match(uri) != ROOT_DIRECTORY) { - //Log_OC.e(TAG, "Inserting invalid URI: " + uri); - throw new IllegalArgumentException("Unknown uri id: " + uri); - } + switch (mUriMatcher.match(uri)){ + case ROOT_DIRECTORY: + case SINGLE_FILE: + String remotePath = values.getAsString(ProviderTableMeta.FILE_PATH); + String accountName = values.getAsString(ProviderTableMeta.FILE_ACCOUNT_OWNER); + String[] projection = new String[] {ProviderTableMeta._ID, ProviderTableMeta.FILE_PATH, ProviderTableMeta.FILE_ACCOUNT_OWNER }; + String where = ProviderTableMeta.FILE_PATH + "=? AND " + ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?"; + String[] whereArgs = new String[] {remotePath, accountName}; + Cursor doubleCheck = query(db, uri, projection, where, whereArgs, null); + if (doubleCheck == null || !doubleCheck.moveToFirst()) { // ugly patch; serious refactorization is needed to reduce work in FileDataStorageManager and bring it to FileContentProvider + long rowId = db.insert(ProviderTableMeta.FILE_TABLE_NAME, null, values); + if (rowId > 0) { + Uri insertedFileUri = ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_FILE, rowId); + //Log_OC.d(TAG, "Inserted " + values.getAsString(ProviderTableMeta.FILE_PATH) + " at provider " + this); + return insertedFileUri; + } else { + //Log_OC.d(TAG, "Error while inserting " + values.getAsString(ProviderTableMeta.FILE_PATH) + " at provider " + this); + throw new SQLException("ERROR " + uri); + } + } else { + // file is already inserted; race condition, let's avoid a duplicated entry + Uri insertedFileUri = ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_FILE, doubleCheck.getLong(doubleCheck.getColumnIndex(ProviderTableMeta._ID))); + doubleCheck.close(); - String remotePath = values.getAsString(ProviderTableMeta.FILE_PATH); - String accountName = values.getAsString(ProviderTableMeta.FILE_ACCOUNT_OWNER); - String[] projection = new String[] {ProviderTableMeta._ID, ProviderTableMeta.FILE_PATH, ProviderTableMeta.FILE_ACCOUNT_OWNER }; - String where = ProviderTableMeta.FILE_PATH + "=? AND " + ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?"; - String[] whereArgs = new String[] {remotePath, accountName}; - Cursor doubleCheck = query(db, uri, projection, where, whereArgs, null); - if (doubleCheck == null || !doubleCheck.moveToFirst()) { // ugly patch; serious refactorization is needed to reduce work in FileDataStorageManager and bring it to FileContentProvider - long rowId = db.insert(ProviderTableMeta.DB_NAME, null, values); - if (rowId > 0) { - Uri insertedFileUri = ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_FILE, rowId); - //Log_OC.d(TAG, "Inserted " + values.getAsString(ProviderTableMeta.FILE_PATH) + " at provider " + this); return insertedFileUri; + } + + case SHARES: + String path = values.getAsString(ProviderTableMeta.OCSHARES_PATH); + String accountNameShare= values.getAsString(ProviderTableMeta.OCSHARES_ACCOUNT_OWNER); + String[] projectionShare = new String[] {ProviderTableMeta._ID, ProviderTableMeta.OCSHARES_PATH, ProviderTableMeta.OCSHARES_ACCOUNT_OWNER }; + String whereShare = ProviderTableMeta.OCSHARES_PATH + "=? AND " + ProviderTableMeta.OCSHARES_ACCOUNT_OWNER + "=?"; + String[] whereArgsShare = new String[] {path, accountNameShare}; + Uri insertedShareUri = null; + Cursor doubleCheckShare = query(db, uri, projectionShare, whereShare, whereArgsShare, null); + if (doubleCheckShare == null || !doubleCheckShare.moveToFirst()) { // ugly patch; serious refactorization is needed to reduce work in FileDataStorageManager and bring it to FileContentProvider + long rowId = db.insert(ProviderTableMeta.OCSHARES_TABLE_NAME, null, values); + if (rowId >0) { + insertedShareUri = ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_SHARE, rowId); + } else { + throw new SQLException("ERROR " + uri); + + } } else { - //Log_OC.d(TAG, "Error while inserting " + values.getAsString(ProviderTableMeta.FILE_PATH) + " at provider " + this); - throw new SQLException("ERROR " + uri); + // file is already inserted; race condition, let's avoid a duplicated entry + insertedShareUri = ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_SHARE, doubleCheckShare.getLong(doubleCheckShare.getColumnIndex(ProviderTableMeta._ID))); + doubleCheckShare.close(); } - } else { - // file is already inserted; race condition, let's avoid a duplicated entry - Uri insertedFileUri = ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_FILE, doubleCheck.getLong(doubleCheck.getColumnIndex(ProviderTableMeta._ID))); - doubleCheck.close(); - return insertedFileUri; + updateFilesTableAccordingToShareInsertion(db, uri, values); + return insertedShareUri; + + + default: + throw new IllegalArgumentException("Unknown uri id: " + uri); } + } - + private void updateFilesTableAccordingToShareInsertion(SQLiteDatabase db, Uri uri, ContentValues shareValues) { + ContentValues fileValues = new ContentValues(); + fileValues.put(ProviderTableMeta.FILE_SHARE_BY_LINK, + ShareType.PUBLIC_LINK.getValue() == shareValues.getAsInteger(ProviderTableMeta.OCSHARES_SHARE_TYPE)? 1 : 0); + String whereShare = ProviderTableMeta.FILE_PATH + "=? AND " + ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?"; + String[] whereArgsShare = new String[] { + shareValues.getAsString(ProviderTableMeta.OCSHARES_PATH), + shareValues.getAsString(ProviderTableMeta.OCSHARES_ACCOUNT_OWNER) + }; + db.update(ProviderTableMeta.FILE_TABLE_NAME, fileValues, whereShare, whereArgsShare); + } + + @Override public boolean onCreate() { mDbHelper = new DataBaseHelper(getContext()); @@ -263,6 +348,8 @@ public class FileContentProvider extends ContentProvider { mUriMatcher.addURI(authority, "file/#", SINGLE_FILE); mUriMatcher.addURI(authority, "dir/", DIRECTORY); mUriMatcher.addURI(authority, "dir/#", DIRECTORY); + mUriMatcher.addURI(authority, "shares/", SHARES); + mUriMatcher.addURI(authority, "shares/#", SHARES); return true; } @@ -285,8 +372,8 @@ public class FileContentProvider extends ContentProvider { private Cursor query(SQLiteDatabase db, Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { SQLiteQueryBuilder sqlQuery = new SQLiteQueryBuilder(); - sqlQuery.setTables(ProviderTableMeta.DB_NAME); - sqlQuery.setProjectionMap(mProjectionMap); + sqlQuery.setTables(ProviderTableMeta.FILE_TABLE_NAME); + sqlQuery.setProjectionMap(mFileProjectionMap); switch (mUriMatcher.match(uri)) { case ROOT_DIRECTORY: @@ -302,13 +389,26 @@ public class FileContentProvider extends ContentProvider { + uri.getPathSegments().get(1)); } break; + case SHARES: + sqlQuery.setTables(ProviderTableMeta.OCSHARES_TABLE_NAME); + sqlQuery.setProjectionMap(mOCSharesProjectionMap); + if (uri.getPathSegments().size() > 1) { + sqlQuery.appendWhere(ProviderTableMeta._ID + "=" + + uri.getPathSegments().get(1)); + } + break; default: throw new IllegalArgumentException("Unknown uri id: " + uri); } String order; if (TextUtils.isEmpty(sortOrder)) { - order = ProviderTableMeta.DEFAULT_SORT_ORDER; + if (mUriMatcher.match(uri) == SHARES) { + order = ProviderTableMeta.OCSHARES_DEFAULT_SORT_ORDER; + } else { + + order = ProviderTableMeta.FILE_DEFAULT_SORT_ORDER; + } } else { order = sortOrder; } @@ -338,12 +438,15 @@ public class FileContentProvider extends ContentProvider { } + private int update(SQLiteDatabase db, Uri uri, ContentValues values, String selection, String[] selectionArgs) { switch (mUriMatcher.match(uri)) { case DIRECTORY: return updateFolderSize(db, selectionArgs[0]); + case SHARES: + return db.update(ProviderTableMeta.OCSHARES_TABLE_NAME, values, selection, selectionArgs); default: - return db.update(ProviderTableMeta.DB_NAME, values, selection, selectionArgs); + return db.update(ProviderTableMeta.FILE_TABLE_NAME, values, selection, selectionArgs); } } @@ -384,7 +487,7 @@ public class FileContentProvider extends ContentProvider { Log_OC.d("FileContentProvider", "Updating " + folderSize + " to " + childrenSize); ContentValues cv = new ContentValues(); cv.put(ProviderTableMeta.FILE_CONTENT_LENGTH, childrenSize); - count = db.update(ProviderTableMeta.DB_NAME, cv, folderWhere, whereArgs); + count = db.update(ProviderTableMeta.FILE_TABLE_NAME, cv, folderWhere, whereArgs); // propagate update until root if (folderParentId > FileDataStorageManager.ROOT_PARENT_ID) { @@ -433,7 +536,7 @@ public class FileContentProvider extends ContentProvider { public void onCreate(SQLiteDatabase db) { // files table Log_OC.i("SQL", "Entering in onCreate"); - db.execSQL("CREATE TABLE " + ProviderTableMeta.DB_NAME + "(" + db.execSQL("CREATE TABLE " + ProviderTableMeta.FILE_TABLE_NAME + "(" + ProviderTableMeta._ID + " INTEGER PRIMARY KEY, " + ProviderTableMeta.FILE_NAME + " TEXT, " + ProviderTableMeta.FILE_PATH + " TEXT, " @@ -448,8 +551,28 @@ public class FileContentProvider extends ContentProvider { + ProviderTableMeta.FILE_KEEP_IN_SYNC + " INTEGER, " + ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA + " INTEGER, " + ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA + " INTEGER, " - + ProviderTableMeta.FILE_ETAG + " TEXT );" + + ProviderTableMeta.FILE_ETAG + " TEXT, " + + ProviderTableMeta.FILE_SHARE_BY_LINK + " INTEGER, " + + ProviderTableMeta.FILE_PUBLIC_LINK + " TEXT );" ); + + // Create table ocshares + db.execSQL("CREATE TABLE " + ProviderTableMeta.OCSHARES_TABLE_NAME + "(" + + ProviderTableMeta._ID + " INTEGER PRIMARY KEY, " + + ProviderTableMeta.OCSHARES_FILE_SOURCE + " INTEGER, " + + ProviderTableMeta.OCSHARES_ITEM_SOURCE + " INTEGER, " + + ProviderTableMeta.OCSHARES_SHARE_TYPE + " INTEGER, " + + ProviderTableMeta.OCSHARES_SHARE_WITH + " TEXT, " + + ProviderTableMeta.OCSHARES_PATH + " TEXT, " + + ProviderTableMeta.OCSHARES_PERMISSIONS+ " INTEGER, " + + ProviderTableMeta.OCSHARES_SHARED_DATE + " INTEGER, " + + ProviderTableMeta.OCSHARES_EXPIRATION_DATE + " INTEGER, " + + ProviderTableMeta.OCSHARES_TOKEN + " TEXT, " + + ProviderTableMeta.OCSHARES_SHARE_WITH_DISPLAY_NAME + " TEXT, " + + ProviderTableMeta.OCSHARES_IS_DIRECTORY + " INTEGER, " // boolean + + ProviderTableMeta.OCSHARES_USER_ID + " INTEGER, " + + ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED + " INTEGER," + + ProviderTableMeta.OCSHARES_ACCOUNT_OWNER + " TEXT );" ); } @Override @@ -458,7 +581,7 @@ public class FileContentProvider extends ContentProvider { boolean upgraded = false; if (oldVersion == 1 && newVersion >= 2) { Log_OC.i("SQL", "Entering in the #1 ADD in onUpgrade"); - db.execSQL("ALTER TABLE " + ProviderTableMeta.DB_NAME + + db.execSQL("ALTER TABLE " + ProviderTableMeta.FILE_TABLE_NAME + " ADD COLUMN " + ProviderTableMeta.FILE_KEEP_IN_SYNC + " INTEGER " + " DEFAULT 0"); upgraded = true; @@ -467,12 +590,12 @@ public class FileContentProvider extends ContentProvider { Log_OC.i("SQL", "Entering in the #2 ADD in onUpgrade"); db.beginTransaction(); try { - db.execSQL("ALTER TABLE " + ProviderTableMeta.DB_NAME + + db.execSQL("ALTER TABLE " + ProviderTableMeta.FILE_TABLE_NAME + " ADD COLUMN " + ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA + " INTEGER " + " DEFAULT 0"); // assume there are not local changes pending to upload - db.execSQL("UPDATE " + ProviderTableMeta.DB_NAME + + db.execSQL("UPDATE " + ProviderTableMeta.FILE_TABLE_NAME + " SET " + ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA + " = " + System.currentTimeMillis() + " WHERE " + ProviderTableMeta.FILE_STORAGE_PATH + " IS NOT NULL"); @@ -486,11 +609,11 @@ public class FileContentProvider extends ContentProvider { Log_OC.i("SQL", "Entering in the #3 ADD in onUpgrade"); db.beginTransaction(); try { - db .execSQL("ALTER TABLE " + ProviderTableMeta.DB_NAME + + db .execSQL("ALTER TABLE " + ProviderTableMeta.FILE_TABLE_NAME + " ADD COLUMN " + ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA + " INTEGER " + " DEFAULT 0"); - db.execSQL("UPDATE " + ProviderTableMeta.DB_NAME + + db.execSQL("UPDATE " + ProviderTableMeta.FILE_TABLE_NAME + " SET " + ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA + " = " + ProviderTableMeta.FILE_MODIFIED + " WHERE " + ProviderTableMeta.FILE_STORAGE_PATH + " IS NOT NULL"); @@ -507,7 +630,7 @@ public class FileContentProvider extends ContentProvider { Log_OC.i("SQL", "Entering in the #4 ADD in onUpgrade"); db.beginTransaction(); try { - db .execSQL("ALTER TABLE " + ProviderTableMeta.DB_NAME + + db .execSQL("ALTER TABLE " + ProviderTableMeta.FILE_TABLE_NAME + " ADD COLUMN " + ProviderTableMeta.FILE_ETAG + " TEXT " + " DEFAULT NULL"); @@ -519,6 +642,45 @@ public class FileContentProvider extends ContentProvider { } if (!upgraded) Log_OC.i("SQL", "OUT of the ADD in onUpgrade; oldVersion == " + oldVersion + ", newVersion == " + newVersion); + + if (oldVersion < 6 && newVersion >= 6) { + Log_OC.i("SQL", "Entering in the #5 ADD in onUpgrade"); + db.beginTransaction(); + try { + db .execSQL("ALTER TABLE " + ProviderTableMeta.FILE_TABLE_NAME + + " ADD COLUMN " + ProviderTableMeta.FILE_SHARE_BY_LINK + " INTEGER " + + " DEFAULT 0"); + + db .execSQL("ALTER TABLE " + ProviderTableMeta.FILE_TABLE_NAME + + " ADD COLUMN " + ProviderTableMeta.FILE_PUBLIC_LINK + " TEXT " + + " DEFAULT NULL"); + + // Create table ocshares + db.execSQL("CREATE TABLE " + ProviderTableMeta.OCSHARES_TABLE_NAME + "(" + + ProviderTableMeta._ID + " INTEGER PRIMARY KEY, " + + ProviderTableMeta.OCSHARES_FILE_SOURCE + " INTEGER, " + + ProviderTableMeta.OCSHARES_ITEM_SOURCE + " INTEGER, " + + ProviderTableMeta.OCSHARES_SHARE_TYPE + " INTEGER, " + + ProviderTableMeta.OCSHARES_SHARE_WITH + " TEXT, " + + ProviderTableMeta.OCSHARES_PATH + " TEXT, " + + ProviderTableMeta.OCSHARES_PERMISSIONS+ " INTEGER, " + + ProviderTableMeta.OCSHARES_SHARED_DATE + " INTEGER, " + + ProviderTableMeta.OCSHARES_EXPIRATION_DATE + " INTEGER, " + + ProviderTableMeta.OCSHARES_TOKEN + " TEXT, " + + ProviderTableMeta.OCSHARES_SHARE_WITH_DISPLAY_NAME + " TEXT, " + + ProviderTableMeta.OCSHARES_IS_DIRECTORY + " INTEGER, " // boolean + + ProviderTableMeta.OCSHARES_USER_ID + " INTEGER, " + + ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED + " INTEGER," + + ProviderTableMeta.OCSHARES_ACCOUNT_OWNER + " TEXT );" ); + + upgraded = true; + db.setTransactionSuccessful(); + } finally { + db.endTransaction(); + } + } + if (!upgraded) + Log_OC.i("SQL", "OUT of the ADD in onUpgrade; oldVersion == " + oldVersion + ", newVersion == " + newVersion); } } diff --git a/src/com/owncloud/android/services/OperationsService.java b/src/com/owncloud/android/services/OperationsService.java new file mode 100644 index 00000000..919bedb3 --- /dev/null +++ b/src/com/owncloud/android/services/OperationsService.java @@ -0,0 +1,296 @@ +/* ownCloud Android client application + * Copyright (C) 2012-2013 ownCloud Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package com.owncloud.android.services; + +import java.io.IOException; +import java.util.concurrent.ConcurrentLinkedQueue; + +import com.owncloud.android.datamodel.FileDataStorageManager; + +import com.owncloud.android.lib.network.OwnCloudClientFactory; +import com.owncloud.android.lib.network.OwnCloudClient; +import com.owncloud.android.operations.GetSharesOperation; +import com.owncloud.android.operations.common.SyncOperation; +import com.owncloud.android.lib.operations.common.RemoteOperation; +import com.owncloud.android.lib.operations.common.RemoteOperationResult; +import com.owncloud.android.utils.Log_OC; + +import android.accounts.Account; +import android.accounts.AccountsException; +import android.app.Service; +import android.content.Intent; +import android.net.Uri; +import android.os.Binder; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.IBinder; +import android.os.Looper; +import android.os.Message; +import android.os.Process; +//import android.support.v4.content.LocalBroadcastManager; +import android.util.Pair; + +public class OperationsService extends Service { + + private static final String TAG = OperationsService.class.getSimpleName(); + + public static final String EXTRA_ACCOUNT = "ACCOUNT"; + public static final String EXTRA_SERVER_URL = "SERVER_URL"; + public static final String EXTRA_RESULT = "RESULT"; + + public static final String ACTION_OPERATION_ADDED = OperationsService.class.getName() + ".OPERATION_ADDED"; + public static final String ACTION_OPERATION_FINISHED = OperationsService.class.getName() + ".OPERATION_FINISHED"; + + private ConcurrentLinkedQueue> mPendingOperations = new ConcurrentLinkedQueue>(); + + private static class Target { + public Uri mServerUrl = null; + public Account mAccount = null; + public Target(Account account, Uri serverUrl) { + mAccount = account; + mServerUrl = serverUrl; + } + } + + private Looper mServiceLooper; + private ServiceHandler mServiceHandler; + private IBinder mBinder; + private OwnCloudClient mOwnCloudClient = null; + private Target mLastTarget = null; + private FileDataStorageManager mStorageManager; + private RemoteOperation mCurrentOperation = null; + + + /** + * Service initialization + */ + @Override + public void onCreate() { + super.onCreate(); + HandlerThread thread = new HandlerThread("Operations service thread", Process.THREAD_PRIORITY_BACKGROUND); + thread.start(); + mServiceLooper = thread.getLooper(); + mServiceHandler = new ServiceHandler(mServiceLooper, this); + mBinder = new OperationsServiceBinder(); + } + + /** + * Entry point to add a new operation to the queue of operations. + * + * New operations are added calling to startService(), resulting in a call to this method. + * This ensures the service will keep on working although the caller activity goes away. + * + * IMPORTANT: the only operations performed here right now is {@link GetSharedFilesOperation}. The class + * is taking advantage of it due to time constraints. + */ + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + if (!intent.hasExtra(EXTRA_ACCOUNT) && !intent.hasExtra(EXTRA_SERVER_URL)) { + Log_OC.e(TAG, "Not enough information provided in intent"); + return START_NOT_STICKY; + } + try { + Account account = intent.getParcelableExtra(EXTRA_ACCOUNT); + String serverUrl = intent.getStringExtra(EXTRA_SERVER_URL); + Target target = new Target(account, (serverUrl == null) ? null : Uri.parse(serverUrl)); + GetSharesOperation operation = new GetSharesOperation(); + mPendingOperations.add(new Pair(target, operation)); + sendBroadcastNewOperation(target, operation); + + Message msg = mServiceHandler.obtainMessage(); + msg.arg1 = startId; + mServiceHandler.sendMessage(msg); + + } catch (IllegalArgumentException e) { + Log_OC.e(TAG, "Bad information provided in intent: " + e.getMessage()); + return START_NOT_STICKY; + } + + return START_NOT_STICKY; + } + + + /** + * Provides a binder object that clients can use to perform actions on the queue of operations, + * except the addition of new operations. + */ + @Override + public IBinder onBind(Intent intent) { + return mBinder; + } + + + /** + * Called when ALL the bound clients were unbound. + */ + @Override + public boolean onUnbind(Intent intent) { + //((OperationsServiceBinder)mBinder).clearListeners(); + return false; // not accepting rebinding (default behaviour) + } + + + /** + * Binder to let client components to perform actions on the queue of operations. + * + * It provides by itself the available operations. + */ + public class OperationsServiceBinder extends Binder { + // TODO + } + + + /** + * Operations worker. Performs the pending operations in the order they were requested. + * + * Created with the Looper of a new thread, started in {@link OperationsService#onCreate()}. + */ + private static class ServiceHandler extends Handler { + // don't make it a final class, and don't remove the static ; lint will warn about a possible memory leak + OperationsService mService; + public ServiceHandler(Looper looper, OperationsService service) { + super(looper); + if (service == null) { + throw new IllegalArgumentException("Received invalid NULL in parameter 'service'"); + } + mService = service; + } + + @Override + public void handleMessage(Message msg) { + mService.nextOperation(); + mService.stopSelf(msg.arg1); + } + } + + + /** + * Performs the next operation in the queue + */ + private void nextOperation() { + + Pair next = null; + synchronized(mPendingOperations) { + next = mPendingOperations.peek(); + } + + if (next != null) { + + mCurrentOperation = next.second; + RemoteOperationResult result = null; + try { + /// prepare client object to send the request to the ownCloud server + if (mLastTarget == null || !mLastTarget.equals(next.first)) { + mLastTarget = next.first; + if (mLastTarget.mAccount != null) { + mOwnCloudClient = OwnCloudClientFactory.createOwnCloudClient(mLastTarget.mAccount, getApplicationContext()); + mStorageManager = new FileDataStorageManager(mLastTarget.mAccount, getContentResolver()); + } else { + mOwnCloudClient = OwnCloudClientFactory.createOwnCloudClient(mLastTarget.mServerUrl, getApplicationContext(), true); // this is not good enough + mStorageManager = null; + } + } + + /// perform the operation + if (mCurrentOperation instanceof SyncOperation) { + result = ((SyncOperation)mCurrentOperation).execute(mOwnCloudClient, mStorageManager); + } else { + result = mCurrentOperation.execute(mOwnCloudClient); + } + + } catch (AccountsException e) { + if (mLastTarget.mAccount == null) { + Log_OC.e(TAG, "Error while trying to get autorization for a NULL account", e); + } else { + Log_OC.e(TAG, "Error while trying to get autorization for " + mLastTarget.mAccount.name, e); + } + result = new RemoteOperationResult(e); + + } catch (IOException e) { + if (mLastTarget.mAccount == null) { + Log_OC.e(TAG, "Error while trying to get autorization for a NULL account", e); + } else { + Log_OC.e(TAG, "Error while trying to get autorization for " + mLastTarget.mAccount.name, e); + } + result = new RemoteOperationResult(e); + } catch (Exception e) { + if (mLastTarget.mAccount == null) { + Log_OC.e(TAG, "Unexpected error for a NULL account", e); + } else { + Log_OC.e(TAG, "Unexpected error for " + mLastTarget.mAccount.name, e); + } + result = new RemoteOperationResult(e); + + } finally { + synchronized(mPendingOperations) { + mPendingOperations.poll(); + } + } + + sendBroadcastOperationFinished(mLastTarget, mCurrentOperation, result); + } + } + + + /** + * Sends a LOCAL broadcast when a new operation is added to the queue. + * + * Local broadcasts are only delivered to activities in the same process. + * + * @param target Account or URL pointing to an OC server. + * @param operation Added operation. + */ + private void sendBroadcastNewOperation(Target target, RemoteOperation operation) { + Intent intent = new Intent(ACTION_OPERATION_ADDED); + if (target.mAccount != null) { + intent.putExtra(EXTRA_ACCOUNT, target.mAccount); + } else { + intent.putExtra(EXTRA_SERVER_URL, target.mServerUrl); + } + //LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(this); + //lbm.sendBroadcast(intent); + sendStickyBroadcast(intent); + } + + + // TODO - maybe add a notification for real start of operations + + /** + * Sends a LOCAL broadcast when an operations finishes in order to the interested activities can update their view + * + * Local broadcasts are only delivered to activities in the same process. + * + * @param target Account or URL pointing to an OC server. + * @param operation Finished operation. + * @param result Result of the operation. + */ + private void sendBroadcastOperationFinished(Target target, RemoteOperation operation, RemoteOperationResult result) { + Intent intent = new Intent(ACTION_OPERATION_FINISHED); + intent.putExtra(EXTRA_RESULT, result); + if (target.mAccount != null) { + intent.putExtra(EXTRA_ACCOUNT, target.mAccount); + } else { + intent.putExtra(EXTRA_SERVER_URL, target.mServerUrl); + } + //LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(this); + //lbm.sendBroadcast(intent); + sendStickyBroadcast(intent); + } + + +} diff --git a/src/com/owncloud/android/syncadapter/FileSyncAdapter.java b/src/com/owncloud/android/syncadapter/FileSyncAdapter.java index c47a251f..6b2ea73e 100644 --- a/src/com/owncloud/android/syncadapter/FileSyncAdapter.java +++ b/src/com/owncloud/android/syncadapter/FileSyncAdapter.java @@ -30,6 +30,7 @@ import com.owncloud.android.R; import com.owncloud.android.authentication.AuthenticatorActivity; import com.owncloud.android.datamodel.FileDataStorageManager; import com.owncloud.android.datamodel.OCFile; +import com.owncloud.android.lib.accounts.OwnCloudAccount; import com.owncloud.android.lib.operations.common.RemoteOperationResult; import com.owncloud.android.operations.SynchronizeFolderOperation; import com.owncloud.android.operations.UpdateOCVersionOperation; @@ -40,6 +41,7 @@ import com.owncloud.android.utils.Log_OC; import android.accounts.Account; +import android.accounts.AccountManager; import android.accounts.AccountsException; import android.app.Notification; import android.app.NotificationManager; @@ -51,6 +53,7 @@ import android.content.Context; import android.content.Intent; import android.content.SyncResult; import android.os.Bundle; +//import android.support.v4.content.LocalBroadcastManager; /** * Implementation of {@link AbstractThreadedSyncAdapter} responsible for synchronizing @@ -69,6 +72,16 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter { private static final int MAX_FAILED_RESULTS = 3; + public static final String EVENT_FULL_SYNC_START = FileSyncAdapter.class.getName() + ".EVENT_FULL_SYNC_START"; + public static final String EVENT_FULL_SYNC_END = FileSyncAdapter.class.getName() + ".EVENT_FULL_SYNC_END"; + public static final String EVENT_FULL_SYNC_FOLDER_CONTENTS_SYNCED = FileSyncAdapter.class.getName() + ".EVENT_FULL_SYNC_FOLDER_CONTENTS_SYNCED"; + public static final String EVENT_FULL_SYNC_FOLDER_SIZE_SYNCED = FileSyncAdapter.class.getName() + ".EVENT_FULL_SYNC_FOLDER_SIZE_SYNCED"; + + public static final String EXTRA_ACCOUNT_NAME = FileSyncAdapter.class.getName() + ".EXTRA_ACCOUNT_NAME"; + public static final String EXTRA_FOLDER_PATH = FileSyncAdapter.class.getName() + ".EXTRA_FOLDER_PATH"; + public static final String EXTRA_RESULT = FileSyncAdapter.class.getName() + ".EXTRA_RESULT"; + + /** Time stamp for the current synchronization process, used to distinguish fresh data */ private long mCurrentSyncTime; @@ -95,6 +108,9 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter { /** {@link SyncResult} instance to return to the system when the synchronization finish */ private SyncResult mSyncResult; + + /** 'True' means that the server supports the share API */ + private boolean mIsSharedSupported; /** @@ -139,6 +155,10 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter { this.setAccount(account); this.setContentProviderClient(providerClient); this.setStorageManager(new FileDataStorageManager(account, providerClient)); + + AccountManager accountManager = getAccountManager(); + mIsSharedSupported = Boolean.parseBoolean(accountManager.getUserData(account, OwnCloudAccount.Constants.KEY_SUPPORTS_SHARE_API)); + try { this.initClientForCurrentAccount(); } catch (IOException e) { @@ -154,7 +174,7 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter { } Log_OC.d(TAG, "Synchronization of ownCloud account " + account.name + " starting"); - sendStickyBroadcast(true, null, null); // message to signal the start of the synchronization to the UI + sendLocalBroadcast(EVENT_FULL_SYNC_START, null, null); // message to signal the start of the synchronization to the UI try { updateOCVersion(); @@ -184,7 +204,7 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter { if (mForgottenLocalFiles.size() > 0) { notifyForgottenLocalFiles(); } - sendStickyBroadcast(false, null, mLastFailedResult); // message to signal the end to the UI + sendLocalBroadcast(EVENT_FULL_SYNC_END, null, mLastFailedResult); // message to signal the end to the UI } } @@ -243,13 +263,13 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter { DataStorageManager dataStorageManager, Account account, Context context ) { - } */ // folder synchronization SynchronizeFolderOperation synchFolderOp = new SynchronizeFolderOperation( folder, mCurrentSyncTime, true, + mIsSharedSupported, getStorageManager(), getAccount(), getContext() @@ -258,7 +278,7 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter { // synchronized folder -> notice to UI - ALWAYS, although !result.isSuccess - sendStickyBroadcast(true, folder.getRemotePath(), null); + sendLocalBroadcast(EVENT_FULL_SYNC_FOLDER_CONTENTS_SYNCED, folder.getRemotePath(), result); // check the result of synchronizing the folder if (result.isSuccess() || result.getCode() == ResultCode.SYNC_CONFLICT) { @@ -332,9 +352,7 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter { syncDown = (parentEtagChanged || etag == null || etag.length() == 0); if(syncDown) { */ synchronizeFolder(newFile); - // update the size of the parent folder again after recursive synchronization - //getStorageManager().updateFolderSize(parent.getFileId()); - sendStickyBroadcast(true, parent.getRemotePath(), null); // notify again to refresh size in UI + sendLocalBroadcast(EVENT_FULL_SYNC_FOLDER_SIZE_SYNCED, parent.getRemotePath(), null); //} } } @@ -346,20 +364,22 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter { /** * Sends a message to any application component interested in the progress of the synchronization. * - * @param inProgress 'True' when the synchronization progress is not finished. - * @param dirRemotePath Remote path of a folder that was just synchronized (with or without success) + * @param event Event in the process of synchronization to be notified. + * @param dirRemotePath Remote path of the folder target of the event occurred. + * @param result Result of an individual {@ SynchronizeFolderOperation}, if completed; may be null. */ - private void sendStickyBroadcast(boolean inProgress, String dirRemotePath, RemoteOperationResult result) { - Intent i = new Intent(FileSyncService.getSyncMessage()); - i.putExtra(FileSyncService.IN_PROGRESS, inProgress); - i.putExtra(FileSyncService.ACCOUNT_NAME, getAccount().name); + private void sendLocalBroadcast(String event, String dirRemotePath, RemoteOperationResult result) { + Log_OC.d(TAG, "Send broadcast " + event); + Intent intent = new Intent(event); + intent.putExtra(FileSyncAdapter.EXTRA_ACCOUNT_NAME, getAccount().name); if (dirRemotePath != null) { - i.putExtra(FileSyncService.SYNC_FOLDER_REMOTE_PATH, dirRemotePath); + intent.putExtra(FileSyncAdapter.EXTRA_FOLDER_PATH, dirRemotePath); } if (result != null) { - i.putExtra(FileSyncService.SYNC_RESULT, result); + intent.putExtra(FileSyncAdapter.EXTRA_RESULT, result); } - getContext().sendStickyBroadcast(i); + getContext().sendStickyBroadcast(intent); + //LocalBroadcastManager.getInstance(getContext()).sendBroadcast(intent); } diff --git a/src/com/owncloud/android/syncadapter/FileSyncService.java b/src/com/owncloud/android/syncadapter/FileSyncService.java index 9ae051ca..5da8c24c 100644 --- a/src/com/owncloud/android/syncadapter/FileSyncService.java +++ b/src/com/owncloud/android/syncadapter/FileSyncService.java @@ -31,20 +31,11 @@ import android.os.IBinder; */ public class FileSyncService extends Service { - private static final String SYNC_MESSAGE = "ACCOUNT_SYNC"; - public static final String SYNC_FOLDER_REMOTE_PATH = "SYNC_FOLDER_REMOTE_PATH"; - public static final String IN_PROGRESS = "SYNC_IN_PROGRESS"; - public static final String ACCOUNT_NAME = "ACCOUNT_NAME"; - public static final String SYNC_RESULT = "SYNC_RESULT"; - // Storage for an instance of the sync adapter private static FileSyncAdapter sSyncAdapter = null; // Object to use as a thread-safe lock private static final Object sSyncAdapterLock = new Object(); - public static String getSyncMessage(){ - return FileSyncService.class.getName().toString() + SYNC_MESSAGE; - } /* * {@inheritDoc} */ diff --git a/src/com/owncloud/android/ui/activity/ConflictsResolveActivity.java b/src/com/owncloud/android/ui/activity/ConflictsResolveActivity.java index 5b22c341..fbbc5dff 100644 --- a/src/com/owncloud/android/ui/activity/ConflictsResolveActivity.java +++ b/src/com/owncloud/android/ui/activity/ConflictsResolveActivity.java @@ -19,7 +19,6 @@ package com.owncloud.android.ui.activity; import com.actionbarsherlock.app.ActionBar; -import com.owncloud.android.datamodel.FileDataStorageManager; import com.owncloud.android.datamodel.OCFile; import com.owncloud.android.files.services.FileUploader; import com.owncloud.android.ui.dialog.ConflictsResolveDialog; @@ -77,6 +76,7 @@ public class ConflictsResolveActivity extends FileActivity implements OnConflict @Override protected void onAccountSet(boolean stateWasRecovered) { + super.onAccountSet(stateWasRecovered); if (getAccount() != null) { OCFile file = getFile(); if (getFile() == null) { @@ -84,8 +84,7 @@ public class ConflictsResolveActivity extends FileActivity implements OnConflict finish(); } else { /// Check whether the 'main' OCFile handled by the Activity is contained in the current Account - FileDataStorageManager storageManager = new FileDataStorageManager(getAccount(), getContentResolver()); - file = storageManager.getFileByPath(file.getRemotePath()); // file = null if not in the current Account + file = getStorageManager().getFileByPath(file.getRemotePath()); // file = null if not in the current Account if (file != null) { setFile(file); ConflictsResolveDialog d = ConflictsResolveDialog.newInstance(file.getRemotePath(), this); @@ -98,7 +97,6 @@ public class ConflictsResolveActivity extends FileActivity implements OnConflict } } else { - Log_OC.wtf(TAG, "onAccountChanged was called with NULL account associated!"); finish(); } diff --git a/src/com/owncloud/android/ui/activity/FileActivity.java b/src/com/owncloud/android/ui/activity/FileActivity.java index 3d2323fb..3c8a2011 100644 --- a/src/com/owncloud/android/ui/activity/FileActivity.java +++ b/src/com/owncloud/android/ui/activity/FileActivity.java @@ -24,16 +24,27 @@ import android.accounts.AccountManagerCallback; import android.accounts.AccountManagerFuture; import android.accounts.OperationCanceledException; import android.content.Intent; -import android.net.Uri; import android.os.Bundle; -import android.webkit.MimeTypeMap; +import android.os.Handler; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentManager; +import android.support.v4.app.FragmentTransaction; +import android.widget.Toast; import com.actionbarsherlock.app.SherlockFragmentActivity; import com.owncloud.android.MainApp; import com.owncloud.android.R; import com.owncloud.android.authentication.AccountUtils; +import com.owncloud.android.datamodel.FileDataStorageManager; import com.owncloud.android.datamodel.OCFile; -import com.owncloud.android.lib.network.webdav.WebdavUtils; +import com.owncloud.android.files.FileOperationsHelper; +import com.owncloud.android.lib.operations.common.OnRemoteOperationListener; +import com.owncloud.android.lib.operations.common.RemoteOperation; +import com.owncloud.android.lib.operations.common.RemoteOperationResult; +import com.owncloud.android.lib.operations.common.RemoteOperationResult.ResultCode; +import com.owncloud.android.operations.CreateShareOperation; + +import com.owncloud.android.ui.dialog.LoadingDialog; import com.owncloud.android.utils.Log_OC; @@ -42,14 +53,16 @@ import com.owncloud.android.utils.Log_OC; * * @author David A. Velasco */ -public abstract class FileActivity extends SherlockFragmentActivity { +public class FileActivity extends SherlockFragmentActivity implements OnRemoteOperationListener { public static final String EXTRA_FILE = "com.owncloud.android.ui.activity.FILE"; public static final String EXTRA_ACCOUNT = "com.owncloud.android.ui.activity.ACCOUNT"; public static final String EXTRA_WAITING_TO_PREVIEW = "com.owncloud.android.ui.activity.WAITING_TO_PREVIEW"; public static final String EXTRA_FROM_NOTIFICATION= "com.owncloud.android.ui.activity.FROM_NOTIFICATION"; - public static final String TAG = FileActivity.class.getSimpleName(); + public static final String TAG = FileActivity.class.getSimpleName(); + + private static final String DIALOG_WAIT_TAG = "DIALOG_WAIT"; /** OwnCloud {@link Account} where the main {@link OCFile} handled by the activity is located. */ @@ -69,6 +82,14 @@ public abstract class FileActivity extends SherlockFragmentActivity { /** Flag to signal if the activity is launched by a notification */ private boolean mFromNotification; + + /** Messages handler associated to the main thread and the life cycle of the activity */ + private Handler mHandler; + + /** Access point to the cached database for the current ownCloud {@link Account} */ + private FileDataStorageManager mStorageManager = null; + + private FileOperationsHelper mFileOperationsHelper; /** @@ -81,7 +102,8 @@ public abstract class FileActivity extends SherlockFragmentActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - + mHandler = new Handler(); + mFileOperationsHelper = new FileOperationsHelper(); Account account; if(savedInstanceState != null) { account = savedInstanceState.getParcelable(FileActivity.EXTRA_ACCOUNT); @@ -94,6 +116,7 @@ public abstract class FileActivity extends SherlockFragmentActivity { } setAccount(account, savedInstanceState != null); + } @@ -292,40 +315,85 @@ public abstract class FileActivity extends SherlockFragmentActivity { * * Child classes must grant that state depending on the {@link Account} is updated. */ - protected abstract void onAccountSet(boolean stateWasRecovered); + protected void onAccountSet(boolean stateWasRecovered) { + if (getAccount() != null) { + mStorageManager = new FileDataStorageManager(getAccount(), getContentResolver()); + + } else { + Log_OC.wtf(TAG, "onAccountChanged was called with NULL account associated!"); + } + } + + + public FileDataStorageManager getStorageManager() { + return mStorageManager; + } + + + public OnRemoteOperationListener getRemoteOperationListener() { + return this; + } + + + public Handler getHandler() { + return mHandler; + } + public FileOperationsHelper getFileOperationsHelper() { + return mFileOperationsHelper; + } + /** + * + * @param operation Removal operation performed. + * @param result Result of the removal. + */ + @Override + public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationResult result) { + Log_OC.d(TAG, "Received result of operation in FileActivity - common behaviour for all the FileActivities "); + if (operation instanceof CreateShareOperation) { + onCreateShareOperationFinish((CreateShareOperation) operation, result); + } + } - public void openFile(OCFile file) { - if (file != null) { - String storagePath = file.getStoragePath(); - String encodedStoragePath = WebdavUtils.encodePath(storagePath); - - Intent intentForSavedMimeType = new Intent(Intent.ACTION_VIEW); - intentForSavedMimeType.setDataAndType(Uri.parse("file://"+ encodedStoragePath), file.getMimetype()); - intentForSavedMimeType.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); - - Intent intentForGuessedMimeType = null; - if (storagePath.lastIndexOf('.') >= 0) { - String guessedMimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(storagePath.substring(storagePath.lastIndexOf('.') + 1)); - if (guessedMimeType != null && !guessedMimeType.equals(file.getMimetype())) { - intentForGuessedMimeType = new Intent(Intent.ACTION_VIEW); - intentForGuessedMimeType.setDataAndType(Uri.parse("file://"+ encodedStoragePath), guessedMimeType); - intentForGuessedMimeType.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); - } - } + private void onCreateShareOperationFinish(CreateShareOperation operation, RemoteOperationResult result) { + dismissLoadingDialog(); + if (result.isSuccess()) { + Intent sendIntent = operation.getSendIntent(); + startActivity(sendIntent); - Intent chooserIntent = null; - if (intentForGuessedMimeType != null) { - chooserIntent = Intent.createChooser(intentForGuessedMimeType, getString(R.string.actionbar_open_with)); - } else { - chooserIntent = Intent.createChooser(intentForSavedMimeType, getString(R.string.actionbar_open_with)); - } - - startActivity(chooserIntent); - - } else { - Log_OC.wtf(TAG, "Trying to open a NULL OCFile"); + } else if (result.getCode() == ResultCode.FILE_NOT_FOUND) { // Error --> SHARE_NOT_FOUND + Toast t = Toast.makeText(this, getString(R.string.share_link_file_no_exist), Toast.LENGTH_LONG); + t.show(); + } else { // Generic error + // Show a Message, operation finished without success + Toast t = Toast.makeText(this, getString(R.string.share_link_file_error), Toast.LENGTH_LONG); + t.show(); + } + } + + + /** + * Show loading dialog + */ + public void showLoadingDialog() { + // Construct dialog + LoadingDialog loading = new LoadingDialog(getResources().getString(R.string.wait_a_moment)); + FragmentManager fm = getSupportFragmentManager(); + FragmentTransaction ft = fm.beginTransaction(); + loading.show(ft, DIALOG_WAIT_TAG); + + } + + + /** + * Dismiss loading dialog + */ + public void dismissLoadingDialog(){ + Fragment frag = getSupportFragmentManager().findFragmentByTag(DIALOG_WAIT_TAG); + if (frag != null) { + LoadingDialog loading = (LoadingDialog) frag; + loading.dismiss(); } } diff --git a/src/com/owncloud/android/ui/activity/FileDisplayActivity.java b/src/com/owncloud/android/ui/activity/FileDisplayActivity.java index 04d0eeec..d5c0d5a9 100644 --- a/src/com/owncloud/android/ui/activity/FileDisplayActivity.java +++ b/src/com/owncloud/android/ui/activity/FileDisplayActivity.java @@ -38,13 +38,12 @@ import android.content.res.Resources.NotFoundException; import android.database.Cursor; import android.net.Uri; import android.os.Bundle; -import android.os.Handler; import android.os.IBinder; import android.preference.PreferenceManager; import android.provider.MediaStore; import android.support.v4.app.Fragment; -import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentTransaction; +//import android.support.v4.content.LocalBroadcastManager; import android.util.Log; import android.view.View; import android.view.ViewGroup; @@ -60,7 +59,6 @@ import com.actionbarsherlock.view.MenuItem; import com.actionbarsherlock.view.Window; import com.owncloud.android.MainApp; import com.owncloud.android.R; -import com.owncloud.android.datamodel.FileDataStorageManager; import com.owncloud.android.datamodel.OCFile; import com.owncloud.android.files.services.FileDownloader; import com.owncloud.android.files.services.FileObserverService; @@ -68,18 +66,19 @@ import com.owncloud.android.files.services.FileUploader; import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder; import com.owncloud.android.files.services.FileUploader.FileUploaderBinder; import com.owncloud.android.operations.CreateFolderOperation; -import com.owncloud.android.lib.operations.common.OnRemoteOperationListener; + import com.owncloud.android.lib.operations.common.RemoteOperation; import com.owncloud.android.lib.operations.common.RemoteOperationResult; import com.owncloud.android.lib.operations.common.RemoteOperationResult.ResultCode; +import com.owncloud.android.operations.CreateShareOperation; import com.owncloud.android.operations.RemoveFileOperation; import com.owncloud.android.operations.RenameFileOperation; import com.owncloud.android.operations.SynchronizeFileOperation; import com.owncloud.android.operations.SynchronizeFolderOperation; -import com.owncloud.android.syncadapter.FileSyncService; +import com.owncloud.android.services.OperationsService; +import com.owncloud.android.syncadapter.FileSyncAdapter; import com.owncloud.android.ui.dialog.EditNameDialog; import com.owncloud.android.ui.dialog.EditNameDialog.EditNameDialogListener; -import com.owncloud.android.ui.dialog.LoadingDialog; import com.owncloud.android.ui.dialog.SslValidatorDialog; import com.owncloud.android.ui.dialog.SslValidatorDialog.OnSslValidatorListener; import com.owncloud.android.ui.fragment.FileDetailFragment; @@ -99,17 +98,15 @@ import com.owncloud.android.utils.Log_OC; * @author David A. Velasco */ -public class FileDisplayActivity extends FileActivity implements -OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNavigationListener, OnSslValidatorListener, OnRemoteOperationListener, EditNameDialogListener { +public class FileDisplayActivity extends HookActivity implements +OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNavigationListener, OnSslValidatorListener, EditNameDialogListener { private ArrayAdapter mDirectories; - /** Access point to the cached database for the current ownCloud {@link Account} */ - private FileDataStorageManager mStorageManager = null; - private SyncBroadcastReceiver mSyncBroadcastReceiver; private UploadFinishReceiver mUploadFinishReceiver; private DownloadFinishReceiver mDownloadFinishReceiver; + //private OperationsServiceReceiver mOperationsServiceReceiver; private FileDownloaderBinder mDownloaderBinder = null; private FileUploaderBinder mUploaderBinder = null; private ServiceConnection mDownloadConnection = null, mUploadConnection = null; @@ -121,14 +118,13 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa private static final String KEY_WAITING_TO_PREVIEW = "WAITING_TO_PREVIEW"; private static final String KEY_SYNC_IN_PROGRESS = "SYNC_IN_PROGRESS"; + private static final String KEY_REFRESH_SHARES_IN_PROGRESS = "SHARES_IN_PROGRESS"; public static final int DIALOG_SHORT_WAIT = 0; private static final int DIALOG_CHOOSE_UPLOAD_SOURCE = 1; private static final int DIALOG_SSL_VALIDATOR = 2; private static final int DIALOG_CERT_NOT_SAVED = 3; - private static final String DIALOG_WAIT_TAG = "DIALOG_WAIT"; - public static final String ACTION_DETAILS = "com.owncloud.android.ui.activity.action.DETAILS"; private static final int ACTION_SELECT_CONTENT_FROM_APPS = 1; @@ -140,9 +136,9 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa private static final String TAG_SECOND_FRAGMENT = "SECOND_FRAGMENT"; private OCFile mWaitingToPreview; - private Handler mHandler; private boolean mSyncInProgress = false; + //private boolean mRefreshSharesInProgress = false; @Override protected void onCreate(Bundle savedInstanceState) { @@ -151,8 +147,6 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa super.onCreate(savedInstanceState); // this calls onAccountChanged() when ownCloud Account is valid - mHandler = new Handler(); - /// bindings to transference services mUploadConnection = new ListServiceConnection(); mDownloadConnection = new ListServiceConnection(); @@ -175,10 +169,12 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa if(savedInstanceState != null) { mWaitingToPreview = (OCFile) savedInstanceState.getParcelable(FileDisplayActivity.KEY_WAITING_TO_PREVIEW); mSyncInProgress = savedInstanceState.getBoolean(KEY_SYNC_IN_PROGRESS); + //mRefreshSharesInProgress = savedInstanceState.getBoolean(KEY_REFRESH_SHARES_IN_PROGRESS); } else { mWaitingToPreview = null; mSyncInProgress = false; + //mRefreshSharesInProgress = false; } /// USER INTERFACE @@ -195,7 +191,7 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa // Action bar setup mDirectories = new CustomArrayAdapter(this, R.layout.sherlock_spinner_dropdown_item); getSupportActionBar().setHomeButtonEnabled(true); // mandatory since Android ICS, according to the official documentation - setSupportProgressBarIndeterminateVisibility(mSyncInProgress); // always AFTER setContentView(...) ; to work around bug in its implementation + setSupportProgressBarIndeterminateVisibility(mSyncInProgress /*|| mRefreshSharesInProgress*/); // always AFTER setContentView(...) ; to work around bug in its implementation Log_OC.d(TAG, "onCreate() end"); } @@ -221,9 +217,8 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa */ @Override protected void onAccountSet(boolean stateWasRecovered) { + super.onAccountSet(stateWasRecovered); if (getAccount() != null) { - mStorageManager = new FileDataStorageManager(getAccount(), getContentResolver()); - /// Check whether the 'main' OCFile handled by the Activity is contained in the current Account OCFile file = getFile(); // get parent from path @@ -233,18 +228,19 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa // upload in progress - right now, files are not inserted in the local cache until the upload is successful // get parent from path parentPath = file.getRemotePath().substring(0, file.getRemotePath().lastIndexOf(file.getFileName())); - if (mStorageManager.getFileByPath(parentPath) == null) + if (getStorageManager().getFileByPath(parentPath) == null) file = null; // not able to know the directory where the file is uploading } else { - file = mStorageManager.getFileByPath(file.getRemotePath()); // currentDir = null if not in the current Account + file = getStorageManager().getFileByPath(file.getRemotePath()); // currentDir = null if not in the current Account } } if (file == null) { // fall back to root folder - file = mStorageManager.getFileByPath(OCFile.ROOT_PATH); // never returns null + file = getStorageManager().getFileByPath(OCFile.ROOT_PATH); // never returns null } setFile(file); setNavigationListWithFolder(file); + if (!stateWasRecovered) { Log_OC.e(TAG, "Initializing Fragments in onAccountChanged.."); initFragmentsWithFile(); @@ -256,10 +252,6 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa updateFragmentsVisibility(!file.isFolder()); updateNavigationElementsInActionBar(file.isFolder() ? null : file); } - - - } else { - Log_OC.wtf(TAG, "onAccountChanged was called with NULL account associated!"); } } @@ -272,10 +264,9 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa if (fileIt.isFolder()) { mDirectories.add(fileIt.getFileName()); } - //fileIt = mStorageManager.getFileById(fileIt.getParentId()); // get parent from path parentPath = fileIt.getRemotePath().substring(0, fileIt.getRemotePath().lastIndexOf(fileIt.getFileName())); - fileIt = mStorageManager.getFileByPath(parentPath); + fileIt = getStorageManager().getFileByPath(parentPath); } mDirectories.add(OCFile.PATH_SEPARATOR); } @@ -437,12 +428,12 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa boolean detailsFragmentChanged = false; if (waitedPreview) { if (success) { - mWaitingToPreview = mStorageManager.getFileById(mWaitingToPreview.getFileId()); // update the file from database, for the local storage path + mWaitingToPreview = getStorageManager().getFileById(mWaitingToPreview.getFileId()); // update the file from database, for the local storage path if (PreviewMediaFragment.canBePreviewed(mWaitingToPreview)) { startMediaPreview(mWaitingToPreview, 0, true); detailsFragmentChanged = true; } else { - openFile(mWaitingToPreview); + getFileOperationsHelper().openFile(mWaitingToPreview, this); } } mWaitingToPreview = null; @@ -454,7 +445,6 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa } } - @Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getSherlock().getMenuInflater(); @@ -533,7 +523,7 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa targetPath = mDirectories.getItem(i) + OCFile.PATH_SEPARATOR + targetPath; } targetPath = OCFile.PATH_SEPARATOR + targetPath; - OCFile targetFolder = mStorageManager.getFileByPath(targetPath); + OCFile targetFolder = getStorageManager().getFileByPath(targetPath); if (targetFolder != null) { browseTo(targetFolder); } @@ -541,7 +531,8 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa // the next operation triggers a new call to this method, but it's necessary to // ensure that the name exposed in the action bar is the current directory when the // user selected it in the navigation list - getSupportActionBar().setSelectedNavigationItem(0); + if (getSupportActionBar().getNavigationMode() == ActionBar.NAVIGATION_MODE_LIST && itemPosition != 0) + getSupportActionBar().setSelectedNavigationItem(0); } return true; } @@ -667,6 +658,7 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa super.onSaveInstanceState(outState); outState.putParcelable(FileDisplayActivity.KEY_WAITING_TO_PREVIEW, mWaitingToPreview); outState.putBoolean(FileDisplayActivity.KEY_SYNC_IN_PROGRESS, mSyncInProgress); + //outState.putBoolean(FileDisplayActivity.KEY_REFRESH_SHARES_IN_PROGRESS, mRefreshSharesInProgress); Log_OC.d(TAG, "onSaveInstanceState() end"); } @@ -679,9 +671,15 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa Log_OC.e(TAG, "onResume() start"); // Listen for sync messages - IntentFilter syncIntentFilter = new IntentFilter(FileSyncService.getSyncMessage()); + IntentFilter syncIntentFilter = new IntentFilter(FileSyncAdapter.EVENT_FULL_SYNC_START); + syncIntentFilter.addAction(FileSyncAdapter.EVENT_FULL_SYNC_END); + syncIntentFilter.addAction(FileSyncAdapter.EVENT_FULL_SYNC_FOLDER_SIZE_SYNCED); + syncIntentFilter.addAction(FileSyncAdapter.EVENT_FULL_SYNC_FOLDER_CONTENTS_SYNCED); + syncIntentFilter.addAction(SynchronizeFolderOperation.EVENT_SINGLE_FOLDER_CONTENTS_SYNCED); + syncIntentFilter.addAction(SynchronizeFolderOperation.EVENT_SINGLE_FOLDER_SHARES_SYNCED); mSyncBroadcastReceiver = new SyncBroadcastReceiver(); registerReceiver(mSyncBroadcastReceiver, syncIntentFilter); + //LocalBroadcastManager.getInstance(this).registerReceiver(mSyncBroadcastReceiver, syncIntentFilter); // Listen for upload messages IntentFilter uploadIntentFilter = new IntentFilter(FileUploader.getUploadFinishMessage()); @@ -693,6 +691,14 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa downloadIntentFilter.addAction(FileDownloader.getDownloadFinishMessage()); mDownloadFinishReceiver = new DownloadFinishReceiver(); registerReceiver(mDownloadFinishReceiver, downloadIntentFilter); + + // Listen for messages from the OperationsService + /* + IntentFilter operationsIntentFilter = new IntentFilter(OperationsService.ACTION_OPERATION_ADDED); + operationsIntentFilter.addAction(OperationsService.ACTION_OPERATION_FINISHED); + mOperationsServiceReceiver = new OperationsServiceReceiver(); + LocalBroadcastManager.getInstance(this).registerReceiver(mOperationsServiceReceiver, operationsIntentFilter); + */ Log_OC.d(TAG, "onResume() end"); } @@ -704,6 +710,7 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa Log_OC.e(TAG, "onPause() start"); if (mSyncBroadcastReceiver != null) { unregisterReceiver(mSyncBroadcastReceiver); + //LocalBroadcastManager.getInstance(this).unregisterReceiver(mSyncBroadcastReceiver); mSyncBroadcastReceiver = null; } if (mUploadFinishReceiver != null) { @@ -714,7 +721,12 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa unregisterReceiver(mDownloadFinishReceiver); mDownloadFinishReceiver = null; } - + /* + if (mOperationsServiceReceiver != null) { + LocalBroadcastManager.getInstance(this).unregisterReceiver(mOperationsServiceReceiver); + mOperationsServiceReceiver = null; + } + */ Log_OC.d(TAG, "onPause() end"); } @@ -811,30 +823,6 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa /** - * Show loading dialog - */ - public void showLoadingDialog() { - // Construct dialog - LoadingDialog loading = new LoadingDialog(getResources().getString(R.string.wait_a_moment)); - FragmentManager fm = getSupportFragmentManager(); - FragmentTransaction ft = fm.beginTransaction(); - loading.show(ft, DIALOG_WAIT_TAG); - - } - - /** - * Dismiss loading dialog - */ - public void dismissLoadingDialog(){ - Fragment frag = getSupportFragmentManager().findFragmentByTag(DIALOG_WAIT_TAG); - if (frag != null) { - LoadingDialog loading = (LoadingDialog) frag; - loading.dismiss(); - } - } - - - /** * Translates a content URI of an image to a physical path * on the disk * @param uri The URI to resolve @@ -886,6 +874,8 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa ((TextView) v).setTextColor(getResources().getColorStateList( android.R.color.white)); + + fixRoot((TextView) v ); return v; } @@ -896,9 +886,16 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa ((TextView) v).setTextColor(getResources().getColorStateList( android.R.color.white)); + fixRoot((TextView) v ); return v; } + private void fixRoot(TextView v) { + if (v.getText().equals(OCFile.PATH_SEPARATOR)) { + v.setText(R.string.default_display_name_for_root_folder); + } + } + } private class SyncBroadcastReceiver extends BroadcastReceiver { @@ -908,47 +905,65 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa */ @Override public void onReceive(Context context, Intent intent) { - boolean inProgress = intent.getBooleanExtra(FileSyncService.IN_PROGRESS, false); - String accountName = intent.getStringExtra(FileSyncService.ACCOUNT_NAME); - RemoteOperationResult synchResult = (RemoteOperationResult)intent.getSerializableExtra(FileSyncService.SYNC_RESULT); - - if (getAccount() != null && accountName.equals(getAccount().name) - && mStorageManager != null - ) { - - String synchFolderRemotePath = intent.getStringExtra(FileSyncService.SYNC_FOLDER_REMOTE_PATH); - - OCFile currentFile = (getFile() == null) ? null : mStorageManager.getFileByPath(getFile().getRemotePath()); - OCFile currentDir = (getCurrentDir() == null) ? null : mStorageManager.getFileByPath(getCurrentDir().getRemotePath()); - - if (currentDir == null) { - // current folder was removed from the server - Toast.makeText( FileDisplayActivity.this, - String.format(getString(R.string.sync_current_folder_was_removed), mDirectories.getItem(0)), - Toast.LENGTH_LONG) - .show(); - browseToRoot(); + String event = intent.getAction(); + Log_OC.d(TAG, "Received broadcast " + event); + String accountName = intent.getStringExtra(FileSyncAdapter.EXTRA_ACCOUNT_NAME); + String synchFolderRemotePath = intent.getStringExtra(FileSyncAdapter.EXTRA_FOLDER_PATH); + RemoteOperationResult synchResult = (RemoteOperationResult)intent.getSerializableExtra(FileSyncAdapter.EXTRA_RESULT); + boolean sameAccount = (getAccount() != null && accountName.equals(getAccount().name) && getStorageManager() != null); + + if (sameAccount) { + + if (FileSyncAdapter.EVENT_FULL_SYNC_START.equals(event)) { + mSyncInProgress = true; } else { - if (currentFile == null && !getFile().isFolder()) { - // currently selected file was removed in the server, and now we know it - cleanSecondFragment(); - currentFile = currentDir; - } - - if (synchFolderRemotePath != null && currentDir.getRemotePath().equals(synchFolderRemotePath)) { - OCFileListFragment fileListFragment = getListOfFilesFragment(); - if (fileListFragment != null) { - fileListFragment.listDirectory(currentDir); + OCFile currentFile = (getFile() == null) ? null : getStorageManager().getFileByPath(getFile().getRemotePath()); + OCFile currentDir = (getCurrentDir() == null) ? null : getStorageManager().getFileByPath(getCurrentDir().getRemotePath()); + + if (currentDir == null) { + // current folder was removed from the server + Toast.makeText( FileDisplayActivity.this, + String.format(getString(R.string.sync_current_folder_was_removed), mDirectories.getItem(0)), + Toast.LENGTH_LONG) + .show(); + browseToRoot(); + + } else { + if (currentFile == null && !getFile().isFolder()) { + // currently selected file was removed in the server, and now we know it + cleanSecondFragment(); + currentFile = currentDir; + } + + if (synchFolderRemotePath != null && currentDir.getRemotePath().equals(synchFolderRemotePath)) { + OCFileListFragment fileListFragment = getListOfFilesFragment(); + if (fileListFragment != null) { + fileListFragment.listDirectory(currentDir); + } } + setFile(currentFile); + } + + mSyncInProgress = (!FileSyncAdapter.EVENT_FULL_SYNC_END.equals(event) && !SynchronizeFolderOperation.EVENT_SINGLE_FOLDER_SHARES_SYNCED.equals(event)); + + /* + if (synchResult != null && + synchResult.isSuccess() && + (SynchronizeFolderOperation.EVENT_SINGLE_FOLDER_SYNCED.equals(event) || + FileSyncAdapter.EVENT_FULL_SYNC_FOLDER_CONTENTS_SYNCED.equals(event) + ) && + !mRefreshSharesInProgress && + getFileOperationsHelper().isSharedSupported(FileDisplayActivity.this) + ) { + startGetShares(); } - setFile(currentFile); + */ + } - - setSupportProgressBarIndeterminateVisibility(inProgress); removeStickyBroadcast(intent); - mSyncInProgress = inProgress; - + Log_OC.d(TAG, "Setting progress visibility to " + mSyncInProgress); + setSupportProgressBarIndeterminateVisibility(mSyncInProgress /*|| mRefreshSharesInProgress*/); } if (synchResult != null) { @@ -1013,16 +1028,45 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa return (accountName != null && getAccount() != null && accountName.equals(getAccount().name)); } } - - + + /** - * {@inheritDoc} + * Class waiting for broadcast events from the {@link OperationsService}. + * + * Updates the list of files when a get for shares is finished; at this moment the refresh of shares is the only + * operation performed in {@link OperationsService}. + * + * In the future will handle the progress or finalization of all the operations performed in {@link OperationsService}, + * probably all the operations associated to the app model. */ - @Override - public FileDataStorageManager getStorageManager() { - return mStorageManager; - } + private class OperationsServiceReceiver extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + if (OperationsService.ACTION_OPERATION_ADDED.equals(intent.getAction())) { + + } else if (OperationsService.ACTION_OPERATION_FINISHED.equals(intent.getAction())) { + //mRefreshSharesInProgress = false; + + Account account = intent.getParcelableExtra(OperationsService.EXTRA_ACCOUNT); + RemoteOperationResult getSharesResult = (RemoteOperationResult)intent.getSerializableExtra(OperationsService.EXTRA_RESULT); + if (getAccount() != null && account.name.equals(getAccount().name) + && getStorageManager() != null + ) { + refeshListOfFilesFragment(); + } + if ((getSharesResult != null) && + RemoteOperationResult.ResultCode.SSL_RECOVERABLE_PEER_UNVERIFIED.equals(getSharesResult.getCode())) { + mLastSslUntrustedServerResult = getSharesResult; + showDialog(DIALOG_SSL_VALIDATOR); + } + + //setSupportProgressBarIndeterminateVisibility(mRefreshSharesInProgress || mSyncInProgress); + } + + } + + } public void browseToRoot() { OCFileListFragment listOfFiles = getListOfFilesFragment(); @@ -1030,7 +1074,7 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa while (mDirectories.getCount() > 1) { popDirname(); } - OCFile root = mStorageManager.getFileByPath(OCFile.ROOT_PATH); + OCFile root = getStorageManager().getFileByPath(OCFile.ROOT_PATH); listOfFiles.listDirectory(root); setFile(listOfFiles.getCurrentFile()); startSyncFolderOperation(root); @@ -1143,9 +1187,13 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa if (chosenFile == null || mDualPane) { // only list of files - set for browsing through folders OCFile currentDir = getCurrentDir(); - actionBar.setDisplayHomeAsUpEnabled(currentDir != null && currentDir.getParentId() != 0); - actionBar.setDisplayShowTitleEnabled(false); - actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST); + boolean noRoot = (currentDir != null && currentDir.getParentId() != 0); + actionBar.setDisplayHomeAsUpEnabled(noRoot); + actionBar.setDisplayShowTitleEnabled(!noRoot); + if (!noRoot) { + actionBar.setTitle(getString(R.string.default_display_name_for_root_folder)); + } + actionBar.setNavigationMode(!noRoot ? ActionBar.NAVIGATION_MODE_STANDARD : ActionBar.NAVIGATION_MODE_LIST); actionBar.setListNavigationCallbacks(mDirectories, this); // assuming mDirectories is updated } else { @@ -1266,6 +1314,8 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa */ @Override public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationResult result) { + super.onRemoteOperationFinish(operation, result); + if (operation instanceof RemoveFileOperation) { onRemoveFileOperationFinish((RemoveFileOperation)operation, result); @@ -1277,11 +1327,21 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa } else if (operation instanceof CreateFolderOperation) { onCreateFolderOperationFinish((CreateFolderOperation)operation, result); - - } + + } else if (operation instanceof CreateShareOperation) { + onCreateShareOperationFinish((CreateShareOperation) operation, result); + } + } + private void onCreateShareOperationFinish(CreateShareOperation operation, RemoteOperationResult result) { + if (result.isSuccess()) { + refeshListOfFilesFragment(); + } + } + + /** * Updates the view associated to the activity after the finish of an operation trying to remove a * file. @@ -1300,7 +1360,7 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa if (second != null && removedFile.equals(second.getFile())) { cleanSecondFragment(); } - if (mStorageManager.getFileById(removedFile.getParentId()).equals(getCurrentDir())) { + if (getStorageManager().getFileById(removedFile.getParentId()).equals(getCurrentDir())) { refeshListOfFilesFragment(); } @@ -1359,7 +1419,7 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa ((FileDetailFragment) details).updateFileDetails(renamedFile, getAccount()); } } - if (mStorageManager.getFileById(renamedFile.getParentId()).equals(getCurrentDir())) { + if (getStorageManager().getFileById(renamedFile.getParentId()).equals(getCurrentDir())) { refeshListOfFilesFragment(); } @@ -1435,11 +1495,11 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa // Create directory path += newDirectoryName + OCFile.PATH_SEPARATOR; - RemoteOperation operation = new CreateFolderOperation(path, false, mStorageManager); + RemoteOperation operation = new CreateFolderOperation(path, false, getStorageManager()); operation.execute( getAccount(), FileDisplayActivity.this, FileDisplayActivity.this, - mHandler, + getHandler(), FileDisplayActivity.this); showLoadingDialog(); @@ -1464,9 +1524,9 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa if (file != null) { if (file.isFolder()) { return file; - } else if (mStorageManager != null) { + } else if (getStorageManager() != null) { String parentPath = file.getRemotePath().substring(0, file.getRemotePath().lastIndexOf(file.getFileName())); - return mStorageManager.getFileByPath(parentPath); + return getStorageManager().getFileByPath(parentPath); } } return null; @@ -1481,6 +1541,7 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa RemoteOperation synchFolderOp = new SynchronizeFolderOperation( folder, currentSyncTime, false, + getFileOperationsHelper().isSharedSupported(this), getStorageManager(), getAccount(), getApplicationContext() @@ -1490,16 +1551,15 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa setSupportProgressBarIndeterminateVisibility(true); } - -// public void enableDisableViewGroup(ViewGroup viewGroup, boolean enabled) { -// int childCount = viewGroup.getChildCount(); -// for (int i = 0; i < childCount; i++) { -// View view = viewGroup.getChildAt(i); -// view.setEnabled(enabled); -// view.setClickable(!enabled); -// if (view instanceof ViewGroup) { -// enableDisableViewGroup((ViewGroup) view, enabled); -// } -// } -// } + /* + private void startGetShares() { + // Get shared files/folders + Intent intent = new Intent(this, OperationsService.class); + intent.putExtra(OperationsService.EXTRA_ACCOUNT, getAccount()); + startService(intent); + + mRefreshSharesInProgress = true; + } + */ + } diff --git a/src/com/owncloud/android/ui/activity/HookActivity.java b/src/com/owncloud/android/ui/activity/HookActivity.java new file mode 100644 index 00000000..54d65b1b --- /dev/null +++ b/src/com/owncloud/android/ui/activity/HookActivity.java @@ -0,0 +1,24 @@ +/* ownCloud Android client application + * Copyright (C) 2012-2014 ownCloud Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package com.owncloud.android.ui.activity; + +public abstract class HookActivity extends FileActivity { + + private static final String TAG = HookActivity.class.getName(); + +} diff --git a/src/com/owncloud/android/ui/activity/Preferences.java b/src/com/owncloud/android/ui/activity/Preferences.java index 05a631d0..3ebb432c 100644 --- a/src/com/owncloud/android/ui/activity/Preferences.java +++ b/src/com/owncloud/android/ui/activity/Preferences.java @@ -17,6 +17,7 @@ */ package com.owncloud.android.ui.activity; +import android.accounts.Account; import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageInfo; @@ -35,6 +36,7 @@ import com.actionbarsherlock.app.SherlockPreferenceActivity; import com.actionbarsherlock.view.Menu; import com.actionbarsherlock.view.MenuItem; import com.owncloud.android.R; +import com.owncloud.android.authentication.AccountUtils; import com.owncloud.android.db.DbHandler; import com.owncloud.android.utils.DisplayUtils; import com.owncloud.android.utils.Log_OC; @@ -131,18 +133,19 @@ public class Preferences extends SherlockPreferenceActivity { Intent intent = new Intent(Intent.ACTION_SENDTO); intent.setType("text/plain"); - //Account currentAccount = AccountUtils.getCurrentOwnCloudAccount(Preferences.this); + intent.setData(Uri.parse(getString(R.string.mail_recommend))); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + String appName = getString(R.string.app_name); - //String username = currentAccount.name.substring(0, currentAccount.name.lastIndexOf('@')); - //String recommendSubject = String.format(getString(R.string.recommend_subject), username, appName); + String downloadUrl = getString(R.string.url_app_download); + Account currentAccount = AccountUtils.getCurrentOwnCloudAccount(Preferences.this); + String username = currentAccount.name.substring(0, currentAccount.name.lastIndexOf('@')); + String recommendSubject = String.format(getString(R.string.recommend_subject), appName); + String recommendText = String.format(getString(R.string.recommend_text), appName, downloadUrl, username); + intent.putExtra(Intent.EXTRA_SUBJECT, recommendSubject); - //String recommendText = String.format(getString(R.string.recommend_text), getString(R.string.app_name), username); - String recommendText = String.format(getString(R.string.recommend_text), getString(R.string.app_name), getString(R.string.url_app_download)); intent.putExtra(Intent.EXTRA_TEXT, recommendText); - - intent.setData(Uri.parse(getString(R.string.mail_recommend))); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(intent); diff --git a/src/com/owncloud/android/ui/activity/UploadFilesActivity.java b/src/com/owncloud/android/ui/activity/UploadFilesActivity.java index 7eff9b45..8b4a41d2 100644 --- a/src/com/owncloud/android/ui/activity/UploadFilesActivity.java +++ b/src/com/owncloud/android/ui/activity/UploadFilesActivity.java @@ -380,6 +380,7 @@ public class UploadFilesActivity extends FileActivity implements @Override protected void onAccountSet(boolean stateWasRecovered) { + super.onAccountSet(stateWasRecovered); if (getAccount() != null) { if (!mAccountOnCreation.equals(getAccount())) { setResult(RESULT_CANCELED); @@ -387,7 +388,6 @@ public class UploadFilesActivity extends FileActivity implements } } else { - Log_OC.wtf(TAG, "onAccountChanged was called with NULL account associated!"); setResult(RESULT_CANCELED); finish(); } diff --git a/src/com/owncloud/android/ui/adapter/FileListListAdapter.java b/src/com/owncloud/android/ui/adapter/FileListListAdapter.java index 841a5d04..f31ca142 100644 --- a/src/com/owncloud/android/ui/adapter/FileListListAdapter.java +++ b/src/com/owncloud/android/ui/adapter/FileListListAdapter.java @@ -1,6 +1,6 @@ /* ownCloud Android client application * Copyright (C) 2011 Bartek Przybylski - * Copyright (C) 2012-2013 ownCloud Inc. + * Copyright (C) 2012-2014 ownCloud Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, @@ -165,8 +165,15 @@ public class FileListListAdapter extends BaseAdapter implements ListAdapter { fileSizeV.setText(DisplayUtils.bytesToHumanReadable(file.getFileLength())); lastModV.setVisibility(View.VISIBLE); lastModV.setText(DisplayUtils.unixTimeToHumanReadable(file.getModificationTimestamp())); - checkBoxV.setVisibility(View.GONE); - view.findViewById(R.id.imageView3).setVisibility(View.GONE); + checkBoxV.setVisibility(View.GONE); + view.findViewById(R.id.imageView3).setVisibility(View.GONE); + } + + ImageView shareIconV = (ImageView) view.findViewById(R.id.shareIcon); + if (file.isShareByLink()) { + shareIconV.setVisibility(View.VISIBLE); + } else { + shareIconV.setVisibility(View.INVISIBLE); } } diff --git a/src/com/owncloud/android/ui/adapter/LocalFileListAdapter.java b/src/com/owncloud/android/ui/adapter/LocalFileListAdapter.java index 7cd2c2a4..5686874e 100644 --- a/src/com/owncloud/android/ui/adapter/LocalFileListAdapter.java +++ b/src/com/owncloud/android/ui/adapter/LocalFileListAdapter.java @@ -1,6 +1,6 @@ /* ownCloud Android client application * Copyright (C) 2011 Bartek Przybylski - * Copyright (C) 2012-2013 ownCloud Inc. + * Copyright (C) 2012-2014 ownCloud Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, @@ -135,6 +135,8 @@ public class LocalFileListAdapter extends BaseAdapter implements ListAdapter { view.findViewById(R.id.imageView2).setVisibility(View.INVISIBLE); // not GONE; the alignment changes; ugly way to keep it view.findViewById(R.id.imageView3).setVisibility(View.GONE); + + view.findViewById(R.id.shareIcon).setVisibility(View.GONE); } return view; diff --git a/src/com/owncloud/android/ui/dialog/ActivityChooserDialog.java b/src/com/owncloud/android/ui/dialog/ActivityChooserDialog.java new file mode 100644 index 00000000..dc15f69a --- /dev/null +++ b/src/com/owncloud/android/ui/dialog/ActivityChooserDialog.java @@ -0,0 +1,151 @@ +/* ownCloud Android client application + * Copyright (C) 2012-2014 ownCloud Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package com.owncloud.android.ui.dialog; + +import java.util.Arrays; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + +import android.app.AlertDialog; +import android.app.Dialog; +import android.content.ComponentName; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.pm.ActivityInfo; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.ImageView; +import android.widget.TextView; + +import com.actionbarsherlock.app.SherlockDialogFragment; +import com.owncloud.android.R; +import com.owncloud.android.datamodel.OCFile; +import com.owncloud.android.files.FileOperationsHelper; +import com.owncloud.android.ui.activity.FileActivity; +import com.owncloud.android.utils.Log_OC; + +/** + * Dialog showing a list activities able to resolve a given Intent, + * filtering out the activities matching give package names. + * + * @author David A. Velasco + */ +public class ActivityChooserDialog extends SherlockDialogFragment { + + private final static String TAG = ActivityChooserDialog.class.getSimpleName(); + private final static String ARG_INTENT = ActivityChooserDialog.class.getSimpleName() + ".ARG_INTENT"; + private final static String ARG_PACKAGES_TO_EXCLUDE = ActivityChooserDialog.class.getSimpleName() + ".ARG_PACKAGES_TO_EXCLUDE"; + private final static String ARG_FILE_TO_SHARE = ActivityChooserDialog.class.getSimpleName() + ".FILE_TO_SHARE"; + + private ActivityAdapter mAdapter; + private OCFile mFile; + private Intent mIntent; + + public static ActivityChooserDialog newInstance(Intent intent, String[] packagesToExclude, OCFile fileToShare) { + ActivityChooserDialog f = new ActivityChooserDialog(); + Bundle args = new Bundle(); + args.putParcelable(ARG_INTENT, intent); + args.putStringArray(ARG_PACKAGES_TO_EXCLUDE, packagesToExclude); + args.putParcelable(ARG_FILE_TO_SHARE, fileToShare); + f.setArguments(args); + return f; + } + + public ActivityChooserDialog() { + super(); + Log_OC.d(TAG, "constructor"); + } + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + mIntent = getArguments().getParcelable(ARG_INTENT); + String[] packagesToExclude = getArguments().getStringArray(ARG_PACKAGES_TO_EXCLUDE); + List packagesToExcludeList = Arrays.asList(packagesToExclude != null ? packagesToExclude : new String[0]); + mFile = getArguments().getParcelable(ARG_FILE_TO_SHARE); + + PackageManager pm= getSherlockActivity().getPackageManager(); + List activities = pm.queryIntentActivities(mIntent, PackageManager.MATCH_DEFAULT_ONLY); + Iterator it = activities.iterator(); + ResolveInfo resolveInfo; + while (it.hasNext()) { + resolveInfo = it.next(); + if (packagesToExcludeList.contains(resolveInfo.activityInfo.packageName.toLowerCase())) { + it.remove(); + } + } + Collections.sort(activities, new ResolveInfo.DisplayNameComparator(pm)); + mAdapter = new ActivityAdapter(getSherlockActivity(), pm, activities); + + return new AlertDialog.Builder(getSherlockActivity()) + .setTitle(R.string.activity_chooser_title) + .setAdapter(mAdapter, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + // Add the information of the chosen activity to the intent to send + ResolveInfo chosen = mAdapter.getItem(which); + ActivityInfo actInfo = chosen.activityInfo; + ComponentName name=new ComponentName(actInfo.applicationInfo.packageName, actInfo.name); + mIntent.setComponent(name); + + // Create a new share resource + FileOperationsHelper foh = new FileOperationsHelper(); + foh.shareFileWithLinkToApp(mFile, mIntent, (FileActivity)getSherlockActivity()); + } + }) + .create(); + } + + + class ActivityAdapter extends ArrayAdapter { + + private PackageManager mPackageManager; + + ActivityAdapter(Context context, PackageManager pm, List apps) { + super(context, R.layout.activity_row, apps); + this.mPackageManager = pm; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + if (convertView == null) { + convertView = newView(parent); + } + bindView(position, convertView); + return convertView; + } + + private View newView(ViewGroup parent) { + return(((LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(R.layout.activity_row, parent, false)); + } + + private void bindView(int position, View row) { + TextView label = (TextView) row.findViewById(R.id.title); + label.setText(getItem(position).loadLabel(mPackageManager)); + ImageView icon = (ImageView) row.findViewById(R.id.icon); + icon.setImageDrawable(getItem(position).loadIcon(mPackageManager)); + } + } + +} diff --git a/src/com/owncloud/android/ui/fragment/FileDetailFragment.java b/src/com/owncloud/android/ui/fragment/FileDetailFragment.java index 49895260..216cceec 100644 --- a/src/com/owncloud/android/ui/fragment/FileDetailFragment.java +++ b/src/com/owncloud/android/ui/fragment/FileDetailFragment.java @@ -335,8 +335,14 @@ public class FileDetailFragment extends FileFragment implements @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { + case R.id.action_share_file: { + FileDisplayActivity activity = (FileDisplayActivity) getSherlockActivity(); + activity.getFileOperationsHelper().shareFileWithLink(getFile(), activity); + return true; + } case R.id.action_open_file_with: { - mContainerActivity.openFile(getFile()); + FileDisplayActivity activity = (FileDisplayActivity) getSherlockActivity(); + activity.getFileOperationsHelper().openFile(getFile(), activity); return true; } case R.id.action_remove_file: { @@ -358,7 +364,7 @@ public class FileDetailFragment extends FileFragment implements return false; } } - + @Override public void onClick(View v) { switch (v.getId()) { @@ -399,7 +405,6 @@ public class FileDetailFragment extends FileFragment implements } } - private void removeFile() { OCFile file = getFile(); ConfirmationDialogFragment confDialog = ConfirmationDialogFragment.newInstance( diff --git a/src/com/owncloud/android/ui/fragment/FileFragment.java b/src/com/owncloud/android/ui/fragment/FileFragment.java index b6c65749..2f1a49b1 100644 --- a/src/com/owncloud/android/ui/fragment/FileFragment.java +++ b/src/com/owncloud/android/ui/fragment/FileFragment.java @@ -21,7 +21,6 @@ import android.support.v4.app.Fragment; import com.actionbarsherlock.app.SherlockFragment; import com.owncloud.android.datamodel.OCFile; -import com.owncloud.android.files.FileHandler; import com.owncloud.android.ui.activity.TransferServiceGetter; @@ -73,7 +72,7 @@ public class FileFragment extends SherlockFragment { * * @author David A. Velasco */ - public interface ContainerActivity extends TransferServiceGetter, FileHandler { + public interface ContainerActivity extends TransferServiceGetter { /** * Callback method invoked when the detail fragment wants to notice its container @@ -95,8 +94,7 @@ public class FileFragment extends SherlockFragment { * @param file File to show details */ public void showDetails(OCFile file); - - + } } diff --git a/src/com/owncloud/android/ui/fragment/OCFileListFragment.java b/src/com/owncloud/android/ui/fragment/OCFileListFragment.java index 91abe7d1..96aa2dc2 100644 --- a/src/com/owncloud/android/ui/fragment/OCFileListFragment.java +++ b/src/com/owncloud/android/ui/fragment/OCFileListFragment.java @@ -25,7 +25,6 @@ import com.owncloud.android.R; import com.owncloud.android.authentication.AccountUtils; import com.owncloud.android.datamodel.FileDataStorageManager; import com.owncloud.android.datamodel.OCFile; -import com.owncloud.android.files.FileHandler; import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder; import com.owncloud.android.files.services.FileUploader.FileUploaderBinder; import com.owncloud.android.lib.operations.common.OnRemoteOperationListener; @@ -183,8 +182,8 @@ public class OCFileListFragment extends ExtendedListFragment implements EditName // media preview mContainerActivity.startMediaPreview(file, 0, true); } else { - // open with - mContainerActivity.openFile(file); + FileDisplayActivity activity = (FileDisplayActivity) getSherlockActivity(); + activity.getFileOperationsHelper().openFile(file, activity); } } else { @@ -284,6 +283,11 @@ public class OCFileListFragment extends ExtendedListFragment implements EditName AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo(); mTargetFile = (OCFile) mAdapter.getItem(info.position); switch (item.getItemId()) { + case R.id.action_share_file: { + FileDisplayActivity activity = (FileDisplayActivity) getSherlockActivity(); + activity.getFileOperationsHelper().shareFileWithLink(mTargetFile, activity); + return true; + } case R.id.action_rename_file: { String fileName = mTargetFile.getFileName(); int extensionStart = mTargetFile.isFolder() ? -1 : fileName.lastIndexOf("."); @@ -410,7 +414,7 @@ public class OCFileListFragment extends ExtendedListFragment implements EditName * * @author David A. Velasco */ - public interface ContainerActivity extends TransferServiceGetter, OnRemoteOperationListener, FileHandler { + public interface ContainerActivity extends TransferServiceGetter, OnRemoteOperationListener { /** * Callback method invoked when a the user browsed into a different folder through the list of files diff --git a/src/com/owncloud/android/ui/preview/PreviewImageActivity.java b/src/com/owncloud/android/ui/preview/PreviewImageActivity.java index edafa65d..374a53b7 100644 --- a/src/com/owncloud/android/ui/preview/PreviewImageActivity.java +++ b/src/com/owncloud/android/ui/preview/PreviewImageActivity.java @@ -70,8 +70,6 @@ public class PreviewImageActivity extends FileActivity implements FileFragment.C private static final String DIALOG_WAIT_TAG = "DIALOG_WAIT"; - private FileDataStorageManager mStorageManager; - private ViewPager mViewPager; private PreviewImagePagerAdapter mPreviewImagePagerAdapter; @@ -115,13 +113,12 @@ public class PreviewImageActivity extends FileActivity implements FileFragment.C private void initViewPager() { // get parent from path String parentPath = getFile().getRemotePath().substring(0, getFile().getRemotePath().lastIndexOf(getFile().getFileName())); - OCFile parentFolder = mStorageManager.getFileByPath(parentPath); - //OCFile parentFolder = mStorageManager.getFileById(getFile().getParentId()); + OCFile parentFolder = getStorageManager().getFileByPath(parentPath); if (parentFolder == null) { // should not be necessary - parentFolder = mStorageManager.getFileByPath(OCFile.ROOT_PATH); + parentFolder = getStorageManager().getFileByPath(OCFile.ROOT_PATH); } - mPreviewImagePagerAdapter = new PreviewImagePagerAdapter(getSupportFragmentManager(), parentFolder, getAccount(), mStorageManager); + mPreviewImagePagerAdapter = new PreviewImagePagerAdapter(getSupportFragmentManager(), parentFolder, getAccount(), getStorageManager()); mViewPager = (ViewPager) findViewById(R.id.fragmentPager); int position = mPreviewImagePagerAdapter.getFilePosition(getFile()); position = (position >= 0) ? position : 0; @@ -385,7 +382,7 @@ public class PreviewImageActivity extends FileActivity implements FileFragment.C if (getAccount().name.equals(accountName) && downloadedRemotePath != null) { - OCFile file = mStorageManager.getFileByPath(downloadedRemotePath); + OCFile file = getStorageManager().getFileByPath(downloadedRemotePath); int position = mPreviewImagePagerAdapter.getFilePosition(file); boolean downloadWasFine = intent.getBooleanExtra(FileDownloader.EXTRA_DOWNLOAD_RESULT, false); //boolean isOffscreen = Math.abs((mViewPager.getCurrentItem() - position)) <= mViewPager.getOffscreenPageLimit(); @@ -433,6 +430,7 @@ public class PreviewImageActivity extends FileActivity implements FileFragment.C @Override protected void onAccountSet(boolean stateWasRecovered) { + super.onAccountSet(stateWasRecovered); if (getAccount() != null) { OCFile file = getFile(); /// Validate handled file (first image to preview) @@ -442,15 +440,14 @@ public class PreviewImageActivity extends FileActivity implements FileFragment.C if (!file.isImage()) { throw new IllegalArgumentException("Non-image file passed as argument"); } - mStorageManager = new FileDataStorageManager(getAccount(), getContentResolver()); // Update file according to DB file, if it is possible if (file.getFileId() > FileDataStorageManager.ROOT_PARENT_ID) - file = mStorageManager.getFileById(file.getFileId()); + file = getStorageManager().getFileById(file.getFileId()); if (file != null) { /// Refresh the activity according to the Account and OCFile set - setFile(file); // reset after getting it fresh from mStorageManager + setFile(file); // reset after getting it fresh from storageManager getSupportActionBar().setTitle(getFile().getFileName()); //if (!stateWasRecovered) { initViewPager(); @@ -460,9 +457,6 @@ public class PreviewImageActivity extends FileActivity implements FileFragment.C // handled file not in the current Account finish(); } - - } else { - Log_OC.wtf(TAG, "onAccountChanged was called with NULL account associated!"); } } @@ -480,5 +474,5 @@ public class PreviewImageActivity extends FileActivity implements FileFragment.C startActivity(i); } } - + } diff --git a/src/com/owncloud/android/ui/preview/PreviewImageFragment.java b/src/com/owncloud/android/ui/preview/PreviewImageFragment.java index 8555fa77..a2d05370 100644 --- a/src/com/owncloud/android/ui/preview/PreviewImageFragment.java +++ b/src/com/owncloud/android/ui/preview/PreviewImageFragment.java @@ -57,6 +57,7 @@ import com.owncloud.android.lib.operations.common.OnRemoteOperationListener; import com.owncloud.android.lib.operations.common.RemoteOperation; import com.owncloud.android.lib.operations.common.RemoteOperationResult; import com.owncloud.android.operations.RemoveFileOperation; +import com.owncloud.android.ui.activity.FileActivity; import com.owncloud.android.ui.fragment.ConfirmationDialogFragment; import com.owncloud.android.ui.fragment.FileFragment; import com.owncloud.android.utils.Log_OC; @@ -247,6 +248,11 @@ public class PreviewImageFragment extends FileFragment implements OnRemoteOper @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { + case R.id.action_share_file: { + FileActivity act = (FileActivity)getSherlockActivity(); + act.getFileOperationsHelper().shareFileWithLink(getFile(), act); + return true; + } case R.id.action_open_file_with: { openFile(); return true; diff --git a/src/com/owncloud/android/ui/preview/PreviewMediaFragment.java b/src/com/owncloud/android/ui/preview/PreviewMediaFragment.java index 464ea6db..ee4a7b00 100644 --- a/src/com/owncloud/android/ui/preview/PreviewMediaFragment.java +++ b/src/com/owncloud/android/ui/preview/PreviewMediaFragment.java @@ -307,6 +307,10 @@ public class PreviewMediaFragment extends FileFragment implements @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { + case R.id.action_share_file: { + shareFileWithLink(); + return true; + } case R.id.action_open_file_with: { openFile(); return true; @@ -326,6 +330,14 @@ public class PreviewMediaFragment extends FileFragment implements } + private void shareFileWithLink() { + stopPreview(false); + FileActivity activity = (FileActivity)((FileFragment.ContainerActivity)getActivity()); + activity.getFileOperationsHelper().shareFileWithLink(getFile(), activity); + + } + + private void seeDetails() { stopPreview(false); ((FileFragment.ContainerActivity)getActivity()).showDetails(getFile()); diff --git a/src/com/owncloud/android/ui/preview/PreviewVideoActivity.java b/src/com/owncloud/android/ui/preview/PreviewVideoActivity.java index 9e6a2803..5e5999b4 100644 --- a/src/com/owncloud/android/ui/preview/PreviewVideoActivity.java +++ b/src/com/owncloud/android/ui/preview/PreviewVideoActivity.java @@ -18,7 +18,6 @@ package com.owncloud.android.ui.preview; import com.owncloud.android.R; -import com.owncloud.android.datamodel.FileDataStorageManager; import com.owncloud.android.datamodel.OCFile; import com.owncloud.android.media.MediaService; import com.owncloud.android.ui.activity.FileActivity; @@ -60,8 +59,6 @@ public class PreviewVideoActivity extends FileActivity implements OnCompletionLi private static final String TAG = PreviewVideoActivity.class.getSimpleName(); - private FileDataStorageManager mStorageManager; - private int mSavedPlaybackPosition; // in the unit time handled by MediaPlayer.getCurrentPosition() private boolean mAutoplay; // when 'true', the playback starts immediately with the activity private VideoView mVideoPlayer; // view to play the file; both performs and show the playback @@ -194,6 +191,7 @@ public class PreviewVideoActivity extends FileActivity implements OnCompletionLi @Override protected void onAccountSet(boolean stateWasRecovered) { + super.onAccountSet(stateWasRecovered); if (getAccount() != null) { OCFile file = getFile(); /// Validate handled file (first image to preview) @@ -203,8 +201,7 @@ public class PreviewVideoActivity extends FileActivity implements OnCompletionLi if (!file.isVideo()) { throw new IllegalArgumentException("Non-video file passed as argument"); } - mStorageManager = new FileDataStorageManager(getAccount(), getContentResolver()); - file = mStorageManager.getFileById(file.getFileId()); + file = getStorageManager().getFileById(file.getFileId()); if (file != null) { if (file.isDown()) { mVideoPlayer.setVideoPath(file.getStoragePath()); @@ -230,7 +227,6 @@ public class PreviewVideoActivity extends FileActivity implements OnCompletionLi finish(); } } else { - Log_OC.wtf(TAG, "onAccountChanged was called with NULL account associated!"); finish(); } }