Merge branch 'master' of https://github.com/owncloud/android into target_marshmallow
authorAndy Scherzinger <info@andy-scherzinger.de>
Fri, 30 Oct 2015 13:21:45 +0000 (14:21 +0100)
committerAndy Scherzinger <info@andy-scherzinger.de>
Fri, 30 Oct 2015 13:21:45 +0000 (14:21 +0100)
1  2 
.travis.yml
src/com/owncloud/android/ui/activity/FileDisplayActivity.java
src/com/owncloud/android/ui/adapter/FileListListAdapter.java
src/com/owncloud/android/ui/fragment/OCFileListFragment.java
src/com/owncloud/android/utils/DisplayUtils.java

diff --combined .travis.yml
@@@ -1,10 -1,9 +1,11 @@@
+ sudo: false
  language: android
  android:
    components:
 -    - build-tools-22.0.1
 +    - build-tools-23.0.1
 +    - android-23
      - android-22
 +    - android-19
  before_install:
    - rm pom.xml
  script:
@@@ -149,7 -149,7 +149,7 @@@ public class FileDisplayActivity extend
      private boolean mSyncInProgress = false;
  
      private static String DIALOG_UNTRUSTED_CERT = "DIALOG_UNTRUSTED_CERT";
 -    private static String DIALOG_CREATE_FOLDER = "DIALOG_CREATE_FOLDER";
 +    public static String DIALOG_CREATE_FOLDER = "DIALOG_CREATE_FOLDER";
      private static String DIALOG_UPLOAD_SOURCE = "DIALOG_UPLOAD_SOURCE";
      private static String DIALOG_CERT_NOT_SAVED = "DIALOG_CERT_NOT_SAVED";
  
              setFile(file);
  
              if (mAccountWasSet) {
 -                RelativeLayout navigationDrawerLayout = (RelativeLayout) findViewById(R.id.left_drawer);
 -                if (navigationDrawerLayout != null && getAccount() != null) {
 -                    TextView username = (TextView) navigationDrawerLayout.findViewById(R.id.drawer_username);
 -                    int lastAtPos = getAccount().name.lastIndexOf("@");
 -                    username.setText(getAccount().name.substring(0, lastAtPos));
 -                }
 +                setUsernameInDrawer((RelativeLayout) findViewById(R.id.left_drawer), getAccount());
              }
  
              if (!stateWasRecovered) {
      @Override
      public boolean onPrepareOptionsMenu(Menu menu) {
          boolean drawerOpen = mDrawerLayout.isDrawerOpen(GravityCompat.START);
 -        menu.findItem(R.id.action_upload).setVisible(!drawerOpen);
 -        menu.findItem(R.id.action_create_dir).setVisible(!drawerOpen);
          menu.findItem(R.id.action_sort).setVisible(!drawerOpen);
          menu.findItem(R.id.action_sync_account).setVisible(!drawerOpen);
          
      public boolean onCreateOptionsMenu(Menu menu) {
          MenuInflater inflater = getMenuInflater();
          inflater.inflate(R.menu.main_menu, menu);
 +        menu.findItem(R.id.action_create_dir).setVisible(false);
          return true;
      }
      
      public boolean onOptionsItemSelected(MenuItem item) {
          boolean retval = true;
          switch (item.getItemId()) {
 -            case R.id.action_create_dir: {
 -                CreateFolderDialogFragment dialog =
 -                        CreateFolderDialogFragment.newInstance(getCurrentDir());
 -                dialog.show(getSupportFragmentManager(), DIALOG_CREATE_FOLDER);
 -                break;
 -            }
 -
              case R.id.action_sync_account: {
                  startSynchronization();
                  break;
              }
 -            case R.id.action_upload: {
 -                UploadSourceDialogFragment dialog =
 -                        UploadSourceDialogFragment.newInstance(getAccount());
 -                dialog.show(getSupportFragmentManager(), DIALOG_UPLOAD_SOURCE);
 -                break;
 -            }
              case android.R.id.home: {
                  FileFragment second = getSecondFragment();
                  OCFile currentDir = getCurrentDir();
          return retval;
      }
  
 +    public void createFolder() {
 +        CreateFolderDialogFragment dialog =
 +                CreateFolderDialogFragment.newInstance(getCurrentDir());
 +        dialog.show(getSupportFragmentManager(), DIALOG_CREATE_FOLDER);
 +    }
 +
 +    public void uploadLocalFilesSelected() {
 +        Intent action = new Intent(this, UploadFilesActivity.class);
 +        action.putExtra(
 +                UploadFilesActivity.EXTRA_ACCOUNT,
 +                getAccount()
 +        );
 +        startActivityForResult(action, ACTION_SELECT_MULTIPLE_FILES);
 +    }
 +
 +    public void uploadFromOtherAppsSelected() {
 +        Intent action = new Intent(Intent.ACTION_GET_CONTENT);
 +        action = action.setType("*/*").addCategory(Intent.CATEGORY_OPENABLE);
 +        //Intent.EXTRA_ALLOW_MULTIPLE is only supported on api level 18+, Jelly Bean
 +        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
 +            action.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
 +        }
 +        startActivityForResult(
 +                Intent.createChooser(action, getString(R.string.upload_chooser_title)),
 +                ACTION_SELECT_CONTENT_FROM_APPS
 +        );
 +    }
 +
      private void startSynchronization() {
          Log_OC.d(TAG, "Got to start sync");
          if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.KITKAT) {
  
      @Override
      public void onBackPressed() {
 -        if (!isDrawerOpen()){
 +        boolean isFabOpen = isFabOpen();
 +        boolean isDrawerOpen = isDrawerOpen();
 +
 +        /*
 +         * BackPressed priority/hierarchy:
 +         *    1. close drawer if opened
 +         *    2. close FAB if open (only if drawer isn't open)
 +         *    3. navigate up (only if drawer and FAB aren't open)
 +         */
 +        if(isDrawerOpen && isFabOpen) {
 +            // close drawer first
 +            super.onBackPressed();
 +        } else if(isDrawerOpen && !isFabOpen) {
 +            // close drawer
 +            super.onBackPressed();
 +        } else if (!isDrawerOpen && isFabOpen) {
 +            // close fab
 +            getListOfFilesFragment().getFabMain().collapse();
 +        } else {
 +            // all closed
              OCFileListFragment listOfFiles = getListOfFilesFragment();
              if (mDualPane || getSecondFragment() == null) {
                  OCFile currentDir = getCurrentDir();
                  setFile(listOfFiles.getCurrentFile());
              }
              cleanSecondFragment();
 -        } else {
 -            super.onBackPressed();
          }
      }
  
          Log_OC.v(TAG, "onPause() end");
      }
  
 +    public boolean isFabOpen() {
 +        if(getListOfFilesFragment() != null && getListOfFilesFragment().getFabMain() != null && getListOfFilesFragment().getFabMain().isExpanded()) {
 +            return true;
 +        } else {
 +            return false;
 +        }
 +    }
 +
  
      private class SyncBroadcastReceiver extends BroadcastReceiver {
  
                          (uploadedRemotePath.startsWith(currentDir.getRemotePath()));
  
                  if (sameAccount && isDescendant) {
-                     refreshListOfFilesFragment();
+                     String linkedToRemotePath =
+                             intent.getStringExtra(FileDownloader.EXTRA_LINKED_TO_PATH);
+                     if (linkedToRemotePath == null || isAscendant(linkedToRemotePath)) {
+                         refreshListOfFilesFragment();
+                     }
                  }
  
                  boolean uploadWasFine = intent.getBooleanExtra(FileUploader.EXTRA_UPLOAD_RESULT,
  
          }
  
+         // TODO refactor this receiver, and maybe DownloadFinishReceiver; this method is duplicated :S
+         private boolean isAscendant(String linkedToRemotePath) {
+             OCFile currentDir = getCurrentDir();
+             return (
+                     currentDir != null &&
+                             currentDir.getRemotePath().startsWith(linkedToRemotePath)
+             );
+         }
      }
  
  
       */
      private class DownloadFinishReceiver extends BroadcastReceiver {
  
-         //int refreshCounter = 0;
          @Override
          public void onReceive(Context context, Intent intent) {
              try {
-                 boolean sameAccount = isSameAccount(context, intent);
+                 boolean sameAccount = isSameAccount(intent);
                  String downloadedRemotePath =
                          intent.getStringExtra(FileDownloader.EXTRA_REMOTE_PATH);
                  boolean isDescendant = isDescendant(downloadedRemotePath);
                      String linkedToRemotePath =
                              intent.getStringExtra(FileDownloader.EXTRA_LINKED_TO_PATH);
                      if (linkedToRemotePath == null || isAscendant(linkedToRemotePath)) {
-                         //Log_OC.v(TAG, "refresh #" + ++refreshCounter);
                          refreshListOfFilesFragment();
                      }
                      refreshSecondFragment(
              );
          }
  
-         private boolean isSameAccount(Context context, Intent intent) {
+         private boolean isSameAccount(Intent intent) {
              String accountName = intent.getStringExtra(FileDownloader.ACCOUNT_NAME);
              return (accountName != null && getAccount() != null &&
                      accountName.equals(getAccount().name));
@@@ -194,7 -194,6 +194,7 @@@ public class FileListListAdapter extend
              switch (viewType){\r
                  case LIST_ITEM:\r
                      TextView fileSizeV = (TextView) view.findViewById(R.id.file_size);\r
 +                    TextView fileSizeSeparatorV = (TextView) view.findViewById(R.id.file_separator);\r
                      TextView lastModV = (TextView) view.findViewById(R.id.last_mod);\r
                      ImageView checkBoxV = (ImageView) view.findViewById(R.id.custom_checkbox);\r
  \r
  \r
                      checkBoxV.setVisibility(View.GONE);\r
  \r
 +                    fileSizeSeparatorV.setVisibility(View.VISIBLE);\r
                      fileSizeV.setVisibility(View.VISIBLE);\r
                      fileSizeV.setText(DisplayUtils.bytesToHumanReadable(file.getFileLength()));\r
  \r
                              } else {\r
                                  if (parentList.isItemChecked(position)) {\r
                                      checkBoxV.setImageResource(\r
 -                                            android.R.drawable.checkbox_on_background);\r
 +                                            R.drawable.ic_checkbox_marked);\r
                                  } else {\r
                                      checkBoxV.setImageResource(\r
 -                                            android.R.drawable.checkbox_off_background);\r
 +                                            R.drawable.ic_checkbox_blank_outline);\r
                                  }\r
                                  checkBoxV.setVisibility(View.VISIBLE);\r
                              }\r
                          }\r
  \r
                      } else { //Folder\r
 +                        fileSizeSeparatorV.setVisibility(View.INVISIBLE);\r
                          fileSizeV.setVisibility(View.INVISIBLE);\r
                      }\r
  \r
                              mTransferServiceGetter.getFileDownloaderBinder();\r
                      FileUploaderBinder uploaderBinder =\r
                              mTransferServiceGetter.getFileUploaderBinder();\r
-                     boolean downloading = (downloaderBinder != null &&\r
-                             downloaderBinder.isDownloading(mAccount, file));\r
                      OperationsServiceBinder opsBinder =\r
                              mTransferServiceGetter.getOperationsServiceBinder();\r
-                     downloading |= (opsBinder != null &&\r
-                             opsBinder.isSynchronizing(mAccount, file.getRemotePath()));\r
-                     if (downloading) {\r
-                         localStateView.setImageResource(R.drawable.downloading_file_indicator);\r
\r
+                     localStateView.setVisibility(View.INVISIBLE);   // default first\r
\r
+                     if ( //synchronizing\r
+                                 opsBinder != null &&\r
+                                 opsBinder.isSynchronizing(mAccount, file.getRemotePath())\r
+                             ) {\r
+                         localStateView.setImageResource(R.drawable.synchronizing_file_indicator);\r
+                         localStateView.setVisibility(View.VISIBLE);\r
\r
+                     } else if ( // downloading\r
+                                 downloaderBinder != null &&\r
+                                 downloaderBinder.isDownloading(mAccount, file)\r
+                             ) {\r
+                         localStateView.setImageResource(\r
+                                 file.isFolder() ?\r
+                                         R.drawable.synchronizing_file_indicator :\r
+                                         R.drawable.downloading_file_indicator\r
+                         );\r
                          localStateView.setVisibility(View.VISIBLE);\r
-                     } else if (uploaderBinder != null &&\r
-                             uploaderBinder.isUploading(mAccount, file)) {\r
-                         localStateView.setImageResource(R.drawable.uploading_file_indicator);\r
\r
+                     } else if ( //uploading\r
+                                 uploaderBinder != null &&\r
+                                 uploaderBinder.isUploading(mAccount, file)\r
+                             ) {\r
+                         localStateView.setImageResource(\r
+                                 file.isFolder() ?\r
+                                         R.drawable.synchronizing_file_indicator :\r
+                                         R.drawable.uploading_file_indicator\r
+                         );\r
                          localStateView.setVisibility(View.VISIBLE);\r
\r
+                     } else if (file.getEtagInConflict() != null) {   // conflict\r
+                         localStateView.setImageResource(R.drawable.conflict_file_indicator);\r
+                         localStateView.setVisibility(View.VISIBLE);\r
\r
                      } else if (file.isDown()) {\r
                          localStateView.setImageResource(R.drawable.local_file_indicator);\r
                          localStateView.setVisibility(View.VISIBLE);\r
-                     } else {\r
-                         localStateView.setVisibility(View.INVISIBLE);\r
                      }\r
  \r
                      // share with me icon\r
          return view;\r
      }\r
  \r
-     /**\r
-      * Local Folder size in human readable format\r
-      * \r
-      * @param path\r
-      *            String\r
-      * @return Size in human readable format\r
-      */\r
-     private String getFolderSizeHuman(String path) {\r
\r
-         File dir = new File(path);\r
\r
-         if (dir.exists()) {\r
-             long bytes = FileStorageUtils.getFolderSize(dir);\r
-             return DisplayUtils.bytesToHumanReadable(bytes);\r
-         }\r
\r
-         return "0 B";\r
-     }\r
\r
-     /**\r
-      * Local Folder size\r
-      * @param dir File\r
-      * @return Size in bytes\r
-      */\r
-     private long getFolderSize(File dir) {\r
-         if (dir.exists()) {\r
-             long result = 0;\r
-             File[] fileList = dir.listFiles();\r
-             for(int i = 0; i < fileList.length; i++) {\r
-                 if(fileList[i].isDirectory()) {\r
-                     result += getFolderSize(fileList[i]);\r
-                 } else {\r
-                     result += fileList[i].length();\r
-                 }\r
-             }\r
-             return result;\r
-         }\r
-         return 0;\r
-     } \r
\r
      @Override\r
      public int getViewTypeCount() {\r
          return 1;\r
@@@ -24,10 -24,7 +24,10 @@@ package com.owncloud.android.ui.fragmen
  
  import android.app.Activity;
  import android.content.Intent;
 +import android.content.SharedPreferences;
 +import android.os.Build;
  import android.os.Bundle;
 +import android.preference.PreferenceManager;
  import android.support.v4.widget.SwipeRefreshLayout;
  import android.view.ContextMenu;
  import android.view.Menu;
@@@ -37,8 -34,6 +37,8 @@@ import android.view.View
  import android.widget.AdapterView;
  import android.widget.AdapterView.AdapterContextMenuInfo;
  import android.widget.PopupMenu;
 +import android.widget.TextView;
 +import android.widget.Toast;
  
  import com.owncloud.android.R;
  import com.owncloud.android.authentication.AccountUtils;
@@@ -51,14 -46,11 +51,14 @@@ import com.owncloud.android.ui.activity
  import com.owncloud.android.ui.activity.FileDisplayActivity;
  import com.owncloud.android.ui.activity.FolderPickerActivity;
  import com.owncloud.android.ui.activity.OnEnforceableRefreshListener;
 +import com.owncloud.android.ui.activity.UploadFilesActivity;
  import com.owncloud.android.ui.adapter.FileListListAdapter;
  import com.owncloud.android.ui.dialog.ConfirmationDialogFragment;
 +import com.owncloud.android.ui.dialog.CreateFolderDialogFragment;
  import com.owncloud.android.ui.dialog.FileActionsDialogFragment;
  import com.owncloud.android.ui.dialog.RemoveFileDialogFragment;
  import com.owncloud.android.ui.dialog.RenameFileDialogFragment;
 +import com.owncloud.android.ui.dialog.UploadSourceDialogFragment;
  import com.owncloud.android.ui.preview.PreviewImageFragment;
  import com.owncloud.android.ui.preview.PreviewMediaFragment;
  import com.owncloud.android.utils.FileStorageUtils;
@@@ -80,12 -72,8 +80,12 @@@ public class OCFileListFragment extend
  
      public final static String ARG_JUST_FOLDERS = MY_PACKAGE + ".JUST_FOLDERS";
      public final static String ARG_ALLOW_CONTEXTUAL_ACTIONS = MY_PACKAGE + ".ALLOW_CONTEXTUAL";
 +    public final static String ARG_HIDE_FAB = MY_PACKAGE + ".HIDE_FAB";
  
      private static final String KEY_FILE = MY_PACKAGE + ".extra.FILE";
 +    private static final String KEY_FAB_EVER_CLICKED = "FAB_EVER_CLICKED";
 +
 +    private static String DIALOG_CREATE_FOLDER = "DIALOG_CREATE_FOLDER";
  
      private FileFragment.ContainerActivity mContainerActivity;
  
@@@ -94,8 -82,8 +94,8 @@@
      private boolean mJustFolders;
      
      private OCFile mTargetFile;
 -    
 -   
 +
 +    private boolean miniFabClicked = false;
      
      /**
       * {@inheritDoc}
          setListAdapter(mAdapter);
  
          registerLongClickListener();
 +
 +        boolean hideFab = (args != null) && args.getBoolean(ARG_HIDE_FAB, false);
 +        if (hideFab) {
 +            setFabEnabled(false);
 +        } else {
 +            setFabEnabled(true);
 +            registerFabListeners();
 +
 +            // detect if a mini FAB has ever been clicked
 +            final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getActivity());
 +            if(prefs.getLong(KEY_FAB_EVER_CLICKED, 0) > 0) {
 +                miniFabClicked = true;
 +            }
 +
 +            // add labels to the min FABs when none of them has ever been clicked on
 +            if(!miniFabClicked) {
 +                setFabLabels();
 +            } else {
 +                removeFabLabels();
 +            }
 +        }
    }
  
 +    /**
 +     * adds labels to all mini FABs.
 +     */
 +    private void setFabLabels() {
 +        getFabUpload().setTitle(getResources().getString(R.string.actionbar_upload));
 +        getFabMkdir().setTitle(getResources().getString(R.string.actionbar_mkdir));
 +        getFabUploadFromApp().setTitle(getResources().getString(R.string.actionbar_upload_from_apps));
 +    }
 +
 +    /**
 +     * registers all listeners on all mini FABs.
 +     */
 +    private void registerFabListeners() {
 +        registerFabUploadListeners();
 +        registerFabMkDirListeners();
 +        registerFabUploadFromAppListeners();
 +    }
 +
 +    /**
 +     * registers {@link android.view.View.OnClickListener} and {@link android.view.View.OnLongClickListener}
 +     * on the Upload mini FAB for the linked action and {@link Toast} showing the underlying action.
 +     */
 +    private void registerFabUploadListeners() {
 +        getFabUpload().setOnClickListener(new View.OnClickListener() {
 +            @Override
 +            public void onClick(View v) {
 +                Intent action = new Intent(getActivity(), UploadFilesActivity.class);
 +                action.putExtra(
 +                        UploadFilesActivity.EXTRA_ACCOUNT,
 +                        ((FileActivity) getActivity()).getAccount()
 +                );
 +                getActivity().startActivityForResult(action, UploadSourceDialogFragment.ACTION_SELECT_MULTIPLE_FILES);
 +                getFabMain().collapse();
 +                recordMiniFabClick();
 +            }
 +        });
 +
 +        getFabUpload().setOnLongClickListener(new View.OnLongClickListener() {
 +            @Override
 +            public boolean onLongClick(View v) {
 +                Toast.makeText(getActivity(), R.string.actionbar_upload, Toast.LENGTH_SHORT).show();
 +                return true;
 +            }
 +        });
 +    }
 +
 +    /**
 +     * registers {@link android.view.View.OnClickListener} and {@link android.view.View.OnLongClickListener}
 +     * on the 'Create Dir' mini FAB for the linked action and {@link Toast} showing the underlying action.
 +     */
 +    private void registerFabMkDirListeners() {
 +        getFabMkdir().setOnClickListener(new View.OnClickListener() {
 +            @Override
 +            public void onClick(View v) {
 +                CreateFolderDialogFragment dialog =
 +                        CreateFolderDialogFragment.newInstance(mFile);
 +                dialog.show(getActivity().getSupportFragmentManager(), FileDisplayActivity.DIALOG_CREATE_FOLDER);
 +                getFabMain().collapse();
 +                recordMiniFabClick();
 +            }
 +        });
 +
 +        getFabMkdir().setOnLongClickListener(new View.OnLongClickListener() {
 +            @Override
 +            public boolean onLongClick(View v) {
 +                Toast.makeText(getActivity(), R.string.actionbar_mkdir, Toast.LENGTH_SHORT).show();
 +                return true;
 +            }
 +        });
 +    }
 +
 +    /**
 +     * registers {@link android.view.View.OnClickListener} and {@link android.view.View.OnLongClickListener}
 +     * on the Upload from App mini FAB for the linked action and {@link Toast} showing the underlying action.
 +     */
 +    private void registerFabUploadFromAppListeners() {
 +        getFabUploadFromApp().setOnClickListener(new View.OnClickListener() {
 +            @Override
 +            public void onClick(View v) {
 +                Intent action = new Intent(Intent.ACTION_GET_CONTENT);
 +                action = action.setType("*/*").addCategory(Intent.CATEGORY_OPENABLE);
 +
 +                //Intent.EXTRA_ALLOW_MULTIPLE is only supported on api level 18+, Jelly Bean
 +                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
 +                    action.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
 +                }
 +
 +                getActivity().startActivityForResult(
 +                        Intent.createChooser(action, getString(R.string.upload_chooser_title)),
 +                        UploadSourceDialogFragment.ACTION_SELECT_CONTENT_FROM_APPS
 +                );
 +                getFabMain().collapse();
 +                recordMiniFabClick();
 +            }
 +        });
 +
 +        getFabUploadFromApp().setOnLongClickListener(new View.OnLongClickListener() {
 +            @Override
 +            public boolean onLongClick(View v) {
 +                Toast.makeText(getActivity(),
 +                        R.string.actionbar_upload_from_apps,
 +                        Toast.LENGTH_SHORT).show();
 +                return true;
 +            }
 +        });
 +    }
 +
 +    /**
 +     * records a click on a mini FAB and thus:
 +     * <ol>
 +     *     <li>persists the click fact</li>
 +     *     <li>removes the mini FAB labels</li>
 +     * </ol>
 +     */
 +    private void recordMiniFabClick() {
 +        // only record if it hasn't been done already at some other time
 +        if(!miniFabClicked) {
 +            final SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getActivity());
 +            sp.edit().putLong(KEY_FAB_EVER_CLICKED, 1).commit();
 +            miniFabClicked = true;
 +        }
 +    }
 +
 +    /**
 +     * removes the labels on all known min FABs.
 +     */
 +    private void removeFabLabels() {
 +        getFabUpload().setTitle(null);
 +        getFabMkdir().setTitle(null);
 +        getFabUploadFromApp().setTitle(null);
 +        ((TextView) getFabUpload().getTag(com.getbase.floatingactionbutton.R.id.fab_label)).setVisibility(View.GONE);
 +        ((TextView) getFabMkdir().getTag(com.getbase.floatingactionbutton.R.id.fab_label)).setVisibility(View.GONE);
 +        ((TextView) getFabUploadFromApp().getTag(com.getbase.floatingactionbutton.R.id.fab_label)).setVisibility(View.GONE);
 +    }
 +
      private void registerLongClickListener() {
          getListView().setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
              public boolean onItemLongClick(AdapterView<?> arg0, View v,
          });
      }
  
 -
      private void showFileAction(int fileIndex) {
          Bundle args = getArguments();
          PopupMenu pm = new PopupMenu(getActivity(),null);
  
      /**
       * Call this, when the user presses the up button.
 -     *
 -     * Tries to move up the current folder one level. If the parent folder was removed from the
 -     * database, it continues browsing up until finding an existing folders.
 -     * <p/>
 -     * return       Count of folder levels browsed up.
 +     * <p>
 +     *     Tries to move up the current folder one level. If the parent folder was removed from the
 +     *     database, it continues browsing up until finding an existing folders.
 +     * </p>
 +     * @return Count of folder levels browsed up.
       */
      public int onBrowseUp() {
          OCFile parentDir = null;
                  mContainerActivity.getFileOperationsHelper().syncFile(mTargetFile);
                  return true;
              }
-             case R.id.action_cancel_download:
-             case R.id.action_cancel_upload: {
-                 ((FileDisplayActivity) mContainerActivity).cancelTransference(mTargetFile);
+             case R.id.action_cancel_sync: {
+                 ((FileDisplayActivity)mContainerActivity).cancelTransference(mTargetFile);
                  return true;
              }
              case R.id.action_see_details: {
@@@ -37,7 -37,6 +37,7 @@@ import com.owncloud.android.MainApp
  import com.owncloud.android.R;\r
  import com.owncloud.android.datamodel.OCFile;\r
  \r
 +import java.math.BigDecimal;\r
  import java.net.IDN;\r
  import java.text.DateFormat;\r
  import java.util.Calendar;\r
@@@ -53,7 -52,6 +53,7 @@@ public class DisplayUtils 
      private static final String OWNCLOUD_APP_NAME = "ownCloud";\r
      \r
      private static final String[] sizeSuffixes = { "B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" };\r
 +    private static final int[] sizeScales = { 0, 0, 0, 1, 1, 2, 2, 2, 2 };\r
  \r
      private static Map<String, String> mimeType2HumanReadable;\r
  \r
  \r
      /**\r
       * Converts the file size in bytes to human readable output.\r
 -     * \r
 +     * <ul>\r
 +     *     <li>appends a size suffix, e.g. B, KB, MB etc.</li>\r
 +     *     <li>rounds the size based on the suffix to 0,1 or 2 decimals</li>\r
 +     * </ul>\r
 +     *\r
       * @param bytes Input file size\r
       * @return Like something readable like "12 MB"\r
       */\r
      public static String bytesToHumanReadable(long bytes) {\r
          double result = bytes;\r
 -        int attachedsuff = 0;\r
 -        while (result > 1024 && attachedsuff < sizeSuffixes.length) {\r
 +        int attachedSuff = 0;\r
 +        while (result > 1024 && attachedSuff < sizeSuffixes.length) {\r
              result /= 1024.;\r
 -            attachedsuff++;\r
 +            attachedSuff++;\r
          }\r
 -        result = ((int) (result * 100)) / 100.;\r
 -        return result + " " + sizeSuffixes[attachedsuff];\r
 +\r
 +        return new BigDecimal(result).setScale(\r
 +                sizeScales[attachedSuff], BigDecimal.ROUND_HALF_UP) + " " + sizeSuffixes[attachedSuff];\r
      }\r
  \r
      /**\r
          else if ((System.currentTimeMillis() - time) < 60 * 1000) {\r
              return c.getString(R.string.file_list_seconds_ago);\r
          } else {\r
-             // Workaround 2.x bug (see https://github.com/owncloud/android/issues/716)\r
-             if (    Build.VERSION.SDK_INT <= Build.VERSION_CODES.HONEYCOMB && \r
-                     (System.currentTimeMillis() - time) > 24 * 60 * 60 * 1000   ) {\r
-                 Date date = new Date(time);\r
-                 date.setHours(0);\r
-                 date.setMinutes(0);\r
-                 date.setSeconds(0);\r
-                 dateString = DateUtils.getRelativeDateTimeString(\r
-                         c, date.getTime(), minResolution, transitionResolution, flags\r
-                 );\r
-             } else {\r
-                 dateString = DateUtils.getRelativeDateTimeString(c, time, minResolution, transitionResolution, flags);\r
-             }\r
+             dateString = DateUtils.getRelativeDateTimeString(c, time, minResolution, transitionResolution, flags);\r
          }\r
  \r
          String[] parts = dateString.toString().split(",");\r
                  return parts[1];\r
              }\r
          }\r
-         //dateString contains unexpected format. use localized, absolute date.\r
-         return DisplayUtils.unixTimeToHumanReadable(time);\r
+         //dateString contains unexpected format. fallback: use relative date time string from android api as is.\r
+         return dateString.toString();\r
      }\r
  \r
      /**\r