浏览代码

Merge branch 'master' of https://github.com/owncloud/android into material_buttons

Conflicts:
	res/layout/list_item.xml
Andy Scherzinger 9 年之前
父节点
当前提交
c31f602fd1
共有 100 个文件被更改,包括 2559 次插入773 次删除
  1. 76 54
      AndroidManifest.xml
  2. 6 2
      build.gradle
  3. 0 0
      res/drawable-hdpi/shared_via_link.png
  4. 0 0
      res/drawable-hdpi/shared_via_users.png
  5. 0 0
      res/drawable-mdpi/shared_via_link.png
  6. 0 0
      res/drawable-mdpi/shared_via_users.png
  7. 0 0
      res/drawable-xhdpi/shared_via_link.png
  8. 0 0
      res/drawable-xhdpi/shared_via_users.png
  9. 4 21
      res/layout/grid_image.xml
  10. 4 21
      res/layout/grid_item.xml
  11. 11 29
      res/layout/list_item.xml
  12. 38 0
      res/layout/search_users_groups_layout.xml
  13. 32 0
      res/layout/share_activity.xml
  14. 117 0
      res/layout/share_file_layout.xml
  15. 56 0
      res/layout/share_user_item.xml
  16. 16 9
      res/layout/ssl_untrusted_cert_layout.xml
  17. 5 0
      res/menu/file_actions_menu.xml
  18. 3 0
      res/values-az/strings.xml
  19. 0 1
      res/values-bg-rBG/strings.xml
  20. 2 0
      res/values-bn-rBD/strings.xml
  21. 1 0
      res/values-bn-rIN/strings.xml
  22. 2 0
      res/values-bs/strings.xml
  23. 7 2
      res/values-cs-rCZ/strings.xml
  24. 0 2
      res/values-da/strings.xml
  25. 4 2
      res/values-de-rDE/strings.xml
  26. 0 2
      res/values-de/strings.xml
  27. 3 2
      res/values-el/strings.xml
  28. 2 0
      res/values-es-rMX/strings.xml
  29. 8 2
      res/values-es/strings.xml
  30. 0 2
      res/values-et-rEE/strings.xml
  31. 2 0
      res/values-eu/strings.xml
  32. 4 2
      res/values-fa/strings.xml
  33. 0 2
      res/values-fi-rFI/strings.xml
  34. 8 3
      res/values-fr/strings.xml
  35. 0 2
      res/values-gl/strings.xml
  36. 6 0
      res/values-hu-rHU/strings.xml
  37. 7 2
      res/values-id/strings.xml
  38. 7 2
      res/values-it/strings.xml
  39. 0 2
      res/values-ja-rJP/strings.xml
  40. 0 2
      res/values-ko/strings.xml
  41. 4 2
      res/values-lt-rLT/strings.xml
  42. 1 0
      res/values-ms-rMY/strings.xml
  43. 7 2
      res/values-nb-rNO/strings.xml
  44. 8 3
      res/values-nl/strings.xml
  45. 2 0
      res/values-nn-rNO/strings.xml
  46. 10 2
      res/values-oc/strings.xml
  47. 7 2
      res/values-pt-rBR/strings.xml
  48. 0 2
      res/values-pt-rPT/strings.xml
  49. 4 2
      res/values-ro/strings.xml
  50. 7 2
      res/values-ru/strings.xml
  51. 2 0
      res/values-si-rLK/strings.xml
  52. 0 2
      res/values-sk-rSK/strings.xml
  53. 4 2
      res/values-sl/strings.xml
  54. 7 2
      res/values-sq/strings.xml
  55. 1 0
      res/values-sr-rSP/strings.xml
  56. 3 1
      res/values-sr/strings.xml
  57. 3 2
      res/values-th-rTH/strings.xml
  58. 0 2
      res/values-tr/strings.xml
  59. 0 2
      res/values-uk/strings.xml
  60. 1 0
      res/values-ur-rPK/strings.xml
  61. 6 0
      res/values-v21/styles.xml
  62. 0 2
      res/values-zh-rCN/strings.xml
  63. 7 2
      res/values-zh-rTW/strings.xml
  64. 18 2
      res/values/strings.xml
  65. 6 0
      res/values/styles.xml
  66. 28 0
      res/xml/users_and_groups_searchable.xml
  67. 11 0
      src/com/owncloud/android/authentication/AccountUtils.java
  68. 283 144
      src/com/owncloud/android/datamodel/FileDataStorageManager.java
  69. 23 2
      src/com/owncloud/android/datamodel/OCFile.java
  70. 3 3
      src/com/owncloud/android/db/ProviderMeta.java
  71. 14 4
      src/com/owncloud/android/files/FileMenuFilter.java
  72. 120 24
      src/com/owncloud/android/files/FileOperationsHelper.java
  73. 52 76
      src/com/owncloud/android/operations/CreateShareViaLinkOperation.java
  74. 115 0
      src/com/owncloud/android/operations/CreateShareWithShareeOperation.java
  75. 3 4
      src/com/owncloud/android/operations/GetSharesForFileOperation.java
  76. 0 63
      src/com/owncloud/android/operations/GetSharesOperation.java
  77. 10 2
      src/com/owncloud/android/operations/RefreshFolderOperation.java
  78. 2 1
      src/com/owncloud/android/operations/SynchronizeFolderOperation.java
  79. 31 19
      src/com/owncloud/android/operations/UnshareOperation.java
  80. 47 53
      src/com/owncloud/android/providers/FileContentProvider.java
  81. 197 0
      src/com/owncloud/android/providers/UsersAndGroupsSearchProvider.java
  82. 34 11
      src/com/owncloud/android/services/OperationsService.java
  83. 44 46
      src/com/owncloud/android/ui/activity/FileActivity.java
  84. 73 45
      src/com/owncloud/android/ui/activity/FileDisplayActivity.java
  85. 6 9
      src/com/owncloud/android/ui/activity/FolderPickerActivity.java
  86. 197 0
      src/com/owncloud/android/ui/activity/ShareActivity.java
  87. 0 2
      src/com/owncloud/android/ui/activity/Uploader.java
  88. 13 28
      src/com/owncloud/android/ui/adapter/FileListListAdapter.java
  89. 0 1
      src/com/owncloud/android/ui/adapter/LocalFileListAdapter.java
  90. 103 0
      src/com/owncloud/android/ui/adapter/ShareUserListAdapter.java
  91. 60 11
      src/com/owncloud/android/ui/adapter/X509CertificateViewAdapter.java
  92. 5 1
      src/com/owncloud/android/ui/fragment/FileDetailFragment.java
  93. 1 2
      src/com/owncloud/android/ui/fragment/FileFragment.java
  94. 11 4
      src/com/owncloud/android/ui/fragment/OCFileListFragment.java
  95. 247 0
      src/com/owncloud/android/ui/fragment/SearchShareesFragment.java
  96. 259 0
      src/com/owncloud/android/ui/fragment/ShareFileFragment.java
  97. 12 13
      src/com/owncloud/android/ui/preview/PreviewImageActivity.java
  98. 4 1
      src/com/owncloud/android/ui/preview/PreviewImageFragment.java
  99. 8 0
      src/com/owncloud/android/ui/preview/PreviewMediaFragment.java
  100. 4 0
      src/com/owncloud/android/ui/preview/PreviewTextFragment.java

+ 76 - 54
AndroidManifest.xml

@@ -1,4 +1,5 @@
-<?xml version="1.0" encoding="utf-8"?><!--
+<?xml version="1.0" encoding="utf-8"?>
+<!--
   ownCloud Android client application
 
   Copyright (C) 2012  Bartek Przybylski
@@ -15,10 +16,15 @@
 
   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
- -->
-<manifest package="com.owncloud.android"
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.owncloud.android"
     android:versionCode="10800000"
-    android:versionName="1.8.0" xmlns:android="http://schemas.android.com/apk/res/android">
+    android:versionName="1.8.0" >
+
+    <uses-sdk
+        android:minSdkVersion="14"
+        android:targetSdkVersion="22" />
 
     <uses-permission android:name="android.permission.GET_ACCOUNTS" />
     <uses-permission android:name="android.permission.USE_CREDENTIALS" />
@@ -31,64 +37,60 @@
     <uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS" />
     <uses-permission android:name="android.permission.BROADCAST_STICKY" />
     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
-    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
-    <uses-permission android:name="android.permission.WAKE_LOCK"/>
-    
-    <uses-sdk
-        android:minSdkVersion="14"
-        android:targetSdkVersion="22" />
+    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
+    <uses-permission android:name="android.permission.WAKE_LOCK" />
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
 
-    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
+    <android:uses-permission android:name="android.permission.READ_PHONE_STATE" />
+    <android:uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
 
     <application
         android:name=".MainApp"
         android:icon="@drawable/icon"
         android:label="@string/app_name"
-        android:theme="@style/Theme.ownCloud">
+        android:theme="@style/Theme.ownCloud" >
         <activity
             android:name=".ui.activity.FileDisplayActivity"
-            android:label="@string/app_name">
+            android:label="@string/app_name" >
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
+
                 <category android:name="android.intent.category.LAUNCHER" />
             </intent-filter>
         </activity>
-        <activity android:name=".ui.activity.UploadFilesActivity"></activity>
-        <activity android:name=".ui.activity.Uploader">
+        <activity android:name=".ui.activity.UploadFilesActivity" />
+        <activity android:name=".ui.activity.Uploader" >
             <intent-filter>
-                <action android:name="android.intent.action.SEND"></action>
+                <action android:name="android.intent.action.SEND" />
 
-                <category android:name="android.intent.category.DEFAULT"></category>
+                <category android:name="android.intent.category.DEFAULT" />
 
-                <data android:mimeType="*/*"></data>
+                <data android:mimeType="*/*" />
             </intent-filter>
             <intent-filter>
-                <action android:name="android.intent.action.SEND_MULTIPLE"></action>
-
-                <category android:name="android.intent.category.DEFAULT"></category>
+                <action android:name="android.intent.action.SEND_MULTIPLE" />
 
-                <data android:mimeType="*/*"></data>
+                <category android:name="android.intent.category.DEFAULT" />
 
+                <data android:mimeType="*/*" />
             </intent-filter>
         </activity>
         <activity
             android:name=".ui.activity.Preferences"
             android:theme="@style/Theme.ownCloud" >
         </activity>
-        <activity	
+        <activity
             android:name=".ui.preview.PreviewImageActivity"
-            android:theme="@style/Theme.ownCloud.Overlay"
-            />
-		        
-        <activity	
+            android:theme="@style/Theme.ownCloud.Overlay" />
+        <activity
             android:name=".ui.preview.PreviewVideoActivity"
             android:label="@string/app_name"
-            android:theme="@style/Theme.ownCloud.Fullscreen"></activity>
+            android:theme="@style/Theme.ownCloud.Fullscreen" />
 
         <service
             android:name=".authentication.AccountAuthenticatorService"
-            android:exported="true">
-            <intent-filter android:priority="100">
+            android:exported="true" >
+            <intent-filter android:priority="100" >
                 <action android:name="android.accounts.AccountAuthenticator" />
             </intent-filter>
 
@@ -98,7 +100,7 @@
         </service>
         <service
             android:name=".syncadapter.FileSyncService"
-            android:exported="true">
+            android:exported="true" >
             <intent-filter>
                 <action android:name="android.content.SyncAdapter" />
             </intent-filter>
@@ -114,13 +116,20 @@
             android:enabled="true"
             android:exported="false"
             android:label="@string/sync_string_files"
-            android:syncable="true"></provider>
+            android:syncable="true" />
+
+        <provider
+            android:name=".providers.UsersAndGroupsSearchProvider"
+            android:authorities="com.owncloud.android.providers.UsersAndGroupsSearchProvider"
+            android:enabled="true"
+            android:exported="false"
+            android:label="@string/search_users_and_groups_hint" />
 
         <activity
             android:name=".authentication.AuthenticatorActivity"
             android:exported="true"
-            android:theme="@style/Theme.ownCloud.noActionBar"
-            android:launchMode="singleTask">
+            android:launchMode="singleTask"
+            android:theme="@style/Theme.ownCloud.noActionBar" >
             <intent-filter>
                 <action android:name="android.intent.action.VIEW" />
 
@@ -131,6 +140,7 @@
             </intent-filter>
             <intent-filter>
                 <action android:name="com.owncloud.android.workaround.accounts.CREATE" />
+
                 <category android:name="android.intent.category.DEFAULT" />
             </intent-filter>
         </activity>
@@ -141,48 +151,60 @@
         <service android:name=".media.MediaService" />
 
         <activity android:name=".ui.activity.PassCodeActivity" />
-        <activity android:name=".ui.activity.ConflictsResolveActivity"/>
-        <activity android:name=".ui.activity.GenericExplanationActivity"/>
-        <activity android:name=".ui.activity.ErrorsWhileCopyingHandlerActivity"/>
-        
-        <activity android:name=".ui.activity.LogHistoryActivity"/>
-        
-        <receiver android:name=".files.InstantUploadBroadcastReceiver">
+        <activity android:name=".ui.activity.ConflictsResolveActivity" />
+        <activity android:name=".ui.activity.GenericExplanationActivity" />
+        <activity android:name=".ui.activity.ErrorsWhileCopyingHandlerActivity" />
+        <activity android:name=".ui.activity.LogHistoryActivity" />
+
+        <receiver android:name=".files.InstantUploadBroadcastReceiver" >
             <intent-filter>
+
                 <!-- unofficially supported by many Android phones but not by HTC devices: -->
                 <action android:name="com.android.camera.NEW_PICTURE" />
                 <!-- officially supported since Android 4.0 (SDK 14, works even for HTC devices): -->
                 <action android:name="android.hardware.action.NEW_PICTURE" />
+
                 <data android:mimeType="image/*" />
             </intent-filter>
             <intent-filter>
                 <action android:name="android.hardware.action.NEW_VIDEO" />
+
                 <data android:mimeType="video/*" />
             </intent-filter>
             <intent-filter>
                 <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
             </intent-filter>
         </receiver>
-        <receiver android:name=".files.BootupBroadcastReceiver">
+        <receiver android:name=".files.BootupBroadcastReceiver" >
             <intent-filter>
                 <action android:name="android.intent.action.BOOT_COMPLETED" />
             </intent-filter>
         </receiver>
-        <service android:name=".services.observer.FileObserverService"/>
-        
-		<activity
-			android:name=".ui.activity.CopyToClipboardActivity"
-			android:label="@string/copy_link"
-			android:icon="@drawable/copy_link"/>
 
-        <activity
-			android:name=".ui.activity.FolderPickerActivity"
-			android:label="@string/app_name"/>
+        <service android:name=".services.observer.FileObserverService" />
 
         <activity
-			android:name=".ui.activity.UploadPathActivity"
-			android:label="@string/app_name"/>
-        
+            android:name=".ui.activity.CopyToClipboardActivity"
+            android:icon="@drawable/copy_link"
+            android:label="@string/copy_link" />
+        <activity
+            android:name=".ui.activity.FolderPickerActivity"
+            android:label="@string/app_name" />
+        <activity
+            android:name=".ui.activity.UploadPathActivity"
+            android:label="@string/app_name" />
+        <activity
+            android:name=".ui.activity.ShareActivity"
+            android:label="@string/share_dialog_title"
+            android:theme="@style/Theme.ownCloud.Dialog"
+            android:launchMode="singleTop"
+            android:windowSoftInputMode="adjustResize" >
+            <intent-filter>
+                <action android:name="android.intent.action.SEARCH" />
+            </intent-filter>
+            <meta-data android:name="android.app.searchable"
+                       android:resource="@xml/users_and_groups_searchable"/>
+        </activity>
     </application>
 
 </manifest>

+ 6 - 2
build.gradle

@@ -20,8 +20,8 @@ repositories {
 
 dependencies {
     compile name: 'touch-image-view'
-    compile 'com.android.support:support-v4:22.2.1'
     compile project(':owncloud-android-library')
+    compile 'com.android.support:support-v4:22.2.1'
     compile 'com.jakewharton:disklrucache:2.0.2'
     compile 'com.android.support:appcompat-v7:22.2.1'
 }
@@ -58,7 +58,7 @@ android {
             abortOnError false
         }
     }
-    
+
     productFlavors {
     }
 
@@ -68,3 +68,7 @@ android {
 }
 
 
+
+
+
+

+ 0 - 0
res/drawable-hdpi/sharedlink.png → res/drawable-hdpi/shared_via_link.png


+ 0 - 0
res/drawable-hdpi/shared_with_me.png → res/drawable-hdpi/shared_via_users.png


+ 0 - 0
res/drawable-mdpi/sharedlink.png → res/drawable-mdpi/shared_via_link.png


+ 0 - 0
res/drawable-mdpi/shared_with_me.png → res/drawable-mdpi/shared_via_users.png


+ 0 - 0
res/drawable-xhdpi/sharedlink.png → res/drawable-xhdpi/shared_via_link.png


+ 0 - 0
res/drawable-xhdpi/shared_with_me.png → res/drawable-xhdpi/shared_via_users.png


+ 4 - 21
res/layout/grid_image.xml

@@ -38,30 +38,13 @@
             android:scaleType="centerCrop"
             android:src="@drawable/ic_menu_archive"/>
 
-        <LinearLayout
+        <ImageView
+            android:id="@+id/sharedIcon"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_gravity="top|right"
-            android:orientation="vertical"
-            android:layout_margin="4dp">
-
-            <ImageView
-                android:id="@+id/sharedIcon"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_gravity="center"
-                android:layout_marginBottom="4dp"
-                android:src="@drawable/sharedlink" />
-
-            <ImageView
-                android:id="@+id/sharedWithMeIcon"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_gravity="center"
-                android:layout_marginTop="4dp"
-                android:src="@drawable/shared_with_me"
-                android:visibility="invisible" />
-        </LinearLayout>
+            android:layout_margin="4dp"
+            android:src="@drawable/shared_via_link" />
 
         <ImageView
             android:id="@+id/localFileIndicator"

+ 4 - 21
res/layout/grid_item.xml

@@ -39,30 +39,13 @@
             android:layout_marginRight="10dp"
             android:src="@drawable/ic_menu_archive" />
 
-        <LinearLayout
+        <ImageView
+            android:id="@+id/sharedIcon"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
+            android:layout_margin="4dp"
             android:layout_gravity="top|right"
-            android:orientation="vertical"
-            android:layout_margin="2dp">
-
-            <ImageView
-                android:id="@+id/sharedIcon"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_gravity="center"
-                android:layout_marginBottom="2dp"
-                android:src="@drawable/sharedlink" />
-
-            <ImageView
-                android:id="@+id/sharedWithMeIcon"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_gravity="center"
-                android:layout_marginTop="2dp"
-                android:src="@drawable/shared_with_me"
-                android:visibility="invisible" />
-        </LinearLayout>
+            android:src="@drawable/shared_via_link" />
 
         <ImageView
             android:id="@+id/localFileIndicator"

+ 11 - 29
res/layout/list_item.xml

@@ -81,7 +81,7 @@
                 android:ellipsize="middle"
                 android:singleLine="true"
                 android:text="TextView"
-                android:textColor="#303030"
+                android:textColor="@color/textColor"
                 android:textSize="@dimen/two_line_primary_text_size" />
 
             <LinearLayout
@@ -121,34 +121,16 @@
 
         </LinearLayout>
 
-        <LinearLayout
-            android:layout_width="25dp"
-            android:layout_height="match_parent"
-            android:gravity="center_vertical"
-            android:orientation="vertical">
-
-            <ImageView
-                android:id="@+id/sharedIcon"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_gravity="center"
-                android:layout_marginLeft="4dp"
-                android:layout_marginBottom="4dp"
-                android:layout_marginRight="4dp"
-                android:src="@drawable/sharedlink" />
-
-            <ImageView
-                android:id="@+id/sharedWithMeIcon"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_gravity="center"
-                android:layout_marginLeft="4dp"
-                android:layout_marginRight="4dp"
-                android:layout_marginTop="4dp"
-                android:src="@drawable/shared_with_me"
-                android:visibility="invisible" />
-
-        </LinearLayout>
+        <ImageView
+            android:id="@+id/sharedIcon"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center"
+            android:layout_marginTop="4dp"
+            android:layout_marginLeft="4dp"
+            android:layout_marginBottom="4dp"
+            android:layout_marginRight="4dp"
+            android:src="@drawable/shared_via_link" />
 
         <ImageView
             android:id="@+id/custom_checkbox"

+ 38 - 0
res/layout/search_users_groups_layout.xml

@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ownCloud Android client application
+  Copyright (C) 2015 ownCloud Inc.
+
+  This program is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License version 2,
+  as published by the Free Software Foundation.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical"
+    android:id="@+id/search_layout"
+    android:minWidth="200dp">
+
+    <SearchView
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:id="@+id/searchView"
+        android:hint="@string/share_search"/>
+
+    <ListView
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:id="@+id/searchUsersListView"
+        android:scrollbars="vertical"/>
+
+</LinearLayout>

+ 32 - 0
res/layout/share_activity.xml

@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ownCloud Android client application
+  Copyright (C) 2015 ownCloud Inc.
+
+  This program is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License version 2,
+  as published by the Free Software Foundation.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+-->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    tools:context="com.owncloud.android.ui.activity.ShareActivity">
+
+    <FrameLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:id="@+id/share_fragment_container">
+    </FrameLayout>
+
+</LinearLayout>

+ 117 - 0
res/layout/share_file_layout.xml

@@ -0,0 +1,117 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ownCloud Android client application
+  Copyright (C) 2015 ownCloud Inc.
+
+  This program is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License version 2,
+  as published by the Free Software Foundation.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+-->
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    tools:context="com.owncloud.android.ui.fragment.ShareFileFragment">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:background="@color/background_material_light"
+        android:orientation="vertical">
+
+        <RelativeLayout
+            android:id="@+id/shareHeaderContainer"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="6dp"
+            android:layout_marginBottom="6dp"
+            android:background="@color/background_color">
+
+            <ImageView
+                android:id="@+id/shareFileIcon"
+                android:layout_width="@dimen/file_icon_size"
+                android:layout_height="@dimen/file_icon_size"
+                android:src="@drawable/file"
+                android:layout_marginLeft="12dp"
+                android:layout_marginRight="12dp"
+                android:layout_gravity="center_vertical"
+                android:layout_marginTop="12dp"
+                android:layout_marginBottom="12dp"/>
+
+            <TextView
+                android:id="@+id/shareFileName"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/placeholder_filename"
+                android:textSize="16dip"
+                android:layout_gravity="center_vertical"
+                android:layout_marginLeft="4dp"
+                android:layout_marginRight="8dp"
+                android:layout_toRightOf="@+id/shareFileIcon"
+                android:layout_toEndOf="@+id/shareFileIcon"
+                android:singleLine="true"
+                android:ellipsize="middle"
+                android:layout_marginTop="12dp"/>
+
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:textSize="12dip"
+                android:text="@string/placeholder_filesize"
+                android:id="@+id/shareFileSize"
+                android:layout_below="@+id/shareFileName"
+                android:layout_toRightOf="@+id/shareFileIcon"
+                android:layout_toEndOf="@+id/shareFileIcon"
+                android:layout_marginTop="4dp"
+                android:layout_marginLeft="4dp"
+                android:layout_marginBottom="12dp"
+                android:layout_gravity="center_vertical"/>
+
+        </RelativeLayout>
+
+        <TextView
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:textSize="16dip"
+            android:text="@string/share_with_user_section_title"
+            android:id="@+id/shareWithUsersSectionTitle"
+            android:layout_gravity="left"
+            android:padding="8dp"
+            android:background="@color/actionbar_start_color"
+            android:textColor="@color/white"/>
+
+        <ListView
+            android:layout_width="match_parent"
+            android:layout_height="0dip"
+            android:id="@+id/shareUsersList"
+            android:visibility="gone"
+            android:scrollbars="vertical"
+            android:layout_weight="1"/>
+
+        <TextView
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:id="@+id/shareNoUsers"
+            android:text="@string/share_no_users"
+            android:textSize="12dip"
+            android:padding="12dp" />
+
+        <android.support.v7.widget.AppCompatButton
+            android:id="@+id/addUserButton"
+            style="@style/ownCloud.Button"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_horizontal"
+            android:text="@string/share_add_user_or_group"
+            android:contentDescription="shareAddUserButton"/>
+
+    </LinearLayout>
+</FrameLayout>

+ 56 - 0
res/layout/share_user_item.xml

@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ownCloud Android client application
+  Copyright (C) 2015 ownCloud Inc.
+
+  This program is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License version 2,
+  as published by the Free Software Foundation.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal"
+        android:weightSum="1"
+        android:longClickable="true">
+        <TextView
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_weight="0.9"
+            android:textSize="16dip"
+            android:text="@string/username"
+            android:id="@+id/userOrGroupName"
+            android:layout_margin="12dp"
+            android:textColor="@color/textColor"
+            android:singleLine="true"
+            android:ellipsize="middle"/>
+
+        <ImageView
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            android:layout_weight="0.1"
+            android:id="@+id/unshareButton"
+            android:src="@drawable/ic_cancel"
+            android:layout_marginRight="8dp"
+            android:layout_marginLeft="4dp"
+            android:layout_gravity="center_horizontal"/>
+    </LinearLayout>
+
+    <View
+        android:layout_width="match_parent"
+        android:layout_height="1dp"
+        android:background="@color/list_divider_background"></View>
+</LinearLayout>

+ 16 - 9
res/layout/ssl_untrusted_cert_layout.xml

@@ -377,7 +377,6 @@
 				    android:text=""
 				    android:textAppearance="?android:attr/textAppearanceSmall"
 				/>
-				
 
 				<TextView
         			android:id="@+id/label_signature"
@@ -404,16 +403,24 @@
         			android:text=""
         			android:textAppearance="?android:attr/textAppearanceSmall"
         		/>
-																								
-								
+
 				<TextView
-        			android:id="@+id/value_signature"
-        			android:layout_width="wrap_content"
-        			android:layout_height="wrap_content"
+					android:id="@+id/label_certificate_fingerprint"
+					android:layout_width="wrap_content"
+					android:layout_height="wrap_content"
 					android:paddingBottom="5dp"
-        			android:text=""
-        			android:textAppearance="?android:attr/textAppearanceSmall"
-        		/>
+					android:text="@string/ssl_validator_label_certificate_fingerprint"
+					android:textAppearance="?android:attr/textAppearanceSmall"
+				/>
+
+				<TextView
+					android:id="@+id/value_certificate_fingerprint"
+					android:layout_width="wrap_content"
+					android:layout_height="wrap_content"
+					android:paddingBottom="5dp"
+					android:text=""
+					android:textAppearance="?android:attr/textAppearanceSmall"
+				/>
 				
 		</LinearLayout>
 		

+ 5 - 0
res/menu/file_actions_menu.xml

@@ -28,6 +28,11 @@
         android:title="@string/action_unshare_file"
         android:icon="@android:drawable/ic_menu_share"
         android:orderInCategory="1" />
+    <item
+        android:id="@+id/action_share_with_users"
+        android:title="@string/action_share_with_users"
+        android:orderInCategory="1" />
+
     <item
         android:id="@+id/action_open_file_with"
         android:title="@string/actionbar_open_with"

+ 3 - 0
res/values-az/strings.xml

@@ -285,6 +285,9 @@ inzibatçınızla əlaqə saxlayasınız.</string>
   <string name="prefs_category_instant_uploading">Anında yükləmələr</string>
   <string name="prefs_category_security">Təhlükəsizlik</string>
   <string name="prefs_instant_video_upload_path_title">Video ünvanını yüklə</string>
+  <string name="subject_user_shared_with_you">%1$s paylaşdı \"%2$s\" sizinlə</string>
   <string name="auth_refresh_button">Qoşulmanı yenilə</string>
   <string name="auth_host_address">Server ünvanı</string>
+  <string name="share_dialog_title">Paylaşılır</string>
+  <string name="share_search">Axtarış</string>
 </resources>

+ 0 - 1
res/values-bg-rBG/strings.xml

@@ -303,7 +303,6 @@
   <string name="prefs_instant_video_upload_path_title">Качване на видео път</string>
   <string name="shared_subject_header">споделен</string>
   <string name="with_you_subject_header">с теб</string>
-  <string name="subject_token">%1$s споделен \"%2$s\" с теб</string>
   <string name="auth_refresh_button">Обнови връзката</string>
   <string name="auth_host_address">Адрес на сървъра</string>
   <string name="common_error_out_memory">Няма достатъчно памет</string>

+ 2 - 0
res/values-bn-rBD/strings.xml

@@ -254,4 +254,6 @@
   <string name="move_file_not_found">সরাতে ব্যার্থ হলো। ফাইলটি রয়েছে কিনা দেখুন।</string>
   <string name="prefs_category_security">নিরাপত্তা</string>
   <string name="auth_host_address">সার্ভার ঠিকানা</string>
+  <string name="share_dialog_title">ভাগাভাগিরত</string>
+  <string name="share_search">অনুসন্ধান</string>
 </resources>

+ 1 - 0
res/values-bn-rIN/strings.xml

@@ -23,4 +23,5 @@
   <string name="common_rename">পুনঃনামকরণ</string>
   <string name="common_remove">সরান</string>
   <string name="empty"></string>
+  <string name="share_search">অনুসন্ধান</string>
 </resources>

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

@@ -38,4 +38,6 @@
   <string name="folder_picker_choose_button_text">Izaberite</string>
   <string name="prefs_category_security">Sigurnost</string>
   <string name="auth_host_address">Adresa servera</string>
+  <string name="share_dialog_title">Dijeljenje</string>
+  <string name="share_search">Potraži</string>
 </resources>

+ 7 - 2
res/values-cs-rCZ/strings.xml

@@ -317,8 +317,8 @@ správce systému.</string>
   <string name="sync_folder_failed_content">Synchronizaci adresáře %1$s nelze dokončit</string>
   <string name="shared_subject_header">sdílené</string>
   <string name="with_you_subject_header">s vámi</string>
-  <string name="subject_token">%1$s s vámi sdílí \"%2$s\"</string>
-  <string name="saml_subject_token">\"%1$s\" ti byl nasdílen</string>
+  <string name="subject_user_shared_with_you">%1$s s vámi sdílí \"%2$s\"</string>
+  <string name="subject_shared_with_you">\"%1$s\" ti byl nasdílen</string>
   <string name="auth_refresh_button">Obnovit připojení</string>
   <string name="auth_host_address">Adresa serveru</string>
   <string name="common_error_out_memory">Nedostatek paměti</string>
@@ -331,4 +331,9 @@ správce systému.</string>
   <string name="file_list__footer__files">%1$d soubory(ů)</string>
   <string name="file_list__footer__files_and_folder">%1$d soubory(ů), 1 adresář</string>
   <string name="file_list__footer__files_and_folders">%1$d soubory(ů), %2$d adresáře(ů)</string>
+  <string name="share_dialog_title">Sdílení</string>
+  <string name="share_with_user_section_title">Sdílet s uživateli a skupinami</string>
+  <string name="share_no_users">Zatím nebyla s uživateli sdílena žádná data</string>
+  <string name="share_add_user_or_group">Přidat uživatele nebo skupinu</string>
+  <string name="share_search">Hledat</string>
 </resources>

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

@@ -313,8 +313,6 @@
   <string name="prefs_instant_video_upload_path_title">Sti til videoupload</string>
   <string name="shared_subject_header">delt</string>
   <string name="with_you_subject_header">med dig</string>
-  <string name="subject_token">%1$s delte \"%2$s\" med dig</string>
-  <string name="saml_subject_token">\"%1$s\" er blevet delt med dig</string>
   <string name="auth_refresh_button">Genopfrisk forbindelsen</string>
   <string name="auth_host_address">Serveradresse</string>
   <string name="common_error_out_memory">Ikke tilstrækkelig hukommelse</string>

+ 4 - 2
res/values-de-rDE/strings.xml

@@ -306,8 +306,8 @@
   <string name="prefs_instant_video_upload_path_title">Verzeichnis zum Hochladen der Videos</string>
   <string name="shared_subject_header">geteilt</string>
   <string name="with_you_subject_header">Mit Ihnen</string>
-  <string name="subject_token">%1$s hat \"%2$s\" mit Ihnen geteilt</string>
-  <string name="saml_subject_token">\"%1$s\" wurde mit dir geteilt</string>
+  <string name="subject_user_shared_with_you">%1$s hat \"%2$s\" mit Ihnen geteilt</string>
+  <string name="subject_shared_with_you">\"%1$s\" wurde mit dir geteilt</string>
   <string name="auth_refresh_button">Verbindung aktualisieren</string>
   <string name="auth_host_address">Serveradresse</string>
   <string name="common_error_out_memory">Nicht genügend Speicher</string>
@@ -320,4 +320,6 @@
   <string name="file_list__footer__files">%1$d Dateien</string>
   <string name="file_list__footer__files_and_folder">%1$d Dateien, 1 Ordner</string>
   <string name="file_list__footer__files_and_folders">%1$d Dateien, %2$d Ordner</string>
+  <string name="share_dialog_title">Teilen</string>
+  <string name="share_search">Suche</string>
 </resources>

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

@@ -315,8 +315,6 @@
   <string name="prefs_instant_video_upload_path_title">Verzeichnis zum Hochladen der Videos</string>
   <string name="shared_subject_header">geteilt</string>
   <string name="with_you_subject_header">Mit Dir</string>
-  <string name="subject_token">%1$s hat \"%2$s\" mit Dir geteilt</string>
-  <string name="saml_subject_token">\"%1$s\" wurde mit dir geteilt</string>
   <string name="auth_refresh_button">Verbindung aktualisieren</string>
   <string name="auth_host_address">Serveradresse</string>
   <string name="common_error_out_memory">Nicht genügend Speicher</string>

+ 3 - 2
res/values-el/strings.xml

@@ -79,6 +79,7 @@
   <string name="filedetails_created">Δημιουργήθηκε:</string>
   <string name="filedetails_modified">Τροποποιήθηκε:</string>
   <string name="filedetails_download">Λήψη</string>
+  <string name="filedetails_sync_file">Συγχρονισμός</string>
   <string name="filedetails_renamed_in_upload_msg">Το αρχείο μετονομάστηκε σε %1$s κατά τη μεταφόρτωση</string>
   <string name="list_layout">Διάταξη Λίστας</string>
   <string name="action_share_file">Διαμοιρασμός συνδέσμου</string>
@@ -86,6 +87,7 @@
   <string name="common_yes">Ναι</string>
   <string name="common_no">Όχι</string>
   <string name="common_ok">ΟΚ</string>
+  <string name="common_cancel_sync">Ακύρωση συγχρονισμού</string>
   <string name="common_cancel">Άκυρο</string>
   <string name="common_save_exit">Αποθήκευση &amp; Έξοδος</string>
   <string name="common_error">Σφάλμα</string>
@@ -313,10 +315,9 @@
   <string name="prefs_category_instant_uploading">Στιγμιαίες Μεταφορτώσεις</string>
   <string name="prefs_category_security">Ασφάλεια</string>
   <string name="prefs_instant_video_upload_path_title">Διαδρομή Μεταφόρτωσης Βίντεο</string>
+  <string name="sync_folder_failed_content">Ο συγχρονισμός του φακέλου %1$s δεν μπόρεσε να ολοκληρωθεί</string>
   <string name="shared_subject_header">διαμοιρασμένα</string>
   <string name="with_you_subject_header">με εσάς</string>
-  <string name="subject_token">Ο %1$s διαμοιράστηκε το \"%2$s\" με εσάς</string>
-  <string name="saml_subject_token">\"%1$s\" μοιράστηκε μαζί σας</string>
   <string name="auth_refresh_button">Ανανέωση σύνδεσης</string>
   <string name="auth_host_address">Διεύθυνση διακομιστή</string>
   <string name="common_error_out_memory">Δεν υπάρχει αρκετή μνήμη</string>

+ 2 - 0
res/values-es-rMX/strings.xml

@@ -206,4 +206,6 @@
   <string name="folder_picker_choose_button_text">Seleccionar</string>
   <string name="prefs_category_security">Seguridad</string>
   <string name="auth_host_address">Dirección del servidor</string>
+  <string name="share_dialog_title">Compartiendo</string>
+  <string name="share_search">Buscar</string>
 </resources>

+ 8 - 2
res/values-es/strings.xml

@@ -79,6 +79,7 @@
   <string name="filedetails_created">Creado:</string>
   <string name="filedetails_modified">Modificado:</string>
   <string name="filedetails_download">Descargar</string>
+  <string name="filedetails_sync_file">Sincronizar</string>
   <string name="filedetails_renamed_in_upload_msg">El fichero fue renombrado como %1$s durante la subida</string>
   <string name="list_layout">Diseño de lista</string>
   <string name="action_share_file">Compartir con enlace</string>
@@ -86,6 +87,7 @@
   <string name="common_yes">Sí</string>
   <string name="common_no">No</string>
   <string name="common_ok">Aceptar</string>
+  <string name="common_cancel_sync">Cancelar sincronización</string>
   <string name="common_cancel">Cancelar</string>
   <string name="common_save_exit">Guardar &amp; Salir</string>
   <string name="common_error">Error</string>
@@ -313,10 +315,11 @@
   <string name="prefs_category_instant_uploading">Subidas instantáneas</string>
   <string name="prefs_category_security">Seguridad</string>
   <string name="prefs_instant_video_upload_path_title">Guardar videos subidos en la carpeta:</string>
+  <string name="sync_folder_failed_content">La sincronización de la carpeta %1$s no se pudo completar</string>
   <string name="shared_subject_header">compartido</string>
   <string name="with_you_subject_header">con usted</string>
-  <string name="subject_token">%1$s compartió \"%2$s\" conmigo</string>
-  <string name="saml_subject_token">\"%1$s\" ha sido compartido con usted.</string>
+  <string name="subject_user_shared_with_you">%1$s compartió \"%2$s\" conmigo</string>
+  <string name="subject_shared_with_you">\"%1$s\" ha sido compartido con usted.</string>
   <string name="auth_refresh_button">Refrescar la conexión</string>
   <string name="auth_host_address">Dirección del servidor</string>
   <string name="common_error_out_memory">No hay suficiente memoria</string>
@@ -329,4 +332,7 @@
   <string name="file_list__footer__files">%1$d archivos</string>
   <string name="file_list__footer__files_and_folder">%1$d archivos, 1 carpeta</string>
   <string name="file_list__footer__files_and_folders">%1$d archivos, %2$d carpetas</string>
+  <string name="share_dialog_title">Compartiendo</string>
+  <string name="share_add_user_or_group">Añadir usuario o grupo</string>
+  <string name="share_search">Buscar</string>
 </resources>

+ 0 - 2
res/values-et-rEE/strings.xml

@@ -318,8 +318,6 @@ Allpool on loend kohalikest failidest ning serveris asuvatest failidest %5$s, mi
   <string name="prefs_instant_video_upload_path_title">Video üleslaadimise asukoht</string>
   <string name="shared_subject_header">jagatud</string>
   <string name="with_you_subject_header">sinuga</string>
-  <string name="subject_token">%1$s jagas sinuga \"%2$s\"</string>
-  <string name="saml_subject_token">\"%1$s\" on sinuga jagatud</string>
   <string name="auth_refresh_button">Värskenda ühendust</string>
   <string name="auth_host_address">Serveri aadress</string>
   <string name="common_error_out_memory">Mälu pole piisavalt</string>

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

@@ -276,4 +276,6 @@ Mesedez, baimendu berriz</string>
   <string name="prefs_category_security">Segurtasuna</string>
   <string name="prefs_instant_video_upload_path_title">Bideo Igoera Bidea</string>
   <string name="auth_host_address">Zerbitzariaren helbidea</string>
+  <string name="share_dialog_title">Partekatzea</string>
+  <string name="share_search">Bilatu</string>
 </resources>

+ 4 - 2
res/values-fa/strings.xml

@@ -281,8 +281,8 @@
   <string name="prefs_instant_video_upload_path_title">مسیر آپلود ویدئو</string>
   <string name="shared_subject_header">به اشتراک گذاشته شد</string>
   <string name="with_you_subject_header">با تو</string>
-  <string name="subject_token">\"%2$s\" توسط %1$s با شما به اشتراک گذاشته شد</string>
-  <string name="saml_subject_token">\"%1$s\" با شما به اشتراک گذاشته شد</string>
+  <string name="subject_user_shared_with_you">\"%2$s\" توسط %1$s با شما به اشتراک گذاشته شد</string>
+  <string name="subject_shared_with_you">\"%1$s\" با شما به اشتراک گذاشته شد</string>
   <string name="auth_refresh_button">بروزرسانی ارتباط</string>
   <string name="auth_host_address">آدرس سرور</string>
   <string name="common_error_out_memory">حافظه کافی وجود ندارد</string>
@@ -295,4 +295,6 @@
   <string name="file_list__footer__files">%1$d  فایل</string>
   <string name="file_list__footer__files_and_folder">%1$d فایل، 1 پوشه</string>
   <string name="file_list__footer__files_and_folders">%1$d فایل, %2$d پوشه</string>
+  <string name="share_dialog_title">اشتراک گذاری</string>
+  <string name="share_search">جست‌و‌جو</string>
 </resources>

+ 0 - 2
res/values-fi-rFI/strings.xml

@@ -298,8 +298,6 @@
   <string name="sync_folder_failed_content">Kansion %1$s synkronointia ei voitu suorittaa kokonaan</string>
   <string name="shared_subject_header">jaettu</string>
   <string name="with_you_subject_header">kanssasi</string>
-  <string name="subject_token">%1$s jakoi kohteen \"%2$s\" kanssasi</string>
-  <string name="saml_subject_token">\"%1$s\" on jaettu kanssasi</string>
   <string name="auth_refresh_button">Päivitä yhteys</string>
   <string name="auth_host_address">Palvelimen osoite</string>
   <string name="common_error_out_memory">Muistia ei ole riittävästi</string>

+ 8 - 3
res/values-fr/strings.xml

@@ -74,7 +74,7 @@ Téléchargez-le ici : %2$s</string>
   <string name="file_list_loading">Chargement...</string>
   <string name="file_list_no_app_for_file_type">Aucune app trouvée pour ce type de fichier !</string>
   <string name="local_file_list_empty">Aucun fichier n\'est présent dans ce dossier.</string>
-  <string name="filedetails_select_file">Appuyez sur un fichier pour afficher des informations supplémentaires</string>
+  <string name="filedetails_select_file">Sélectionnez un fichier pour afficher des informations supplémentaires</string>
   <string name="filedetails_size">Taille :</string>
   <string name="filedetails_type">Type :</string>
   <string name="filedetails_created">Créé le :</string>
@@ -322,8 +322,8 @@ Ci-dessous la liste des fichiers locaux, et les fichiers distants dans %5$s auxq
   <string name="sync_folder_failed_content">La synchronisation du dossier %1$s n\'a pas pu être terminée</string>
   <string name="shared_subject_header">a partagé</string>
   <string name="with_you_subject_header">avec vous</string>
-  <string name="subject_token">%1$s a partagé \"%2$s\" avec vous</string>
-  <string name="saml_subject_token">\"%1$s\" a été partagé avec vous</string>
+  <string name="subject_user_shared_with_you">%1$s a partagé \"%2$s\" avec vous</string>
+  <string name="subject_shared_with_you">\"%1$s\" a été partagé avec vous</string>
   <string name="auth_refresh_button">Actualiser la connexion</string>
   <string name="auth_host_address">Adresse du serveur</string>
   <string name="common_error_out_memory">Mémoire insuffisante</string>
@@ -336,4 +336,9 @@ Ci-dessous la liste des fichiers locaux, et les fichiers distants dans %5$s auxq
   <string name="file_list__footer__files">%1$d fichiers</string>
   <string name="file_list__footer__files_and_folder">%1$d fichiers, 1 dossier</string>
   <string name="file_list__footer__files_and_folders">%1$d fichiers, %2$d dossiers</string>
+  <string name="share_dialog_title">Partage</string>
+  <string name="share_with_user_section_title">Partager avec des Utilisateurs et des Groupes</string>
+  <string name="share_no_users">Aucune donnée partagée avec des utilisateurs pour le moment</string>
+  <string name="share_add_user_or_group">Ajouter un Utilisateur ou un Groupe</string>
+  <string name="share_search">Rechercher</string>
 </resources>

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

@@ -310,8 +310,6 @@ Descárgueo de aquí: %2$s</string>
   <string name="prefs_instant_video_upload_path_title">Enviar a ruta do vídeo</string>
   <string name="shared_subject_header">compartido</string>
   <string name="with_you_subject_header">con vostede</string>
-  <string name="subject_token">%1$s compartiu «%2$s» con vostede</string>
-  <string name="saml_subject_token">«%1$s» foi compartido con vostede</string>
   <string name="auth_refresh_button">Actualizar a conexión</string>
   <string name="auth_host_address">Enderezo do servidor</string>
   <string name="common_error_out_memory">Non hai memoria abondo</string>

+ 6 - 0
res/values-hu-rHU/strings.xml

@@ -45,6 +45,7 @@
   <string name="prefs_recommend">Ajánlja egy barátjának</string>
   <string name="prefs_feedback">Visszajelzés</string>
   <string name="prefs_imprint">Impresszum</string>
+  <string name="prefs_remember_last_share_location">Emlékezzen a megosztás helyére</string>
   <string name="recommend_subject">Próbálja ki %1$s-t az okostelefonján!</string>
   <string name="auth_check_server">Szerver állapot ellenörzés</string>
   <string name="auth_host_url">Kiszolgáló címe https://...</string>
@@ -74,12 +75,15 @@
   <string name="filedetails_created">Készült:</string>
   <string name="filedetails_modified">Módosítva:</string>
   <string name="filedetails_download">Letöltés</string>
+  <string name="filedetails_sync_file">Szinkronizálás</string>
   <string name="filedetails_renamed_in_upload_msg">A feltöltés során az állmányt erre neveztük át: %1$s</string>
+  <string name="list_layout">Lista Elrendezés</string>
   <string name="action_share_file">Megosztás hivatkozással</string>
   <string name="action_unshare_file">Megosztás visszavonása</string>
   <string name="common_yes">Igen</string>
   <string name="common_no">Nem</string>
   <string name="common_ok">OK</string>
+  <string name="common_cancel_sync">Szinkronizálás megállítása</string>
   <string name="common_cancel">Mégsem</string>
   <string name="common_save_exit">Mentés &amp; Kilépés</string>
   <string name="common_error">Hiba</string>
@@ -146,6 +150,7 @@
   <string name="auth_no_net_conn_title">Nincs hálózati kapcsolat</string>
   <string name="auth_nossl_plain_ok_title">Nem érhető el biztonságos kapcsolat.</string>
   <string name="auth_connection_established">A kapcsolat létrejött</string>
+  <string name="auth_testing_connection">Kapcsolat ellenőrzése</string>
   <string name="auth_not_configured_title">Hibás a kiszolgáló beállítása</string>
   <string name="auth_account_not_new">Egy bejelentkezési beállítás már létezik ugyanehhez a kiszolgálóhoz és felhasználóhoz</string>
   <string name="auth_account_not_the_same">A megadott felhasználó nem azonos ezzel a belépési jogosultsággal</string>
@@ -233,6 +238,7 @@
   <string name="preview_image_description">Előnézeti kép</string>
   <string name="preview_image_error_unknown_format">Ez a kép nem jeleníthető meg</string>
   <string name="error__upload__local_file_not_copied">%1$s nem lehet másolni a %2$s helyi könyvtárba</string>
+  <string name="prefs_instant_upload_path_title">Feltöltési Elérési Út</string>
   <string name="share_link_file_error">Hiba lépett fel a mappa megosztásakor</string>
   <string name="unshare_link_file_error">Hiba lépett fel a mappa megosztásának visszavonásakor</string>
   <string name="share_link_password_title">Jelszó beírása</string>

+ 7 - 2
res/values-id/strings.xml

@@ -315,8 +315,8 @@
   <string name="prefs_instant_video_upload_path_title">Unggah Lokasi Video</string>
   <string name="shared_subject_header">dibagikan</string>
   <string name="with_you_subject_header">kepada Anda</string>
-  <string name="subject_token">%1$s dibagikan \"%2$s\" kepada Anda</string>
-  <string name="saml_subject_token">\"%1$s\" telah membagikan dengan Anda</string>
+  <string name="subject_user_shared_with_you">%1$s dibagikan \"%2$s\" kepada Anda</string>
+  <string name="subject_shared_with_you">\"%1$s\" telah membagikan dengan Anda</string>
   <string name="auth_refresh_button">Menyegarkan sambungan</string>
   <string name="auth_host_address">Alamat server</string>
   <string name="common_error_out_memory">Memori tidak cukup</string>
@@ -329,4 +329,9 @@
   <string name="file_list__footer__files">%1$d berkas</string>
   <string name="file_list__footer__files_and_folder">%1$d berkas, 1 folder</string>
   <string name="file_list__footer__files_and_folders">%1$d berkas, %2$d folder</string>
+  <string name="share_dialog_title">Berbagi</string>
+  <string name="share_with_user_section_title">Bagikan dengan Pengguna dan Grup</string>
+  <string name="share_no_users">Tidak ada data yang dibagikan dengan pengguna</string>
+  <string name="share_add_user_or_group">Tambah Pengguna atau Grup</string>
+  <string name="share_search">Cari</string>
 </resources>

+ 7 - 2
res/values-it/strings.xml

@@ -318,8 +318,8 @@
   <string name="sync_folder_failed_content">La sincronizzazione della cartella %1$s non può essere completata</string>
   <string name="shared_subject_header">condiviso</string>
   <string name="with_you_subject_header">con te</string>
-  <string name="subject_token">%1$s ha condiviso \"%2$s\" con te</string>
-  <string name="saml_subject_token">\"%1$s\" è stato condiviso con te</string>
+  <string name="subject_user_shared_with_you">%1$s ha condiviso \"%2$s\" con te</string>
+  <string name="subject_shared_with_you">\"%1$s\" è stato condiviso con te</string>
   <string name="auth_refresh_button">Aggiorna la connessione</string>
   <string name="auth_host_address">Indirizzo del server</string>
   <string name="common_error_out_memory">Memoria insufficiente</string>
@@ -332,4 +332,9 @@
   <string name="file_list__footer__files">%1$d file</string>
   <string name="file_list__footer__files_and_folder">%1$d file, 1 cartella</string>
   <string name="file_list__footer__files_and_folders">%1$d file, %2$d cartelle</string>
+  <string name="share_dialog_title">Condivisione</string>
+  <string name="share_with_user_section_title">Condividi con utenti e gruppi</string>
+  <string name="share_no_users">Ancora nessun dato condiviso con gli utenti </string>
+  <string name="share_add_user_or_group">Aggiungi utente o gruppo</string>
+  <string name="share_search">Cerca</string>
 </resources>

+ 0 - 2
res/values-ja-rJP/strings.xml

@@ -307,8 +307,6 @@
   <string name="prefs_instant_video_upload_path_title">動画のアップロードパス</string>
   <string name="shared_subject_header">共有中</string>
   <string name="with_you_subject_header">あなたと</string>
-  <string name="subject_token">%1$s は \"%2$s\" をあなたと共有しました</string>
-  <string name="saml_subject_token">\"%1$s\" があなたと共有しました</string>
   <string name="auth_refresh_button">再接続中</string>
   <string name="auth_host_address">サーバーアドレス</string>
   <string name="common_error_out_memory">十分なメモリがありません</string>

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

@@ -314,8 +314,6 @@
   <string name="prefs_instant_video_upload_path_title">동영상 업로드 경로</string>
   <string name="shared_subject_header">공유됨</string>
   <string name="with_you_subject_header">여러분과</string>
-  <string name="subject_token">%1$s 님이 \"%2$s\" 항목을 여러분과 공유하였습니다</string>
-  <string name="saml_subject_token">\"%1$s\"을(를) 여러분과 공유하였습니다</string>
   <string name="auth_refresh_button">연결 새로 고침</string>
   <string name="auth_host_address">서버 주소</string>
   <string name="common_error_out_memory">메모리 부족</string>

+ 4 - 2
res/values-lt-rLT/strings.xml

@@ -79,6 +79,7 @@
   <string name="filedetails_created">Sukurta:</string>
   <string name="filedetails_modified">Modifikuota:</string>
   <string name="filedetails_download">Atsisiųsti</string>
+  <string name="filedetails_sync_file">Sinchronizuojama</string>
   <string name="filedetails_renamed_in_upload_msg">Įkėlimo metu failas buvo pervadintas į %1$s</string>
   <string name="list_layout">Sąrašo išdėstymas</string>
   <string name="action_share_file">Dalintis nuoroda</string>
@@ -86,6 +87,7 @@
   <string name="common_yes">Taip</string>
   <string name="common_no">Ne</string>
   <string name="common_ok">Gerai</string>
+  <string name="common_cancel_sync">Atšaukti sinchronizavimą</string>
   <string name="common_cancel">Atšaukti</string>
   <string name="common_save_exit">Išsaugoti ir Išeiti</string>
   <string name="common_error">Klaida</string>
@@ -123,6 +125,7 @@
   <string name="sync_fail_in_favourites_content">Nepavyko sinchronizuoti %1$d failų turinio (%2$d konfliktų)</string>
   <string name="sync_foreign_files_forgotten_ticker">Keli vietiniai failai buvo užmiršti</string>
   <string name="sync_foreign_files_forgotten_content">%1$d failai iš %2$s aplanko negali būti nukopijuoti</string>
+  <string name="sync_foreign_files_forgotten_explanation">Iki 1.3.16 versijos, iš šio įrenginio įkelti failai nukopijuoti į vietinį %1$s aplanką, siekiant išvengti duomenų praradimo kai vienas failas sinchronizuojamas su keletu įrenginių.\n\nTodėl visi failai įkelti su ankstesne versija nukopijuoti į %2$s aplanką. Dėja kopijavimas nepavuko dėl klaidos sinchronizuojant paskyrą. Galita palikti failus ir pašalinti ryšį su %3$s, arba perkelti failą(us) į %1$s aplanką ir palikti ryšį su %4$s.\n\nŽemiau pateikti vietiniai failai ir aplankas(ai), bei nutolę failai susieti per  %5$s.</string>
   <string name="sync_current_folder_was_removed">Aplankas %1$s nebeegzistuoja</string>
   <string name="foreign_files_move">Perkelti visus</string>
   <string name="foreign_files_success">Visi failai buvo perkelti</string>
@@ -310,10 +313,9 @@
   <string name="prefs_category_instant_uploading">Momentinis įkėlimas</string>
   <string name="prefs_category_security">Saugumas</string>
   <string name="prefs_instant_video_upload_path_title">Vaizdo įrašų įkėlimo kelias</string>
+  <string name="sync_folder_failed_content">%1$s sinchronizavimas negali būti užbaigtas.</string>
   <string name="shared_subject_header">Dalinamasi</string>
   <string name="with_you_subject_header">su jumis</string>
-  <string name="subject_token">%1$s dalinamasi \"%2$s\" su jumis</string>
-  <string name="saml_subject_token">\"%1$s\" dalinamasi su jumis</string>
   <string name="auth_refresh_button">Atnaujinti sujungimą</string>
   <string name="auth_host_address">Serverio adresas</string>
   <string name="common_error_out_memory">Nepakanka atminties</string>

+ 1 - 0
res/values-ms-rMY/strings.xml

@@ -60,4 +60,5 @@
   <string name="empty"></string>
   <string name="prefs_category_accounts">Akaun</string>
   <string name="auth_host_address">Alamat pelayan</string>
+  <string name="share_search">Cari</string>
 </resources>

+ 7 - 2
res/values-nb-rNO/strings.xml

@@ -315,8 +315,8 @@
   <string name="prefs_instant_video_upload_path_title">Sti til video-opplasting</string>
   <string name="shared_subject_header">delte</string>
   <string name="with_you_subject_header">med deg</string>
-  <string name="subject_token">%1$s delte \"%2$s\" med deg</string>
-  <string name="saml_subject_token">\"%1$s\" er blitt delt med deg</string>
+  <string name="subject_user_shared_with_you">%1$s delte \"%2$s\" med deg</string>
+  <string name="subject_shared_with_you">\"%1$s\" er blitt delt med deg</string>
   <string name="auth_refresh_button">Oppfrisk forbindelse</string>
   <string name="auth_host_address">Server-adresse</string>
   <string name="common_error_out_memory">Ikke nok minne</string>
@@ -329,4 +329,9 @@
   <string name="file_list__footer__files">%1$d filer</string>
   <string name="file_list__footer__files_and_folder">%1$d filer, 1 mappe</string>
   <string name="file_list__footer__files_and_folders">%1$d filer, %2$d mapper</string>
+  <string name="share_dialog_title">Deling</string>
+  <string name="share_with_user_section_title">Del med brukere og grupper</string>
+  <string name="share_no_users">Ingen data delt med brukere ennå</string>
+  <string name="share_add_user_or_group">Legg til bruker eller gruppe</string>
+  <string name="share_search">Søk</string>
 </resources>

+ 8 - 3
res/values-nl/strings.xml

@@ -302,7 +302,7 @@ Hieronder staan de lokale bestanden en de externe bestanden in %5$s waar ze naar
   <string name="log_progress_dialog_text">Laden data...</string>
   <string name="saml_authentication_required_text">Authenticatie vereist</string>
   <string name="saml_authentication_wrong_pass">Onjuist wachtwoord</string>
-  <string name="actionbar_move">verplaatsen</string>
+  <string name="actionbar_move">Verplaatsen</string>
   <string name="file_list_empty_moving">Niets hier. U kunt een map toevoegen!</string>
   <string name="folder_picker_choose_button_text">Kies</string>
   <string name="move_file_not_found">Kan niet verplaatsen. Ga na of het bestand wel bestaat</string>
@@ -321,8 +321,8 @@ Hieronder staan de lokale bestanden en de externe bestanden in %5$s waar ze naar
   <string name="sync_folder_failed_content">Synchronisatie van map %1$s kon niet worden voltooid</string>
   <string name="shared_subject_header">gedeeld</string>
   <string name="with_you_subject_header">met u</string>
-  <string name="subject_token">%1$s deelde \"%2$s\" met u</string>
-  <string name="saml_subject_token">\"%1$s\" is gedeeld met u</string>
+  <string name="subject_user_shared_with_you">%1$s deelde \"%2$s\" met u</string>
+  <string name="subject_shared_with_you">\"%1$s\" is gedeeld met u</string>
   <string name="auth_refresh_button">Verversen verbinding</string>
   <string name="auth_host_address">Serveradres</string>
   <string name="common_error_out_memory">Niet voldoende geheugen</string>
@@ -335,4 +335,9 @@ Hieronder staan de lokale bestanden en de externe bestanden in %5$s waar ze naar
   <string name="file_list__footer__files">%1$d bestanden</string>
   <string name="file_list__footer__files_and_folder">%1$d bestanden, 1 map</string>
   <string name="file_list__footer__files_and_folders">%1$d bestanden, %2$d mappen</string>
+  <string name="share_dialog_title">Delen</string>
+  <string name="share_with_user_section_title">Delen met gebruikers en groepen</string>
+  <string name="share_no_users">Nog geen gegevens met gebruikers gedeeld</string>
+  <string name="share_add_user_or_group">Toevoegen gebruiker of groep</string>
+  <string name="share_search">Zoeken</string>
 </resources>

+ 2 - 0
res/values-nn-rNO/strings.xml

@@ -126,4 +126,6 @@
   <string name="folder_picker_choose_button_text">Vel</string>
   <string name="prefs_category_security">Tryggleik</string>
   <string name="auth_host_address">Tenaradresse</string>
+  <string name="share_dialog_title">Deling</string>
+  <string name="share_search">Søk</string>
 </resources>

+ 10 - 2
res/values-oc/strings.xml

@@ -80,6 +80,7 @@ Telecargatz-lo aicí : %2$s</string>
   <string name="filedetails_created">Creat lo :</string>
   <string name="filedetails_modified">Modificat lo :</string>
   <string name="filedetails_download">Telecargar</string>
+  <string name="filedetails_sync_file">Sincronizar</string>
   <string name="filedetails_renamed_in_upload_msg">Lo fichièr es estat renomenat en %s pendent lo mandadís</string>
   <string name="list_layout">Afichatge en lista</string>
   <string name="action_share_file">Partejar lo ligam</string>
@@ -87,6 +88,7 @@ Telecargatz-lo aicí : %2$s</string>
   <string name="common_yes">Òc</string>
   <string name="common_no">Non</string>
   <string name="common_ok">D\'acòrdi</string>
+  <string name="common_cancel_sync">Anullar la sincronizacion</string>
   <string name="common_cancel">Anullar</string>
   <string name="common_save_exit">Salvar &amp; Quitar</string>
   <string name="common_error">Error</string>
@@ -317,10 +319,11 @@ En rason d\'aquesta modificacion, totes los fichièrs mandats amb de versions an
   <string name="prefs_category_instant_uploading">Mandadís immediat</string>
   <string name="prefs_category_security">Seguretat</string>
   <string name="prefs_instant_video_upload_path_title">Repertòri de mandadís de las vidèos</string>
+  <string name="sync_folder_failed_content">La sincronizacion del dorsièr %1$s a pas pogut èsser acabad</string>
   <string name="shared_subject_header">a partejat</string>
   <string name="with_you_subject_header">amb vos</string>
-  <string name="subject_token">%1$s a partejat \"%2$s\" amb vos</string>
-  <string name="saml_subject_token">\"%1$s\" es estat partejat amb vos</string>
+  <string name="subject_user_shared_with_you">%1$s a partejat \"%2$s\" amb vos</string>
+  <string name="subject_shared_with_you">\"%1$s\" es estat partejat amb vos</string>
   <string name="auth_refresh_button">Actualizar la connexion</string>
   <string name="auth_host_address">Adreça del servidor</string>
   <string name="common_error_out_memory">Memòria insufisenta</string>
@@ -333,4 +336,9 @@ En rason d\'aquesta modificacion, totes los fichièrs mandats amb de versions an
   <string name="file_list__footer__files">%1$d fichièrs</string>
   <string name="file_list__footer__files_and_folder">%1$d fichièrs, 1 dorsièr</string>
   <string name="file_list__footer__files_and_folders">%1$d fichièrs, %2$d dorsièrs</string>
+  <string name="share_dialog_title">Partiment</string>
+  <string name="share_with_user_section_title">Partejar amb d\'utilizaires e de gropes</string>
+  <string name="share_no_users">Cap de donada es pas partejada amb d\'utilizaires pel moment</string>
+  <string name="share_add_user_or_group">Apondre un utilizaire o un grop</string>
+  <string name="share_search">Recercar</string>
 </resources>

+ 7 - 2
res/values-pt-rBR/strings.xml

@@ -318,8 +318,8 @@
   <string name="sync_folder_failed_content">A sincronização da pasta %1$s não pode ser finalizada</string>
   <string name="shared_subject_header">compartilhado</string>
   <string name="with_you_subject_header">com você</string>
-  <string name="subject_token">%1$s compartilhado \"%2$s\" com você</string>
-  <string name="saml_subject_token">\"%1$s\" foi compartilhado com você</string>
+  <string name="subject_user_shared_with_you">%1$s compartilhado \"%2$s\" com você</string>
+  <string name="subject_shared_with_you">\"%1$s\" foi compartilhado com você</string>
   <string name="auth_refresh_button">Reinicializar conexão</string>
   <string name="auth_host_address">Endereço do servidor</string>
   <string name="common_error_out_memory">Não há memoria suficiente</string>
@@ -332,4 +332,9 @@
   <string name="file_list__footer__files">%1$d arquivos</string>
   <string name="file_list__footer__files_and_folder">%1$d arquivos, 1 pasta</string>
   <string name="file_list__footer__files_and_folders">%1$d arquivos, %2$d pastas</string>
+  <string name="share_dialog_title">Compartilhamento</string>
+  <string name="share_with_user_section_title">Compartilhar com Usuários ou Grupos</string>
+  <string name="share_no_users">Nenhum dado compartilhados comusuários ainda</string>
+  <string name="share_add_user_or_group">Adicionar Usuário ou Grupo</string>
+  <string name="share_search">Perquisar</string>
 </resources>

+ 0 - 2
res/values-pt-rPT/strings.xml

@@ -316,8 +316,6 @@
   <string name="sync_folder_failed_content">Não foi possível completar a sincronização da pasta %1$s</string>
   <string name="shared_subject_header">partilhado</string>
   <string name="with_you_subject_header">consigo</string>
-  <string name="subject_token">%1$s partilhou \"%2$s\" consigo</string>
-  <string name="saml_subject_token">\"%1$s\" foi partilhado consigo</string>
   <string name="auth_refresh_button">Recarregar ligação</string>
   <string name="auth_host_address">Endereço do servidor</string>
   <string name="common_error_out_memory">Falta de memória</string>

+ 4 - 2
res/values-ro/strings.xml

@@ -308,8 +308,8 @@
   <string name="prefs_instant_video_upload_path_title">Calea de încărcare Video</string>
   <string name="shared_subject_header">partajat</string>
   <string name="with_you_subject_header">cu tine</string>
-  <string name="subject_token">%1$s a partajat fișierul \"%2$s\" cu tine</string>
-  <string name="saml_subject_token">„%1$s” a fost partajat cu dumneavoastră</string>
+  <string name="subject_user_shared_with_you">%1$s a partajat fișierul \"%2$s\" cu tine</string>
+  <string name="subject_shared_with_you">„%1$s” a fost partajat cu dumneavoastră</string>
   <string name="auth_refresh_button">Reîmprospătează conexiunea</string>
   <string name="auth_host_address">Adresa server-ului</string>
   <string name="common_error_out_memory">Memorie insuficientă </string>
@@ -322,4 +322,6 @@
   <string name="file_list__footer__files">%1$d fișiere</string>
   <string name="file_list__footer__files_and_folder">%1$d fișiere, 1 folder</string>
   <string name="file_list__footer__files_and_folders">%1$d fișiere, %2$d foldere</string>
+  <string name="share_dialog_title">Partajare</string>
+  <string name="share_search">Căutare</string>
 </resources>

+ 7 - 2
res/values-ru/strings.xml

@@ -316,8 +316,8 @@
   <string name="prefs_instant_video_upload_path_title">Путь для загрузки Видео</string>
   <string name="shared_subject_header">поделился</string>
   <string name="with_you_subject_header">с вами</string>
-  <string name="subject_token">%1$s предоставил вам доступ к \"%2$s\"</string>
-  <string name="saml_subject_token">Вам предоставлен доступ к \"%1$s\"</string>
+  <string name="subject_user_shared_with_you">%1$s предоставил вам доступ к \"%2$s\"</string>
+  <string name="subject_shared_with_you">Вам предоставлен доступ к \"%1$s\"</string>
   <string name="auth_refresh_button">Обновить соединение</string>
   <string name="auth_host_address">Адрес сервера</string>
   <string name="common_error_out_memory">Недостаточно памяти</string>
@@ -330,4 +330,9 @@
   <string name="file_list__footer__files">%1$d файлов</string>
   <string name="file_list__footer__files_and_folder">%1$d файлов, 1 каталог</string>
   <string name="file_list__footer__files_and_folders">%1$d файлов, %2$d каталогов</string>
+  <string name="share_dialog_title">Общий доступ</string>
+  <string name="share_with_user_section_title">Поделиться с пользователями или группами</string>
+  <string name="share_no_users">Нет данных используемых совместно с другими пользователями</string>
+  <string name="share_add_user_or_group">Добавить пользователя или группу</string>
+  <string name="share_search">Найти</string>
 </resources>

+ 2 - 0
res/values-si-rLK/strings.xml

@@ -78,4 +78,6 @@
   <string name="prefs_category_accounts">ගිණුම්</string>
   <string name="folder_picker_choose_button_text">තෝරන්න</string>
   <string name="auth_host_address">සේවාදායකයේ ලිපිනය</string>
+  <string name="share_dialog_title">හුවමාරු කිරීම</string>
+  <string name="share_search">සොයන්න</string>
 </resources>

+ 0 - 2
res/values-sk-rSK/strings.xml

@@ -314,8 +314,6 @@
   <string name="prefs_instant_video_upload_path_title">Cesta pre nahrávanie videí</string>
   <string name="shared_subject_header">zdieľané</string>
   <string name="with_you_subject_header">s vami</string>
-  <string name="subject_token">%1$s vám zdieľal \"%2$s\"</string>
-  <string name="saml_subject_token">\"%1$s\" bol s vami nazdieľaný</string>
   <string name="auth_refresh_button">Obnoviť pripojenie</string>
   <string name="auth_host_address">Adresa servera</string>
   <string name="common_error_out_memory">Nedostatok pamäte</string>

+ 4 - 2
res/values-sl/strings.xml

@@ -310,8 +310,8 @@
   <string name="prefs_instant_video_upload_path_title">Pot videa za pošiljanje</string>
   <string name="shared_subject_header">v souporabi</string>
   <string name="with_you_subject_header">z vami</string>
-  <string name="subject_token">Uporabnik %1$s je omogočil souporabo \"%2$s\" z vami</string>
-  <string name="saml_subject_token">\"%1$s\" je oddan v souporabo z vami</string>
+  <string name="subject_user_shared_with_you">Uporabnik %1$s je omogočil souporabo \"%2$s\" z vami</string>
+  <string name="subject_shared_with_you">\"%1$s\" je oddan v souporabo z vami</string>
   <string name="auth_refresh_button">Osveži povezavo</string>
   <string name="auth_host_address">Naslov strežnika</string>
   <string name="common_error_out_memory">Ni dovolj pomnilnika</string>
@@ -324,4 +324,6 @@
   <string name="file_list__footer__files">%1$d datotek</string>
   <string name="file_list__footer__files_and_folder">%1$d datotek, 1 mapa</string>
   <string name="file_list__footer__files_and_folders">%1$d datotek, %2$d map</string>
+  <string name="share_dialog_title">Souporaba</string>
+  <string name="share_search">Poišči</string>
 </resources>

+ 7 - 2
res/values-sq/strings.xml

@@ -314,8 +314,8 @@
   <string name="sync_folder_failed_content">Njëkohësimi i dosjes %1$s s’u plotësua dot</string>
   <string name="shared_subject_header">ndarë</string>
   <string name="with_you_subject_header">me ju</string>
-  <string name="subject_token">%1$s ndau me ju \"%2$s\"</string>
-  <string name="saml_subject_token">\"%1$s\" është ndarë me ju</string>
+  <string name="subject_user_shared_with_you">%1$s ndau me ju \"%2$s\"</string>
+  <string name="subject_shared_with_you">\"%1$s\" është ndarë me ju</string>
   <string name="auth_refresh_button">Rifreskoni lidhjen</string>
   <string name="auth_host_address">Adresë shërbyesi</string>
   <string name="common_error_out_memory">Pa kujtesë të mjaftueshme</string>
@@ -328,4 +328,9 @@
   <string name="file_list__footer__files">%1$d kartelë</string>
   <string name="file_list__footer__files_and_folder">%1$d kartela, 1 dosje</string>
   <string name="file_list__footer__files_and_folders">%1$d kartela, %2$d dosje</string>
+  <string name="share_dialog_title">Ndarje me të tjerët</string>
+  <string name="share_with_user_section_title">Ndani me Përdorues dhe Grupe</string>
+  <string name="share_no_users">Ende pa të dhëna të ndara me përdorues</string>
+  <string name="share_add_user_or_group">Shtoni Përdorues ose Grup</string>
+  <string name="share_search">Kërko</string>
 </resources>

+ 1 - 0
res/values-sr-rSP/strings.xml

@@ -72,4 +72,5 @@
   <string name="empty"></string>
   <string name="prefs_category_accounts">Nalozi</string>
   <string name="folder_picker_choose_button_text">Izaberi</string>
+  <string name="share_search">Traži</string>
 </resources>

+ 3 - 1
res/values-sr/strings.xml

@@ -304,7 +304,7 @@
   <string name="prefs_instant_video_upload_path_title">Путања отпремања видеа</string>
   <string name="shared_subject_header">дељено</string>
   <string name="with_you_subject_header">са вама</string>
-  <string name="subject_token">%1$s подели „%2$s“ са вама</string>
+  <string name="subject_user_shared_with_you">%1$s подели „%2$s“ са вама</string>
   <string name="auth_refresh_button">Освежи везу</string>
   <string name="auth_host_address">Адреса сервера</string>
   <string name="common_error_out_memory">Нема довољно меморије</string>
@@ -317,4 +317,6 @@
   <string name="file_list__footer__files">%1$d фајлова</string>
   <string name="file_list__footer__files_and_folder">%1$d фајлова, 1 фасцикла</string>
   <string name="file_list__footer__files_and_folders">%1$d фајлова, %2$d фасцикли</string>
+  <string name="share_dialog_title">Дељење</string>
+  <string name="share_search">Тражи</string>
 </resources>

+ 3 - 2
res/values-th-rTH/strings.xml

@@ -79,6 +79,7 @@
   <string name="filedetails_created">สร้างเมื่อ:</string>
   <string name="filedetails_modified">แก้ไขเมื่อ:</string>
   <string name="filedetails_download">ดาวน์โหลด</string>
+  <string name="filedetails_sync_file">ประสานข้อมูล</string>
   <string name="filedetails_renamed_in_upload_msg">ไฟล์ได้ถูกเปลี่ยนชื่อเป็น %1$s ในระหว่างการอัพโหลด</string>
   <string name="list_layout">เค้าโครงรายการ</string>
   <string name="action_share_file">แชร์ลิงค์</string>
@@ -86,6 +87,7 @@
   <string name="common_yes">ตกลง</string>
   <string name="common_no">ไม่ตกลง</string>
   <string name="common_ok">ตกลง</string>
+  <string name="common_cancel_sync">ยกเลิกการประสานข้อมูล</string>
   <string name="common_cancel">ยกเลิก</string>
   <string name="common_save_exit">บันทึก &amp; ออก</string>
   <string name="common_error">ข้อผิดพลาด</string>
@@ -311,10 +313,9 @@
   <string name="prefs_category_instant_uploading">อัพโหลดทันที</string>
   <string name="prefs_category_security">ความปลอดภัย</string>
   <string name="prefs_instant_video_upload_path_title">อัพโหลดเส้นทางวิดีโอ</string>
+  <string name="sync_folder_failed_content">ประสานข้อมูลโฟลเดอร์ %1$s ไม่สำเร็จ</string>
   <string name="shared_subject_header">ถูกแชร์</string>
   <string name="with_you_subject_header">กับคุณ</string>
-  <string name="subject_token">%1$s ได้แชร์ \"%2$s\" กับคุณ</string>
-  <string name="saml_subject_token">\"%1$s\" ได้ถูกแชร์กับคุณ</string>
   <string name="auth_refresh_button">ฟื้นฟูการเชื่อมต่อ</string>
   <string name="auth_host_address">ที่อยู่เซิร์ฟเวอร์</string>
   <string name="common_error_out_memory">หน่วยความจำไม่พอ</string>

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

@@ -314,8 +314,6 @@
   <string name="prefs_instant_video_upload_path_title">Video Yükleme Yolu</string>
   <string name="shared_subject_header">sizinle</string>
   <string name="with_you_subject_header">paylaştı</string>
-  <string name="subject_token">%1$s, sizinle \"%2$s\" paylaşımını yaptı</string>
-  <string name="saml_subject_token">\"%1$s\" sizinle paylaşıldı</string>
   <string name="auth_refresh_button">Bağlantıyı yenile</string>
   <string name="auth_host_address">Sunucu adresi</string>
   <string name="common_error_out_memory">Yeterli hafıza yok</string>

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

@@ -314,8 +314,6 @@
   <string name="prefs_instant_video_upload_path_title">Шлях завантаження відео</string>
   <string name="shared_subject_header">поширений</string>
   <string name="with_you_subject_header">з Вами</string>
-  <string name="subject_token">%1$s поділився \"%2$s\" з вами</string>
-  <string name="saml_subject_token">З Вами поділилися \"%1$s\"</string>
   <string name="auth_refresh_button">Оновити з\'єднання</string>
   <string name="auth_host_address">Ареса серверу</string>
   <string name="common_error_out_memory">Недостатньо пам\'яті</string>

+ 1 - 0
res/values-ur-rPK/strings.xml

@@ -26,4 +26,5 @@
   <string name="activity_chooser_send_file_title">بھجیں</string>
   <string name="empty"></string>
   <string name="folder_picker_choose_button_text">منتخب کریں</string>
+  <string name="share_search">تلاش</string>
 </resources>

+ 6 - 0
res/values-v21/styles.xml

@@ -19,4 +19,10 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android">
 	<style name="ProgressDialogTheme" parent="ownCloud.Dialog">
 	</style>
+    <style name="Theme.ownCloud.NoActionBar">
+        <item name="windowActionBar">false</item>
+        <item name="windowNoTitle">true</item>
+        <item name="android:windowDrawsSystemBarBackgrounds">true</item>
+        <item name="android:statusBarColor">@android:color/transparent</item>
+    </style>
 </resources>

+ 0 - 2
res/values-zh-rCN/strings.xml

@@ -314,8 +314,6 @@
   <string name="prefs_instant_video_upload_path_title">视频上传路径</string>
   <string name="shared_subject_header">已共享</string>
   <string name="with_you_subject_header">与你</string>
-  <string name="subject_token">%1$s和你分享了“%2$s”</string>
-  <string name="saml_subject_token">已与你分享“%1$s”</string>
   <string name="auth_refresh_button">刷新连接</string>
   <string name="auth_host_address">服务器地址</string>
   <string name="common_error_out_memory">内存不足</string>

+ 7 - 2
res/values-zh-rTW/strings.xml

@@ -309,8 +309,8 @@
   <string name="prefs_instant_video_upload_path_title">影片上傳路徑</string>
   <string name="shared_subject_header">以分享的</string>
   <string name="with_you_subject_header">與你</string>
-  <string name="subject_token">%1$s 分享了 \"%2$s\" 給您</string>
-  <string name="saml_subject_token">\"%1$s\" 已經與您分享</string>
+  <string name="subject_user_shared_with_you">%1$s 分享了 \"%2$s\" 給您</string>
+  <string name="subject_shared_with_you">\"%1$s\" 已經與您分享</string>
   <string name="auth_refresh_button">重新連線</string>
   <string name="auth_host_address">伺服器位址</string>
   <string name="common_error_out_memory">記憶體不足</string>
@@ -323,4 +323,9 @@
   <string name="file_list__footer__files">%1$d 個檔案</string>
   <string name="file_list__footer__files_and_folder">%1$d 個檔案, 1 個資料夾</string>
   <string name="file_list__footer__files_and_folders">%1$d 個檔案, %2$d 個資料夾</string>
+  <string name="share_dialog_title">分享</string>
+  <string name="share_with_user_section_title">與用戶或群組分享</string>
+  <string name="share_no_users">目前沒有任何您分享的內容</string>
+  <string name="share_add_user_or_group">新增使用者或是群組</string>
+  <string name="share_search">搜尋</string>
 </resources>

+ 18 - 2
res/values/strings.xml

@@ -87,6 +87,7 @@
     <string name="list_layout">List Layout</string>
     <string name="action_share_file">Share link</string>
     <string name="action_unshare_file">Unshare link</string>
+    <string name="action_share_with_users">Share with users</string>
     <string name="common_yes">Yes</string>
     <string name="common_no">No</string>
     <string name="common_ok">OK</string>
@@ -253,6 +254,9 @@
     <string name="ssl_validator_label_validity_to">To:</string>
     <string name="ssl_validator_label_signature">Signature:</string>
     <string name="ssl_validator_label_signature_algorithm">Algorithm:</string>
+    <string name="digest_algorithm_not_available">This digest algorithm is not available on your phone.</string>
+    <string name="ssl_validator_label_certificate_fingerprint">Fingerprint:</string>
+    <string name="certificate_load_problem">There is a problem loading the certificate.</string>
     <string name="ssl_validator_null_cert">The certificate could not be shown.</string>
     <string name="ssl_validator_no_info_about_error">- No information about the error</string>
 
@@ -347,8 +351,8 @@
 	<string name="shared_subject_header">shared</string>
 	<string name="with_you_subject_header">with you</string>
     
-	<string name="subject_token">%1$s shared \"%2$s\" with you</string>
-    <string name="saml_subject_token">\"%1$s\" has been shared with you</string>
+	<string name="subject_user_shared_with_you">%1$s shared \"%2$s\" with you</string>
+    <string name="subject_shared_with_you">\"%1$s\" has been shared with you</string>
 
     <string name="auth_refresh_button">Refresh connection</string>
     <string name="auth_host_address">Server address</string>
@@ -365,4 +369,16 @@
     <string name="file_list__footer__files_and_folder">%1$d files, 1 folder</string>
     <string name="file_list__footer__files_and_folders">%1$d files, %2$d folders</string>
 
+    <string name="share_dialog_title">Sharing</string>
+    <string name="share_with_user_section_title">Share with Users and Groups</string>
+    <string name="share_no_users">No data shared with users yet</string>
+    <string name="share_add_user_or_group">Add User or Group</string>
+    <string name="share_search">Search</string>
+
+    <string name="search_users_and_groups_hint">Search users and groups</string>
+    <string name="share_group_clarification">%1$s (group)</string>
+
+    <string name="share_sharee_unavailable">Sorry, your server version does not allow share with users within clients.
+        \nPlease contact your administrator</string>
+
 </resources>

+ 6 - 0
res/values/styles.xml

@@ -216,4 +216,10 @@
 		
 	<color name="setup_text_hint">#777777</color>
 	<color name="setup_text_typed">#000000</color>
+    <style name="Theme.ownCloud.NoActionBar">
+        <item name="windowActionBar">false</item>
+        <item name="windowNoTitle">true</item>
+    </style>
+    <style name="Theme.ownCloud.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar" />
+    <style name="Theme.ownCloud.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" />
 </resources>

+ 28 - 0
res/xml/users_and_groups_searchable.xml

@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ownCloud Android client application
+
+  @author David A. Velasco
+  Copyright (C) 2015 ownCloud Inc.
+
+  This program is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License version 2,
+  as published by the Free Software Foundation.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+-->
+
+<!-- Searchable configuration to search users & groups in an OC server -->
+<searchable xmlns:android="http://schemas.android.com/apk/res/android"
+    android:label="@string/app_name"
+    android:hint="@string/search_users_and_groups_hint"
+    android:searchSuggestAuthority="com.owncloud.android.providers.UsersAndGroupsSearchProvider"
+    android:searchSuggestIntentAction="com.owncloud.android.providers.UsersAndGroupsSearchProvider.action.SHARE_WITH"
+    android:searchSuggestThreshold="1" >
+</searchable>

+ 11 - 0
src/com/owncloud/android/authentication/AccountUtils.java

@@ -289,4 +289,15 @@ public class AccountUtils {
         return serverVersion;
     }
 
+    public static boolean hasSearchUsersSupport(Account account){
+        OwnCloudVersion serverVersion = null;
+        if (account != null) {
+            AccountManager accountMgr = AccountManager.get(MainApp.getAppContext());
+            String serverVersionStr = accountMgr.getUserData(account, Constants.KEY_OC_VERSION);
+            if (serverVersionStr != null) {
+                serverVersion = new OwnCloudVersion(serverVersionStr);
+            }
+        }
+        return (serverVersion != null ? serverVersion.isSearchUsersSupported() : false);
+    }
 }

+ 283 - 144
src/com/owncloud/android/datamodel/FileDataStorageManager.java

@@ -154,12 +154,12 @@ public class FileDataStorageManager {
 
 
     public Vector<OCFile> getFolderImages(OCFile folder/*, boolean onlyOnDevice*/) {
-        Vector<OCFile> ret = new Vector<OCFile>(); 
+        Vector<OCFile> ret = new Vector<OCFile>();
         if (folder != null) {
             // TODO better implementation, filtering in the access to database instead of here
             // TODO Enable when "On Device" is recovered ?
             Vector<OCFile> tmp = getFolderContent(folder/*, onlyOnDevice*/);
-            OCFile current = null; 
+            OCFile current = null;
             for (int i=0; i<tmp.size(); i++) {
                 current = tmp.get(i);
                 if (current.isImage()) {
@@ -174,9 +174,9 @@ public class FileDataStorageManager {
         boolean overriden = false;
         ContentValues cv = new ContentValues();
         cv.put(ProviderTableMeta.FILE_MODIFIED, file.getModificationTimestamp());
-        cv.put( 
-            ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA, 
-            file.getModificationTimestampAtLastSyncForData()
+        cv.put(
+                ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA,
+                file.getModificationTimestampAtLastSyncForData()
         );
         cv.put(ProviderTableMeta.FILE_CREATION, file.getCreationTimestamp());
         cv.put(ProviderTableMeta.FILE_CONTENT_LENGTH, file.getFileLength());
@@ -191,7 +191,8 @@ public class FileDataStorageManager {
         cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA, file.getLastSyncDateForData());
         cv.put(ProviderTableMeta.FILE_KEEP_IN_SYNC, file.isFavorite() ? 1 : 0);
         cv.put(ProviderTableMeta.FILE_ETAG, file.getEtag());
-        cv.put(ProviderTableMeta.FILE_SHARE_BY_LINK, file.isShareByLink() ? 1 : 0);
+        cv.put(ProviderTableMeta.FILE_SHARED_VIA_LINK, file.isSharedViaLink() ? 1 : 0);
+        cv.put(ProviderTableMeta.FILE_SHARED_WITH_SHAREE, file.isSharedWithSharee() ? 1 : 0);
         cv.put(ProviderTableMeta.FILE_PUBLIC_LINK, file.getPublicLink());
         cv.put(ProviderTableMeta.FILE_PERMISSIONS, file.getPermissions());
         cv.put(ProviderTableMeta.FILE_REMOTE_ID, file.getRemoteId());
@@ -200,7 +201,8 @@ public class FileDataStorageManager {
         cv.put(ProviderTableMeta.FILE_ETAG_IN_CONFLICT, file.getEtagInConflict());
 
         boolean sameRemotePath = fileExists(file.getRemotePath());
-        if (sameRemotePath ||                fileExists(file.getFileId())) {           // for renamed files; no more delete and create
+        if (sameRemotePath ||
+                fileExists(file.getFileId())) {  // for renamed files; no more delete and create
 
             OCFile oldFile;
             if (sameRemotePath) {
@@ -264,12 +266,12 @@ public class FileDataStorageManager {
      */
     public void saveFolder(
             OCFile folder, Collection<OCFile> updatedFiles, Collection<OCFile> filesToRemove
-        ) {
-        
-        Log_OC.d(TAG,  "Saving folder " + folder.getRemotePath() + " with " + updatedFiles.size() 
+    ) {
+
+        Log_OC.d(TAG,  "Saving folder " + folder.getRemotePath() + " with " + updatedFiles.size()
                 + " children and " + filesToRemove.size() + " files to remove");
 
-        ArrayList<ContentProviderOperation> operations = 
+        ArrayList<ContentProviderOperation> operations =
                 new ArrayList<ContentProviderOperation>(updatedFiles.size());
 
         // prepare operations to insert or update files to save in the given folder
@@ -277,8 +279,8 @@ public class FileDataStorageManager {
             ContentValues cv = new ContentValues();
             cv.put(ProviderTableMeta.FILE_MODIFIED, file.getModificationTimestamp());
             cv.put(
-                ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA, 
-                file.getModificationTimestampAtLastSyncForData()
+                    ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA,
+                    file.getModificationTimestampAtLastSyncForData()
             );
             cv.put(ProviderTableMeta.FILE_CREATION, file.getCreationTimestamp());
             cv.put(ProviderTableMeta.FILE_CONTENT_LENGTH, file.getFileLength());
@@ -295,7 +297,8 @@ public class FileDataStorageManager {
             cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA, file.getLastSyncDateForData());
             cv.put(ProviderTableMeta.FILE_KEEP_IN_SYNC, file.isFavorite() ? 1 : 0);
             cv.put(ProviderTableMeta.FILE_ETAG, file.getEtag());
-            cv.put(ProviderTableMeta.FILE_SHARE_BY_LINK, file.isShareByLink() ? 1 : 0);
+            cv.put(ProviderTableMeta.FILE_SHARED_VIA_LINK, file.isSharedViaLink() ? 1 : 0);
+            cv.put(ProviderTableMeta.FILE_SHARED_WITH_SHAREE, file.isSharedWithSharee() ? 1 : 0);
             cv.put(ProviderTableMeta.FILE_PUBLIC_LINK, file.getPublicLink());
             cv.put(ProviderTableMeta.FILE_PERMISSIONS, file.getPermissions());
             cv.put(ProviderTableMeta.FILE_REMOTE_ID, file.getRemoteId());
@@ -332,8 +335,8 @@ public class FileDataStorageManager {
                                     ProviderTableMeta.CONTENT_URI_DIR, file.getFileId()
                             )
                     ).withSelection(where, whereArgs).build());
-                    
-                    File localFolder = 
+
+                    File localFolder =
                             new File(FileStorageUtils.getDefaultSavePathFor(mAccount.name, file));
                     if (localFolder.exists()) {
                         removeLocalFolder(localFolder);
@@ -358,8 +361,8 @@ public class FileDataStorageManager {
         ContentValues cv = new ContentValues();
         cv.put(ProviderTableMeta.FILE_MODIFIED, folder.getModificationTimestamp());
         cv.put(
-            ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA, 
-            folder.getModificationTimestampAtLastSyncForData()
+                ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA,
+                folder.getModificationTimestampAtLastSyncForData()
         );
         cv.put(ProviderTableMeta.FILE_CREATION, folder.getCreationTimestamp());
         cv.put(ProviderTableMeta.FILE_CONTENT_LENGTH, 0);
@@ -372,7 +375,8 @@ public class FileDataStorageManager {
         cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA, folder.getLastSyncDateForData());
         cv.put(ProviderTableMeta.FILE_KEEP_IN_SYNC, folder.isFavorite() ? 1 : 0);
         cv.put(ProviderTableMeta.FILE_ETAG, folder.getEtag());
-        cv.put(ProviderTableMeta.FILE_SHARE_BY_LINK, folder.isShareByLink() ? 1 : 0);
+        cv.put(ProviderTableMeta.FILE_SHARED_VIA_LINK, folder.isSharedViaLink() ? 1 : 0);
+        cv.put(ProviderTableMeta.FILE_SHARED_WITH_SHAREE, folder.isSharedWithSharee() ? 1 : 0);
         cv.put(ProviderTableMeta.FILE_PUBLIC_LINK, folder.getPublicLink());
         cv.put(ProviderTableMeta.FILE_PERMISSIONS, folder.getPermissions());
         cv.put(ProviderTableMeta.FILE_REMOTE_ID, folder.getRemoteId());
@@ -433,9 +437,12 @@ public class FileDataStorageManager {
 
             } else {
                 if (removeDBData) {
-                    //Uri file_uri = Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_FILE, ""+file.getFileId());
-                    Uri file_uri = ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_FILE, file.getFileId());
-                    String where = ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?" + " AND " + ProviderTableMeta.FILE_PATH + "=?";
+                    //Uri file_uri = Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_FILE,
+                    // ""+file.getFileId());
+                    Uri file_uri = ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_FILE,
+                            file.getFileId());
+                    String where = ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?" + " AND " +
+                            ProviderTableMeta.FILE_PATH + "=?";
                     String[] whereArgs = new String[]{mAccount.name, file.getRemotePath()};
                     int deleted = 0;
                     if (getContentProviderClient() != null) {
@@ -484,7 +491,7 @@ public class FileDataStorageManager {
     private boolean removeFolderInDb(OCFile folder) {
         Uri folder_uri = Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_DIR, "" +
                 folder.getFileId());   // URI for recursive deletion
-        String where = ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?" + " AND " + 
+        String where = ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?" + " AND " +
                 ProviderTableMeta.FILE_PATH + "=?";
         String [] whereArgs = new String[]{mAccount.name, folder.getRemotePath()};
         int deleted = 0;
@@ -551,7 +558,7 @@ public class FileDataStorageManager {
         return success;
     }
 
-    
+
     /**
      * Updates database and file system for a file or folder that was moved to a different location.
      *
@@ -564,7 +571,8 @@ public class FileDataStorageManager {
 
             OCFile targetParent = getFileByPath(targetParentPath);
             if (targetParent == null) {
-                throw new IllegalStateException("Parent folder of the target path does not exist!!");
+                throw new IllegalStateException(
+                        "Parent folder of the target path does not exist!!");
             }
 
             /// 1. get all the descendants of the moved element in a single QUERY
@@ -621,12 +629,12 @@ public class FileDataStorageManager {
                         // update link to downloaded content - but local move is not done here!
                         String targetLocalPath = defaultSavePath + targetPath +
                                 child.getStoragePath().substring(lengthOfOldStoragePath);
-                        
+
                         cv.put(ProviderTableMeta.FILE_STORAGE_PATH, targetLocalPath);
-                        
+
                         originalPathsToTriggerMediaScan.add(child.getStoragePath());
                         newPathsToTriggerMediaScan.add(targetLocalPath);
-                        
+
                     }
                     if (child.getRemotePath().equals(file.getRemotePath())) {
                         cv.put(
@@ -657,7 +665,8 @@ public class FileDataStorageManager {
                 }
 
             } catch (Exception e) {
-                Log_OC.e(TAG, "Fail to update " + file.getFileId() + " and descendants in database", e);
+                Log_OC.e(TAG, "Fail to update " + file.getFileId() + " and descendants in database",
+                        e);
             }
 
             /// 4. move in local file system 
@@ -741,7 +750,7 @@ public class FileDataStorageManager {
         return ret;
     }
 
-    
+
     private Vector<OCFile> getFolderContent(long parentId/*, boolean onlyOnDevice*/) {
 
         Vector<OCFile> ret = new Vector<OCFile>();
@@ -771,7 +780,7 @@ public class FileDataStorageManager {
                 OCFile child = createFileInstance(c);
                 // TODO Enable when "On Device" is recovered ?
                 // if (child.isFolder() || !onlyOnDevice || onlyOnDevice && child.isDown()){
-                    ret.add(child);
+                ret.add(child);
                 // }
             } while (c.moveToNext());
         }
@@ -888,8 +897,10 @@ public class FileDataStorageManager {
             file.setFavorite(c.getInt(
                     c.getColumnIndex(ProviderTableMeta.FILE_KEEP_IN_SYNC)) == 1 ? true : false);
             file.setEtag(c.getString(c.getColumnIndex(ProviderTableMeta.FILE_ETAG)));
-            file.setShareByLink(c.getInt(
-                    c.getColumnIndex(ProviderTableMeta.FILE_SHARE_BY_LINK)) == 1 ? true : false);
+            file.setShareViaLink(c.getInt(
+                    c.getColumnIndex(ProviderTableMeta.FILE_SHARED_VIA_LINK)) == 1 ? true : false);
+            file.setShareWithSharee(c.getInt(
+                    c.getColumnIndex(ProviderTableMeta.FILE_SHARED_WITH_SHAREE)) == 1 ? true : false);
             file.setPublicLink(c.getString(c.getColumnIndex(ProviderTableMeta.FILE_PUBLIC_LINK)));
             file.setPermissions(c.getString(c.getColumnIndex(ProviderTableMeta.FILE_PERMISSIONS)));
             file.setRemoteId(c.getString(c.getColumnIndex(ProviderTableMeta.FILE_REMOTE_ID)));
@@ -917,15 +928,15 @@ public class FileDataStorageManager {
         cv.put(ProviderTableMeta.OCSHARES_EXPIRATION_DATE, share.getExpirationDate());
         cv.put(ProviderTableMeta.OCSHARES_TOKEN, share.getToken());
         cv.put(
-            ProviderTableMeta.OCSHARES_SHARE_WITH_DISPLAY_NAME, 
-            share.getSharedWithDisplayName()
+                ProviderTableMeta.OCSHARES_SHARE_WITH_DISPLAY_NAME,
+                share.getSharedWithDisplayName()
         );
         cv.put(ProviderTableMeta.OCSHARES_IS_DIRECTORY, share.isFolder() ? 1 : 0);
         cv.put(ProviderTableMeta.OCSHARES_USER_ID, share.getUserId());
         cv.put(ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED, share.getIdRemoteShared());
         cv.put(ProviderTableMeta.OCSHARES_ACCOUNT_OWNER, mAccount.name);
 
-        if (shareExists(share.getIdRemoteShared())) {           // for renamed files; no more delete and create
+        if (shareExists(share.getIdRemoteShared())) {// for renamed files; no more delete and create
             overriden = true;
             if (getContentResolver() != null) {
                 getContentResolver().update(ProviderTableMeta.CONTENT_URI_SHARE, cv,
@@ -968,26 +979,29 @@ public class FileDataStorageManager {
     }
 
 
-    public OCShare getFirstShareByPathAndType(String path, ShareType type) {
+    public OCShare getFirstShareByPathAndType(String path, ShareType type, String shareWith) {
         Cursor c = null;
+
+        String selection = ProviderTableMeta.OCSHARES_PATH + "=? AND "
+                + ProviderTableMeta.OCSHARES_SHARE_TYPE + "=? AND "
+                + ProviderTableMeta.OCSHARES_SHARE_WITH + "=? AND "
+                + ProviderTableMeta.OCSHARES_ACCOUNT_OWNER + "=?" ;
+
+        String [] selectionArgs =  new String[]{path, Integer.toString(type.getValue()),
+                shareWith, mAccount.name};
+
         if (getContentResolver() != null) {
             c = getContentResolver().query(
                     ProviderTableMeta.CONTENT_URI_SHARE,
                     null,
-                    ProviderTableMeta.OCSHARES_PATH + "=? AND "
-                            + ProviderTableMeta.OCSHARES_SHARE_TYPE + "=? AND "
-                            + ProviderTableMeta.OCSHARES_ACCOUNT_OWNER + "=?",
-                    new String[]{path, Integer.toString(type.getValue()), mAccount.name},
+                    selection, selectionArgs,
                     null);
         } else {
             try {
                 c = getContentProviderClient().query(
                         ProviderTableMeta.CONTENT_URI_SHARE,
                         null,
-                        ProviderTableMeta.OCSHARES_PATH + "=? AND "
-                                + ProviderTableMeta.OCSHARES_SHARE_TYPE + "=? AND "
-                                + ProviderTableMeta.OCSHARES_ACCOUNT_OWNER + "=?",
-                        new String[]{path, Integer.toString(type.getValue()), mAccount.name},
+                        selection, selectionArgs,
                         null);
 
             } catch (RemoteException e) {
@@ -1013,6 +1027,8 @@ public class FileDataStorageManager {
                     .getColumnIndex(ProviderTableMeta.OCSHARES_ITEM_SOURCE)));
             share.setShareType(ShareType.fromValue(c.getInt(c
                     .getColumnIndex(ProviderTableMeta.OCSHARES_SHARE_TYPE))));
+            share.setShareWith(c.getString(c
+                    .getColumnIndex(ProviderTableMeta.OCSHARES_SHARE_WITH)));
             share.setPermissions(c.getInt(c
                     .getColumnIndex(ProviderTableMeta.OCSHARES_PERMISSIONS)));
             share.setSharedDate(c.getLong(c
@@ -1026,7 +1042,8 @@ public class FileDataStorageManager {
             share.setIsFolder(c.getInt(
                     c.getColumnIndex(ProviderTableMeta.OCSHARES_IS_DIRECTORY)) == 1);
             share.setUserId(c.getLong(c.getColumnIndex(ProviderTableMeta.OCSHARES_USER_ID)));
-            share.setIdRemoteShared(c.getLong(c.getColumnIndex(ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED)));
+            share.setIdRemoteShared(c.getLong(
+                    c.getColumnIndex(ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED)));
         }
         return share;
     }
@@ -1065,9 +1082,10 @@ public class FileDataStorageManager {
         return shareExists(ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED, String.valueOf(remoteId));
     }
 
-    private void cleanSharedFiles() {
+    private void resetShareFlagsInAllFiles() {
         ContentValues cv = new ContentValues();
-        cv.put(ProviderTableMeta.FILE_SHARE_BY_LINK, false);
+        cv.put(ProviderTableMeta.FILE_SHARED_VIA_LINK, false);
+        cv.put(ProviderTableMeta.FILE_SHARED_WITH_SHAREE, false);
         cv.put(ProviderTableMeta.FILE_PUBLIC_LINK, "");
         String where = ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?";
         String[] whereArgs = new String[]{mAccount.name};
@@ -1077,29 +1095,54 @@ public class FileDataStorageManager {
 
         } else {
             try {
-                getContentProviderClient().update(ProviderTableMeta.CONTENT_URI, cv, where, whereArgs);
+                getContentProviderClient().update(ProviderTableMeta.CONTENT_URI, cv, where,
+                        whereArgs);
             } catch (RemoteException e) {
-                Log_OC.e(TAG, "Exception in cleanSharedFiles" + e.getMessage());
+                Log_OC.e(TAG, "Exception in resetShareFlagsInAllFiles" + e.getMessage());
             }
         }
     }
 
-    private void cleanSharedFilesInFolder(OCFile folder) {
+    private void resetShareFlagsInFolder(OCFile folder) {
         ContentValues cv = new ContentValues();
-        cv.put(ProviderTableMeta.FILE_SHARE_BY_LINK, false);
+        cv.put(ProviderTableMeta.FILE_SHARED_VIA_LINK, false);
+        cv.put(ProviderTableMeta.FILE_SHARED_WITH_SHAREE, false);
         cv.put(ProviderTableMeta.FILE_PUBLIC_LINK, "");
         String where = ProviderTableMeta.FILE_ACCOUNT_OWNER + "=? AND " +
                 ProviderTableMeta.FILE_PARENT + "=?";
         String [] whereArgs = new String[] { mAccount.name , String.valueOf(folder.getFileId()) };
-        
+
         if (getContentResolver() != null) {
             getContentResolver().update(ProviderTableMeta.CONTENT_URI, cv, where, whereArgs);
 
         } else {
             try {
-                getContentProviderClient().update(ProviderTableMeta.CONTENT_URI, cv, where, whereArgs);
+                getContentProviderClient().update(ProviderTableMeta.CONTENT_URI, cv, where,
+                        whereArgs);
             } catch (RemoteException e) {
-                Log_OC.e(TAG, "Exception in cleanSharedFilesInFolder " + e.getMessage());
+                Log_OC.e(TAG, "Exception in resetShareFlagsInFolder " + e.getMessage());
+            }
+        }
+    }
+
+    private void resetShareFlagInAFile(String filePath){
+        ContentValues cv = new ContentValues();
+        cv.put(ProviderTableMeta.FILE_SHARED_VIA_LINK, false);
+        cv.put(ProviderTableMeta.FILE_SHARED_WITH_SHAREE, false);
+        cv.put(ProviderTableMeta.FILE_PUBLIC_LINK, "");
+        String where = ProviderTableMeta.FILE_ACCOUNT_OWNER + "=? AND " +
+                ProviderTableMeta.FILE_PATH+ "=?";
+        String [] whereArgs = new String[] { mAccount.name , filePath };
+
+        if (getContentResolver() != null) {
+            getContentResolver().update(ProviderTableMeta.CONTENT_URI, cv, where, whereArgs);
+
+        } else {
+            try {
+                getContentProviderClient().update(ProviderTableMeta.CONTENT_URI, cv, where,
+                        whereArgs);
+            } catch (RemoteException e) {
+                Log_OC.e(TAG, "Exception in resetShareFlagsInFolder " + e.getMessage());
             }
         }
     }
@@ -1113,7 +1156,8 @@ public class FileDataStorageManager {
 
         } else {
             try {
-                getContentProviderClient().delete(ProviderTableMeta.CONTENT_URI_SHARE, where, whereArgs);
+                getContentProviderClient().delete(ProviderTableMeta.CONTENT_URI_SHARE, where,
+                        whereArgs);
             } catch (RemoteException e) {
                 Log_OC.e(TAG, "Exception in cleanShares" + e.getMessage());
             }
@@ -1123,7 +1167,7 @@ public class FileDataStorageManager {
     public void saveShares(Collection<OCShare> shares) {
         cleanShares();
         if (shares != null) {
-            ArrayList<ContentProviderOperation> operations = 
+            ArrayList<ContentProviderOperation> operations =
                     new ArrayList<ContentProviderOperation>(shares.size());
 
             // prepare operations to insert or update files to save in the given folder
@@ -1139,8 +1183,8 @@ public class FileDataStorageManager {
                 cv.put(ProviderTableMeta.OCSHARES_EXPIRATION_DATE, share.getExpirationDate());
                 cv.put(ProviderTableMeta.OCSHARES_TOKEN, share.getToken());
                 cv.put(
-                    ProviderTableMeta.OCSHARES_SHARE_WITH_DISPLAY_NAME, 
-                    share.getSharedWithDisplayName()
+                        ProviderTableMeta.OCSHARES_SHARE_WITH_DISPLAY_NAME,
+                        share.getSharedWithDisplayName()
                 );
                 cv.put(ProviderTableMeta.OCSHARES_IS_DIRECTORY, share.isFolder() ? 1 : 0);
                 cv.put(ProviderTableMeta.OCSHARES_USER_ID, share.getUserId());
@@ -1151,16 +1195,16 @@ public class FileDataStorageManager {
                     // updating an existing file
                     operations.add(
                             ContentProviderOperation.newUpdate(ProviderTableMeta.CONTENT_URI_SHARE).
-                            withValues(cv).
-                            withSelection(ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED + "=?",
-                                    new String[]{String.valueOf(share.getIdRemoteShared())})
-                            .build());
+                                    withValues(cv).
+                                    withSelection(ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED + "=?",
+                                            new String[]{String.valueOf(share.getIdRemoteShared())})
+                                    .build());
                 } else {
                     // adding a new file
                     operations.add(
                             ContentProviderOperation.newInsert(ProviderTableMeta.CONTENT_URI_SHARE).
-                            withValues(cv).
-                            build()
+                                    withValues(cv).
+                                    build()
                     );
                 }
             }
@@ -1169,11 +1213,12 @@ public class FileDataStorageManager {
             if (operations.size() > 0) {
                 @SuppressWarnings("unused")
                 ContentProviderResult[] results = null;
-                Log_OC.d(TAG, "Sending " + operations.size() + 
+                Log_OC.d(TAG, "Sending " + operations.size() +
                         " operations to FileContentProvider");
                 try {
                     if (getContentResolver() != null) {
-                        results = getContentResolver().applyBatch(MainApp.getAuthority(), operations);
+                        results = getContentResolver().applyBatch(MainApp.getAuthority(),
+                                operations);
                     } else {
                         results = getContentProviderClient().applyBatch(operations);
                     }
@@ -1190,10 +1235,10 @@ public class FileDataStorageManager {
     }
 
     public void updateSharedFiles(Collection<OCFile> sharedFiles) {
-        cleanSharedFiles();
+        resetShareFlagsInAllFiles();
 
         if (sharedFiles != null) {
-            ArrayList<ContentProviderOperation> operations = 
+            ArrayList<ContentProviderOperation> operations =
                     new ArrayList<ContentProviderOperation>(sharedFiles.size());
 
             // prepare operations to insert or update files to save in the given folder
@@ -1201,8 +1246,8 @@ public class FileDataStorageManager {
                 ContentValues cv = new ContentValues();
                 cv.put(ProviderTableMeta.FILE_MODIFIED, file.getModificationTimestamp());
                 cv.put(
-                    ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA, 
-                    file.getModificationTimestampAtLastSyncForData()
+                        ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA,
+                        file.getModificationTimestampAtLastSyncForData()
                 );
                 cv.put(ProviderTableMeta.FILE_CREATION, file.getCreationTimestamp());
                 cv.put(ProviderTableMeta.FILE_CONTENT_LENGTH, file.getFileLength());
@@ -1216,18 +1261,19 @@ public class FileDataStorageManager {
                 cv.put(ProviderTableMeta.FILE_ACCOUNT_OWNER, mAccount.name);
                 cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE, file.getLastSyncDateForProperties());
                 cv.put(
-                    ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA, 
-                    file.getLastSyncDateForData()
+                        ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA,
+                        file.getLastSyncDateForData()
                 );
                 cv.put(ProviderTableMeta.FILE_KEEP_IN_SYNC, file.isFavorite() ? 1 : 0);
                 cv.put(ProviderTableMeta.FILE_ETAG, file.getEtag());
-                cv.put(ProviderTableMeta.FILE_SHARE_BY_LINK, file.isShareByLink() ? 1 : 0);
+                cv.put(ProviderTableMeta.FILE_SHARED_VIA_LINK, file.isSharedViaLink() ? 1 : 0);
+                cv.put(ProviderTableMeta.FILE_SHARED_WITH_SHAREE, file.isSharedWithSharee() ? 1 : 0);
                 cv.put(ProviderTableMeta.FILE_PUBLIC_LINK, file.getPublicLink());
                 cv.put(ProviderTableMeta.FILE_PERMISSIONS, file.getPermissions());
                 cv.put(ProviderTableMeta.FILE_REMOTE_ID, file.getRemoteId());
                 cv.put(
-                    ProviderTableMeta.FILE_UPDATE_THUMBNAIL, 
-                    file.needsUpdateThumbnail() ? 1 : 0
+                        ProviderTableMeta.FILE_UPDATE_THUMBNAIL,
+                        file.needsUpdateThumbnail() ? 1 : 0
                 );
                 cv.put(
                         ProviderTableMeta.FILE_IS_DOWNLOADING,
@@ -1240,17 +1286,17 @@ public class FileDataStorageManager {
                     // updating an existing file
                     operations.add(
                             ContentProviderOperation.newUpdate(ProviderTableMeta.CONTENT_URI).
-                            withValues(cv).
-                            withSelection(ProviderTableMeta._ID + "=?",
-                                    new String[]{String.valueOf(file.getFileId())})
-                            .build());
+                                    withValues(cv).
+                                    withSelection(ProviderTableMeta._ID + "=?",
+                                            new String[]{String.valueOf(file.getFileId())})
+                                    .build());
 
                 } else {
                     // adding a new file
                     operations.add(
                             ContentProviderOperation.newInsert(ProviderTableMeta.CONTENT_URI).
-                            withValues(cv).
-                            build()
+                                    withValues(cv).
+                                    build()
                     );
                 }
             }
@@ -1259,7 +1305,7 @@ public class FileDataStorageManager {
             if (operations.size() > 0) {
                 @SuppressWarnings("unused")
                 ContentProviderResult[] results = null;
-                Log_OC.d(TAG, "Sending " + operations.size() + 
+                Log_OC.d(TAG, "Sending " + operations.size() +
                         " operations to FileContentProvider");
                 try {
                     if (getContentResolver() != null) {
@@ -1282,8 +1328,8 @@ public class FileDataStorageManager {
     public void removeShare(OCShare share) {
         Uri share_uri = ProviderTableMeta.CONTENT_URI_SHARE;
         String where = ProviderTableMeta.OCSHARES_ACCOUNT_OWNER + "=?" + " AND " +
-                ProviderTableMeta.FILE_PATH + "=?";
-        String [] whereArgs = new String[]{mAccount.name, share.getPath()};
+                ProviderTableMeta._ID + "=?";
+        String [] whereArgs = new String[]{mAccount.name, Long.toString(share.getId())};
         if (getContentProviderClient() != null) {
             try {
                 getContentProviderClient().delete(share_uri, where, whereArgs);
@@ -1296,36 +1342,106 @@ public class FileDataStorageManager {
     }
 
     public void saveSharesDB(ArrayList<OCShare> shares) {
-        saveShares(shares);
-
-        ArrayList<OCFile> sharedFiles = new ArrayList<OCFile>();
+        ArrayList<ContentProviderOperation> operations = new ArrayList<ContentProviderOperation>();
 
-        for (OCShare share : shares) {
-            // Get the path
-            String path = share.getPath();
-            if (share.isFolder()) {
-                path = path + FileUtils.PATH_SEPARATOR;
+        // Reset flags & Remove shares for this files
+        String filePath = "";
+        for (OCShare share: shares) {
+            if (filePath != share.getPath()){
+                filePath = share.getPath();
+                resetShareFlagInAFile(filePath);
+                operations = prepareRemoveSharesInFile(filePath, operations);
             }
+        }
+
+       // Add operations to insert shares
+       operations = prepareInsertShares(shares, operations);
 
-            // 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);
+        // apply operations in batch
+        if (operations.size() > 0) {
+            Log_OC.d(TAG, "Sending " + operations.size() + " operations to FileContentProvider");
+            try {
+                if (getContentResolver() != null) {
+                    getContentResolver().applyBatch(MainApp.getAuthority(), operations);
+
+                } else {
+                    getContentProviderClient().applyBatch(operations);
                 }
+
+            } catch (OperationApplicationException e) {
+                Log_OC.e(TAG, "Exception in batch of operations " + e.getMessage());
+
+            } catch (RemoteException e) {
+                Log_OC.e(TAG, "Exception in batch of operations  " + e.getMessage());
             }
         }
 
-        updateSharedFiles(sharedFiles);
+//        // TODO: review if it is needed
+//        // Update shared files
+//        ArrayList<OCFile> sharedFiles = new ArrayList<OCFile>();
+//
+//        for (OCShare share : shares) {
+//            // Get the path
+//            String path = share.getPath();
+//            if (share.isFolder()) {
+//                path = path + FileUtils.PATH_SEPARATOR;
+//            }
+//
+//            // Update OCFile with data from share: ShareByLink, publicLink and
+//            OCFile file = getFileByPath(path);
+//            if (file != null) {
+//                if (share.getShareType().equals(ShareType.PUBLIC_LINK)) {
+//                    file.setShareViaLink(true);
+//                    sharedFiles.add(file);
+//                }
+//            }
+//        }
+//
+//        // TODO: Review
+//        updateSharedFiles(sharedFiles);
     }
 
 
     public void saveSharesInFolder(ArrayList<OCShare> shares, OCFile folder) {
-        cleanSharedFilesInFolder(folder);
+        resetShareFlagsInFolder(folder);
         ArrayList<ContentProviderOperation> operations = new ArrayList<ContentProviderOperation>();
         operations = prepareRemoveSharesInFolder(folder, operations);
 
+        if (shares != null) {
+            // prepare operations to insert or update files to save in the given folder
+            operations = prepareInsertShares(shares, operations);
+        }
+
+        // apply operations in batch
+        if (operations.size() > 0) {
+            Log_OC.d(TAG, "Sending " + operations.size() + " operations to FileContentProvider");
+            try {
+                if (getContentResolver() != null) {
+                    getContentResolver().applyBatch(MainApp.getAuthority(), operations);
+
+                } else {
+                    getContentProviderClient().applyBatch(operations);
+                }
+
+            } catch (OperationApplicationException e) {
+                Log_OC.e(TAG, "Exception in batch of operations " + e.getMessage());
+
+            } catch (RemoteException e) {
+
+            }
+        }
+
+    }
+
+    /**
+     * Prepare operations to insert or update files to save in the given folder
+     * @param shares        List of shares to insert
+     * @param operations    List of operations
+     * @return
+     */
+    private ArrayList<ContentProviderOperation> prepareInsertShares(
+            ArrayList<OCShare> shares, ArrayList<ContentProviderOperation> operations) {
+
         if (shares != null) {
             // prepare operations to insert or update files to save in the given folder
             for (OCShare share : shares) {
@@ -1340,58 +1456,23 @@ public class FileDataStorageManager {
                 cv.put(ProviderTableMeta.OCSHARES_EXPIRATION_DATE, share.getExpirationDate());
                 cv.put(ProviderTableMeta.OCSHARES_TOKEN, share.getToken());
                 cv.put(
-                    ProviderTableMeta.OCSHARES_SHARE_WITH_DISPLAY_NAME, 
-                    share.getSharedWithDisplayName()
+                        ProviderTableMeta.OCSHARES_SHARE_WITH_DISPLAY_NAME,
+                        share.getSharedWithDisplayName()
                 );
                 cv.put(ProviderTableMeta.OCSHARES_IS_DIRECTORY, share.isFolder() ? 1 : 0);
                 cv.put(ProviderTableMeta.OCSHARES_USER_ID, share.getUserId());
                 cv.put(ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED, share.getIdRemoteShared());
                 cv.put(ProviderTableMeta.OCSHARES_ACCOUNT_OWNER, mAccount.name);
 
-                /*
-                if (shareExists(share.getIdRemoteShared())) {
-                    // updating an existing share resource
-                    operations.add(
-                            ContentProviderOperation.newUpdate(ProviderTableMeta.CONTENT_URI_SHARE).
-                            withValues(cv).
-                            withSelection(  ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED + "=?", 
-                                    new String[] { String.valueOf(share.getIdRemoteShared()) })
-                                    .build());
-
-                } else {
-                */
                 // adding a new share resource
                 operations.add(
                         ContentProviderOperation.newInsert(ProviderTableMeta.CONTENT_URI_SHARE).
-                        withValues(cv).
-                        build()
+                                withValues(cv).
+                                build()
                 );
-                //}
             }
         }
-
-        // apply operations in batch
-        if (operations.size() > 0) {
-            @SuppressWarnings("unused")
-            ContentProviderResult[] results = null;
-            Log_OC.d(TAG, "Sending " + operations.size() + " operations to FileContentProvider");
-            try {
-                if (getContentResolver() != null) {
-                    results = getContentResolver().applyBatch(MainApp.getAuthority(), operations);
-
-                } else {
-                    results = getContentProviderClient().applyBatch(operations);
-                }
-
-            } catch (OperationApplicationException e) {
-                Log_OC.e(TAG, "Exception in batch of operations " + e.getMessage());
-
-            } catch (RemoteException e) {
-                Log_OC.e(TAG, "Exception in batch of operations  " + e.getMessage());
-            }
-        }
-        //}
-
+        return operations;
     }
 
     private ArrayList<ContentProviderOperation> prepareRemoveSharesInFolder(
@@ -1403,17 +1484,75 @@ public class FileDataStorageManager {
 
             // TODO Enable when "On Device" is recovered ?
             Vector<OCFile> files = getFolderContent(folder /*, false*/);
-            
+
             for (OCFile file : files) {
                 whereArgs[0] = file.getRemotePath();
                 preparedOperations.add(
                         ContentProviderOperation.newDelete(ProviderTableMeta.CONTENT_URI_SHARE).
-                        withSelection(where, whereArgs).
-                        build()
+                                withSelection(where, whereArgs).
+                                build()
                 );
             }
         }
         return preparedOperations;
+
+    }
+
+    private ArrayList<ContentProviderOperation> prepareRemoveSharesInFile(
+            String filePath, ArrayList<ContentProviderOperation> preparedOperations) {
+
+        String where = ProviderTableMeta.OCSHARES_PATH + "=?" + " AND "
+                + ProviderTableMeta.OCSHARES_ACCOUNT_OWNER + "=?";
+        String[] whereArgs = new String[]{filePath, mAccount.name};
+
+        preparedOperations.add(
+                ContentProviderOperation.newDelete(ProviderTableMeta.CONTENT_URI_SHARE).
+                        withSelection(where, whereArgs).
+                        build()
+        );
+
+        return preparedOperations;
+
+    }
+
+    public ArrayList<OCShare> getSharesWithForAFile(String filePath, String accountName){
+        // Condition
+        String where = ProviderTableMeta.OCSHARES_PATH + "=?" + " AND "
+                + ProviderTableMeta.OCSHARES_ACCOUNT_OWNER + "=?"+ "AND"
+                + " (" + ProviderTableMeta.OCSHARES_SHARE_TYPE + "=? OR "
+                + ProviderTableMeta.OCSHARES_SHARE_TYPE +  "=? ) ";
+        String [] whereArgs = new String[]{ filePath, accountName ,
+                Integer.toString(ShareType.USER.getValue()),
+                Integer.toString(ShareType.GROUP.getValue()) };
+
+        Cursor c = null;
+        if (getContentResolver() != null) {
+            c = getContentResolver().query(
+                    ProviderTableMeta.CONTENT_URI_SHARE,
+                    null, where, whereArgs, null);
+        } else {
+            try {
+                c = getContentProviderClient().query(
+                        ProviderTableMeta.CONTENT_URI_SHARE,
+                        null, where, whereArgs, null);
+
+            } catch (RemoteException e) {
+                Log_OC.e(TAG, "Could not get list of shares with: " + e.getMessage());
+                c = null;
+            }
+        }
+        ArrayList<OCShare> shares = new ArrayList<OCShare>();
+        OCShare share = null;
+        if (c.moveToFirst()) {
+            do {
+                share = createShareInstance(c);
+                shares.add(share);
+                // }
+            } while (c.moveToNext());
+        }
+        c.close();
+
+        return shares;
     }
 
     public void triggerMediaScan(String path) {

+ 23 - 2
src/com/owncloud/android/datamodel/OCFile.java

@@ -43,6 +43,8 @@ public class OCFile implements Parcelable, Comparable<OCFile> {
         }
     };
 
+    private final static String PERMISSION_SHARED_WITH_ME = "S";    // TODO move to better location
+
     public static final String PATH_SEPARATOR = "/";
     public static final String ROOT_PATH = PATH_SEPARATOR;
 
@@ -76,6 +78,8 @@ public class OCFile implements Parcelable, Comparable<OCFile> {
 
     private String mEtagInConflict;    // Save file etag in the server, when there is a conflict. No conflict =  null
 
+    private boolean mShareWithSharee;
+
 
     /**
      * Create new {@link OCFile} with given path.
@@ -120,6 +124,7 @@ public class OCFile implements Parcelable, Comparable<OCFile> {
         mNeedsUpdateThumbnail = source.readInt() == 1;
         mIsDownloading = source.readInt() == 1;
         mEtagInConflict = source.readString();
+        mShareWithSharee = source.readInt() == 1;
 
     }
 
@@ -146,6 +151,7 @@ public class OCFile implements Parcelable, Comparable<OCFile> {
         dest.writeInt(mNeedsUpdateThumbnail ? 1 : 0);
         dest.writeInt(mIsDownloading ? 1 : 0);
         dest.writeString(mEtagInConflict);
+        dest.writeInt(mShareWithSharee ? 1 : 0);
     }
 
     /**
@@ -344,6 +350,7 @@ public class OCFile implements Parcelable, Comparable<OCFile> {
         mNeedsUpdateThumbnail = false;
         mIsDownloading = false;
         mEtagInConflict = null;
+        mShareWithSharee = false;
     }
 
     /**
@@ -488,11 +495,12 @@ public class OCFile implements Parcelable, Comparable<OCFile> {
         this.mEtag = (etag != null ? etag : "");
     }
 
-    public boolean isShareByLink() {
+
+    public boolean isSharedViaLink() {
         return mShareByLink;
     }
 
-    public void setShareByLink(boolean shareByLink) {
+    public void setShareViaLink(boolean shareByLink) {
         this.mShareByLink = shareByLink;
     }
 
@@ -591,4 +599,17 @@ public class OCFile implements Parcelable, Comparable<OCFile> {
     public void setEtagInConflict(String etagInConflict) {
         mEtagInConflict = etagInConflict;
     }
+
+    public boolean isSharedWithSharee() {
+        return mShareWithSharee;
+    }
+
+    public void setShareWithSharee(boolean shareWithSharee) {
+        this.mShareWithSharee = shareWithSharee;
+    }
+
+    public boolean isSharedWithMe() {
+        String permissions = getPermissions();
+        return (permissions != null && permissions.contains(PERMISSION_SHARED_WITH_ME));
+    }
 }

+ 3 - 3
src/com/owncloud/android/db/ProviderMeta.java

@@ -31,7 +31,7 @@ import com.owncloud.android.MainApp;
 public class ProviderMeta {
 
     public static final String DB_NAME = "filelist";
-    public static final int DB_VERSION = 11;
+    public static final int DB_VERSION = 12;
 
     private ProviderMeta() {
     }
@@ -66,7 +66,8 @@ public class ProviderMeta {
         public static final String FILE_LAST_SYNC_DATE_FOR_DATA = "last_sync_date_for_data";
         public static final String FILE_KEEP_IN_SYNC = "keep_in_sync";
         public static final String FILE_ETAG = "etag";
-        public static final String FILE_SHARE_BY_LINK = "share_by_link";
+        public static final String FILE_SHARED_VIA_LINK = "share_by_link";
+        public static final String FILE_SHARED_WITH_SHAREE = "shared_via_users";
         public static final String FILE_PUBLIC_LINK = "public_link";
         public static final String FILE_PERMISSIONS = "permissions";
         public static final String FILE_REMOTE_ID = "remote_id";
@@ -96,6 +97,5 @@ public class ProviderMeta {
         public static final String OCSHARES_DEFAULT_SORT_ORDER = OCSHARES_FILE_SOURCE 
                 + " collate nocase asc";
 
-
     }
 }

+ 14 - 4
src/com/owncloud/android/files/FileMenuFilter.java

@@ -29,6 +29,7 @@ import android.view.Menu;
 import android.view.MenuItem;
 
 import com.owncloud.android.R;
+import com.owncloud.android.authentication.AccountUtils;
 import com.owncloud.android.datamodel.OCFile;
 import com.owncloud.android.files.services.FileDownloader;
 import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder;
@@ -57,7 +58,8 @@ public class FileMenuFilter {
      *                          {@link FileUploader} and {@link FileDownloader} services
      * @param context           Android {@link Context}, needed to access build setup resources.
      */
-    public FileMenuFilter(OCFile targetFile, Account account, ComponentsGetter cg, Context context) {
+    public FileMenuFilter(OCFile targetFile, Account account, ComponentsGetter cg,
+                          Context context) {
         mFile = targetFile;
         mAccount = account;
         mComponentsGetter = cg;
@@ -179,7 +181,7 @@ public class FileMenuFilter {
             toShow.add(R.id.action_sync_file);
         }
 
-        // SHARE FILE 
+        // SHARE FILE
         // TODO add check on SHARE available on server side?
         boolean shareAllowed = (mContext != null  &&
                 mContext.getString(R.string.share_feature).equalsIgnoreCase("on"));
@@ -189,14 +191,22 @@ public class FileMenuFilter {
             toShow.add(R.id.action_share_file);
         }
 
-        // UNSHARE FILE  
+        // UNSHARE FILE
         // TODO add check on SHARE available on server side?
-        if ( !shareAllowed || (mFile == null || !mFile.isShareByLink())) {
+        if ( !shareAllowed || (mFile == null || !mFile.isSharedViaLink())) {
             toHide.add(R.id.action_unshare_file);
         } else {
             toShow.add(R.id.action_unshare_file);
         }
 
+        // SHARE FILE, with Users
+        if (!shareAllowed ||  mFile == null) {
+            toHide.add(R.id.action_share_with_users);
+        } else {
+            toShow.add(R.id.action_share_with_users);
+        }
+
+
         // SEE DETAILS
         if (mFile == null || mFile.isFolder()) {
             toHide.add(R.id.action_see_details);

+ 120 - 24
src/com/owncloud/android/files/FileOperationsHelper.java

@@ -39,10 +39,12 @@ import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder;
 import com.owncloud.android.files.services.FileUploader.FileUploaderBinder;
 import com.owncloud.android.lib.common.network.WebdavUtils;
 import com.owncloud.android.lib.common.utils.Log_OC;
+import com.owncloud.android.lib.resources.shares.ShareType;
 import com.owncloud.android.lib.resources.status.OwnCloudVersion;
 import com.owncloud.android.services.OperationsService;
 import com.owncloud.android.services.observer.FileObserverService;
 import com.owncloud.android.ui.activity.FileActivity;
+import com.owncloud.android.ui.activity.ShareActivity;
 import com.owncloud.android.ui.dialog.ShareLinkToDialog;
 
 import org.apache.http.protocol.HTTP;
@@ -74,7 +76,8 @@ public class FileOperationsHelper {
             String encodedStoragePath = WebdavUtils.encodePath(storagePath);
 
             Intent intentForSavedMimeType = new Intent(Intent.ACTION_VIEW);
-            intentForSavedMimeType.setDataAndType(Uri.parse("file://"+ encodedStoragePath), file.getMimetype());
+            intentForSavedMimeType.setDataAndType(Uri.parse("file://"+ encodedStoragePath),
+                    file.getMimetype());
             intentForSavedMimeType.setFlags(
                     Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION
             );
@@ -86,9 +89,12 @@ public class FileOperationsHelper {
                 );
                 if (guessedMimeType != null && !guessedMimeType.equals(file.getMimetype())) {
                     intentForGuessedMimeType = new Intent(Intent.ACTION_VIEW);
-                    intentForGuessedMimeType.setDataAndType(Uri.parse("file://"+ encodedStoragePath), guessedMimeType);
+                    intentForGuessedMimeType.
+                            setDataAndType(Uri.parse("file://"+ encodedStoragePath),
+                                    guessedMimeType);
                     intentForGuessedMimeType.setFlags(
-                            Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION
+                            Intent.FLAG_GRANT_READ_URI_PERMISSION |
+                                    Intent.FLAG_GRANT_WRITE_URI_PERMISSION
                     );
                 }
             }
@@ -140,7 +146,8 @@ public class FileOperationsHelper {
                 String link = "https://fake.url";
                 Intent intent = createShareWithLinkIntent(link);
                 String[] packagesToExclude = new String[]{mFileActivity.getPackageName()};
-                DialogFragment chooserDialog = ShareLinkToDialog.newInstance(intent, packagesToExclude, file);
+                DialogFragment chooserDialog = ShareLinkToDialog.newInstance(intent,
+                        packagesToExclude, file);
                 chooserDialog.show(mFileActivity.getSupportFragmentManager(), FTAG_CHOOSER_DIALOG);
 
             } else {
@@ -150,7 +157,8 @@ public class FileOperationsHelper {
         } else {
             // Show a Message
             Toast t = Toast.makeText(
-                    mFileActivity, mFileActivity.getString(R.string.share_link_no_support_share_api), Toast.LENGTH_LONG
+                    mFileActivity, mFileActivity.getString(R.string.share_link_no_support_share_api),
+                    Toast.LENGTH_LONG
             );
             t.show();
         }
@@ -160,10 +168,11 @@ public class FileOperationsHelper {
     public void shareFileWithLinkToApp(OCFile file, String password, Intent sendIntent) {
         
         if (file != null) {
-            mFileActivity.showLoadingDialog();
+            mFileActivity.showLoadingDialog(mFileActivity.getApplicationContext().
+                    getString(R.string.wait_a_moment));
 
             Intent service = new Intent(mFileActivity, OperationsService.class);
-            service.setAction(OperationsService.ACTION_CREATE_SHARE);
+            service.setAction(OperationsService.ACTION_CREATE_SHARE_VIA_LINK);
             service.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
             service.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
             service.putExtra(OperationsService.EXTRA_PASSWORD_SHARE, password);
@@ -184,6 +193,33 @@ public class FileOperationsHelper {
     }
 
 
+    /**
+     * Helper method to share a file with a know sharee. Starts a request to do it in {@link OperationsService}
+     *
+     * @param file          The file to share.
+     * @param shareeName    Name (user name or group name) of the target sharee.
+     * @param shareType     The share type determines the sharee type.
+     */
+    public void shareFileWithSharee(OCFile file, String shareeName, ShareType shareType) {
+        if (file != null) {
+            // TODO check capability?
+            mFileActivity.showLoadingDialog(mFileActivity.getApplicationContext().
+                    getString(R.string.wait_a_moment));
+
+            Intent service = new Intent(mFileActivity, OperationsService.class);
+            service.setAction(OperationsService.ACTION_CREATE_SHARE_WITH_SHAREE);
+            service.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
+            service.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
+            service.putExtra(OperationsService.EXTRA_SHARE_WITH, shareeName);
+            service.putExtra(OperationsService.EXTRA_SHARE_TYPE, shareType);
+            mWaitingForOpId = mFileActivity.getOperationsServiceBinder().queueNewOperation(service);
+
+        } else {
+            Log_OC.wtf(TAG, "Trying to share a NULL OCFile");
+        }
+    }
+
+
     /**
      * @return 'True' if the server supports the Share API
      */
@@ -198,24 +234,75 @@ public class FileOperationsHelper {
 
     public void unshareFileWithLink(OCFile file) {
 
+        // Unshare the file: Create the intent
+        Intent unshareService = new Intent(mFileActivity, OperationsService.class);
+        unshareService.setAction(OperationsService.ACTION_UNSHARE);
+        unshareService.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
+        unshareService.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
+        unshareService.putExtra(OperationsService.EXTRA_SHARE_TYPE, ShareType.PUBLIC_LINK);
+        unshareService.putExtra(OperationsService.EXTRA_SHARE_WITH, "");
+
+        unshareFile(unshareService);
+    }
+
+    public void unshareFileWithUserOrGroup(OCFile file, ShareType shareType, String userOrGroup){
+
+        // Unshare the file: Create the intent
+        Intent unshareService = new Intent(mFileActivity, OperationsService.class);
+        unshareService.setAction(OperationsService.ACTION_UNSHARE);
+        unshareService.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
+        unshareService.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
+        unshareService.putExtra(OperationsService.EXTRA_SHARE_TYPE, shareType);
+        unshareService.putExtra(OperationsService.EXTRA_SHARE_WITH, userOrGroup);
+
+        unshareFile(unshareService);
+    }
+
+
+    private void unshareFile(Intent unshareService){
         if (isSharedSupported()) {
             // Unshare the file
-            Intent service = new Intent(mFileActivity, OperationsService.class);
-            service.setAction(OperationsService.ACTION_UNSHARE);
-            service.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
-            service.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
-            mWaitingForOpId = mFileActivity.getOperationsServiceBinder().queueNewOperation(service);
-            
-            mFileActivity.showLoadingDialog();
+            mWaitingForOpId = mFileActivity.getOperationsServiceBinder().
+                    queueNewOperation(unshareService);
+
+            mFileActivity.showLoadingDialog(mFileActivity.getApplicationContext().
+                    getString(R.string.wait_a_moment));
 
         } else {
             // Show a Message
-            Toast t = Toast.makeText(mFileActivity, mFileActivity.getString(R.string.share_link_no_support_share_api), Toast.LENGTH_LONG);
+            Toast t = Toast.makeText(mFileActivity,
+                    mFileActivity.getString(R.string.share_link_no_support_share_api),
+                    Toast.LENGTH_LONG);
             t.show();
 
         }
     }
 
+    /**
+     * Show an instance of {@link ShareType} for sharing or unsharing the {@OCFile} received as parameter.
+     *
+     * @param file  File to share or unshare.
+     */
+    public void showShareFile(OCFile file){
+        Intent intent = new Intent(mFileActivity, ShareActivity.class);
+        intent.putExtra(mFileActivity.EXTRA_FILE, file);
+        intent.putExtra(mFileActivity.EXTRA_ACCOUNT, mFileActivity.getAccount());
+        mFileActivity.startActivity(intent);
+
+    }
+
+
+    /**
+     * @return 'True' if the server supports the Search Users API
+     */
+    public boolean isSearchUsersSupportedSupported() {
+        if (mFileActivity.getAccount() != null) {
+            OwnCloudVersion serverVersion = AccountUtils.getServerVersion(mFileActivity.getAccount());
+            return (serverVersion != null && serverVersion.isSearchUsersSupported());
+        }
+        return false;
+    }
+
     public void sendDownloadedFile(OCFile file) {
         if (file != null) {
             String storagePath = file.getStoragePath();
@@ -228,7 +315,8 @@ public class FileOperationsHelper {
 
             // Show dialog, without the own app
             String[] packagesToExclude = new String[]{mFileActivity.getPackageName()};
-            DialogFragment chooserDialog = ShareLinkToDialog.newInstance(sendIntent, packagesToExclude, file);
+            DialogFragment chooserDialog = ShareLinkToDialog.newInstance(sendIntent,
+                    packagesToExclude, file);
             chooserDialog.show(mFileActivity.getSupportFragmentManager(), FTAG_CHOOSER_DIALOG);
 
         } else {
@@ -249,7 +337,8 @@ public class FileOperationsHelper {
             intent.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
             intent.putExtra(OperationsService.EXTRA_SYNC_FILE_CONTENTS, true);
             mWaitingForOpId = mFileActivity.getOperationsServiceBinder().queueNewOperation(intent);
-            mFileActivity.showLoadingDialog();
+            mFileActivity.showLoadingDialog(mFileActivity.getApplicationContext().
+                    getString(R.string.wait_a_moment));
             
         } else {
             Intent intent = new Intent(mFileActivity, OperationsService.class);
@@ -288,7 +377,8 @@ public class FileOperationsHelper {
         service.putExtra(OperationsService.EXTRA_NEWNAME, newFilename);
         mWaitingForOpId = mFileActivity.getOperationsServiceBinder().queueNewOperation(service);
         
-        mFileActivity.showLoadingDialog();
+        mFileActivity.showLoadingDialog(mFileActivity.getApplicationContext().
+                getString(R.string.wait_a_moment));
     }
 
 
@@ -301,7 +391,8 @@ public class FileOperationsHelper {
         service.putExtra(OperationsService.EXTRA_REMOVE_ONLY_LOCAL, onlyLocalCopy);
         mWaitingForOpId =  mFileActivity.getOperationsServiceBinder().queueNewOperation(service);
         
-        mFileActivity.showLoadingDialog();
+        mFileActivity.showLoadingDialog(mFileActivity.getApplicationContext().
+                getString(R.string.wait_a_moment));
     }
 
 
@@ -314,7 +405,8 @@ public class FileOperationsHelper {
         service.putExtra(OperationsService.EXTRA_CREATE_FULL_PATH, createFullPath);
         mWaitingForOpId =  mFileActivity.getOperationsServiceBinder().queueNewOperation(service);
         
-        mFileActivity.showLoadingDialog();
+        mFileActivity.showLoadingDialog(mFileActivity.getApplicationContext().
+                getString(R.string.wait_a_moment));
     }
 
     /**
@@ -324,7 +416,8 @@ public class FileOperationsHelper {
     public void cancelTransference(OCFile file) {
         Account account = mFileActivity.getAccount();
         if (file.isFolder()) {
-            OperationsService.OperationsServiceBinder opsBinder = mFileActivity.getOperationsServiceBinder();
+            OperationsService.OperationsServiceBinder opsBinder =
+                    mFileActivity.getOperationsServiceBinder();
             if (opsBinder != null) {
                 opsBinder.cancel(account, file);
             }
@@ -356,7 +449,8 @@ public class FileOperationsHelper {
         service.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
         mWaitingForOpId =  mFileActivity.getOperationsServiceBinder().queueNewOperation(service);
 
-        mFileActivity.showLoadingDialog();
+        mFileActivity.showLoadingDialog(mFileActivity.getApplicationContext().
+                getString(R.string.wait_a_moment));
     }
 
     /**
@@ -374,7 +468,8 @@ public class FileOperationsHelper {
         service.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
         mWaitingForOpId = mFileActivity.getOperationsServiceBinder().queueNewOperation(service);
 
-        mFileActivity.showLoadingDialog();
+        mFileActivity.showLoadingDialog(mFileActivity.getApplicationContext().
+                getString(R.string.wait_a_moment));
     }
 
     public long getOpIdWaitingFor() {
@@ -391,7 +486,8 @@ public class FileOperationsHelper {
      */
     public boolean isVersionWithForbiddenCharacters() {
         if (mFileActivity.getAccount() != null) {
-            OwnCloudVersion serverVersion = AccountUtils.getServerVersion(mFileActivity.getAccount());
+            OwnCloudVersion serverVersion =
+                    AccountUtils.getServerVersion(mFileActivity.getAccount());
             return (serverVersion != null && serverVersion.isVersionWithForbiddenCharacters());
         }
         return false;

+ 52 - 76
src/com/owncloud/android/operations/CreateShareOperation.java → src/com/owncloud/android/operations/CreateShareViaLinkOperation.java

@@ -2,6 +2,7 @@
  *   ownCloud Android client application
  *
  *   @author masensio
+ *   @author David A. Velasco
  *   Copyright (C) 2015 ownCloud Inc.
  *
  *   This program is free software: you can redistribute it and/or modify
@@ -21,9 +22,10 @@
 package com.owncloud.android.operations;
 
 /**
- * Creates a new share from a given file
+ * Creates a new public share for a given file
  */
 
+
 import android.content.Context;
 import android.content.Intent;
 
@@ -31,80 +33,61 @@ import com.owncloud.android.R;
 import com.owncloud.android.datamodel.FileDataStorageManager;
 import com.owncloud.android.datamodel.OCFile;
 import com.owncloud.android.lib.common.OwnCloudClient;
-import com.owncloud.android.lib.resources.shares.OCShare;
 import com.owncloud.android.lib.common.operations.RemoteOperation;
 import com.owncloud.android.lib.common.operations.RemoteOperationResult;
-import com.owncloud.android.lib.common.utils.Log_OC;
+import com.owncloud.android.lib.resources.files.FileUtils;
+import com.owncloud.android.lib.resources.shares.CreateRemoteShareOperation;
 import com.owncloud.android.lib.resources.shares.GetRemoteSharesForFileOperation;
+import com.owncloud.android.lib.resources.shares.OCShare;
 import com.owncloud.android.lib.resources.shares.ShareType;
-import com.owncloud.android.lib.resources.shares.CreateRemoteShareOperation;
-import com.owncloud.android.lib.resources.files.FileUtils;
 import com.owncloud.android.operations.common.SyncOperation;
 
-public class CreateShareOperation extends SyncOperation {
-
-    private static final String TAG = CreateShareOperation.class.getSimpleName();
+public class CreateShareViaLinkOperation extends SyncOperation {
 
     protected FileDataStorageManager mStorageManager;
 
-    private Context mContext;
     private String mPath;
-    private ShareType mShareType;
-    private String mShareWith;
-    private boolean mPublicUpload;
     private String mPassword;
-    private int mPermissions;
     private Intent mSendIntent;
+    private String mFileName;
 
     /**
      * Constructor
-     * @param context       The context that the share is coming from.
      * @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.
+     *  @param sendIntent   Optional Intent with the information of an app where the link to the new share (if public)
+     *                      should be posted later.
      */
-    public CreateShareOperation(Context context, String path, ShareType shareType, String shareWith,
-                                boolean publicUpload, String password, int permissions,
-                                Intent sendIntent) {
+    public CreateShareViaLinkOperation(
+            String path,
+            String password,
+            Intent sendIntent
+    ) {
 
-        mContext = context;
         mPath = path;
-        mShareType = shareType;
-        mShareWith = shareWith;
-        mPublicUpload = publicUpload;
         mPassword = password;
-        mPermissions = permissions;
         mSendIntent = sendIntent;
+        mFileName = null;
     }
 
     @Override
     protected RemoteOperationResult run(OwnCloudClient client) {
-        RemoteOperation operation = null;
-        
         // Check if the share link already exists
-        operation = new GetRemoteSharesForFileOperation(mPath, false, false);
-        RemoteOperationResult result =
-                ((GetRemoteSharesForFileOperation)operation).execute(client);
+        RemoteOperation operation = new GetRemoteSharesForFileOperation(mPath, false, false);
+        RemoteOperationResult result = operation.execute(client);
+        // TODO - fix this check; if the user already shared the file with users or group, a share via link will not be created
 
         if (!result.isSuccess() || result.getData().size() <= 0) {
-            operation = new CreateRemoteShareOperation(mPath, mShareType, mShareWith, mPublicUpload,
-                    mPassword, mPermissions);
-            result = ((CreateRemoteShareOperation)operation).execute(client);
+            operation = new CreateRemoteShareOperation(
+                    mPath,
+                    ShareType.PUBLIC_LINK,
+                    "",
+                    false,
+                    mPassword,
+                    OCShare.DEFAULT_PERMISSION
+            );
+            result = operation.execute(client);
         }
         
         if (result.isSuccess()) {
@@ -121,30 +104,36 @@ public class CreateShareOperation extends SyncOperation {
         return mPath;
     }
 
-    public ShareType getShareType() {
-        return mShareType;
-    }
-
-    public String getShareWith() {
-        return mShareWith;
-    }
-
-    public boolean getPublicUpload() {
-        return mPublicUpload;
-    }
-
     public String getPassword() {
         return mPassword;
     }
 
-    public int getPermissions() {
-        return mPermissions;
+    public Intent getSendIntent() {
+        return mSendIntent;
     }
 
-    public Intent getSendIntent() {
+    public Intent getSendIntentWithSubject(Context context) {
+        if (context != null && mSendIntent != null && mSendIntent.getStringExtra(Intent.EXTRA_SUBJECT) != null) {
+            if (getClient() == null || getClient().getCredentials() == null ||
+                    getClient().getCredentials().getUsername() == null) {
+                mSendIntent.putExtra(
+                        Intent.EXTRA_SUBJECT,
+                        context.getString(R.string.subject_shared_with_you, mFileName)
+                );
+            } else {
+                mSendIntent.putExtra(
+                        Intent.EXTRA_SUBJECT,
+                        context.getString(
+                                R.string.subject_user_shared_with_you,
+                                getClient().getCredentials().getUsername(),
+                                mFileName
+                        )
+                );
+            }
+        }
         return mSendIntent;
     }
-    
+
     private void updateData(OCShare share) {
         // Update DB with the response
         share.setPath(mPath);
@@ -153,29 +142,16 @@ public class CreateShareOperation extends SyncOperation {
         } else {
             share.setIsFolder(false);
         }
-        share.setPermissions(mPermissions);
-        
+
         getStorageManager().saveShare(share);
         
         // Update OCFile with data from share: ShareByLink  and publicLink
         OCFile file = getStorageManager().getFileByPath(mPath);
         if (file!=null) {
             mSendIntent.putExtra(Intent.EXTRA_TEXT, share.getShareLink());
-            if (getClient().getCredentials().getUsername() == null) {
-                //in saml is null
-                mSendIntent.putExtra(Intent.EXTRA_SUBJECT,
-                        String.format(mContext.getString(R.string.saml_subject_token),
-                                file.getFileName()));
-            } else {
-                mSendIntent.putExtra(Intent.EXTRA_SUBJECT,
-                        String.format(mContext.getString(R.string.subject_token),
-                                getClient().getCredentials().getUsername(), file.getFileName()));
-            }
             file.setPublicLink(share.getShareLink());
-            file.setShareByLink(true);
+            file.setShareViaLink(true);
             getStorageManager().saveFile(file);
-            Log_OC.d(TAG, "Public Link = " + file.getPublicLink());
-
         }
     }
 

+ 115 - 0
src/com/owncloud/android/operations/CreateShareWithShareeOperation.java

@@ -0,0 +1,115 @@
+/**
+ *   ownCloud Android client application
+ *
+ *   @author masensio
+ *   @author David A. Velasco
+ *   Copyright (C) 2015 ownCloud Inc.
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License version 2,
+ *   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 private share for a given file
+ */
+
+
+import com.owncloud.android.datamodel.FileDataStorageManager;
+import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.lib.common.OwnCloudClient;
+import com.owncloud.android.lib.common.operations.RemoteOperationResult;
+import com.owncloud.android.lib.resources.files.FileUtils;
+import com.owncloud.android.lib.resources.shares.CreateRemoteShareOperation;
+import com.owncloud.android.lib.resources.shares.OCShare;
+import com.owncloud.android.lib.resources.shares.ShareType;
+import com.owncloud.android.operations.common.SyncOperation;
+
+public class CreateShareWithShareeOperation extends SyncOperation {
+
+    protected FileDataStorageManager mStorageManager;
+
+    private String mPath;
+    private String mShareeName;
+    private ShareType mShareType;
+
+    /**
+     * Constructor.
+     *
+     * @param path          Full path of the file/folder being shared.
+     * @param shareeName    User or group name of the target sharee.
+     * @param shareType     Type of share determines type of sharee; {@link ShareType#USER} and {@link ShareType#GROUP}
+     *                      are the only valid values for the moment.
+     */
+    public CreateShareWithShareeOperation(String path, String shareeName, ShareType shareType) {
+        if (!ShareType.USER.equals(shareType) && !ShareType.GROUP.equals(shareType)) {
+            throw new IllegalArgumentException("Illegal share type " + shareType);
+        }
+        mPath = path;
+        mShareeName = shareeName;
+        mShareType = shareType;
+    }
+
+    @Override
+    protected RemoteOperationResult run(OwnCloudClient client) {
+        // Check if the share link already exists
+        // TODO or not
+        /*
+        RemoteOperation operation = new GetRemoteSharesForFileOperation(mPath, false, false);
+        RemoteOperationResult result = operation.execute(client);
+        if (!result.isSuccess() || result.getData().size() <= 0) {
+        */
+
+        CreateRemoteShareOperation operation = new CreateRemoteShareOperation(
+                mPath,
+                mShareType,
+                mShareeName,
+                false,
+                "",
+                OCShare.DEFAULT_PERMISSION
+        );
+        operation.setGetShareDetails(true);
+        RemoteOperationResult result = operation.execute(client);
+
+        
+        if (result.isSuccess()) {
+            if (result.getData().size() > 0) {
+                OCShare share = (OCShare) result.getData().get(0);
+                updateData(share);
+            } 
+        }
+        
+        return result;
+    }
+    
+    public String getPath() {
+        return mPath;
+    }
+
+    private void updateData(OCShare share) {
+        // Update DB with the response
+        share.setPath(mPath);
+        share.setIsFolder(mPath.endsWith(FileUtils.PATH_SEPARATOR));
+
+        getStorageManager().saveShare(share);
+        
+        // Update OCFile with data from share: ShareByLink  and publicLink
+        OCFile file = getStorageManager().getFileByPath(mPath);
+        if (file!=null) {
+            file.setShareWithSharee(true);    // TODO - this should be done by the FileContentProvider, as part of getStorageManager().saveShare(share)
+            getStorageManager().saveFile(file);
+        }
+    }
+
+}

+ 3 - 4
src/com/owncloud/android/operations/GetSharesForFileOperation.java

@@ -21,16 +21,15 @@
 
 package com.owncloud.android.operations;
 
-import java.util.ArrayList;
-
-import com.owncloud.android.MainApp;
 import com.owncloud.android.lib.common.OwnCloudClient;
-import com.owncloud.android.lib.resources.shares.OCShare;
 import com.owncloud.android.lib.common.operations.RemoteOperationResult;
 import com.owncloud.android.lib.common.utils.Log_OC;
 import com.owncloud.android.lib.resources.shares.GetRemoteSharesForFileOperation;
+import com.owncloud.android.lib.resources.shares.OCShare;
 import com.owncloud.android.operations.common.SyncOperation;
 
+import java.util.ArrayList;
+
 /**
  * Provide a list shares for a specific file.
  */

+ 0 - 63
src/com/owncloud/android/operations/GetSharesOperation.java

@@ -1,63 +0,0 @@
-/**
- *   ownCloud Android client application
- *
- *   @author masensio
- *   @author David A. Velasco
- *   Copyright (C) 2015 ownCloud Inc.
- *
- *   This program is free software: you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License version 2,
- *   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.MainApp;
-import com.owncloud.android.lib.common.OwnCloudClient;
-import com.owncloud.android.lib.common.operations.RemoteOperationResult;
-import com.owncloud.android.lib.common.utils.Log_OC;
-import com.owncloud.android.lib.resources.shares.OCShare;
-import com.owncloud.android.lib.resources.shares.GetRemoteSharesOperation;
-import com.owncloud.android.operations.common.SyncOperation;
-
-/**
- * Access to remote operation to get the share files/folders
- * Save the data in Database
- */
-
-public class GetSharesOperation extends SyncOperation {
-
-    private static final String TAG = GetSharesOperation.class.getSimpleName();
-
-    @Override
-    protected RemoteOperationResult run(OwnCloudClient client) {
-        GetRemoteSharesOperation operation = new GetRemoteSharesOperation();
-        RemoteOperationResult result = operation.execute(client);
-
-        if (result.isSuccess()) {
-
-            // Update DB with the response
-            Log_OC.d(TAG, "Share list size = " + result.getData().size());
-            ArrayList<OCShare> shares = new ArrayList<OCShare>();
-            for(Object obj: result.getData()) {
-                shares.add((OCShare) obj);
-            }
-
-            getStorageManager().saveSharesDB(shares);
-        }
-
-        return result;
-    }
-
-}

+ 10 - 2
src/com/owncloud/android/operations/RefreshFolderOperation.java

@@ -391,7 +391,8 @@ public class RefreshFolderOperation extends RemoteOperation {
                     Log.d(TAG, "Image " + remoteFile.getFileName() + " updated on the server");
                 }
                 updatedFile.setPublicLink(localFile.getPublicLink());
-                updatedFile.setShareByLink(localFile.isShareByLink());
+                updatedFile.setShareViaLink(localFile.isSharedViaLink());
+                updatedFile.setShareWithSharee(localFile.isSharedWithSharee());
                 updatedFile.setEtagInConflict(localFile.getEtagInConflict());
             } else {
                 // remote eTag will not be updated unless file CONTENTS are synchronized
@@ -456,12 +457,19 @@ public class RefreshFolderOperation extends RemoteOperation {
     }
 
 
+    /**
+     * Syncs the Share resources for the files contained in the folder refreshed (children, not deeper descendants).
+     *
+     * @param client    Handler of a session with an OC server.
+     * @return          The result of the remote operation retrieving the Share resources in the folder refreshed by
+     *                  the operation.
+     */
     private RemoteOperationResult refreshSharesForFolder(OwnCloudClient client) {
         RemoteOperationResult result = null;
         
         // remote request 
         GetRemoteSharesForFileOperation operation = 
-                new GetRemoteSharesForFileOperation(mLocalFolder.getRemotePath(), false, true);
+                new GetRemoteSharesForFileOperation(mLocalFolder.getRemotePath(), true, true);
         result = operation.execute(client);
         
         if (result.isSuccess()) {

+ 2 - 1
src/com/owncloud/android/operations/SynchronizeFolderOperation.java

@@ -339,7 +339,8 @@ public class SynchronizeFolderOperation extends SyncOperation {
                     Log.d(TAG, "Image " + remoteFile.getFileName() + " updated on the server");
                 }
                 updatedFile.setPublicLink(localFile.getPublicLink());
-                updatedFile.setShareByLink(localFile.isShareByLink());
+                updatedFile.setShareViaLink(localFile.isSharedViaLink());
+                updatedFile.setShareWithSharee(localFile.isSharedWithSharee());
                 updatedFile.setEtagInConflict(localFile.getEtagInConflict());
             } else {
                 // remote eTag will not be updated unless file CONTENTS are synchronized

+ 31 - 19
src/com/owncloud/android/operations/UnshareLinkOperation.java → src/com/owncloud/android/operations/UnshareOperation.java

@@ -22,7 +22,6 @@ package com.owncloud.android.operations;
 
 import android.content.Context;
 
-import com.owncloud.android.MainApp;
 import com.owncloud.android.datamodel.OCFile;
 
 import com.owncloud.android.lib.common.OwnCloudClient;
@@ -36,20 +35,26 @@ import com.owncloud.android.lib.resources.shares.ShareType;
 
 import com.owncloud.android.operations.common.SyncOperation;
 
+import java.util.ArrayList;
+
 /**
  * Unshare file/folder
  * Save the data in Database
  */
-public class UnshareLinkOperation extends SyncOperation {
+public class UnshareOperation extends SyncOperation {
 
-    private static final String TAG = UnshareLinkOperation.class.getSimpleName();
+    private static final String TAG = UnshareOperation.class.getSimpleName();
     
     private String mRemotePath;
+    private ShareType mShareType;
+    private String mShareWith;
     private Context mContext;
     
-    
-    public UnshareLinkOperation(String remotePath, Context context) {
+    public UnshareOperation(String remotePath, ShareType shareType, String shareWith,
+                                Context context) {
         mRemotePath = remotePath;
+        mShareType = shareType;
+        mShareWith = shareWith;
         mContext = context;
     }
 
@@ -59,31 +64,38 @@ public class UnshareLinkOperation extends SyncOperation {
         
         // Get Share for a file
         OCShare share = getStorageManager().getFirstShareByPathAndType(mRemotePath,
-                ShareType.PUBLIC_LINK);
+                mShareType, mShareWith);
         
         if (share != null) {
+            OCFile file = getStorageManager().getFileByPath(mRemotePath);
             RemoveRemoteShareOperation operation =
                     new RemoveRemoteShareOperation((int) share.getIdRemoteShared());
             result = operation.execute(client);
 
-            if (result.isSuccess() || result.getCode() == ResultCode.SHARE_NOT_FOUND) {
+            if (result.isSuccess()) {
                 Log_OC.d(TAG, "Share id = " + share.getIdRemoteShared() + " deleted");
 
-                OCFile file = getStorageManager().getFileByPath(mRemotePath);
-                file.setShareByLink(false);
-                file.setPublicLink("");
-                getStorageManager().saveFile(file);
-                getStorageManager().removeShare(share);
-                
-                if (result.getCode() == ResultCode.SHARE_NOT_FOUND) {
-                    if (existsFile(client, file.getRemotePath())) {
-                        result = new RemoteOperationResult(ResultCode.OK);
-                    } else {
-                        getStorageManager().removeFile(file, true, true);
+                if (mShareType == ShareType.PUBLIC_LINK) {
+                    file.setShareViaLink(false);
+                    file.setPublicLink("");
+                } else if (mShareType == ShareType.USER || mShareType == ShareType.GROUP){
+                    // Check if it is the last share
+                    ArrayList <OCShare> sharesWith = getStorageManager().
+                            getSharesWithForAFile(mRemotePath,
+                            getStorageManager().getAccount().name);
+                    if (sharesWith.size() == 1) {
+                        file.setShareWithSharee(false);
                     }
                 }
-            } 
+
+                getStorageManager().saveFile(file);
+                getStorageManager().removeShare(share);
                 
+            } else if (!existsFile(client, file.getRemotePath())) {
+                // unshare failed because file was deleted before
+                getStorageManager().removeFile(file, true, true);
+            }
+
         } else {
             result = new RemoteOperationResult(ResultCode.SHARE_NOT_FOUND);
         }

+ 47 - 53
src/com/owncloud/android/providers/FileContentProvider.java

@@ -94,8 +94,10 @@ public class FileContentProvider extends ContentProvider {
                 ProviderTableMeta.FILE_ACCOUNT_OWNER);
         mFileProjectionMap.put(ProviderTableMeta.FILE_ETAG,
                 ProviderTableMeta.FILE_ETAG);
-        mFileProjectionMap.put(ProviderTableMeta.FILE_SHARE_BY_LINK,
-                ProviderTableMeta.FILE_SHARE_BY_LINK);
+        mFileProjectionMap.put(ProviderTableMeta.FILE_SHARED_VIA_LINK,
+                ProviderTableMeta.FILE_SHARED_VIA_LINK);
+        mFileProjectionMap.put(ProviderTableMeta.FILE_SHARED_WITH_SHAREE,
+                ProviderTableMeta.FILE_SHARED_WITH_SHAREE);
         mFileProjectionMap.put(ProviderTableMeta.FILE_PUBLIC_LINK,
                 ProviderTableMeta.FILE_PUBLIC_LINK);
         mFileProjectionMap.put(ProviderTableMeta.FILE_PERMISSIONS,
@@ -308,9 +310,7 @@ public class FileContentProvider extends ContentProvider {
                 }
                 long rowId = db.insert(ProviderTableMeta.FILE_TABLE_NAME, null, values);
                 if (rowId > 0) {
-                    Uri insertedFileUri =
-                            ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_FILE, rowId);
-                    return insertedFileUri;
+                    return ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_FILE, rowId);
                 } else {
                     throw new SQLException("ERROR " + uri);
                 }
@@ -326,43 +326,16 @@ public class FileContentProvider extends ContentProvider {
             }
 
         case SHARES:
-            String path = values.getAsString(ProviderTableMeta.OCSHARES_PATH);
-            String accountNameShare= values.getAsString(ProviderTableMeta.OCSHARES_ACCOUNT_OWNER);
-            String[] projectionShare = new String[] {
-                    ProviderTableMeta._ID, ProviderTableMeta.OCSHARES_PATH,
-                    ProviderTableMeta.OCSHARES_ACCOUNT_OWNER
-            };
-            String whereShare = ProviderTableMeta.OCSHARES_PATH + "=? AND " +
-                    ProviderTableMeta.OCSHARES_ACCOUNT_OWNER + "=?";
-            String[] whereArgsShare = new String[] {path, accountNameShare};
             Uri insertedShareUri = null;
-            Cursor doubleCheckShare =
-                    query(db, uri, projectionShare, whereShare, whereArgsShare, null);
-            // ugly patch; serious refactorization is needed to reduce work in
-            // FileDataStorageManager and bring it to FileContentProvider
-            if (doubleCheckShare == null || !doubleCheckShare.moveToFirst()) {
-                if (doubleCheckShare != null) {
-                    doubleCheckShare.close();
-                }
-                long rowId = db.insert(ProviderTableMeta.OCSHARES_TABLE_NAME, null, values);
-                if (rowId >0) {
-                    insertedShareUri =
-                            ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_SHARE, rowId);
-                } else {
-                    throw new SQLException("ERROR " + uri);
-
-                }
+            long rowId = db.insert(ProviderTableMeta.OCSHARES_TABLE_NAME, null, values);
+            if (rowId >0) {
+                insertedShareUri =
+                        ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_SHARE, rowId);
             } else {
-                // file is already inserted; race condition, let's avoid a duplicated entry
-                insertedShareUri = ContentUris.withAppendedId(
-                        ProviderTableMeta.CONTENT_URI_SHARE,
-                        doubleCheckShare.getLong(
-                                doubleCheckShare.getColumnIndex(ProviderTableMeta._ID)
-                        )
-                );
-                doubleCheckShare.close();
+                throw new SQLException("ERROR " + uri);
+
             }
-            updateFilesTableAccordingToShareInsertion(db, uri, values);
+            updateFilesTableAccordingToShareInsertion(db, values);
             return insertedShareUri;
 
 
@@ -373,21 +346,23 @@ public class FileContentProvider extends ContentProvider {
     }
 
     private void updateFilesTableAccordingToShareInsertion(
-            SQLiteDatabase db, Uri uri, ContentValues shareValues
+            SQLiteDatabase db, ContentValues newShare
             ) {
         ContentValues fileValues = new ContentValues();
-        fileValues.put(
-                ProviderTableMeta.FILE_SHARE_BY_LINK,
-                ShareType.PUBLIC_LINK.getValue() ==
-                        shareValues.getAsInteger(ProviderTableMeta.OCSHARES_SHARE_TYPE) ? 1 : 0
-        );
-        String whereShare = ProviderTableMeta.FILE_PATH + "=? AND " +
+        int newShareType = newShare.getAsInteger(ProviderTableMeta.OCSHARES_SHARE_TYPE);
+        if (newShareType == ShareType.PUBLIC_LINK.getValue()) {
+            fileValues.put(ProviderTableMeta.FILE_SHARED_VIA_LINK, 1);
+        } else if (newShareType == ShareType.USER.getValue() || newShareType == ShareType.GROUP.getValue()) {
+            fileValues.put(ProviderTableMeta.FILE_SHARED_WITH_SHAREE, 1);
+        }
+
+        String where = ProviderTableMeta.FILE_PATH + "=? AND " +
                 ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?";
-        String[] whereArgsShare = new String[] {
-                shareValues.getAsString(ProviderTableMeta.OCSHARES_PATH),
-                shareValues.getAsString(ProviderTableMeta.OCSHARES_ACCOUNT_OWNER)
+        String[] whereArgs = new String[] {
+                newShare.getAsString(ProviderTableMeta.OCSHARES_PATH),
+                newShare.getAsString(ProviderTableMeta.OCSHARES_ACCOUNT_OWNER)
         };
-        db.update(ProviderTableMeta.FILE_TABLE_NAME, fileValues, whereShare, whereArgsShare);
+        db.update(ProviderTableMeta.FILE_TABLE_NAME, fileValues, where, whereArgs);
     }
 
 
@@ -579,13 +554,14 @@ public class FileContentProvider extends ContentProvider {
                     + ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA + " INTEGER, "
                     + ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA + " INTEGER, "
                     + ProviderTableMeta.FILE_ETAG + " TEXT, "
-                    + ProviderTableMeta.FILE_SHARE_BY_LINK + " INTEGER, "
+                    + ProviderTableMeta.FILE_SHARED_VIA_LINK + " INTEGER, "
                     + ProviderTableMeta.FILE_PUBLIC_LINK  + " TEXT, "
                     + ProviderTableMeta.FILE_PERMISSIONS  + " TEXT null,"
                     + ProviderTableMeta.FILE_REMOTE_ID  + " TEXT null,"
                     + ProviderTableMeta.FILE_UPDATE_THUMBNAIL  + " INTEGER," //boolean
                     + ProviderTableMeta.FILE_IS_DOWNLOADING  + " INTEGER," //boolean
-                    + ProviderTableMeta.FILE_ETAG_IN_CONFLICT + " TEXT);"
+                    + ProviderTableMeta.FILE_ETAG_IN_CONFLICT + " TEXT,"
+                    + ProviderTableMeta.FILE_SHARED_WITH_SHAREE + " INTEGER);"
                     );
 
             // Create table ocshares
@@ -684,7 +660,7 @@ public class FileContentProvider extends ContentProvider {
                 db.beginTransaction();
                 try {
                     db .execSQL("ALTER TABLE " + ProviderTableMeta.FILE_TABLE_NAME +
-                            " ADD COLUMN " + ProviderTableMeta.FILE_SHARE_BY_LINK + " INTEGER " +
+                            " ADD COLUMN " + ProviderTableMeta.FILE_SHARED_VIA_LINK + " INTEGER " +
                             " DEFAULT 0");
 
                     db .execSQL("ALTER TABLE " + ProviderTableMeta.FILE_TABLE_NAME +
@@ -793,6 +769,24 @@ public class FileContentProvider extends ContentProvider {
                     db .execSQL("ALTER TABLE " + ProviderTableMeta.FILE_TABLE_NAME +
                             " ADD COLUMN " + ProviderTableMeta.FILE_ETAG_IN_CONFLICT + " TEXT " +
                             " DEFAULT NULL");
+
+                    upgraded = true;
+                    db.setTransactionSuccessful();
+                } finally {
+                    db.endTransaction();
+                }
+            }
+            if (!upgraded)
+                Log_OC.i("SQL", "OUT of the ADD in onUpgrade; oldVersion == " + oldVersion +
+                        ", newVersion == " + newVersion);
+
+            if (oldVersion < 12 && newVersion >= 12) {
+                Log_OC.i("SQL", "Entering in the #12 ADD in onUpgrade");
+                db.beginTransaction();
+                try {
+                    db .execSQL("ALTER TABLE " + ProviderTableMeta.FILE_TABLE_NAME +
+                            " ADD COLUMN " + ProviderTableMeta.FILE_SHARED_WITH_SHAREE + " INTEGER " +
+                            " DEFAULT 0");
                     upgraded = true;
                     db.setTransactionSuccessful();
                 } finally {

+ 197 - 0
src/com/owncloud/android/providers/UsersAndGroupsSearchProvider.java

@@ -0,0 +1,197 @@
+/**
+ *   ownCloud Android client application
+ *
+ *   @author David A. Velasco
+ *   Copyright (C) 2015 ownCloud Inc.
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License version 2,
+ *   as published by the Free Software Foundation.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+package com.owncloud.android.providers;
+
+import android.accounts.Account;
+import android.app.SearchManager;
+import android.content.ContentProvider;
+import android.content.ContentValues;
+import android.content.UriMatcher;
+import android.database.Cursor;
+import android.database.MatrixCursor;
+import android.net.Uri;
+import android.provider.BaseColumns;
+import android.support.annotation.Nullable;
+
+import com.owncloud.android.R;
+import com.owncloud.android.authentication.AccountUtils;
+import com.owncloud.android.lib.common.operations.RemoteOperationResult;
+import com.owncloud.android.lib.common.utils.Log_OC;
+import com.owncloud.android.lib.resources.shares.GetRemoteShareesOperation;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+
+/**
+ * Content provider for search suggestions, to search for users and groups existing in an ownCloud server.
+ */
+public class UsersAndGroupsSearchProvider extends ContentProvider {
+
+    private static final String TAG = UsersAndGroupsSearchProvider.class.getSimpleName();
+
+    private static final String[] COLUMNS = {
+        BaseColumns._ID,
+        SearchManager.SUGGEST_COLUMN_TEXT_1,
+        SearchManager.SUGGEST_COLUMN_INTENT_DATA
+    };
+
+    private static final int SEARCH = 1;
+
+    private static final int RESULTS_PER_PAGE = 50;
+    private static final int REQUESTED_PAGE = 1;
+
+    public static final String AUTHORITY = UsersAndGroupsSearchProvider.class.getCanonicalName();
+    public static final String ACTION_SHARE_WITH = AUTHORITY + ".action.SHARE_WITH";
+    public static final String DATA_USER = AUTHORITY + ".data.user";
+    public static final String DATA_GROUP = AUTHORITY + ".data.group";
+
+    private UriMatcher mUriMatcher;
+
+    @Nullable
+    @Override
+    public String getType(Uri uri) {
+        // TODO implement
+        return null;
+    }
+
+    @Override
+    public boolean onCreate() {
+        mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
+        mUriMatcher.addURI(AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY + "/*", SEARCH);
+        return true;
+    }
+
+    /**
+     * TODO description
+     *
+     * Reference: http://developer.android.com/guide/topics/search/adding-custom-suggestions.html#CustomContentProvider
+     *
+     * @param uri           Content {@link Uri}, formattted as
+     *                      "content://com.owncloud.android.providers.UsersAndGroupsSearchProvider/" +
+     *                      {@link android.app.SearchManager#SUGGEST_URI_PATH_QUERY} + "/" + 'userQuery'
+     * @param projection    Expected to be NULL.
+     * @param selection     Expected to be NULL.
+     * @param selectionArgs Expected to be NULL.
+     * @param sortOrder     Expected to be NULL.
+     * @return              Cursor with users and groups in the ownCloud server that match 'userQuery'.
+     */
+    @Nullable
+    @Override
+    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
+        Log_OC.d(TAG, "query received in thread " + Thread.currentThread().getName());
+
+        int match = mUriMatcher.match(uri);
+        switch (match) {
+            case SEARCH:
+                return searchForUsersOrGroups(uri);
+
+            default:
+                return null;
+        }
+    }
+
+    private Cursor searchForUsersOrGroups(Uri uri) {
+        MatrixCursor response = null;
+
+
+        String userQuery = uri.getLastPathSegment().toLowerCase();
+
+
+        /// need to trust on the AccountUtils to get the current account since the query in the client side is not
+        /// directly started by our code, but from SearchView implementation
+        Account account = AccountUtils.getCurrentOwnCloudAccount(getContext());
+
+        /// request to the OC server about users and groups matching userQuery
+        GetRemoteShareesOperation searchRequest = new GetRemoteShareesOperation(
+                userQuery, REQUESTED_PAGE, RESULTS_PER_PAGE
+        );
+        RemoteOperationResult result = searchRequest.execute(account, getContext());
+        List<JSONObject> names = new ArrayList<JSONObject>();
+        if (result.isSuccess()) {
+            for (Object o : result.getData()) {
+                // Get JSonObjects from response
+                names.add((JSONObject) o);
+            }
+        }
+
+        /// convert the responses from the OC server to the expected format
+        if (names.size() > 0) {
+            response = new MatrixCursor(COLUMNS);
+            Iterator<JSONObject> namesIt = names.iterator();
+            int count = 0;
+            JSONObject item;
+            String displayName;
+            Uri dataUri;
+            Uri userBaseUri = new Uri.Builder().scheme("content").authority(DATA_USER).build();
+            Uri groupBaseUri = new Uri.Builder().scheme("content").authority(DATA_GROUP).build();
+            try {
+                while (namesIt.hasNext()) {
+                    item = namesIt.next();
+                    String userName = item.getString(GetRemoteShareesOperation.PROPERTY_LABEL);
+                    JSONObject value = item.getJSONObject(GetRemoteShareesOperation.NODE_VALUE);
+                    byte type = (byte) value.getInt(GetRemoteShareesOperation.PROPERTY_SHARE_TYPE);
+                    String shareWith = value.getString(GetRemoteShareesOperation.PROPERTY_SHARE_WITH);
+                    if (GetRemoteShareesOperation.GROUP_TYPE.equals(type)) {
+                        displayName = getContext().getString(R.string.share_group_clarification, userName);
+                        dataUri = Uri.withAppendedPath(groupBaseUri, shareWith);
+                    } else {
+                        displayName = userName;
+                        dataUri = Uri.withAppendedPath(userBaseUri, shareWith);
+                    }
+                    response.newRow()
+                            .add(count++)             // BaseColumns._ID
+                            .add(displayName)         // SearchManager.SUGGEST_COLUMN_TEXT_1
+                            .add(dataUri);
+                }
+            } catch (JSONException e) {
+                Log_OC.e(TAG, "Exception while parsing data of users/groups", e);
+            }
+        }
+
+        return response;
+    }
+
+    @Nullable
+    @Override
+    public Uri insert(Uri uri, ContentValues values) {
+        // TODO implementation
+        return null;
+    }
+
+    @Override
+    public int delete(Uri uri, String selection, String[] selectionArgs) {
+        // TODO implementation
+        return 0;
+    }
+
+    @Override
+    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
+        // TODO implementation
+        return 0;
+    }
+
+}

+ 34 - 11
src/com/owncloud/android/services/OperationsService.java

@@ -54,7 +54,8 @@ import com.owncloud.android.lib.resources.status.OwnCloudVersion;
 import com.owncloud.android.lib.resources.users.GetRemoteUserNameOperation;
 import com.owncloud.android.operations.CopyFileOperation;
 import com.owncloud.android.operations.CreateFolderOperation;
-import com.owncloud.android.operations.CreateShareOperation;
+import com.owncloud.android.operations.CreateShareViaLinkOperation;
+import com.owncloud.android.operations.CreateShareWithShareeOperation;
 import com.owncloud.android.operations.GetServerInfoOperation;
 import com.owncloud.android.operations.MoveFileOperation;
 import com.owncloud.android.operations.OAuth2GetAccessToken;
@@ -62,7 +63,7 @@ import com.owncloud.android.operations.RemoveFileOperation;
 import com.owncloud.android.operations.RenameFileOperation;
 import com.owncloud.android.operations.SynchronizeFileOperation;
 import com.owncloud.android.operations.SynchronizeFolderOperation;
-import com.owncloud.android.operations.UnshareLinkOperation;
+import com.owncloud.android.operations.UnshareOperation;
 import com.owncloud.android.operations.common.SyncOperation;
 
 import java.io.IOException;
@@ -88,10 +89,13 @@ public class OperationsService extends Service {
     public static final String EXTRA_NEW_PARENT_PATH = "NEW_PARENT_PATH";
     public static final String EXTRA_FILE = "FILE";
     public static final String EXTRA_PASSWORD_SHARE = "PASSWORD_SHARE";
+    public static final String EXTRA_SHARE_TYPE = "SHARE_TYPE";
+    public static final String EXTRA_SHARE_WITH = "SHARE_WITH";
 
     public static final String EXTRA_COOKIE = "COOKIE";
 
-    public static final String ACTION_CREATE_SHARE = "CREATE_SHARE";
+    public static final String ACTION_CREATE_SHARE_VIA_LINK = "CREATE_SHARE_VIA_LINK";
+    public static final String ACTION_CREATE_SHARE_WITH_SHAREE = "CREATE_SHARE_WITH_SHAREE";
     public static final String ACTION_UNSHARE = "UNSHARE";
     public static final String ACTION_GET_SERVER_INFO = "GET_SERVER_INFO";
     public static final String ACTION_OAUTH2_GET_ACCESS_TOKEN = "OAUTH2_GET_ACCESS_TOKEN";
@@ -110,7 +114,6 @@ public class OperationsService extends Service {
             ".OPERATION_FINISHED";
 
 
-
     private ConcurrentMap<Integer, Pair<RemoteOperation, RemoteOperationResult>>
             mUndispatchedFinishedOperations =
             new ConcurrentHashMap<Integer, Pair<RemoteOperation, RemoteOperationResult>>();
@@ -548,22 +551,42 @@ public class OperationsService extends Service {
                 );
                 
                 String action = operationIntent.getAction();
-                if (action.equals(ACTION_CREATE_SHARE)) {  // Create Share
+                if (action.equals(ACTION_CREATE_SHARE_VIA_LINK)) {  // Create public share via link
                     String remotePath = operationIntent.getStringExtra(EXTRA_REMOTE_PATH);
                     String password = operationIntent.getStringExtra(EXTRA_PASSWORD_SHARE);
                     Intent sendIntent = operationIntent.getParcelableExtra(EXTRA_SEND_INTENT);
                     if (remotePath.length() > 0) {
-                        operation = new CreateShareOperation(OperationsService.this, remotePath,
-                                ShareType.PUBLIC_LINK,
-                                "", false, password, 1, sendIntent);
+                        operation = new CreateShareViaLinkOperation(
+                                remotePath,
+                                password,
+                                sendIntent
+                        );
                     }
 
+                } else if (action.equals(ACTION_CREATE_SHARE_WITH_SHAREE)) {  // Create private share with user or group
+                        String remotePath = operationIntent.getStringExtra(EXTRA_REMOTE_PATH);
+                        String shareeName = operationIntent.getStringExtra(EXTRA_SHARE_WITH);
+                        ShareType shareType = (ShareType) operationIntent.getSerializableExtra(EXTRA_SHARE_TYPE);
+                        if (remotePath.length() > 0) {
+                            operation = new CreateShareWithShareeOperation(
+                                    remotePath,
+                                    shareeName,
+                                    shareType
+                            );
+                        }
+
                 } else if (action.equals(ACTION_UNSHARE)) {  // Unshare file
                     String remotePath = operationIntent.getStringExtra(EXTRA_REMOTE_PATH);
+                    ShareType shareType = (ShareType) operationIntent.
+                            getSerializableExtra(EXTRA_SHARE_TYPE);
+                    String shareWith = operationIntent.getStringExtra(EXTRA_SHARE_WITH);
                     if (remotePath.length() > 0) {
-                        operation = new UnshareLinkOperation(
-                                remotePath, 
-                                OperationsService.this);
+                        operation = new UnshareOperation(
+                                remotePath,
+                                shareType,
+                                shareWith,
+                                OperationsService.this
+                        );
                     }
                     
                 } else if (action.equals(ACTION_GET_SERVER_INFO)) { 

+ 44 - 46
src/com/owncloud/android/ui/activity/FileActivity.java

@@ -43,7 +43,6 @@ import android.support.v4.widget.DrawerLayout;
 import android.support.v7.app.ActionBar;
 import android.support.v7.app.ActionBarDrawerToggle;
 import android.support.v7.app.AppCompatActivity;
-import android.util.Log;
 import android.view.View;
 import android.widget.AdapterView;
 import android.widget.ListView;
@@ -68,10 +67,12 @@ import com.owncloud.android.lib.common.operations.RemoteOperation;
 import com.owncloud.android.lib.common.operations.RemoteOperationResult;
 import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;
 import com.owncloud.android.lib.common.utils.Log_OC;
-import com.owncloud.android.operations.CreateShareOperation;
+import com.owncloud.android.operations.CreateShareViaLinkOperation;
+import com.owncloud.android.operations.CreateShareWithShareeOperation;
+import com.owncloud.android.operations.GetSharesForFileOperation;
 import com.owncloud.android.operations.SynchronizeFileOperation;
 import com.owncloud.android.operations.SynchronizeFolderOperation;
-import com.owncloud.android.operations.UnshareLinkOperation;
+import com.owncloud.android.operations.UnshareOperation;
 import com.owncloud.android.services.OperationsService;
 import com.owncloud.android.services.OperationsService.OperationsServiceBinder;
 import com.owncloud.android.ui.NavigationDrawerItem;
@@ -100,12 +101,13 @@ public class FileActivity extends AppCompatActivity
     public static final String TAG = FileActivity.class.getSimpleName();
 
     private static final String DIALOG_WAIT_TAG = "DIALOG_WAIT";
+
     private static final String KEY_WAITING_FOR_OP_ID = "WAITING_FOR_OP_ID";
     private static final String DIALOG_SHARE_PASSWORD = "DIALOG_SHARE_PASSWORD";
     private static final String KEY_TRY_SHARE_AGAIN = "TRY_SHARE_AGAIN";
     private static final String KEY_ACTION_BAR_TITLE = "ACTION_BAR_TITLE";
 
-    protected static final long DELAY_TO_REQUEST_OPERATION_ON_ACTIVITY_RESULTS = 200;
+    protected static final long DELAY_TO_REQUEST_OPERATIONS_LATER = 200;
 
 
     /** OwnCloud {@link Account} where the main {@link OCFile} handled by the activity is located.*/
@@ -182,7 +184,9 @@ public class FileActivity extends AppCompatActivity
                     savedInstanceState.getLong(KEY_WAITING_FOR_OP_ID, Long.MAX_VALUE)
                     );
             mTryShareAgain = savedInstanceState.getBoolean(KEY_TRY_SHARE_AGAIN);
-            getSupportActionBar().setTitle(savedInstanceState.getString(KEY_ACTION_BAR_TITLE));
+            if (getSupportActionBar() != null) {
+                getSupportActionBar().setTitle(savedInstanceState.getString(KEY_ACTION_BAR_TITLE));
+            }
         } else {
             account = getIntent().getParcelableExtra(FileActivity.EXTRA_ACCOUNT);
             mFile = getIntent().getParcelableExtra(FileActivity.EXTRA_FILE);
@@ -561,7 +565,7 @@ public class FileActivity extends AppCompatActivity
         outState.putBoolean(FileActivity.EXTRA_FROM_NOTIFICATION, mFromNotification);
         outState.putLong(KEY_WAITING_FOR_OP_ID, mFileOperationsHelper.getOpIdWaitingFor());
         outState.putBoolean(KEY_TRY_SHARE_AGAIN, mTryShareAgain);
-        if(getSupportActionBar().getTitle() != null) {
+        if(getSupportActionBar() != null && getSupportActionBar().getTitle() != null) {
             // Null check in case the actionbar is used in ActionBar.NAVIGATION_MODE_LIST
             // since it doesn't have a title then
             outState.putString(KEY_ACTION_BAR_TITLE, getSupportActionBar().getTitle().toString());
@@ -719,6 +723,8 @@ public class FileActivity extends AppCompatActivity
 
         mFileOperationsHelper.setOpIdWaitingFor(Long.MAX_VALUE);
 
+        dismissLoadingDialog();
+
         if (!result.isSuccess() && (
                 result.getCode() == ResultCode.UNAUTHORIZED ||
                 result.isIdPRedirection() ||
@@ -736,18 +742,37 @@ public class FileActivity extends AppCompatActivity
             }
             mTryShareAgain = false;
 
-        } else if (operation instanceof CreateShareOperation) {
-            onCreateShareOperationFinish((CreateShareOperation) operation, result);
+        } else if (operation == null ||
+                operation instanceof CreateShareWithShareeOperation ||
+                operation instanceof UnshareOperation ||
+                operation instanceof SynchronizeFolderOperation
+                ) {
+            if (result.isSuccess()) {
+                updateFileFromDB();
 
-        } else if (operation instanceof UnshareLinkOperation) {
-            onUnshareLinkOperationFinish((UnshareLinkOperation)operation, result);
+            } else if (result.getCode() != ResultCode.CANCELLED) {
+                Toast t = Toast.makeText(this,
+                        ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()),
+                        Toast.LENGTH_LONG);
+                t.show();
+            }
+
+        } else if (operation instanceof CreateShareViaLinkOperation) {
+            onCreateShareViaLinkOperationFinish((CreateShareViaLinkOperation) operation, result);
 
-        } else if (operation instanceof SynchronizeFolderOperation) {
-            onSynchronizeFolderOperationFinish((SynchronizeFolderOperation)operation, result);
+        } else if (operation instanceof SynchronizeFileOperation) {
+            onSynchronizeFileOperationFinish((SynchronizeFileOperation) operation, result);
 
-        }else if (operation instanceof SynchronizeFileOperation) {
-            onSynchronizeFileOperationFinish((SynchronizeFileOperation)operation, result);
+        } else if (operation instanceof GetSharesForFileOperation) {
+            if (result.isSuccess()) {
+                updateFileFromDB();
 
+            } else if (result.getCode() != ResultCode.SHARE_NOT_FOUND) {
+                Toast t = Toast.makeText(this,
+                        ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()),
+                        Toast.LENGTH_LONG);
+                t.show();
+            }
         }
     }
 
@@ -763,14 +788,13 @@ public class FileActivity extends AppCompatActivity
 
 
 
-    private void onCreateShareOperationFinish(CreateShareOperation operation,
-                                              RemoteOperationResult result) {
-        dismissLoadingDialog();
+    private void onCreateShareViaLinkOperationFinish(CreateShareViaLinkOperation operation,
+                                                     RemoteOperationResult result) {
         if (result.isSuccess()) {
             mTryShareAgain = false;
             updateFileFromDB();
 
-            Intent sendIntent = operation.getSendIntent();
+            Intent sendIntent = operation.getSendIntentWithSubject(this);
             startActivity(sendIntent);
         } else {
             // Detect Failure (403) --> needs Password
@@ -796,34 +820,8 @@ public class FileActivity extends AppCompatActivity
         }
     }
 
-
-    private void onUnshareLinkOperationFinish(UnshareLinkOperation operation,
-                                              RemoteOperationResult result) {
-        dismissLoadingDialog();
-
-        if (result.isSuccess()){
-            updateFileFromDB();
-
-        } else {
-            Toast t = Toast.makeText(this, ErrorMessageAdapter.getErrorCauseMessage(result,
-                            operation, getResources()), Toast.LENGTH_LONG);
-            t.show();
-        }
-    }
-
-    private void onSynchronizeFolderOperationFinish(
-            SynchronizeFolderOperation operation, RemoteOperationResult result
-    ) {
-        if (!result.isSuccess() && result.getCode() != ResultCode.CANCELLED){
-            Toast t = Toast.makeText(this, ErrorMessageAdapter.getErrorCauseMessage(result,
-                            operation, getResources()), Toast.LENGTH_LONG);
-            t.show();
-        }
-    }
-
     private void onSynchronizeFileOperationFinish(SynchronizeFileOperation operation,
                                                   RemoteOperationResult result) {
-        dismissLoadingDialog();
         OCFile syncedFile = operation.getLocalFile();
         if (!result.isSuccess()) {
             if (result.getCode() == ResultCode.SYNC_CONFLICT) {
@@ -855,9 +853,9 @@ public class FileActivity extends AppCompatActivity
     /**
      * Show loading dialog
      */
-    public void showLoadingDialog() {
+    public void showLoadingDialog(String message) {
         // Construct dialog
-        LoadingDialog loading = new LoadingDialog(getResources().getString(R.string.wait_a_moment));
+        LoadingDialog loading = new LoadingDialog(message);
         FragmentManager fm = getSupportFragmentManager();
         FragmentTransaction ft = fm.beginTransaction();
         loading.show(ft, DIALOG_WAIT_TAG);

+ 73 - 45
src/com/owncloud/android/ui/activity/FileDisplayActivity.java

@@ -79,13 +79,14 @@ import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCo
 import com.owncloud.android.lib.common.utils.Log_OC;
 import com.owncloud.android.operations.CopyFileOperation;
 import com.owncloud.android.operations.CreateFolderOperation;
-import com.owncloud.android.operations.CreateShareOperation;
+import com.owncloud.android.operations.CreateShareViaLinkOperation;
+import com.owncloud.android.operations.CreateShareWithShareeOperation;
 import com.owncloud.android.operations.MoveFileOperation;
 import com.owncloud.android.operations.RefreshFolderOperation;
 import com.owncloud.android.operations.RemoveFileOperation;
 import com.owncloud.android.operations.RenameFileOperation;
 import com.owncloud.android.operations.SynchronizeFileOperation;
-import com.owncloud.android.operations.UnshareLinkOperation;
+import com.owncloud.android.operations.UnshareOperation;
 import com.owncloud.android.services.observer.FileObserverService;
 import com.owncloud.android.syncadapter.FileSyncAdapter;
 import com.owncloud.android.ui.dialog.ConfirmationDialogFragment;
@@ -116,8 +117,6 @@ public class FileDisplayActivity extends HookActivity
         implements FileFragment.ContainerActivity,
         OnSslUntrustedCertListener, OnEnforceableRefreshListener {
 
-
-
     private SyncBroadcastReceiver mSyncBroadcastReceiver;
     private UploadFinishReceiver mUploadFinishReceiver;
     private DownloadFinishReceiver mDownloadFinishReceiver;
@@ -226,6 +225,13 @@ public class FileDisplayActivity extends HookActivity
         Log_OC.v(TAG, "onStart() end");
     }
 
+    @Override
+    protected void onStop() {
+        Log_OC.v(TAG, "onStop() start");
+        super.onStop();
+        Log_OC.v(TAG, "onStop() end");
+    }
+
     @Override
     protected void onDestroy() {
         Log_OC.v(TAG, "onDestroy() start");
@@ -631,7 +637,7 @@ public class FileDisplayActivity extends HookActivity
                             requestMoveOperation(fData, fResultCode);
                         }
                     },
-                    DELAY_TO_REQUEST_OPERATION_ON_ACTIVITY_RESULTS
+                    DELAY_TO_REQUEST_OPERATIONS_LATER
             );
 
         } else if (requestCode == ACTION_COPY_FILES && resultCode == RESULT_OK) {
@@ -645,7 +651,7 @@ public class FileDisplayActivity extends HookActivity
                             requestCopyOperation(fData, fResultCode);
                         }
                     },
-                    DELAY_TO_REQUEST_OPERATION_ON_ACTIVITY_RESULTS
+                    DELAY_TO_REQUEST_OPERATIONS_LATER
             );
 
         } else {
@@ -978,6 +984,7 @@ public class FileDisplayActivity extends HookActivity
                             }
 
                         }
+
                     }
                     removeStickyBroadcast(intent);
                     Log_OC.d(TAG, "Setting progress visibility to " + mSyncInProgress);
@@ -1341,11 +1348,14 @@ public class FileDisplayActivity extends HookActivity
         } else if (operation instanceof CreateFolderOperation) {
             onCreateFolderOperationFinish((CreateFolderOperation) operation, result);
 
-        } else if (operation instanceof CreateShareOperation) {
-            onCreateShareOperationFinish((CreateShareOperation) operation, result);
+        } else if (operation instanceof CreateShareViaLinkOperation ||
+                    operation instanceof CreateShareWithShareeOperation ) {
 
-        } else if (operation instanceof UnshareLinkOperation) {
-            onUnshareLinkOperationFinish((UnshareLinkOperation) operation, result);
+            refreshShowDetails();
+            refreshListOfFilesFragment();
+
+        } else if (operation instanceof UnshareOperation) {
+            onUnshareLinkOperationFinish((UnshareOperation) operation, result);
 
         } else if (operation instanceof MoveFileOperation) {
             onMoveFileOperationFinish((MoveFileOperation) operation, result);
@@ -1355,15 +1365,8 @@ public class FileDisplayActivity extends HookActivity
         }
 
     }
-    private void onCreateShareOperationFinish(CreateShareOperation operation,
-                                              RemoteOperationResult result) {
-        if (result.isSuccess()) {
-            refreshShowDetails();
-            refreshListOfFilesFragment();
-        }
-    }
 
-    private void onUnshareLinkOperationFinish(UnshareLinkOperation operation,
+    private void onUnshareLinkOperationFinish(UnshareOperation operation,
                                               RemoteOperationResult result) {
         if (result.isSuccess()) {
             refreshShowDetails();
@@ -1404,8 +1407,6 @@ public class FileDisplayActivity extends HookActivity
      */
     private void onRemoveFileOperationFinish(RemoveFileOperation operation,
                                              RemoteOperationResult result) {
-        dismissLoadingDialog();
-
         Toast msg = Toast.makeText(this,
                 ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()),
                 Toast.LENGTH_LONG);
@@ -1444,10 +1445,8 @@ public class FileDisplayActivity extends HookActivity
     private void onMoveFileOperationFinish(MoveFileOperation operation,
                                            RemoteOperationResult result) {
         if (result.isSuccess()) {
-            dismissLoadingDialog();
             refreshListOfFilesFragment();
         } else {
-            dismissLoadingDialog();
             try {
                 Toast msg = Toast.makeText(FileDisplayActivity.this,
                         ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()),
@@ -1469,10 +1468,8 @@ public class FileDisplayActivity extends HookActivity
      */
     private void onCopyFileOperationFinish(CopyFileOperation operation, RemoteOperationResult result) {
         if (result.isSuccess()) {
-            dismissLoadingDialog();
             refreshListOfFilesFragment();
         } else {
-            dismissLoadingDialog();
             try {
                 Toast msg = Toast.makeText(FileDisplayActivity.this,
                         ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()),
@@ -1494,7 +1491,6 @@ public class FileDisplayActivity extends HookActivity
      */
     private void onRenameFileOperationFinish(RenameFileOperation operation,
                                              RemoteOperationResult result) {
-        dismissLoadingDialog();
         OCFile renamedFile = operation.getFile();
         if (result.isSuccess()) {
             FileFragment details = getSecondFragment();
@@ -1563,10 +1559,8 @@ public class FileDisplayActivity extends HookActivity
     private void onCreateFolderOperationFinish(CreateFolderOperation operation,
                                                RemoteOperationResult result) {
         if (result.isSuccess()) {
-            dismissLoadingDialog();
             refreshListOfFilesFragment();
         } else {
-            dismissLoadingDialog();
             try {
                 Toast msg = Toast.makeText(FileDisplayActivity.this,
                         ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()),
@@ -1629,26 +1623,60 @@ public class FileDisplayActivity extends HookActivity
         return null;
     }
 
-    public void startSyncFolderOperation(OCFile folder, boolean ignoreETag) {
-        long currentSyncTime = System.currentTimeMillis();
-
-        mSyncInProgress = true;
-
-        // perform folder synchronization
-        RemoteOperation synchFolderOp = new RefreshFolderOperation( folder,
-                currentSyncTime,
-                false,
-                getFileOperationsHelper().isSharedSupported(),
-                ignoreETag,
-                getStorageManager(),
-                getAccount(),
-                getApplicationContext()
+    /**
+     * Starts an operation to refresh the requested folder.
+     *
+     * The operation is run in a new background thread created on the fly.
+     *
+     * The refresh updates is a "light sync": properties of regular files in folder are updated (including
+     * associated shares), but not their contents. Only the contents of files marked to be kept-in-sync are
+     * synchronized too.
+     *
+     * @param folder        Folder to refresh.
+     * @param ignoreETag    If 'true', the data from the server will be fetched and sync'ed even if the eTag
+     *                      didn't change.
+     */
+    public void startSyncFolderOperation(final OCFile folder, final boolean ignoreETag) {
+
+        // the execution is slightly delayed to allow the activity get the window focus if it's being started
+        // or if the method is called from a dialog that is being dismissed
+        getHandler().postDelayed(
+                new Runnable() {
+                    @Override
+                    public void run() {
+                        if (hasWindowFocus()) {
+                            long currentSyncTime = System.currentTimeMillis();
+                            mSyncInProgress = true;
+
+                            // perform folder synchronization
+                            RemoteOperation synchFolderOp = new RefreshFolderOperation(folder,
+                                    currentSyncTime,
+                                    false,
+                                    getFileOperationsHelper().isSharedSupported(),
+                                    ignoreETag,
+                                    getStorageManager(),
+                                    getAccount(),
+                                    getApplicationContext()
+                            );
+                            synchFolderOp.execute(
+                                    getAccount(),
+                                    MainApp.getAppContext(),
+                                    FileDisplayActivity.this,
+                                    null,
+                                    null
+                            );
+
+                            mProgressBar.setIndeterminate(true);
+
+                            setBackgroundText();
+
+                        }   // else: NOTHING ; lets' not refresh when the user rotates the device but there is
+                        // another window floating over
+                    }
+                },
+                DELAY_TO_REQUEST_OPERATIONS_LATER
         );
-        synchFolderOp.execute(getAccount(), MainApp.getAppContext(), this, null, null);
-
-        mProgressBar.setIndeterminate(true);
 
-        setBackgroundText();
     }
 
     /**

+ 6 - 9
src/com/owncloud/android/ui/activity/FolderPickerActivity.java

@@ -38,7 +38,6 @@ import android.view.MenuInflater;
 import android.view.MenuItem;
 import android.view.View;
 import android.view.View.OnClickListener;
-import android.view.Window;
 import android.widget.Button;
 import android.widget.ProgressBar;
 import android.widget.Toast;
@@ -350,9 +349,9 @@ public class FolderPickerActivity extends FileActivity implements FileFragment.C
         actionBar.setDisplayHomeAsUpEnabled(!atRoot);
         actionBar.setHomeButtonEnabled(!atRoot);
         actionBar.setTitle(
-            atRoot 
-                ? getString(R.string.default_display_name_for_root_folder) 
-                : currentDir.getFileName()
+                atRoot
+                        ? getString(R.string.default_display_name_for_root_folder)
+                        : currentDir.getFileName()
         );
     }
 
@@ -390,7 +389,7 @@ public class FolderPickerActivity extends FileActivity implements FileFragment.C
         super.onRemoteOperationFinish(operation, result);
         
         if (operation instanceof CreateFolderOperation) {
-            onCreateFolderOperationFinish((CreateFolderOperation)operation, result);
+            onCreateFolderOperationFinish((CreateFolderOperation) operation, result);
             
         }
     }
@@ -408,10 +407,8 @@ public class FolderPickerActivity extends FileActivity implements FileFragment.C
             ) {
         
         if (result.isSuccess()) {
-            dismissLoadingDialog();
             refreshListOfFilesFragment();
         } else {
-            dismissLoadingDialog();
             try {
                 Toast msg = Toast.makeText(FolderPickerActivity.this, 
                         ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()), 
@@ -542,9 +539,9 @@ public class FolderPickerActivity extends FileActivity implements FileFragment.C
     
 
     /**
-     * Shows the information of the {@link OCFile} received as a 
+     * Shows the information of the {@link OCFile} received as a
      * parameter in the second fragment.
-     * 
+     *
      * @param file          {@link OCFile} whose details will be shown
      */
     @Override

+ 197 - 0
src/com/owncloud/android/ui/activity/ShareActivity.java

@@ -0,0 +1,197 @@
+/**
+ *   ownCloud Android client application
+ *
+ *   @author masensio
+ *   @author David A. Velasco
+ *   Copyright (C) 2015 ownCloud Inc.
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License version 2,
+ *   as published by the Free Software Foundation.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.ui.activity;
+
+import android.app.SearchManager;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentTransaction;
+
+import com.owncloud.android.R;
+import com.owncloud.android.lib.common.utils.Log_OC;
+import com.owncloud.android.providers.UsersAndGroupsSearchProvider;
+
+import com.owncloud.android.lib.common.operations.RemoteOperation;
+import com.owncloud.android.lib.common.operations.RemoteOperationResult;
+import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.lib.resources.shares.OCShare;
+import com.owncloud.android.lib.resources.shares.ShareType;
+import com.owncloud.android.ui.fragment.SearchShareesFragment;
+import com.owncloud.android.ui.fragment.ShareFileFragment;
+import com.owncloud.android.utils.GetShareWithUsersAsyncTask;
+
+
+/**
+ * Activity for sharing files
+ */
+
+public class ShareActivity extends FileActivity
+        implements ShareFileFragment.OnShareFragmentInteractionListener,
+        SearchShareesFragment.OnSearchFragmentInteractionListener {
+
+    private static final String TAG = ShareActivity.class.getSimpleName();
+
+    private static final String TAG_SHARE_FRAGMENT = "SHARE_FRAGMENT";
+    private static final String TAG_SEARCH_FRAGMENT = "SEARCH_USER_AND_GROUPS_FRAGMENT";
+
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        setContentView(R.layout.share_activity);
+
+        FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
+
+        if (savedInstanceState == null) {
+            // Add Share fragment on first creation
+            Fragment fragment = ShareFileFragment.newInstance(getFile(), getAccount());
+            ft.replace(R.id.share_fragment_container, fragment, TAG_SHARE_FRAGMENT);
+            ft.commit();
+        }
+
+    }
+
+    protected void onAccountSet(boolean stateWasRecovered) {
+        super.onAccountSet(stateWasRecovered);
+
+        // Load data into the list
+        Log_OC.d(TAG, "Refreshing lists on account set");
+        refreshUsersInLists();
+
+        // Request for a refresh of the data through the server (starts an Async Task)
+        refreshUsersOrGroupsListFromServer();
+    }
+
+
+    @Override
+    protected void onNewIntent(Intent intent) {
+        // Verify the action and get the query
+        if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
+            String query = intent.getStringExtra(SearchManager.QUERY);
+            Log_OC.w(TAG, "Ignored Intent requesting to query for " + query);
+
+        } else if (UsersAndGroupsSearchProvider.ACTION_SHARE_WITH.equals(intent.getAction())) {
+            Uri data = intent.getData();
+            doShareWith(
+                    data.getLastPathSegment(),
+                    UsersAndGroupsSearchProvider.DATA_GROUP.equals(data.getAuthority())
+            );
+
+        } else {
+            Log_OC.wtf(TAG, "Unexpected intent " + intent.toString());
+        }
+    }
+
+    private void doShareWith(String shareeName, boolean isGroup) {
+        getFileOperationsHelper().shareFileWithSharee(
+                getFile(),
+                shareeName,
+                (isGroup ? ShareType.GROUP : ShareType.USER)
+        );
+    }
+
+    @Override
+    public void showSearchUsersAndGroups() {
+        // replace ShareFragment with SearchFragment on demand
+        FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
+        Fragment searchFragment = SearchShareesFragment.newInstance(getFile(), getAccount());
+        ft.replace(R.id.share_fragment_container, searchFragment, TAG_SEARCH_FRAGMENT);
+        ft.addToBackStack(null);    // BACK button will recover the ShareFragment
+        ft.commit();
+    }
+
+    @Override
+    // Call to Unshare operation
+    public void unshareWith(OCShare share) {
+        OCFile file = getFile();
+        getFileOperationsHelper().unshareFileWithUserOrGroup(file, share.getShareType(), share.getShareWith());
+    }
+
+    /**
+     * Get users and groups from the server to fill in the "share with" list
+     */
+    @Override
+    public void refreshUsersOrGroupsListFromServer() {
+        // Show loading
+        showLoadingDialog(getString(R.string.common_loading));
+        // Get Users and Groups
+        GetShareWithUsersAsyncTask getTask = new GetShareWithUsersAsyncTask(this);
+        Object[] params = {getFile(), getAccount(), getStorageManager()};
+        getTask.execute(params);
+    }
+
+    /**
+     * Updates the view associated to the activity after the finish of some operation over files
+     * in the current account.
+     *
+     * @param operation Removal operation performed.
+     * @param result    Result of the removal.
+     */
+    @Override
+    public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationResult result) {
+        super.onRemoteOperationFinish(operation, result);
+
+        if (result.isSuccess()) {
+            Log_OC.d(TAG, "Refreshing lists on successful sync");
+            refreshUsersInLists();
+        }
+
+    }
+
+    private void refreshUsersInLists() {
+        ShareFileFragment shareFileFragment = getShareFileFragment();
+        if (shareFileFragment != null) {          // only if added to the view hierarchy!!
+            if (shareFileFragment.isAdded()) {
+                shareFileFragment.refreshUsersOrGroupsListFromDB();
+            }
+        }
+
+        SearchShareesFragment searchShareesFragment = getSearchFragment();
+        if (searchShareesFragment != null) {
+            if (searchShareesFragment.isAdded()) {  // only if added to the view hierarchy!!
+                searchShareesFragment.refreshUsersOrGroupsListFromDB();
+            }
+        }
+    }
+
+    /**
+     * Shortcut to get access to the {@link ShareFileFragment} instance, if any
+     *
+     * @return  A {@link ShareFileFragment} instance, or null
+     */
+    private ShareFileFragment getShareFileFragment() {
+        return (ShareFileFragment) getSupportFragmentManager().findFragmentByTag(TAG_SHARE_FRAGMENT);
+    }
+
+    /**
+     * Shortcut to get access to the {@link SearchShareesFragment} instance, if any
+     *
+     * @return  A {@link SearchShareesFragment} instance, or null
+     */
+    private SearchShareesFragment getSearchFragment() {
+        return (SearchShareesFragment) getSupportFragmentManager().findFragmentByTag(TAG_SEARCH_FRAGMENT);
+    }
+
+}

+ 0 - 2
src/com/owncloud/android/ui/activity/Uploader.java

@@ -607,10 +607,8 @@ public class Uploader extends FileActivity
     private void onCreateFolderOperationFinish(CreateFolderOperation operation,
                                                RemoteOperationResult result) {
         if (result.isSuccess()) {
-            dismissLoadingDialog();
             populateDirectoryList();
         } else {
-            dismissLoadingDialog();
             try {
                 Toast msg = Toast.makeText(this, 
                         ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()), 

+ 13 - 28
src/com/owncloud/android/ui/adapter/FileListListAdapter.java

@@ -63,7 +63,6 @@ import com.owncloud.android.utils.MimetypeIconUtil;
  * instance.
  */
 public class FileListListAdapter extends BaseAdapter implements ListAdapter {
-    private final static String PERMISSION_SHARED_WITH_ME = "S";
 
     private Context mContext;
     private OCFile mFile = null;
@@ -238,13 +237,21 @@ public class FileListListAdapter extends BaseAdapter implements ListAdapter {
                 case GRID_IMAGE:
                     // sharedIcon
                     ImageView sharedIconV = (ImageView) view.findViewById(R.id.sharedIcon);
-                    if (file.isShareByLink()) {
+                    if (file.isSharedViaLink()) {
+                        sharedIconV.setImageResource(R.drawable.shared_via_link);
+                        sharedIconV.setVisibility(View.VISIBLE);
+                        sharedIconV.bringToFront();
+                    } else if (file.isSharedWithSharee() || file.isSharedWithMe() ) {
+                        sharedIconV.setImageResource(R.drawable.shared_via_users);
                         sharedIconV.setVisibility(View.VISIBLE);
                         sharedIconV.bringToFront();
                     } else {
                         sharedIconV.setVisibility(View.GONE);
                     }
 
+                    /*ImageView sharedWithMeIcon = (ImageView) view.findViewById(R.id.sharedWithMeIcon);
+                    sharedWithMeIcon.bringToFront();*/
+
                     // local state
                     ImageView localStateView = (ImageView) view.findViewById(R.id.localFileIndicator);
                     localStateView.bringToFront();
@@ -295,17 +302,6 @@ public class FileListListAdapter extends BaseAdapter implements ListAdapter {
                         localStateView.setVisibility(View.VISIBLE);
                     }
 
-                    // share with me icon
-                    ImageView sharedWithMeIconV = (ImageView)
-                            view.findViewById(R.id.sharedWithMeIcon);
-                    sharedWithMeIconV.bringToFront();
-                    if (checkIfFileIsSharedWithMe(file) &&
-                            (!file.isFolder() || !mGridMode)) {
-                        sharedWithMeIconV.setVisibility(View.VISIBLE);
-                    } else {
-                        sharedWithMeIconV.setVisibility(View.GONE);
-                    }
-
                     break;
             }
             
@@ -364,7 +360,10 @@ public class FileListListAdapter extends BaseAdapter implements ListAdapter {
                 // Folder
                 fileIcon.setImageResource(
                         MimetypeIconUtil.getFolderTypeIconId(
-                                checkIfFileIsSharedWithMe(file), file.isShareByLink()));
+                                file.isSharedWithMe() || file.isSharedWithSharee(),
+                                file.isSharedViaLink()
+                        )
+                );
             }
         }
 
@@ -436,20 +435,6 @@ public class FileListListAdapter extends BaseAdapter implements ListAdapter {
     }
     
     
-    /**
-     * Check if parent folder does not include 'S' permission and if file/folder
-     * is shared with me
-     * 
-     * @param file: OCFile
-     * @return boolean: True if it is shared with me and false if it is not
-     */
-    private boolean checkIfFileIsSharedWithMe(OCFile file) {
-        return (mFile.getPermissions() != null 
-                && !mFile.getPermissions().contains(PERMISSION_SHARED_WITH_ME)
-                && file.getPermissions() != null 
-                && file.getPermissions().contains(PERMISSION_SHARED_WITH_ME));
-    }
-
     public void setSortOrder(Integer order, boolean ascending) {
         SharedPreferences.Editor editor = mAppPreferences.edit();
         editor.putInt("sortOrder", order);

+ 0 - 1
src/com/owncloud/android/ui/adapter/LocalFileListAdapter.java

@@ -188,7 +188,6 @@ public class LocalFileListAdapter extends BaseAdapter implements ListAdapter {
             view.findViewById(R.id.favoriteIcon).setVisibility(View.GONE);
             
             view.findViewById(R.id.sharedIcon).setVisibility(View.GONE);
-            view.findViewById(R.id.sharedWithMeIcon).setVisibility(View.GONE);
         }
 
         return view;

+ 103 - 0
src/com/owncloud/android/ui/adapter/ShareUserListAdapter.java

@@ -0,0 +1,103 @@
+/**
+ *   ownCloud Android client application
+ *
+ *   @author masensio
+ *   Copyright (C) 2015 ownCloud Inc.
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License version 2,
+ *   as published by the Free Software Foundation.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.ui.adapter;
+
+import android.content.Context;
+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.owncloud.android.R;
+import com.owncloud.android.lib.resources.shares.OCShare;
+import com.owncloud.android.lib.resources.shares.ShareType;
+
+import java.util.ArrayList;
+
+/**
+ * Adapter to show a user/group in Share With List
+ */
+public class ShareUserListAdapter extends ArrayAdapter {
+
+    private Context mContext;
+    private ArrayList<OCShare> mShares;
+    private ShareUserAdapterListener mListener;
+
+    public ShareUserListAdapter(Context context, int resource, ArrayList<OCShare>shares,
+                                ShareUserAdapterListener listener) {
+        super(context, resource);
+        mContext= context;
+        mShares = shares;
+        mListener = listener;
+    }
+
+    @Override
+    public int getCount() {
+        return mShares.size();
+    }
+
+    @Override
+    public Object getItem(int position) {
+        return mShares.get(position);
+    }
+
+    @Override
+    public long getItemId(int position) {
+        return 0;
+    }
+
+    @Override
+    public View getView(final int position, View convertView, ViewGroup parent) {
+        LayoutInflater inflator = (LayoutInflater) mContext
+                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+        View view = inflator.inflate(R.layout.share_user_item, parent, false);
+
+        if (mShares != null && mShares.size() > position) {
+            OCShare share = mShares.get(position);
+
+            TextView userName = (TextView) view.findViewById(R.id.userOrGroupName);
+            String name = share.getSharedWithDisplayName();
+            if (share.getShareType() == ShareType.GROUP) {
+                name = getContext().getString(R.string.share_group_clarification, name);
+            }
+            userName.setText(name);
+
+            final ImageView unshareButton = (ImageView) view.findViewById(R.id.unshareButton);
+            unshareButton.setOnClickListener(new View.OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    mListener.unshareButtonPressed(mShares.get(position));
+                }
+            });
+
+        }
+        return view;
+    }
+
+    public interface ShareUserAdapterListener {
+        void unshareButtonPressed(OCShare share);
+    }
+
+
+
+}

+ 60 - 11
src/com/owncloud/android/ui/adapter/X509CertificateViewAdapter.java

@@ -20,6 +20,9 @@
  */
 package com.owncloud.android.ui.adapter;
 
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateEncodingException;
 import java.security.cert.X509Certificate;
 import java.text.DateFormat;
 import java.util.Date;
@@ -31,6 +34,7 @@ import javax.security.auth.x500.X500Principal;
 import com.owncloud.android.R;
 import com.owncloud.android.ui.dialog.SslUntrustedCertDialog;
 
+import android.util.Log;
 import android.view.View;
 import android.widget.TextView;
 
@@ -42,7 +46,9 @@ public class X509CertificateViewAdapter implements SslUntrustedCertDialog.Certif
     //private final static String TAG = X509CertificateViewAdapter.class.getSimpleName();
     
     private X509Certificate mCertificate = null;
-    
+
+    private static final String TAG = X509CertificateViewAdapter.class.getSimpleName();
+
     public X509CertificateViewAdapter(X509Certificate certificate) {
         mCertificate = certificate;
     }
@@ -63,25 +69,68 @@ public class X509CertificateViewAdapter implements SslUntrustedCertDialog.Certif
         }
     }
 
+    private byte[] getDigest(String algorithm, byte[] message) {
+        MessageDigest md = null;
+
+        try {
+            md = MessageDigest.getInstance(algorithm);
+        } catch (NoSuchAlgorithmException e) {
+            return null;
+        }
+        md.reset();
+        return md.digest(message);
+    }
+
     private void showSignature(View dialogView) {
-        TextView sigView = ((TextView)dialogView.findViewById(R.id.value_signature));
-        TextView algorithmView = ((TextView)dialogView.findViewById(R.id.value_signature_algorithm));
-        sigView.setText(getHex(mCertificate.getSignature()));
-        algorithmView.setText(mCertificate.getSigAlgName());
+        byte[] cert = null;
+
+        TextView certFingerprintView = ((TextView) dialogView.findViewById(R.id.value_certificate_fingerprint));
+        TextView algorithmView = ((TextView) dialogView.findViewById(R.id.value_signature_algorithm));
+
+        try {
+            cert = mCertificate.getEncoded();
+            if (cert == null) {
+
+                certFingerprintView.setText(R.string.certificate_load_problem);
+                algorithmView.setText(R.string.certificate_load_problem);
+
+            } else {
+
+                certFingerprintView.setText(
+                        getDigestHexBytesWithColonsAndNewLines(dialogView, "SHA-256", cert)
+                                + getDigestHexBytesWithColonsAndNewLines(dialogView, "SHA-1", cert)
+                                + getDigestHexBytesWithColonsAndNewLines(dialogView, "MD5", cert));
+                algorithmView.setText(mCertificate.getSigAlgName());
+
+            }
+
+        } catch (CertificateEncodingException e) {
+            Log.e(TAG, "Problem while trying to decode the certificate.");
+        }
+
+
     }
     
-    public String getHex(final byte [] raw) {
-        if (raw == null) {
-           return null;
+    private final String getDigestHexBytesWithColonsAndNewLines(View dialogView, final String digestType, final byte [] cert) {
+        final byte[] rawDigest;
+        final String newLine = System.getProperty("line.separator");
+
+        rawDigest = getDigest(digestType, cert);
+
+        if ( rawDigest == null) {
+            return digestType + ":" + newLine + dialogView.getContext().getString(R.string.digest_algorithm_not_available) + newLine + newLine;
         }
-        final StringBuilder hex = new StringBuilder(2 * raw.length);
-        for (final byte b : raw) {
+
+        final StringBuilder hex = new StringBuilder(3 * rawDigest.length);
+
+        for (final byte b : rawDigest) {
            final int hiVal = (b & 0xF0) >> 4;
            final int loVal = b & 0x0F;
            hex.append((char) ('0' + (hiVal + (hiVal / 10 * 7))));
            hex.append((char) ('0' + (loVal + (loVal / 10 * 7))));
+           hex.append(":");
         }
-        return hex.toString();
+        return digestType + ":" + newLine + hex.toString().replaceFirst("\\:$","") + newLine + newLine;
      }    
 
     private void showValidity(Date notBefore, Date notAfter, View dialogView) {

+ 5 - 1
src/com/owncloud/android/ui/fragment/FileDetailFragment.java

@@ -230,10 +230,15 @@ public class FileDetailFragment extends FileFragment implements OnClickListener
                 mContainerActivity.getFileOperationsHelper().shareFileWithLink(getFile());
                 return true;
             }
+            case R.id.action_share_with_users: {
+                mContainerActivity.getFileOperationsHelper().showShareFile(getFile());
+                return true;
+            }
             case R.id.action_unshare_file: {
                 mContainerActivity.getFileOperationsHelper().unshareFileWithLink(getFile());
                 return true;
             }
+
             case R.id.action_open_file_with: {
                 mContainerActivity.getFileOperationsHelper().openFile(getFile());
                 return true;
@@ -262,7 +267,6 @@ public class FileDetailFragment extends FileFragment implements OnClickListener
                 if (!getFile().isDown()) {  // Download the file                    
                     Log_OC.d(TAG, getFile().getRemotePath() + " : File must be downloaded");
                     ((FileDisplayActivity) mContainerActivity).startDownloadForSending(getFile());
-
                 }
                 else {
                     mContainerActivity.getFileOperationsHelper().sendDownloadedFile(getFile());

+ 1 - 2
src/com/owncloud/android/ui/fragment/FileFragment.java

@@ -141,9 +141,8 @@ public class FileFragment extends Fragment {
          * @param downloading   Flag signaling if the file is now downloading.
          * @param uploading     Flag signaling if the file is now uploading.
          */
-        public void onTransferStateChanged(OCFile file, boolean downloading, boolean uploading); 
+        public void onTransferStateChanged(OCFile file, boolean downloading, boolean uploading);
 
-        
     }
 
 }

+ 11 - 4
src/com/owncloud/android/ui/fragment/OCFileListFragment.java

@@ -53,8 +53,8 @@ import com.owncloud.android.ui.dialog.RemoveFileDialogFragment;
 import com.owncloud.android.ui.dialog.RenameFileDialogFragment;
 import com.owncloud.android.ui.preview.PreviewImageFragment;
 import com.owncloud.android.ui.preview.PreviewMediaFragment;
-import com.owncloud.android.utils.FileStorageUtils;
 import com.owncloud.android.ui.preview.PreviewTextFragment;
+import com.owncloud.android.utils.FileStorageUtils;
 
 import java.io.File;
 
@@ -63,7 +63,8 @@ import java.io.File;
  *
  * TODO refactor to get rid of direct dependency on FileDisplayActivity
  */
-public class OCFileListFragment extends ExtendedListFragment implements FileActionsDialogFragment.FileActionsDialogFragmentListener {
+public class OCFileListFragment extends ExtendedListFragment
+        implements FileActionsDialogFragment.FileActionsDialogFragmentListener {
     
     private static final String TAG = OCFileListFragment.class.getSimpleName();
 
@@ -193,7 +194,8 @@ public class OCFileListFragment extends ExtendedListFragment implements FileActi
                 }
             }
 
-            FileActionsDialogFragment dialog = FileActionsDialogFragment.newInstance(menu, fileIndex, targetFile.getFileName());
+            FileActionsDialogFragment dialog = FileActionsDialogFragment.newInstance(menu,
+                    fileIndex, targetFile.getFileName());
             dialog.setTargetFragment(this, 0);
             dialog.show(getFragmentManager(), FileActionsDialogFragment.FTAG_FILE_ACTIONS);
         }
@@ -345,6 +347,10 @@ public class OCFileListFragment extends ExtendedListFragment implements FileActi
                 mContainerActivity.getFileOperationsHelper().shareFileWithLink(mTargetFile);
                 return true;
             }
+            case R.id.action_share_with_users: {
+                mContainerActivity.getFileOperationsHelper().showShareFile(mTargetFile);
+                return true;
+            }
             case R.id.action_open_file_with: {
                 mContainerActivity.getFileOperationsHelper().openFile(mTargetFile);
                 return true;
@@ -421,7 +427,8 @@ public class OCFileListFragment extends ExtendedListFragment implements FileActi
     @Override
     public boolean onContextItemSelected (MenuItem item) {
         AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
-        boolean matched = onFileActionChosen(item.getItemId(), ((AdapterContextMenuInfo) item.getMenuInfo()).position);
+        boolean matched = onFileActionChosen(item.getItemId(),
+                ((AdapterContextMenuInfo) item.getMenuInfo()).position);
         if(!matched) {
             return super.onContextItemSelected(item);
         } else {

+ 247 - 0
src/com/owncloud/android/ui/fragment/SearchShareesFragment.java

@@ -0,0 +1,247 @@
+/**
+ *   ownCloud Android client application
+ *
+ *   @author masensio
+ *   @author David A. Velasco
+ *   Copyright (C) 2015 ownCloud Inc.
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License version 2,
+ *   as published by the Free Software Foundation.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.ui.fragment;
+
+import android.accounts.Account;
+import android.app.Activity;
+import android.app.SearchManager;
+import android.content.Context;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.ListView;
+import android.widget.SearchView;
+
+import com.owncloud.android.R;
+import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.lib.common.utils.Log_OC;
+import com.owncloud.android.lib.resources.shares.OCShare;
+import com.owncloud.android.ui.activity.FileActivity;
+import com.owncloud.android.ui.activity.ShareActivity;
+import com.owncloud.android.ui.adapter.ShareUserListAdapter;
+
+import java.util.ArrayList;
+
+/**
+ * Fragment for Searching sharees (users and groups)
+ *
+ * A simple {@link Fragment} subclass.
+ *
+ * Activities that contain this fragment must implement the
+ * {@link SearchShareesFragment.OnSearchFragmentInteractionListener} interface
+ * to handle interaction events.
+ *
+ * Use the {@link SearchShareesFragment#newInstance} factory method to
+ * create an instance of this fragment.
+ */
+public class SearchShareesFragment extends Fragment implements ShareUserListAdapter.ShareUserAdapterListener {
+    private static final String TAG = SearchShareesFragment.class.getSimpleName();
+
+    // the fragment initialization parameters
+    private static final String ARG_FILE = "FILE";
+    private static final String ARG_ACCOUNT = "ACCOUNT";
+
+    // Parameters
+    private OCFile mFile;
+    private Account mAccount;
+
+    // other members
+    private ArrayList<OCShare> mShares;
+    private ShareUserListAdapter mUserGroupsAdapter = null;
+    private OnSearchFragmentInteractionListener mListener;
+
+
+    /**
+     * Public factory method to create new SearchShareesFragment instances.
+     *
+     * @param fileToShare   An {@link OCFile} to be shared
+     * @param account       The ownCloud account containing fileToShare
+     * @return A new instance of fragment SearchShareesFragment.
+     */
+    public static SearchShareesFragment newInstance(OCFile fileToShare, Account account) {
+        SearchShareesFragment fragment = new SearchShareesFragment();
+        Bundle args = new Bundle();
+        args.putParcelable(ARG_FILE, fileToShare);
+        args.putParcelable(ARG_ACCOUNT, account);
+        fragment.setArguments(args);
+        return fragment;
+    }
+
+    public SearchShareesFragment() {
+        // Required empty public constructor
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        if (getArguments() != null) {
+            mFile = getArguments().getParcelable(ARG_FILE);
+            mAccount = getArguments().getParcelable(ARG_ACCOUNT);
+        }
+
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+                             Bundle savedInstanceState) {
+        // Inflate the layout for this fragment
+        View view = inflater.inflate(R.layout.search_users_groups_layout, container, false);
+
+        // Get the SearchView and set the searchable configuration
+        SearchView searchView = (SearchView) view.findViewById(R.id.searchView);
+        SearchManager searchManager = (SearchManager) getActivity().getSystemService(Context.SEARCH_SERVICE);
+        searchView.setSearchableInfo(searchManager.getSearchableInfo(
+                getActivity().getComponentName())   // assumes parent activity is the searchable activity
+        );
+        searchView.setIconifiedByDefault(false);    // do not iconify the widget; expand it by default
+
+        searchView.setImeOptions(EditorInfo.IME_FLAG_NO_EXTRACT_UI); // avoid fullscreen with softkeyboard
+
+        searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
+            @Override
+            public boolean onQueryTextSubmit(String query) {
+                Log_OC.v(TAG, "onQueryTextSubmit intercepted, query: " + query);
+                return true;    // return true to prevent the query is processed to be queried;
+                // a user / group will be picked only if selected in the list of suggestions
+            }
+
+            @Override
+            public boolean onQueryTextChange(String newText) {
+                return false;   // let it for the parent listener in the hierarchy / default behaviour
+            }
+        });
+
+        return view;
+    }
+
+
+    @Override
+    public void onActivityCreated(Bundle savedInstanceState) {
+        super.onActivityCreated(savedInstanceState);
+
+        // Load data into the list
+        refreshUsersOrGroupsListFromDB();
+    }
+
+
+    /**
+     * Get users and groups from the DB to fill in the "share with" list
+     *
+     * Depends on the parent Activity provides a {@link com.owncloud.android.datamodel.FileDataStorageManager}
+     * instance ready to use. If not ready, does nothing.
+     */
+    public void refreshUsersOrGroupsListFromDB (){
+        // Get Users and Groups
+        if (((FileActivity) mListener).getStorageManager() != null) {
+            mShares = ((FileActivity) mListener).getStorageManager().getSharesWithForAFile(
+                    mFile.getRemotePath(),
+                    mAccount.name
+            );
+
+            // Update list of users/groups
+            updateListOfUserGroups();
+        }
+    }
+
+    private void updateListOfUserGroups() {
+        // Update list of users/groups
+        // TODO Refactoring: create a new {@link ShareUserListAdapter} instance with every call should not be needed
+        mUserGroupsAdapter = new ShareUserListAdapter(
+                getActivity().getApplicationContext(),
+                R.layout.share_user_item, mShares, this
+        );
+
+        // Show data
+        ListView usersList = (ListView) getView().findViewById(R.id.searchUsersListView);
+
+        if (mShares.size() > 0) {
+            usersList.setVisibility(View.VISIBLE);
+            usersList.setAdapter(mUserGroupsAdapter);
+
+        } else {
+            usersList.setVisibility(View.GONE);
+        }
+    }
+
+    @Override
+    public void onAttach(Activity activity) {
+        super.onAttach(activity);
+        try {
+            mListener = (OnSearchFragmentInteractionListener) activity;
+        } catch (ClassCastException e) {
+            throw new ClassCastException(activity.toString()
+                    + " must implement OnFragmentInteractionListener");
+        }
+    }
+
+    @Override
+    public void onStart() {
+        super.onStart();
+        // focus the search view and request the software keyboard be shown
+        View searchView = getView().findViewById(R.id.searchView);
+        if (searchView.requestFocus()) {
+            InputMethodManager imm = (InputMethodManager)
+                    getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
+            if (imm != null) {
+                imm.showSoftInput(searchView.findFocus(), InputMethodManager.SHOW_IMPLICIT);
+            }
+        }
+    }
+
+    @Override
+    public void onDetach() {
+        super.onDetach();
+        mListener = null;
+    }
+
+    @Override
+    public void unshareButtonPressed(OCShare share) {
+        // Unshare
+        mListener.unshareWith(share);
+        Log_OC.d(TAG, "Unshare - " + share.getSharedWithDisplayName());
+    }
+
+    /**
+     * This interface must be implemented by activities that contain this
+     * fragment to allow an interaction in this fragment to be communicated
+     * to the activity and potentially other fragments contained in that
+     * activity.
+     * <p/>
+     * See the Android Training lesson <a href=
+     * "http://developer.android.com/training/basics/fragments/communicating.html"
+     * >Communicating with Other Fragments</a> for more information.
+     */
+    public interface OnSearchFragmentInteractionListener {
+        void unshareWith(OCShare share);
+    }
+
+}

+ 259 - 0
src/com/owncloud/android/ui/fragment/ShareFileFragment.java

@@ -0,0 +1,259 @@
+/**
+ *   ownCloud Android client application
+ *
+ *   @author masensio
+ *   @author David A. Velasco
+ *   Copyright (C) 2015 ownCloud Inc.
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License version 2,
+ *   as published by the Free Software Foundation.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.ui.fragment;
+
+import android.accounts.Account;
+import android.app.Activity;
+import android.graphics.Bitmap;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.ListView;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.owncloud.android.R;
+import com.owncloud.android.authentication.AccountUtils;
+import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.datamodel.ThumbnailsCacheManager;
+import com.owncloud.android.lib.common.utils.Log_OC;
+import com.owncloud.android.lib.resources.shares.OCShare;
+import com.owncloud.android.ui.activity.FileActivity;
+import com.owncloud.android.ui.activity.ShareActivity;
+import com.owncloud.android.ui.adapter.ShareUserListAdapter;
+import com.owncloud.android.utils.DisplayUtils;
+import com.owncloud.android.utils.MimetypeIconUtil;
+
+import java.util.ArrayList;
+
+/**
+ * Fragment for Sharing a file with sharees (users or groups)
+ *
+ * A simple {@link Fragment} subclass.
+ *
+ * Activities that contain this fragment must implement the
+ * {@link ShareFileFragment.OnShareFragmentInteractionListener} interface
+ * to handle interaction events.
+ *
+ * Use the {@link ShareFileFragment#newInstance} factory method to
+ * create an instance of this fragment.
+ */
+public class ShareFileFragment extends Fragment
+        implements ShareUserListAdapter.ShareUserAdapterListener{
+
+    private static final String TAG = ShareFileFragment.class.getSimpleName();
+
+    // the fragment initialization parameters
+    private static final String ARG_FILE = "FILE";
+    private static final String ARG_ACCOUNT = "ACCOUNT";
+
+    // Parameters
+    private OCFile mFile;
+    private Account mAccount;
+
+    // other members
+    private ArrayList<OCShare> mShares;
+    private ShareUserListAdapter mUserGroupsAdapter = null;
+    private OnShareFragmentInteractionListener mListener;
+
+    /**
+     * Public factory method to create new ShareFileFragment instances.
+     *
+     * @param fileToShare An {@link OCFile} to show in the fragment
+     * @param account     An ownCloud account
+     * @return A new instance of fragment ShareFileFragment.
+     */
+    public static ShareFileFragment newInstance(OCFile fileToShare, Account account) {
+        ShareFileFragment fragment = new ShareFileFragment();
+        Bundle args = new Bundle();
+        args.putParcelable(ARG_FILE, fileToShare);
+        args.putParcelable(ARG_ACCOUNT, account);
+        fragment.setArguments(args);
+        return fragment;
+    }
+
+    public ShareFileFragment() {
+        // Required empty public constructor
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        if (getArguments() != null) {
+            mFile = getArguments().getParcelable(ARG_FILE);
+            mAccount = getArguments().getParcelable(ARG_ACCOUNT);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+                             Bundle savedInstanceState) {
+        // Inflate the layout for this fragment
+        View view = inflater.inflate(R.layout.share_file_layout, container, false);
+
+        // Setup layout
+        // Image
+        ImageView icon = (ImageView) view.findViewById(R.id.shareFileIcon);
+        icon.setImageResource(MimetypeIconUtil.getFileTypeIconId(mFile.getMimetype(),
+                mFile.getFileName()));
+        if (mFile.isImage()) {
+            String remoteId = String.valueOf(mFile.getRemoteId());
+            Bitmap thumbnail = ThumbnailsCacheManager.getBitmapFromDiskCache(remoteId);
+            if (thumbnail != null) {
+                icon.setImageBitmap(thumbnail);
+            }
+        }
+        // Name
+        TextView filename = (TextView) view.findViewById(R.id.shareFileName);
+        filename.setText(mFile.getFileName());
+        // Size
+        TextView size = (TextView) view.findViewById(R.id.shareFileSize);
+        if (mFile.isFolder()) {
+            size.setVisibility(View.GONE);
+        } else {
+            size.setText(DisplayUtils.bytesToHumanReadable(mFile.getFileLength()));
+        }
+
+        //  Add User Button
+        Button addUserGroupButton = (Button)
+                view.findViewById(R.id.addUserButton);
+        addUserGroupButton.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View view) {
+                 boolean shareWithUsersEnable = AccountUtils.hasSearchUsersSupport(mAccount);
+                if (shareWithUsersEnable) {
+                    // Show Search Fragment
+                    mListener.showSearchUsersAndGroups();
+                } else {
+                    String message = getString(R.string.share_sharee_unavailable);
+                    Toast.makeText(getActivity(), message, Toast.LENGTH_LONG).show();
+                }
+            }
+        });
+
+        return view;
+    }
+
+    @Override
+    public void onActivityCreated(Bundle savedInstanceState) {
+        super.onActivityCreated(savedInstanceState);
+
+        // Load data into the list
+        refreshUsersOrGroupsListFromDB();
+    }
+
+    @Override
+    public void onAttach(Activity activity) {
+        super.onAttach(activity);
+        try {
+            mListener = (OnShareFragmentInteractionListener) activity;
+        } catch (ClassCastException e) {
+            throw new ClassCastException(activity.toString()
+                    + " must implement OnShareFragmentInteractionListener");
+        }
+    }
+
+    @Override
+    public void onDetach() {
+        super.onDetach();
+        mListener = null;
+    }
+
+    /**
+     * Get users and groups from the DB to fill in the "share with" list
+     *
+     * Depends on the parent Activity provides a {@link com.owncloud.android.datamodel.FileDataStorageManager}
+     * instance ready to use. If not ready, does nothing.
+     */
+    public void refreshUsersOrGroupsListFromDB (){
+        if (((FileActivity) mListener).getStorageManager() != null) {
+            // Get Users and Groups
+            mShares = ((FileActivity) mListener).getStorageManager().getSharesWithForAFile(
+                    mFile.getRemotePath(),
+                    mAccount.name
+            );
+
+            // Update list of users/groups
+            updateListOfUserGroups();
+        }
+    }
+
+    private void updateListOfUserGroups() {
+        // Update list of users/groups
+        // TODO Refactoring: create a new {@link ShareUserListAdapter} instance with every call should not be needed
+        mUserGroupsAdapter = new ShareUserListAdapter(
+                getActivity(),
+                R.layout.share_user_item,
+                mShares,
+                this
+        );
+
+        // Show data
+        TextView noShares = (TextView) getView().findViewById(R.id.shareNoUsers);
+        ListView usersList = (ListView) getView().findViewById(R.id.shareUsersList);
+
+        if (mShares.size() > 0) {
+            noShares.setVisibility(View.GONE);
+            usersList.setVisibility(View.VISIBLE);
+            usersList.setAdapter(mUserGroupsAdapter);
+
+        } else {
+            noShares.setVisibility(View.VISIBLE);
+            usersList.setVisibility(View.GONE);
+        }
+    }
+
+    @Override
+    public void unshareButtonPressed(OCShare share) {
+        // Unshare
+        mListener.unshareWith(share);
+        Log_OC.d(TAG, "Unshare - " + share.getSharedWithDisplayName());
+    }
+
+
+    /**
+     * This interface must be implemented by activities that contain this
+     * fragment to allow an interaction in this fragment to be communicated
+     * to the activity and potentially other fragments contained in that
+     * activity.
+     * <p/>
+     * See the Android Training lesson <a href=
+     * "http://developer.android.com/training/basics/fragments/communicating.html"
+     * >Communicating with Other Fragments</a> for more information.
+     */
+    public interface OnShareFragmentInteractionListener {
+        void showSearchUsersAndGroups();
+        void refreshUsersOrGroupsListFromServer();
+        void unshareWith(OCShare share);
+    }
+
+}

+ 12 - 13
src/com/owncloud/android/ui/preview/PreviewImageActivity.java

@@ -26,7 +26,6 @@ import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.ServiceConnection;
-import android.graphics.drawable.ColorDrawable;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
@@ -54,14 +53,15 @@ import com.owncloud.android.lib.common.operations.RemoteOperation;
 import com.owncloud.android.lib.common.operations.RemoteOperationResult;
 import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;
 import com.owncloud.android.lib.common.utils.Log_OC;
-import com.owncloud.android.operations.CreateShareOperation;
+import com.owncloud.android.operations.CreateShareViaLinkOperation;
+import com.owncloud.android.operations.CreateShareWithShareeOperation;
 import com.owncloud.android.operations.RemoveFileOperation;
 import com.owncloud.android.operations.SynchronizeFileOperation;
-import com.owncloud.android.operations.UnshareLinkOperation;
+import com.owncloud.android.operations.UnshareOperation;
 import com.owncloud.android.ui.activity.FileActivity;
 import com.owncloud.android.ui.activity.FileDisplayActivity;
+import com.owncloud.android.ui.activity.ShareActivity;
 import com.owncloud.android.ui.fragment.FileFragment;
-import com.owncloud.android.utils.DisplayUtils;
 
 
 /**
@@ -230,11 +230,12 @@ public class PreviewImageActivity extends FileActivity implements
     public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationResult result) {
         super.onRemoteOperationFinish(operation, result);
         
-        if (operation instanceof CreateShareOperation) {
-            onCreateShareOperationFinish((CreateShareOperation) operation, result);
-            
-        } else if (operation instanceof UnshareLinkOperation) {
-            onUnshareLinkOperationFinish((UnshareLinkOperation) operation, result);
+        if (operation instanceof CreateShareViaLinkOperation ||
+                operation instanceof CreateShareWithShareeOperation) {
+            onCreateShareOperationFinish(result);
+
+        } else if (operation instanceof UnshareOperation) {
+            onUnshareLinkOperationFinish((UnshareOperation) operation, result);
             
         } else if (operation instanceof RemoveFileOperation) {
             finish();
@@ -245,7 +246,7 @@ public class PreviewImageActivity extends FileActivity implements
     }
     
     
-    private void onUnshareLinkOperationFinish(UnshareLinkOperation operation,
+    private void onUnshareLinkOperationFinish(UnshareOperation operation,
                                               RemoteOperationResult result) {
         if (result.isSuccess()) {
             OCFile file = getStorageManager().getFileByPath(getFile().getRemotePath());
@@ -259,8 +260,7 @@ public class PreviewImageActivity extends FileActivity implements
             
     }
     
-    private void onCreateShareOperationFinish(CreateShareOperation operation,
-                                              RemoteOperationResult result) {
+    private void onCreateShareOperationFinish(RemoteOperationResult result) {
         if (result.isSuccess()) {
             OCFile file = getStorageManager().getFileByPath(getFile().getRemotePath());
             if (file != null) {
@@ -400,7 +400,6 @@ public class PreviewImageActivity extends FileActivity implements
         
     }
 
-    
     private void requestForDownload(OCFile file) {
         if (mDownloaderBinder == null) {
             Log_OC.d(TAG, "requestForDownload called without binder to download service");

+ 4 - 1
src/com/owncloud/android/ui/preview/PreviewImageFragment.java

@@ -289,6 +289,10 @@ public class PreviewImageFragment extends FileFragment {
                 mContainerActivity.getFileOperationsHelper().shareFileWithLink(getFile());
                 return true;
             }
+            case R.id.action_share_with_users: {
+                mContainerActivity.getFileOperationsHelper().showShareFile(getFile());
+                return true;
+            }
             case R.id.action_unshare_file: {
                 mContainerActivity.getFileOperationsHelper().unshareFileWithLink(getFile());
                 return true;
@@ -332,7 +336,6 @@ public class PreviewImageFragment extends FileFragment {
         mContainerActivity.showDetails(getFile());
     }
 
-
     @Override
     public void onResume() {
         super.onResume();

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

@@ -355,6 +355,10 @@ public class PreviewMediaFragment extends FileFragment implements
                 mContainerActivity.getFileOperationsHelper().shareFileWithLink(getFile());
                 return true;
             }
+            case R.id.action_share_with_users: {
+                seeShareFile();
+                return true;
+            }
             case R.id.action_unshare_file: {
                 stopPreview(false);
                 mContainerActivity.getFileOperationsHelper().unshareFileWithLink(getFile());
@@ -415,6 +419,10 @@ public class PreviewMediaFragment extends FileFragment implements
         mContainerActivity.showDetails(getFile());
     }
 
+    private void seeShareFile() {
+        stopPreview(false);
+        mContainerActivity.getFileOperationsHelper().showShareFile(getFile());
+    }
 
     private void prepareVideo() {
         // create helper to get more control on the playback

+ 4 - 0
src/com/owncloud/android/ui/preview/PreviewTextFragment.java

@@ -302,6 +302,10 @@ public class PreviewTextFragment extends FileFragment {
                 mContainerActivity.getFileOperationsHelper().shareFileWithLink(getFile());
                 return true;
             }
+            case R.id.action_share_with_users: {
+                mContainerActivity.getFileOperationsHelper().showShareFile(getFile());
+                return true;
+            }
             case R.id.action_unshare_file: {
                 mContainerActivity.getFileOperationsHelper().unshareFileWithLink(getFile());
                 return true;

部分文件因为文件数量过多而无法显示