1 /* ownCloud Android client application 
   2  *   Copyright (C) 2011  Bartek Przybylski 
   3  *   Copyright (C) 2012-2013 ownCloud Inc. 
   5  *   This program is free software: you can redistribute it and/or modify 
   6  *   it under the terms of the GNU General Public License version 2, 
   7  *   as published by the Free Software Foundation. 
   9  *   This program is distributed in the hope that it will be useful, 
  10  *   but WITHOUT ANY WARRANTY; without even the implied warranty of 
  11  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
  12  *   GNU General Public License for more details. 
  14  *   You should have received a copy of the GNU General Public License 
  15  *   along with this program.  If not, see <http://www.gnu.org/licenses/>. 
  18 package com
.owncloud
.android
.ui
.fragment
; 
  21 import java
.lang
.ref
.WeakReference
; 
  22 import java
.util
.ArrayList
; 
  23 import java
.util
.List
; 
  25 import android
.accounts
.Account
; 
  26 import android
.app
.Activity
; 
  27 import android
.content
.BroadcastReceiver
; 
  28 import android
.content
.Context
; 
  29 import android
.content
.Intent
; 
  30 import android
.content
.IntentFilter
; 
  31 import android
.os
.Bundle
; 
  32 import android
.os
.Handler
; 
  33 import android
.view
.LayoutInflater
; 
  34 import android
.view
.View
; 
  35 import android
.view
.View
.OnClickListener
; 
  36 import android
.view
.ViewGroup
; 
  37 import android
.widget
.CheckBox
; 
  38 import android
.widget
.ImageView
; 
  39 import android
.widget
.ProgressBar
; 
  40 import android
.widget
.TextView
; 
  41 import android
.widget
.Toast
; 
  43 import com
.actionbarsherlock
.view
.Menu
; 
  44 import com
.actionbarsherlock
.view
.MenuInflater
; 
  45 import com
.actionbarsherlock
.view
.MenuItem
; 
  46 import com
.owncloud
.android
.DisplayUtils
; 
  47 import com
.owncloud
.android
.Log_OC
; 
  48 import com
.owncloud
.android
.R
; 
  49 import com
.owncloud
.android
.datamodel
.FileDataStorageManager
; 
  50 import com
.owncloud
.android
.datamodel
.OCFile
; 
  51 import com
.owncloud
.android
.files
.services
.FileDownloader
.FileDownloaderBinder
; 
  52 import com
.owncloud
.android
.files
.services
.FileObserverService
; 
  53 import com
.owncloud
.android
.files
.services
.FileUploader
; 
  54 import com
.owncloud
.android
.files
.services
.FileUploader
.FileUploaderBinder
; 
  55 import com
.owncloud
.android
.operations
.OnRemoteOperationListener
; 
  56 import com
.owncloud
.android
.operations
.RemoteOperation
; 
  57 import com
.owncloud
.android
.operations
.RemoteOperationResult
; 
  58 import com
.owncloud
.android
.operations
.RemoteOperationResult
.ResultCode
; 
  59 import com
.owncloud
.android
.operations
.RemoveFileOperation
; 
  60 import com
.owncloud
.android
.operations
.RenameFileOperation
; 
  61 import com
.owncloud
.android
.operations
.SynchronizeFileOperation
; 
  62 import com
.owncloud
.android
.ui
.activity
.ConflictsResolveActivity
; 
  63 import com
.owncloud
.android
.ui
.activity
.FileActivity
; 
  64 import com
.owncloud
.android
.ui
.activity
.FileDisplayActivity
; 
  65 import com
.owncloud
.android
.ui
.dialog
.EditNameDialog
; 
  66 import com
.owncloud
.android
.ui
.dialog
.EditNameDialog
.EditNameDialogListener
; 
  68 import eu
.alefzero
.webdav
.OnDatatransferProgressListener
; 
  71  * This Fragment is used to display the details about a file. 
  73  * @author Bartek Przybylski 
  74  * @author David A. Velasco 
  76 public class FileDetailFragment 
extends FileFragment 
implements 
  78         ConfirmationDialogFragment
.ConfirmationDialogFragmentListener
, OnRemoteOperationListener
, EditNameDialogListener 
{ 
  80     private FileFragment
.ContainerActivity mContainerActivity
; 
  84     private Account mAccount
; 
  85     private FileDataStorageManager mStorageManager
; 
  87     private UploadFinishReceiver mUploadFinishReceiver
; 
  88     public ProgressListener mProgressListener
; 
  90     private Handler mHandler
; 
  91     private RemoteOperation mLastRemoteOperation
; 
  93     private static final String TAG 
= FileDetailFragment
.class.getSimpleName(); 
  94     public static final String FTAG_CONFIRMATION 
= "REMOVE_CONFIRMATION_FRAGMENT"; 
  98      * Creates an empty details fragment. 
 100      * It's necessary to keep a public constructor without parameters; the system uses it when tries to reinstantiate a fragment automatically.  
 102     public FileDetailFragment() { 
 105         mStorageManager 
= null
; 
 106         mLayout 
= R
.layout
.file_details_empty
; 
 107         mProgressListener 
= null
; 
 111      * Creates a details fragment. 
 113      * When 'fileToDetail' or 'ocAccount' are null, creates a dummy layout (to use when a file wasn't tapped before). 
 115      * @param fileToDetail      An {@link OCFile} to show in the fragment 
 116      * @param ocAccount         An ownCloud account; needed to start downloads 
 118     public FileDetailFragment(OCFile fileToDetail
, Account ocAccount
) { 
 120         mAccount 
= ocAccount
; 
 121         mStorageManager 
= null
; // we need a context to init this; the container activity is not available yet at this moment  
 122         mLayout 
= R
.layout
.file_details_empty
; 
 123         mProgressListener 
= null
; 
 128     public void onCreate(Bundle savedInstanceState
) { 
 129         super.onCreate(savedInstanceState
); 
 130         mHandler 
= new Handler(); 
 131         setHasOptionsMenu(true
); 
 136     public View 
onCreateView(LayoutInflater inflater
, ViewGroup container
, 
 137             Bundle savedInstanceState
) { 
 138         //super.onCreateView(inflater, container, savedInstanceState); 
 140         if (savedInstanceState 
!= null
) { 
 141             setFile((OCFile
)savedInstanceState
.getParcelable(FileActivity
.EXTRA_FILE
)); 
 142             mAccount 
= savedInstanceState
.getParcelable(FileActivity
.EXTRA_ACCOUNT
); 
 145         if(getFile() != null 
&& mAccount 
!= null
) { 
 146             mLayout 
= R
.layout
.file_details_fragment
; 
 150         //view = inflater.inflate(mLayout, container, false); 
 151         view 
= inflater
.inflate(mLayout
, null
); 
 154         if (mLayout 
== R
.layout
.file_details_fragment
) { 
 155             mView
.findViewById(R
.id
.fdKeepInSync
).setOnClickListener(this); 
 156             ProgressBar progressBar 
= (ProgressBar
)mView
.findViewById(R
.id
.fdProgressBar
); 
 157             mProgressListener 
= new ProgressListener(progressBar
); 
 158             mView
.findViewById(R
.id
.fdCancelBtn
).setOnClickListener(this); 
 161         updateFileDetails(false
, false
); 
 169     public void onAttach(Activity activity
) { 
 170         super.onAttach(activity
); 
 172             mContainerActivity 
= (ContainerActivity
) activity
; 
 174         } catch (ClassCastException e
) { 
 175             throw new ClassCastException(activity
.toString() + " must implement " + FileDetailFragment
.ContainerActivity
.class.getSimpleName()); 
 184     public void onActivityCreated(Bundle savedInstanceState
) { 
 185         super.onActivityCreated(savedInstanceState
); 
 186         if (mAccount 
!= null
) { 
 187             mStorageManager 
= new FileDataStorageManager(mAccount
, getActivity().getApplicationContext().getContentResolver()); 
 193     public void onSaveInstanceState(Bundle outState
) { 
 194         super.onSaveInstanceState(outState
); 
 195         outState
.putParcelable(FileActivity
.EXTRA_FILE
, getFile()); 
 196         outState
.putParcelable(FileActivity
.EXTRA_ACCOUNT
, mAccount
); 
 200     public void onStart() { 
 202         listenForTransferProgress(); 
 206     public void onResume() { 
 208         mUploadFinishReceiver 
= new UploadFinishReceiver(); 
 209         IntentFilter filter 
= new IntentFilter(FileUploader
.UPLOAD_FINISH_MESSAGE
); 
 210         getActivity().registerReceiver(mUploadFinishReceiver
, filter
); 
 216     public void onPause() { 
 218         if (mUploadFinishReceiver 
!= null
) { 
 219             getActivity().unregisterReceiver(mUploadFinishReceiver
); 
 220             mUploadFinishReceiver 
= null
; 
 226     public void onStop() { 
 228         leaveTransferProgress(); 
 233     public View 
getView() { 
 234         return super.getView() == null ? mView 
: super.getView(); 
 242     public void onCreateOptionsMenu(Menu menu
, MenuInflater inflater
) { 
 243         super.onCreateOptionsMenu(menu
, inflater
); 
 244         inflater
.inflate(R
.menu
.file_actions_menu
, menu
); 
 245         MenuItem item 
= menu
.findItem(R
.id
.action_see_details
); 
 247             item
.setVisible(false
); 
 248             item
.setEnabled(false
); 
 257     public void onPrepareOptionsMenu (Menu menu
) { 
 258         super.onPrepareOptionsMenu(menu
); 
 260         List
<Integer
> toHide 
= new ArrayList
<Integer
>(); 
 261         List
<Integer
> toShow 
= new ArrayList
<Integer
>(); 
 262         OCFile file 
= getFile(); 
 264         FileDownloaderBinder downloaderBinder 
= mContainerActivity
.getFileDownloaderBinder(); 
 265         boolean downloading 
= downloaderBinder 
!= null 
&& downloaderBinder
.isDownloading(mAccount
, file
); 
 266         FileUploaderBinder uploaderBinder 
= mContainerActivity
.getFileUploaderBinder(); 
 267         boolean uploading 
= uploaderBinder 
!= null 
&& uploaderBinder
.isUploading(mAccount
, getFile()); 
 269         if (downloading 
|| uploading
) { 
 270             toHide
.add(R
.id
.action_download_file
); 
 271             toHide
.add(R
.id
.action_rename_file
); 
 272             toHide
.add(R
.id
.action_remove_file
); 
 273             toHide
.add(R
.id
.action_open_file_with
); 
 275                 toHide
.add(R
.id
.action_cancel_download
); 
 276                 toShow
.add(R
.id
.action_cancel_upload
); 
 278                 toHide
.add(R
.id
.action_cancel_upload
); 
 279                 toShow
.add(R
.id
.action_cancel_download
); 
 282         } else if (file 
!= null 
&& file
.isDown()) { 
 283             toHide
.add(R
.id
.action_download_file
); 
 284             toHide
.add(R
.id
.action_cancel_download
); 
 285             toHide
.add(R
.id
.action_cancel_upload
); 
 287             toShow
.add(R
.id
.action_rename_file
); 
 288             toShow
.add(R
.id
.action_remove_file
); 
 289             toShow
.add(R
.id
.action_open_file_with
); 
 290             toShow
.add(R
.id
.action_sync_file
); 
 292         } else if (file 
!= null
) { 
 293             toHide
.add(R
.id
.action_open_file_with
); 
 294             toHide
.add(R
.id
.action_cancel_download
); 
 295             toHide
.add(R
.id
.action_cancel_upload
); 
 296             toHide
.add(R
.id
.action_sync_file
); 
 298             toShow
.add(R
.id
.action_rename_file
); 
 299             toShow
.add(R
.id
.action_remove_file
); 
 300             toShow
.add(R
.id
.action_download_file
); 
 303             toHide
.add(R
.id
.action_open_file_with
); 
 304             toHide
.add(R
.id
.action_cancel_download
); 
 305             toHide
.add(R
.id
.action_cancel_upload
); 
 306             toHide
.add(R
.id
.action_sync_file
); 
 307             toHide
.add(R
.id
.action_download_file
); 
 308             toHide
.add(R
.id
.action_rename_file
); 
 309             toHide
.add(R
.id
.action_remove_file
); 
 313         MenuItem item 
= null
; 
 314         for (int i 
: toHide
) { 
 315             item 
= menu
.findItem(i
); 
 317                 item
.setVisible(false
); 
 318                 item
.setEnabled(false
); 
 321         for (int i 
: toShow
) { 
 322             item 
= menu
.findItem(i
); 
 324                 item
.setVisible(true
); 
 325                 item
.setEnabled(true
); 
 335     public boolean onOptionsItemSelected(MenuItem item
) { 
 336         switch (item
.getItemId()) { 
 337             case R
.id
.action_open_file_with
: { 
 338                 mContainerActivity
.openFile(getFile()); 
 341             case R
.id
.action_remove_file
: { 
 345             case R
.id
.action_rename_file
: { 
 349             case R
.id
.action_download_file
:  
 350             case R
.id
.action_cancel_download
: 
 351             case R
.id
.action_cancel_upload
: 
 352             case R
.id
.action_sync_file
: { 
 362     public void onClick(View v
) { 
 364             case R
.id
.fdKeepInSync
: { 
 368             case R
.id
.fdCancelBtn
: { 
 373                 Log_OC
.e(TAG
, "Incorrect view clicked!"); 
 378     private void toggleKeepInSync() { 
 379         CheckBox cb 
= (CheckBox
) getView().findViewById(R
.id
.fdKeepInSync
); 
 380         OCFile file 
= getFile(); 
 381         file
.setKeepInSync(cb
.isChecked()); 
 382         mStorageManager
.saveFile(file
); 
 384         /// register the OCFile instance in the observer service to monitor local updates; 
 385         /// if necessary, the file is download  
 386         Intent intent 
= new Intent(getActivity().getApplicationContext(), 
 387                                    FileObserverService
.class); 
 388         intent
.putExtra(FileObserverService
.KEY_FILE_CMD
, 
 390                            FileObserverService
.CMD_ADD_OBSERVED_FILE
: 
 391                            FileObserverService
.CMD_DEL_OBSERVED_FILE
)); 
 392         intent
.putExtra(FileObserverService
.KEY_CMD_ARG_FILE
, file
); 
 393         intent
.putExtra(FileObserverService
.KEY_CMD_ARG_ACCOUNT
, mAccount
); 
 394         getActivity().startService(intent
); 
 396         if (file
.keepInSync()) { 
 397             synchronizeFile();   // force an immediate synchronization 
 402     private void removeFile() { 
 403         OCFile file 
= getFile(); 
 404         ConfirmationDialogFragment confDialog 
= ConfirmationDialogFragment
.newInstance( 
 405                 R
.string
.confirmation_remove_alert
, 
 406                 new String
[]{file
.getFileName()}, 
 407                 file
.isDown() ? R
.string
.confirmation_remove_remote_and_local 
: R
.string
.confirmation_remove_remote
, 
 408                 file
.isDown() ? R
.string
.confirmation_remove_local 
: -1, 
 409                 R
.string
.common_cancel
); 
 410         confDialog
.setOnConfirmationListener(this); 
 411         confDialog
.show(getFragmentManager(), FTAG_CONFIRMATION
); 
 415     private void renameFile() { 
 416         OCFile file 
= getFile(); 
 417         String fileName 
= file
.getFileName(); 
 418         int extensionStart 
= file
.isFolder() ? 
-1 : fileName
.lastIndexOf("."); 
 419         int selectionEnd 
= (extensionStart 
>= 0) ? extensionStart 
: fileName
.length(); 
 420         EditNameDialog dialog 
= EditNameDialog
.newInstance(getString(R
.string
.rename_dialog_title
), fileName
, 0, selectionEnd
, this); 
 421         dialog
.show(getFragmentManager(), "nameeditdialog"); 
 424     private void synchronizeFile() { 
 425         OCFile file 
= getFile(); 
 426         FileDownloaderBinder downloaderBinder 
= mContainerActivity
.getFileDownloaderBinder(); 
 427         FileUploaderBinder uploaderBinder 
= mContainerActivity
.getFileUploaderBinder(); 
 428         if (downloaderBinder 
!= null 
&& downloaderBinder
.isDownloading(mAccount
, file
)) { 
 429             downloaderBinder
.cancel(mAccount
, file
); 
 433                 setButtonsForRemote(); 
 436         } else if (uploaderBinder 
!= null 
&& uploaderBinder
.isUploading(mAccount
, file
)) { 
 437             uploaderBinder
.cancel(mAccount
, file
); 
 438             if (!file
.fileExists()) { 
 439                 // TODO make something better 
 440                 ((FileDisplayActivity
)getActivity()).cleanSecondFragment(); 
 442             } else if (file
.isDown()) { 
 445                 setButtonsForRemote(); 
 449             mLastRemoteOperation 
= new SynchronizeFileOperation(file
, null
, mStorageManager
, mAccount
, true
, false
, getActivity()); 
 450             mLastRemoteOperation
.execute(mAccount
, getSherlockActivity(), this, mHandler
, getSherlockActivity()); 
 453             ((FileDisplayActivity
) getActivity()).showLoadingDialog(); 
 459     public void onConfirmation(String callerTag
) { 
 460         OCFile file 
= getFile(); 
 461         if (callerTag
.equals(FTAG_CONFIRMATION
)) { 
 462             if (mStorageManager
.getFileById(file
.getFileId()) != null
) { 
 463                 mLastRemoteOperation 
= new RemoveFileOperation( file
,  
 466                 mLastRemoteOperation
.execute(mAccount
, getSherlockActivity(), this, mHandler
, getSherlockActivity()); 
 468                 ((FileDisplayActivity
) getActivity()).showLoadingDialog(); 
 474     public void onNeutral(String callerTag
) { 
 476         OCFile file 
= getFile(); 
 477         if (file
.isDown() && (f 
= new File(file
.getStoragePath())).exists()) { 
 479             file
.setStoragePath(null
); 
 480             mStorageManager
.saveFile(file
); 
 481             updateFileDetails(file
, mAccount
); 
 486     public void onCancel(String callerTag
) { 
 487         Log_OC
.d(TAG
, "REMOVAL CANCELED"); 
 492      * Check if the fragment was created with an empty layout. An empty fragment can't show file details, must be replaced. 
 494      * @return  True when the fragment was created with the empty layout. 
 496     public boolean isEmpty() { 
 497         return (mLayout 
== R
.layout
.file_details_empty 
|| getFile() == null 
|| mAccount 
== null
); 
 502      * Use this method to signal this Activity that it shall update its view. 
 504      * @param file : An {@link OCFile} 
 506     public void updateFileDetails(OCFile file
, Account ocAccount
) { 
 508         if (ocAccount 
!= null 
&& (  
 509                 mStorageManager 
== null 
||  
 510                 (mAccount 
!= null 
&& !mAccount
.equals(ocAccount
)) 
 512             mStorageManager 
= new FileDataStorageManager(ocAccount
, getActivity().getApplicationContext().getContentResolver()); 
 514         mAccount 
= ocAccount
; 
 515         updateFileDetails(false
, false
); 
 519      * Updates the view with all relevant details about that file. 
 521      * TODO Remove parameter when the transferring state of files is kept in database.  
 523      * TODO REFACTORING! this method called 5 times before every time the fragment is shown!  
 525      * @param transferring      Flag signaling if the file should be considered as downloading or uploading,  
 526      *                          although {@link FileDownloaderBinder#isDownloading(Account, OCFile)}  and  
 527      *                          {@link FileUploaderBinder#isUploading(Account, OCFile)} return false. 
 529      * @param refresh           If 'true', try to refresh the hold file from the database 
 531     public void updateFileDetails(boolean transferring
, boolean refresh
) { 
 535             if (refresh 
&& mStorageManager 
!= null
) { 
 536                 setFile(mStorageManager
.getFileByPath(getFile().getRemotePath())); 
 538             OCFile file 
= getFile(); 
 541             setFilename(file
.getFileName()); 
 542             setFiletype(file
.getMimetype()); 
 543             setFilesize(file
.getFileLength()); 
 544             if(ocVersionSupportsTimeCreated()){ 
 545                 setTimeCreated(file
.getCreationTimestamp()); 
 548             setTimeModified(file
.getModificationTimestamp()); 
 550             CheckBox cb 
= (CheckBox
)getView().findViewById(R
.id
.fdKeepInSync
); 
 551             cb
.setChecked(file
.keepInSync()); 
 553             // configure UI for depending upon local state of the file 
 554             //if (FileDownloader.isDownloading(mAccount, mFile.getRemotePath()) || FileUploader.isUploading(mAccount, mFile.getRemotePath())) { 
 555             FileDownloaderBinder downloaderBinder 
= mContainerActivity
.getFileDownloaderBinder(); 
 556             FileUploaderBinder uploaderBinder 
= mContainerActivity
.getFileUploaderBinder(); 
 557             if (transferring 
|| (downloaderBinder 
!= null 
&& downloaderBinder
.isDownloading(mAccount
, file
)) || (uploaderBinder 
!= null 
&& uploaderBinder
.isUploading(mAccount
, file
))) { 
 558                 setButtonsForTransferring(); 
 560             } else if (file
.isDown()) { 
 565                 // TODO load default preview image; when the local file is removed, the preview remains there 
 566                 setButtonsForRemote(); 
 569         getView().invalidate(); 
 573      * Checks if the fragment is ready to show details of a OCFile 
 575      * @return  'True' when the fragment is ready to show details of a file 
 577     private boolean readyToShow() { 
 578         return (getFile() != null 
&& mAccount 
!= null 
&& mLayout 
== R
.layout
.file_details_fragment
);         
 583      * Updates the filename in view 
 584      * @param filename to set 
 586     private void setFilename(String filename
) { 
 587         TextView tv 
= (TextView
) getView().findViewById(R
.id
.fdFilename
); 
 589             tv
.setText(filename
); 
 593      * Updates the MIME type in view 
 594      * @param mimetype to set 
 596     private void setFiletype(String mimetype
) { 
 597         TextView tv 
= (TextView
) getView().findViewById(R
.id
.fdType
); 
 599             String printableMimetype 
= DisplayUtils
.convertMIMEtoPrettyPrint(mimetype
);;         
 600             tv
.setText(printableMimetype
); 
 602         ImageView iv 
= (ImageView
) getView().findViewById(R
.id
.fdIcon
); 
 604             iv
.setImageResource(DisplayUtils
.getResourceId(mimetype
)); 
 609      * Updates the file size in view 
 610      * @param filesize in bytes to set 
 612     private void setFilesize(long filesize
) { 
 613         TextView tv 
= (TextView
) getView().findViewById(R
.id
.fdSize
); 
 615             tv
.setText(DisplayUtils
.bytesToHumanReadable(filesize
)); 
 619      * Updates the time that the file was created in view 
 620      * @param milliseconds Unix time to set 
 622     private void setTimeCreated(long milliseconds
){ 
 623         TextView tv 
= (TextView
) getView().findViewById(R
.id
.fdCreated
); 
 624         TextView tvLabel 
= (TextView
) getView().findViewById(R
.id
.fdCreatedLabel
); 
 626             tv
.setText(DisplayUtils
.unixTimeToHumanReadable(milliseconds
)); 
 627             tv
.setVisibility(View
.VISIBLE
); 
 628             tvLabel
.setVisibility(View
.VISIBLE
); 
 633      * Updates the time that the file was last modified 
 634      * @param milliseconds Unix time to set 
 636     private void setTimeModified(long milliseconds
){ 
 637         TextView tv 
= (TextView
) getView().findViewById(R
.id
.fdModified
); 
 639             tv
.setText(DisplayUtils
.unixTimeToHumanReadable(milliseconds
)); 
 644      * Enables or disables buttons for a file being downloaded 
 646     private void setButtonsForTransferring() { 
 648             // let's protect the user from himself ;) 
 649             getView().findViewById(R
.id
.fdKeepInSync
).setEnabled(false
); 
 651             // show the progress bar for the transfer 
 652             getView().findViewById(R
.id
.fdProgressBlock
).setVisibility(View
.VISIBLE
); 
 653             TextView progressText 
= (TextView
)getView().findViewById(R
.id
.fdProgressText
); 
 654             progressText
.setVisibility(View
.VISIBLE
); 
 655             FileDownloaderBinder downloaderBinder 
= mContainerActivity
.getFileDownloaderBinder(); 
 656             FileUploaderBinder uploaderBinder 
= mContainerActivity
.getFileUploaderBinder(); 
 657             if (downloaderBinder 
!= null 
&& downloaderBinder
.isDownloading(mAccount
, getFile())) { 
 658                 progressText
.setText(R
.string
.downloader_download_in_progress_ticker
); 
 659             } else if (uploaderBinder 
!= null 
&& uploaderBinder
.isUploading(mAccount
, getFile())) { 
 660                 progressText
.setText(R
.string
.uploader_upload_in_progress_ticker
); 
 666      * Enables or disables buttons for a file locally available  
 668     private void setButtonsForDown() { 
 670             getView().findViewById(R
.id
.fdKeepInSync
).setEnabled(true
); 
 672             // hides the progress bar 
 673             getView().findViewById(R
.id
.fdProgressBlock
).setVisibility(View
.GONE
); 
 674             TextView progressText 
= (TextView
)getView().findViewById(R
.id
.fdProgressText
); 
 675             progressText
.setVisibility(View
.GONE
); 
 680      * Enables or disables buttons for a file not locally available  
 682     private void setButtonsForRemote() { 
 684             getView().findViewById(R
.id
.fdKeepInSync
).setEnabled(true
); 
 686             // hides the progress bar 
 687             getView().findViewById(R
.id
.fdProgressBlock
).setVisibility(View
.GONE
); 
 688             TextView progressText 
= (TextView
)getView().findViewById(R
.id
.fdProgressText
); 
 689             progressText
.setVisibility(View
.GONE
); 
 695      * In ownCloud 3.X.X and 4.X.X there is a bug that SabreDAV does not return 
 696      * the time that the file was created. There is a chance that this will 
 697      * be fixed in future versions. Use this method to check if this version of 
 698      * ownCloud has this fix. 
 699      * @return True, if ownCloud the ownCloud version is supporting creation time 
 701     private boolean ocVersionSupportsTimeCreated(){ 
 702         /*if(mAccount != null){ 
 703             AccountManager accManager = (AccountManager) getActivity().getSystemService(Context.ACCOUNT_SERVICE); 
 704             OwnCloudVersion ocVersion = new OwnCloudVersion(accManager 
 705                     .getUserData(mAccount, AccountAuthenticator.KEY_OC_VERSION)); 
 706             if(ocVersion.compareTo(new OwnCloudVersion(0x030000)) < 0) { 
 715      * Once the file upload has finished -> update view 
 717      * Being notified about the finish of an upload is necessary for the next sequence: 
 718      *   1. Upload a big file. 
 719      *   2. Force a synchronization; if it finished before the upload, the file in transfer will be included in the local database and in the file list 
 720      *      of its containing folder; the the server includes it in the PROPFIND requests although it's not fully upload.  
 721      *   3. Click the file in the list to see its details. 
 722      *   4. Wait for the upload finishes; at this moment, the details view must be refreshed to enable the action buttons. 
 724     private class UploadFinishReceiver 
extends BroadcastReceiver 
{ 
 726         public void onReceive(Context context
, Intent intent
) { 
 727             String accountName 
= intent
.getStringExtra(FileUploader
.ACCOUNT_NAME
); 
 729             if (!isEmpty() && accountName
.equals(mAccount
.name
)) { 
 730                 boolean uploadWasFine 
= intent
.getBooleanExtra(FileUploader
.EXTRA_UPLOAD_RESULT
, false
); 
 731                 String uploadRemotePath 
= intent
.getStringExtra(FileUploader
.EXTRA_REMOTE_PATH
); 
 732                 boolean renamedInUpload 
= getFile().getRemotePath().equals(intent
.getStringExtra(FileUploader
.EXTRA_OLD_REMOTE_PATH
)); 
 733                 if (getFile().getRemotePath().equals(uploadRemotePath
) || 
 736                         setFile(mStorageManager
.getFileByPath(uploadRemotePath
)); 
 738                     if (renamedInUpload
) { 
 739                         String newName 
= (new File(uploadRemotePath
)).getName(); 
 740                         Toast msg 
= Toast
.makeText(getActivity().getApplicationContext(), String
.format(getString(R
.string
.filedetails_renamed_in_upload_msg
), newName
), Toast
.LENGTH_LONG
); 
 743                     getSherlockActivity().removeStickyBroadcast(intent
);    // not the best place to do this; a small refactorization of BroadcastReceivers should be done 
 744                     updateFileDetails(false
, false
);    // it updates the buttons; must be called although !uploadWasFine; interrupted uploads still leave an incomplete file in the server 
 751     public void onDismiss(EditNameDialog dialog
) { 
 752         if (dialog
.getResult()) { 
 753             String newFilename 
= dialog
.getNewFilename(); 
 754             Log_OC
.d(TAG
, "name edit dialog dismissed with new name " + newFilename
); 
 755             mLastRemoteOperation 
= new RenameFileOperation( getFile(),  
 758                                                             new FileDataStorageManager(mAccount
, getActivity().getContentResolver())); 
 759             mLastRemoteOperation
.execute(mAccount
, getSherlockActivity(), this, mHandler
, getSherlockActivity()); 
 760             ((FileDisplayActivity
) getActivity()).showLoadingDialog(); 
 769     public void onRemoteOperationFinish(RemoteOperation operation
, RemoteOperationResult result
) { 
 770         if (operation
.equals(mLastRemoteOperation
)) { 
 771             if (operation 
instanceof RemoveFileOperation
) { 
 772                 onRemoveFileOperationFinish((RemoveFileOperation
)operation
, result
); 
 774             } else if (operation 
instanceof RenameFileOperation
) { 
 775                 onRenameFileOperationFinish((RenameFileOperation
)operation
, result
); 
 777             } else if (operation 
instanceof SynchronizeFileOperation
) { 
 778                 onSynchronizeFileOperationFinish((SynchronizeFileOperation
)operation
, result
); 
 784     private void onRemoveFileOperationFinish(RemoveFileOperation operation
, RemoteOperationResult result
) { 
 785         ((FileDisplayActivity
) getActivity()).dismissLoadingDialog(); 
 786         if (result
.isSuccess()) { 
 787             Toast msg 
= Toast
.makeText(getActivity().getApplicationContext(), R
.string
.remove_success_msg
, Toast
.LENGTH_LONG
); 
 789             ((FileDisplayActivity
)getActivity()).cleanSecondFragment(); 
 792             Toast msg 
= Toast
.makeText(getActivity(), R
.string
.remove_fail_msg
, Toast
.LENGTH_LONG
);  
 794             if (result
.isSslRecoverableException()) { 
 795                 // TODO show the SSL warning dialog 
 800     private void onRenameFileOperationFinish(RenameFileOperation operation
, RemoteOperationResult result
) { 
 801         ((FileDisplayActivity
) getActivity()).dismissLoadingDialog(); 
 803         if (result
.isSuccess()) { 
 804             updateFileDetails(((RenameFileOperation
)operation
).getFile(), mAccount
); 
 805             mContainerActivity
.onFileStateChanged(); 
 808             if (result
.getCode().equals(ResultCode
.INVALID_LOCAL_FILE_NAME
)) { 
 809                 Toast msg 
= Toast
.makeText(getActivity(), R
.string
.rename_local_fail_msg
, Toast
.LENGTH_LONG
);  
 811                 // TODO throw again the new rename dialog 
 813                 Toast msg 
= Toast
.makeText(getActivity(), R
.string
.rename_server_fail_msg
, Toast
.LENGTH_LONG
);  
 815                 if (result
.isSslRecoverableException()) { 
 816                     // TODO show the SSL warning dialog 
 822     private void onSynchronizeFileOperationFinish(SynchronizeFileOperation operation
, RemoteOperationResult result
) { 
 823         ((FileDisplayActivity
) getActivity()).dismissLoadingDialog(); 
 824         OCFile file 
= getFile(); 
 825         if (!result
.isSuccess()) { 
 826             if (result
.getCode() == ResultCode
.SYNC_CONFLICT
) { 
 827                 Intent i 
= new Intent(getActivity(), ConflictsResolveActivity
.class); 
 828                 i
.putExtra(ConflictsResolveActivity
.EXTRA_FILE
, file
); 
 829                 i
.putExtra(ConflictsResolveActivity
.EXTRA_ACCOUNT
, mAccount
); 
 838                 setButtonsForRemote(); 
 842             if (operation
.transferWasRequested()) { 
 843                 setButtonsForTransferring(); 
 844                 mContainerActivity
.onFileStateChanged();    // this is not working; FileDownloader won't do NOTHING at all until this method finishes, so  
 845                                                             // checking the service to see if the file is downloading results in FALSE 
 847                 Toast msg 
= Toast
.makeText(getActivity(), R
.string
.sync_file_nothing_to_do_msg
, Toast
.LENGTH_LONG
);  
 853                     setButtonsForRemote(); 
 860     public void listenForTransferProgress() { 
 861         if (mProgressListener 
!= null
) { 
 862             if (mContainerActivity
.getFileDownloaderBinder() != null
) { 
 863                 mContainerActivity
.getFileDownloaderBinder().addDatatransferProgressListener(mProgressListener
, mAccount
, getFile()); 
 865             if (mContainerActivity
.getFileUploaderBinder() != null
) { 
 866                 mContainerActivity
.getFileUploaderBinder().addDatatransferProgressListener(mProgressListener
, mAccount
, getFile()); 
 872     public void leaveTransferProgress() { 
 873         if (mProgressListener 
!= null
) { 
 874             if (mContainerActivity
.getFileDownloaderBinder() != null
) { 
 875                 mContainerActivity
.getFileDownloaderBinder().removeDatatransferProgressListener(mProgressListener
, mAccount
, getFile()); 
 877             if (mContainerActivity
.getFileUploaderBinder() != null
) { 
 878                 mContainerActivity
.getFileUploaderBinder().removeDatatransferProgressListener(mProgressListener
, mAccount
, getFile()); 
 886      * Helper class responsible for updating the progress bar shown for file uploading or downloading   
 888      * @author David A. Velasco 
 890     private class ProgressListener 
implements OnDatatransferProgressListener 
{ 
 891         int mLastPercent 
= 0; 
 892         WeakReference
<ProgressBar
> mProgressBar 
= null
; 
 894         ProgressListener(ProgressBar progressBar
) { 
 895             mProgressBar 
= new WeakReference
<ProgressBar
>(progressBar
); 
 899         public void onTransferProgress(long progressRate
) { 
 900             // old method, nothing here 
 904         public void onTransferProgress(long progressRate
, long totalTransferredSoFar
, long totalToTransfer
, String filename
) { 
 905             int percent 
= (int)(100.0*((double)totalTransferredSoFar
)/((double)totalToTransfer
)); 
 906             if (percent 
!= mLastPercent
) { 
 907                 ProgressBar pb 
= mProgressBar
.get(); 
 909                     pb
.setProgress(percent
); 
 913             mLastPercent 
= percent
;