Merge remote-tracking branch 'remotes/upstream/externalSD2' into beta
authortobiasKaminsky <tobias@kaminsky.me>
Fri, 20 Nov 2015 17:32:55 +0000 (18:32 +0100)
committertobiasKaminsky <tobias@kaminsky.me>
Fri, 20 Nov 2015 17:32:55 +0000 (18:32 +0100)
1  2 
AndroidManifest.xml
owncloud-android-library
res/values-hu-rHU/strings.xml
res/values/strings.xml
res/xml/preferences.xml
src/com/owncloud/android/MainApp.java
src/com/owncloud/android/datamodel/FileDataStorageManager.java
src/com/owncloud/android/ui/activity/Preferences.java
src/com/owncloud/android/ui/activity/UploadFilesActivity.java
src/com/owncloud/android/utils/FileStorageUtils.java

diff --combined AndroidManifest.xml
  
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 --->
 -<manifest xmlns:android="http://schemas.android.com/apk/res/android"
 -    package="com.owncloud.android"
 + -->
 +<manifest package="com.owncloud.android"
      android:versionCode="10800000"
 -    android:versionName="1.8.0" >
 +    android:versionName="ownCloud beta" xmlns:android="http://schemas.android.com/apk/res/android">
  
      <uses-sdk
          android:minSdkVersion="14"
              </intent-filter>
          </activity>
          <activity android:name=".ui.activity.UploadFilesActivity" />
 -        <activity android:name=".ui.activity.Uploader" >
+         <activity android:name=".ui.activity.LocalDirectorySelectorActivity" />
+         <activity android:name=".ui.activity.StorageMigrationActivity" />
 +        <activity android:name=".ui.activity.Uploader"
 +            android:label="@string/uploader_top_message"
 +            android:theme="@style/Theme.ownCloud">
              <intent-filter>
                  <action android:name="android.intent.action.SEND" />
  
              android:name=".providers.FileContentProvider"
              android:authorities="@string/authority"
              android:enabled="true"
 -            android:exported="false"
 +            android:exported="true"
              android:label="@string/sync_string_files"
              android:syncable="true" />
  
              android:exported="false"
              android:label="@string/search_users_and_groups_hint" />
  
 +        <provider
 +            android:name=".ui.adapter.DiskLruImageCacheFileProvider"
 +            android:authorities="@string/authorityCache"
 +            android:exported="true">
 +        </provider>
 +
          <activity
              android:name=".authentication.AuthenticatorActivity"
              android:exported="true"
          <service android:name=".media.MediaService" />
  
          <activity android:name=".ui.activity.PassCodeActivity" />
 -        <activity android:name=".ui.activity.ConflictsResolveActivity" />
 -        <activity android:name=".ui.activity.GenericExplanationActivity" />
 -        <activity android:name=".ui.activity.ErrorsWhileCopyingHandlerActivity" />
 -        <activity android:name=".ui.activity.LogHistoryActivity" />
 -
 -        <receiver android:name=".files.InstantUploadBroadcastReceiver" >
 +        <activity android:name=".ui.activity.ConflictsResolveActivity"/>
 +        <activity android:name=".ui.activity.GenericExplanationActivity"/>
 +        <activity android:name=".ui.activity.ErrorsWhileCopyingHandlerActivity"/>
 +        
 +        <activity android:name=".ui.activity.LogHistoryActivity"/>
 +        <activity android:name=".ui.activity.ErrorReportActivity"/>
 +
 +        <receiver android:name=".files.InstantUploadBroadcastReceiver">
              <intent-filter>
  
                  <!-- unofficially supported by many Android phones but not by HTC devices: -->
              <intent-filter>
                  <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
              </intent-filter>
 +            <intent-filter>
 +                              <action android:name="android.intent.action.ACTION_POWER_CONNECTED"/>
 +                          <action android:name="android.intent.action.ACTION_POWER_DISCONNECTED"/>
 +                      </intent-filter>
          </receiver>
          <receiver android:name=".files.BootupBroadcastReceiver" >
              <intent-filter>
diff --combined owncloud-android-library
@@@ -1,1 -1,1 +1,1 @@@
- Subproject commit 2e0f2a79224383145d61cc15ca42c6bcc59902d5
 -Subproject commit b09969d078b3a790b01c8d61a7298a37439a9f24
++Subproject commit 4f9a7528cab0563cb234a8b817e8ee371dd6cc25
    <string name="unfavorite">Nem kedvenc</string>
    <string name="common_rename">Átnevezés</string>
    <string name="common_remove">Eltávolítás</string>
 -  <string name="confirmation_remove_alert">Tényleg el akarod távolítani %1$s?</string>
 +  <string name="confirmation_remove_file_alert">Tényleg el akarod távolítani %1$s?</string>
    <string name="confirmation_remove_folder_alert">Tényleg el akarod távolítani a %1$s és tartalmát?</string>
    <string name="confirmation_remove_local">Csak a helyi példány</string>
    <string name="confirmation_remove_folder_local">Csak a helyi példány</string>
    <string name="sync_file_nothing_to_do_msg">Az állományok már szinkonizálva vannak</string>
    <string name="create_dir_fail_msg">A könyvtárt nem lehet létrehozni</string>
    <string name="filename_forbidden_characters">Nem megendedett karakterek: / \\ &lt; &gt; : \" | ? *</string>
+   <string name="filename_forbidden_charaters_from_server">A fájlnév legalább egy érvénytelen karaktert tartalmaz!</string>
    <string name="filename_empty">A fájl név nem lehet üres</string>
    <string name="wait_a_moment">Egy pillanat...</string>
    <string name="filedisplay_unexpected_bad_get_content">Váratlan hiba; válassza ki a fájlt más programból</string>
diff --combined res/values/strings.xml
@@@ -23,7 -23,8 +23,7 @@@
      <!-- TODO re-enable when "Accounts" is available in Navigation Drawer -->
      <!--<string name="drawer_item_accounts">Accounts</string>-->
      <string name="drawer_item_all_files">All files</string>
 -    <!-- TODO re-enable when "On Device" is available
 -    <string name="drawer_item_on_device">On device</string>-->
 +    <string name="drawer_item_on_device">On device</string>
      <string name="drawer_item_settings">Settings</string>
      <string name="drawer_item_logs">Logs</string>
        <string name="drawer_close">Close</string>
@@@ -61,7 -62,7 +61,7 @@@
      <string name="setup_btn_connect">Connect</string>
      <string name="uploader_btn_upload_text">Upload</string>
      <string name="uploader_btn_new_folder_text">New folder</string>
 -    <string name="uploader_top_message">Choose upload folder:</string>
 +    <string name="uploader_top_message">Choose upload folder</string>
      <string name="uploader_wrn_no_account_title">No account found</string>
      <string name="uploader_wrn_no_account_text">There are no %1$s accounts on your device. Please setup an account first.</string>
      <string name="uploader_wrn_no_account_setup_btn_text">Setup</string>
      <string name="unfavorite">Unfavorite</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="confirmation_remove_folder_local">Local only</string>
 -    <string name="confirmation_remove_remote">From server</string>
 +    <string name="confirmation_remove_file_remote">From server</string>
      <string name="confirmation_remove_remote_and_local">Remote &amp; local</string>
      <string name="remove_success_msg">"Removal succeeded"</string>
      <string name="remove_fail_msg">"Removal failed"</string>
      <string name="placeholder_filesize">389 KB</string>
      <string name="placeholder_timestamp">2012/05/18 12:23 PM</string>
      <string name="placeholder_media_time">12:23:45</string>
 -
 -    <string name="instant_upload_on_wifi">Upload pictures via WiFi only</string>
 -    <string name="instant_video_upload_on_wifi">Upload videos via WiFi only</string>
 +    
 +    <string name="instant_upload_on_wifi">Upload pictures via wifi only</string>
 +    <string name="instant_upload_on_charging">Upload when charging only</string>
 +    <string name="instant_video_upload_on_wifi">Upload videos via wifi only</string>
 +    <string name="instant_video_upload_on_charging">Upload when charging only</string>
      <string name="instant_upload_path">/InstantUpload</string>
      <string name="conflict_title">File conflict</string>
      <string name="conflict_message">Which files do you want to keep? If you select both versions, the local file will have a number added to its name.</string>
      <string name="preview_image_error_unknown_format">This image cannot be shown</string>
  
      <string name="error__upload__local_file_not_copied">%1$s could not be copied to %2$s local folder</string>
 -    <string name="prefs_instant_upload_path_title">Upload Path</string>
 +    <string name="prefs_instant_upload_path_title">Upload path</string>
  
        <string name="share_link_no_support_share_api">Sorry, sharing is not enabled on your server. Please contact your
                administrator.</string>
      <string name="uploader_upload_forbidden_permissions">to upload in this folder</string>
      <string name="downloader_download_file_not_found">The file is no longer available on the server</string>
  
+     <string name="file_migration_finish_button">Finish</string>
+     <string name="file_migration_preparing">Preparing for migration...</string>
+     <string name="file_migration_checking_destination">Checking destination...</string>
+     <string name="file_migration_saving_accounts_configuration">Saving accounts configuration...</string>
+     <string name="file_migration_waiting_for_unfinished_sync">Waiting for unfinished synchronizations...</string>
+     <string name="file_migration_migrating">Moving data...</string>
+     <string name="file_migration_updating_index">Updating index...</string>
+     <string name="file_migration_cleaning">Cleaning...</string>
+     <string name="file_migration_restoring_accounts_configuration">Restoring accounts configuration...</string>
+     <string name="file_migration_ok_finished">Finished</string>
+     <string name="file_migration_failed_not_enough_space">ERROR: Not enough space</string>
+     <string name="file_migration_failed_not_writable">ERROR: File is not writable</string>
+     <string name="file_migration_failed_not_readable">ERROR: File is not readable</string>
+     <string name="file_migration_failed_dir_already_exists">ERROR: owncloud directory already exists</string>
+     <string name="file_migration_failed_while_coping">ERROR: While migrating</string>
+     <string name="file_migration_failed_while_updating_index">ERROR: While updating index</string>
      <string name="prefs_category_accounts">Accounts</string>
      <string name="prefs_add_account">Add account</string>
      <string name="auth_redirect_non_secure_connection_title">Secure connection is redirected through an unsecured route.</string>
      <string name="prefs_category_instant_uploading">Instant Uploads</string>
        <string name="prefs_category_security">Security</string>
  
 -      <string name="prefs_instant_video_upload_path_title">Upload Video Path</string>
 +      <string name="prefs_instant_video_upload_path_title">Upload video path</string>
 +    <string name="download_folder_failed_content">Download of %1$s folder could not be completed</string>
      <string name="sync_folder_failed_content">Synchronization of %1$s folder could not be completed</string>
  
        <string name="shared_subject_header">shared</string>
      <string name="file_list__footer__files">%1$d files</string>
      <string name="file_list__footer__files_and_folder">%1$d files, 1 folder</string>
      <string name="file_list__footer__files_and_folders">%1$d files, %2$d folders</string>
 +    <string name="action_switch_grid_view">Switch to grid view</string>
 +    <string name="action_switch_list_view">Switch to list view</string>
 +    <string name="common_category">Common</string>
 +    <string name="pref_cache_size">Cache size</string>
 +    <string name="prefs_instant_behaviour_dialogTitle">Upload file to server and ...</string>
 +    <string name="prefs_instant_behaviour_title">Behaviour</string>
 +    <string name="upload_copy_files">Copy file</string>
 +    <string name="upload_move_files">Move file</string>
+     <string name="prefs_storage_path">Storage path</string>
+     <string name="prefs_common">Common</string>
  
 +    <string name="pref_behaviour_entries_do_nothing">do nothing</string>
 +    <string name="pref_behaviour_entries_copy">copy file to OC folder</string>
 +    <string name="pref_behaviour_entries_move">move file to OC folder</string>
 +    <string name="pref_behaviour_entries_delete">delete origin file</string>
 +    <string name="confirmation_remove_files_alert">Do you really want to remove selected items?</string>
 +    <string name="confirmation_remove_folders_alert">Do you really want to remove a folder and its content?</string>
 +    <string name="confirmation_remove_files">selected items</string>
 +    <string name="error_log_exit">Exit</string>
 +    <string name="error_log_send">Send Log</string>
 +    <string name="error_log_title">Error Log</string>
 +    <string name="action_stream_file">Stream file with external player</string>
 +    <string name="stream_expose_password">Do you want to stream this file with an external app?\n\nCAUTION: This may expose your password!</string>
 +    <string name="set_picture_as">Set picture as</string>
 +
      <string name="share_dialog_title">Sharing</string>
      <string name="share_with_user_section_title">Share with Users and Groups</string>
      <string name="share_no_users">No data shared with users yet</string>
  
      <string name="share_sharee_unavailable">Sorry, your server version does not allow share with users within clients.
          \nPlease contact your administrator</string>
 +    <string name="changelog">https://github.com/owncloud/android/raw/beta/CHANGELOG.md</string>
  
  </resources>
diff --combined res/xml/preferences.xml
@@@ -3,7 -3,7 +3,7 @@@
    ownCloud Android client application
  
    Copyright (C) 2012  Bartek Przybylski
 -  Copyright (C) 2015 ownCloud Inc.
 +  Copyright (C) 2012-2013 ownCloud Inc.
  
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License version 2,
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  -->
  <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >
-     <PreferenceCategory
-               android:title="@string/prefs_category_accounts"
-               android:key="accounts_category">
+       <PreferenceCategory android:title="@string/prefs_category_general">
+               <com.owncloud.android.ui.PreferenceWithLongSummary
+                       android:title="@string/prefs_storage_path"
+                       android:key="storage_path" />
+       </PreferenceCategory>
+     <PreferenceCategory android:title="@string/prefs_category_accounts" android:key="accounts_category">
      </PreferenceCategory>
 -    
 +
        <PreferenceCategory android:title="@string/prefs_category_security">
 -          <android.preference.CheckBoxPreference android:title="@string/prefs_passcode" android:key="set_pincode" />
 +              <android.preference.CheckBoxPreference android:title="@string/prefs_passcode" android:key="set_pincode" />
        </PreferenceCategory>
  
      <PreferenceCategory android:title="@string/prefs_category_instant_uploading" android:key="instant_uploading_category">
 -         <com.owncloud.android.ui.CheckBoxPreferenceWithLongTitle android:key="instant_uploading"
 +         <com.owncloud.android.ui.dialog.OwnCloudListPreference android:key="prefs_instant_behaviour"
 +                       android:dialogTitle="@string/prefs_instant_behaviour_dialogTitle"
 +                       android:title="@string/prefs_instant_behaviour_title"
 +                       android:entries="@array/pref_behaviour_entries"
 +                       android:entryValues="@array/pref_behaviour_entryValues"
 +                       android:defaultValue="NOTHING"
 +                       android:summary="%s"
 +                       />
 +
 +              <com.owncloud.android.ui.CheckBoxPreferenceWithLongTitle android:key="instant_uploading"
                                android:title="@string/prefs_instant_upload"
                                android:summary="@string/prefs_instant_upload_summary"/>
           <com.owncloud.android.ui.PreferenceWithLongSummary
                                                        android:title="@string/prefs_instant_upload_path_title"
                                                        android:key="instant_upload_path" />
            <com.owncloud.android.ui.CheckBoxPreferenceWithLongTitle
 -                                              android:title="@string/instant_upload_on_wifi"
 -                                              android:key="instant_upload_on_wifi"/>
 -          <com.owncloud.android.ui.CheckBoxPreferenceWithLongTitle android:key="instant_video_uploading"
 -                              android:title="@string/prefs_instant_video_upload"
 -                              android:summary="@string/prefs_instant_video_upload_summary" />
 +                      android:dependency="instant_uploading"
 +                      android:disableDependentsState="true"
 +              android:title="@string/instant_upload_on_wifi"
 +              android:key="instant_upload_on_wifi"/>
 +              <com.owncloud.android.ui.CheckBoxPreferenceWithLongTitle
 +                      android:dependency="instant_uploading"
 +                      android:disableDependentsState="true"
 +                      android:title="@string/instant_upload_on_charging"
 +                      android:key="instant_upload_on_charging"/>
 +
 +              <com.owncloud.android.ui.CheckBoxPreferenceWithLongTitle
 +                      android:key="instant_video_uploading"
 +              android:title="@string/prefs_instant_video_upload"
 +              android:summary="@string/prefs_instant_video_upload_summary" />
            <com.owncloud.android.ui.PreferenceWithLongSummary
 -                                                      android:title="@string/prefs_instant_video_upload_path_title"
 -                                                      android:key="instant_video_upload_path" />
 +                      android:dependency="instant_video_uploading"
 +                      android:disableDependentsState="true"
 +                      android:title="@string/prefs_instant_video_upload_path_title"
 +                      android:key="instant_video_upload_path" />
            <com.owncloud.android.ui.CheckBoxPreferenceWithLongTitle
 -                                              android:title="@string/instant_video_upload_on_wifi"
 -                                              android:key="instant_video_upload_on_wifi"/>
 -          <!-- DISABLED FOR RELEASE UNTIL FIXED
 +                      android:dependency="instant_video_uploading"
 +                      android:disableDependentsState="true"
 +              android:title="@string/instant_video_upload_on_wifi"
 +              android:key="instant_video_upload_on_wifi"/>
 +              <com.owncloud.android.ui.CheckBoxPreferenceWithLongTitle
 +                      android:dependency="instant_video_uploading"
 +                      android:disableDependentsState="true"
 +                      android:title="@string/instant_video_upload_on_charging"
 +                      android:key="instant_video_upload_on_charging"/>
 +      </PreferenceCategory>
 +
 +      <PreferenceCategory android:title="@string/common_category" android:key="common_category">
 +              <EditTextPreference android:title="@string/pref_cache_size"
 +                                                      android:key="pref_cache_size"
 +                                                      android:digits="0123456789"/>
 +      </PreferenceCategory>
 +
 +      <PreferenceCategory android:title="@string/prefs_category_more" android:key="more">
 +              <!-- DISABLED FOR RELEASE UNTIL FIXED
            CheckBoxPreference android:key="log_to_file"
                                android:title="@string/prefs_log_title"
                                android:summary="@string/prefs_log_summary"/>
                <Preference             android:key="log_history"
                                android:title="@string/prefs_log_title_history"
                                android:summary="@string/prefs_log_summary_history"/ -->
 -                        
 -    </PreferenceCategory>
 -      
 -      <PreferenceCategory android:title="@string/prefs_category_more" android:key="more">
      <Preference android:title="@string/prefs_help" android:key="help" />
      <Preference android:title="@string/prefs_recommend" android:key="recommend" />
      <Preference android:title="@string/prefs_feedback" android:key="feedback" />
      <Preference android:title="@string/prefs_imprint" android:key="imprint" />
 -                        
 -      <Preference             android:id="@+id/about_app" 
 -                                      android:title="@string/about_title" 
 +
 +      <Preference             android:id="@+id/about_app"
 +                                      android:title="@string/about_title"
                                        android:key="about_app" />
 -      </PreferenceCategory>
 -    
  
 +      <Preference android:id="@+id/beta_link"
 +                              android:title="Download latest beta version"
 +                              android:key="beta_link" />
 +
 +      <Preference android:id="@+id/changelog_link"
 +              android:title="Changelog beta version"
 +              android:key="changelog_link" />
 +
 +      </PreferenceCategory>
  </PreferenceScreen>
@@@ -23,18 -23,19 +23,21 @@@ package com.owncloud.android
  import android.app.Activity;
  import android.app.Application;
  import android.content.Context;
 +import android.content.Intent;
+ import android.content.SharedPreferences;
  import android.content.pm.PackageInfo;
  import android.content.pm.PackageManager;
  import android.os.Build;
  import android.os.Bundle;
+ import android.os.Environment;
+ import android.preference.PreferenceManager;
  
  import com.owncloud.android.authentication.PassCodeManager;
  import com.owncloud.android.datamodel.ThumbnailsCacheManager;
  import com.owncloud.android.lib.common.OwnCloudClientManagerFactory;
  import com.owncloud.android.lib.common.OwnCloudClientManagerFactory.Policy;
  import com.owncloud.android.lib.common.utils.Log_OC;
 +import com.owncloud.android.utils.ExceptionHandler;
  
  
  /**
@@@ -56,16 -57,22 +59,24 @@@ public class MainApp extends Applicatio
  
      private static Context mContext;
  
 -    // TODO Enable when "On Device" is recovered?
 -    // TODO better place
 -    // private static boolean mOnlyOnDevice = false;
+     private static String storagePath;
 +    private static boolean mOnlyOnDevice = false;
  
      
      public void onCreate(){
          super.onCreate();
          MainApp.mContext = getApplicationContext();
  
 +        // Setup handler for uncaught exceptions.
 +        Thread.setDefaultUncaughtExceptionHandler(new ExceptionHandler());
 +        
++
+         SharedPreferences appPrefs =
+                 PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
+         MainApp.storagePath = appPrefs.getString("storage_path", Environment.
+                               getExternalStorageDirectory().getAbsolutePath());
          boolean isSamlAuth = AUTH_ON.equals(getString(R.string.auth_method_saml_web_sso));
  
          OwnCloudClientManagerFactory.setUserAgent(getUserAgent());
@@@ -85,7 -92,7 +96,7 @@@
              // Set folder for store logs
              Log_OC.setLogDataFolder(dataFolder);
  
-             Log_OC.startLogging();
+             Log_OC.startLogging(MainApp.storagePath);
              Log_OC.d("Debug", "start logging");
          }
  
          return MainApp.mContext;
      }
  
+     public static String getStoragePath(){
+         return MainApp.storagePath;
+     }
+     public static void setStoragePath(String path){
+         MainApp.storagePath = path;
+     }
      // Methods to obtain Strings referring app_name 
      //   From AccountAuthenticator 
      //   public static final String ACCOUNT_TYPE = "owncloud";    
          return getAppContext().getResources().getString(R.string.log_name);
      }
  
 -    // TODO Enable when "On Device" is recovered ?
 -//    public static void showOnlyFilesOnDevice(boolean state){
 -//        mOnlyOnDevice = state;
 -//    }
 -//
 -//    public static boolean getOnlyOnDevice(){
 -//        return mOnlyOnDevice;
 -//    }
 +    public static void showOnlyFilesOnDevice(boolean state){
 +        mOnlyOnDevice = state;
 +    }
 +
 +    public static boolean getOnlyOnDevice(){
 +        return mOnlyOnDevice;
 +    }
  
      // user agent
      public static String getUserAgent() {
@@@ -47,19 -47,12 +47,12 @@@ import android.provider.MediaStore
  import com.owncloud.android.MainApp;
  import com.owncloud.android.db.ProviderMeta.ProviderTableMeta;
  import com.owncloud.android.lib.common.utils.Log_OC;
- import com.owncloud.android.lib.resources.files.FileUtils;
  import com.owncloud.android.lib.resources.shares.OCShare;
  import com.owncloud.android.lib.resources.shares.ShareType;
  import com.owncloud.android.lib.resources.status.CapabilityBooleanType;
  import com.owncloud.android.lib.resources.status.OCCapability;
  import com.owncloud.android.utils.FileStorageUtils;
  
- import java.io.FileInputStream;
- import java.io.FileOutputStream;
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.OutputStream;
  public class FileDataStorageManager {
  
      public static final int ROOT_PARENT_ID = 0;
      }
  
  
 -    public Vector<OCFile> getFolderContent(OCFile f/*, boolean onlyOnDevice*/) {
 +    public Vector<OCFile> getFolderContent(OCFile f, boolean onlyOnDevice) {
          if (f != null && f.isFolder() && f.getFileId() != -1) {
 -            // TODO Enable when "On Device" is recovered ?
 -            return getFolderContent(f.getFileId()/*, onlyOnDevice*/);
 +            return getFolderContent(f.getFileId(), onlyOnDevice);
  
          } else {
              return new Vector<OCFile>();
      }
  
  
 -    public Vector<OCFile> getFolderImages(OCFile folder/*, boolean onlyOnDevice*/) {
 -        Vector<OCFile> ret = new Vector<OCFile>();
 +    public Vector<OCFile> getFolderImages(OCFile folder, boolean onlyOnDevice) {
 +        Vector<OCFile> ret = new Vector<OCFile>(); 
          if (folder != null) {
              // TODO better implementation, filtering in the access to database instead of here
 -            // TODO Enable when "On Device" is recovered ?
 -            Vector<OCFile> tmp = getFolderContent(folder/*, onlyOnDevice*/);
 -            OCFile current = null;
 +            Vector<OCFile> tmp = getFolderContent(folder, onlyOnDevice);
 +            OCFile current = null; 
              for (int i=0; i<tmp.size(); i++) {
                  current = tmp.get(i);
                  if (current.isImage()) {
          File localFolder = new File(localFolderPath);
          if (localFolder.exists()) {
              // stage 1: remove the local files already registered in the files database
 -            // TODO Enable when "On Device" is recovered ?
 -            Vector<OCFile> files = getFolderContent(folder.getFileId()/*, false*/);
 +            Vector<OCFile> files = getFolderContent(folder.getFileId(), false);
              if (files != null) {
                  for (OCFile file : files) {
                      if (file.isFolder()) {
                  if (!targetFolder.exists()) {
                      targetFolder.mkdirs();
                  }
-                 copied = copyFile(localFile, targetFile);
+                 copied = FileStorageUtils.copyFile(localFile, targetFile);
              }
              Log_OC.d(TAG, "Local file COPIED : " + copied);
          }
      }
  
-     private boolean copyFile(File src, File target) {
-         boolean ret = true;
+     public void migrateStoredFiles(String srcPath, String dstPath) throws Exception {
+         Cursor c = null;
+         if (getContentResolver() != null) {
+             c = getContentResolver().query(ProviderTableMeta.CONTENT_URI_FILE,
+                     null,
+                     ProviderTableMeta.FILE_STORAGE_PATH  + " IS NOT NULL",
+                     null,
+                     null);
+         } else {
+             try {
+                 c = getContentProviderClient().query(ProviderTableMeta.CONTENT_URI_FILE,
+                         new String[]{ProviderTableMeta._ID, ProviderTableMeta.FILE_STORAGE_PATH},
+                         ProviderTableMeta.FILE_STORAGE_PATH + " IS NOT NULL",
+                         null,
+                         null);
+             } catch (RemoteException e) {
+                 Log_OC.e(TAG, e.getMessage());
+                 throw e;
+             }
+         }
+         ArrayList<ContentProviderOperation> operations =
+                 new ArrayList<ContentProviderOperation>(c.getCount());
+         if (c.moveToFirst()) {
+             do {
+                 ContentValues cv = new ContentValues();
+                 long fileId = c.getLong(c.getColumnIndex(ProviderTableMeta._ID));
+                 String oldFileStoragePath = c.getString(c.getColumnIndex(ProviderTableMeta.FILE_STORAGE_PATH));
+                 if (oldFileStoragePath.startsWith(srcPath)) {
+                     cv.put(
+                             ProviderTableMeta.FILE_STORAGE_PATH,
+                             oldFileStoragePath.replaceFirst(srcPath, dstPath));
+                     operations.add(
+                             ContentProviderOperation.newUpdate(ProviderTableMeta.CONTENT_URI).
+                                     withValues(cv).
+                                     withSelection(
+                                             ProviderTableMeta._ID + "=?",
+                                             new String[]{String.valueOf(fileId)}
+                                     )
+                                     .build());
+                 }
  
-         InputStream in = null;
-         OutputStream out = null;
+             } while (c.moveToNext());
+         }
+         c.close();
  
+         /// 3. apply updates in batch
          try {
-             in = new FileInputStream(src);
-             out = new FileOutputStream(target);
-             byte[] buf = new byte[1024];
-             int len;
-             while ((len = in.read(buf)) > 0) {
-                 out.write(buf, 0, len);
-             }
-         } catch (IOException ex) {
-             ret = false;
-         } finally {
-             if (in != null) try {
-                 in.close();
-             } catch (IOException e) {
-                 e.printStackTrace(System.err);
-             }
-             if (out != null) try {
-                 out.close();
-             } catch (IOException e) {
-                 e.printStackTrace(System.err);
+             if (getContentResolver() != null) {
+                 getContentResolver().applyBatch(MainApp.getAuthority(), operations);
+             } else {
+                 getContentProviderClient().applyBatch(operations);
              }
-         }
  
-         return ret;
+         } catch (Exception e) {
+             throw e;
+         }
      }
  
 -    private Vector<OCFile> getFolderContent(long parentId/*, boolean onlyOnDevice*/) {
 +    
 +    private Vector<OCFile> getFolderContent(long parentId, boolean onlyOnDevice) {
  
          Vector<OCFile> ret = new Vector<OCFile>();
  
          if (c.moveToFirst()) {
              do {
                  OCFile child = createFileInstance(c);
 -                // TODO Enable when "On Device" is recovered ?
 -                // if (child.isFolder() || !onlyOnDevice || onlyOnDevice && child.isDown()){
 -                ret.add(child);
 -                // }
 +                 if (child.isFolder() || !onlyOnDevice || onlyOnDevice && child.isDown()){
 +                    ret.add(child);
 +                 }
              } while (c.moveToNext());
          }
  
                      + ProviderTableMeta.OCSHARES_ACCOUNT_OWNER + "=?";
              String [] whereArgs = new String[]{ "", mAccount.name };
  
 -            // TODO Enable when "On Device" is recovered ?
 -            Vector<OCFile> files = getFolderContent(folder /*, false*/);
 -
 +            Vector<OCFile> files = getFolderContent(folder, false);
 +            
              for (OCFile file : files) {
                  whereArgs[0] = file.getRemotePath();
                  preparedOperations.add(
          return shares;
      }
  
 -    public void triggerMediaScan(String path) {
 +    public static void triggerMediaScan(String path) {
          Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
          intent.setData(Uri.fromFile(new File(path)));
          MainApp.getAppContext().sendBroadcast(intent);
@@@ -34,8 -34,8 +34,9 @@@ import android.content.pm.PackageInfo
  import android.content.pm.PackageManager.NameNotFoundException;
  import android.content.res.Configuration;
  import android.net.Uri;
 +import android.os.AsyncTask;
  import android.os.Bundle;
+ import android.os.Environment;
  import android.os.Handler;
  import android.os.IBinder;
  import android.preference.CheckBoxPreference;
@@@ -63,7 -63,6 +64,7 @@@ import android.widget.AdapterView.OnIte
  import android.widget.ArrayAdapter;
  import android.widget.ListAdapter;
  import android.widget.ListView;
 +import android.widget.Toast;
  
  import com.owncloud.android.BuildConfig;
  import com.owncloud.android.MainApp;
@@@ -72,22 -71,17 +73,24 @@@ import com.owncloud.android.authenticat
  import com.owncloud.android.authentication.AuthenticatorActivity;
  import com.owncloud.android.datamodel.FileDataStorageManager;
  import com.owncloud.android.datamodel.OCFile;
 +import com.owncloud.android.datamodel.ThumbnailsCacheManager;
  import com.owncloud.android.db.DbHandler;
  import com.owncloud.android.files.FileOperationsHelper;
  import com.owncloud.android.files.services.FileDownloader;
  import com.owncloud.android.files.services.FileUploader;
  import com.owncloud.android.lib.common.utils.Log_OC;
  import com.owncloud.android.services.OperationsService;
+ import com.owncloud.android.ui.PreferenceWithLongSummary;
  import com.owncloud.android.ui.RadioButtonPreference;
  import com.owncloud.android.utils.DisplayUtils;
  
 +import java.io.BufferedReader;
 +import java.io.IOException;
 +import java.io.InputStreamReader;
 +import java.net.MalformedURLException;
 +import java.net.URL;
 +import java.util.concurrent.ExecutionException;
+ import java.io.File;
  
  
  /**
@@@ -103,6 -97,8 +106,8 @@@ public class Preferences extends Prefer
  
      private static final int ACTION_SELECT_UPLOAD_PATH = 1;
      private static final int ACTION_SELECT_UPLOAD_VIDEO_PATH = 2;
+     private static final int ACTION_SELECT_STORAGE_PATH = 3;
+     private static final int ACTION_PERFORM_MIGRATION = 4;
  
      private DbHandler mDbHandler;
      private CheckBoxPreference pCode;
      protected FileDownloader.FileDownloaderBinder mDownloaderBinder = null;
      protected FileUploader.FileUploaderBinder mUploaderBinder = null;
      private ServiceConnection mDownloadServiceConnection, mUploadServiceConnection = null;
+     private PreferenceWithLongSummary mPrefStoragePath;
+     private String mStoragePath;
  
      @SuppressWarnings("deprecation")
      @Override
              
          }
  
 +        final Preference pCacheSize = findPreference("pref_cache_size");
 +        if (pCacheSize != null){
 +            final SharedPreferences appPrefs =
 +                    PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
 +            Long cacheSize = ThumbnailsCacheManager.getMaxSize();
 +            pCacheSize.setSummary(cacheSize + " Mb");
 +            pCacheSize.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
 +                @Override
 +                public boolean onPreferenceChange(Preference preference, Object newValue) {
 +                    Long size = Long.decode((String) newValue);
 +                    if (ThumbnailsCacheManager.setMaxSize(size)){
 +                        appPrefs.edit().putString("pref_cache_size", size.toString());
 +                        pCacheSize.setSummary(size + " MB");
 +                        return true;
 +                    } else {
 +                        return false;
 +                    }
 +                }
 +            });
 +        }
 +
          PreferenceCategory preferenceCategory = (PreferenceCategory) findPreference("more");
          
          boolean helpEnabled = getResources().getBoolean(R.bool.help_enabled);
-         Preference pHelp =  findPreference("help");
+         Preference pHelp = findPreference("help");
          if (pHelp != null ){
              if (helpEnabled) {
                  pHelp.setOnPreferenceClickListener(new OnPreferenceClickListener() {
          }
  
          if (BuildConfig.DEBUG) {
-             Preference pLog =  findPreference("log");
+             Preference pLog = findPreference("log");
              if (pLog != null ){
                  pLog.setOnPreferenceClickListener(new OnPreferenceClickListener() {
                      @Override
                          intent.putExtra(Intent.EXTRA_TEXT, recommendText);
                          startActivity(intent);
  
-                         return(true);
+                         return true;
  
                      }
                  });
                  pFeedback.setOnPreferenceClickListener(new OnPreferenceClickListener() {
                      @Override
                      public boolean onPreferenceClick(Preference preference) {
-                         String feedbackMail   =(String) getText(R.string.mail_feedback);
-                         String feedback   =(String) getText(R.string.prefs_feedback) + " - android v" + appVersion;
-                         Intent intent = new Intent(Intent.ACTION_SENDTO); 
+                         String feedbackMail = (String) getText(R.string.mail_feedback);
+                         String feedback     = String.format("%s - android v%s", getText(R.string.prefs_feedback),  appVersion);
+                         Intent intent       = new Intent(Intent.ACTION_SENDTO);
                          intent.setType("text/plain");
                          intent.putExtra(Intent.EXTRA_SUBJECT, feedback);
                          
              }
          }
  
-         mPrefInstantUploadPath =  findPreference("instant_upload_path");
+         mPrefStoragePath =  (PreferenceWithLongSummary)findPreference("storage_path");
+         if (mPrefStoragePath != null) {
+             mPrefStoragePath.setOnPreferenceClickListener(new OnPreferenceClickListener() {
+                 @Override
+                 public boolean onPreferenceClick(Preference preference) {
+                     Intent intent = new Intent(Preferences.this, LocalDirectorySelectorActivity.class);
+                     intent.putExtra(UploadFilesActivity.KEY_DIRECTORY_PATH, mStoragePath);
+                     startActivityForResult(intent, ACTION_SELECT_STORAGE_PATH);
+                     return true;
+                 }
+             });
+             mPrefStoragePath.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
+                     @Override
+                     public boolean onPreferenceChange(Preference preference, Object newValue) {
+                         MainApp.setStoragePath((String) newValue);
+                         return true;
+                     }
+                 });
+         }
+         mPrefInstantUploadPath = (PreferenceWithLongSummary)findPreference("instant_upload_path");
          if (mPrefInstantUploadPath != null){
  
              mPrefInstantUploadPath.setOnPreferenceClickListener(new OnPreferenceClickListener() {
          mPrefInstantUploadCategory =
                  (PreferenceCategory) findPreference("instant_uploading_category");
          
-         mPrefInstantUploadPathWiFi =  findPreference("instant_upload_on_wifi");
+         mPrefInstantUploadPathWiFi = findPreference("instant_upload_on_wifi");
          mPrefInstantUpload = findPreference("instant_uploading");
          
          toggleInstantPictureOptions(((CheckBoxPreference) mPrefInstantUpload).isChecked());
          });
              
          /* About App */
-        pAboutApp = (Preference) findPreference("about_app");
+        pAboutApp = findPreference("about_app");
         if (pAboutApp != null) { 
 -               pAboutApp.setTitle(String.format(getString(R.string.about_android), getString(R.string.app_name)));
 -               pAboutApp.setSummary(String.format(getString(R.string.about_version), appVersion));
 +               pAboutApp.setTitle(String.format(getString(R.string.about_android),
 +                                                getString(R.string.app_name)));
 +           try {
 +               Integer currentVersion = getPackageManager().getPackageInfo
 +                  (getPackageName(), 0).versionCode;
 +               pAboutApp.setSummary(String.format(getString(R.string.about_version),
 +                                    currentVersion));
 +           } catch (NameNotFoundException e) {
 +           }
         }
  
         loadInstantUploadPath();
+        loadStoragePath();
         loadInstantUploadVideoPath();
  
          /* ComponentsGetter */
                      Context.BIND_AUTO_CREATE);
          }
  
 +        /* Link to Beta apks */
 +        Preference pBetaLink =  findPreference("beta_link");
 +        if (pBetaLink != null ){
 +            pBetaLink.setOnPreferenceClickListener(new OnPreferenceClickListener() {
 +                @Override
 +                public boolean onPreferenceClick(Preference preference) {
 +                    Integer latestVersion = -1;
 +                    Integer currentVersion = -1;
 +                    try {
 +                        currentVersion = getPackageManager().getPackageInfo
 +                                                 (getPackageName(), 0).versionCode;
 +                        LoadingVersionNumberTask loadTask = new LoadingVersionNumberTask();
 +                        loadTask.execute();
 +                        latestVersion = loadTask.get();
 +                    } catch (InterruptedException | ExecutionException e) {
 +                        e.printStackTrace();
 +                    } catch (NameNotFoundException e) {
 +                        e.printStackTrace();
 +                    }
 +                    if (latestVersion == -1 || currentVersion == -1) {
 +                        Toast.makeText(getApplicationContext(), "No information available!",
 +                                       Toast.LENGTH_SHORT).show();
 +                    }
 +                    if (latestVersion > currentVersion) {
 +                        String betaLinkWeb = (String) getText(R.string.beta_link) +
 +                                                              latestVersion + ".apk";
 +                        if (betaLinkWeb != null && betaLinkWeb.length() > 0) {
 +                            Uri uriUrl = Uri.parse(betaLinkWeb);
 +                            Intent intent = new Intent(Intent.ACTION_VIEW, uriUrl);
 +                            startActivity(intent);
 +                            return true;
 +                        }
 +                    } else {
 +                        Toast.makeText(getApplicationContext(), "No new version available!",
 +                                       Toast.LENGTH_SHORT).show();
 +                        return true;
 +                    }
 +                    return true;
 +                }
 +            });
 +        }
 +
 +        /* Link to Beta apks */
 +        Preference pChangelogLink =  findPreference("changelog_link");
 +        if (pChangelogLink != null) {
 +            pChangelogLink.setOnPreferenceClickListener(new OnPreferenceClickListener() {
 +                @Override
 +                public boolean onPreferenceClick(Preference preference) {
 +                    String betaLinkWeb = getString(R.string.changelog);
 +                    if (betaLinkWeb != null && betaLinkWeb.length() > 0) {
 +                        Uri uriUrl = Uri.parse(betaLinkWeb);
 +                        Intent intent = new Intent(Intent.ACTION_VIEW, uriUrl);
 +                        startActivity(intent);
 +                        return true;
 +                    }
 +                    return true;
 +                }
 +            });
 +        }
      }
      
      private void toggleInstantPictureOptions(Boolean value){
              mPrefInstantUploadCategory.addPreference(mPrefInstantUploadPathWiFi);
              mPrefInstantUploadCategory.addPreference(mPrefInstantUploadPath);
          } else {
 -            mPrefInstantUploadCategory.removePreference(mPrefInstantUploadPathWiFi);
 -            mPrefInstantUploadCategory.removePreference(mPrefInstantUploadPath);
 +//            mPrefInstantUploadCategory.removePreference(mPrefInstantUploadPathWiFi);
 +//            mPrefInstantUploadCategory.removePreference(mPrefInstantUploadPath);
          }
      }
      
              mPrefInstantUploadCategory.addPreference(mPrefInstantVideoUploadPathWiFi);
              mPrefInstantUploadCategory.addPreference(mPrefInstantVideoUploadPath);
          } else {
 -            mPrefInstantUploadCategory.removePreference(mPrefInstantVideoUploadPathWiFi);
 -            mPrefInstantUploadCategory.removePreference(mPrefInstantVideoUploadPath);
 +//            mPrefInstantUploadCategory.removePreference(mPrefInstantVideoUploadPathWiFi);
 +//            mPrefInstantUploadCategory.removePreference(mPrefInstantVideoUploadPath);
          }
      }
  
  
          if (requestCode == ACTION_SELECT_UPLOAD_PATH && resultCode == RESULT_OK){
  
-             OCFile folderToUpload =
-                     (OCFile) data.getParcelableExtra(UploadPathActivity.EXTRA_FOLDER);
+             OCFile folderToUpload =  data.getParcelableExtra(UploadPathActivity.EXTRA_FOLDER);
  
              mUploadPath = folderToUpload.getRemotePath();
  
  
              saveInstantUploadPathOnPreferences();
  
-         } else if (requestCode == ACTION_SELECT_UPLOAD_VIDEO_PATH && resultCode == RESULT_OK){
+         } else if (requestCode == ACTION_SELECT_UPLOAD_VIDEO_PATH && resultCode == RESULT_OK) {
  
-             OCFile folderToUploadVideo =
-                     (OCFile) data.getParcelableExtra(UploadPathActivity.EXTRA_FOLDER);
+             OCFile folderToUploadVideo = data.getParcelableExtra(UploadPathActivity.EXTRA_FOLDER);
  
              mUploadVideoPath = folderToUploadVideo.getRemotePath();
  
              mPrefInstantVideoUploadPath.setSummary(mUploadVideoPath);
  
              saveInstantUploadVideoPathOnPreferences();
+         } else if (requestCode == ACTION_SELECT_STORAGE_PATH && resultCode == RESULT_OK) {
+             File currentStorageDir = new File(mStoragePath);
+             File upcomingStorageDir = new File(data.getStringExtra(UploadFilesActivity.EXTRA_CHOSEN_FILES));
+             if (currentStorageDir != upcomingStorageDir) {
+                 Intent migrationIntent = new Intent(this, StorageMigrationActivity.class);
+                 migrationIntent.putExtra(StorageMigrationActivity.KEY_MIGRATION_SOURCE_DIR,
+                         currentStorageDir.getAbsolutePath());
+                 migrationIntent.putExtra(StorageMigrationActivity.KEY_MIGRATION_TARGET_DIR,
+                         upcomingStorageDir.getAbsolutePath());
+                 startActivityForResult(migrationIntent, ACTION_PERFORM_MIGRATION);
+             }
+         } else if (requestCode == ACTION_PERFORM_MIGRATION && resultCode == RESULT_OK) {
+             String resultStorageDir = data.getStringExtra(StorageMigrationActivity.KEY_MIGRATION_TARGET_DIR);
+             saveStoragePath(resultStorageDir);
          }
      }
  
      public void setContentView(View view) {
          getDelegate().setContentView(view);
      }
 +
      @Override
      public void setContentView(View view, ViewGroup.LayoutParams params) {
          getDelegate().setContentView(view, params);
      }
  
      /**
+      * Save storage path
+      */
+     private void saveStoragePath(String newStoragePath) {
+         SharedPreferences appPrefs =
+                 PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
+         mStoragePath = newStoragePath;
+         MainApp.setStoragePath(mStoragePath);
+         SharedPreferences.Editor editor = appPrefs.edit();
+         editor.putString("storage_path", mStoragePath);
+         editor.commit();
+         mPrefStoragePath.setSummary(mStoragePath);
+     }
+     /**
+      * Load storage path set on preferences
+      */
+     private void loadStoragePath() {
+         SharedPreferences appPrefs =
+                 PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
+         mStoragePath = appPrefs.getString("storage_path", Environment.getExternalStorageDirectory()
+                                                          .getAbsolutePath());
+         mPrefStoragePath.setSummary(mStoragePath);
+     }
+     /**
       * Save the "Instant Upload Path" on preferences
       */
      private void saveInstantUploadPathOnPreferences() {
       * Load upload video path set on preferences
       */
      private void loadInstantUploadVideoPath() {
-         SharedPreferences appPrefs =
-                 PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
-         mUploadVideoPath = appPrefs.getString("instant_video_upload_path", getString(R.string.instant_upload_path));
-         mPrefInstantVideoUploadPath.setSummary(mUploadVideoPath);
+         mPrefInstantVideoUploadPath.setSummary(MainApp.getStoragePath());
      }
  
      /**
          editor.commit();
      }
  
-     // Methods for ComponetsGetter
+     // Methods for ComponentsGetter
      @Override
      public FileDownloader.FileDownloaderBinder getFileDownloaderBinder() {
          return mDownloaderBinder;
  
              if (component.equals(new ComponentName(Preferences.this, FileDownloader.class))) {
                  mDownloaderBinder = (FileDownloader.FileDownloaderBinder) service;
              } else if (component.equals(new ComponentName(Preferences.this, FileUploader.class))) {
                  Log_OC.d(TAG, "Upload service connected");
                  mUploaderBinder = (FileUploader.FileUploaderBinder) service;
-             } else {
-                 return;
              }
          }
  
          @Override
              }
          }
      };
 +
 +    /**
 +     *
 +     * Class for loading the version number
 +     *
 +     */
 +    private class LoadingVersionNumberTask extends AsyncTask<Void, Void, Integer> {
 +        protected Integer doInBackground(Void... args) {
 +            try {
 +                URL url = new URL("https://github.com/owncloud/android/raw/beta/apks/latest");
 +                BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream()));
 +
 +                Integer latestVersion = Integer.parseInt(in.readLine());
 +                in.close();
 +
 +                return latestVersion;
 +
 +            } catch (MalformedURLException e) {
 +                e.printStackTrace();
 +            } catch (IOException e) {
 +                e.printStackTrace();
 +            }
 +            return -1;
 +        }
 +    }
  }
  package com.owncloud.android.ui.activity;
  
  import android.accounts.Account;
 +import android.app.AlertDialog;
 +import android.content.DialogInterface;
  import android.content.Intent;
 +import android.content.SharedPreferences;
  import android.os.AsyncTask;
  import android.os.Bundle;
  import android.os.Environment;
 +import android.preference.PreferenceManager;
  import android.support.v4.app.DialogFragment;
  import android.support.v7.app.ActionBar;
 +import android.view.Menu;
 +import android.view.MenuInflater;
  import android.view.MenuItem;
  import android.view.View;
  import android.view.View.OnClickListener;
  import android.view.ViewGroup;
  import android.widget.ArrayAdapter;
  import android.widget.Button;
 +import android.widget.RadioButton;
  import android.widget.TextView;
  
  import com.owncloud.android.R;
 +import com.owncloud.android.files.services.FileUploader;
  import com.owncloud.android.lib.common.utils.Log_OC;
  import com.owncloud.android.ui.dialog.ConfirmationDialogFragment;
  import com.owncloud.android.ui.dialog.ConfirmationDialogFragment.ConfirmationDialogFragmentListener;
@@@ -65,34 -57,33 +65,35 @@@ public class UploadFilesActivity extend
      
      private ArrayAdapter<String> mDirectories;
      private File mCurrentDir = null;
-     private LocalFileListFragment mFileListFragment;
-     private Button mCancelBtn;
-     private Button mUploadBtn;
-     private Account mAccountOnCreation;
-     private DialogFragment mCurrentDialog;
+     protected LocalFileListFragment mFileListFragment;
+     protected Button mCancelBtn;
+     protected Button mUploadBtn;
+     protected Account mAccountOnCreation;
+     protected DialogFragment mCurrentDialog;
      
      public static final String EXTRA_CHOSEN_FILES =
              UploadFilesActivity.class.getCanonicalName() + ".EXTRA_CHOSEN_FILES";
  
      public static final int RESULT_OK_AND_MOVE = RESULT_FIRST_USER; 
      
-     private static final String KEY_DIRECTORY_PATH =
+     public static final String KEY_DIRECTORY_PATH =
              UploadFilesActivity.class.getCanonicalName() + ".KEY_DIRECTORY_PATH";
      private static final String TAG = "UploadFilesActivity";
      private static final String WAIT_DIALOG_TAG = "WAIT";
      private static final String QUERY_TO_MOVE_DIALOG_TAG = "QUERY_TO_MOVE";
 -    
 -    
 +    private RadioButton mRadioBtnCopyFiles;
 +    private RadioButton mRadioBtnMoveFiles;
 +
 +
      @Override
      public void onCreate(Bundle savedInstanceState) {
          Log_OC.d(TAG, "onCreate() start");
          super.onCreate(savedInstanceState);
  
          if(savedInstanceState != null) {
-             mCurrentDir = new File(savedInstanceState.getString(
-                     UploadFilesActivity.KEY_DIRECTORY_PATH));
+             mCurrentDir = new File(savedInstanceState.getString(KEY_DIRECTORY_PATH));
+         } else if (getIntent() != null && getIntent().hasExtra(KEY_DIRECTORY_PATH)) {
+             mCurrentDir = new File(getIntent().getStringExtra(KEY_DIRECTORY_PATH));
          } else {
              mCurrentDir = Environment.getExternalStorageDirectory();
          }
          mCancelBtn.setOnClickListener(this);
          mUploadBtn = (Button) findViewById(R.id.upload_files_btn_upload);
          mUploadBtn.setOnClickListener(this);
 +
 +        SharedPreferences appPreferences = PreferenceManager
 +                .getDefaultSharedPreferences(getApplicationContext());
 +
 +        Integer localBehaviour = appPreferences.getInt("prefs_uploader_behaviour", FileUploader.LOCAL_BEHAVIOUR_COPY);
 +
 +        mRadioBtnMoveFiles = (RadioButton) findViewById(R.id.upload_radio_move);
 +        if (localBehaviour == FileUploader.LOCAL_BEHAVIOUR_MOVE){
 +            mRadioBtnMoveFiles.setChecked(true);
 +        }
 +
 +        mRadioBtnCopyFiles = (RadioButton) findViewById(R.id.upload_radio_copy);
 +        if (localBehaviour == FileUploader.LOCAL_BEHAVIOUR_COPY){
 +            mRadioBtnCopyFiles.setChecked(true);
 +        }
          
              
          // Action bar setup
          Log_OC.d(TAG, "onCreate() end");
      }
  
 +    @Override
 +    public boolean onCreateOptionsMenu(Menu menu) {
 +        MenuInflater inflater = getMenuInflater();
 +        inflater.inflate(R.menu.uploader_menu, menu);
 +        return true;
 +    }
 +
  
      @Override
      public boolean onOptionsItemSelected(MenuItem item) {
                  }
                  break;
              }
 +            case R.id.action_sort: {
 +                SharedPreferences appPreferences = PreferenceManager
 +                        .getDefaultSharedPreferences(this);
 +
 +                // Read sorting order, default to sort by name ascending
 +                Integer sortOrder = appPreferences
 +                        .getInt("sortOrder", FileStorageUtils.SORT_NAME);
 +
 +                AlertDialog.Builder builder = new AlertDialog.Builder(this);
 +                builder.setTitle(R.string.actionbar_sort_title)
 +                        .setSingleChoiceItems(R.array.actionbar_sortby, sortOrder ,
 +                                new DialogInterface.OnClickListener() {
 +                                    public void onClick(DialogInterface dialog, int which) {
 +                                        switch (which){
 +                                            case 0:
 +                                                mFileListFragment.sortByName(true);
 +                                                break;
 +                                            case 1:
 +                                                mFileListFragment.sortByDate(false);
 +                                                break;
 +                                        }
 +
 +                                        dialog.dismiss();
 +                                    }
 +                                });
 +                builder.create().show();
 +                break;
 +            }
              default:
                  retval = super.onOptionsItemSelected(item);
          }
                  // return the list of selected files (success)
                  Intent data = new Intent();
                  data.putExtra(EXTRA_CHOSEN_FILES, mFileListFragment.getCheckedFilePaths());
 -                setResult(RESULT_OK, data);
 +
 +                SharedPreferences.Editor appPreferencesEditor = PreferenceManager
 +                        .getDefaultSharedPreferences(getApplicationContext()).edit();
 +
 +
 +                if (mRadioBtnMoveFiles.isChecked()){
 +                    setResult(RESULT_OK_AND_MOVE, data);
 +                    appPreferencesEditor.putInt("prefs_uploader_behaviour",
 +                            FileUploader.LOCAL_BEHAVIOUR_MOVE);
 +                } else {
 +                    setResult(RESULT_OK, data);
 +                    appPreferencesEditor.putInt("prefs_uploader_behaviour",
 +                            FileUploader.LOCAL_BEHAVIOUR_COPY);
 +                }
 +                appPreferencesEditor.apply();
                  finish();
 -                
              } else {
                  // show a dialog to query the user if wants to move the selected files
                  // to the ownCloud folder instead of copying
  package com.owncloud.android.utils;
  
  import java.io.File;
 +import java.util.ArrayList;
 +import java.util.Arrays;
+ import java.io.FileInputStream;
+ import java.io.FileOutputStream;
+ import java.io.IOException;
+ import java.io.InputStream;
+ import java.io.OutputStream;
  import java.util.Collections;
  import java.util.Comparator;
 +import java.util.List;
  import java.util.Vector;
  
  import third_parties.daveKoeller.AlphanumComparator;
@@@ -41,7 -43,6 +46,6 @@@ import android.content.Context
  import android.content.SharedPreferences;
  import android.preference.PreferenceManager;
  import android.net.Uri;
- import android.os.Environment;
  import android.os.StatFs;
  import android.webkit.MimeTypeMap;
  
@@@ -58,8 -59,9 +62,9 @@@ public class FileStorageUtils 
  
      
      public static final String getSavePath(String accountName) {
-         File sdCard = Environment.getExternalStorageDirectory();
-         return sdCard.getAbsolutePath() + "/" + MainApp.getDataFolder() + "/" + Uri.encode(accountName, "@");
+ //        File sdCard = Environment.getExternalStorageDirectory();
+         return MainApp.getStoragePath() + File.separator + MainApp.getDataFolder() + File.separator + Uri.encode(accountName, "@");
          // URL encoding is an 'easy fix' to overcome that NTFS and FAT32 don't allow ":" in file names, that can be in the accountName since 0.1.190B
      }
  
      }
  
      public static final String getTemporalPath(String accountName) {
-         File sdCard = Environment.getExternalStorageDirectory();
-         return sdCard.getAbsolutePath() + "/" + MainApp.getDataFolder() + "/tmp/" + Uri.encode(accountName, "@");
+         return MainApp.getStoragePath() + File.separator + MainApp.getDataFolder() + File.separator + "tmp" + File.separator + Uri.encode(accountName, "@");
              // URL encoding is an 'easy fix' to overcome that NTFS and FAT32 don't allow ":" in file names, that can be in the accountName since 0.1.190B
      }
  
      @SuppressLint("NewApi")
      public static final long getUsableSpace(String accountName) {
-         File savePath = Environment.getExternalStorageDirectory();
+         File savePath = new File(MainApp.getStoragePath());
          if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.GINGERBREAD) {
              return savePath.getUsableSpace();
  
@@@ -87,7 -88,7 +91,7 @@@
      }
      
      public static final String getLogPath()  {
-         return Environment.getExternalStorageDirectory() + File.separator + MainApp.getDataFolder() + File.separator + "log";
+         return MainApp.getStoragePath() + File.separator + MainApp.getDataFolder() + File.separator + "log";
      }
  
      public static String getInstantUploadFilePath(Context context, String fileName) {
      /**
       * Sorts all filenames, regarding last user decision 
       */
 -    public static Vector<OCFile> sortFolder(Vector<OCFile> files){
 +    public static Vector<OCFile> sortOcFolder(Vector<OCFile> files){
          switch (mSortOrder){
          case 0:
 -            files = FileStorageUtils.sortByName(files);
 +            files = FileStorageUtils.sortOCFilesByName(files);
              break;
          case 1:
 -            files = FileStorageUtils.sortByDate(files);
 +            files = FileStorageUtils.sortOCFilesByDate(files);
              break;
          case 2: 
             // mFiles = FileStorageUtils.sortBySize(mSortAscending);
         
          return files;
      }
 +
 +    /**
 +     * Sorts all filenames, regarding last user decision
 +     */
 +    public static File[] sortLocalFolder(File[] files){
 +        switch (mSortOrder){
 +            case 0:
 +                files = FileStorageUtils.sortLocalFilesByName(files);
 +                break;
 +            case 1:
 +                files = FileStorageUtils.sortLocalFilesByDate(files);
 +                break;
 +            case 2:
 +                // mFiles = FileStorageUtils.sortBySize(mSortAscending);
 +                break;
 +        }
 +
 +        return files;
 +    }
      
      /**
       * Sorts list by Date
       * @param files
       */
 -    public static Vector<OCFile> sortByDate(Vector<OCFile> files){
 +    public static Vector<OCFile> sortOCFilesByDate(Vector<OCFile> files){
          final Integer val;
          if (mSortAscending){
              val = 1;
          return files;
      }
  
 +    /**
 +     * Sorts list by Date
 +     * @param filesArray
 +     */
 +    public static File[] sortLocalFilesByDate(File[] filesArray){
 +        final Integer val;
 +        if (mSortAscending){
 +            val = 1;
 +        } else {
 +            val = -1;
 +        }
 +
 +        List<File> files = new ArrayList<File>(Arrays.asList(filesArray));
 +
 +        Collections.sort(files, new Comparator<File>() {
 +            public int compare(File o1, File o2) {
 +                if (o1.isDirectory() && o2.isDirectory()) {
 +                    Long obj1 = o1.lastModified();
 +                    return val * obj1.compareTo(o2.lastModified());
 +                }
 +                else if (o1.isDirectory()) {
 +                    return -1;
 +                } else if (o2.isDirectory()) {
 +                    return 1;
 +                } else if (o1.lastModified() == 0 || o2.lastModified() == 0){
 +                    return 0;
 +                } else {
 +                    Long obj1 = o1.lastModified();
 +                    return val * obj1.compareTo(o2.lastModified());
 +                }
 +            }
 +        });
 +
 +        File[] returnArray = new File[1];
 +        return files.toArray(returnArray);
 +    }
 +
  //    /**
  //     * Sorts list by Size
  //     * @param sortAscending true: ascending, false: descending
       * Sorts list by Name
       * @param files     files to sort
       */
 -    public static Vector<OCFile> sortByName(Vector<OCFile> files){
 +    public static Vector<OCFile> sortOCFilesByName(Vector<OCFile> files){
          final Integer val;
          if (mSortAscending){
              val = 1;
          
          return files;
      }
 +
 +    /**
 +     * Sorts list by Name
 +     * @param filesArray    files to sort
 +     */
 +    public static File[] sortLocalFilesByName(File[] filesArray){
 +        final Integer val;
 +        if (mSortAscending){
 +            val = 1;
 +        } else {
 +            val = -1;
 +        }
 +
 +        List<File> files = new ArrayList<File>(Arrays.asList(filesArray));
 +
 +        Collections.sort(files, new Comparator<File>() {
 +            public int compare(File o1, File o2) {
 +                if (o1.isDirectory() && o2.isDirectory()) {
 +                    return val * o1.getPath().toLowerCase().compareTo(o2.getPath().toLowerCase());
 +                } else if (o1.isDirectory()) {
 +                    return -1;
 +                } else if (o2.isDirectory()) {
 +                    return 1;
 +                }
 +                return val * new AlphanumComparator().compare(o1.getPath().toLowerCase(),
 +                                                              o2.getPath().toLowerCase());
 +            }
 +        });
 +
 +        File[] returnArray = new File[1];
 +        return files.toArray(returnArray);
 +    }
      
      /**
       * Local Folder size
      public static long getFolderSize(File dir) {
          if (dir.exists()) {
              long result = 0;
-             File[] fileList = dir.listFiles();
-             for(int i = 0; i < fileList.length; i++) {
-                 if(fileList[i].isDirectory()) {
-                     result += getFolderSize(fileList[i]);
-                 } else {
-                     result += fileList[i].length();
-                 }
+             for (File f : dir.listFiles()) {
+                 if (f.isDirectory())
+                     result += getFolderSize(f);
+                 else
+                     result += f.length();
              }
              return result;
          }
          }
      }
  
+     public static boolean copyFile(File src, File target) {
+         boolean ret = true;
+         InputStream in = null;
+         OutputStream out = null;
+         try {
+             in = new FileInputStream(src);
+             out = new FileOutputStream(target);
+             byte[] buf = new byte[1024];
+             int len;
+             while ((len = in.read(buf)) > 0) {
+                 out.write(buf, 0, len);
+             }
+         } catch (IOException ex) {
+             ret = false;
+         } finally {
+             if (in != null) try {
+                 in.close();
+             } catch (IOException e) {
+                 e.printStackTrace(System.err);
+             }
+             if (out != null) try {
+                 out.close();
+             } catch (IOException e) {
+                 e.printStackTrace(System.err);
+             }
+         }
+         return ret;
+     }
  }