Browse Source

Merge branch 'share_link__new_share' into share_link__unshare_file

masensio 11 years ago
parent
commit
e437d8320d
28 changed files with 942 additions and 288 deletions
  1. 5 3
      AndroidManifest.xml
  2. 21 9
      SETUP.md
  3. 59 0
      res/layout-v11/activity_row.xml
  4. 55 0
      res/layout/activity_row.xml
  5. 16 0
      res/values-es-rCL/strings.xml
  6. 32 32
      res/values-ja-rJP/strings.xml
  7. 2 0
      res/values-ml/strings.xml
  8. 2 0
      res/values-mn/strings.xml
  9. 1 0
      res/values-nb-rNO/strings.xml
  10. 2 0
      res/values/strings.xml
  11. 26 0
      src/com/owncloud/android/datamodel/FileDataStorageManager.java
  12. 0 30
      src/com/owncloud/android/files/FileHandler.java
  13. 165 0
      src/com/owncloud/android/files/FileOperationsHelper.java
  14. 129 0
      src/com/owncloud/android/operations/CreateShareOperation.java
  15. 79 0
      src/com/owncloud/android/operations/GetSharesForFileOperation.java
  16. 1 30
      src/com/owncloud/android/operations/GetSharesOperation.java
  17. 2 4
      src/com/owncloud/android/ui/activity/ConflictsResolveActivity.java
  18. 101 48
      src/com/owncloud/android/ui/activity/FileActivity.java
  19. 43 96
      src/com/owncloud/android/ui/activity/FileDisplayActivity.java
  20. 1 1
      src/com/owncloud/android/ui/activity/UploadFilesActivity.java
  21. 151 0
      src/com/owncloud/android/ui/dialog/ActivityChooserDialog.java
  22. 8 3
      src/com/owncloud/android/ui/fragment/FileDetailFragment.java
  23. 2 4
      src/com/owncloud/android/ui/fragment/FileFragment.java
  24. 11 8
      src/com/owncloud/android/ui/fragment/OCFileListFragment.java
  25. 8 14
      src/com/owncloud/android/ui/preview/PreviewImageActivity.java
  26. 6 0
      src/com/owncloud/android/ui/preview/PreviewImageFragment.java
  27. 12 0
      src/com/owncloud/android/ui/preview/PreviewMediaFragment.java
  28. 2 6
      src/com/owncloud/android/ui/preview/PreviewVideoActivity.java

+ 5 - 3
AndroidManifest.xml

@@ -54,7 +54,6 @@
             >
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
-
                 <category android:name="android.intent.category.LAUNCHER" />
             </intent-filter>
         </activity>
@@ -81,9 +80,12 @@
                 <category android:name="android.intent.category.DEFAULT" >
                 </category>
 
-                <data android:mimeType="*/*" >
+                <data android:mimeType="*/*" android:scheme="content">
                 </data>
-            </intent-filter>
+
+                <data android:mimeType="*/*" android:scheme="file">
+                </data>
+                </intent-filter>
         </activity>
         <activity
             android:name=".ui.activity.Preferences"

+ 21 - 9
SETUP.md

@@ -27,15 +27,17 @@ NOTE: You must have the Android SDK 'tools/', and 'platforms-tools/' folders in
 
 NOTE: You must have mvn (version >= 3.1.1) in your environment path. Current Android 'platforms-tools' need to be installed.
 
-* Download/install Android plugin for Maven, then build ownCloud with mvn:
-* "cd .."
-* "git clone https://github.com/mosabua/maven-android-sdk-deployer.git"
-* "cd maven-android-sdk-deployer"
-* "mvn -pl com.simpligility.android.sdk-deployer:android-19 -am install"
-* "cd ../android/oc_framework"
-* "mvn install"
-* "cd .."
-* Now you can create ownCloud APK using "mvn package"
+Download/install Android plugin for Maven, install oc_framework, then build ownCloud with mvn:
+
+* cd ..
+* git clone https://github.com/mosabua/maven-android-sdk-deployer.git
+* cd maven-android-sdk-deployer
+* mvn -pl com.simpligility.android.sdk-deployer:android-19 -am install
+* cd ../android/oc_framework
+* mvn install
+* cd ..
+
+Now you can create ownCloud APK using "mvn package"
 
 ### 4. Building with Eclipse:
 
@@ -70,6 +72,16 @@ NOTE: You must sign the [Contributor Agreement][1] before your changes can be ac
 * Again, click "Edit" and set "compare:develop"
 * Enter description and send pull request.
 
+### 6. Create another pull request:
+
+To make sure your new pull request does not contain commits which are already contained in previous PRs, create a new branch which is a clone of upstream/develop.
+
+* git fetch upstream
+* git checkout -b my_new_develop_branch upstream/develop
+* If you want to rename that branch later: "git checkout -b my_new_develop_branch_with_new_name"
+* Push branch to server: "git push -u origin name_of_local_develop_branch"
+* Use Github to issue PR
+
 
 [0]: https://github.com/owncloud/android/blob/master/CONTRIBUTING.md
 [1]: http://owncloud.org/about/contributor-agreement/

+ 59 - 0
res/layout-v11/activity_row.xml

@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ownCloud Android client application
+
+  Copyright (C) 2012-2014 ownCloud Inc.
+
+  This program is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License version 2,
+  as published by the Free Software Foundation.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+-->
+
+<LinearLayout 	xmlns:android="http://schemas.android.com/apk/res/android"
+    			android:id="@+id/list_item"
+				android:layout_width="match_parent"
+				android:layout_height="48dp"
+				android:paddingStart="16dip"
+				android:paddingEnd="16dip"
+				android:paddingRight="16dip"
+				android:paddingLeft="16dip"
+				android:minWidth="196dip"
+				android:background="?android:attr/activatedBackgroundIndicator"
+    			android:orientation="vertical" >
+
+	<LinearLayout
+		android:layout_width="wrap_content"
+		android:layout_height="match_parent"
+		android:duplicateParentState="true" >
+
+		<ImageView
+			android:id="@+id/icon"
+			android:layout_width="40dip"
+			android:layout_height="40dip"
+			android:layout_gravity="center_vertical"
+			android:layout_marginEnd="8dip"
+			android:layout_marginRight="8dip"
+			android:duplicateParentState="true" />
+
+        <TextView
+            android:id="@+id/title"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_vertical"
+            android:textAppearance="?android:attr/textAppearanceLargePopupMenu"
+            android:duplicateParentState="true"
+            android:singleLine="true"
+            android:ellipsize="marquee"
+            android:fadingEdge="horizontal" />
+
+    </LinearLayout>
+
+</LinearLayout>

+ 55 - 0
res/layout/activity_row.xml

@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ownCloud Android client application
+
+  Copyright (C) 2012-2014 ownCloud Inc.
+
+  This program is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License version 2,
+  as published by the Free Software Foundation.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+-->
+
+<LinearLayout 	xmlns:android="http://schemas.android.com/apk/res/android"
+    			android:id="@+id/list_item"
+				android:layout_width="match_parent"
+				android:layout_height="48dp"
+				android:paddingRight="16dip"
+				android:paddingLeft="16dip"
+				android:minWidth="196dip"
+    			android:orientation="vertical" >
+
+	<LinearLayout
+		android:layout_width="wrap_content"
+		android:layout_height="match_parent"
+		android:duplicateParentState="true" >
+
+		<ImageView
+			android:id="@+id/icon"
+			android:layout_width="40dip"
+			android:layout_height="40dip"
+			android:layout_gravity="center_vertical"
+			android:layout_marginRight="8dip"
+			android:duplicateParentState="true" />
+
+        <TextView
+            android:id="@+id/title"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_vertical"
+            android:textAppearance="?android:attr/textAppearanceLarge"
+            android:duplicateParentState="true"
+            android:singleLine="true"
+            android:ellipsize="marquee"
+            android:fadingEdge="horizontal" />
+
+    </LinearLayout>
+
+</LinearLayout>

+ 16 - 0
res/values-es-rCL/strings.xml

@@ -13,4 +13,20 @@
   <string name="uploader_btn_upload_text">Subir</string>
   <string name="uploader_wrn_no_account_title">No se encuentra la cuenta</string>
   <string name="uploader_info_uploading">Subiendo</string>
+  <string name="filedetails_select_file">Seleccione un archivo para desplegar información adicional.</string>
+  <string name="filedetails_size">Tamaño:</string>
+  <string name="filedetails_type">Tipo:</string>
+  <string name="filedetails_created">Creado:</string>
+  <string name="filedetails_modified">Modificado:</string>
+  <string name="filedetails_download">Descargar</string>
+  <string name="common_yes">Si</string>
+  <string name="common_no">No</string>
+  <string name="common_ok">OK</string>
+  <string name="common_cancel">Cancelar</string>
+  <string name="common_error">Error</string>
+  <string name="uploader_info_dirname">Nombre del directorio</string>
+  <string name="common_choose_account">Elija una cuenta</string>
+  <string name="pincode_enter_pin_code">Por favor, ingreses su PIN de aplicación</string>
+  <string name="pincode_configure_your_pin">Ingrese su PIN de aplicación</string>
+  <string name="pincode_reenter_your_pincode">Por favor, reingrese su PIN de aplicación</string>
 </resources>

+ 32 - 32
res/values-ja-rJP/strings.xml

@@ -18,9 +18,9 @@
   <string name="prefs_pincode_summary">クライアントを保護する</string>
   <string name="prefs_instant_upload">自動アップロードを有効</string>
   <string name="prefs_instant_upload_summary">カメラで撮影した画像を自動アップロード</string>
-  <string name="prefs_log_title">記録を有効化</string>
-  <string name="prefs_log_summary">これは問題を記録するのにつかわれます。</string>
-  <string name="prefs_log_title_history">記録している履歴</string>
+  <string name="prefs_log_title">ログを有効にする</string>
+  <string name="prefs_log_summary">これは問題をログに記録するのに使用します。</string>
+  <string name="prefs_log_title_history">ログ履歴</string>
   <string name="prefs_log_summary_history">これは記録されたログを表示します</string>
   <string name="prefs_log_delete_history_button">履歴を削除</string>
   <string name="prefs_help">ヘルプ</string>
@@ -46,7 +46,7 @@
   <string name="uploader_wrn_no_content_text">コンテンツを受信しませんでした。アップロードするものはありません。</string>
   <string name="uploader_error_forbidden_content">%1$sで共有コンテンツへのアクセスが許可されていません。</string>
   <string name="uploader_info_uploading">アップロード中</string>
-  <string name="file_list_empty">このフォルダにはファイルがありません。\n\"アップロード\" メニューで新しいファイルを追加することができます。</string>
+  <string name="file_list_empty">このフォルダにはファイルがありません。\n\"アップロード\" メニューで新しいファイルを追加することができます。</string>
   <string name="filedetails_select_file">ファイルをタップすると追加情報が表示されます。</string>
   <string name="filedetails_size">サイズ:</string>
   <string name="filedetails_type">タイプ:</string>
@@ -92,16 +92,16 @@
   <string name="sync_conflicts_in_favourites_content">%1$d 同期ファイルを同期できませんでした</string>
   <string name="sync_fail_in_favourites_ticker">ファイルの同期に失敗しました</string>
   <string name="sync_fail_in_favourites_content">%1$d ファイルのコンテンツを同期できませんでした(%2$d の競合)</string>
-  <string name="sync_foreign_files_forgotten_ticker">いくつかのローカルファイルが忘れられています</string>
+  <string name="sync_foreign_files_forgotten_ticker">一部のローカルファイルが忘れられています</string>
   <string name="sync_foreign_files_forgotten_content">%2$s ディレクトリ内の %1$d ファイルはコピーすることができませんでした</string>
-  <string name="sync_foreign_files_forgotten_explanation">\"バージョン 1.3.16から、このデバイスからアップロードされたファイルは、単独のファイルが複数のアカウントと同期される時にデータの損失を防ぐため、ローカルの%1$sのフォルダにコピーされます。\n\nこの変更により、このアプリの以前のバージョンでアップロードされたすべてのファイルが%2$s フォルダにコピーされます。ただし、アカウント同期の際に、エラーがこの操作の完了を阻止しました。このままファイルを残し、%3$sへのリンクを削除するか、あるいは%1$s ディレクトリのファイルを移動し、%4$sへのリンクを維持することができます。\n\n以下にローカルのファイルと、それにリンクしていた%5$sのリモートファイルがリストされています</string>
-  <string name="sync_current_folder_was_removed">フォルダ %1$s はもう存在しません</string>
+  <string name="sync_foreign_files_forgotten_explanation">\"バージョン 1.3.16から、このデバイスからアップロードされたファイルは、単独のファイルが複数のアカウントと同期される時にデータの損失を防ぐため、ローカルの%1$sのフォルダにコピーされます。\n\nこの変更により、このアプリの以前のバージョンでアップロードされたすべてのファイルが%2$s フォルダにコピーされます。ただし、アカウント同期の際に、エラーがこの操作の完了を阻止しました。このままファイルを残し、%3$sへのリンクを削除するか、あるいは%1$s ディレクトリのファイルを移動し、%4$sへのリンクを維持することができます。\n\n以下にローカルのファイルと、それにリンクしていた%5$sのリモートファイルがリストされています</string>
+  <string name="sync_current_folder_was_removed">フォルダ %1$s はもう存在しません</string>
   <string name="foreign_files_move">全て移動</string>
   <string name="foreign_files_success">全てのファイルは移動されました</string>
-  <string name="foreign_files_fail">いくつかのファイルは移動出来ませんでした</string>
+  <string name="foreign_files_fail">一部のファイルは移動できませんでした</string>
   <string name="foreign_files_local_text">ローカル: %1$s</string>
   <string name="foreign_files_remote_text">リモート: %1$s</string>
-  <string name="upload_query_move_foreign_files">%1$s フォルダに選択されたファイルをコピーするのに十分なスペースがありません。コピーする代わりに、それらを移動させますか?</string>
+  <string name="upload_query_move_foreign_files">%1$s フォルダに選択されたファイルをコピーするのに十分な空き領域がありません。コピーする代わりに、それらを移動させますか?</string>
   <string name="pincode_enter_pin_code">アプリのパスワードを入力してください</string>
   <string name="pincode_configure_your_pin">アプリのパスワードを入力してください</string>
   <string name="pincode_configure_your_pin_explanation">アプリ開始時に毎回PINが要求されます。</string>
@@ -123,29 +123,29 @@
   <string name="media_err_malformed">メディアファイルが正確にエンコードされていません</string>
   <string name="media_err_timeout">再生中にタイムアウトが発生しました</string>
   <string name="media_err_invalid_progressive_playback">メディアファイルをストリーミングできません</string>
-  <string name="media_err_unknown">メディアファイルをStock Media Playerでプレイ出来ません</string>
-  <string name="media_err_security_ex">プレイに際してセキュリティエラー %1$s</string>
-  <string name="media_err_io_ex">プレイに際して入力エラー %1$s</string>
-  <string name="media_err_unexpected">プレイに際して予期しないエラー %1$s</string>
+  <string name="media_err_unknown">メディアファイルをStock Media Playerで再生できません</string>
+  <string name="media_err_security_ex">再生時にセキュリティエラー %1$s</string>
+  <string name="media_err_io_ex">再生時に入力エラー %1$s</string>
+  <string name="media_err_unexpected">再生時に予期しないエラー %1$s</string>
   <string name="media_rewind_description">巻き戻しボタン</string>
-  <string name="media_play_pause_description">プレイ/ポーズボタン</string>
+  <string name="media_play_pause_description">再生/一時停止ボタン</string>
   <string name="media_forward_description">早送りボタン</string>
   <string name="auth_trying_to_login">ログイン中...</string>
   <string name="auth_no_net_conn_title">ネットワークに接続されていません</string>
   <string name="auth_nossl_plain_ok_title">暗号化通信が利用できません。</string>
   <string name="auth_connection_established">接続が確立しました</string>
   <string name="auth_testing_connection">接続をテスト中...</string>
-  <string name="auth_not_configured_title">サーバーの間違った設定</string>
-  <string name="auth_account_not_new">同じユーザとサーバのアカウントがデバイス上にすでに存在します</string>
-  <string name="auth_account_not_the_same">入力されたユーザはこのアカウントのユーザと一致しません</string>
+  <string name="auth_not_configured_title">サーバー設定が間違っています</string>
+  <string name="auth_account_not_new">同じユーザとサーバのアカウントがデバイス上にすでに存在します</string>
+  <string name="auth_account_not_the_same">入力されたユーザはこのアカウントのユーザと一致しません</string>
   <string name="auth_unknown_error_title">不明なエラーに発生しました</string>
   <string name="auth_unknown_host_title">ホストが見つかりませんでした</string>
-  <string name="auth_incorrect_path_title">のインスタンスが見つかりませんでした</string>
-  <string name="auth_timeout_title">サーバーからの反応がありません</string>
+  <string name="auth_incorrect_path_title">サーバーのインスタンスが見つかりません</string>
+  <string name="auth_timeout_title">サーバーからの反応がありません</string>
   <string name="auth_incorrect_address_title">不明なURL形式</string>
   <string name="auth_ssl_general_error_title">SSLの初期化に失敗しました</string>
-  <string name="auth_ssl_unverified_server_title">SSL サーバ識別子を確認できませんでした</string>
-  <string name="auth_bad_oc_version_title">認識出来ないサーバのバージョンです</string>
+  <string name="auth_ssl_unverified_server_title">SSLサーバ識別子を確認できませんでした</string>
+  <string name="auth_bad_oc_version_title">認識できないサーバーのバージョンです</string>
   <string name="auth_wrong_connection_title">接続を確立できませんでした</string>
   <string name="auth_secure_connection">暗号化通信を確立しました</string>
   <string name="auth_unauthorized">間違ったユーザー名もしくはパスワード</string>
@@ -155,8 +155,8 @@
   <string name="auth_expired_oauth_token_toast">認証情報は有効期限切れです。再度認証を行ってください。</string>
   <string name="auth_expired_basic_auth_toast">現在のパスワードを入力してください</string>
   <string name="auth_expired_saml_sso_token_toast">セッションの有効期限切れです。再度接続してください。</string>
-  <string name="auth_connecting_auth_server">認証サーバに接続中 ...</string>
-  <string name="auth_unsupported_auth_method">サーバはこの認証方式をサポートしていません</string>
+  <string name="auth_connecting_auth_server">認証サーバに接続中 ...</string>
+  <string name="auth_unsupported_auth_method">サーバはこの認証方式をサポートしていません</string>
   <string name="auth_unsupported_multiaccount">%1$s は複数アカウントをサポートしていません</string>
   <string name="fd_keep_in_sync">ファイルを最新に保つ</string>
   <string name="common_rename">名前を変更</string>
@@ -165,7 +165,7 @@
   <string name="confirmation_remove_folder_alert">本当に %1$s およびそのコンテンツを削除してもよろしいですか?</string>
   <string name="confirmation_remove_local">ローカルのみ</string>
   <string name="confirmation_remove_folder_local">ローカルコンテンツのみ</string>
-  <string name="confirmation_remove_remote">サーバから削除</string>
+  <string name="confirmation_remove_remote">サーバから削除</string>
   <string name="confirmation_remove_remote_and_local">リモートとローカルの両方</string>
   <string name="remove_success_msg">削除に成功しました</string>
   <string name="remove_fail_msg">削除を完了できませんでした</string>
@@ -179,12 +179,12 @@
   <string name="wait_a_moment">しばらくお待ちください</string>
   <string name="filedisplay_unexpected_bad_get_content">予期せぬ問題;他のアプリでファイルを選択してみてください。</string>
   <string name="filedisplay_no_file_selected">ファイルは選択されていません</string>
-  <string name="oauth_check_onoff">oAuth2 でログイン</string>
+  <string name="oauth_check_onoff">oAuth2でログイン</string>
   <string name="oauth_login_connection">oAuth2サーバーに接続中...</string>
   <string name="ssl_validator_header">サイトの識別子を確認できませんでした</string>
-  <string name="ssl_validator_reason_cert_not_trusted">- サーバ証明書は信頼されていません</string>
-  <string name="ssl_validator_reason_cert_expired">- サーバ証明書は有効期限切れです</string>
-  <string name="ssl_validator_reason_cert_not_yet_valid">- サーバ証明書は若すぎます</string>
+  <string name="ssl_validator_reason_cert_not_trusted">- サーバ証明書は信頼されていません</string>
+  <string name="ssl_validator_reason_cert_expired">- サーバ証明書は有効期限切れです</string>
+  <string name="ssl_validator_reason_cert_not_yet_valid">- サーバー証明書の有効期限は未来のものです</string>
   <string name="ssl_validator_reason_hostname_not_verified">- URLは証明書内のホスト名と一致しません</string>
   <string name="ssl_validator_question">この証明書を信頼してもよろしいですか?</string>
   <string name="ssl_validator_not_saved">証明書は保存できませんでした</string>
@@ -211,14 +211,14 @@
   <string name="placeholder_media_time">12:23:45</string>
   <string name="instant_upload_on_wifi">WiFi経由でのみ写真をアップロード</string>
   <string name="instant_upload_path">/InstantUpload</string>
-  <string name="conflict_title">更新競合</string>
-  <string name="conflict_message">リモートファイル %s はローカルファイルと同期していません。続行すると、サーバ上のファイルを置き換えます。</string>
+  <string name="conflict_title">更新競合</string>
+  <string name="conflict_message">リモートファイル %s はローカルファイルと同期していません。続行すると、サーバ上のファイルを置き換えます。</string>
   <string name="conflict_keep_both">両方を保持</string>
   <string name="conflict_overwrite">上書き</string>
   <string name="conflict_dont_upload">アップロードしない</string>
   <string name="preview_image_description">イメージプレビュー</string>
   <string name="preview_image_error_unknown_format">この画像は表示できません</string>
-  <string name="error__upload__local_file_not_copied">%1$s は %2$s ローカルディレクトリにコピー出来ませんでした</string>
+  <string name="error__upload__local_file_not_copied">%1$s は %2$s ローカルディレクトリにコピーできませんでした</string>
   <string name="actionbar_failed_instant_upload">インスタントアップロードに失敗</string>
   <string name="failed_upload_headline_text">インスタントアップロードに失敗</string>
   <string name="failed_upload_headline_hint">全ての失敗したインスタントアップロードの要約</string>
@@ -229,5 +229,5 @@
   <string name="failed_upload_load_more_images">更に画像を読み込む</string>
   <string name="failed_upload_retry_do_nothing_text">オンラインでなく、インスタントアップロードのために何もしません</string>
   <string name="failed_upload_failure_text">失敗メッセージ:</string>
-  <string name="failed_upload_quota_exceeded_text">サーバーの設定を確認してください。許容を超過している可能性があります。</string>
+  <string name="failed_upload_quota_exceeded_text">サーバー設定を確認してください。クォータサイズを超えている可能性があります。</string>
 </resources>

+ 2 - 0
res/values-ml/strings.xml

@@ -0,0 +1,2 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<resources/>

+ 2 - 0
res/values-mn/strings.xml

@@ -0,0 +1,2 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<resources/>

+ 1 - 0
res/values-nb-rNO/strings.xml

@@ -35,6 +35,7 @@
   <string name="common_cancel">Avbryt</string>
   <string name="common_save_exit">Lagre og avslutt</string>
   <string name="common_error">Feil</string>
+  <string name="common_error_unknown">Ukjent feil</string>
   <string name="about_title">Om</string>
   <string name="change_password">Endre passord</string>
   <string name="delete_account">Slett konto</string>

+ 2 - 0
res/values/strings.xml

@@ -188,6 +188,7 @@
     <string name="wait_a_moment">Wait a moment</string>
     <string name="filedisplay_unexpected_bad_get_content">"Unexpected problem ; please select the file from a different app"</string>
     <string name="filedisplay_no_file_selected">No file was selected</string>
+    <string name="activity_chooser_title">Send link to &#8230;</string>
     
     <string name="oauth_check_onoff">Login with oAuth2</string> 
     <string name="oauth_login_connection">Connecting to oAuth2 server…</string>    
@@ -248,4 +249,5 @@
 	
 	<string name="share_link_no_support_share_api">Sorry, sharing is not enabled on your server. Please contact your administrator.</string>
 	<string name="share_link_file_no_exist">Unable to share this file or folder. Please, make sure it exists</string>
+	<string name="share_link_file_error">An error occurred while trying to share this file or folder</string>
 </resources>

+ 26 - 0
src/com/owncloud/android/datamodel/FileDataStorageManager.java

@@ -29,6 +29,7 @@ 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;
 
@@ -1114,4 +1115,29 @@ public class FileDataStorageManager {
             getContentResolver().delete(share_uri, where, whereArgs); 
         }
     }
+    
+    public void saveSharesDB(ArrayList<OCShare> shares) {
+        saveShares(shares);
+
+        ArrayList<OCFile> sharedFiles = new ArrayList<OCFile>();
+
+        for (OCShare share : shares) {
+            // Get the path
+            String path = share.getPath();
+            if (share.isDirectory()) {
+                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);
+    }
 }

+ 0 - 30
src/com/owncloud/android/files/FileHandler.java

@@ -1,30 +0,0 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012-2013 ownCloud Inc.
- *
- *   This program is free software: you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License version 2,
- *   as published by the Free Software Foundation.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-package com.owncloud.android.files;
-
-import com.owncloud.android.datamodel.OCFile;
-
-public interface FileHandler {
-
-    /**
-     * TODO
-     */
-    public void openFile(OCFile file);
-
-    
-}

+ 165 - 0
src/com/owncloud/android/files/FileOperationsHelper.java

@@ -0,0 +1,165 @@
+/* ownCloud Android client application
+ *   Copyright (C) 2012-2014 ownCloud Inc.
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License version 2,
+ *   as published by the Free Software Foundation.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.files;
+
+import org.apache.http.protocol.HTTP;
+
+import android.accounts.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.operations.UnshareLinkOperation;
+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;
+    }
+
+    
+    public void unshareFileWithLink(OCFile file, FileActivity callerActivity) {
+        
+        if (isSharedSupported(callerActivity)) {
+            // Unshare the file
+            UnshareLinkOperation unshare = new UnshareLinkOperation(file);
+            unshare.execute(callerActivity.getStorageManager(), 
+                    callerActivity, 
+                    callerActivity.getRemoteOperationListener(), 
+                    callerActivity.getHandler(), 
+                    callerActivity);
+         
+            callerActivity.showLoadingDialog();
+            
+        } else {
+            // Show a Message
+            Toast t = Toast.makeText(callerActivity, callerActivity.getString(R.string.share_link_no_support_share_api), Toast.LENGTH_LONG);
+            t.show();
+            
+        }
+    }
+}

+ 129 - 0
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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.operations;
+
+/**
+ * Creates a new share from a given file
+ * 
+ * @author masensio
+ *
+ */
+
+import android.content.Intent;
+
+import com.owncloud.android.datamodel.FileDataStorageManager;
+import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.lib.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.setIsDirectory(true);
+                    
+                } else {
+                    share.setPath(mPath);
+                    share.setIsDirectory(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;
+    }
+
+}

+ 79 - 0
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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+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<OCShare> shares = new ArrayList<OCShare>();
+            for(Object obj: result.getData()) {
+                shares.add((OCShare) obj);
+            }
+
+            getStorageManager().saveSharesDB(shares);
+        }
+
+        return result;
+    }
+
+}

+ 1 - 30
src/com/owncloud/android/operations/GetSharesOperation.java

@@ -19,13 +19,10 @@ package com.owncloud.android.operations;
 
 import java.util.ArrayList;
 
-import com.owncloud.android.datamodel.OCFile;
 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.common.ShareType;
 import com.owncloud.android.lib.operations.remote.GetRemoteSharesOperation;
-import com.owncloud.android.lib.utils.FileUtils;
 import com.owncloud.android.operations.common.SyncOperation;
 import com.owncloud.android.utils.Log_OC;
 
@@ -55,36 +52,10 @@ public class GetSharesOperation extends SyncOperation {
                 shares.add((OCShare) obj);
             }
 
-            saveSharesDB(shares);
+            getStorageManager().saveSharesDB(shares);
         }
 
         return result;
     }
 
-    private void saveSharesDB(ArrayList<OCShare> shares) {
-        // Save share file
-        getStorageManager().saveShares(shares);
-
-        ArrayList<OCFile> sharedFiles = new ArrayList<OCFile>();
-
-        for (OCShare share : shares) {
-            // Get the path
-            String path = share.getPath();
-            if (share.isDirectory()) {
-                path = path + FileUtils.PATH_SEPARATOR;
-            }           
-
-            // Update OCFile with data from share: ShareByLink  ¿and publicLink?
-            OCFile file = getStorageManager().getFileByPath(path);
-            if (file != null) {
-                if (share.getShareType().equals(ShareType.PUBLIC_LINK)) {
-                    file.setShareByLink(true);
-                    sharedFiles.add(file);
-                }
-            } 
-        }
-        
-        getStorageManager().updateSharedFiles(sharedFiles);
-    }
-
 }

+ 2 - 4
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();
         }
         

+ 101 - 48
src/com/owncloud/android/ui/activity/FileActivity.java

@@ -24,19 +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.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.lib.accounts.OwnCloudAccount;
-import com.owncloud.android.lib.network.webdav.WebdavUtils;
-
+import com.owncloud.android.ui.dialog.LoadingDialog;
 import com.owncloud.android.utils.Log_OC;
 
 
@@ -45,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. */
@@ -73,6 +83,13 @@ 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;
 
     
     /**
@@ -85,6 +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);
@@ -249,17 +268,6 @@ public abstract class FileActivity extends SherlockFragmentActivity {
     }
     
     
-    /**
-     *  @return 'True' if the server supports the Share API
-     */
-    public boolean isSharedSupported() {
-        if (getAccount() != null) {
-            AccountManager accountManager = AccountManager.get(this);
-            return Boolean.parseBoolean(accountManager.getUserData(getAccount(), OwnCloudAccount.Constants.KEY_SUPPORTS_SHARE_API));
-        }
-        return false;
-    }
-
     /**
      * Helper class handling a callback from the {@link AccountManager} after the creation of
      * a new ownCloud {@link Account} finished, successfully or not.
@@ -307,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);
-                }
-            }
-            
-            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);
+    private void onCreateShareOperationFinish(CreateShareOperation operation, RemoteOperationResult result) {
+        dismissLoadingDialog();
+        if (result.isSuccess()) {
+            Intent sendIntent = operation.getSendIntent();
+            startActivity(sendIntent);
             
-        } 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();
         }
     }
     

+ 43 - 96
src/com/owncloud/android/ui/activity/FileDisplayActivity.java

@@ -38,12 +38,10 @@ 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;
@@ -61,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;
@@ -70,11 +67,10 @@ 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;
@@ -84,7 +80,6 @@ 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;
@@ -105,13 +100,10 @@ import com.owncloud.android.utils.Log_OC;
  */
 
 public class FileDisplayActivity extends FileActivity implements
-OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNavigationListener, OnSslValidatorListener, OnRemoteOperationListener, EditNameDialogListener {
+OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNavigationListener, OnSslValidatorListener, EditNameDialogListener {
 
     private ArrayAdapter<String> mDirectories;
 
-    /** Access point to the cached database for the current ownCloud {@link Account} */
-    private FileDataStorageManager mStorageManager = null;
-
     private SyncBroadcastReceiver mSyncBroadcastReceiver;
     private UploadFinishReceiver mUploadFinishReceiver;
     private DownloadFinishReceiver mDownloadFinishReceiver;
@@ -134,8 +126,6 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
     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;
@@ -147,7 +137,6 @@ 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;
@@ -159,8 +148,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();
@@ -231,9 +218,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
@@ -243,15 +229,15 @@ 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);
@@ -267,10 +253,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!");
         }
     }
 
@@ -283,10 +265,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);
     }
@@ -448,12 +429,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;
@@ -465,7 +446,6 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
         }
     }
 
-
     @Override
     public boolean onCreateOptionsMenu(Menu menu) {
         MenuInflater inflater = getSherlock().getMenuInflater();
@@ -544,7 +524,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);
             }
@@ -837,30 +817,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
@@ -939,14 +895,13 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
             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) && mStorageManager != null); 
+            boolean sameAccount = (getAccount() != null && accountName.equals(getAccount().name) && getStorageManager() != null); 
 
             if (sameAccount) {
                 
                 if (!FileSyncAdapter.EVENT_FULL_SYNC_START.equals(event)) {
-                    
-                    OCFile currentFile = (getFile() == null) ? null : mStorageManager.getFileByPath(getFile().getRemotePath());
-                    OCFile currentDir = (getCurrentDir() == null) ? null : mStorageManager.getFileByPath(getCurrentDir().getRemotePath());
+                    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 
@@ -972,13 +927,17 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
                         setFile(currentFile);
                     }
                     
-                    mSyncInProgress = (!FileSyncAdapter.EVENT_FULL_SYNC_END.equals(event) && !SynchronizeFolderOperation.EVENT_SINGLE_FOLDER_SYNCED.equals(event));
+                    mSyncInProgress = (!FileSyncAdapter.EVENT_FULL_SYNC_END.equals(event) && 
+                                        !SynchronizeFolderOperation.EVENT_SINGLE_FOLDER_SYNCED.equals(event) &&
+                                        (synchResult == null || synchResult.isSuccess())) ;
                     
                     if (synchResult != null && 
                         synchResult.isSuccess() &&
                             (SynchronizeFolderOperation.EVENT_SINGLE_FOLDER_SYNCED.equals(event) || 
                                 FileSyncAdapter.EVENT_FOLDER_CONTENTS_SYNCED.equals(event)
-                            )
+                            ) &&
+                            !mRefreshSharesInProgress &&
+                            getFileOperationsHelper().isSharedSupported(FileDisplayActivity.this)
                         ) {
                         startGetShares();
                     }
@@ -1073,7 +1032,7 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
                 Account account = intent.getParcelableExtra(OperationsService.EXTRA_ACCOUNT);
                 RemoteOperationResult getSharesResult = (RemoteOperationResult)intent.getSerializableExtra(OperationsService.EXTRA_RESULT);
                 if (getAccount() != null && account.name.equals(getAccount().name)
-                        && mStorageManager != null
+                        && getStorageManager() != null
                         ) {
                     refeshListOfFilesFragment();
                 }
@@ -1090,23 +1049,13 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
             
     }
 
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public FileDataStorageManager getStorageManager() {
-        return mStorageManager;
-    }
-
-
     public void browseToRoot() {
         OCFileListFragment listOfFiles = getListOfFilesFragment(); 
         if (listOfFiles != null) {  // should never be null, indeed
             while (mDirectories.getCount() > 1) {
                 popDirname();
             }
-            OCFile root = mStorageManager.getFileByPath(OCFile.ROOT_PATH);
+            OCFile root = getStorageManager().getFileByPath(OCFile.ROOT_PATH);
             listOfFiles.listDirectory(root);
             setFile(listOfFiles.getCurrentFile());
             startSyncFolderOperation(root);
@@ -1342,6 +1291,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);
 
@@ -1354,12 +1305,16 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
         } else if (operation instanceof CreateFolderOperation) {
             onCreateFolderOperationFinish((CreateFolderOperation)operation, result);
             
+        } else if (operation instanceof CreateShareOperation) {
+            onCreateShareOperationFinish((CreateShareOperation) operation, result);
+            
         } else if (operation instanceof UnshareLinkOperation) {
             onUnshareLinkOperationFinish((UnshareLinkOperation)operation, result);
-        }
+        
+        } 
+        
     }
 
-
     private void onUnshareLinkOperationFinish(UnshareLinkOperation operation, RemoteOperationResult result) {
         if (result.getCode() == ResultCode.FILE_NOT_FOUND) {
             // Show a Message
@@ -1372,6 +1327,13 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
         dismissLoadingDialog();
     }
 
+    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. 
@@ -1390,7 +1352,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();
             }
 
@@ -1449,7 +1411,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();
             }
 
@@ -1525,11 +1487,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();
@@ -1554,9 +1516,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;
@@ -1591,21 +1553,6 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
     }
     
     
-    public void unshareFileWithLink(OCFile file) {
-        
-        if (isSharedSupported()) {
-            // Unshare the file
-            UnshareLinkOperation unshare = new UnshareLinkOperation(file);
-            unshare.execute(getStorageManager(), this, this, mHandler, this);
-         
-            showLoadingDialog();
-            
-        } else {
-            // Show a Message
-            Toast t = Toast.makeText(this, getString(R.string.share_link_no_support_share_api), Toast.LENGTH_LONG);
-            t.show();
-            
-        }
-    }
+
 
 }

+ 1 - 1
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();
         }

+ 151 - 0
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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.ui.dialog;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.actionbarsherlock.app.SherlockDialogFragment;
+import com.owncloud.android.R;
+import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.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<String> packagesToExcludeList = Arrays.asList(packagesToExclude != null ? packagesToExclude : new String[0]);
+        mFile = getArguments().getParcelable(ARG_FILE_TO_SHARE);
+        
+        PackageManager pm= getSherlockActivity().getPackageManager();
+        List<ResolveInfo> activities = pm.queryIntentActivities(mIntent, PackageManager.MATCH_DEFAULT_ONLY);
+        Iterator<ResolveInfo> it = activities.iterator();
+        ResolveInfo resolveInfo;
+        while (it.hasNext()) {
+            resolveInfo = it.next();
+            if (packagesToExcludeList.contains(resolveInfo.activityInfo.packageName.toLowerCase())) {
+                it.remove();
+            }
+        }
+        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<ResolveInfo> {
+        
+        private PackageManager mPackageManager;
+        
+        ActivityAdapter(Context context, PackageManager pm, List<ResolveInfo> apps) {
+            super(context, R.layout.activity_row, apps);
+            this.mPackageManager = pm;
+        }
+        
+        @Override
+        public View getView(int position, View convertView, ViewGroup parent) {
+            if (convertView == null) {
+                convertView = newView(parent);
+            }
+            bindView(position, convertView);
+            return convertView;
+        }
+        
+        private View newView(ViewGroup parent) {
+            return(((LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(R.layout.activity_row, parent, false));
+        }
+        
+        private void bindView(int position, View row) {
+            TextView label = (TextView) row.findViewById(R.id.title);
+            label.setText(getItem(position).loadLabel(mPackageManager));
+            ImageView icon = (ImageView) row.findViewById(R.id.icon);
+            icon.setImageDrawable(getItem(position).loadIcon(mPackageManager));
+        }
+    }
+    
+}

+ 8 - 3
src/com/owncloud/android/ui/fragment/FileDetailFragment.java

@@ -340,8 +340,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: {
@@ -363,7 +369,7 @@ public class FileDetailFragment extends FileFragment implements
                 return false;
         }
     }
-    
+
     @Override
     public void onClick(View v) {
         switch (v.getId()) {
@@ -404,7 +410,6 @@ public class FileDetailFragment extends FileFragment implements
         }
     }
 
-
     private void removeFile() {
         OCFile file = getFile();
         ConfirmationDialogFragment confDialog = ConfirmationDialogFragment.newInstance(

+ 2 - 4
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);
-        
-        
+
     }
     
 }

+ 11 - 8
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 {
@@ -283,9 +282,15 @@ public class OCFileListFragment extends ExtendedListFragment implements EditName
     public boolean onContextItemSelected (MenuItem item) {
         AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();        
         mTargetFile = (OCFile) mAdapter.getItem(info.position);
-        switch (item.getItemId()) {
+        switch (item.getItemId()) {                
+            case R.id.action_share_file: {
+                FileDisplayActivity activity = (FileDisplayActivity) getSherlockActivity();
+                activity.getFileOperationsHelper().shareFileWithLink(mTargetFile, activity);
+                return true;
+            }
             case R.id.action_unshare_file: {
-                mContainerActivity.unshareFileWithLink(mTargetFile);
+                FileDisplayActivity activity = (FileDisplayActivity) getSherlockActivity();
+                activity.getFileOperationsHelper().unshareFileWithLink(mTargetFile, activity);
                 return true;
             }
             case R.id.action_rename_file: {
@@ -414,7 +419,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
@@ -422,8 +427,6 @@ public class OCFileListFragment extends ExtendedListFragment implements EditName
          * @param file
          */
         public void onBrowsedDownTo(OCFile folder);
-        
-        public void unshareFileWithLink(OCFile mTargetFile);
 
         public void startDownloadForPreview(OCFile file);
 

+ 8 - 14
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);
         }
     }
-    
+
 }

+ 6 - 0
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;
@@ -252,6 +253,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;

+ 12 - 0
src/com/owncloud/android/ui/preview/PreviewMediaFragment.java

@@ -312,6 +312,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;
@@ -339,6 +343,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());        

+ 2 - 6
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();
         }
    }