Эх сурвалжийг харах

Merge branch 'master' of https://github.com/nextcloud/android into userTheming

# Conflicts:
#	scripts/lint/lint-results.txt
#	src/main/java/com/owncloud/android/ui/activity/ActivitiesListActivity.java
#	src/main/java/com/owncloud/android/ui/activity/FolderSyncActivity.java
#	src/main/java/com/owncloud/android/ui/fragment/contactsbackup/ContactsBackupFragment.java
AndyScherzinger 7 жил өмнө
parent
commit
c88d9205a2
34 өөрчлөгдсөн 407 нэмэгдсэн , 154 устгасан
  1. 5 5
      .drone.yml
  2. 0 0
      .drone.yml.sig
  3. 2 1
      src/main/AndroidManifest.xml
  4. 1 0
      src/main/java/com/owncloud/android/authentication/AuthenticatorActivity.java
  5. 43 6
      src/main/java/com/owncloud/android/datamodel/MediaProvider.java
  6. 26 9
      src/main/java/com/owncloud/android/datamodel/ThumbnailsCacheManager.java
  7. 7 5
      src/main/java/com/owncloud/android/files/InstantUploadBroadcastReceiver.java
  8. 95 23
      src/main/java/com/owncloud/android/ui/activity/ActivitiesListActivity.java
  9. 11 0
      src/main/java/com/owncloud/android/ui/activity/ContactsPreferenceActivity.java
  10. 3 1
      src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java
  11. 15 5
      src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java
  12. 1 0
      src/main/java/com/owncloud/android/ui/activity/FolderPickerActivity.java
  13. 39 11
      src/main/java/com/owncloud/android/ui/activity/FolderSyncActivity.java
  14. 10 5
      src/main/java/com/owncloud/android/ui/activity/LogHistoryActivity.java
  15. 1 0
      src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java
  16. 1 0
      src/main/java/com/owncloud/android/ui/activity/ManageSpaceActivity.java
  17. 3 1
      src/main/java/com/owncloud/android/ui/activity/ParticipateActivity.java
  18. 31 15
      src/main/java/com/owncloud/android/ui/activity/Preferences.java
  19. 1 0
      src/main/java/com/owncloud/android/ui/activity/ReceiveExternalFilesActivity.java
  20. 1 1
      src/main/java/com/owncloud/android/ui/activity/UploadFilesActivity.java
  21. 17 4
      src/main/java/com/owncloud/android/ui/adapter/ActivityListAdapter.java
  22. 20 3
      src/main/java/com/owncloud/android/ui/adapter/FileListListAdapter.java
  23. 1 0
      src/main/java/com/owncloud/android/ui/asynctasks/CopyAndUploadContentUrisTask.java
  24. 1 0
      src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java
  25. 8 0
      src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java
  26. 24 12
      src/main/java/com/owncloud/android/ui/fragment/contactsbackup/ContactsBackupFragment.java
  27. 1 0
      src/main/java/com/owncloud/android/ui/preview/FileDownloadFragment.java
  28. 1 0
      src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java
  29. 7 4
      src/main/java/com/owncloud/android/ui/preview/PreviewImageFragment.java
  30. 22 37
      src/main/res/layout/contacts_backup_fragment.xml
  31. 1 0
      src/main/res/layout/folder_sync_layout.xml
  32. 1 0
      src/main/res/values/setup.xml
  33. 3 6
      src/main/res/values/strings.xml
  34. 4 0
      src/main/res/xml/preferences.xml

+ 5 - 5
.drone.yml

@@ -5,9 +5,9 @@ pipeline:
       # uncomment gplay for Gplay, Modified only
       - sh -c "if [ '$FLAVOUR' != 'Generic' ]; then sed -i '/com.google.*.gms/s/^.*\/\///g' build.gradle; fi"
 
-      - echo no | android create avd --force -n test -t $ANDROID_TARGET --abi $ANDROID_ABI -c 20M
-      - emulator -avd test -no-window &
-      - ./wait_for_emulator.sh
+      # - echo no | android create avd --force -n test -t $ANDROID_TARGET --abi $ANDROID_ABI -c 20M
+      # - emulator -avd test -no-window &
+      # - ./wait_for_emulator.sh
 
       # build app and assemble APK, in debug mode
       - ./gradlew assemble${FLAVOUR}
@@ -16,8 +16,8 @@ pipeline:
       # - ./gradlew connectedDebugAndroidTest --info
 
       # install app, then assemble and install instrumented tests of app module
-      - ./gradlew :install${FLAVOUR}Debug
-      - ./gradlew :install${FLAVOUR}DebugAndroidTest
+      # - ./gradlew :install${FLAVOUR}Debug
+      # - ./gradlew :install${FLAVOUR}DebugAndroidTest
 
       # run sample instrumented unit test
       # TODO fails because test runner is not available

Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 0 - 0
.drone.yml.sig


+ 2 - 1
src/main/AndroidManifest.xml

@@ -83,7 +83,8 @@
         <activity android:name=".ui.activity.UserInfoActivity" />
         <activity android:name=".ui.activity.NotificationsActivity"/>
         <activity android:name=".ui.activity.ParticipateActivity" />
-        <activity android:name=".ui.activity.ActivitiesListActivity"/>
+        <activity android:name=".ui.activity.ActivitiesListActivity"
+                  android:configChanges="orientation|screenSize|keyboardHidden" />
         <activity android:name=".ui.activity.FolderSyncActivity" />
         <activity android:name=".ui.activity.UploadFilesActivity" />
         <activity android:name=".ui.activity.ExternalSiteWebView"

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

@@ -1460,6 +1460,7 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
             default:
                 mServerStatusText = 0;
                 mServerStatusIcon = 0;
+                break;
         }
     }
 

+ 43 - 6
src/main/java/com/owncloud/android/datamodel/MediaProvider.java

@@ -1,33 +1,40 @@
-/**
+/*
  * Nextcloud Android client application
  *
  * @author Andy Scherzinger
  * Copyright (C) 2016 Andy Scherzinger
  * Copyright (C) 2016 Nextcloud
- * <p>
+ *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
  * License as published by the Free Software Foundation; either
  * version 3 of the License, or any later version.
- * <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 AFFERO GENERAL PUBLIC LICENSE for more details.
- * <p>
+ *
  * You should have received a copy of the GNU Affero General Public
  * License along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
 package com.owncloud.android.datamodel;
 
+import android.Manifest;
+import android.app.Activity;
 import android.content.ContentResolver;
 import android.database.Cursor;
 import android.net.Uri;
 import android.provider.MediaStore;
+import android.support.design.widget.Snackbar;
 import android.util.Log;
+import android.view.View;
 
 import com.owncloud.android.MainApp;
+import com.owncloud.android.R;
+import com.owncloud.android.utils.DisplayUtils;
+import com.owncloud.android.utils.PermissionUtil;
 
 import java.io.File;
 import java.util.ArrayList;
@@ -54,9 +61,39 @@ public class MediaProvider {
      * @param itemLimit       the number of media items (usually images) to be returned per media folder.
      * @return list with media folders
      */
-    public static List<MediaFolder> getMediaFolders(ContentResolver contentResolver, int itemLimit) {
+    public static List<MediaFolder> getMediaFolders(ContentResolver contentResolver, int itemLimit,
+                                                    final Activity activity) {
+        // check permissions
+        if (!PermissionUtil.checkSelfPermission(activity.getApplicationContext(),
+                Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
+            // Check if we should show an explanation
+            if (PermissionUtil.shouldShowRequestPermissionRationale(activity,
+                    Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
+                // Show explanation to the user and then request permission
+                Snackbar snackbar = Snackbar.make(activity.findViewById(R.id.ListLayout),
+                        R.string.permission_storage_access, Snackbar.LENGTH_INDEFINITE)
+                        .setAction(R.string.common_ok, new View.OnClickListener() {
+                            @Override
+                            public void onClick(View v) {
+                                PermissionUtil.requestWriteExternalStoreagePermission(activity);
+                            }
+                        });
+
+                DisplayUtils.colorSnackbar(activity.getApplicationContext(), snackbar);
+
+                snackbar.show();
+            } else {
+                // No explanation needed, request the permission.
+                PermissionUtil.requestWriteExternalStoreagePermission(activity);
+            }
+        }
+
         // query media/image folders
-        Cursor cursorFolders = contentResolver.query(MEDIA_URI, FOLDER_PROJECTION, null, null, FOLDER_SORT_ORDER);
+        Cursor cursorFolders = null;
+        if (PermissionUtil.checkSelfPermission(activity.getApplicationContext(),
+                Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
+            cursorFolders = contentResolver.query(MEDIA_URI, FOLDER_PROJECTION, null, null, FOLDER_SORT_ORDER);
+        }
         List<MediaFolder> mediaFolders = new ArrayList<>();
         String dataPath = MainApp.getStoragePath() + File.separator + MainApp.getDataFolder();
 

+ 26 - 9
src/main/java/com/owncloud/android/datamodel/ThumbnailsCacheManager.java

@@ -56,6 +56,7 @@ import org.apache.commons.httpclient.methods.GetMethod;
 import java.io.File;
 import java.io.InputStream;
 import java.lang.ref.WeakReference;
+import java.util.ArrayList;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 
@@ -183,13 +184,20 @@ public class ThumbnailsCacheManager {
     public static class ThumbnailGenerationTask extends AsyncTask<Object, Void, Bitmap> {
         private final WeakReference<ImageView> mImageViewReference;
         private static Account mAccount;
+        private ArrayList<ThumbnailGenerationTask> mAsyncTasks = null;
         private Object mFile;
         private String mImageKey = null;
         private FileDataStorageManager mStorageManager;
+        private GetMethod getMethod;
 
+        public ThumbnailGenerationTask(ImageView imageView, FileDataStorageManager storageManager, Account account)
+                throws IllegalArgumentException {
+            this(imageView, storageManager, account, null);
+        }
 
         public ThumbnailGenerationTask(ImageView imageView, FileDataStorageManager storageManager,
-                                       Account account) throws IllegalArgumentException {
+                                       Account account, ArrayList<ThumbnailGenerationTask> asyncTasks)
+                throws IllegalArgumentException {
             // Use a WeakReference to ensure the ImageView can be garbage collected
             mImageViewReference = new WeakReference<ImageView>(imageView);
             if (storageManager == null) {
@@ -197,6 +205,11 @@ public class ThumbnailsCacheManager {
             }
             mStorageManager = storageManager;
             mAccount = account;
+            mAsyncTasks = asyncTasks;
+        }
+
+        public GetMethod getGetMethod() {
+            return getMethod;
         }
 
         public ThumbnailGenerationTask(FileDataStorageManager storageManager, Account account){
@@ -277,6 +290,10 @@ public class ThumbnailsCacheManager {
                     }
                 }
             }
+
+            if (mAsyncTasks != null) {
+                mAsyncTasks.remove(this);
+            }
         }
 
         /**
@@ -325,18 +342,18 @@ public class ThumbnailsCacheManager {
                     OwnCloudVersion serverOCVersion = AccountUtils.getServerVersion(mAccount);
                     if (mClient != null && serverOCVersion != null) {
                         if (serverOCVersion.supportsRemoteThumbnails()) {
-                            GetMethod get = null;
+                            getMethod = null;
                             try {
                                 String uri = mClient.getBaseUri() + "" +
                                         "/index.php/apps/files/api/v1/thumbnail/" +
                                         px + "/" + px + Uri.encode(file.getRemotePath(), "/");
                                 Log_OC.d("Thumbnail", "URI: " + uri);
-                                get = new GetMethod(uri);
-                                get.setRequestHeader("Cookie",
+                                getMethod = new GetMethod(uri);
+                                getMethod.setRequestHeader("Cookie",
                                         "nc_sameSiteCookielax=true;nc_sameSiteCookiestrict=true");
-                                int status = mClient.executeMethod(get);
+                                int status = mClient.executeMethod(getMethod);
                                 if (status == HttpStatus.SC_OK) {
-                                    InputStream inputStream = get.getResponseBodyAsStream();
+                                    InputStream inputStream = getMethod.getResponseBodyAsStream();
                                     Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
                                     thumbnail = ThumbnailUtils.extractThumbnail(bitmap, px, px);
 
@@ -350,13 +367,13 @@ public class ThumbnailsCacheManager {
                                         addBitmapToCache(imageKey, thumbnail);
                                     }
                                 } else {
-                                    mClient.exhaustResponse(get.getResponseBodyAsStream());
+                                    mClient.exhaustResponse(getMethod.getResponseBodyAsStream());
                                 }
                             } catch (Exception e) {
                                 Log_OC.d(TAG, e.getMessage(), e);
                             } finally {
-                                if (get != null) {
-                                    get.releaseConnection();
+                                if (getMethod != null) {
+                                    getMethod.releaseConnection();
                                 }
                             }
                         } else {

+ 7 - 5
src/main/java/com/owncloud/android/files/InstantUploadBroadcastReceiver.java

@@ -105,12 +105,14 @@ public class InstantUploadBroadcastReceiver extends BroadcastReceiver {
         String[] CONTENT_PROJECTION = {
                 Images.Media.DATA, Images.Media.DISPLAY_NAME, Images.Media.MIME_TYPE, Images.Media.SIZE};
 
-        int permissionCheck = ContextCompat.checkSelfPermission(context,
-                Manifest.permission.READ_EXTERNAL_STORAGE);
+        // if < Jelly Bean permission must be accepted during installation
+        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN) {
+            int permissionCheck = ContextCompat.checkSelfPermission(context, Manifest.permission.READ_EXTERNAL_STORAGE);
 
-        if (android.content.pm.PackageManager.PERMISSION_GRANTED != permissionCheck) {
-            Log_OC.w(TAG, "Read external storage permission isn't granted, aborting");
-            return;
+            if (android.content.pm.PackageManager.PERMISSION_GRANTED != permissionCheck) {
+                Log_OC.w(TAG, "Read external storage permission isn't granted, aborting");
+                return;
+            }
         }
 
         c = context.getContentResolver().query(intent.getData(), CONTENT_PROJECTION, null, null, null);

+ 95 - 23
src/main/java/com/owncloud/android/ui/activity/ActivitiesListActivity.java

@@ -1,4 +1,4 @@
-/**
+/*
  * Nextcloud Android client application
  *
  * @author Andy Scherzinger
@@ -26,6 +26,7 @@ import android.accounts.AuthenticatorException;
 import android.accounts.OperationCanceledException;
 import android.content.Context;
 import android.content.Intent;
+import android.os.AsyncTask;
 import android.graphics.PorterDuff;
 import android.os.Bundle;
 import android.support.design.widget.BottomNavigationView;
@@ -38,10 +39,12 @@ import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.widget.ProgressBar;
 import android.widget.TextView;
+import android.widget.Toast;
 
 import com.owncloud.android.MainApp;
 import com.owncloud.android.R;
 import com.owncloud.android.authentication.AccountUtils;
+import com.owncloud.android.datamodel.FileDataStorageManager;
 import com.owncloud.android.datamodel.OCFile;
 import com.owncloud.android.lib.common.OwnCloudAccount;
 import com.owncloud.android.lib.common.OwnCloudClient;
@@ -52,12 +55,16 @@ import com.owncloud.android.lib.common.utils.Log_OC;
 import com.owncloud.android.lib.resources.activities.GetRemoteActivitiesOperation;
 import com.owncloud.android.lib.resources.activities.models.RichObject;
 import com.owncloud.android.lib.resources.files.FileUtils;
+import com.owncloud.android.lib.resources.files.ReadRemoteFileOperation;
+import com.owncloud.android.lib.resources.files.RemoteFile;
+import com.owncloud.android.operations.RefreshFolderOperation;
 import com.owncloud.android.ui.adapter.ActivityListAdapter;
 import com.owncloud.android.ui.interfaces.ActivityListInterface;
 import com.owncloud.android.ui.preview.PreviewImageActivity;
 import com.owncloud.android.ui.preview.PreviewImageFragment;
 import com.owncloud.android.utils.AnalyticsUtils;
 import com.owncloud.android.utils.DisplayUtils;
+import com.owncloud.android.utils.FileStorageUtils;
 import com.owncloud.android.utils.ThemeUtils;
 
 import java.io.IOException;
@@ -107,6 +114,8 @@ public class ActivitiesListActivity extends FileActivity implements ActivityList
 
     private ActivityListAdapter adapter;
     private Unbinder unbinder;
+    private OwnCloudClient ownCloudClient;
+    private AsyncTask<String, Object, OCFile> updateTask;
 
 
     @Override
@@ -142,8 +151,6 @@ public class ActivitiesListActivity extends FileActivity implements ActivityList
                 fetchAndSetData();
             }
         });
-
-        setupContent();
     }
 
     public void onDestroy() {
@@ -168,7 +175,8 @@ public class ActivitiesListActivity extends FileActivity implements ActivityList
                 PorterDuff.Mode.SRC_IN);
         setLoadingMessage();
 
-        adapter = new ActivityListAdapter(this, this);
+        FileDataStorageManager storageManager = new FileDataStorageManager(getAccount(), getContentResolver());
+        adapter = new ActivityListAdapter(this, this, storageManager);
         recyclerView.setAdapter(adapter);
 
         LinearLayoutManager layoutManager = new LinearLayoutManager(this);
@@ -193,19 +201,16 @@ public class ActivitiesListActivity extends FileActivity implements ActivityList
 
 
             public void run() {
-                OwnCloudAccount ocAccount = null;
+                OwnCloudAccount ocAccount;
                 try {
-                    ocAccount = new OwnCloudAccount(
-                            currentAccount,
-                            context
-                    );
-                    final OwnCloudClient mClient = OwnCloudClientManagerFactory.getDefaultSingleton().
+                    ocAccount = new OwnCloudAccount(currentAccount, context);
+                    ownCloudClient = OwnCloudClientManagerFactory.getDefaultSingleton().
                             getClientFor(ocAccount, MainApp.getAppContext());
-                    mClient.setOwnCloudVersion(AccountUtils.getServerVersion(currentAccount));
+                    ownCloudClient.setOwnCloudVersion(AccountUtils.getServerVersion(currentAccount));
 
                     RemoteOperation getRemoteNotificationOperation = new GetRemoteActivitiesOperation();
                     Log_OC.d(TAG, "BEFORE getRemoteActivitiesOperation.execute");
-                    final RemoteOperationResult result = getRemoteNotificationOperation.execute(mClient);
+                    final RemoteOperationResult result = getRemoteNotificationOperation.execute(ownCloudClient);
 
                     if (result.isSuccess() && result.getData() != null) {
                         final ArrayList<Object> activities = result.getData();
@@ -214,7 +219,7 @@ public class ActivitiesListActivity extends FileActivity implements ActivityList
                             @Override
                             public void run() {
                                 if (activities.size() > 0) {
-                                    populateList(activities, mClient);
+                                    populateList(activities, ownCloudClient);
                                     swipeEmptyListRefreshLayout.setVisibility(View.GONE);
                                     swipeListRefreshLayout.setVisibility(View.VISIBLE);
                                 } else {
@@ -312,21 +317,88 @@ public class ActivitiesListActivity extends FileActivity implements ActivityList
     protected void onResume() {
         super.onResume();
 
+        setupContent();
+
         AnalyticsUtils.setCurrentScreenName(this, SCREEN_NAME, TAG);
     }
 
+    @Override
+    protected void onStop() {
+        if (updateTask != null) {
+            updateTask.cancel(true);
+        }
+
+        super.onStop();
+    }
 
     @Override
     public void onActivityClicked(RichObject richObject) {
-        Intent showDetailsIntent;
-        OCFile ocFile = new OCFile(FileUtils.PATH_SEPARATOR + richObject.getPath());
-        if (PreviewImageFragment.canBePreviewed(ocFile)) {
-            showDetailsIntent = new Intent(this, PreviewImageActivity.class);
-        } else {
-            showDetailsIntent = new Intent(this, FileDisplayActivity.class);
-        }
-        showDetailsIntent.putExtra(EXTRA_FILE, ocFile);
-        showDetailsIntent.putExtra(EXTRA_ACCOUNT, getAccount());
-        startActivity(showDetailsIntent);
+        String path = FileUtils.PATH_SEPARATOR + richObject.getPath();
+
+        runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                swipeEmptyListRefreshLayout.setVisibility(View.VISIBLE);
+                swipeListRefreshLayout.setVisibility(View.GONE);
+                setLoadingMessage();
+            }
+        });
+
+        updateTask = new AsyncTask<String, Object, OCFile>() {
+            @Override
+            protected OCFile doInBackground(String... path) {
+                OCFile ocFile = null;
+
+                // always update file as it could be an old state saved in database
+                ReadRemoteFileOperation operation = new ReadRemoteFileOperation(path[0]);
+                RemoteOperationResult resultRemoteFileOp = operation.execute(ownCloudClient);
+                if (resultRemoteFileOp.isSuccess()) {
+                    OCFile temp = FileStorageUtils.fillOCFile((RemoteFile) resultRemoteFileOp.getData().get(0));
+
+                    ocFile = getStorageManager().saveFileWithParent(temp, getBaseContext());
+
+                    if (ocFile.isFolder()) {
+                        // perform folder synchronization
+                        RemoteOperation synchFolderOp = new RefreshFolderOperation(ocFile,
+                                System.currentTimeMillis(),
+                                false,
+                                getFileOperationsHelper().isSharedSupported(),
+                                true,
+                                getStorageManager(),
+                                getAccount(),
+                                getApplicationContext());
+                        synchFolderOp.execute(ownCloudClient);
+                    }
+                }
+
+                return ocFile;
+            }
+
+            @Override
+            protected void onPostExecute(OCFile ocFile) {
+                if (!isCancelled()) {
+                    if (ocFile == null) {
+                        Toast.makeText(getBaseContext(), R.string.file_not_found, Toast.LENGTH_LONG).show();
+
+                        swipeEmptyListRefreshLayout.setVisibility(View.GONE);
+                        swipeListRefreshLayout.setVisibility(View.VISIBLE);
+                        dismissLoadingDialog();
+
+                    } else {
+                        Intent showDetailsIntent;
+                        if (PreviewImageFragment.canBePreviewed(ocFile)) {
+                            showDetailsIntent = new Intent(getBaseContext(), PreviewImageActivity.class);
+                        } else {
+                            showDetailsIntent = new Intent(getBaseContext(), FileDisplayActivity.class);
+                        }
+                        showDetailsIntent.putExtra(EXTRA_FILE, ocFile);
+                        showDetailsIntent.putExtra(EXTRA_ACCOUNT, getAccount());
+                        startActivity(showDetailsIntent);
+                    }
+                }
+            }
+        };
+
+        updateTask.execute(path);
     }
 }

+ 11 - 0
src/main/java/com/owncloud/android/ui/activity/ContactsPreferenceActivity.java

@@ -28,6 +28,7 @@ import android.os.Bundle;
 import android.support.design.widget.BottomNavigationView;
 import android.support.v4.app.FragmentManager;
 import android.support.v4.app.FragmentTransaction;
+import android.support.v4.widget.DrawerLayout;
 import android.view.View;
 
 import com.evernote.android.job.JobManager;
@@ -56,6 +57,7 @@ public class ContactsPreferenceActivity extends FileActivity implements FileFrag
     public static final String PREFERENCE_CONTACTS_AUTOMATIC_BACKUP = "PREFERENCE_CONTACTS_AUTOMATIC_BACKUP";
     public static final String PREFERENCE_CONTACTS_LAST_BACKUP = "PREFERENCE_CONTACTS_LAST_BACKUP";
     public static final String BACKUP_TO_LIST = "BACKUP_TO_LIST";
+    public static final String EXTRA_SHOW_SIDEBAR = "SHOW_SIDEBAR";
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
@@ -69,6 +71,14 @@ public class ContactsPreferenceActivity extends FileActivity implements FileFrag
         // setup drawer
         setupDrawer(R.id.nav_contacts);
 
+        // show sidebar?
+        boolean showSidebar = getIntent().getBooleanExtra(EXTRA_SHOW_SIDEBAR, true);
+        if (!showSidebar) {
+            setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
+            getSupportActionBar().setDisplayHomeAsUpEnabled(true);
+            mDrawerToggle.setDrawerIndicatorEnabled(false);
+        }
+
         Intent intent = getIntent();
         if (savedInstanceState == null) {
             FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
@@ -77,6 +87,7 @@ public class ContactsPreferenceActivity extends FileActivity implements FileFrag
                 ContactsBackupFragment fragment = new ContactsBackupFragment();
                 Bundle bundle = new Bundle();
                 bundle.putParcelable(ContactListFragment.ACCOUNT, getAccount());
+                bundle.putBoolean(EXTRA_SHOW_SIDEBAR, showSidebar);
                 fragment.setArguments(bundle);
                 transaction.add(R.id.frame_container, fragment);
             } else {

+ 3 - 1
src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java

@@ -357,7 +357,8 @@ public abstract class DrawerActivity extends ToolbarActivity implements DisplayU
             navigationView.getMenu().removeItem(R.id.nav_shared);
         }
 
-        if (!getResources().getBoolean(R.bool.contacts_backup)) {
+        if (!getResources().getBoolean(R.bool.contacts_backup)
+                || !getResources().getBoolean(R.bool.show_drawer_contacts_backup)) {
             navigationView.getMenu().removeItem(R.id.nav_contacts);
         }
 
@@ -500,6 +501,7 @@ public abstract class DrawerActivity extends ToolbarActivity implements DisplayU
                 break;
             default:
                 Log_OC.i(TAG, "Unknown drawer menu item clicked: " + menuItem.getTitle());
+                break;
         }
     }
 

+ 15 - 5
src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java

@@ -1,4 +1,4 @@
-/**
+/*
  * ownCloud Android client application
  *
  * @author Bartek Przybylski
@@ -788,6 +788,7 @@ public class FileDisplayActivity extends HookActivity
             }
             default:
                 retval = super.onOptionsItemSelected(item);
+                break;
         }
         return retval;
     }
@@ -1074,14 +1075,23 @@ public class FileDisplayActivity extends HookActivity
         Log_OC.v(TAG, "onResume() start");
         super.onResume();
 
+        OCFile startFile = null;
+        if (getIntent() != null && getIntent().getParcelableExtra(EXTRA_FILE) != null) {
+            startFile = getIntent().getParcelableExtra(EXTRA_FILE);
+            setFile(startFile);
+        }
 
         revertBottomNavigationBarToAllFiles();
         // refresh list of files
 
         if (searchView != null && !TextUtils.isEmpty(searchQuery)) {
             searchView.setQuery(searchQuery, true);
-        } else if (getListOfFilesFragment() != null && !getListOfFilesFragment().getIsSearchFragment()) {
+        } else if (getListOfFilesFragment() != null && !getListOfFilesFragment().getIsSearchFragment()
+                && startFile == null) {
             refreshListOfFilesFragment(false);
+        } else {
+            getListOfFilesFragment().listDirectory(startFile, false, false);
+            updateActionBarTitleAndHomeButton(startFile);
         }
 
         // Listen for sync messages
@@ -1223,8 +1233,7 @@ public class FileDisplayActivity extends HookActivity
                             if (currentDir.getRemotePath().equals(synchFolderRemotePath)) {
                                 OCFileListFragment fileListFragment = getListOfFilesFragment();
                                 if (fileListFragment != null) {
-                                    fileListFragment.listDirectory(currentDir,
-                                            MainApp.isOnlyOnDevice(), false);
+                                    fileListFragment.listDirectory(currentDir, MainApp.isOnlyOnDevice(), false);
                                 }
                             }
                             setFile(currentFile);
@@ -1563,7 +1572,8 @@ public class FileDisplayActivity extends HookActivity
             // a new chance to get the mDownloadBinder through
             // getFileDownloadBinder() - THIS IS A MESS
             OCFileListFragment listOfFiles = getListOfFilesFragment();
-            if (listOfFiles != null) {
+            if (listOfFiles != null && (getIntent() == null ||
+                    (getIntent() != null && getIntent().getParcelableExtra(EXTRA_FILE) == null))) {
                 listOfFiles.listDirectory(MainApp.isOnlyOnDevice(), false);
             }
             FileFragment secondFragment = getSecondFragment();

+ 1 - 0
src/main/java/com/owncloud/android/ui/activity/FolderPickerActivity.java

@@ -300,6 +300,7 @@ public class FolderPickerActivity extends FileActivity implements FileFragment.C
         }
         default:
             retval = super.onOptionsItemSelected(item);
+            break;
         }
         return retval;
     }

+ 39 - 11
src/main/java/com/owncloud/android/ui/activity/FolderSyncActivity.java

@@ -1,20 +1,20 @@
-/**
+/*
  * Nextcloud Android client application
  *
  * @author Andy Scherzinger
  * Copyright (C) 2016 Andy Scherzinger
  * Copyright (C) 2016 Nextcloud
- * <p>
+ *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
  * License as published by the Free Software Foundation; either
  * version 3 of the License, or any later version.
- * <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 AFFERO GENERAL PUBLIC LICENSE for more details.
- * <p>
+ *
  * You should have received a copy of the GNU Affero General Public
  * License along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
@@ -23,6 +23,7 @@ package com.owncloud.android.ui.activity;
 
 import android.accounts.Account;
 import android.content.Intent;
+import android.content.pm.PackageManager;
 import android.os.Bundle;
 import android.os.Handler;
 import android.support.annotation.NonNull;
@@ -30,6 +31,7 @@ import android.support.design.widget.BottomNavigationView;
 import android.support.v4.app.FragmentManager;
 import android.support.v4.app.FragmentTransaction;
 import android.support.v4.widget.DrawerLayout;
+import android.support.v7.app.ActionBar;
 import android.support.v7.widget.GridLayoutManager;
 import android.support.v7.widget.RecyclerView;
 import android.view.MenuItem;
@@ -54,6 +56,7 @@ import com.owncloud.android.ui.dialog.parcel.SyncedFolderParcelable;
 import com.owncloud.android.utils.AnalyticsUtils;
 import com.owncloud.android.utils.DisplayUtils;
 import com.owncloud.android.utils.ThemeUtils;
+import com.owncloud.android.utils.PermissionUtil;
 
 import java.io.File;
 import java.util.ArrayList;
@@ -112,8 +115,11 @@ public class FolderSyncActivity extends FileActivity implements FolderSyncAdapte
 
         setupContent();
 
-        ThemeUtils.setColoredTitle(getSupportActionBar(), getString(R.string.drawer_folder_sync));
-        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
+        ActionBar actionBar = getSupportActionBar();
+        if (actionBar != null) {
+            ThemeUtils.setColoredTitle(getSupportActionBar(), getString(R.string.drawer_folder_sync));
+            actionBar.setDisplayHomeAsUpEnabled(true);
+        }
     }
 
     @Override
@@ -150,7 +156,7 @@ public class FolderSyncActivity extends FileActivity implements FolderSyncAdapte
             DisplayUtils.setupBottomBar(bottomNavigationView, getResources(), this, -1);
         }
 
-        load(gridWidth * 2);
+        load(gridWidth * 2, false);
     }
 
     /**
@@ -158,8 +164,8 @@ public class FolderSyncActivity extends FileActivity implements FolderSyncAdapte
      *
      * @param perFolderMediaItemLimit the amount of media items to be loaded/shown per media folder
      */
-    private void load(final int perFolderMediaItemLimit) {
-        if (mAdapter.getItemCount() > 0) {
+    private void load(final int perFolderMediaItemLimit, boolean force) {
+        if (mAdapter.getItemCount() > 0 && !force) {
             return;
         }
         setListShown(false);
@@ -168,9 +174,9 @@ public class FolderSyncActivity extends FileActivity implements FolderSyncAdapte
             @Override
             public void run() {
                 final List<MediaFolder> mediaFolders = MediaProvider.getMediaFolders(getContentResolver(),
-                        perFolderMediaItemLimit);
+                        perFolderMediaItemLimit, FolderSyncActivity.this);
                 List<SyncedFolder> syncedFolderArrayList = mSyncedFolderProvider.getSyncedFolders();
-                List<SyncedFolder> currentAccountSyncedFoldersList = new ArrayList<SyncedFolder>();
+                List<SyncedFolder> currentAccountSyncedFoldersList = new ArrayList<>();
                 Account currentAccount = AccountUtils.getCurrentOwnCloudAccount(FolderSyncActivity.this);
                 for (SyncedFolder syncedFolder : syncedFolderArrayList) {
                     if (syncedFolder.getAccount().equals(currentAccount.name)) {
@@ -377,6 +383,7 @@ public class FolderSyncActivity extends FileActivity implements FolderSyncAdapte
 
             default:
                 result = super.onOptionsItemSelected(item);
+                break;
         }
         return result;
     }
@@ -493,4 +500,25 @@ public class FolderSyncActivity extends FileActivity implements FolderSyncAdapte
         item.setEnabled(enabled);
         return item;
     }
+
+    @Override
+    public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[],
+                                           @NonNull int[] grantResults) {
+        switch (requestCode) {
+            case PermissionUtil.PERMISSIONS_WRITE_EXTERNAL_STORAGE: {
+                // If request is cancelled, result arrays are empty.
+                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
+                    // permission was granted
+                    int gridWidth = getResources().getInteger(R.integer.media_grid_width);
+                    load(gridWidth * 2, true);
+                } else {
+                    // permission denied --> do nothing
+                    return;
+                }
+                return;
+            }
+            default:
+                super.onRequestPermissionsResult(requestCode, permissions, grantResults);
+        }
+    }
 }

+ 10 - 5
src/main/java/com/owncloud/android/ui/activity/LogHistoryActivity.java

@@ -1,4 +1,4 @@
-/**
+/*
  *   ownCloud Android client application
  *
  *   Copyright (C) 2015 ownCloud Inc.
@@ -78,7 +78,9 @@ public class LogHistoryActivity extends ToolbarActivity {
         setupToolbar();
 
         setTitle(getText(R.string.actionbar_logger));
-        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
+        if (getSupportActionBar() != null) {
+            getSupportActionBar().setDisplayHomeAsUpEnabled(true);
+        }
         Button deleteHistoryButton = (Button) findViewById(R.id.deleteLogHistoryButton);
         Button sendHistoryButton = (Button) findViewById(R.id.sendLogHistoryButton);
         sendHistoryButton.getBackground().setColorFilter(ThemeUtils.primaryAccentColor(), PorterDuff.Mode.SRC_ATOP);
@@ -136,6 +138,7 @@ public class LogHistoryActivity extends ToolbarActivity {
                 break;
             default:
                 retval = super.onOptionsItemSelected(item);
+                break;
         }
         return retval;
     }
@@ -198,7 +201,7 @@ public class LogHistoryActivity extends ToolbarActivity {
     private class LoadingLogTask extends AsyncTask<String, Void, String> {
         private final WeakReference<TextView> textViewReference;
 
-        public LoadingLogTask(TextView logTV){
+        LoadingLogTask(TextView logTV) {
             // Use of a WeakReference to ensure the TextView can be garbage collected
             textViewReference  = new WeakReference<>(logTV);
         }
@@ -293,7 +296,9 @@ public class LogHistoryActivity extends ToolbarActivity {
     protected void onSaveInstanceState(Bundle outState) {
         super.onSaveInstanceState(outState);
 
-        /// global state
-        outState.putString(KEY_LOG_TEXT, mLogText);
+        if (isChangingConfigurations()) {
+            // global state
+            outState.putString(KEY_LOG_TEXT, mLogText);
+        }
     }
 }

+ 1 - 0
src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java

@@ -238,6 +238,7 @@ public class ManageAccountsActivity extends FileActivity
                 break;
             default:
                 retval = super.onOptionsItemSelected(item);
+                break;
         }
         return retval;
     }

+ 1 - 0
src/main/java/com/owncloud/android/ui/activity/ManageSpaceActivity.java

@@ -85,6 +85,7 @@ public class ManageSpaceActivity extends AppCompatActivity {
             default:
                 Log_OC.w(TAG, "Unknown menu item triggered");
                 retval =  super.onOptionsItemSelected(item);
+                break;
         }
         return retval;
     }

+ 3 - 1
src/main/java/com/owncloud/android/ui/activity/ParticipateActivity.java

@@ -131,7 +131,7 @@ public class ParticipateActivity extends FileActivity {
 
     @Override
     public boolean onOptionsItemSelected(MenuItem item) {
-        boolean retval;
+        boolean retval = true;
         switch (item.getItemId()) {
             case android.R.id.home: {
                 if (isDrawerOpen()) {
@@ -139,10 +139,12 @@ public class ParticipateActivity extends FileActivity {
                 } else {
                     openDrawer();
                 }
+                break;
             }
 
             default:
                 retval = super.onOptionsItemSelected(item);
+                break;
         }
         return retval;
     }

+ 31 - 15
src/main/java/com/owncloud/android/ui/activity/Preferences.java

@@ -36,7 +36,6 @@ import android.net.Uri;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.Environment;
-import android.preference.CheckBoxPreference;
 import android.preference.ListPreference;
 import android.preference.Preference;
 import android.preference.Preference.OnPreferenceChangeListener;
@@ -72,6 +71,7 @@ import com.owncloud.android.lib.common.ExternalLinkType;
 import com.owncloud.android.lib.common.OwnCloudAccount;
 import com.owncloud.android.lib.common.OwnCloudClientManagerFactory;
 import com.owncloud.android.lib.common.utils.Log_OC;
+import com.owncloud.android.ui.CheckBoxPreferenceWithLongTitle;
 import com.owncloud.android.utils.AnalyticsUtils;
 import com.owncloud.android.utils.DisplayUtils;
 import com.owncloud.android.utils.ThemeUtils;
@@ -112,13 +112,13 @@ public class Preferences extends PreferenceActivity
 
     private String mUploadPath;
     private PreferenceCategory mPrefInstantUploadCategory;
-    private Preference mPrefInstantUpload;
+    private CheckBoxPreferenceWithLongTitle mPrefInstantUpload;
     private Preference mPrefInstantUploadBehaviour;
     private Preference mPrefInstantUploadPath;
     private Preference mPrefInstantUploadUseSubfolders;
     private Preference mPrefInstantPictureUploadOnlyOnCharging;
     private Preference mPrefInstantUploadPathWiFi;
-    private Preference mPrefInstantVideoUpload;
+    private CheckBoxPreferenceWithLongTitle mPrefInstantVideoUpload;
     private Preference mPrefInstantVideoUploadPath;
     private Preference mPrefInstantVideoUploadUseSubfolders;
     private Preference mPrefInstantVideoUploadPathWiFi;
@@ -364,6 +364,25 @@ public class Preferences extends PreferenceActivity
             }
         }
 
+        boolean contactsBackupEnabled = !getResources().getBoolean(R.bool.show_drawer_contacts_backup)
+                && getResources().getBoolean(R.bool.contacts_backup);
+        Preference pContactsBackup = findPreference("contacts");
+        if (pCalendarContacts != null) {
+            if (contactsBackupEnabled) {
+                pContactsBackup.setOnPreferenceClickListener(new OnPreferenceClickListener() {
+                    @Override
+                    public boolean onPreferenceClick(Preference preference) {
+                        Intent contactsIntent = new Intent(getApplicationContext(), ContactsPreferenceActivity.class);
+                        contactsIntent.putExtra(ContactsPreferenceActivity.EXTRA_SHOW_SIDEBAR, false);
+                        startActivity(contactsIntent);
+                        return true;
+                    }
+                });
+            } else {
+                preferenceCategoryMore.removePreference(pContactsBackup);
+            }
+        }
+
         if (!fShowHiddenFilesEnabled && !fPrintEnabled && !fPassCodeEnabled) {
             preferenceScreen.removePreference(preferenceCategoryDetails);
         }
@@ -543,24 +562,21 @@ public class Preferences extends PreferenceActivity
             mPrefInstantUploadUseSubfolders = findPreference("instant_upload_path_use_subfolders");
             mPrefInstantUploadPathWiFi = findPreference("instant_upload_on_wifi");
             mPrefInstantPictureUploadOnlyOnCharging = findPreference("instant_upload_on_charging");
-            mPrefInstantUpload = findPreference("instant_uploading");
+            mPrefInstantUpload = (CheckBoxPreferenceWithLongTitle) findPreference("instant_uploading");
 
-            toggleInstantPictureOptions(((SwitchPreference) mPrefInstantUpload).isChecked());
+            toggleInstantPictureOptions(mPrefInstantUpload.isChecked());
 
             mPrefInstantUpload.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
-
                 @Override
                 public boolean onPreferenceChange(Preference preference, Object newValue) {
                     toggleInstantPictureOptions((Boolean) newValue);
-                    toggleInstantUploadBehaviour(
-                            ((SwitchPreference) mPrefInstantVideoUpload).isChecked(),
-                            (Boolean) newValue);
+                    toggleInstantUploadBehaviour(mPrefInstantVideoUpload.isChecked(), (Boolean) newValue);
                     return true;
                 }
             });
 
         mPrefInstantVideoUploadPath = findPreference(PreferenceKeys.INSTANT_VIDEO_UPLOAD_PATH);
-        if (mPrefInstantVideoUploadPath != null){
+            if (mPrefInstantVideoUploadPath != null) {
 
                 mPrefInstantVideoUploadPath.setOnPreferenceClickListener(new OnPreferenceClickListener() {
                     @Override
@@ -579,24 +595,24 @@ public class Preferences extends PreferenceActivity
 
             mPrefInstantVideoUploadUseSubfolders = findPreference("instant_video_upload_path_use_subfolders");
             mPrefInstantVideoUploadPathWiFi = findPreference("instant_video_upload_on_wifi");
-            mPrefInstantVideoUpload = findPreference("instant_video_uploading");
+            mPrefInstantVideoUpload = (CheckBoxPreferenceWithLongTitle) findPreference("instant_video_uploading");
             mPrefInstantVideoUploadOnlyOnCharging = findPreference("instant_video_upload_on_charging");
-            toggleInstantVideoOptions(((CheckBoxPreference) mPrefInstantVideoUpload).isChecked());
+            toggleInstantVideoOptions(mPrefInstantVideoUpload.isChecked());
             mPrefInstantVideoUpload.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
                 @Override
                 public boolean onPreferenceChange(Preference preference, Object newValue) {
                     toggleInstantVideoOptions((Boolean) newValue);
                     toggleInstantUploadBehaviour(
                             (Boolean) newValue,
-                            ((CheckBoxPreference) mPrefInstantUpload).isChecked());
+                            mPrefInstantUpload.isChecked());
                     return true;
                 }
             });
 
             mPrefInstantUploadBehaviour = findPreference("prefs_instant_behaviour");
             toggleInstantUploadBehaviour(
-                    ((CheckBoxPreference) mPrefInstantVideoUpload).isChecked(),
-                    ((CheckBoxPreference) mPrefInstantUpload).isChecked());
+                    mPrefInstantVideoUpload.isChecked(),
+                    mPrefInstantUpload.isChecked());
 
             loadInstantUploadPath();
             loadInstantUploadVideoPath();

+ 1 - 0
src/main/java/com/owncloud/android/ui/activity/ReceiveExternalFilesActivity.java

@@ -999,6 +999,7 @@ public class ReceiveExternalFilesActivity extends FileActivity
 
             default:
                 retval = super.onOptionsItemSelected(item);
+                break;
         }
         return retval;
     }

+ 1 - 1
src/main/java/com/owncloud/android/ui/activity/UploadFilesActivity.java

@@ -240,10 +240,10 @@ public class UploadFilesActivity extends FileActivity implements
                     item.setIcon(R.drawable.ic_view_list);
                     mFileListFragment.switchToGridView();
                 }
-                return true;
             }
             default:
                 retval = super.onOptionsItemSelected(item);
+                break;
         }
         return retval;
     }

+ 17 - 4
src/main/java/com/owncloud/android/ui/adapter/ActivityListAdapter.java

@@ -1,4 +1,4 @@
-/**
+/*
  * Nextcloud Android client application
  *
  * @author Alejandro Bautista
@@ -47,11 +47,13 @@ import com.bumptech.glide.load.resource.file.FileToStreamDecoder;
 import com.caverock.androidsvg.SVG;
 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.lib.common.OwnCloudClient;
 import com.owncloud.android.lib.resources.activities.models.Activity;
 import com.owncloud.android.lib.resources.activities.models.RichElement;
 import com.owncloud.android.lib.resources.activities.models.RichObject;
+import com.owncloud.android.lib.resources.files.FileUtils;
 import com.owncloud.android.ui.interfaces.ActivityListInterface;
 import com.owncloud.android.utils.DisplayUtils;
 import com.owncloud.android.utils.MimeTypeUtil;
@@ -79,12 +81,15 @@ public class ActivityListAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
     private OwnCloudClient mClient;
 
     private Context context;
+    private FileDataStorageManager storageManager;
     private List<Object> mValues;
 
-    public ActivityListAdapter(Context context, ActivityListInterface activityListInterface) {
+    public ActivityListAdapter(Context context, ActivityListInterface activityListInterface,
+                               FileDataStorageManager storageManager) {
         this.mValues = new ArrayList<>();
         this.context = context;
         this.activityListInterface = activityListInterface;
+        this.storageManager = storageManager;
         px = getThumbnailDimension();
     }
 
@@ -203,8 +208,16 @@ public class ActivityListAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
     }
 
     private ImageView createThumbnail(final RichObject richObject) {
-        OCFile file = new OCFile("/" + richObject.getPath());
-        file.setRemoteId(richObject.getId());
+        String path = FileUtils.PATH_SEPARATOR + richObject.getPath();
+        OCFile file = storageManager.getFileByPath(path);
+
+        if (file == null) {
+            file = storageManager.getFileByPath(path + FileUtils.PATH_SEPARATOR);
+        }
+        if (file == null) {
+            file = new OCFile(path);
+            file.setRemoteId(richObject.getId());
+        }
 
         LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(px, px);
         params.setMargins(10, 10, 10, 10);

+ 20 - 3
src/main/java/com/owncloud/android/ui/adapter/FileListListAdapter.java

@@ -93,6 +93,8 @@ public class FileListListAdapter extends BaseAdapter {
     private OCFile currentDirectory;
     private static final String TAG = FileListListAdapter.class.getSimpleName();
 
+    private ArrayList<ThumbnailsCacheManager.ThumbnailGenerationTask> asyncTasks = new ArrayList<>();
+
     public FileListListAdapter(
             boolean justFolders,
             Context context,
@@ -250,7 +252,7 @@ public class FileListListAdapter extends BaseAdapter {
                     fileSizeV.setVisibility(View.VISIBLE);
                     fileSizeV.setText(DisplayUtils.bytesToHumanReadable(file.getFileLength()));
 
-
+                    break;
                 case GRID_ITEM:
                     // filename
                     fileName = (TextView) view.findViewById(R.id.Filename);
@@ -263,6 +265,7 @@ public class FileListListAdapter extends BaseAdapter {
                         fileName.setVisibility(View.GONE);
                     }
 
+                    break;
                 case GRID_IMAGE:
                     // sharedIcon
                     ImageView sharedIconV = (ImageView) view.findViewById(R.id.sharedIcon);
@@ -376,8 +379,7 @@ public class FileListListAdapter extends BaseAdapter {
                             try {
                                 final ThumbnailsCacheManager.ThumbnailGenerationTask task =
                                         new ThumbnailsCacheManager.ThumbnailGenerationTask(
-                                                fileIcon, mStorageManager, mAccount
-                                        );
+                                                fileIcon, mStorageManager, mAccount, asyncTasks);
 
                                 if (thumbnail == null) {
                                     if (MimeTypeUtil.isVideo(file)) {
@@ -393,6 +395,7 @@ public class FileListListAdapter extends BaseAdapter {
                                                 task
                                         );
                                 fileIcon.setImageDrawable(asyncDrawable);
+                                asyncTasks.add(task);
                                 task.execute(file);
                             } catch (IllegalArgumentException e) {
                                 Log_OC.d(TAG, "ThumbnailGenerationTask : " + e.getMessage());
@@ -706,4 +709,18 @@ public class FileListListAdapter extends BaseAdapter {
         return ret;
     }
 
+    public void cancelAllPendingTasks() {
+        for (ThumbnailsCacheManager.ThumbnailGenerationTask task : asyncTasks) {
+            if (task != null) {
+                task.cancel(true);
+                if (task.getGetMethod() != null) {
+                    Log_OC.d(TAG, "cancel: abort get method directly");
+                    task.getGetMethod().abort();
+                }
+            }
+        }
+
+        asyncTasks.clear();
+    }
+
 }

+ 1 - 0
src/main/java/com/owncloud/android/ui/asynctasks/CopyAndUploadContentUrisTask.java

@@ -255,6 +255,7 @@ public class CopyAndUploadContentUrisTask extends AsyncTask<Object, Void, Result
                         break;
                     default:
                         messageId = R.string.common_error_unknown;
+                        break;
                 }
                 String message = String.format(
                     mAppContext.getString(messageId),

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

@@ -335,6 +335,7 @@ public class FileDetailFragment extends FileFragment implements OnClickListener
             }
             default:
                 Log_OC.e(TAG, "Incorrect view clicked!");
+                break;
         }
     }
 

+ 8 - 0
src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java

@@ -279,6 +279,14 @@ public class OCFileListFragment extends ExtendedListFragment implements OCFileLi
         super.onDetach();
     }
 
+    @Override
+    public void onPause() {
+        super.onPause();
+        mAdapter.cancelAllPendingTasks();
+    }
+
+
+
     /**
      * {@inheritDoc}
      */

+ 24 - 12
src/main/java/com/owncloud/android/ui/fragment/contactsbackup/ContactsBackupFragment.java

@@ -25,6 +25,7 @@ import android.accounts.Account;
 import android.app.DatePickerDialog;
 import android.content.DialogInterface;
 import android.graphics.PorterDuff;
+import android.content.Intent;
 import android.os.AsyncTask;
 import android.os.Bundle;
 import android.support.annotation.NonNull;
@@ -52,6 +53,7 @@ import com.owncloud.android.lib.common.operations.RemoteOperationResult;
 import com.owncloud.android.operations.RefreshFolderOperation;
 import com.owncloud.android.services.ContactsBackupJob;
 import com.owncloud.android.ui.activity.ContactsPreferenceActivity;
+import com.owncloud.android.ui.activity.Preferences;
 import com.owncloud.android.ui.fragment.FileFragment;
 import com.owncloud.android.utils.DisplayUtils;
 import com.owncloud.android.utils.PermissionUtil;
@@ -76,9 +78,6 @@ public class ContactsBackupFragment extends FileFragment implements DatePickerDi
     @BindView(R.id.contacts_automatic_backup)
     public SwitchCompat backupSwitch;
 
-    @BindView(R.id.contacts_header_restore)
-    public TextView contactsRestoreHeader;
-
     @BindView(R.id.contacts_header_backup)
     public TextView contactsBackupHeader;
 
@@ -101,6 +100,7 @@ public class ContactsBackupFragment extends FileFragment implements DatePickerDi
     private static final String KEY_CALENDAR_YEAR = "CALENDAR_YEAR";
     private ArbitraryDataProvider arbitraryDataProvider;
     private Account account;
+    private boolean showSidebar = true;
 
 
     @Override
@@ -115,6 +115,10 @@ public class ContactsBackupFragment extends FileFragment implements DatePickerDi
 
         setHasOptionsMenu(true);
 
+        if (getArguments() != null) {
+            showSidebar = getArguments().getBoolean(ContactsPreferenceActivity.EXTRA_SHOW_SIDEBAR);
+        }
+
         final ContactsPreferenceActivity contactsPreferenceActivity = (ContactsPreferenceActivity) getActivity();
 
         account = (Account) getArguments().get(ContactListFragment.ACCOUNT);
@@ -204,11 +208,16 @@ public class ContactsBackupFragment extends FileFragment implements DatePickerDi
                         getActivity().getContentResolver());
 
                 OCFile folder = storageManager.getFileByPath(path[0]);
-                RefreshFolderOperation operation = new RefreshFolderOperation(folder, System.currentTimeMillis(),
-                        false, false, false, storageManager, account, getContext());
 
-                RemoteOperationResult result = operation.execute(account, getContext());
-                return result.isSuccess();
+                if (folder != null) {
+                    RefreshFolderOperation operation = new RefreshFolderOperation(folder, System.currentTimeMillis(),
+                            false, false, false, storageManager, account, getContext());
+
+                    RemoteOperationResult result = operation.execute(account, getContext());
+                    return result.isSuccess();
+                } else {
+                    return false;
+                }
             }
 
             @Override
@@ -220,10 +229,8 @@ public class ContactsBackupFragment extends FileFragment implements DatePickerDi
                             .getFolderContent(backupFolder, false);
 
                     if (backupFiles == null || backupFiles.size() == 0) {
-                        contactsRestoreHeader.setVisibility(View.GONE);
                         contactsDatePickerBtn.setVisibility(View.GONE);
                     } else {
-                        contactsRestoreHeader.setVisibility(View.VISIBLE);
                         contactsDatePickerBtn.setVisibility(View.VISIBLE);
                     }
                 }
@@ -241,10 +248,15 @@ public class ContactsBackupFragment extends FileFragment implements DatePickerDi
         boolean retval;
         switch (item.getItemId()) {
             case android.R.id.home:
-                if (contactsPreferenceActivity.isDrawerOpen()) {
-                    contactsPreferenceActivity.closeDrawer();
+                if (showSidebar) {
+                    if (contactsPreferenceActivity.isDrawerOpen()) {
+                        contactsPreferenceActivity.closeDrawer();
+                    } else {
+                        contactsPreferenceActivity.openDrawer();
+                    }
                 } else {
-                    contactsPreferenceActivity.openDrawer();
+                    Intent settingsIntent = new Intent(getContext(), Preferences.class);
+                    startActivity(settingsIntent);
                 }
                 retval = true;
                 break;

+ 1 - 0
src/main/java/com/owncloud/android/ui/preview/FileDownloadFragment.java

@@ -218,6 +218,7 @@ public class FileDownloadFragment extends FileFragment implements OnClickListene
             }
             default:
                 Log_OC.e(TAG, "Incorrect view clicked!");
+                break;
         }
     }
 

+ 1 - 0
src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java

@@ -272,6 +272,7 @@ public class PreviewImageActivity extends FileActivity implements
             break;
         default:
         	returnValue = super.onOptionsItemSelected(item);
+            break;
         }
         
         return returnValue;

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

@@ -1,18 +1,18 @@
-/**
+/*
  * ownCloud Android client application
  *
  * @author David A. Velasco
  * Copyright (C) 2015 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/>.
  */
@@ -32,6 +32,7 @@ import android.graphics.drawable.PictureDrawable;
 import android.os.AsyncTask;
 import android.os.Build;
 import android.os.Bundle;
+import android.os.Process;
 import android.support.annotation.DrawableRes;
 import android.support.annotation.StringRes;
 import android.support.v4.app.FragmentStatePagerAdapter;
@@ -442,6 +443,8 @@ public class PreviewImageFragment extends FileFragment {
 
         @Override
         protected LoadImage doInBackground(OCFile... params) {
+            Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND + Process.THREAD_PRIORITY_MORE_FAVORABLE);
+
             Bitmap bitmapResult = null;
             Drawable drawableResult = null;
 

+ 22 - 37
src/main/res/layout/contacts_backup_fragment.xml

@@ -28,17 +28,6 @@
         android:layout_height="wrap_content"
         android:orientation="vertical">
 
-        <TextView
-            android:id="@+id/contacts_header_backup"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_marginLeft="@dimen/standard_margin"
-            android:layout_marginRight="@dimen/standard_margin"
-            android:layout_marginTop="@dimen/standard_margin"
-            android:text="@string/contacts_header_backup"
-            android:textColor="@color/primary"
-            android:textStyle="bold"/>
-
         <android.support.v7.widget.SwitchCompat
             android:id="@+id/contacts_automatic_backup"
             android:layout_width="match_parent"
@@ -73,34 +62,30 @@
                 android:textAppearance="?android:attr/textAppearanceMedium"/>
         </LinearLayout>
 
-        <android.support.v7.widget.AppCompatButton
-            android:id="@+id/contacts_backup_now"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_margin="@dimen/standard_margin"
-            android:text="@string/contacts_backup_button"
-            android:theme="@style/Button.Primary"/>
-
-        <TextView
-            android:id="@+id/contacts_header_restore"
+        <LinearLayout
             android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_marginLeft="@dimen/standard_margin"
-            android:layout_marginRight="@dimen/standard_margin"
-            android:layout_marginTop="@dimen/standard_margin"
-            android:text="@string/contacts_header_restore"
-            android:textColor="@color/primary"
-            android:textStyle="bold"
-            android:visibility="gone"/>
+            android:layout_height="match_parent"
+            android:orientation="horizontal">
 
-        <android.support.v7.widget.AppCompatButton
-            android:id="@+id/contacts_datepicker"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_margin="@dimen/standard_margin"
-            android:text="@string/contacts_preference_choose_date"
-            android:theme="@style/Button.Primary"
-            android:visibility="gone"/>
+            <android.support.v7.widget.AppCompatButton
+                android:id="@+id/contacts_backup_now"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_margin="@dimen/standard_margin"
+                android:layout_weight="1"
+                android:text="@string/contacts_backup_button"
+                android:theme="@style/Button.Primary"/>
+
+            <android.support.v7.widget.AppCompatButton
+                android:id="@+id/contacts_datepicker"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_margin="@dimen/standard_margin"
+                android:layout_weight="1"
+                android:text="@string/contacts_preference_choose_date"
+                android:theme="@style/Button"
+                android:visibility="gone"/>
+        </LinearLayout>
 
     </LinearLayout>
 

+ 1 - 0
src/main/res/layout/folder_sync_layout.xml

@@ -40,6 +40,7 @@
             android:layout_height="match_parent"
             android:layout_above="@+id/bottom_navigation_view"
             android:layout_below="@+id/appbar"
+            android:id="@+id/ListLayout"
             android:orientation="vertical">
 
             <android.support.v7.widget.RecyclerView

+ 1 - 0
src/main/res/values/setup.xml

@@ -83,6 +83,7 @@
     <bool name="shared_enabled">true</bool>
     <bool name="videos_enabled">false</bool>
     <bool name="show_drawer_logout">false</bool>
+    <bool name="show_drawer_contacts_backup">false</bool> <!-- if false it will shown in settings -->
 
     <!-- Various other options -->
     <bool name="allow_profile_click">true</bool>

+ 3 - 6
src/main/res/values/strings.xml

@@ -642,13 +642,10 @@
     <string name="webview_error">Error occurred</string>
     <string name="prefs_category_about">About</string>
 
-    <string name="actionbar_contacts">Backup contacts</string>
+    <string name="actionbar_contacts">Back up contacts</string>
     <string name="actionbar_contacts_restore">Restore contacts</string>
-    <string name="contacts_backup_button">Backup now</string>
-    <string name="contacts_restore_button">Restore last backup</string>
-    <string name="contacts_header_restore">Restore</string>
-    <string name="contacts_header_backup">Backup</string>
-    <string name="contacts_automatic_backup">Contacts backup</string>
+    <string name="contacts_backup_button">Back up now</string>
+    <string name="contacts_automatic_backup">Automatic backup</string>
     <string name="contacts_last_backup">Last backup</string>
     <string name="contacts_read_permission">Permission to read contact list needed</string>
     <string name="contacts_write_permission">Permission to change contact list needed</string>

+ 4 - 0
src/main/res/xml/preferences.xml

@@ -102,6 +102,10 @@
 		<Preference android:title="@string/prefs_calendar_contacts"
 					android:key="calendar_contacts"
 					android:summary="@string/prefs_calendar_contacts_summary" />
+		<Preference
+			android:title="@string/actionbar_contacts"
+			android:key="contacts"
+			android:summary="Daily backup of your contacts"/>
 		<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" />

Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно