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
.activity
; 
  20 import android
.accounts
.Account
; 
  21 import android
.app
.Dialog
; 
  22 import android
.app
.ProgressDialog
; 
  23 import android
.content
.BroadcastReceiver
; 
  24 import android
.content
.ComponentName
; 
  25 import android
.content
.Context
; 
  26 import android
.content
.Intent
; 
  27 import android
.content
.IntentFilter
; 
  28 import android
.content
.ServiceConnection
; 
  29 import android
.content
.res
.Configuration
; 
  30 import android
.os
.Bundle
; 
  31 import android
.os
.IBinder
; 
  32 import android
.support
.v4
.app
.Fragment
; 
  33 import android
.support
.v4
.app
.FragmentTransaction
; 
  34 import android
.util
.Log
; 
  36 import com
.actionbarsherlock
.app
.ActionBar
; 
  37 import com
.actionbarsherlock
.app
.SherlockFragmentActivity
; 
  38 import com
.actionbarsherlock
.view
.MenuItem
; 
  39 import com
.owncloud
.android
.datamodel
.FileDataStorageManager
; 
  40 import com
.owncloud
.android
.datamodel
.OCFile
; 
  41 import com
.owncloud
.android
.files
.services
.FileDownloader
; 
  42 import com
.owncloud
.android
.files
.services
.FileDownloader
.FileDownloaderBinder
; 
  43 import com
.owncloud
.android
.files
.services
.FileUploader
; 
  44 import com
.owncloud
.android
.files
.services
.FileUploader
.FileUploaderBinder
; 
  45 import com
.owncloud
.android
.ui
.fragment
.FileDetailFragment
; 
  46 import com
.owncloud
.android
.ui
.fragment
.FileFragment
; 
  47 import com
.owncloud
.android
.ui
.preview
.PreviewMediaFragment
; 
  48 import com
.owncloud
.android
.AccountUtils
; 
  49 import com
.owncloud
.android
.Log_OC
; 
  51 import com
.owncloud
.android
.R
; 
  54  * This activity displays the details of a file like its name, its size and so 
  57  * @author Bartek Przybylski 
  58  * @author David A. Velasco 
  60 public class FileDetailActivity 
extends SherlockFragmentActivity 
implements FileFragment
.ContainerActivity 
{ 
  62     public static final int DIALOG_SHORT_WAIT 
= 0; 
  64     public static final String TAG 
= FileDetailActivity
.class.getSimpleName(); 
  66     public static final String EXTRA_MODE 
= "MODE"; 
  67     public static final int MODE_DETAILS 
= 0; 
  68     public static final int MODE_PREVIEW 
= 1; 
  70     public static final String KEY_WAITING_TO_PREVIEW 
= "WAITING_TO_PREVIEW"; 
  72     private boolean mConfigurationChangedToLandscape 
= false
; 
  73     private FileDownloaderBinder mDownloaderBinder 
= null
; 
  74     private ServiceConnection mDownloadConnection
, mUploadConnection 
= null
; 
  75     private FileUploaderBinder mUploaderBinder 
= null
; 
  76     private boolean mWaitingToPreview
; 
  79     private Account mAccount
; 
  81     private FileDataStorageManager mStorageManager
; 
  82     private DownloadFinishReceiver mDownloadFinishReceiver
; 
  86     protected void onCreate(Bundle savedInstanceState
) { 
  87         super.onCreate(savedInstanceState
); 
  89         mFile 
= getIntent().getParcelableExtra(FileDetailFragment
.EXTRA_FILE
); 
  90         mAccount 
= getIntent().getParcelableExtra(FileDetailFragment
.EXTRA_ACCOUNT
); 
  91         mStorageManager 
= new FileDataStorageManager(mAccount
, getContentResolver()); 
  93         // check if configuration changed to large-land ; for a tablet being changed from portrait to landscape when in FileDetailActivity  
  94         Configuration conf 
= getResources().getConfiguration(); 
  95         mConfigurationChangedToLandscape 
= (conf
.orientation 
== Configuration
.ORIENTATION_LANDSCAPE 
&&  
  96                                                 (conf
.screenLayout 
& Configuration
.SCREENLAYOUT_SIZE_MASK
) >= Configuration
.SCREENLAYOUT_SIZE_LARGE
 
  99         if (!mConfigurationChangedToLandscape
) { 
 100             setContentView(R
.layout
.file_activity_details
); 
 102             ActionBar actionBar 
= getSupportActionBar(); 
 103             actionBar
.setDisplayHomeAsUpEnabled(true
); 
 105             if (savedInstanceState 
== null
) { 
 106                 mWaitingToPreview 
= false
; 
 107                 createChildFragment(); 
 109                 mWaitingToPreview 
= savedInstanceState
.getBoolean(KEY_WAITING_TO_PREVIEW
); 
 112             mDownloadConnection 
= new DetailsServiceConnection(); 
 113             bindService(new Intent(this, FileDownloader
.class), mDownloadConnection
, Context
.BIND_AUTO_CREATE
); 
 114             mUploadConnection 
= new DetailsServiceConnection(); 
 115             bindService(new Intent(this, FileUploader
.class), mUploadConnection
, Context
.BIND_AUTO_CREATE
); 
 119             backToDisplayActivity(false
);   // the 'back' won't be effective until this.onStart() and this.onResume() are completed; 
 125      * Creates the proper fragment depending upon the state of the handled {@link OCFile} and 
 126      * the requested {@link Intent}. 
 128     private void createChildFragment() { 
 129         int mode 
= getIntent().getIntExtra(EXTRA_MODE
, MODE_PREVIEW
);  
 131         Fragment newFragment 
= null
; 
 132         if (PreviewMediaFragment
.canBePreviewed(mFile
) && mode 
== MODE_PREVIEW
) { 
 133             if (mFile
.isDown()) { 
 134                 newFragment 
= new PreviewMediaFragment(mFile
, mAccount
); 
 137                 newFragment 
= new FileDetailFragment(mFile
, mAccount
); 
 138                 mWaitingToPreview 
= true
; 
 142             newFragment 
= new FileDetailFragment(mFile
, mAccount
); 
 144         FragmentTransaction ft 
= getSupportFragmentManager().beginTransaction(); 
 145         ft
.replace(R
.id
.fragment
, newFragment
, FileDetailFragment
.FTAG
); 
 151     protected void onSaveInstanceState(Bundle outState
) { 
 152         super.onSaveInstanceState(outState
); 
 153         outState
.putBoolean(KEY_WAITING_TO_PREVIEW
, mWaitingToPreview
); 
 158     public void onPause() { 
 160         if (mDownloadFinishReceiver 
!= null
) { 
 161             unregisterReceiver(mDownloadFinishReceiver
); 
 162             mDownloadFinishReceiver 
= null
; 
 168     public void onResume() { 
 170         if (!mConfigurationChangedToLandscape
) { 
 171             // TODO this is probably unnecessary 
 172             Fragment fragment 
= getSupportFragmentManager().findFragmentByTag(FileDetailFragment
.FTAG
); 
 173             if (fragment 
!= null 
&& fragment 
instanceof FileDetailFragment
) { 
 174                 ((FileDetailFragment
) fragment
).updateFileDetails(false
, false
); 
 177         // Listen for download messages 
 178         IntentFilter downloadIntentFilter 
= new IntentFilter(FileDownloader
.DOWNLOAD_ADDED_MESSAGE
); 
 179         downloadIntentFilter
.addAction(FileDownloader
.DOWNLOAD_FINISH_MESSAGE
); 
 180         mDownloadFinishReceiver 
= new DownloadFinishReceiver(); 
 181         registerReceiver(mDownloadFinishReceiver
, downloadIntentFilter
); 
 185     /** Defines callbacks for service binding, passed to bindService() */ 
 186     private class DetailsServiceConnection 
implements ServiceConnection 
{ 
 189         public void onServiceConnected(ComponentName component
, IBinder service
) { 
 191             if (component
.equals(new ComponentName(FileDetailActivity
.this, FileDownloader
.class))) { 
 192                 Log_OC
.d(TAG
, "Download service connected"); 
 193                 mDownloaderBinder 
= (FileDownloaderBinder
) service
; 
 194                 if (mWaitingToPreview
) { 
 195                     requestForDownload(); 
 198             } else if (component
.equals(new ComponentName(FileDetailActivity
.this, FileUploader
.class))) { 
 199                 Log_OC
.d(TAG
, "Upload service connected"); 
 200                 mUploaderBinder 
= (FileUploaderBinder
) service
; 
 205             Fragment fragment 
= getSupportFragmentManager().findFragmentByTag(FileDetailFragment
.FTAG
); 
 206             FileDetailFragment detailsFragment 
= (fragment 
instanceof FileDetailFragment
) ? 
(FileDetailFragment
) fragment 
: null
; 
 207             if (detailsFragment 
!= null
) { 
 208                 detailsFragment
.listenForTransferProgress(); 
 209                 detailsFragment
.updateFileDetails(mWaitingToPreview
, false
);   // let the fragment gets the mDownloadBinder through getDownloadBinder() (see FileDetailFragment#updateFileDetais()) 
 214         public void onServiceDisconnected(ComponentName component
) { 
 215             if (component
.equals(new ComponentName(FileDetailActivity
.this, FileDownloader
.class))) { 
 216                 Log_OC
.d(TAG
, "Download service disconnected"); 
 217                 mDownloaderBinder 
= null
; 
 218             } else if (component
.equals(new ComponentName(FileDetailActivity
.this, FileUploader
.class))) { 
 219                 Log_OC
.d(TAG
, "Upload service disconnected"); 
 220                 mUploaderBinder 
= null
; 
 227     public void onDestroy() { 
 229         if (mDownloadConnection 
!= null
) { 
 230             unbindService(mDownloadConnection
); 
 231             mDownloadConnection 
= null
; 
 233         if (mUploadConnection 
!= null
) { 
 234             unbindService(mUploadConnection
); 
 235             mUploadConnection 
= null
; 
 241     public boolean onOptionsItemSelected(MenuItem item
) { 
 242         boolean returnValue 
= false
; 
 244         switch(item
.getItemId()){ 
 245         case android
.R
.id
.home
: 
 246             backToDisplayActivity(true
); 
 250             returnValue 
= super.onOptionsItemSelected(item
); 
 256     private void backToDisplayActivity(boolean moveToParent
) { 
 257         Intent intent 
= new Intent(this, FileDisplayActivity
.class); 
 258         intent
.addFlags(Intent
.FLAG_ACTIVITY_CLEAR_TOP
); 
 259         OCFile targetFile 
= null
; 
 261             targetFile 
= moveToParent ? mStorageManager
.getFileById(mFile
.getParentId()) : mFile
; 
 263         intent
.putExtra(FileDetailFragment
.EXTRA_FILE
, targetFile
); 
 264         intent
.putExtra(FileDetailFragment
.EXTRA_ACCOUNT
, mAccount
); 
 265         startActivity(intent
); 
 271     protected Dialog 
onCreateDialog(int id
) { 
 272         Dialog dialog 
= null
; 
 274         case DIALOG_SHORT_WAIT
: { 
 275             ProgressDialog working_dialog 
= new ProgressDialog(this); 
 276             working_dialog
.setMessage(getResources().getString( 
 277                     R
.string
.wait_a_moment
)); 
 278             working_dialog
.setIndeterminate(true
); 
 279             working_dialog
.setCancelable(false
); 
 280             dialog 
= working_dialog
; 
 294     public void onFileStateChanged() { 
 295         // nothing to do here! 
 303     public FileDownloaderBinder 
getFileDownloaderBinder() { 
 304         return mDownloaderBinder
; 
 309     public FileUploaderBinder 
getFileUploaderBinder() { 
 310         return mUploaderBinder
; 
 315     public void showFragmentWithDetails(OCFile file
) { 
 316         FragmentTransaction transaction 
= getSupportFragmentManager().beginTransaction(); 
 317         transaction
.replace(R
.id
.fragment
, new FileDetailFragment(file
, mAccount
), FileDetailFragment
.FTAG
);  
 318         transaction
.commit(); 
 322     private void requestForDownload() { 
 323         if (!mDownloaderBinder
.isDownloading(mAccount
, mFile
)) { 
 324             Intent i 
= new Intent(this, FileDownloader
.class); 
 325             i
.putExtra(FileDownloader
.EXTRA_ACCOUNT
, mAccount
); 
 326             i
.putExtra(FileDownloader
.EXTRA_FILE
, mFile
); 
 333      * Class waiting for broadcast events from the {@link FielDownloader} service. 
 335      * Updates the UI when a download is started or finished, provided that it is relevant for the 
 338     private class DownloadFinishReceiver 
extends BroadcastReceiver 
{ 
 340         public void onReceive(Context context
, Intent intent
) { 
 341             boolean sameAccount 
= isSameAccount(context
, intent
); 
 342             String downloadedRemotePath 
= intent
.getStringExtra(FileDownloader
.EXTRA_REMOTE_PATH
); 
 343             boolean samePath 
= (mFile 
!= null 
&& mFile
.getRemotePath().equals(downloadedRemotePath
)); 
 345             if (sameAccount 
&& samePath
) { 
 346                 updateChildFragment(intent
.getAction(), downloadedRemotePath
, intent
.getBooleanExtra(FileDownloader
.EXTRA_DOWNLOAD_RESULT
, false
)); 
 349             removeStickyBroadcast(intent
); 
 352         private boolean isSameAccount(Context context
, Intent intent
) { 
 353             String accountName 
= intent
.getStringExtra(FileDownloader
.ACCOUNT_NAME
); 
 354             return (accountName 
!= null 
&& accountName
.equals(AccountUtils
.getCurrentOwnCloudAccount(context
).name
)); 
 359     public void updateChildFragment(String downloadEvent
, String downloadedRemotePath
, boolean success
) { 
 360         Fragment fragment 
= getSupportFragmentManager().findFragmentByTag(FileDetailFragment
.FTAG
); 
 361         if (fragment 
!= null 
&& fragment 
instanceof FileDetailFragment
) { 
 362             FileDetailFragment detailsFragment 
= (FileDetailFragment
) fragment
; 
 363             OCFile fileInFragment 
= detailsFragment
.getFile(); 
 364             if (fileInFragment 
!= null 
&& !downloadedRemotePath
.equals(fileInFragment
.getRemotePath())) { 
 365                 // this never should happen; fileInFragment should be always equals to mFile, that was compared to downloadedRemotePath in DownloadReceiver  
 366                 mWaitingToPreview 
= false
; 
 368             } else if (downloadEvent
.equals(FileDownloader
.DOWNLOAD_ADDED_MESSAGE
)) { 
 369                 // grants that the progress bar is updated 
 370                 detailsFragment
.listenForTransferProgress(); 
 371                 detailsFragment
.updateFileDetails(true
, false
); 
 373             } else if (downloadEvent
.equals(FileDownloader
.DOWNLOAD_FINISH_MESSAGE
)) { 
 374                 //  refresh the details fragment  
 375                 if (success 
&& mWaitingToPreview
) { 
 376                     mFile 
= mStorageManager
.getFileById(mFile
.getFileId());   // update the file from database, for the local storage path 
 377                     FragmentTransaction transaction 
= getSupportFragmentManager().beginTransaction(); 
 378                     transaction
.replace(R
.id
.fragment
, new PreviewMediaFragment(mFile
, mAccount
), FileDetailFragment
.FTAG
); 
 379                     transaction
.commit(); 
 380                     mWaitingToPreview 
= false
; 
 383                     detailsFragment
.updateFileDetails(false
, (success
)); 
 384                     // TODO error message if !success ¿? 
 387         } // TODO else if (fragment != null && fragment )