Bladeren bron

Merge pull request #61 from nextcloud/multiSelectNew

Multi Select
Andy Scherzinger 8 jaren geleden
bovenliggende
commit
55c0dcc3b0
100 gewijzigde bestanden met toevoegingen van 1019 en 732 verwijderingen
  1. 4 1
      build.gradle
  2. BIN
      res/drawable-hdpi/ic_action_cancel_grey.png
  3. BIN
      res/drawable-hdpi/ic_action_cancel_white.png
  4. 0 0
      res/drawable-hdpi/ic_action_delete_grey.png
  5. BIN
      res/drawable-hdpi/ic_action_refresh_white.png
  6. BIN
      res/drawable-hdpi/ic_action_set_available_offline.png
  7. BIN
      res/drawable-hdpi/ic_action_share.png
  8. BIN
      res/drawable-hdpi/ic_action_unset_available_offline.png
  9. BIN
      res/drawable-hdpi/ic_open_in_app.png
  10. BIN
      res/drawable-hdpi/ic_pencil.png
  11. BIN
      res/drawable-mdpi/ic_action_cancel_grey.png
  12. BIN
      res/drawable-mdpi/ic_action_cancel_white.png
  13. 0 0
      res/drawable-mdpi/ic_action_delete_grey.png
  14. BIN
      res/drawable-mdpi/ic_action_refresh_grey.png
  15. BIN
      res/drawable-mdpi/ic_action_refresh_white.png
  16. BIN
      res/drawable-mdpi/ic_action_set_available_offline.png
  17. BIN
      res/drawable-mdpi/ic_action_share.png
  18. BIN
      res/drawable-mdpi/ic_action_unset_available_offline.png
  19. BIN
      res/drawable-mdpi/ic_open_in_app.png
  20. BIN
      res/drawable-mdpi/ic_pencil.png
  21. 0 0
      res/drawable-xhdpi/ic_action_cancel_grey.png
  22. BIN
      res/drawable-xhdpi/ic_action_cancel_white.png
  23. 0 0
      res/drawable-xhdpi/ic_action_delete_grey.png
  24. BIN
      res/drawable-xhdpi/ic_action_download.png
  25. 0 0
      res/drawable-xhdpi/ic_action_refresh_white.png
  26. BIN
      res/drawable-xhdpi/ic_action_set_available_offline.png
  27. BIN
      res/drawable-xhdpi/ic_action_share.png
  28. BIN
      res/drawable-xhdpi/ic_action_unset_available_offline.png
  29. BIN
      res/drawable-xhdpi/ic_open_in_app.png
  30. BIN
      res/drawable-xhdpi/ic_pencil.png
  31. 0 0
      res/drawable-xxhdpi/ic_action_cancel_grey.png
  32. BIN
      res/drawable-xxhdpi/ic_action_cancel_white.png
  33. 0 0
      res/drawable-xxhdpi/ic_action_delete_grey.png
  34. BIN
      res/drawable-xxhdpi/ic_action_download.png
  35. 0 0
      res/drawable-xxhdpi/ic_action_refresh_white.png
  36. BIN
      res/drawable-xxhdpi/ic_action_set_available_offline.png
  37. BIN
      res/drawable-xxhdpi/ic_action_share.png
  38. BIN
      res/drawable-xxhdpi/ic_action_unset_available_offline.png
  39. BIN
      res/drawable-xxhdpi/ic_pencil.png
  40. 0 0
      res/drawable-xxxhdpi/ic_action_delete_grey.png
  41. BIN
      res/drawable-xxxhdpi/ic_action_download.png
  42. BIN
      res/drawable-xxxhdpi/ic_open_in_app.png
  43. 1 1
      res/layout/account_item.xml
  44. 1 1
      res/layout/file_details_fragment.xml
  45. 1 1
      res/layout/file_download_fragment.xml
  46. 10 0
      res/layout/grid_image.xml
  47. 9 1
      res/layout/grid_item.xml
  48. 26 17
      res/layout/list_item.xml
  49. 1 1
      res/layout/share_user_item.xml
  50. 1 4
      res/layout/text_file_preview.xml
  51. 0 1
      res/layout/toolbar_standard.xml
  52. 16 4
      res/menu/file_actions_menu.xml
  53. 1 1
      res/menu/main_menu.xml
  54. 3 1
      res/values-ar/strings.xml
  55. 0 1
      res/values-az/strings.xml
  56. 0 1
      res/values-bn-rBD/strings.xml
  57. 0 1
      res/values-da/strings.xml
  58. 0 1
      res/values-eo/strings.xml
  59. 0 1
      res/values-es-rAR/strings.xml
  60. 0 1
      res/values-es-rCL/strings.xml
  61. 0 1
      res/values-eu/strings.xml
  62. 0 1
      res/values-fa/strings.xml
  63. 0 1
      res/values-gl/strings.xml
  64. 0 1
      res/values-mk/strings.xml
  65. 0 1
      res/values-nn-rNO/strings.xml
  66. 0 1
      res/values-oc/strings.xml
  67. 1 0
      res/values-v21/styles.xml
  68. 6 1
      res/values/setup.xml
  69. 14 1
      res/values/strings.xml
  70. 3 0
      res/values/styles.xml
  71. 13 0
      src/com/owncloud/android/authentication/AuthenticatorActivity.java
  72. 9 3
      src/com/owncloud/android/authentication/AuthenticatorAsyncTask.java
  73. 1 0
      src/com/owncloud/android/datamodel/OCFile.java
  74. 4 2
      src/com/owncloud/android/datamodel/ThumbnailsCacheManager.java
  75. 156 48
      src/com/owncloud/android/files/FileMenuFilter.java
  76. 63 44
      src/com/owncloud/android/files/FileOperationsHelper.java
  77. 4 1
      src/com/owncloud/android/files/services/FileDownloader.java
  78. 4 1
      src/com/owncloud/android/files/services/FileUploader.java
  79. 72 0
      src/com/owncloud/android/operations/GetUserProfileOperation.java
  80. 13 4
      src/com/owncloud/android/operations/RefreshFolderOperation.java
  81. 5 5
      src/com/owncloud/android/services/OperationsService.java
  82. 0 2
      src/com/owncloud/android/syncadapter/AbstractOwnCloudSyncAdapter.java
  83. 11 7
      src/com/owncloud/android/ui/activity/FileActivity.java
  84. 53 33
      src/com/owncloud/android/ui/activity/FileDisplayActivity.java
  85. 8 10
      src/com/owncloud/android/ui/activity/FolderPickerActivity.java
  86. 3 3
      src/com/owncloud/android/ui/activity/LogHistoryActivity.java
  87. 4 3
      src/com/owncloud/android/ui/activity/ManageSpaceActivity.java
  88. 10 9
      src/com/owncloud/android/ui/activity/ReceiveExternalFilesActivity.java
  89. 14 2
      src/com/owncloud/android/ui/activity/ToolbarActivity.java
  90. 9 3
      src/com/owncloud/android/ui/adapter/ExpandableUploadListAdapter.java
  91. 112 107
      src/com/owncloud/android/ui/adapter/FileListListAdapter.java
  92. 1 0
      src/com/owncloud/android/ui/dialog/AccountActionsDialogFragment.java
  93. 0 159
      src/com/owncloud/android/ui/dialog/FileActionsDialogFragment.java
  94. 8 2
      src/com/owncloud/android/ui/dialog/RemoveFileDialogFragment.java
  95. 146 0
      src/com/owncloud/android/ui/dialog/RemoveFilesDialogFragment.java
  96. 32 53
      src/com/owncloud/android/ui/fragment/ExtendedListFragment.java
  97. 3 3
      src/com/owncloud/android/ui/fragment/FileDetailFragment.java
  98. 157 174
      src/com/owncloud/android/ui/fragment/OCFileListFragment.java
  99. 3 3
      src/com/owncloud/android/ui/preview/PreviewImageFragment.java
  100. 3 3
      src/com/owncloud/android/ui/preview/PreviewMediaFragment.java

+ 4 - 1
build.gradle

@@ -17,7 +17,7 @@ buildscript {
 apply plugin: 'com.android.application'
 
 ext {
-    supportLibraryVersion = '23.1.1'
+    supportLibraryVersion = '23.4.0'
 }
 
 repositories {
@@ -54,6 +54,9 @@ dependencies {
     // Android JUnit Runner
     androidTestCompile 'com.android.support.test:runner:0.5'
 
+    // Android Annotation Support
+    androidTestCompile "com.android.support:support-annotations:${supportLibraryVersion}"
+
     // Espresso core
     androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2.2'
 

BIN
res/drawable-hdpi/ic_action_cancel_grey.png


BIN
res/drawable-hdpi/ic_action_cancel_white.png


+ 0 - 0
res/drawable-hdpi/ic_action_delete.png → res/drawable-hdpi/ic_action_delete_grey.png


BIN
res/drawable-hdpi/ic_action_refresh_white.png


BIN
res/drawable-hdpi/ic_action_set_available_offline.png


BIN
res/drawable-hdpi/ic_action_share.png


BIN
res/drawable-hdpi/ic_action_unset_available_offline.png


BIN
res/drawable-hdpi/ic_open_in_app.png


BIN
res/drawable-hdpi/ic_pencil.png


BIN
res/drawable-mdpi/ic_action_cancel_grey.png


BIN
res/drawable-mdpi/ic_action_cancel_white.png


+ 0 - 0
res/drawable-mdpi/ic_action_delete.png → res/drawable-mdpi/ic_action_delete_grey.png


BIN
res/drawable-mdpi/ic_action_refresh_grey.png


BIN
res/drawable-mdpi/ic_action_refresh_white.png


BIN
res/drawable-mdpi/ic_action_set_available_offline.png


BIN
res/drawable-mdpi/ic_action_share.png


BIN
res/drawable-mdpi/ic_action_unset_available_offline.png


BIN
res/drawable-mdpi/ic_open_in_app.png


BIN
res/drawable-mdpi/ic_pencil.png


+ 0 - 0
res/drawable-xhdpi/ic_cancel.png → res/drawable-xhdpi/ic_action_cancel_grey.png


BIN
res/drawable-xhdpi/ic_action_cancel_white.png


+ 0 - 0
res/drawable-xhdpi/ic_action_delete.png → res/drawable-xhdpi/ic_action_delete_grey.png


BIN
res/drawable-xhdpi/ic_action_download.png


+ 0 - 0
res/drawable-xhdpi/ic_action_refresh.png → res/drawable-xhdpi/ic_action_refresh_white.png


BIN
res/drawable-xhdpi/ic_action_set_available_offline.png


BIN
res/drawable-xhdpi/ic_action_share.png


BIN
res/drawable-xhdpi/ic_action_unset_available_offline.png


BIN
res/drawable-xhdpi/ic_open_in_app.png


BIN
res/drawable-xhdpi/ic_pencil.png


+ 0 - 0
res/drawable-xxhdpi/ic_cancel.png → res/drawable-xxhdpi/ic_action_cancel_grey.png


BIN
res/drawable-xxhdpi/ic_action_cancel_white.png


+ 0 - 0
res/drawable-xxhdpi/ic_action_delete.png → res/drawable-xxhdpi/ic_action_delete_grey.png


BIN
res/drawable-xxhdpi/ic_action_download.png


+ 0 - 0
res/drawable-xxhdpi/ic_action_refresh.png → res/drawable-xxhdpi/ic_action_refresh_white.png


BIN
res/drawable-xxhdpi/ic_action_set_available_offline.png


BIN
res/drawable-xxhdpi/ic_action_share.png


BIN
res/drawable-xxhdpi/ic_action_unset_available_offline.png


BIN
res/drawable-xxhdpi/ic_pencil.png


+ 0 - 0
res/drawable-xxxhdpi/ic_action_delete.png → res/drawable-xxxhdpi/ic_action_delete_grey.png


BIN
res/drawable-xxxhdpi/ic_action_download.png


BIN
res/drawable-xxxhdpi/ic_open_in_app.png


+ 1 - 1
res/layout/account_item.xml

@@ -65,6 +65,6 @@
         android:paddingBottom="@dimen/standard_padding"
         android:paddingRight="@dimen/standard_padding"
         android:background="?android:selectableItemBackground"
-        android:src="@drawable/ic_action_delete"/>
+        android:src="@drawable/ic_action_delete_grey"/>
 
 </LinearLayout>         

+ 1 - 1
res/layout/file_details_fragment.xml

@@ -207,7 +207,7 @@
 						android:layout_width="wrap_content"
 						android:layout_height="wrap_content"
 						android:layout_marginLeft="12dp"
-						android:src="@drawable/ic_cancel"
+						android:src="@drawable/ic_action_cancel_grey"
 						android:background="@android:color/transparent"
 						/>
 						

+ 1 - 1
res/layout/file_download_fragment.xml

@@ -60,7 +60,7 @@
 			android:layout_width="wrap_content"
 			android:layout_height="wrap_content"
 			android:layout_marginLeft="12dp"
-			android:src="@drawable/ic_cancel"
+			android:src="@drawable/ic_action_cancel_grey"
 			android:background="@android:color/transparent"
 		/>
 

+ 10 - 0
res/layout/grid_image.xml

@@ -64,6 +64,16 @@
             android:layout_marginBottom="4dp"
             android:layout_marginRight="4dp"
             android:src="@drawable/ic_available_offline" />
+
+        <ImageView
+            android:id="@+id/custom_checkbox"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_vertical|top"
+            android:layout_marginLeft="4dp"
+            android:layout_marginRight="4dp"
+            android:gravity=""
+            android:src="@android:drawable/checkbox_off_background" />
     </FrameLayout>
 
 </LinearLayout>

+ 9 - 1
res/layout/grid_item.xml

@@ -65,7 +65,15 @@
             android:layout_marginRight="2dp"
             android:src="@drawable/ic_available_offline" />
 
-
+        <ImageView
+            android:id="@+id/custom_checkbox"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_vertical|top"
+            android:layout_marginLeft="4dp"
+            android:layout_marginRight="4dp"
+            android:src="@android:drawable/checkbox_off_background"
+            android:elevation="30dp" />
 
     </FrameLayout>
 

+ 26 - 17
res/layout/list_item.xml

@@ -121,26 +121,35 @@
 
         </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"
+        <RelativeLayout
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_gravity="center_vertical"
-            android:layout_marginLeft="4dp"
-            android:layout_marginRight="@dimen/standard_margin"
-            android:gravity=""
-            android:src="@drawable/ic_checkbox_blank_outline" />
+            android:paddingRight="@dimen/standard_padding">
+
+            <ImageView
+                android:id="@+id/sharedIcon"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center_vertical"
+                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"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center_vertical"
+                android:layout_marginLeft="4dp"
+
+                android:src="@drawable/ic_checkbox_blank_outline"
+                android:layout_toRightOf="@id/sharedIcon"/>
+        </RelativeLayout>
+
+
     </LinearLayout>
 
     <View

+ 1 - 1
res/layout/share_user_item.xml

@@ -52,7 +52,7 @@
             android:layout_width="36dp"
             android:layout_height="36dp"
             android:id="@+id/unshareButton"
-            android:src="@drawable/ic_action_delete"
+            android:src="@drawable/ic_action_delete_grey"
             android:layout_gravity="center_vertical"
             android:padding="@dimen/standard_half_padding"/>
 

+ 1 - 4
res/layout/text_file_preview.xml

@@ -25,10 +25,7 @@
         android:id="@+id/text_preview"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:layout_marginEnd="8dp"
-        android:layout_marginLeft="8dp"
-        android:layout_marginRight="8dp"
-        android:layout_marginStart="8dp"
+        android:padding="@dimen/standard_padding"
         android:textIsSelectable="true"
         android:visibility="gone"/>
 </ScrollView>

+ 0 - 1
res/layout/toolbar_standard.xml

@@ -38,7 +38,6 @@
         android:layout_width="match_parent"
         android:layout_height="4dp"
         android:layout_margin="0dp"
-        android:background="@color/primary"
         android:indeterminate="false"
         android:indeterminateOnly="false"
         android:padding="0dp"

+ 16 - 4
res/menu/file_actions_menu.xml

@@ -17,28 +17,32 @@
   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 -->
-<menu xmlns:android="http://schemas.android.com/apk/res/android">
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+      xmlns:app="http://schemas.android.com/apk/res-auto">
 
     <item
         android:id="@+id/action_share_file"
         android:title="@string/action_share"
         android:icon="@drawable/ic_share"
+        app:showAsAction="ifRoom"
         android:orderInCategory="1" />
-
     <item
         android:id="@+id/action_open_file_with"
         android:title="@string/actionbar_open_with"
-        android:icon="@drawable/ic_open_with"
+        android:icon="@drawable/ic_open_in_app"
+        app:showAsAction="never"
         android:orderInCategory="1" />
     <item
         android:id="@+id/action_download_file"
         android:title="@string/filedetails_download"
         android:icon="@drawable/ic_action_download"
+        app:showAsAction="ifRoom"
         android:orderInCategory="1" />
     <item
         android:id="@+id/action_sync_file"
         android:title="@string/filedetails_sync_file"
-        android:icon="@drawable/ic_action_refresh"
+        android:icon="@drawable/ic_action_refresh_white"
+        app:showAsAction="ifRoom"
         android:orderInCategory="1" />
     <item
         android:id="@+id/action_cancel_sync"
@@ -49,41 +53,49 @@
         android:id="@+id/action_rename_file"
         android:title="@string/common_rename"
         android:icon="@drawable/ic_edit"
+        app:showAsAction="never"
         android:orderInCategory="1" />
     <item
         android:id="@+id/action_move"
         android:title="@string/actionbar_move"
         android:icon="@drawable/ic_action_move"
+        app:showAsAction="ifRoom"
         android:orderInCategory="1" />
     <item
         android:id="@+id/action_copy"
         android:title="@android:string/copy"
         android:icon="@drawable/ic_action_copy"
+        app:showAsAction="ifRoom"
         android:orderInCategory="1" />
     <item
         android:id="@+id/action_remove_file"
         android:title="@string/common_remove"
         android:icon="@drawable/ic_action_delete_white"
+        app:showAsAction="ifRoom"
         android:orderInCategory="1" />
     <item
         android:id="@+id/action_send_file"
         android:title="@string/actionbar_send_file"
         android:icon="@drawable/ic_send"
+        app:showAsAction="never"
         android:orderInCategory="1" />
     <item
         android:id="@+id/action_favorite_file"
         android:title="@string/favorite"
         android:icon="@drawable/ic_action_set_available_offline_white"
+        app:showAsAction="never"
         android:orderInCategory="1" />
     <item
         android:id="@+id/action_unfavorite_file"
         android:title="@string/unfavorite"
         android:icon="@drawable/ic_action_unset_available_offline_white"
+        app:showAsAction="never"
         android:orderInCategory="1" />
     <item
         android:id="@+id/action_see_details"
         android:title="@string/actionbar_see_details"
         android:icon="@drawable/ic_information"
+        app:showAsAction="never"
         android:orderInCategory="1" />
 
 </menu>

+ 1 - 1
res/menu/main_menu.xml

@@ -35,7 +35,7 @@
         android:title="@string/action_switch_grid_view" />
     <item
         android:id="@+id/action_sync_account"
-        android:icon="@drawable/ic_action_refresh"
+        android:icon="@drawable/ic_action_refresh_white"
         android:orderInCategory="1"
         app:showAsAction="never"
         android:title="@string/actionbar_sync"

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

@@ -55,7 +55,6 @@
   <string name="sync_string_files">الملفات</string>
   <string name="setup_btn_connect">اتصال</string>
   <string name="uploader_btn_upload_text">رفع</string>
-  <string name="uploader_top_message">اختر مجلد الرفع</string>
   <string name="uploader_wrn_no_account_title">لم يتم العثور على أي حساب</string>
   <string name="uploader_wrn_no_account_text">لا توجد حسابات %1$s على جهازك.  أنت بحاجة لإعداد حساب في البداية.</string>
   <string name="uploader_wrn_no_account_setup_btn_text">تهيئة</string>
@@ -269,7 +268,10 @@
   <string name="prefs_category_accounts">حسابات</string>
   <string name="actionbar_logger">سجل</string>
   <string name="saml_authentication_wrong_pass">كلمة مرور خاطئة</string>
+  <string name="actionbar_move">أنقل</string>
   <string name="folder_picker_choose_button_text">اختيار</string>
+  <string name="move_file_invalid_overwrite">الملف موجود بالفعل في المجلد الوجهة</string>
+  <string name="copy_file_invalid_overwrite">الملف موجود بالفعل في المجلد الوجهة</string>
   <string name="prefs_category_details">تفاصيل</string>
   <string name="auth_host_address">عنوان الخادم</string>
   <string name="share_dialog_title">مشاركة</string>

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

@@ -47,7 +47,6 @@
   <string name="sync_string_files">Fayllar</string>
   <string name="setup_btn_connect">Qoşul</string>
   <string name="uploader_btn_upload_text">Serverə yüklə</string>
-  <string name="uploader_top_message">Yüklənmə qovluöunu seçin:</string>
   <string name="uploader_wrn_no_account_title">Hesab tapılmadı</string>
   <string name="uploader_wrn_no_account_setup_btn_text">Qurulum</string>
   <string name="uploader_wrn_no_account_quit_btn_text">Çıx</string>

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

@@ -38,7 +38,6 @@
   <string name="sync_string_files">ফাইল</string>
   <string name="setup_btn_connect">সংযুক্ত হও</string>
   <string name="uploader_btn_upload_text">আপলোড</string>
-  <string name="uploader_top_message">আপলোডের ফোলডার পছনদ করেন</string>
   <string name="uploader_wrn_no_account_title">কোন একাউন্ট খুঁজে পাওয়া গেল না</string>
   <string name="uploader_wrn_no_account_setup_btn_text">সেট-আপ</string>
   <string name="uploader_wrn_no_account_quit_btn_text">বন্ধ</string>

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

@@ -56,7 +56,6 @@
   <string name="sync_string_files">Filer</string>
   <string name="setup_btn_connect">Tilslut</string>
   <string name="uploader_btn_upload_text">Upload</string>
-  <string name="uploader_top_message">Vælg upload-mappe:</string>
   <string name="uploader_wrn_no_account_title">Ingen konto fundet</string>
   <string name="uploader_wrn_no_account_setup_btn_text">Opsætning</string>
   <string name="uploader_wrn_no_account_quit_btn_text">Afslut</string>

+ 0 - 1
res/values-eo/strings.xml

@@ -44,7 +44,6 @@
   <string name="sync_string_files">Dosieroj</string>
   <string name="setup_btn_connect">Konekti</string>
   <string name="uploader_btn_upload_text">Alŝuti</string>
-  <string name="uploader_top_message">Elektu alŝutan dosierujon:</string>
   <string name="uploader_wrn_no_account_title">Neniu konto troviĝis</string>
   <string name="uploader_wrn_no_account_setup_btn_text">Agordi</string>
   <string name="uploader_wrn_no_account_quit_btn_text">Forlasi</string>

+ 0 - 1
res/values-es-rAR/strings.xml

@@ -49,7 +49,6 @@
   <string name="sync_string_files">Archivos</string>
   <string name="setup_btn_connect">Conectar</string>
   <string name="uploader_btn_upload_text">Subir</string>
-  <string name="uploader_top_message">Elija la carpeta de subida:</string>
   <string name="uploader_wrn_no_account_title">No se encontraron cuentas</string>
   <string name="uploader_wrn_no_account_setup_btn_text">Configurar</string>
   <string name="uploader_wrn_no_account_quit_btn_text">Salir</string>

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

@@ -25,7 +25,6 @@
   <string name="sync_string_files">Archivos</string>
   <string name="setup_btn_connect">Conectar</string>
   <string name="uploader_btn_upload_text">Subir</string>
-  <string name="uploader_top_message">Elija el directorio donde subir los archivos:</string>
   <string name="uploader_wrn_no_account_title">No se encuentra la cuenta</string>
   <string name="uploader_wrn_no_account_setup_btn_text">Configuración</string>
   <string name="uploader_wrn_no_account_quit_btn_text">Salir</string>

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

@@ -53,7 +53,6 @@
   <string name="sync_string_files">Fitxategiak</string>
   <string name="setup_btn_connect">Konektatu</string>
   <string name="uploader_btn_upload_text">Igo</string>
-  <string name="uploader_top_message">Hautatu igoera karpeta:</string>
   <string name="uploader_wrn_no_account_title">Ez da konturik aurkitu</string>
   <string name="uploader_wrn_no_account_setup_btn_text">Konfiguratu</string>
   <string name="uploader_wrn_no_account_quit_btn_text">Irten</string>

+ 0 - 1
res/values-fa/strings.xml

@@ -44,7 +44,6 @@
   <string name="sync_string_files">پرونده‌ها</string>
   <string name="setup_btn_connect">اتصال</string>
   <string name="uploader_btn_upload_text">بارگزاری</string>
-  <string name="uploader_top_message">انتخاب پوشه آپلود:</string>
   <string name="uploader_wrn_no_account_title">هیچ حسابی یافت نشد</string>
   <string name="uploader_wrn_no_account_setup_btn_text">نصب</string>
   <string name="uploader_wrn_no_account_quit_btn_text">خروج</string>

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

@@ -54,7 +54,6 @@ Descárgueo de aquí: %2$s</string>
   <string name="sync_string_files">Ficheiros</string>
   <string name="setup_btn_connect">Conectar</string>
   <string name="uploader_btn_upload_text">Enviar</string>
-  <string name="uploader_top_message">Escolla o cartafol de envío:</string>
   <string name="uploader_wrn_no_account_title">Non se atoparon contas</string>
   <string name="uploader_wrn_no_account_setup_btn_text">Instalación</string>
   <string name="uploader_wrn_no_account_quit_btn_text">Saír</string>

+ 0 - 1
res/values-mk/strings.xml

@@ -51,7 +51,6 @@
   <string name="sync_string_files">Датотеки</string>
   <string name="setup_btn_connect">Поврзи се</string>
   <string name="uploader_btn_upload_text">Подигни</string>
-  <string name="uploader_top_message">Избери папка за префрлање:</string>
   <string name="uploader_wrn_no_account_title">Не е пронајдена сметка</string>
   <string name="uploader_wrn_no_account_setup_btn_text">Нагодување</string>
   <string name="uploader_wrn_no_account_quit_btn_text">Прекини</string>

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

@@ -53,7 +53,6 @@
   <string name="sync_string_files">Filer</string>
   <string name="setup_btn_connect">Kopla til</string>
   <string name="uploader_btn_upload_text">Last opp</string>
-  <string name="uploader_top_message">Vel opplastingsmappe:</string>
   <string name="uploader_wrn_no_account_title">Fann ingen konto</string>
   <string name="uploader_wrn_no_account_text">Det finst ingen %1$s-kontoar på eininga di. Ver venleg og set opp ein konto først.</string>
   <string name="uploader_wrn_no_account_setup_btn_text">Oppsett</string>

+ 0 - 1
res/values-oc/strings.xml

@@ -54,7 +54,6 @@ Telecargatz-lo aicí : %2$s</string>
   <string name="sync_string_files">Fichièrs</string>
   <string name="setup_btn_connect">Connectar</string>
   <string name="uploader_btn_upload_text">Mandar</string>
-  <string name="uploader_top_message">Seleccionar lo dorsièr de mandadís :</string>
   <string name="uploader_wrn_no_account_title">Cap de compte es pas estat trobat</string>
   <string name="uploader_wrn_no_account_setup_btn_text">Configuracion</string>
   <string name="uploader_wrn_no_account_quit_btn_text">Quitar</string>

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

@@ -27,6 +27,7 @@
         <item name="android:alertDialogTheme">@style/Theme.ownCloud.Dialog</item>
         <item name="alertDialogTheme">@style/ownCloud.AlertDialog</item>
         <item name="searchViewStyle">@style/ownCloud.SearchView</item>
+        <item name="windowActionModeOverlay">true</item>
     </style>
 
     <style name="Theme.ownCloud.Toolbar.Drawer">

+ 6 - 1
res/values/setup.xml

@@ -46,7 +46,12 @@
 
     <!-- Button -->
     <color name="button_text_color">#000000</color>
-    
+
+    <!-- Multiselect backgrounds -->
+    <color name="action_mode_background">#757575</color>
+    <color name="action_mode_status_bar_background">#616161</color>
+    <color name="selected_item_background">#ECECEC</color>
+
     <!-- Multiaccount support -->
     <bool name="multiaccount_support">true</bool>
     

+ 14 - 1
res/values/strings.xml

@@ -231,7 +231,7 @@
     <string name="unfavorite">Unset as available offline</string>
     <string name="common_rename">Rename</string>
     <string name="common_remove">Remove</string>
-    <string name="confirmation_remove_alert">"Do you really want to remove %1$s?"</string>
+    <string name="confirmation_remove_file_alert">"Do you really want to remove %1$s?"</string>
     <string name="confirmation_remove_folder_alert">"Do you really want to remove %1$s and its contents?"</string>
     <string name="confirmation_remove_local">Local only</string>
     <string name="remove_success_msg">"Removal succeeded"</string>
@@ -455,5 +455,18 @@
 
     <string name="permission_storage_access">Additional permissions required to upload &amp; download files.</string>
     <string name="local_file_not_found_toast">The file was not found in the local file system</string>
+    <string name="confirmation_remove_files_alert">Do you really want to remove the selected items?</string>
+    <string name="confirmation_remove_folders_alert">Do you really want to remove the selected items and their contents?</string>
+    <plurals name="items_selected_count">
+        <!--
+             As a developer, you should always supply "one" and "other"
+             strings. Your translators will know which strings are actually
+             needed for their language. Always include %d in "one" because
+             translators will need to use %d for languages where "one"
+             doesn't mean 1 (as explained above).
+          -->
+        <item quantity="one">%d selected</item>
+        <item quantity="other">%d selected</item>
+    </plurals>
 
 </resources>

+ 3 - 0
res/values/styles.xml

@@ -24,6 +24,8 @@
 	<style name="Theme.ownCloud" parent="Theme.AppCompat.Light.DarkActionBar">
     	<item name="android:actionBarStyle">@style/Theme.ownCloud.Widget.ActionBar</item>
     	<item name="actionBarStyle">@style/Theme.ownCloud.Widget.ActionBar</item>
+		<item name="actionModeBackground">@color/action_mode_background</item>
+		<item name="actionBarPopupTheme">@style/ThemeOverlay.AppCompat.Light</item>
 		<item name="colorPrimary">@color/primary</item>
 		<item name="colorPrimaryDark">@color/primary_dark</item>
 		<item name="colorAccent">@color/color_accent</item>
@@ -44,6 +46,7 @@
 		<item name="alertDialogTheme">@style/ownCloud.AlertDialog</item>
 		<item name="android:windowBackground">@color/background_color</item>
 		<item name="searchViewStyle">@style/ownCloud.SearchView</item>
+		<item name="windowActionModeOverlay">true</item>
     </style>
 
 	<!-- separate style for Drawer activities needed for v21+ theming -->

+ 13 - 0
src/com/owncloud/android/authentication/AuthenticatorActivity.java

@@ -80,6 +80,7 @@ import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCo
 import com.owncloud.android.lib.common.utils.Log_OC;
 import com.owncloud.android.lib.resources.status.OwnCloudVersion;
 import com.owncloud.android.lib.resources.users.GetRemoteUserInfoOperation;
+import com.owncloud.android.lib.resources.users.GetRemoteUserInfoOperation.UserInfo;
 import com.owncloud.android.operations.DetectAuthenticationMethodOperation.AuthenticationMethod;
 import com.owncloud.android.operations.GetServerInfoOperation;
 import com.owncloud.android.operations.OAuth2GetAccessToken;
@@ -1594,6 +1595,18 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
             mAccountMgr.setUserData(
                     mAccount, Constants.KEY_OC_BASE_URL,   mServerInfo.mBaseUrl
             );
+            if (authResult.getData() != null) {
+                try {
+                    UserInfo userInfo = (UserInfo) authResult.getData().get(0);
+                    mAccountMgr.setUserData(
+                        mAccount, Constants.KEY_DISPLAY_NAME, userInfo.mDisplayName
+                    );
+                } catch (ClassCastException c) {
+                    Log_OC.w(TAG, "Couldn't get display name for " + username);
+                }
+            } else {
+                Log_OC.w(TAG, "Couldn't get display name for " + username);
+            }
 
             if (isSaml) {
                 mAccountMgr.setUserData(mAccount, Constants.KEY_SUPPORTS_SAML_WEB_SSO, "TRUE"); 

+ 9 - 3
src/com/owncloud/android/authentication/AuthenticatorAsyncTask.java

@@ -30,6 +30,7 @@ import com.owncloud.android.lib.common.OwnCloudCredentials;
 import com.owncloud.android.lib.common.network.RedirectionPath;
 import com.owncloud.android.lib.common.operations.RemoteOperationResult;
 import com.owncloud.android.lib.resources.files.ExistenceCheckRemoteOperation;
+import com.owncloud.android.lib.resources.users.GetRemoteUserInfoOperation;
 
 import java.lang.ref.WeakReference;
 
@@ -44,11 +45,10 @@ public class AuthenticatorAsyncTask  extends AsyncTask<Object, Void, RemoteOpera
 
     private Context mContext;
     private final WeakReference<OnAuthenticatorTaskListener> mListener;
-    protected Activity mActivity;
 
     public AuthenticatorAsyncTask(Activity activity) {
         mContext = activity.getApplicationContext();
-        mListener = new WeakReference<OnAuthenticatorTaskListener>((OnAuthenticatorTaskListener)activity);
+        mListener = new WeakReference<>((OnAuthenticatorTaskListener)activity);
     }
 
     @Override
@@ -64,7 +64,7 @@ public class AuthenticatorAsyncTask  extends AsyncTask<Object, Void, RemoteOpera
             OwnCloudClient client = OwnCloudClientFactory.createOwnCloudClient(uri, mContext, true);
             client.setCredentials(credentials);
 
-            // Operation
+            // Operation - try credentials
             ExistenceCheckRemoteOperation operation = new ExistenceCheckRemoteOperation(
                     REMOTE_PATH,
                     mContext,
@@ -78,6 +78,12 @@ public class AuthenticatorAsyncTask  extends AsyncTask<Object, Void, RemoteOpera
                 result.setLastPermanentLocation(permanentLocation);
             }
 
+            // Operation - get display name
+            if (result.isSuccess()) {
+                GetRemoteUserInfoOperation remoteUserNameOperation = new GetRemoteUserInfoOperation();
+                result = remoteUserNameOperation.execute(client);
+            }
+
         } else {
             result = new RemoteOperationResult(RemoteOperationResult.ResultCode.UNKNOWN_ERROR);
         }

+ 1 - 0
src/com/owncloud/android/datamodel/OCFile.java

@@ -39,6 +39,7 @@ import third_parties.daveKoeller.AlphanumComparator;
 public class OCFile implements Parcelable, Comparable<OCFile> {
 
     public static final Parcelable.Creator<OCFile> CREATOR = new Parcelable.Creator<OCFile>() {
+
         @Override
         public OCFile createFromParcel(Parcel source) {
             return new OCFile(source);

+ 4 - 2
src/com/owncloud/android/datamodel/ThumbnailsCacheManager.java

@@ -196,8 +196,10 @@ public class ThumbnailsCacheManager {
 
             try {
                 if (mAccount != null) {
-                    OwnCloudAccount ocAccount = new OwnCloudAccount(mAccount,
-                            MainApp.getAppContext());
+                    OwnCloudAccount ocAccount = new OwnCloudAccount(
+                            mAccount,
+                            MainApp.getAppContext()
+                    );
                     mClient = OwnCloudClientManagerFactory.getDefaultSingleton().
                             getClientFor(ocAccount, MainApp.getAppContext());
                 }

+ 156 - 48
src/com/owncloud/android/files/FileMenuFilter.java

@@ -27,7 +27,6 @@ import android.view.MenuItem;
 
 import com.owncloud.android.R;
 import com.owncloud.android.datamodel.OCFile;
-import com.owncloud.android.files.services.FileDownloader;
 import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder;
 import com.owncloud.android.files.services.FileUploader.FileUploaderBinder;
 import com.owncloud.android.lib.resources.status.OCCapability;
@@ -35,6 +34,9 @@ import com.owncloud.android.services.OperationsService.OperationsServiceBinder;
 import com.owncloud.android.ui.activity.ComponentsGetter;
 
 import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
 import java.util.List;
 
 /**
@@ -43,7 +45,9 @@ import java.util.List;
  */
 public class FileMenuFilter {
 
-    private OCFile mFile;
+    private static final int SINGLE_SELECT_ITEMS = 1;
+
+    private Collection<OCFile> mFiles;
     private ComponentsGetter mComponentsGetter;
     private Account mAccount;
     private Context mContext;
@@ -51,20 +55,31 @@ public class FileMenuFilter {
     /**
      * Constructor
      *
-     * @param targetFile        {@link OCFile} target of the action to filter in the {@link Menu}.
+     * @param targetFiles       Collection of {@link OCFile} file targets of the action to filter in the {@link Menu}.
      * @param account           ownCloud {@link Account} holding targetFile.
-     * @param cg                Accessor to app components, needed to access the
-     *                          {@link FileUploader} and {@link FileDownloader} services
+     * @param cg                Accessor to app components, needed to access synchronization services
      * @param context           Android {@link Context}, needed to access build setup resources.
      */
-    public FileMenuFilter(OCFile targetFile, Account account, ComponentsGetter cg,
+    public FileMenuFilter(Collection<OCFile> targetFiles, Account account, ComponentsGetter cg,
                           Context context) {
-        mFile = targetFile;
+        mFiles = targetFiles;
         mAccount = account;
         mComponentsGetter = cg;
         mContext = context;
     }
 
+    /**
+     * Constructor
+     *
+     * @param targetFile        {@link OCFile} target of the action to filter in the {@link Menu}.
+     * @param account           ownCloud {@link Account} holding targetFile.
+     * @param cg                Accessor to app components, needed to access synchronization services
+     * @param context           Android {@link Context}, needed to access build setup resources.
+     */
+    public FileMenuFilter(OCFile targetFile, Account account, ComponentsGetter cg,
+                          Context context) {
+        this(Arrays.asList(new OCFile[]{targetFile}), account, cg, context);
+    }
 
     /**
      * Filters out the file actions available in the passed {@link Menu} taken into account
@@ -73,26 +88,40 @@ public class FileMenuFilter {
      * @param menu              Options or context menu to filter.
      */
     public void filter(Menu menu) {
-        List<Integer> toShow = new ArrayList<Integer>();
-        List<Integer> toHide = new ArrayList<Integer>();
+        if (mFiles == null || mFiles.size() <= 0) {
+            hideAll(menu);
 
-        filter(toShow, toHide);
+        } else {
+            List<Integer> toShow = new ArrayList<Integer>();
+            List<Integer> toHide = new ArrayList<Integer>();
+
+            filter(toShow, toHide);
+
+            MenuItem item;
+            for (int i : toShow) {
+                item = menu.findItem(i);
+                if (item != null) {
+                    item.setVisible(true);
+                    item.setEnabled(true);
+                }
+            }
 
-        MenuItem item = null;
-        for (int i : toShow) {
-            item = menu.findItem(i);
-            if (item != null) {
-                item.setVisible(true);
-                item.setEnabled(true);
+            for (int i : toHide) {
+                item = menu.findItem(i);
+                if (item != null) {
+                    item.setVisible(false);
+                    item.setEnabled(false);
+                }
             }
         }
+    }
 
-        for (int i : toHide) {
-            item = menu.findItem(i);
-            if (item != null) {
-                item.setVisible(false);
-                item.setEnabled(false);
-            }
+    private void hideAll(Menu menu) {
+        MenuItem item;
+        for (int i=0; i<menu.size(); i++) {
+            item = menu.getItem(i);
+            item.setVisible(false);
+            item.setEnabled(false);
         }
     }
 
@@ -106,25 +135,12 @@ public class FileMenuFilter {
      * @param toHide            List to save the options that must be shown in the menu.
      */
     private void filter(List<Integer> toShow, List <Integer> toHide) {
-        boolean synchronizing = false;
-        if (mComponentsGetter != null && mFile != null && mAccount != null) {
-            OperationsServiceBinder opsBinder = mComponentsGetter.getOperationsServiceBinder();
-            FileUploaderBinder uploaderBinder = mComponentsGetter.getFileUploaderBinder();
-            FileDownloaderBinder downloaderBinder = mComponentsGetter.getFileDownloaderBinder();
-            synchronizing = (
-                // comparing local and remote
-                (opsBinder != null && opsBinder.isSynchronizing(mAccount, mFile.getRemotePath())) ||
-                // downloading
-                (downloaderBinder != null && downloaderBinder.isDownloading(mAccount, mFile)) ||
-                // uploading
-                (uploaderBinder != null && uploaderBinder.isUploading(mAccount, mFile))
-            );
-        }
+        boolean synchronizing = anyFileSynchronizing();
 
         /// decision is taken for each possible action on a file in the menu
 
         // DOWNLOAD 
-        if (mFile == null || mFile.isDown() || mFile.isFolder() || synchronizing) {
+        if (mFiles.isEmpty() || containsFolder() || anyFileDown() || synchronizing) {
             toHide.add(R.id.action_download_file);
 
         } else {
@@ -132,7 +148,7 @@ public class FileMenuFilter {
         }
 
         // RENAME
-        if (mFile == null || synchronizing) {
+        if (!isSingleSelection() || synchronizing) {
             toHide.add(R.id.action_rename_file);
 
         } else {
@@ -140,7 +156,7 @@ public class FileMenuFilter {
         }
 
         // MOVE & COPY
-        if (mFile == null || synchronizing) {
+        if (mFiles.isEmpty() || synchronizing) {
             toHide.add(R.id.action_move);
             toHide.add(R.id.action_copy);
         } else {
@@ -149,7 +165,7 @@ public class FileMenuFilter {
         }
 
         // REMOVE
-        if (mFile == null || synchronizing) {
+        if (mFiles.isEmpty() || synchronizing) {
             toHide.add(R.id.action_remove_file);
 
         } else {
@@ -157,7 +173,7 @@ public class FileMenuFilter {
         }
 
         // OPEN WITH (different to preview!)
-        if (mFile == null || mFile.isFolder() || !mFile.isDown() || synchronizing) {
+        if (!isSingleFile() || !anyFileDown() || synchronizing) {
             toHide.add(R.id.action_open_file_with);
 
         } else {
@@ -165,7 +181,7 @@ public class FileMenuFilter {
         }
 
         // CANCEL SYNCHRONIZATION
-        if (mFile == null || !synchronizing) {
+        if (mFiles.isEmpty() || !synchronizing) {
             toHide.add(R.id.action_cancel_sync);
 
         } else {
@@ -173,7 +189,7 @@ public class FileMenuFilter {
         }
 
         // SYNC CONTENTS (BOTH FILE AND FOLDER)
-        if (mFile == null || (!mFile.isFolder() && !mFile.isDown()) || synchronizing) {
+        if (mFiles.isEmpty() || (!anyFileDown() && !containsFolder()) || synchronizing) {
             toHide.add(R.id.action_sync_file);
 
         } else {
@@ -191,14 +207,14 @@ public class FileMenuFilter {
                 (capability.getFilesSharingApiEnabled().isTrue() ||
                         capability.getFilesSharingApiEnabled().isUnknown()
                 );
-        if ((!shareViaLinkAllowed && !shareWithUsersAllowed) ||  mFile == null || !shareApiEnabled) {
+        if ((!shareViaLinkAllowed && !shareWithUsersAllowed) || !isSingleSelection() || !shareApiEnabled) {
             toHide.add(R.id.action_share_file);
         } else {
             toShow.add(R.id.action_share_file);
         }
 
         // SEE DETAILS
-        if (mFile == null || mFile.isFolder()) {
+        if (!isSingleFile()) {
             toHide.add(R.id.action_see_details);
         } else {
             toShow.add(R.id.action_see_details);
@@ -207,21 +223,21 @@ public class FileMenuFilter {
         // SEND
         boolean sendAllowed = (mContext != null &&
                 mContext.getString(R.string.send_files_to_other_apps).equalsIgnoreCase("on"));
-        if (mFile == null || !sendAllowed || mFile.isFolder() || synchronizing) {
+        if (!isSingleFile() || !sendAllowed || synchronizing) {
             toHide.add(R.id.action_send_file);
         } else {
             toShow.add(R.id.action_send_file);
         }
 
         // FAVORITES
-        if (mFile == null || synchronizing || mFile.isFolder() || mFile.isFavorite()) {
+        if (!allFiles() || synchronizing || allFavorites()) {
             toHide.add(R.id.action_favorite_file);
         } else {
             toShow.add(R.id.action_favorite_file);
         }
 
         // UNFAVORITES
-        if (mFile == null || synchronizing || mFile.isFolder() || !mFile.isFavorite()) {
+        if (!allFiles() || synchronizing || allUnfavorites()) {
             toHide.add(R.id.action_unfavorite_file);
         } else {
             toShow.add(R.id.action_unfavorite_file);
@@ -229,4 +245,96 @@ public class FileMenuFilter {
 
     }
 
+    private boolean anyFileSynchronizing() {
+        boolean synchronizing = false;
+        if (mComponentsGetter != null && !mFiles.isEmpty() && mAccount != null) {
+            OperationsServiceBinder opsBinder = mComponentsGetter.getOperationsServiceBinder();
+            FileUploaderBinder uploaderBinder = mComponentsGetter.getFileUploaderBinder();
+            FileDownloaderBinder downloaderBinder = mComponentsGetter.getFileDownloaderBinder();
+            synchronizing = (
+                anyFileSynchronizing(opsBinder) ||      // comparing local and remote
+                anyFileDownloading(downloaderBinder) ||
+                anyFileUploading(uploaderBinder)
+            );
+        }
+        return synchronizing;
+    }
+
+    private boolean anyFileSynchronizing(OperationsServiceBinder opsBinder) {
+        boolean synchronizing = false;
+        if (opsBinder != null) {
+            for (Iterator<OCFile> iterator = mFiles.iterator(); !synchronizing && iterator.hasNext();) {
+                synchronizing = opsBinder.isSynchronizing(mAccount, iterator.next());
+            }
+        }
+        return synchronizing;
+    }
+
+    private boolean anyFileDownloading(FileDownloaderBinder downloaderBinder) {
+        boolean downloading = false;
+        if (downloaderBinder != null) {
+            for (Iterator<OCFile> iterator = mFiles.iterator(); !downloading && iterator.hasNext();) {
+                downloading = downloaderBinder.isDownloading(mAccount, iterator.next());
+            }
+        }
+        return downloading;
+    }
+
+    private boolean anyFileUploading(FileUploaderBinder uploaderBinder) {
+        boolean uploading = false;
+        if (uploaderBinder != null) {
+            for (Iterator<OCFile> iterator = mFiles.iterator(); !uploading && iterator.hasNext();) {
+                uploading = uploaderBinder.isUploading(mAccount, iterator.next());
+            }
+        }
+        return uploading;
+    }
+
+    private boolean isSingleSelection() {
+        return mFiles.size() == SINGLE_SELECT_ITEMS;
+    }
+
+    private boolean isSingleFile() {
+        return isSingleSelection() && !mFiles.iterator().next().isFolder();
+    }
+
+    private boolean allFiles() {
+        return mFiles != null && !containsFolder();
+    }
+
+    private boolean containsFolder() {
+        for(OCFile file: mFiles) {
+            if(file.isFolder()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private boolean anyFileDown() {
+        for(OCFile file: mFiles) {
+            if(file.isDown()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private boolean allFavorites() {
+        for(OCFile file: mFiles) {
+            if(!file.isFavorite()) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private boolean allUnfavorites() {
+        for(OCFile file: mFiles) {
+            if(file.isFavorite()) {
+                return false;
+            }
+        }
+        return true;
+    }
 }

+ 63 - 44
src/com/owncloud/android/files/FileOperationsHelper.java

@@ -53,8 +53,11 @@ import com.owncloud.android.ui.activity.ShareActivity;
 import com.owncloud.android.ui.dialog.ShareLinkToDialog;
 import com.owncloud.android.ui.dialog.SharePasswordDialogFragment;
 
+import java.util.Collection;
 import java.util.List;
 
+import java.util.ArrayList;
+
 /**
  *
  */
@@ -398,7 +401,7 @@ public class FileOperationsHelper {
     /**
      * @return 'True' if the server supports the Search Users API
      */
-    public boolean isSearchUsersSupportedSupported() {
+    public boolean isSearchUserSupportedSupported() {
         if (mFileActivity.getAccount() != null) {
             OwnCloudVersion serverVersion = AccountUtils.getServerVersion(mFileActivity.getAccount());
             return (serverVersion != null && serverVersion.isSearchUsersSupported());
@@ -426,6 +429,12 @@ public class FileOperationsHelper {
         }
     }
 
+    public void syncFiles(Collection<OCFile> files) {
+        for (OCFile file: files) {
+            syncFile(file);
+        }
+    }
+
     /**
      * Request the synchronization of a file or folder with the OC server, including its contents.
      *
@@ -452,6 +461,12 @@ public class FileOperationsHelper {
         }
     }
 
+    public void toggleFavorites(Collection<OCFile> files, boolean isFavorite){
+        for (OCFile file: files) {
+            toggleFavorite(file, isFavorite);
+        }
+    }
+
     public void toggleFavorite(OCFile file, boolean isFavorite) {
         file.setFavorite(isFavorite);
         mFileActivity.getStorageManager().saveFile(file);
@@ -479,22 +494,29 @@ public class FileOperationsHelper {
         service.putExtra(OperationsService.EXTRA_NEWNAME, newFilename);
         mWaitingForOpId = mFileActivity.getOperationsServiceBinder().queueNewOperation(service);
         
-        mFileActivity.showLoadingDialog(mFileActivity.getApplicationContext().
-                getString(R.string.wait_a_moment));
+        mFileActivity.showLoadingDialog(mFileActivity.getString(R.string.wait_a_moment));
     }
 
 
-    public void removeFile(OCFile file, boolean onlyLocalCopy) {
-        // RemoveFile
-        Intent service = new Intent(mFileActivity, OperationsService.class);
-        service.setAction(OperationsService.ACTION_REMOVE);
-        service.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
-        service.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
-        service.putExtra(OperationsService.EXTRA_REMOVE_ONLY_LOCAL, onlyLocalCopy);
-        mWaitingForOpId =  mFileActivity.getOperationsServiceBinder().queueNewOperation(service);
+    /**
+     * Start operations to delete one or several files
+     *
+     * @param files             Files to delete
+     * @param onlyLocalCopy     When 'true' only local copy of the files is removed; otherwise files are also deleted
+     *                          in the server.
+     */
+    public void removeFiles(Collection<OCFile> files, boolean onlyLocalCopy) {
+        for (OCFile file : files) {
+            // RemoveFile
+            Intent service = new Intent(mFileActivity, OperationsService.class);
+            service.setAction(OperationsService.ACTION_REMOVE);
+            service.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
+            service.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
+            service.putExtra(OperationsService.EXTRA_REMOVE_ONLY_LOCAL, onlyLocalCopy);
+            mWaitingForOpId = mFileActivity.getOperationsServiceBinder().queueNewOperation(service);
+        }
         
-        mFileActivity.showLoadingDialog(mFileActivity.getApplicationContext().
-                getString(R.string.wait_a_moment));
+        mFileActivity.showLoadingDialog(mFileActivity.getString(R.string.wait_a_moment));
     }
 
 
@@ -507,8 +529,7 @@ public class FileOperationsHelper {
         service.putExtra(OperationsService.EXTRA_CREATE_FULL_PATH, createFullPath);
         mWaitingForOpId =  mFileActivity.getOperationsServiceBinder().queueNewOperation(service);
         
-        mFileActivity.showLoadingDialog(mFileActivity.getApplicationContext().
-                getString(R.string.wait_a_moment));
+        mFileActivity.showLoadingDialog(mFileActivity.getString(R.string.wait_a_moment));
     }
 
     /**
@@ -537,41 +558,39 @@ public class FileOperationsHelper {
     }
 
     /**
-     * Start move file operation
+     * Start operations to move one or several files
      *
-     * @param newfile     File where it is going to be moved
-     * @param currentFile File with the previous info
+     * @param files            Files to move
+     * @param targetFolder     Folder where the files while be moved into
      */
-    public void moveFile(OCFile newfile, OCFile currentFile) {
-        // Move files
-        Intent service = new Intent(mFileActivity, OperationsService.class);
-        service.setAction(OperationsService.ACTION_MOVE_FILE);
-        service.putExtra(OperationsService.EXTRA_NEW_PARENT_PATH, newfile.getRemotePath());
-        service.putExtra(OperationsService.EXTRA_REMOTE_PATH, currentFile.getRemotePath());
-        service.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
-        mWaitingForOpId =  mFileActivity.getOperationsServiceBinder().queueNewOperation(service);
-
-        mFileActivity.showLoadingDialog(mFileActivity.getApplicationContext().
-                getString(R.string.wait_a_moment));
+    public void moveFiles(Collection<OCFile> files, OCFile targetFolder) {
+        for (OCFile file : files) {
+            Intent service = new Intent(mFileActivity, OperationsService.class);
+            service.setAction(OperationsService.ACTION_MOVE_FILE);
+            service.putExtra(OperationsService.EXTRA_NEW_PARENT_PATH, targetFolder.getRemotePath());
+            service.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
+            service.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
+            mWaitingForOpId = mFileActivity.getOperationsServiceBinder().queueNewOperation(service);
+        }
+        mFileActivity.showLoadingDialog(mFileActivity.getString(R.string.wait_a_moment));
     }
 
     /**
-     * Start copy file operation
+     * Start operations to copy one or several files
      *
-     * @param newfile     File where it is going to be moved
-     * @param currentFile File with the previous info
+     * @param files            Files to copy
+     * @param targetFolder     Folder where the files while be copied into
      */
-    public void copyFile(OCFile newfile, OCFile currentFile) {
-        // Copy files
-        Intent service = new Intent(mFileActivity, OperationsService.class);
-        service.setAction(OperationsService.ACTION_COPY_FILE);
-        service.putExtra(OperationsService.EXTRA_NEW_PARENT_PATH, newfile.getRemotePath());
-        service.putExtra(OperationsService.EXTRA_REMOTE_PATH, currentFile.getRemotePath());
-        service.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
-        mWaitingForOpId = mFileActivity.getOperationsServiceBinder().queueNewOperation(service);
-
-        mFileActivity.showLoadingDialog(mFileActivity.getApplicationContext().
-                getString(R.string.wait_a_moment));
+    public void copyFiles(Collection<OCFile> files, OCFile targetFolder) {
+        for (OCFile file : files) {
+            Intent service = new Intent(mFileActivity, OperationsService.class);
+            service.setAction(OperationsService.ACTION_COPY_FILE);
+            service.putExtra(OperationsService.EXTRA_NEW_PARENT_PATH, targetFolder.getRemotePath());
+            service.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
+            service.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
+            mWaitingForOpId = mFileActivity.getOperationsServiceBinder().queueNewOperation(service);
+        }
+        mFileActivity.showLoadingDialog(mFileActivity.getString(R.string.wait_a_moment));
     }
 
     public long getOpIdWaitingFor() {
@@ -607,7 +626,7 @@ public class FileOperationsHelper {
         mWaitingForOpId = mFileActivity.getOperationsServiceBinder().queueNewOperation(service);
 
         mFileActivity.showLoadingDialog(
-            mFileActivity.getApplicationContext().getString(R.string.wait_checking_credentials)
+            mFileActivity.getString(R.string.wait_checking_credentials)
         );
     }
 }

+ 4 - 1
src/com/owncloud/android/files/services/FileDownloader.java

@@ -411,7 +411,10 @@ public class FileDownloader extends Service
 
                     // always get client from client manager, to get fresh credentials in case
                     // of update
-                    OwnCloudAccount ocAccount = new OwnCloudAccount(mCurrentAccount, this);
+                    OwnCloudAccount ocAccount = new OwnCloudAccount(
+                            mCurrentAccount,
+                            this
+                    );
                     mDownloadClient = OwnCloudClientManagerFactory.getDefaultSingleton().
                             getClientFor(ocAccount, this);
 

+ 4 - 1
src/com/owncloud/android/files/services/FileUploader.java

@@ -910,7 +910,10 @@ public class FileUploader extends Service
                 }   // else, reuse storage manager from previous operation
 
                 // always get client from client manager, to get fresh credentials in case of update
-                OwnCloudAccount ocAccount = new OwnCloudAccount(mCurrentAccount, this);
+                OwnCloudAccount ocAccount = new OwnCloudAccount(
+                        mCurrentAccount,
+                        this
+                );
                 mUploadClient = OwnCloudClientManagerFactory.getDefaultSingleton().
                         getClientFor(ocAccount, this);
 

+ 72 - 0
src/com/owncloud/android/operations/GetUserProfileOperation.java

@@ -0,0 +1,72 @@
+/**
+ *   ownCloud Android client application
+ *
+ *   @author David A. Velasco
+ *   Copyright (C) 2016 ownCloud Inc.
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License version 2,
+ *   as published by the Free Software Foundation.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+package com.owncloud.android.operations;
+
+import android.accounts.Account;
+import android.accounts.AccountManager;
+
+import com.owncloud.android.MainApp;
+import com.owncloud.android.lib.common.OwnCloudClient;
+import com.owncloud.android.lib.common.accounts.AccountUtils;
+import com.owncloud.android.lib.common.operations.RemoteOperationResult;
+import com.owncloud.android.lib.resources.users.GetRemoteUserInfoOperation;
+import com.owncloud.android.lib.resources.users.GetRemoteUserInfoOperation.UserInfo;
+import com.owncloud.android.operations.common.SyncOperation;
+
+/**
+ * Get and save user's profile from the server.
+ *
+ * Currently only retrieves the display name.
+ */
+public class GetUserProfileOperation extends SyncOperation {
+
+    /**
+     * Performs the operation.
+     *
+     * Target user account is implicit in 'client'.
+     *
+     * Stored account is implicit in {@link #getStorageManager()}.
+     *
+     * @return      Result of the operation. If successful, includes an instance of
+     *              {@link String} with the display name retrieved from the server.
+     *              Call {@link RemoteOperationResult#getData()}.get(0) to get it.
+     */
+    @Override
+    protected RemoteOperationResult run(OwnCloudClient client) {
+
+        // get display name
+        GetRemoteUserInfoOperation getDisplayName = new GetRemoteUserInfoOperation();
+        RemoteOperationResult result = getDisplayName.execute(client);
+
+        if (result.isSuccess()) {
+            // store display name with account data
+            AccountManager accountManager = AccountManager.get(MainApp.getAppContext());
+            UserInfo userInfo = (UserInfo) result.getData().get(0);
+            Account storedAccount = getStorageManager().getAccount();
+            accountManager.setUserData(
+                storedAccount,
+                AccountUtils.Constants.KEY_DISPLAY_NAME,
+                userInfo.mDisplayName
+            );
+        }
+        return result;
+    }
+
+}

+ 13 - 4
src/com/owncloud/android/operations/RefreshFolderOperation.java

@@ -185,7 +185,7 @@ public class RefreshFolderOperation extends RemoteOperation {
         
         if (OCFile.ROOT_PATH.equals(mLocalFolder.getRemotePath()) && !mSyncFullAccount) {
             updateOCVersion(client);
-
+            updateUserProfile();
         }
         
         result = checkForChanges(client);
@@ -224,7 +224,6 @@ public class RefreshFolderOperation extends RemoteOperation {
         
     }
 
-
     private void updateOCVersion(OwnCloudClient client) {
         UpdateOCVersionOperation update = new UpdateOCVersionOperation(mAccount, mContext);
         RemoteOperationResult result = update.execute(client);
@@ -233,14 +232,24 @@ public class RefreshFolderOperation extends RemoteOperation {
 
             // Update Capabilities for this account
             if (update.getOCVersion().isVersionWithCapabilitiesAPI()) {
-                updateCapabilities(client);
+                updateCapabilities();
             } else {
                 Log_OC.d(TAG, "Capabilities API disabled");
             }
         }
     }
 
-    private void updateCapabilities(OwnCloudClient client){
+    private void updateUserProfile() {
+        GetUserProfileOperation update = new GetUserProfileOperation();
+        RemoteOperationResult result = update.execute(mStorageManager, mContext);
+        if (!result.isSuccess()) {
+            Log_OC.w(TAG, "Couldn't update user profile from server");
+        } else {
+            Log_OC.i(TAG, "Got display name: " + result.getData().get(0));
+        }
+    }
+
+    private void updateCapabilities(){
         GetCapabilitiesOperarion getCapabilities = new GetCapabilitiesOperarion();
         RemoteOperationResult  result = getCapabilities.execute(mStorageManager,mContext);
         if (!result.isSuccess()){

+ 5 - 5
src/com/owncloud/android/services/OperationsService.java

@@ -71,6 +71,7 @@ import com.owncloud.android.operations.common.SyncOperation;
 
 import java.io.IOException;
 import java.util.Iterator;
+import java.util.List;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentLinkedQueue;
 import java.util.concurrent.ConcurrentMap;
@@ -380,11 +381,11 @@ public class OperationsService extends Service {
          * or waiting to download.
          * 
          * @param account       ownCloud account where the remote file is stored.
-         * @param remotePath    Path of the folder to check if something is synchronizing
+         * @param file          File to check if something is synchronizing
          *                      / downloading / uploading inside.
          */
-        public boolean isSynchronizing(Account account, String remotePath) {
-            return mSyncFolderHandler.isSynchronizing(account, remotePath);
+        public boolean isSynchronizing(Account account, OCFile file) {
+            return mSyncFolderHandler.isSynchronizing(account, file.getRemotePath());
         }
 
     }
@@ -448,8 +449,7 @@ public class OperationsService extends Service {
                     if (mLastTarget == null || !mLastTarget.equals(next.first)) {
                         mLastTarget = next.first;
                         if (mLastTarget.mAccount != null) {
-                            OwnCloudAccount ocAccount = new OwnCloudAccount(mLastTarget.mAccount,
-                                    mService);
+                            OwnCloudAccount ocAccount = new OwnCloudAccount(mLastTarget.mAccount, mService);
                             mOwnCloudClient = OwnCloudClientManagerFactory.getDefaultSingleton().
                                     getClientFor(ocAccount, mService);
 

+ 0 - 2
src/com/owncloud/android/syncadapter/AbstractOwnCloudSyncAdapter.java

@@ -25,7 +25,6 @@ package com.owncloud.android.syncadapter;
 import java.io.IOException;
 
 import com.owncloud.android.datamodel.FileDataStorageManager;
-import com.owncloud.android.lib.common.accounts.AccountUtils;
 import com.owncloud.android.lib.common.accounts.AccountUtils.AccountNotFoundException;
 import com.owncloud.android.lib.common.OwnCloudAccount;
 import com.owncloud.android.lib.common.OwnCloudClient;
@@ -100,7 +99,6 @@ public abstract class AbstractOwnCloudSyncAdapter extends
 
     protected void initClientForCurrentAccount() throws OperationCanceledException,
             AuthenticatorException, IOException, AccountNotFoundException {
-        AccountUtils.constructFullURLForAccount(getContext(), account);
         OwnCloudAccount ocAccount = new OwnCloudAccount(account, getContext());
         mClient = OwnCloudClientManagerFactory.getDefaultSingleton().
                 getClientFor(ocAccount, getContext());

+ 11 - 7
src/com/owncloud/android/ui/activity/FileActivity.java

@@ -375,8 +375,7 @@ public class FileActivity extends DrawerActivity
                 account = getAccount();
             }
             OwnCloudClient client;
-            OwnCloudAccount ocAccount =
-                    new OwnCloudAccount(account, context);
+            OwnCloudAccount ocAccount = new OwnCloudAccount(account, context);
             client = (OwnCloudClientManagerFactory.getDefaultSingleton().
                     removeClientFor(ocAccount));
             if (client != null) {
@@ -461,11 +460,15 @@ public class FileActivity extends DrawerActivity
         // grant that only one waiting dialog is shown
         dismissLoadingDialog();
         // Construct dialog
-        LoadingDialog loading = new LoadingDialog(message);
-        FragmentManager fm = getSupportFragmentManager();
-        FragmentTransaction ft = fm.beginTransaction();
-        loading.show(ft, DIALOG_WAIT_TAG);
-
+        Fragment frag = getSupportFragmentManager().findFragmentByTag(DIALOG_WAIT_TAG);
+        if (frag == null) {
+            Log_OC.d(TAG, "show loading dialog");
+            LoadingDialog loading = new LoadingDialog(message);
+            FragmentManager fm = getSupportFragmentManager();
+            FragmentTransaction ft = fm.beginTransaction();
+            loading.show(ft, DIALOG_WAIT_TAG);
+            fm.executePendingTransactions();
+        }
     }
 
 
@@ -475,6 +478,7 @@ public class FileActivity extends DrawerActivity
     public void dismissLoadingDialog() {
         Fragment frag = getSupportFragmentManager().findFragmentByTag(DIALOG_WAIT_TAG);
         if (frag != null) {
+            Log_OC.d(TAG, "dismiss loading dialog");
             LoadingDialog loading = (LoadingDialog) frag;
             loading.dismiss();
         }

+ 53 - 33
src/com/owncloud/android/ui/activity/FileDisplayActivity.java

@@ -40,27 +40,22 @@ import android.os.Build;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.Parcelable;
-import android.support.design.widget.NavigationView;
 import android.support.design.widget.Snackbar;
 import android.support.v4.app.Fragment;
 import android.support.v4.app.FragmentManager;
 import android.support.v4.app.FragmentTransaction;
 import android.support.v4.content.ContextCompat;
-import android.support.v4.view.GravityCompat;
 import android.support.v7.app.AlertDialog;
-import android.support.v7.widget.Toolbar;
 import android.view.Menu;
 import android.view.MenuInflater;
 import android.view.MenuItem;
 import android.view.View;
-import android.widget.ProgressBar;
 import android.widget.Toast;
 
 import com.owncloud.android.MainApp;
 import com.owncloud.android.R;
 import com.owncloud.android.datamodel.FileDataStorageManager;
 import com.owncloud.android.datamodel.OCFile;
-import com.owncloud.android.db.PreferenceManager;
 import com.owncloud.android.files.services.FileDownloader;
 import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder;
 import com.owncloud.android.files.services.FileUploader;
@@ -95,6 +90,9 @@ import com.owncloud.android.utils.PermissionUtil;
 
 import java.io.File;
 import java.util.ArrayList;
+import java.util.Collection;
+
+import static com.owncloud.android.db.PreferenceManager.getSortOrder;
 
 /**
  * Displays, what files the user has available in his ownCloud. This is the main view.
@@ -323,6 +321,9 @@ public class FileDisplayActivity extends HookActivity
 
     private void createMinFragments() {
         OCFileListFragment listOfFiles = new OCFileListFragment();
+        Bundle args = new Bundle();
+        args.putBoolean(OCFileListFragment.ARG_ALLOW_CONTEXTUAL_ACTIONS, true);
+        listOfFiles.setArguments(args);
         FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
         transaction.add(R.id.left_fragment_container, listOfFiles, TAG_LIST_OF_FILES);
         transaction.commit();
@@ -552,7 +553,7 @@ public class FileDisplayActivity extends HookActivity
                 break;
             }
             case R.id.action_sort: {
-                Integer sortOrder = PreferenceManager.getSortOrder(this);
+                Integer sortOrder = getSortOrder(this);
 
                 AlertDialog.Builder builder = new AlertDialog.Builder(this);
                 builder.setTitle(R.string.actionbar_sort_title)
@@ -647,12 +648,11 @@ public class FileDisplayActivity extends HookActivity
 
         } else if (requestCode == REQUEST_CODE__MOVE_FILES && resultCode == RESULT_OK) {
             final Intent fData = data;
-            final int fResultCode = resultCode;
             getHandler().postDelayed(
                     new Runnable() {
                         @Override
                         public void run() {
-                            requestMoveOperation(fData, fResultCode);
+                            requestMoveOperation(fData);
                         }
                     },
                     DELAY_TO_REQUEST_OPERATIONS_LATER
@@ -666,7 +666,7 @@ public class FileDisplayActivity extends HookActivity
                     new Runnable() {
                         @Override
                         public void run() {
-                            requestCopyOperation(fData, fResultCode);
+                            requestCopyOperation(fData);
                         }
                     },
                     DELAY_TO_REQUEST_OPERATIONS_LATER
@@ -752,24 +752,22 @@ public class FileDisplayActivity extends HookActivity
      * Request the operation for moving the file/folder from one path to another
      *
      * @param data       Intent received
-     * @param resultCode Result code received
      */
-    private void requestMoveOperation(Intent data, int resultCode) {
-        OCFile folderToMoveAt = (OCFile) data.getParcelableExtra(FolderPickerActivity.EXTRA_FOLDER);
-        OCFile targetFile = (OCFile) data.getParcelableExtra(FolderPickerActivity.EXTRA_FILE);
-        getFileOperationsHelper().moveFile(folderToMoveAt, targetFile);
+    private void requestMoveOperation(Intent data) {
+        OCFile folderToMoveAt = data.getParcelableExtra(FolderPickerActivity.EXTRA_FOLDER);
+        ArrayList<OCFile> files = data.getParcelableArrayListExtra(FolderPickerActivity.EXTRA_FILES);
+        getFileOperationsHelper().moveFiles(files, folderToMoveAt);
     }
 
     /**
      * Request the operation for copying the file/folder from one path to another
      *
      * @param data       Intent received
-     * @param resultCode Result code received
      */
-    private void requestCopyOperation(Intent data, int resultCode) {
+    private void requestCopyOperation(Intent data) {
         OCFile folderToMoveAt = data.getParcelableExtra(FolderPickerActivity.EXTRA_FOLDER);
-        OCFile targetFile = data.getParcelableExtra(FolderPickerActivity.EXTRA_FILE);
-        getFileOperationsHelper().copyFile(folderToMoveAt, targetFile);
+        ArrayList<OCFile> files = data.getParcelableArrayListExtra(FolderPickerActivity.EXTRA_FILES);
+        getFileOperationsHelper().copyFiles(files, folderToMoveAt);
     }
 
     @Override
@@ -963,30 +961,30 @@ public class FileDisplayActivity extends HookActivity
                                         .equals(event));
 
                         if (RefreshFolderOperation.EVENT_SINGLE_FOLDER_CONTENTS_SYNCED.
-                            equals(event) &&/// TODO refactor and make common
+                            equals(event)) {
+
+                            if (synchResult != null && !synchResult.isSuccess()) {
+                                /// TODO refactor and make common
 
-                            synchResult != null && !synchResult.isSuccess()) {
+                                if (checkForRemoteOperationError(synchResult)) {
 
-                            if(ResultCode.UNAUTHORIZED.equals(synchResult.getCode()) ||
-                                (synchResult.isException() && synchResult.getException()
-                                    instanceof AuthenticatorException)) {
+                                    requestCredentialsUpdate(context);
 
-                                requestCredentialsUpdate(context);
+                                } else if (RemoteOperationResult.ResultCode.SSL_RECOVERABLE_PEER_UNVERIFIED.equals(
+                                    synchResult.getCode())) {
 
-                            } else if(RemoteOperationResult.ResultCode.SSL_RECOVERABLE_PEER_UNVERIFIED.equals(
-                                synchResult.getCode())) {
+                                    showUntrustedCertDialog(synchResult);
+                                }
 
-                                showUntrustedCertDialog(synchResult);
                             }
 
                         }
+                        removeStickyBroadcast(intent);
+                        Log_OC.d(TAG, "Setting progress visibility to " + mSyncInProgress);
+                        setIndeterminate(mSyncInProgress);
 
+                        setBackgroundText();
                     }
-                    removeStickyBroadcast(intent);
-                    Log_OC.d(TAG, "Setting progress visibility to " + mSyncInProgress);
-                    setIndeterminate(mSyncInProgress);
-
-                    setBackgroundText();
                 }
 
                 if (synchResult != null) {
@@ -1003,6 +1001,12 @@ public class FileDisplayActivity extends HookActivity
         }
     }
 
+    private boolean checkForRemoteOperationError(RemoteOperationResult syncResult) {
+        return ResultCode.UNAUTHORIZED.equals(syncResult.getCode()) ||
+                (syncResult.isException() && syncResult.getException()
+                        instanceof AuthenticatorException);
+    }
+
     /**
      * Show a text message on screen view for notifying user if content is
      * loading or folder is empty
@@ -1720,6 +1724,11 @@ public class FileDisplayActivity extends HookActivity
     }
 
 
+    /**
+     * Request stopping the upload/download operation in progress over the given {@link OCFile} file.
+     *
+     * @param file {@link OCFile} file which operation are wanted to be cancel
+     */
     public void cancelTransference(OCFile file) {
         getFileOperationsHelper().cancelTransference(file);
         if (mWaitingToPreview != null &&
@@ -1733,6 +1742,17 @@ public class FileDisplayActivity extends HookActivity
         onTransferStateChanged(file, false, false);
     }
 
+    /**
+     * Request stopping all upload/download operations in progress over the given {@link OCFile} files.
+     *
+     * @param files collection of {@link OCFile} files which operations are wanted to be cancel
+     */
+    public void cancelTransference(Collection<OCFile> files) {
+        for(OCFile file: files) {
+            cancelTransference(file);
+        }
+    }
+
     @Override
     public void onRefresh(boolean ignoreETag) {
         refreshList(ignoreETag);
@@ -1768,7 +1788,7 @@ public class FileDisplayActivity extends HookActivity
     }
 
     private boolean isGridView() {
-        return getListOfFilesFragment().isGridView();
+        return getListOfFilesFragment().isGridEnabled();
     }
 
     public void allFilesOption() {

+ 8 - 10
src/com/owncloud/android/ui/activity/FolderPickerActivity.java

@@ -55,14 +55,15 @@ import com.owncloud.android.ui.fragment.FileFragment;
 import com.owncloud.android.ui.fragment.OCFileListFragment;
 import com.owncloud.android.utils.ErrorMessageAdapter;
 
-public class FolderPickerActivity extends FileActivity implements FileFragment.ContainerActivity, 
+import java.util.ArrayList;
+
+public class FolderPickerActivity extends FileActivity implements FileFragment.ContainerActivity,
     OnClickListener, OnEnforceableRefreshListener {
 
-    public static final String EXTRA_FOLDER = UploadFilesActivity.class.getCanonicalName()
+    public static final String EXTRA_FOLDER = FolderPickerActivity.class.getCanonicalName()
                                                             + ".EXTRA_FOLDER";
-    public static final String EXTRA_FILE = UploadFilesActivity.class.getCanonicalName()
-                                                            + ".EXTRA_FILE";
-    //TODO: Think something better
+    public static final String EXTRA_FILES = FolderPickerActivity.class.getCanonicalName()
+            + ".EXTRA_FILES";
 
     private SyncBroadcastReceiver mSyncBroadcastReceiver;
 
@@ -140,7 +141,6 @@ public class FolderPickerActivity extends FileActivity implements FileFragment.C
         OCFileListFragment listOfFiles = new OCFileListFragment();
         Bundle args = new Bundle();
         args.putBoolean(OCFileListFragment.ARG_JUST_FOLDERS, true);
-        args.putBoolean(OCFileListFragment.ARG_ALLOW_CONTEXTUAL_ACTIONS, false);
         args.putBoolean(OCFileListFragment.ARG_HIDE_FAB, true);
         listOfFiles.setArguments(args);
         FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
@@ -358,13 +358,11 @@ public class FolderPickerActivity extends FileActivity implements FileFragment.C
             finish();
         } else if (v == mChooseBtn) {
             Intent i = getIntent();
-            Parcelable targetFile = i.getParcelableExtra(FolderPickerActivity.EXTRA_FILE);
+            ArrayList<Parcelable> targetFiles = i.getParcelableArrayListExtra(FolderPickerActivity.EXTRA_FILES);
 
             Intent data = new Intent();
             data.putExtra(EXTRA_FOLDER, getCurrentFolder());
-            if (targetFile != null) {
-                data.putExtra(EXTRA_FILE, targetFile);
-            }
+            data.putParcelableArrayListExtra(EXTRA_FILES, targetFiles);
             setResult(RESULT_OK, data);
 
             finish();

+ 3 - 3
src/com/owncloud/android/ui/activity/LogHistoryActivity.java

@@ -117,15 +117,15 @@ public class LogHistoryActivity extends ToolbarActivity {
 
     @Override
     public boolean onOptionsItemSelected(MenuItem item) {
-        super.onOptionsItemSelected(item);
+        boolean retval = true;
         switch (item.getItemId()) {
             case android.R.id.home:
                 finish();
                 break;
             default:
-                return false;
+                retval = super.onOptionsItemSelected(item);
         }
-        return true;
+        return retval;
     }
 
 

+ 4 - 3
src/com/owncloud/android/ui/activity/ManageSpaceActivity.java

@@ -68,15 +68,16 @@ public class ManageSpaceActivity extends AppCompatActivity {
 
     @Override
     public boolean onOptionsItemSelected(MenuItem item) {
-        super.onOptionsItemSelected(item);
+        boolean retval = true;
         switch (item.getItemId()) {
             case android.R.id.home:
                 finish();
-                return true;
+                break;
             default:
                 Log_OC.w(TAG, "Unknown menu item triggered");
-                return false;
+                retval =  super.onOptionsItemSelected(item);
         }
+        return retval;
     }
 
     /**

+ 10 - 9
src/com/owncloud/android/ui/activity/ReceiveExternalFilesActivity.java

@@ -58,6 +58,7 @@ import com.owncloud.android.authentication.AccountAuthenticator;
 import com.owncloud.android.datamodel.OCFile;
 import com.owncloud.android.db.PreferenceManager;
 import com.owncloud.android.files.services.FileUploader;
+import com.owncloud.android.lib.common.OwnCloudAccount;
 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;
@@ -263,14 +264,15 @@ public class ReceiveExternalFilesActivity extends FileActivity
             });
             return builder.create();
         case DIALOG_MULTIPLE_ACCOUNT:
-            CharSequence ac[] = new CharSequence[
-                    mAccountManager.getAccountsByType(MainApp.getAccountType()).length];
-            for (int i = 0; i < ac.length; ++i) {
-                ac[i] = DisplayUtils.convertIdn(
-                        mAccountManager.getAccountsByType(MainApp.getAccountType())[i].name, false);
+            Account accounts[] = mAccountManager.getAccountsByType(MainApp.getAccountType());
+            CharSequence dialogItems[] = new CharSequence[accounts.length];
+            OwnCloudAccount oca;
+            for (int i = 0; i < dialogItems.length; ++i) {
+                dialogItems[i] = DisplayUtils.getAccountNameDisplayText(
+                        this, accounts[i], accounts[i].name, DisplayUtils.convertIdn(accounts[i].name, false));
             }
             builder.setTitle(R.string.common_choose_account);
-            builder.setItems(ac, new OnClickListener() {
+            builder.setItems(dialogItems, new OnClickListener() {
                 @Override
                 public void onClick(DialogInterface dialog, int which) {
                     setAccount(mAccountManager.getAccountsByType(MainApp.getAccountType())[which]);
@@ -400,7 +402,6 @@ public class ReceiveExternalFilesActivity extends FileActivity
 
         mFile = getStorageManager().getFileByPath(full_path);
         if (mFile != null) {
-            // TODO Enable when "On Device" is recovered ?
             Vector<OCFile> files = getStorageManager().getFolderContent(mFile, false);
             sortFileList(files);
 
@@ -452,11 +453,11 @@ public class ReceiveExternalFilesActivity extends FileActivity
         synchFolderOp.execute(getAccount(), this, null, null);
     }
 
-    private void sortFileList(Vector<OCFile> files) {
+    private Vector<OCFile> sortFileList(Vector<OCFile> files) {
         // Read sorting order, default to sort by name ascending
         FileStorageUtils.mSortOrder = PreferenceManager.getSortOrder(this);
         FileStorageUtils.mSortAscending = PreferenceManager.getSortAscending(this);
-        FileStorageUtils.sortOcFolder(files);
+        return FileStorageUtils.sortOcFolder(files);
     }
 
     private String generatePath(Stack<String> dirs) {

+ 14 - 2
src/com/owncloud/android/ui/activity/ToolbarActivity.java

@@ -19,11 +19,11 @@
 
 package com.owncloud.android.ui.activity;
 
-import android.accounts.AccountManagerFuture;
+import android.graphics.PorterDuff;
 import android.os.Bundle;
+import android.support.annotation.ColorInt;
 import android.support.v4.content.ContextCompat;
 import android.support.v7.app.ActionBar;
-import android.support.v7.app.AppCompatActivity;
 import android.support.v7.widget.Toolbar;
 import android.view.View;
 import android.widget.ProgressBar;
@@ -118,4 +118,16 @@ public abstract class ToolbarActivity extends BaseActivity {
     public void setIndeterminate(boolean indeterminate) {
         mProgressBar.setIndeterminate(indeterminate);
     }
+
+    /**
+     * Set the background to to progress bar of the toolbar. The resource should refer to
+     * a Drawable object or 0 to remove the background.#
+     *
+     * @param color The identifier of the color.
+     * @attr ref android.R.styleable#View_background
+     */
+    public void setProgressBarBackgroundColor(@ColorInt int color) {
+        mProgressBar.setBackgroundColor(color);
+        mProgressBar.getProgressDrawable().setColorFilter(color, PorterDuff.Mode.SRC_IN);
+    }
 }

+ 9 - 3
src/com/owncloud/android/ui/adapter/ExpandableUploadListAdapter.java

@@ -19,6 +19,7 @@
  */
 package com.owncloud.android.ui.adapter;
 
+import android.accounts.Account;
 import android.content.Context;
 import android.database.DataSetObserver;
 import android.graphics.Bitmap;
@@ -36,6 +37,7 @@ 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.datamodel.UploadsStorageManager;
@@ -239,7 +241,11 @@ public class ExpandableUploadListAdapter extends BaseExpandableListAdapter imple
             uploadDateTextView.setText(dateString);
 
             TextView accountNameTextView = (TextView) view.findViewById(R.id.upload_account);
-            accountNameTextView.setText(upload.getAccountName());
+            Account account = AccountUtils.getOwnCloudAccountByName(mParentActivity, upload.getAccountName());
+            accountNameTextView.setText(
+                    DisplayUtils.getAccountNameDisplayText(
+                            mParentActivity, account, account.name, upload.getAccountName())
+            );
 
             TextView statusTextView = (TextView) view.findViewById(R.id.upload_status);
 
@@ -316,7 +322,7 @@ public class ExpandableUploadListAdapter extends BaseExpandableListAdapter imple
             ImageButton rightButton = (ImageButton) view.findViewById(R.id.upload_right_button);
             if (upload.getUploadStatus() == UploadStatus.UPLOAD_IN_PROGRESS) {
                 //Cancel
-                rightButton.setImageResource(R.drawable.ic_cancel);
+                rightButton.setImageResource(R.drawable.ic_action_cancel_grey);
                 rightButton.setVisibility(View.VISIBLE);
                 rightButton.setOnClickListener(new OnClickListener() {
                     @Override
@@ -331,7 +337,7 @@ public class ExpandableUploadListAdapter extends BaseExpandableListAdapter imple
 
             } else if (upload.getUploadStatus() == UploadStatus.UPLOAD_FAILED) {
                 //Delete
-                rightButton.setImageResource(R.drawable.ic_action_delete);
+                rightButton.setImageResource(R.drawable.ic_action_delete_grey);
                 rightButton.setVisibility(View.VISIBLE);
                 rightButton.setOnClickListener(new OnClickListener() {
                     @Override

+ 112 - 107
src/com/owncloud/android/ui/adapter/FileListListAdapter.java

@@ -1,25 +1,24 @@
 /**
- *   ownCloud Android client application
- *
- *   @author Bartek Przybylski
- *   @author Tobias Kaminsky
- *   @author David A. Velasco
- *   @author masensio
- *   Copyright (C) 2011  Bartek Przybylski
- *   Copyright (C) 2016 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/>.
+ * ownCloud Android client application
  *
+ * @author Bartek Przybylski
+ * @author Tobias Kaminsky
+ * @author David A. Velasco
+ * @author masensio
+ * Copyright (C) 2011  Bartek Przybylski
+ * Copyright (C) 2016 ownCloud Inc.
+ * <p>
+ * 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.
+ * <p>
+ * 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.
+ * <p>
+ * 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;
 
@@ -27,15 +26,14 @@ package com.owncloud.android.ui.adapter;
 import android.accounts.Account;
 import android.content.Context;
 import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.os.Build;
+import android.graphics.Color;
+import android.util.SparseBooleanArray;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.AbsListView;
 import android.widget.BaseAdapter;
+import android.widget.GridView;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.widget.ListAdapter;
@@ -55,6 +53,7 @@ import com.owncloud.android.utils.DisplayUtils;
 import com.owncloud.android.utils.FileStorageUtils;
 import com.owncloud.android.utils.MimetypeIconUtil;
 
+import java.util.ArrayList;
 import java.util.Vector;
 
 
@@ -65,40 +64,35 @@ import java.util.Vector;
 public class FileListListAdapter extends BaseAdapter implements ListAdapter {
 
     private Context mContext;
-    private OCFile mFile = null;
     private Vector<OCFile> mFiles = null;
-    private Vector<OCFile> mFilesOrig = new Vector<OCFile>();
     private boolean mJustFolders;
 
     private FileDataStorageManager mStorageManager;
     private Account mAccount;
     private ComponentsGetter mTransferServiceGetter;
-    private boolean mGridMode;
 
-    private enum ViewType {LIST_ITEM, GRID_IMAGE, GRID_ITEM };
-    
+    private enum ViewType {LIST_ITEM, GRID_IMAGE, GRID_ITEM}
+
     public FileListListAdapter(
-            boolean justFolders, 
+            boolean justFolders,
             Context context,
             ComponentsGetter transferServiceGetter
-            ) {
-        
+    ) {
+
         mJustFolders = justFolders;
         mContext = context;
         mAccount = AccountUtils.getCurrentOwnCloudAccount(mContext);
 
         mTransferServiceGetter = transferServiceGetter;
-        
+
         // Read sorting order, default to sort by name ascending
         FileStorageUtils.mSortOrder = PreferenceManager.getSortOrder(mContext);
         FileStorageUtils.mSortAscending = PreferenceManager.getSortAscending(mContext);
         
         // initialise thumbnails cache on background thread
         new ThumbnailsCacheManager.InitDiskCacheTask().execute();
-
-        mGridMode = false;
     }
-    
+
     @Override
     public boolean areAllItemsEnabled() {
         return true;
@@ -147,35 +141,35 @@ public class FileListListAdapter extends BaseAdapter implements ListAdapter {
 
         // Find out which layout should be displayed
         ViewType viewType;
-        if (!mGridMode){
-            viewType = ViewType.LIST_ITEM;
-        } else if (file.isImage() || file.isVideo()){
-            viewType = ViewType.GRID_IMAGE;
+        if (parent instanceof GridView) {
+            if (file != null && (file.isImage() || file.isVideo())) {
+                viewType = ViewType.GRID_IMAGE;
+            } else {
+                viewType = ViewType.GRID_ITEM;
+            }
         } else {
-            viewType = ViewType.GRID_ITEM;
+            viewType = ViewType.LIST_ITEM;
         }
 
         // create view only if differs, otherwise reuse
-        if (convertView == null || (convertView != null && convertView.getTag() != viewType)) {
+        if (convertView == null || convertView.getTag() != viewType) {
             switch (viewType) {
                 case GRID_IMAGE:
-                    view = inflator.inflate(R.layout.grid_image, null);
+                    view = inflator.inflate(R.layout.grid_image, parent, false);
                     view.setTag(ViewType.GRID_IMAGE);
                     break;
                 case GRID_ITEM:
-                    view = inflator.inflate(R.layout.grid_item, null);
+                    view = inflator.inflate(R.layout.grid_item, parent, false);
                     view.setTag(ViewType.GRID_ITEM);
                     break;
                 case LIST_ITEM:
-                    view = inflator.inflate(R.layout.list_item, null);
+                    view = inflator.inflate(R.layout.list_item, parent, false);
                     view.setTag(ViewType.LIST_ITEM);
                     break;
             }
         }
 
-        view.invalidate();
-
-        if (file != null){
+        if (file != null) {
 
             ImageView fileIcon = (ImageView) view.findViewById(R.id.thumbnail);
 
@@ -186,38 +180,24 @@ public class FileListListAdapter extends BaseAdapter implements ListAdapter {
             LinearLayout linearLayout = (LinearLayout) view.findViewById(R.id.ListItemLayout);
             linearLayout.setContentDescription("LinearLayout-" + name);
 
-            switch (viewType){
+            switch (viewType) {
                 case LIST_ITEM:
                     TextView fileSizeV = (TextView) view.findViewById(R.id.file_size);
                     TextView fileSizeSeparatorV = (TextView) view.findViewById(R.id.file_separator);
                     TextView lastModV = (TextView) view.findViewById(R.id.last_mod);
-                    ImageView checkBoxV = (ImageView) view.findViewById(R.id.custom_checkbox);
+
 
                     lastModV.setVisibility(View.VISIBLE);
                     lastModV.setText(DisplayUtils.getRelativeTimestamp(mContext, file.getModificationTimestamp()));
 
-                    checkBoxV.setVisibility(View.GONE);
 
                     fileSizeSeparatorV.setVisibility(View.VISIBLE);
                     fileSizeV.setVisibility(View.VISIBLE);
                     fileSizeV.setText(DisplayUtils.bytesToHumanReadable(file.getFileLength()));
 
-                    if (!file.isFolder()) {
-                        AbsListView parentList = (AbsListView)parent;
-                        if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
-                            if (parentList.getChoiceMode() == AbsListView.CHOICE_MODE_NONE) {
-                                checkBoxV.setVisibility(View.GONE);
-                            } else {
-                                if (parentList.isItemChecked(position)) {
-                                    checkBoxV.setImageResource(
-                                            R.drawable.ic_checkbox_marked);
-                                } else {
-                                    checkBoxV.setImageResource(
-                                            R.drawable.ic_checkbox_blank_outline);
-                                }
-                                checkBoxV.setVisibility(View.VISIBLE);
-                            }
-                        }
+                    if (file.isFolder()) {
+                        fileSizeSeparatorV.setVisibility(View.GONE);
+                        fileSizeV.setVisibility(View.GONE);
                     }
 
                 case GRID_ITEM:
@@ -233,7 +213,7 @@ public class FileListListAdapter extends BaseAdapter implements ListAdapter {
                         sharedIconV.setImageResource(R.drawable.shared_via_link);
                         sharedIconV.setVisibility(View.VISIBLE);
                         sharedIconV.bringToFront();
-                    } else if (file.isSharedWithSharee() || file.isSharedWithMe() ) {
+                    } else if (file.isSharedWithSharee() || file.isSharedWithMe()) {
                         sharedIconV.setImageResource(R.drawable.shared_via_users);
                         sharedIconV.setVisibility(View.VISIBLE);
                         sharedIconV.bringToFront();
@@ -241,9 +221,6 @@ public class FileListListAdapter extends BaseAdapter implements ListAdapter {
                         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();
@@ -257,22 +234,22 @@ public class FileListListAdapter extends BaseAdapter implements ListAdapter {
                     localStateView.setVisibility(View.INVISIBLE);   // default first
 
                     if ( //synchronizing
-                                opsBinder != null &&
-                                opsBinder.isSynchronizing(mAccount, file.getRemotePath())
+                            opsBinder != null &&
+                                    opsBinder.isSynchronizing(mAccount, file)
                             ) {
                         localStateView.setImageResource(R.drawable.ic_synchronizing);
                         localStateView.setVisibility(View.VISIBLE);
 
                     } else if ( // downloading
-                                downloaderBinder != null &&
-                                downloaderBinder.isDownloading(mAccount, file)
+                            downloaderBinder != null &&
+                                    downloaderBinder.isDownloading(mAccount, file)
                             ) {
                         localStateView.setImageResource(R.drawable.ic_synchronizing);
                         localStateView.setVisibility(View.VISIBLE);
 
                     } else if ( //uploading
-                                uploaderBinder != null &&
-                                uploaderBinder.isUploading(mAccount, file)
+                            uploaderBinder != null &&
+                                    uploaderBinder.isUploading(mAccount, file)
                             ) {
                         localStateView.setImageResource(R.drawable.ic_synchronizing);
                         localStateView.setVisibility(View.VISIBLE);
@@ -288,9 +265,30 @@ public class FileListListAdapter extends BaseAdapter implements ListAdapter {
 
                     break;
             }
-            
+
             // For all Views
-            
+
+            ImageView checkBoxV = (ImageView) view.findViewById(R.id.custom_checkbox);
+            checkBoxV.setVisibility(View.GONE);
+            view.setBackgroundColor(Color.WHITE);
+
+            AbsListView parentList = (AbsListView) parent;
+            if (parentList.getChoiceMode() != AbsListView.CHOICE_MODE_NONE &&
+                    parentList.getCheckedItemCount() > 0
+                ) {
+                if (parentList.isItemChecked(position)) {
+                    view.setBackgroundColor(mContext.getResources().getColor(
+                            R.color.selected_item_background));
+                    checkBoxV.setImageResource(
+                            R.drawable.ic_checkbox_marked);
+                } else {
+                    view.setBackgroundColor(Color.WHITE);
+                    checkBoxV.setImageResource(
+                            R.drawable.ic_checkbox_blank_outline);
+                }
+                checkBoxV.setVisibility(View.VISIBLE);
+            }
+
             // this if-else is needed even though favorite icon is visible by default
             // because android reuses views in listview
             if (!file.isFavorite()) {
@@ -298,15 +296,15 @@ public class FileListListAdapter extends BaseAdapter implements ListAdapter {
             } else {
                 view.findViewById(R.id.favoriteIcon).setVisibility(View.VISIBLE);
             }
-            
+
             // No Folder
             if (!file.isFolder()) {
-                if ((file.isImage() || file.isVideo()) && file.getRemoteId() != null){
+                if ((file.isImage() || file.isVideo()) && file.getRemoteId() != null) {
                     // Thumbnail in Cache?
                     Bitmap thumbnail = ThumbnailsCacheManager.getBitmapFromDiskCache(
                             String.valueOf(file.getRemoteId())
-                            );
-                    if (thumbnail != null && !file.needsUpdateThumbnail()){
+                    );
+                    if (thumbnail != null && !file.needsUpdateThumbnail()) {
 
                         if (file.isVideo()) {
                             Bitmap withOverlay = ThumbnailsCacheManager.addVideoOverlay(thumbnail);
@@ -320,7 +318,7 @@ public class FileListListAdapter extends BaseAdapter implements ListAdapter {
                             final ThumbnailsCacheManager.ThumbnailGenerationTask task =
                                     new ThumbnailsCacheManager.ThumbnailGenerationTask(
                                             fileIcon, mStorageManager, mAccount
-                                            );
+                                    );
                             if (thumbnail == null) {
                                 if (file.isVideo()) {
                                     thumbnail = ThumbnailsCacheManager.mDefaultVideo;
@@ -361,7 +359,6 @@ public class FileListListAdapter extends BaseAdapter implements ListAdapter {
                 );
             }
         }
-
         return view;
     }
 
@@ -382,23 +379,21 @@ public class FileListListAdapter extends BaseAdapter implements ListAdapter {
 
     /**
      * Change the adapted directory for a new one
-     * @param directory                 New file to adapt. Can be NULL, meaning 
-     *                                  "no content to adapt".
-     * @param updatedStorageManager     Optional updated storage manager; used to replace 
-     *                                  mStorageManager if is different (and not NULL)
+     *
+     * @param directory                New folder to adapt. Can be NULL, meaning
+     *                              "no content to adapt".
+     * @param updatedStorageManager Optional updated storage manager; used to replace
+     *                              mStorageManager if is different (and not NULL)
      */
     public void swapDirectory(OCFile directory, FileDataStorageManager updatedStorageManager
             , boolean onlyOnDevice) {
-        mFile = directory;
         if (updatedStorageManager != null && updatedStorageManager != mStorageManager) {
             mStorageManager = updatedStorageManager;
             mAccount = AccountUtils.getCurrentOwnCloudAccount(mContext);
         }
         if (mStorageManager != null) {
-            mFiles = mStorageManager.getFolderContent(mFile, onlyOnDevice);
-            mFilesOrig.clear();
-            mFilesOrig.addAll(mFiles);
-            
+            mFiles = mStorageManager.getFolderContent(directory, onlyOnDevice);
+
             if (mJustFolders) {
                 mFiles = getFolders(mFiles);
             }
@@ -409,17 +404,17 @@ public class FileListListAdapter extends BaseAdapter implements ListAdapter {
         mFiles = FileStorageUtils.sortOcFolder(mFiles);
         notifyDataSetChanged();
     }
-    
 
     /**
      * Filter for getting only the folders
-     * @param files
-     * @return Vector<OCFile>
+     *
+     * @param files             Collection of files to filter
+     * @return                  Folders in the input
      */
     public Vector<OCFile> getFolders(Vector<OCFile> files) {
-        Vector<OCFile> ret = new Vector<OCFile>(); 
-        OCFile current = null; 
-        for (int i=0; i<files.size(); i++) {
+        Vector<OCFile> ret = new Vector<>();
+        OCFile current;
+        for (int i = 0; i < files.size(); i++) {
             current = files.get(i);
             if (current.isFolder()) {
                 ret.add(current);
@@ -427,9 +422,10 @@ public class FileListListAdapter extends BaseAdapter implements ListAdapter {
         }
         return ret;
     }
-    
-    
+
+
     public void setSortOrder(Integer order, boolean ascending) {
+
         PreferenceManager.setSortOrder(mContext, order);
         PreferenceManager.setSortAscending(mContext, ascending);
         
@@ -440,11 +436,20 @@ public class FileListListAdapter extends BaseAdapter implements ListAdapter {
         notifyDataSetChanged();
     }
 
-    public void setGridMode(boolean gridMode) {
-        mGridMode = gridMode;
-    }
 
-    public boolean isGridMode() {
-        return mGridMode;
+    public ArrayList<OCFile> getCheckedItems(AbsListView parentList) {
+        SparseBooleanArray checkedPositions = parentList.getCheckedItemPositions();
+        ArrayList<OCFile> files = new ArrayList<>();
+        Object item;
+        for (int i=0; i < checkedPositions.size(); i++) {
+            if (checkedPositions.valueAt(i)) {
+                item = getItem(checkedPositions.keyAt(i));
+                if (item != null) {
+                    files.add((OCFile)item);
+                }
+            }
+        }
+        return files;
     }
+
 }

+ 1 - 0
src/com/owncloud/android/ui/dialog/AccountActionsDialogFragment.java

@@ -39,6 +39,7 @@ public class AccountActionsDialogFragment extends DialogFragment implements
      * Listener interface for the file action fragment.
      */
     public interface FileActionsDialogFragmentListener {
+        // TODO Tobi change to int array?
         public boolean onFileActionChosen(int menuId, int filePosition);
     }
 

+ 0 - 159
src/com/owncloud/android/ui/dialog/FileActionsDialogFragment.java

@@ -1,159 +0,0 @@
-package com.owncloud.android.ui.dialog;
-
-import android.support.v4.app.DialogFragment;
-import android.os.Bundle;
-import android.view.LayoutInflater;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.Window;
-import android.widget.AdapterView;
-import android.widget.AdapterView.OnItemClickListener;
-import android.widget.ArrayAdapter;
-import android.widget.ListView;
-import android.widget.TextView;
-
-import com.owncloud.android.R;
-import com.owncloud.android.ui.dialog.parcel.MenuItemParcelable;
-import com.owncloud.android.ui.dialog.parcel.MenuParcelable;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Dialog for choosing a file action.
- */
-public class FileActionsDialogFragment extends DialogFragment implements
-        OnItemClickListener {
-    private static final String ARG_ITEM_LIST = "ITEM_LIST";
-    private static final String ARG_FILE_POSITION = "FILE_POSITION";
-    private static final String ARG_FILE_NAME = "FILE_NAME";
-    public static final String FTAG_FILE_ACTIONS = "FILE_ACTIONS_FRAGMENT";
-
-    private List<MenuItemParcelable> mMenuItems;
-
-    private int mFilePosition;
-
-    private ListView mListView;
-
-    /**
-     * Listener interface for the file action fragment.
-     */
-    public interface FileActionsDialogFragmentListener {
-        public boolean onFileActionChosen(int menuId, int filePosition);
-    }
-
-    /**
-     * Public factory method to create new FileActionsDialogFragment instances.
-     *
-     * @param menu menu to be display.
-     * @return Dialog ready to show.
-     */
-    public static FileActionsDialogFragment newInstance(Menu menu, int filePosition, String fileName) {
-        FileActionsDialogFragment fragment = new FileActionsDialogFragment();
-        Bundle args = new Bundle();
-
-        MenuParcelable menuParcelable = new MenuParcelable();
-        menuParcelable.setMenuItems(calculateMenuParcel(menu));
-
-        args.putParcelable(ARG_ITEM_LIST, menuParcelable);
-        args.putInt(ARG_FILE_POSITION, filePosition);
-        args.putCharSequence(ARG_FILE_NAME, fileName);
-
-        fragment.setArguments(args);
-        return fragment;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setStyle(DialogFragment.STYLE_NORMAL, R.style.ownCloud_Dialog);
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public View onCreateView(LayoutInflater inflater, ViewGroup container,
-                             Bundle savedInstanceState) {
-        View view = inflater.inflate(R.layout.file_actions, null, false);
-        mListView = (ListView) view.findViewById(R.id.file_actions_list);
-
-        CharSequence title =  getArguments().getCharSequence(ARG_FILE_NAME);
-        if(title != null && title.length() > 0) {
-            TextView header = (TextView)view.findViewById(R.id.file_actions_header);
-            header.setText(title);
-            header.setVisibility(View.VISIBLE);
-            view.findViewById(R.id.file_actions_header_divider).setVisibility(View.VISIBLE);
-        } else {
-            getDialog().getWindow().requestFeature(Window.FEATURE_NO_TITLE);
-        }
-
-        return view;
-    }
-
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void onActivityCreated(Bundle savedInstanceState) {
-        super.onActivityCreated(savedInstanceState);
-
-        mFilePosition = getArguments().getInt(ARG_FILE_POSITION);
-
-        MenuParcelable menu = getArguments().getParcelable(ARG_ITEM_LIST);
-        mMenuItems = menu.getMenuItems();
-        List<String> stringList = new ArrayList<String>();
-        for (int i = 0; i < mMenuItems.size(); i++) {
-            stringList.add(mMenuItems.get(i).getMenuText());
-        }
-
-        ArrayAdapter<String> adapter = new ArrayAdapter<String>(getActivity(),
-                R.layout.simple_dialog_list_item, stringList);
-
-        mListView.setAdapter(adapter);
-
-        mListView.setOnItemClickListener(this);
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
-        dismiss();
-        ((FileActionsDialogFragmentListener) getTargetFragment())
-                .onFileActionChosen(mMenuItems.get(position).getMenuItemId(), mFilePosition);
-    }
-
-    /**
-     * calculates a parcelable list of MenuItemParcelable based on the given menu and the visibility of the menu items.
-     *
-     * @param menu the menu to be displayed
-     * @return a filtered List of parcelables based on the menu
-     */
-    private static List<MenuItemParcelable> calculateMenuParcel(Menu menu) {
-        int index = 0;
-        boolean hasNext = true;
-        List<MenuItemParcelable> itemList = new ArrayList<MenuItemParcelable>();
-        MenuParcelable menuParcelable = new MenuParcelable();
-        try {
-            while (hasNext) {
-                MenuItem item = menu.getItem(index);
-                if (item.isVisible()) {
-                    itemList.add(new MenuItemParcelable(item));
-                }
-                index++;
-            }
-        } catch (IndexOutOfBoundsException iobe) {
-            // reach the end of the item list
-        }
-
-        return itemList;
-    }
-}

+ 8 - 2
src/com/owncloud/android/ui/dialog/RemoveFileDialogFragment.java

@@ -35,6 +35,8 @@ import com.owncloud.android.datamodel.OCFile;
 import com.owncloud.android.ui.activity.ComponentsGetter;
 import com.owncloud.android.ui.dialog.ConfirmationDialogFragment.ConfirmationDialogFragmentListener;
 
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Vector;
 
 public class RemoveFileDialogFragment extends ConfirmationDialogFragment 
@@ -92,7 +94,9 @@ implements ConfirmationDialogFragmentListener {
         ComponentsGetter cg = (ComponentsGetter)getActivity();
         FileDataStorageManager storageManager = cg.getStorageManager();
         if (storageManager.getFileById(mTargetFile.getFileId()) != null) {
-            cg.getFileOperationsHelper().removeFile(mTargetFile, false);
+            ArrayList<OCFile> list = new ArrayList<>();
+            list.add(mTargetFile);
+            cg.getFileOperationsHelper().removeFiles(list, false);
         }
     }
     
@@ -102,7 +106,9 @@ implements ConfirmationDialogFragmentListener {
     @Override
     public void onCancel(String callerTag) {
         ComponentsGetter cg = (ComponentsGetter)getActivity();
-        cg.getFileOperationsHelper().removeFile(mTargetFile, true);
+        ArrayList<OCFile> list = new ArrayList<>();
+        list.add(mTargetFile);
+        cg.getFileOperationsHelper().removeFiles(list, true);
         
         FileDataStorageManager storageManager = cg.getStorageManager();
         

+ 146 - 0
src/com/owncloud/android/ui/dialog/RemoveFilesDialogFragment.java

@@ -0,0 +1,146 @@
+/**
+ *   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.ui.dialog;
+
+/**
+ *  Dialog requiring confirmation before removing a collection of given OCFiles.
+ * 
+ *  Triggers the removal according to the user response.
+ */
+
+import android.app.Dialog;
+import android.os.Bundle;
+
+import com.owncloud.android.R;
+import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.ui.activity.ComponentsGetter;
+import com.owncloud.android.ui.dialog.ConfirmationDialogFragment.ConfirmationDialogFragmentListener;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+public class RemoveFilesDialogFragment extends ConfirmationDialogFragment
+implements ConfirmationDialogFragmentListener {
+
+    private Collection<OCFile> mTargetFiles;
+
+    private static final String ARG_TARGET_FILES = "TARGET_FILES";
+
+    /**
+     * Public factory method to create new RemoveFilesDialogFragment instances.
+     * 
+     * @param files           Files to remove.
+     * @return                Dialog ready to show.
+     */
+    public static RemoveFilesDialogFragment newInstance(ArrayList<OCFile> files) {
+        RemoveFilesDialogFragment frag = new RemoveFilesDialogFragment();
+        Bundle args = new Bundle();
+        int messageStringId;
+
+        boolean containsFolder = false;
+        boolean containsDown = false;
+        boolean containsFavorite = false;
+        for (OCFile file: files) {
+            containsFolder |= file.isFolder();
+            containsDown |= file.isDown();
+            containsFavorite |= file.isFavorite();
+        }
+
+        if (files.size() == 1) {
+            // choose message for a single file
+            OCFile file = files.get(0);
+
+            messageStringId = (file.isFolder()) ?
+                R.string.confirmation_remove_folder_alert :
+                R.string.confirmation_remove_file_alert;
+
+        } else {
+            // choose message for more than one file
+            messageStringId = (containsFolder) ?
+                R.string.confirmation_remove_folders_alert :
+                R.string.confirmation_remove_files_alert;
+
+        }
+
+        int localRemoveButton = (!containsFavorite && (containsFolder || containsDown)) ?
+            R.string.confirmation_remove_local :
+            -1;
+
+        args.putInt(ARG_MESSAGE_RESOURCE_ID, messageStringId);
+        if (files.size() == 1) {
+            args.putStringArray(ARG_MESSAGE_ARGUMENTS, new String[]{files.get(0).getFileName()});
+        }
+        args.putInt(ARG_POSITIVE_BTN_RES, R.string.common_yes);
+        args.putInt(ARG_NEUTRAL_BTN_RES, R.string.common_no);
+        args.putInt(ARG_NEGATIVE_BTN_RES, localRemoveButton);
+        args.putParcelableArrayList(ARG_TARGET_FILES, files);
+        frag.setArguments(args);
+        
+        return frag;
+    }
+
+
+    /**
+     * Convenience factory method to create new RemoveFilesDialogFragment instances for a single file
+     *
+     * @param file           File to remove.
+     * @return                Dialog ready to show.
+     */
+    public static RemoveFilesDialogFragment newInstance(OCFile file) {
+        ArrayList<OCFile> list = new ArrayList<>();
+        list.add(file);
+        return newInstance(list);
+    }
+
+    
+    @Override
+    public Dialog onCreateDialog(Bundle savedInstanceState) {
+        Dialog dialog = super.onCreateDialog(savedInstanceState);
+        mTargetFiles = getArguments().getParcelableArrayList(ARG_TARGET_FILES);
+        
+        setOnConfirmationListener(this);
+        
+        return dialog;
+    }    
+
+    /**
+     * Performs the removal of the target file, both locally and in the server.
+     */
+    @Override
+    public void onConfirmation(String callerTag) {
+        ComponentsGetter cg = (ComponentsGetter) getActivity();
+        cg.getFileOperationsHelper().removeFiles(mTargetFiles, false);
+    }
+    
+    /**
+     * Performs the removal of the local copy of the target file
+     */
+    @Override
+    public void onCancel(String callerTag) {
+        ComponentsGetter cg = (ComponentsGetter) getActivity();
+        cg.getFileOperationsHelper().removeFiles(mTargetFiles, true);
+    }
+
+    @Override
+    public void onNeutral(String callerTag) {
+        // nothing to do here
+    }
+}

+ 32 - 53
src/com/owncloud/android/ui/fragment/ExtendedListFragment.java

@@ -20,7 +20,6 @@
 
 package com.owncloud.android.ui.fragment;
 
-import android.os.Build;
 import android.os.Bundle;
 import android.support.v4.app.Fragment;
 import android.support.v4.widget.SwipeRefreshLayout;
@@ -32,7 +31,6 @@ import android.widget.AdapterView;
 import android.widget.AdapterView.OnItemClickListener;
 import android.widget.GridView;
 import android.widget.ListAdapter;
-import android.widget.ListView;
 import android.widget.TextView;
 
 import com.getbase.floatingactionbutton.FloatingActionButton;
@@ -59,6 +57,7 @@ public class ExtendedListFragment extends Fragment
     private static final String KEY_TOPS = "TOPS";
     private static final String KEY_HEIGHT_CELL = "HEIGHT_CELL";
     private static final String KEY_EMPTY_LIST_MESSAGE = "EMPTY_LIST_MESSAGE";
+    private static final String KEY_IS_GRID_VISIBLE = "IS_GRID_VISIBLE";
 
     protected SwipeRefreshLayout mRefreshListLayout;
     private SwipeRefreshLayout mRefreshGridLayout;
@@ -88,13 +87,8 @@ public class ExtendedListFragment extends Fragment
 
     protected void setListAdapter(ListAdapter listAdapter) {
         mAdapter = listAdapter;
-        if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
-            mCurrentListView.setAdapter(listAdapter);
-        } else {
-            ((ListView)mCurrentListView).setAdapter(listAdapter);
-        }
-
-        mCurrentListView.invalidate();
+        mCurrentListView.setAdapter(listAdapter);
+        mCurrentListView.invalidateViews();
     }
 
     protected AbsListView getListView() {
@@ -118,41 +112,27 @@ public class ExtendedListFragment extends Fragment
     }
 
     public void switchToGridView() {
-        if ((mCurrentListView == mListView)) {
-
+        if (!isGridEnabled()) {
             mListView.setAdapter(null);
             mRefreshListLayout.setVisibility(View.GONE);
-
-            if (mAdapter instanceof FileListListAdapter) {
-                ((FileListListAdapter) mAdapter).setGridMode(true);
-            }
-            mGridView.setAdapter(mAdapter);
             mRefreshGridLayout.setVisibility(View.VISIBLE);
-
             mCurrentListView = mGridView;
+            setListAdapter(mAdapter);
         }
     }
 
     public void switchToListView() {
-        if (mCurrentListView == mGridView) {
+        if (isGridEnabled()) {
             mGridView.setAdapter(null);
             mRefreshGridLayout.setVisibility(View.GONE);
-
-            if (mAdapter instanceof FileListListAdapter) {
-                ((FileListListAdapter) mAdapter).setGridMode(false);
-            }
-            mListView.setAdapter(mAdapter);
             mRefreshListLayout.setVisibility(View.VISIBLE);
-
             mCurrentListView = mListView;
+            setListAdapter(mAdapter);
         }
     }
 
-    public boolean isGridView(){
-        if (mAdapter instanceof FileListListAdapter) {
-            return ((FileListListAdapter) mAdapter).isGridMode();
-        }
-        return false;
+    public boolean isGridEnabled(){
+        return (mCurrentListView == mGridView);
     }
     
     
@@ -165,23 +145,14 @@ public class ExtendedListFragment extends Fragment
 
         mListView = (ExtendedListView)(v.findViewById(R.id.list_root));
         mListView.setOnItemClickListener(this);
+        //mListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
         mListFooterView = inflater.inflate(R.layout.list_footer, null, false);
 
         mGridView = (GridViewWithHeaderAndFooter) (v.findViewById(R.id.grid_root));
         mGridView.setNumColumns(GridView.AUTO_FIT);
         mGridView.setOnItemClickListener(this);
-        mGridFooterView = inflater.inflate(R.layout.list_footer, null, false);
 
-        if (savedInstanceState != null) {
-            int referencePosition = savedInstanceState.getInt(KEY_SAVED_LIST_POSITION);
-            if (mCurrentListView == mListView) {
-                Log_OC.v(TAG, "Setting and centering around list position " + referencePosition);
-                mListView.setAndCenterSelection(referencePosition);
-            } else {
-                Log_OC.v(TAG, "Setting grid position " + referencePosition);
-                mGridView.setSelection(referencePosition);
-            }
-        }
+        mGridFooterView = inflater.inflate(R.layout.list_footer, null, false);
 
         // Pull-down to refresh layout
         mRefreshListLayout = (SwipeRefreshLayout) v.findViewById(R.id.swipe_containing_list);
@@ -196,13 +167,26 @@ public class ExtendedListFragment extends Fragment
         mListView.setEmptyView(mRefreshEmptyLayout);
         mGridView.setEmptyView(mRefreshEmptyLayout);
 
-        mCurrentListView = mListView;   // list as default
-
         mFabMain = (FloatingActionsMenu) v.findViewById(R.id.fab_main);
         mFabUpload = (FloatingActionButton) v.findViewById(R.id.fab_upload);
         mFabMkdir = (FloatingActionButton) v.findViewById(R.id.fab_mkdir);
         mFabUploadFromApp = (FloatingActionButton) v.findViewById(R.id.fab_upload_from_app);
 
+        mCurrentListView = mListView;   // list by default
+        if (savedInstanceState != null) {
+            if (savedInstanceState.getBoolean(KEY_IS_GRID_VISIBLE, false)) {
+                switchToGridView();
+            }
+            int referencePosition = savedInstanceState.getInt(KEY_SAVED_LIST_POSITION);
+            if (isGridEnabled()) {
+                Log_OC.v(TAG, "Setting grid position " + referencePosition);
+                mGridView.setSelection(referencePosition);
+            } else {
+                Log_OC.v(TAG, "Setting and centering around list position " + referencePosition);
+                mListView.setAndCenterSelection(referencePosition);
+            }
+        }
+
         return v;
     }
 
@@ -233,6 +217,7 @@ public class ExtendedListFragment extends Fragment
     public void onSaveInstanceState(Bundle savedInstanceState) {
         super.onSaveInstanceState(savedInstanceState);
         Log_OC.d(TAG, "onSaveInstanceState()");
+        savedInstanceState.putBoolean(KEY_IS_GRID_VISIBLE, isGridEnabled());
         savedInstanceState.putInt(KEY_SAVED_LIST_POSITION, getReferencePosition());
         savedInstanceState.putIntegerArrayList(KEY_INDEXES, mIndexes);
         savedInstanceState.putIntegerArrayList(KEY_FIRST_POSITIONS, mFirstPositions);
@@ -404,19 +389,13 @@ public class ExtendedListFragment extends Fragment
     }
 
     protected void setChoiceMode(int choiceMode) {
-        if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
-            mListView.setChoiceMode(choiceMode);
-            mGridView.setChoiceMode(choiceMode);
-        } else {
-            ((ListView)mListView).setChoiceMode(choiceMode);
-        }
+        mListView.setChoiceMode(choiceMode);
+        mGridView.setChoiceMode(choiceMode);
     }
 
-    protected void registerForContextMenu() {
-        registerForContextMenu(mListView);
-        registerForContextMenu(mGridView);
-        mListView.setOnCreateContextMenuListener(this);
-        mGridView.setOnCreateContextMenuListener(this);
+    protected void setMultiChoiceModeListener(AbsListView.MultiChoiceModeListener listener) {
+        mListView.setMultiChoiceModeListener(listener);
+        mGridView.setMultiChoiceModeListener(listener);
     }
 
     /**

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

@@ -48,7 +48,7 @@ import com.owncloud.android.lib.common.network.OnDatatransferProgressListener;
 import com.owncloud.android.lib.common.utils.Log_OC;
 import com.owncloud.android.ui.activity.FileActivity;
 import com.owncloud.android.ui.activity.FileDisplayActivity;
-import com.owncloud.android.ui.dialog.RemoveFileDialogFragment;
+import com.owncloud.android.ui.dialog.RemoveFilesDialogFragment;
 import com.owncloud.android.ui.dialog.RenameFileDialogFragment;
 import com.owncloud.android.utils.DisplayUtils;
 import com.owncloud.android.utils.MimetypeIconUtil;
@@ -255,7 +255,7 @@ public class FileDetailFragment extends FileFragment implements OnClickListener
                 return true;
             }
             case R.id.action_remove_file: {
-                RemoveFileDialogFragment dialog = RemoveFileDialogFragment.newInstance(getFile());
+                RemoveFilesDialogFragment dialog = RemoveFilesDialogFragment.newInstance(getFile());
                 dialog.show(getFragmentManager(), FTAG_CONFIRMATION);
                 return true;
             }
@@ -293,7 +293,7 @@ public class FileDetailFragment extends FileFragment implements OnClickListener
                 return true;
             }
             default:
-                return false;
+                return super.onOptionsItemSelected(item);
         }
     }
 

+ 157 - 174
src/com/owncloud/android/ui/fragment/OCFileListFragment.java

@@ -22,7 +22,6 @@
  */
 package com.owncloud.android.ui.fragment;
 
-import android.app.Activity;
 import android.content.Context;
 import android.content.Intent;
 import android.content.SharedPreferences;
@@ -30,16 +29,16 @@ import android.os.Build;
 import android.os.Bundle;
 import android.preference.PreferenceManager;
 import android.support.v4.widget.SwipeRefreshLayout;
-import android.view.ContextMenu;
+import android.view.ActionMode;
 import android.view.LayoutInflater;
 import android.view.Menu;
 import android.view.MenuInflater;
 import android.view.MenuItem;
 import android.view.View;
 import android.view.ViewGroup;
+import android.widget.AbsListView;
 import android.widget.AdapterView;
-import android.widget.AdapterView.AdapterContextMenuInfo;
-import android.widget.PopupMenu;
+import android.widget.ListView;
 import android.widget.TextView;
 import android.widget.Toast;
 
@@ -59,23 +58,24 @@ import com.owncloud.android.ui.activity.UploadFilesActivity;
 import com.owncloud.android.ui.adapter.FileListListAdapter;
 import com.owncloud.android.ui.dialog.ConfirmationDialogFragment;
 import com.owncloud.android.ui.dialog.CreateFolderDialogFragment;
-import com.owncloud.android.ui.dialog.FileActionsDialogFragment;
-import com.owncloud.android.ui.dialog.RemoveFileDialogFragment;
+import com.owncloud.android.ui.dialog.RemoveFilesDialogFragment;
 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.ui.preview.PreviewTextFragment;
+import com.owncloud.android.utils.DisplayUtils;
 import com.owncloud.android.utils.FileStorageUtils;
 
 import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
 
 /**
  * A Fragment that lists all files and folders in a given path.
  *
  * TODO refactor to get rid of direct dependency on FileDisplayActivity
  */
-public class OCFileListFragment extends ExtendedListFragment
-        implements FileActionsDialogFragment.FileActionsDialogFragmentListener {
+public class OCFileListFragment extends ExtendedListFragment {
 
     private static final String TAG = OCFileListFragment.class.getSimpleName();
 
@@ -99,35 +99,44 @@ public class OCFileListFragment extends ExtendedListFragment
     private FileListListAdapter mAdapter;
     private boolean mJustFolders;
 
-    private OCFile mTargetFile;
+    private int mSystemBarActionModeColor;
+    private int mSystemBarColor;
+    private int mProgressBarActionModeColor;
+    private int mProgressBarColor;
 
+    private boolean mHideFab = true;
     private boolean miniFabClicked = false;
-   
+    private ActionMode mActiveActionMode;
+
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setHasOptionsMenu(true);
+        mSystemBarActionModeColor = getResources().getColor(R.color.action_mode_status_bar_background);
+        mSystemBarColor = getResources().getColor(R.color.primary_dark);
+        mProgressBarActionModeColor = getResources().getColor(R.color.action_mode_background);
+        mProgressBarColor = getResources().getColor(R.color.primary);
     }
 
     /**
      * {@inheritDoc}
      */
     @Override
-    public void onAttach(Activity activity) {
-        super.onAttach(activity);
-        Log_OC.e(TAG, "onAttach");
+    public void onAttach(Context context) {
+        super.onAttach(context);
+        Log_OC.i(TAG, "onAttach");
         try {
-            mContainerActivity = (FileFragment.ContainerActivity) activity;
+            mContainerActivity = (FileFragment.ContainerActivity) context;
 
         } catch (ClassCastException e) {
-            throw new ClassCastException(activity.toString() + " must implement " +
+            throw new ClassCastException(context.toString() + " must implement " +
                     FileFragment.ContainerActivity.class.getSimpleName());
         }
         try {
-            setOnRefreshListener((OnEnforceableRefreshListener) activity);
+            setOnRefreshListener((OnEnforceableRefreshListener) context);
 
         } catch (ClassCastException e) {
-            throw new ClassCastException(activity.toString() + " must implement " +
+            throw new ClassCastException(context.toString() + " must implement " +
                     SwipeRefreshLayout.OnRefreshListener.class.getSimpleName());
         }
     }
@@ -139,7 +148,11 @@ public class OCFileListFragment extends ExtendedListFragment
     public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
         Log_OC.i(TAG, "onCreateView() start");
         View v = super.onCreateView(inflater, container, savedInstanceState);
-
+        Bundle args = getArguments();
+        boolean allowContextualActions = (args != null) && args.getBoolean(ARG_ALLOW_CONTEXTUAL_ACTIONS, false);
+        if (allowContextualActions) {
+            setChoiceModeAsMultipleModal();
+        }
         Log_OC.i(TAG, "onCreateView() end");
         return v;
     }
@@ -158,7 +171,7 @@ public class OCFileListFragment extends ExtendedListFragment
     @Override
     public void onActivityCreated(Bundle savedInstanceState) {
         super.onActivityCreated(savedInstanceState);
-        Log_OC.e(TAG, "onActivityCreated() start");
+        Log_OC.i(TAG, "onActivityCreated() start");
 
         if (savedInstanceState != null) {
             mFile = savedInstanceState.getParcelable(KEY_FILE);
@@ -171,7 +184,7 @@ public class OCFileListFragment extends ExtendedListFragment
         }
 
         Bundle args = getArguments();
-        mJustFolders = (args == null) ? false : args.getBoolean(ARG_JUST_FOLDERS, false);
+        mJustFolders = (args != null) && args.getBoolean(ARG_JUST_FOLDERS, false);
         mAdapter = new FileListListAdapter(
                 mJustFolders,
                 getActivity(),
@@ -179,10 +192,8 @@ public class OCFileListFragment extends ExtendedListFragment
         );
         setListAdapter(mAdapter);
 
-        registerLongClickListener();
-
-        boolean hideFab = (args != null) && args.getBoolean(ARG_HIDE_FAB, false);
-        if (hideFab) {
+        mHideFab = (args != null) && args.getBoolean(ARG_HIDE_FAB, false);
+        if (mHideFab) {
             setFabEnabled(false);
         } else {
             setFabEnabled(true);
@@ -201,7 +212,7 @@ public class OCFileListFragment extends ExtendedListFragment
                 removeFabLabels();
             }
         }
-  }
+    }
 
     /**
      * adds labels to all mini FABs.
@@ -229,7 +240,7 @@ public class OCFileListFragment extends ExtendedListFragment
         getFabUpload().setOnClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View v) {
-                UploadFilesActivity.startUploadActivityForResult(getActivity(), ((FileActivity)getActivity())
+                UploadFilesActivity.startUploadActivityForResult(getActivity(), ((FileActivity) getActivity())
                         .getAccount(), FileDisplayActivity.REQUEST_CODE__SELECT_FILES_FROM_FILE_SYSTEM);
                 getFabMain().collapse();
                 recordMiniFabClick();
@@ -315,7 +326,7 @@ public class OCFileListFragment extends ExtendedListFragment
         // only record if it hasn't been done already at some other time
         if(!miniFabClicked) {
             final SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getActivity());
-            sp.edit().putLong(KEY_FAB_EVER_CLICKED, 1).commit();
+            sp.edit().putLong(KEY_FAB_EVER_CLICKED, 1).apply();
             miniFabClicked = true;
         }
     }
@@ -335,58 +346,76 @@ public class OCFileListFragment extends ExtendedListFragment
                 com.getbase.floatingactionbutton.R.id.fab_label)).setVisibility(View.GONE);
     }
 
-    private void registerLongClickListener() {
-        getListView().setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
-            public boolean onItemLongClick(AdapterView<?> arg0, View v,
-                                           int index, long arg3) {
-                showFileAction(index);
-                return true;
+    private void setChoiceModeAsMultipleModal() {
+
+        setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
+
+        setMultiChoiceModeListener(new AbsListView.MultiChoiceModeListener() {
+
+            @Override
+            public void onItemCheckedStateChanged(ActionMode mode, int position, long id, boolean checked) {
+                getListView().invalidateViews();
+                mode.invalidate();
             }
-        });
-    }
 
+            @Override
+            public boolean onCreateActionMode(ActionMode mode, Menu menu) {
+                mActiveActionMode = mode;
 
-    private void showFileAction(int fileIndex) {
-        Bundle args = getArguments();
-        PopupMenu pm = new PopupMenu(getActivity(),null);
-        Menu menu = pm.getMenu();
+                MenuInflater inflater = getActivity().getMenuInflater();
+                inflater.inflate(R.menu.file_actions_menu, menu);
+                mode.invalidate();
 
-        boolean allowContextualActions =
-                (args == null) ? true : args.getBoolean(ARG_ALLOW_CONTEXTUAL_ACTIONS, true);
+                //set gray color
+                DisplayUtils.colorStatusBar(getActivity(), mSystemBarActionModeColor);
+                DisplayUtils.colorToolbarProgressBar(getActivity(), mProgressBarActionModeColor);
 
-        if (allowContextualActions) {
-            MenuInflater inflater = getActivity().getMenuInflater();
+                // hide FAB in multi selection mode
+                setFabEnabled(false);
 
-            inflater.inflate(R.menu.file_actions_menu, menu);
-            OCFile targetFile = (OCFile) mAdapter.getItem(fileIndex);
+                return true;
+            }
 
-            if (mContainerActivity.getStorageManager() != null) {
+            @Override
+            public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
+                List<OCFile> checkedFiles = mAdapter.getCheckedItems(getListView());
+                final int checkedCount = checkedFiles.size();
+                String title = getResources().getQuantityString(
+                    R.plurals.items_selected_count,
+                    checkedCount,
+                    checkedCount
+                );
+                mode.setTitle(title);
                 FileMenuFilter mf = new FileMenuFilter(
-                        targetFile,
-                        mContainerActivity.getStorageManager().getAccount(),
-                        mContainerActivity,
-                        getActivity()
+                    checkedFiles,
+                    ((FileActivity) getActivity()).getAccount(),
+                    mContainerActivity,
+                    getActivity()
                 );
                 mf.filter(menu);
+
+                return true;
             }
 
-            /// TODO break this direct dependency on FileDisplayActivity... if possible
-            MenuItem item = menu.findItem(R.id.action_open_file_with);
-            FileFragment frag = ((FileDisplayActivity)getActivity()).getSecondFragment();
-            if (frag != null && frag instanceof FileDetailFragment &&
-                    frag.getFile().getFileId() == targetFile.getFileId()) {
-                item = menu.findItem(R.id.action_see_details);
-                if (item != null) {
-                    item.setVisible(false);
-                    item.setEnabled(false);
-                }
+            @Override
+            public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
+                return onFileActionChosen(item.getItemId());
             }
 
-            FileActionsDialogFragment dialog = FileActionsDialogFragment.newInstance(menu,
-                    fileIndex, targetFile.getFileName());
-            dialog.setTargetFragment(this, 0);
-            dialog.show(getFragmentManager(), FileActionsDialogFragment.FTAG_FILE_ACTIONS);
-        }
+            @Override
+            public void onDestroyActionMode(ActionMode mode) {
+                mActiveActionMode = null;
+
+                // reset to previous color
+                DisplayUtils.colorStatusBar(getActivity(), mSystemBarColor);
+                DisplayUtils.colorToolbarProgressBar(getActivity(), mProgressBarColor);
+
+                // show FAB on multi selection mode exit
+                if(!mHideFab) {
+                    setFabEnabled(true);
+                }
+            }
+        });
     }
 
     /**
@@ -412,7 +441,7 @@ public class OCFileListFragment extends ExtendedListFragment
      * return       Count of folder levels browsed up.
      */
     public int onBrowseUp() {
-        OCFile parentDir = null;
+        OCFile parentDir;
         int moveCount = 0;
 
         if (mFile != null) {
@@ -489,118 +518,86 @@ public class OCFileListFragment extends ExtendedListFragment
     }
 
     /**
-     * {@inheritDoc}
+     * Start the appropriate action(s) on the currently selected files given menu selected by the user.
+     *
+     * @param menuId        Identifier of the action menu selected by the user
+     * @return              'true' if the menu selection started any action, 'false' otherwise.
      */
-    @Override
-    public void onCreateContextMenu(
-            ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
-        Bundle args = getArguments();
-        boolean allowContextualActions =
-                (args == null) ? true : args.getBoolean(ARG_ALLOW_CONTEXTUAL_ACTIONS, true);
-        if (allowContextualActions) {
-            MenuInflater inflater = getActivity().getMenuInflater();
-            inflater.inflate(R.menu.file_actions_menu, menu);
-            AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo;
-            OCFile targetFile = (OCFile) mAdapter.getItem(info.position);
-
-            if (mContainerActivity.getStorageManager() != null) {
-                FileMenuFilter mf = new FileMenuFilter(
-                    targetFile,
-                    mContainerActivity.getStorageManager().getAccount(),
-                    mContainerActivity,
-                    getActivity()
-                );
-                mf.filter(menu);
-            }
+    public boolean onFileActionChosen(int menuId) {
+        final ArrayList<OCFile> checkedFiles = mAdapter.getCheckedItems(getListView());
+        if (checkedFiles.size() <= 0) return false;
+
+        if (checkedFiles.size() == 1) {
+            /// action only possible on a single file
+            OCFile singleFile = checkedFiles.get(0);
+            switch (menuId) {
+                case R.id.action_share_file: {
+                    mContainerActivity.getFileOperationsHelper().showShareFile(singleFile);
+                    return true;
+                }
+                case R.id.action_open_file_with: {
+                    mContainerActivity.getFileOperationsHelper().openFile(singleFile);
+                    return true;
+                }
+                case R.id.action_rename_file: {
+                    RenameFileDialogFragment dialog = RenameFileDialogFragment.newInstance(singleFile);
+                    dialog.show(getFragmentManager(), FileDetailFragment.FTAG_RENAME_FILE);
+                    return true;
+                }
+                case R.id.action_see_details: {
+                    if (mActiveActionMode != null) {
+                        mActiveActionMode.finish();
+                    }
+                    mContainerActivity.showDetails(singleFile);
+                    return true;
+                }
+                case R.id.action_send_file: {
+                    // Obtain the file
+                    if (!singleFile.isDown()) {  // Download the file
+                        Log_OC.d(TAG, singleFile.getRemotePath() + " : File must be downloaded");
+                        ((FileDisplayActivity) mContainerActivity).startDownloadForSending(singleFile);
 
-            /// TODO break this direct dependency on FileDisplayActivity... if possible
-            MenuItem item = menu.findItem(R.id.action_open_file_with);
-            FileFragment frag = ((FileDisplayActivity)getActivity()).getSecondFragment();
-            if (frag != null && frag instanceof FileDetailFragment &&
-                    frag.getFile().getFileId() == targetFile.getFileId()) {
-                item = menu.findItem(R.id.action_see_details);
-                if (item != null) {
-                    item.setVisible(false);
-                    item.setEnabled(false);
+                    } else {
+                        mContainerActivity.getFileOperationsHelper().sendDownloadedFile(singleFile);
+                    }
+                    return true;
                 }
             }
-
-//            String.format(mContext.getString(R.string.subject_token),
-//                    getClient().getCredentials().getUsername(), file.getFileName()));
-
         }
-    }
 
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public boolean onFileActionChosen(int menuId, int filePosition) {
-        mTargetFile = (OCFile) mAdapter.getItem(filePosition);
+        /// actions possible on a batch of files
         switch (menuId) {
-            case R.id.action_share_file: {
-                mContainerActivity.getFileOperationsHelper().showShareFile(mTargetFile);
-                return true;
-            }
-            case R.id.action_open_file_with: {
-                mContainerActivity.getFileOperationsHelper().openFile(mTargetFile);
-                return true;
-            }
-            case R.id.action_rename_file: {
-                RenameFileDialogFragment dialog = RenameFileDialogFragment.newInstance(mTargetFile);
-                dialog.show(getFragmentManager(), FileDetailFragment.FTAG_RENAME_FILE);
-                return true;
-            }
             case R.id.action_remove_file: {
-                RemoveFileDialogFragment dialog = RemoveFileDialogFragment.newInstance(mTargetFile);
+                RemoveFilesDialogFragment dialog = RemoveFilesDialogFragment.newInstance(checkedFiles);
                 dialog.show(getFragmentManager(), ConfirmationDialogFragment.FTAG_CONFIRMATION);
                 return true;
             }
             case R.id.action_download_file:
             case R.id.action_sync_file: {
-                mContainerActivity.getFileOperationsHelper().syncFile(mTargetFile);
+                mContainerActivity.getFileOperationsHelper().syncFiles(checkedFiles);
                 return true;
             }
             case R.id.action_cancel_sync: {
-                ((FileDisplayActivity)mContainerActivity).cancelTransference(mTargetFile);
+                ((FileDisplayActivity) mContainerActivity).cancelTransference(checkedFiles);
                 return true;
             }
-            case R.id.action_see_details: {
-                mContainerActivity.showDetails(mTargetFile);
+            case R.id.action_favorite_file: {
+                mContainerActivity.getFileOperationsHelper().toggleFavorites(checkedFiles, true);
                 return true;
             }
-            case R.id.action_send_file: {
-                // Obtain the file
-                if (!mTargetFile.isDown()) {  // Download the file
-                    Log_OC.d(TAG, mTargetFile.getRemotePath() + " : File must be downloaded");
-                    ((FileDisplayActivity) mContainerActivity).startDownloadForSending(mTargetFile);
-
-                } else {
-                    mContainerActivity.getFileOperationsHelper().sendDownloadedFile(mTargetFile);
-                }
+            case R.id.action_unfavorite_file: {
+                mContainerActivity.getFileOperationsHelper().toggleFavorites(checkedFiles, false);
                 return true;
             }
             case R.id.action_move: {
                 Intent action = new Intent(getActivity(), FolderPickerActivity.class);
-
-                // Pass mTargetFile that contains info of selected file/folder
-                action.putExtra(FolderPickerActivity.EXTRA_FILE, mTargetFile);
+                action.putParcelableArrayListExtra(FolderPickerActivity.EXTRA_FILES, checkedFiles);
                 getActivity().startActivityForResult(action, FileDisplayActivity.REQUEST_CODE__MOVE_FILES);
                 return true;
             }
-            case R.id.action_favorite_file: {
-                mContainerActivity.getFileOperationsHelper().toggleFavorite(mTargetFile, true);
-                return true;
-            }
-            case R.id.action_unfavorite_file: {
-                mContainerActivity.getFileOperationsHelper().toggleFavorite(mTargetFile, false);
-                return true;
-            }
             case R.id.action_copy:
                 Intent action = new Intent(getActivity(), FolderPickerActivity.class);
-
-                // Pass mTargetFile that contains info of selected file/folder
-                action.putExtra(FolderPickerActivity.EXTRA_FILE, mTargetFile);
+                action.putParcelableArrayListExtra(FolderPickerActivity.EXTRA_FILES, checkedFiles);
                 getActivity().startActivityForResult(action, FileDisplayActivity.REQUEST_CODE__COPY_FILES);
                 return true;
             default:
@@ -608,22 +605,6 @@ public class OCFileListFragment extends ExtendedListFragment
         }
     }
 
-    /**
-     * {@inhericDoc}
-     */
-    @Override
-    public boolean onContextItemSelected (MenuItem item) {
-        AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
-        boolean matched = onFileActionChosen(item.getItemId(),
-                ((AdapterContextMenuInfo) item.getMenuInfo()).position);
-        if(!matched) {
-            return super.onContextItemSelected(item);
-        } else {
-            return matched;
-        }
-    }
-
-
     /**
      * Use this to query the {@link OCFile} that is currently
      * being displayed by this fragment
@@ -686,7 +667,7 @@ public class OCFileListFragment extends ExtendedListFragment
 
     private void updateLayout() {
         if (!mJustFolders) {
-            int filesCount = 0, foldersCount = 0, imagesCount = 0;
+            int filesCount = 0, foldersCount = 0;
             int count = mAdapter.getCount();
             OCFile file;
             for (int i=0; i < count ; i++) {
@@ -696,10 +677,6 @@ public class OCFileListFragment extends ExtendedListFragment
                 } else {
                     if (!file.isHidden()) {
                         filesCount++;
-
-                        if (file.isImage() || file.isVideo()) {
-                            imagesCount++;
-                        }
                     }
                 }
             }
@@ -712,11 +689,17 @@ public class OCFileListFragment extends ExtendedListFragment
             if (version != null && version.supportsRemoteThumbnails() &&
                     isGridViewPreferred(mFile)) {
                 switchToGridView();
-                registerLongClickListener();
             } else {
                 switchToListView();
             }
         }
+        invalidateActionMode();
+    }
+
+    private void invalidateActionMode() {
+        if(mActiveActionMode != null){
+            mActiveActionMode.invalidate();
+        }
     }
 
     private String generateFooterText(int filesCount, int foldersCount) {
@@ -774,13 +757,13 @@ public class OCFileListFragment extends ExtendedListFragment
     /**
      * Determines if user set folder to grid or list view. If folder is not set itself,
      * it finds a parent that is set (at least root is set).
-     * @param file
-     * @return
+     * @param file      Folder to check.
+     * @return          'true' is folder should be shown in grid mode, 'false' if list mode is preferred.
      */
     public boolean isGridViewPreferred(OCFile file){
         if (file != null) {
             OCFile fileToTest = file;
-            OCFile parentDir = null;
+            OCFile parentDir;
             String parentPath = null;
             FileDataStorageManager storageManager = mContainerActivity.getStorageManager();
 

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

@@ -46,7 +46,7 @@ import com.owncloud.android.datamodel.OCFile;
 import com.owncloud.android.files.FileMenuFilter;
 import com.owncloud.android.lib.common.utils.Log_OC;
 import com.owncloud.android.ui.dialog.ConfirmationDialogFragment;
-import com.owncloud.android.ui.dialog.RemoveFileDialogFragment;
+import com.owncloud.android.ui.dialog.RemoveFilesDialogFragment;
 import com.owncloud.android.ui.fragment.FileFragment;
 import com.owncloud.android.utils.BitmapUtils;
 import com.owncloud.android.utils.DisplayUtils;
@@ -294,7 +294,7 @@ public class PreviewImageFragment extends FileFragment {
                 return true;
             }
             case R.id.action_remove_file: {
-                RemoveFileDialogFragment dialog = RemoveFileDialogFragment.newInstance(getFile());
+                RemoveFilesDialogFragment dialog = RemoveFilesDialogFragment.newInstance(getFile());
                 dialog.show(getFragmentManager(), ConfirmationDialogFragment.FTAG_CONFIRMATION);
                 return true;
             }
@@ -319,7 +319,7 @@ public class PreviewImageFragment extends FileFragment {
                 return true;
             }
             default:
-                return false;
+                return super.onOptionsItemSelected(item);
         }
     }
 

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

@@ -59,7 +59,7 @@ import com.owncloud.android.media.MediaService;
 import com.owncloud.android.media.MediaServiceBinder;
 import com.owncloud.android.ui.activity.FileActivity;
 import com.owncloud.android.ui.dialog.ConfirmationDialogFragment;
-import com.owncloud.android.ui.dialog.RemoveFileDialogFragment;
+import com.owncloud.android.ui.dialog.RemoveFilesDialogFragment;
 import com.owncloud.android.ui.fragment.FileFragment;
 
 
@@ -357,7 +357,7 @@ public class PreviewMediaFragment extends FileFragment implements
                 return true;
             }
             case R.id.action_remove_file: {
-                RemoveFileDialogFragment dialog = RemoveFileDialogFragment.newInstance(getFile());
+                RemoveFilesDialogFragment dialog = RemoveFilesDialogFragment.newInstance(getFile());
                 dialog.show(getFragmentManager(), ConfirmationDialogFragment.FTAG_CONFIRMATION);
                 return true;
             }
@@ -382,7 +382,7 @@ public class PreviewMediaFragment extends FileFragment implements
                 return true;
             }
             default:
-                return false;
+                return super.onOptionsItemSelected(item);
         }
     }
 

Some files were not shown because too many files changed in this diff