1 /* ownCloud Android client application 
   2  *   Copyright (C) 2011  Bartek Przybylski 
   4  *   This program is free software: you can redistribute it and/or modify 
   5  *   it under the terms of the GNU General Public License as published by 
   6  *   the Free Software Foundation, either version 3 of the License, or 
   7  *   (at your option) any later version. 
   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/>. 
  19 package eu
.alefzero
.owncloud
.ui
.activity
; 
  22 import java
.util
.ArrayList
; 
  24 import android
.accounts
.Account
; 
  25 import android
.accounts
.AccountManager
; 
  26 import android
.app
.AlertDialog
; 
  27 import android
.app
.AlertDialog
.Builder
; 
  28 import android
.app
.Dialog
; 
  29 import android
.content
.BroadcastReceiver
; 
  30 import android
.content
.ContentResolver
; 
  31 import android
.content
.Context
; 
  32 import android
.content
.DialogInterface
; 
  33 import android
.content
.DialogInterface
.OnClickListener
; 
  34 import android
.content
.Intent
; 
  35 import android
.content
.IntentFilter
; 
  36 import android
.content
.pm
.PackageInfo
; 
  37 import android
.content
.pm
.PackageManager
.NameNotFoundException
; 
  38 import android
.database
.Cursor
; 
  39 import android
.net
.Uri
; 
  40 import android
.os
.Bundle
; 
  41 import android
.provider
.MediaStore
; 
  42 import android
.support
.v4
.app
.FragmentTransaction
; 
  43 import android
.util
.Log
; 
  44 import android
.view
.View
; 
  45 import android
.view
.ViewGroup
; 
  46 import android
.widget
.ArrayAdapter
; 
  47 import android
.widget
.EditText
; 
  48 import android
.widget
.TextView
; 
  50 import com
.actionbarsherlock
.app
.ActionBar
; 
  51 import com
.actionbarsherlock
.app
.ActionBar
.OnNavigationListener
; 
  52 import com
.actionbarsherlock
.app
.SherlockFragmentActivity
; 
  53 import com
.actionbarsherlock
.view
.Menu
; 
  54 import com
.actionbarsherlock
.view
.MenuInflater
; 
  55 import com
.actionbarsherlock
.view
.MenuItem
; 
  56 import com
.actionbarsherlock
.view
.Window
; 
  58 import eu
.alefzero
.owncloud
.AccountUtils
; 
  59 import eu
.alefzero
.owncloud
.CrashHandler
; 
  60 import eu
.alefzero
.owncloud
.R
; 
  61 import eu
.alefzero
.owncloud
.authenticator
.AccountAuthenticator
; 
  62 import eu
.alefzero
.owncloud
.datamodel
.DataStorageManager
; 
  63 import eu
.alefzero
.owncloud
.datamodel
.FileDataStorageManager
; 
  64 import eu
.alefzero
.owncloud
.datamodel
.OCFile
; 
  65 import eu
.alefzero
.owncloud
.files
.services
.FileDownloader
; 
  66 import eu
.alefzero
.owncloud
.files
.services
.FileUploader
; 
  67 import eu
.alefzero
.owncloud
.syncadapter
.FileSyncService
; 
  68 import eu
.alefzero
.owncloud
.ui
.fragment
.FileDetailFragment
; 
  69 import eu
.alefzero
.owncloud
.ui
.fragment
.FileListFragment
; 
  70 import eu
.alefzero
.webdav
.WebdavClient
; 
  73  * Displays, what files the user has available in his ownCloud. 
  75  * @author Bartek Przybylski 
  79 public class FileDisplayActivity 
extends SherlockFragmentActivity 
implements 
  80     FileListFragment
.ContainerActivity
, OnNavigationListener
, OnClickListener
, android
.view
.View
.OnClickListener  
{ 
  82     private ArrayAdapter
<String
> mDirectories
; 
  83     private OCFile mCurrentDir
; 
  84     private String
[] mDirs 
= null
; 
  86     private DataStorageManager mStorageManager
; 
  87     private SyncBroadcastReceiver mSyncBroadcastReceiver
; 
  88     private UploadFinishReceiver mUploadFinishReceiver
; 
  90     private View mLayoutView 
= null
; 
  91     private FileListFragment mFileList
; 
  93     private boolean mDualPane
; 
  95     private boolean mForcedLoginToCreateFirstAccount 
= false
; 
  97     private static final String KEY_DIR_ARRAY 
= "DIR_ARRAY"; 
  98     private static final String KEY_CURRENT_DIR 
= "DIR"; 
 100     private static final int DIALOG_SETUP_ACCOUNT 
= 0; 
 101     private static final int DIALOG_CREATE_DIR 
= 1; 
 102     private static final int DIALOG_ABOUT_APP 
= 2; 
 104     private static final int ACTION_SELECT_FILE 
= 1; 
 107     public void onCreate(Bundle savedInstanceState
) { 
 108         Log
.i(getClass().toString(), "onCreate() start"); 
 109         super.onCreate(savedInstanceState
); 
 111         requestWindowFeature(Window
.FEATURE_INDETERMINATE_PROGRESS
); 
 112         setSupportProgressBarIndeterminateVisibility(false
); 
 114         Thread
.setDefaultUncaughtExceptionHandler(new CrashHandler(getApplicationContext())); 
 116         if(savedInstanceState 
!= null
) { 
 117             mDirs 
= savedInstanceState
.getStringArray(KEY_DIR_ARRAY
); 
 118             mDirectories 
= new CustomArrayAdapter
<String
>(this, R
.layout
.sherlock_spinner_dropdown_item
); 
 119             mDirectories
.add("/"); 
 121                 for (String s 
: mDirs
) 
 122                     mDirectories
.insert(s
, 0); 
 123             mCurrentDir 
= savedInstanceState
.getParcelable(FileDetailFragment
.EXTRA_FILE
); 
 126         mLayoutView 
= getLayoutInflater().inflate(R
.layout
.files
, null
);  // always inflate this at onCreate() ; just once! 
 128         if (AccountUtils
.accountsAreSetup(this)) { 
 130             initDelayedTilAccountAvailabe(); 
 134             setContentView(R
.layout
.no_account_available
); 
 135             getSupportActionBar().setNavigationMode(ActionBar
.DISPLAY_SHOW_TITLE
); 
 136             findViewById(R
.id
.setup_account
).setOnClickListener(this); 
 138             Intent intent 
= new Intent(android
.provider
.Settings
.ACTION_ADD_ACCOUNT
); 
 139             intent
.putExtra(android
.provider
.Settings
.EXTRA_AUTHORITIES
, new String
[] { AccountAuthenticator
.AUTH_TOKEN_TYPE 
}); 
 140             startActivity(intent
);  // although the code is here, the activity won't be created until this.onStart() and this.onResume() are finished; 
 141             mForcedLoginToCreateFirstAccount 
= true
; 
 144         Log
.i(getClass().toString(), "onCreate() end"); 
 148     public boolean onCreateOptionsMenu(Menu menu
) { 
 149         MenuInflater inflater 
= getSherlock().getMenuInflater(); 
 150             inflater
.inflate(R
.menu
.menu
, menu
); 
 155     public boolean onOptionsItemSelected(MenuItem item
) { 
 156         boolean retval 
= true
; 
 157         switch (item
.getItemId()) { 
 158             case R
.id
.createDirectoryItem
: { 
 159                 showDialog(DIALOG_CREATE_DIR
); 
 162             case R
.id
.startSync
: { 
 163                 // This could be interesting 
 164                 //ContentResolver.cancelSync(null, "org.owncloud");   // cancel the current synchronizations of any other ownCloud account 
 165                 Bundle bundle 
= new Bundle(); 
 166                 bundle
.putBoolean(ContentResolver
.SYNC_EXTRAS_MANUAL
, true
); 
 167                 ContentResolver
.requestSync( 
 168                         AccountUtils
.getCurrentOwnCloudAccount(this), 
 169                         "org.owncloud", bundle
); 
 172             case R
.id
.action_upload
: { 
 173                 Intent action 
= new Intent(Intent
.ACTION_GET_CONTENT
); 
 174                 action 
= action
.setType("*/*") 
 175                         .addCategory(Intent
.CATEGORY_OPENABLE
); 
 176                 startActivityForResult( 
 177                         Intent
.createChooser(action
, "Upload file from..."), 
 181             case R
.id
.action_settings
: { 
 182                 Intent settingsIntent 
= new Intent(this, Preferences
.class); 
 183                 startActivity(settingsIntent
); 
 186             case R
.id
.about_app 
: { 
 187                 showDialog(DIALOG_ABOUT_APP
); 
 190             case android
.R
.id
.home
: { 
 191                 if(mCurrentDir 
!= null 
&& mCurrentDir
.getParentId() != 0){ 
 203     public boolean onNavigationItemSelected(int itemPosition
, long itemId
) { 
 204         int i 
= itemPosition
; 
 212      * Called, when the user selected something for uploading 
 214     public void onActivityResult(int requestCode
, int resultCode
, Intent data
) { 
 215         if (requestCode 
== ACTION_SELECT_FILE
) { 
 216             if (resultCode 
== RESULT_OK
) { 
 217                 Uri selectedImageUri 
= data
.getData(); 
 219                 String filemanagerstring 
= selectedImageUri
.getPath(); 
 220                 String selectedImagePath 
= getPath(selectedImageUri
); 
 223                 if (selectedImagePath 
!= null
) 
 224                     filepath 
= selectedImagePath
; 
 226                     filepath 
= filemanagerstring
; 
 228                 if (filepath 
== null
) { 
 229                     Log
.e("FileDisplay", "Couldnt resolve path to file"); 
 233                 Intent i 
= new Intent(this, FileUploader
.class); 
 234                 i
.putExtra(FileUploader
.KEY_ACCOUNT
, 
 235                         AccountUtils
.getCurrentOwnCloudAccount(this)); 
 236                 String remotepath 
= new String(); 
 237                 for (int j 
= mDirectories
.getCount() - 2; j 
>= 0; --j
) { 
 238                     remotepath 
+= "/" + mDirectories
.getItem(j
); 
 240                 if (!remotepath
.endsWith("/")) 
 242                 remotepath 
+= new File(filepath
).getName(); 
 243                 remotepath 
= Uri
.encode(remotepath
, "/"); 
 245                 i
.putExtra(FileUploader
.KEY_LOCAL_FILE
, filepath
); 
 246                 i
.putExtra(FileUploader
.KEY_REMOTE_FILE
, remotepath
); 
 247                 i
.putExtra(FileUploader
.KEY_UPLOAD_TYPE
, FileUploader
.UPLOAD_SINGLE_FILE
); 
 251         }/* dvelasco: WIP - not working as expected ... yet :) 
 252              else if (requestCode == ACTION_CREATE_FIRST_ACCOUNT) { 
 253             if (resultCode != RESULT_OK) { 
 254                 finish();   // the user cancelled the AuthenticatorActivity 
 260     public void onBackPressed() { 
 261         if (mDirectories 
== null 
|| mDirectories
.getCount() <= 1) { 
 266         mFileList
.onNavigateUp(); 
 267         mCurrentDir 
= mFileList
.getCurrentFile(); 
 269         if(mCurrentDir
.getParentId() == 0){ 
 270             ActionBar actionBar 
= getSupportActionBar();  
 271             actionBar
.setDisplayHomeAsUpEnabled(false
); 
 276     protected void onSaveInstanceState(Bundle outState
) { 
 277         // responsability of restore is prefered in onCreate() before than in onRestoreInstanceState when there are Fragments involved 
 278         Log
.i(getClass().toString(), "onSaveInstanceState() start"); 
 279         super.onSaveInstanceState(outState
); 
 280         if(mDirectories 
!= null 
&& mDirectories
.getCount() != 0){ 
 281             mDirs 
= new String
[mDirectories
.getCount()-1]; 
 282             for (int j 
= mDirectories
.getCount() - 2, i 
= 0; j 
>= 0; --j
, ++i
) { 
 283                 mDirs
[i
] = mDirectories
.getItem(j
); 
 286         outState
.putStringArray(KEY_DIR_ARRAY
, mDirs
); 
 287         outState
.putParcelable(FileDetailFragment
.EXTRA_FILE
, mCurrentDir
); 
 288         Log
.i(getClass().toString(), "onSaveInstanceState() end"); 
 292     protected void onResume() { 
 293         Log
.i(getClass().toString(), "onResume() start"); 
 296         if (AccountUtils
.accountsAreSetup(this)) { 
 297          // at least an account exist: normal operation 
 299             // set the layout only if it couldn't be set in onCreate 
 300             if (mForcedLoginToCreateFirstAccount
) { 
 301                 initDelayedTilAccountAvailabe(); 
 302                 mForcedLoginToCreateFirstAccount 
= false
; 
 305             // Listen for sync messages 
 306             IntentFilter syncIntentFilter 
= new IntentFilter(FileSyncService
.SYNC_MESSAGE
); 
 307             mSyncBroadcastReceiver 
= new SyncBroadcastReceiver(); 
 308             registerReceiver(mSyncBroadcastReceiver
, syncIntentFilter
); 
 310             // Listen for upload messages 
 311             IntentFilter uploadIntentFilter 
= new IntentFilter(FileUploader
.UPLOAD_FINISH_MESSAGE
); 
 312             mUploadFinishReceiver 
= new UploadFinishReceiver(); 
 313             registerReceiver(mUploadFinishReceiver
, uploadIntentFilter
); 
 315             // Storage manager initialization 
 316             mStorageManager 
= new FileDataStorageManager( 
 317                     AccountUtils
.getCurrentOwnCloudAccount(this), 
 318                     getContentResolver()); 
 320             // File list fragments    
 321             mFileList 
= (FileListFragment
) getSupportFragmentManager().findFragmentById(R
.id
.fileList
); 
 324             // Figure out what directory to list.  
 325             // Priority: Intent (here), savedInstanceState (onCreate), root dir (dir is null) 
 326             if(getIntent().hasExtra(FileDetailFragment
.EXTRA_FILE
)){ 
 327                 mCurrentDir 
= (OCFile
) getIntent().getParcelableExtra(FileDetailFragment
.EXTRA_FILE
); 
 328                 if(mCurrentDir 
!= null 
&& !mCurrentDir
.isDirectory()){ 
 329                     mCurrentDir 
= mStorageManager
.getFileById(mCurrentDir
.getParentId()); 
 332                 // Clear intent extra, so rotating the screen will not return us to this directory 
 333                 getIntent().removeExtra(FileDetailFragment
.EXTRA_FILE
); 
 336             if (mCurrentDir 
== null
) 
 337                 mCurrentDir 
= mStorageManager
.getFileByPath("/"); 
 339             // Drop-Down navigation and file list restore 
 340             mDirectories 
= new CustomArrayAdapter
<String
>(this, R
.layout
.sherlock_spinner_dropdown_item
); 
 343             // Given the case we have a file to display: 
 344             if(mCurrentDir 
!= null
){ 
 345                 ArrayList
<OCFile
> files 
= new ArrayList
<OCFile
>(); 
 346                 OCFile currFile 
= mCurrentDir
; 
 347                 while(currFile 
!= null
){ 
 349                     currFile 
= mStorageManager
.getFileById(currFile
.getParentId()); 
 353                 mDirs 
= new String
[files
.size()]; 
 354                 for(int i 
= files
.size() - 1; i 
>= 0; i
--){ 
 355                     mDirs
[i
] = files
.get(i
).getFileName(); 
 360                 for (String s 
: mDirs
) 
 363                 mDirectories
.add("/"); 
 367             ActionBar action_bar 
= getSupportActionBar(); 
 368             action_bar
.setNavigationMode(ActionBar
.NAVIGATION_MODE_LIST
); 
 369             action_bar
.setDisplayShowTitleEnabled(false
); 
 370             action_bar
.setListNavigationCallbacks(mDirectories
, this); 
 371             if(mCurrentDir 
!= null 
&& mCurrentDir
.getParentId() != 0){ 
 372                 action_bar
.setDisplayHomeAsUpEnabled(true
); 
 374                 action_bar
.setDisplayHomeAsUpEnabled(false
); 
 378             mFileList
.listDirectory(mCurrentDir
); 
 380         Log
.i(getClass().toString(), "onResume() end"); 
 384     protected void onPause() { 
 385         Log
.i(getClass().toString(), "onPause() start"); 
 387         if (mSyncBroadcastReceiver 
!= null
) { 
 388             unregisterReceiver(mSyncBroadcastReceiver
); 
 389             mSyncBroadcastReceiver 
= null
; 
 391         if (mUploadFinishReceiver 
!= null
) { 
 392             unregisterReceiver(mUploadFinishReceiver
); 
 393             mUploadFinishReceiver 
= null
; 
 395         getIntent().putExtra(FileDetailFragment
.EXTRA_FILE
, mCurrentDir
); 
 396         Log
.i(getClass().toString(), "onPause() end"); 
 400     protected Dialog 
onCreateDialog(int id
) { 
 401         Dialog dialog 
= null
; 
 402         AlertDialog
.Builder builder
; 
 404         case DIALOG_SETUP_ACCOUNT
: 
 405             builder 
= new AlertDialog
.Builder(this); 
 406             builder
.setTitle(R
.string
.main_tit_accsetup
); 
 407             builder
.setMessage(R
.string
.main_wrn_accsetup
); 
 408             builder
.setCancelable(false
); 
 409             builder
.setPositiveButton(android
.R
.string
.ok
, this); 
 410             builder
.setNegativeButton(android
.R
.string
.cancel
, this); 
 411             dialog 
= builder
.create(); 
 413         case DIALOG_ABOUT_APP
: { 
 414             builder 
= new AlertDialog
.Builder(this); 
 415             builder
.setTitle("About"); 
 418                 pkg 
= getPackageManager().getPackageInfo(getPackageName(), 0); 
 419                 builder
.setMessage("ownCloud android client\n\nversion: " + pkg
.versionName 
); 
 420                 builder
.setIcon(android
.R
.drawable
.ic_menu_info_details
); 
 421                 dialog 
= builder
.create(); 
 422             } catch (NameNotFoundException e
) { 
 429         case DIALOG_CREATE_DIR
: { 
 430             builder 
= new Builder(this); 
 431             final EditText dirNameInput 
= new EditText(getBaseContext()); 
 432             final Account a 
= AccountUtils
.getCurrentOwnCloudAccount(this); 
 433             builder
.setView(dirNameInput
); 
 434             builder
.setTitle(R
.string
.uploader_info_dirname
); 
 435             int typed_color 
= getResources().getColor(R
.color
.setup_text_typed
); 
 436             dirNameInput
.setTextColor(typed_color
); 
 437             builder
.setPositiveButton(android
.R
.string
.ok
, 
 438                     new OnClickListener() { 
 439                         public void onClick(DialogInterface dialog
, int which
) { 
 440                             String directoryName 
= dirNameInput
.getText().toString(); 
 441                             if (directoryName
.trim().length() == 0) { 
 446                             // Figure out the path where the dir needs to be created 
 448                             if (mCurrentDir 
== null
) { 
 449                                 // this is just a patch; we should ensure that mCurrentDir never is null 
 450                                 if (!mStorageManager
.fileExists("/")) { 
 451                                     OCFile file 
= new OCFile("/"); 
 452                                     mStorageManager
.saveFile(file
); 
 454                                 mCurrentDir 
= mStorageManager
.getFileByPath("/"); 
 456                             path 
= FileDisplayActivity
.this.mCurrentDir
.getRemotePath(); 
 459                             path 
+= Uri
.encode(directoryName
) + "/"; 
 460                             Thread thread 
= new Thread(new DirectoryCreator(path
, a
)); 
 463                             // Save new directory in local database 
 464                             OCFile newDir 
= new OCFile(path
); 
 465                             newDir
.setMimetype("DIR"); 
 466                             newDir
.setParentId(mCurrentDir
.getFileId()); 
 467                             mStorageManager
.saveFile(newDir
); 
 469                             // Display the new folder right away 
 471                             mFileList
.listDirectory(mCurrentDir
); 
 474             builder
.setNegativeButton(R
.string
.common_cancel
, 
 475                     new OnClickListener() { 
 476                         public void onClick(DialogInterface dialog
, int which
) { 
 480             dialog 
= builder
.create(); 
 492      * Responds to the "There are no ownCloud Accounts setup" dialog 
 493      * TODO: Dialog is 100% useless -> Remove 
 496     public void onClick(DialogInterface dialog
, int which
) { 
 497         // In any case - we won't need it anymore 
 500         case DialogInterface
.BUTTON_POSITIVE
: 
 501             Intent intent 
= new Intent("android.settings.ADD_ACCOUNT_SETTINGS"); 
 502             intent
.putExtra("authorities", 
 503                     new String
[] { AccountAuthenticator
.AUTH_TOKEN_TYPE 
}); 
 504             startActivity(intent
); 
 506         case DialogInterface
.BUTTON_NEGATIVE
: 
 513      * Translates a content URI of an image to a physical path 
 515      * @param uri The URI to resolve 
 516      * @return The path to the image or null if it could not be found 
 518     public String 
getPath(Uri uri
) { 
 519         String
[] projection 
= { MediaStore
.Images
.Media
.DATA 
}; 
 520         Cursor cursor 
= managedQuery(uri
, projection
, null
, null
, null
); 
 521         if (cursor 
!= null
) { 
 522             int column_index 
= cursor
 
 523                     .getColumnIndexOrThrow(MediaStore
.Images
.Media
.DATA
); 
 524             cursor
.moveToFirst(); 
 525             return cursor
.getString(column_index
); 
 531      * Pushes a directory to the drop down list 
 532      * @param directory to push 
 533      * @throws IllegalArgumentException If the {@link OCFile#isDirectory()} returns false. 
 535     public void pushDirname(OCFile directory
) { 
 536         if(!directory
.isDirectory()){ 
 537             throw new IllegalArgumentException("Only directories may be pushed!"); 
 539         mDirectories
.insert(directory
.getFileName(), 0); 
 540         mCurrentDir 
= directory
; 
 544      * Pops a directory name from the drop down list 
 545      * @return True, unless the stack is empty 
 547     public boolean popDirname() { 
 548         mDirectories
.remove(mDirectories
.getItem(0)); 
 549         return !mDirectories
.isEmpty(); 
 552     private class DirectoryCreator 
implements Runnable 
{ 
 553         private String mTargetPath
; 
 554         private Account mAccount
; 
 555         private AccountManager mAm
; 
 557         public DirectoryCreator(String targetPath
, Account account
) { 
 558             mTargetPath 
= targetPath
; 
 560             mAm 
= (AccountManager
) getSystemService(ACCOUNT_SERVICE
); 
 565             WebdavClient wdc 
= new WebdavClient(mAccount
, getApplicationContext()); 
 567             String username 
= mAccount
.name
.substring(0, 
 568                     mAccount
.name
.lastIndexOf('@')); 
 569             String password 
= mAm
.getPassword(mAccount
); 
 571             wdc
.setCredentials(username
, password
); 
 572             wdc
.allowSelfsignedCertificates(); 
 573             wdc
.createDirectory(mTargetPath
); 
 578     // Custom array adapter to override text colors 
 579     private class CustomArrayAdapter
<T
> extends ArrayAdapter
<T
> { 
 581         public CustomArrayAdapter(FileDisplayActivity ctx
, int view
) { 
 585         public View 
getView(int position
, View convertView
, ViewGroup parent
) { 
 586             View v 
= super.getView(position
, convertView
, parent
); 
 588             ((TextView
) v
).setTextColor(getResources().getColorStateList( 
 589                     android
.R
.color
.white
)); 
 593         public View 
getDropDownView(int position
, View convertView
, 
 595             View v 
= super.getDropDownView(position
, convertView
, parent
); 
 597             ((TextView
) v
).setTextColor(getResources().getColorStateList( 
 598                     android
.R
.color
.white
)); 
 605     private class SyncBroadcastReceiver 
extends BroadcastReceiver 
{ 
 607          * {@link BroadcastReceiver} to enable syncing feedback in UI 
 610         public void onReceive(Context context
, Intent intent
) { 
 611             boolean inProgress 
= intent
.getBooleanExtra( 
 612                     FileSyncService
.IN_PROGRESS
, false
); 
 613             String account_name 
= intent
 
 614                     .getStringExtra(FileSyncService
.ACCOUNT_NAME
); 
 616             Log
.d("FileDisplay", "sync of account " + account_name
 
 617                     + " is in_progress: " + inProgress
); 
 619             if (account_name
.equals(AccountUtils
.getCurrentOwnCloudAccount(context
).name
)) {   
 621                 String synchFolderRemotePath 
= intent
.getStringExtra(FileSyncService
.SYNC_FOLDER_REMOTE_PATH
);  
 623                 if (mCurrentDir 
== null
) 
 624                     mCurrentDir 
= mStorageManager
.getFileByPath("/"); 
 626                 if (synchFolderRemotePath 
!= null 
&& mCurrentDir 
!= null 
&& mCurrentDir
.getRemotePath().equals(synchFolderRemotePath
) ) { 
 627                     FileListFragment fileListFragment 
= (FileListFragment
) getSupportFragmentManager() 
 628                             .findFragmentById(R
.id
.fileList
); 
 629                     mCurrentDir 
= getStorageManager().getFileByPath(synchFolderRemotePath
); 
 630                     if (fileListFragment 
!= null
) { 
 631                         fileListFragment
.listDirectory(mCurrentDir
);   
 635                 setSupportProgressBarIndeterminateVisibility(inProgress
); 
 642     private class UploadFinishReceiver 
extends BroadcastReceiver 
{ 
 644          * Once the file upload has finished -> update view 
 645          *  @author David A. Velasco 
 646          * {@link BroadcastReceiver} to enable upload feedback in UI 
 649         public void onReceive(Context context
, Intent intent
) { 
 650             long parentDirId 
= intent
.getLongExtra(FileUploader
.EXTRA_PARENT_DIR_ID
, -1); 
 651             OCFile parentDir 
= mStorageManager
.getFileById(parentDirId
); 
 653             if (parentDir 
!= null 
&& ( 
 654                     (mCurrentDir 
== null 
&& parentDir
.getFileName().equals("/")) || 
 655                      parentDir
.equals(mCurrentDir
)) 
 657                 FileListFragment fileListFragment 
= (FileListFragment
) getSupportFragmentManager().findFragmentById(R
.id
.fileList
); 
 658                 if (fileListFragment 
!= null
) {  
 659                     fileListFragment
.listDirectory(); 
 668     public void onClick(View v
) { 
 669         if (v
.getId() == R
.id
.setup_account
) { 
 670             Intent intent 
= new Intent(android
.provider
.Settings
.ACTION_ADD_ACCOUNT
); 
 671             intent
.putExtra(android
.provider
.Settings
.EXTRA_AUTHORITIES
, new String
[] { AccountAuthenticator
.AUTH_TOKEN_TYPE 
}); 
 672             startActivity(intent
);  
 673             mForcedLoginToCreateFirstAccount 
= true
; 
 685     public DataStorageManager 
getStorageManager() { 
 686         return mStorageManager
; 
 694     public void onDirectoryClick(OCFile directory
) { 
 695         pushDirname(directory
); 
 696         ActionBar actionBar 
= getSupportActionBar(); 
 697         actionBar
.setDisplayHomeAsUpEnabled(true
); 
 700             // Resets the FileDetailsFragment on Tablets so that it always displays 
 701             FileDetailFragment fileDetails 
= (FileDetailFragment
) getSupportFragmentManager().findFragmentByTag(FileDetailFragment
.FTAG
); 
 702             if (fileDetails 
!= null
) { 
 703                 FragmentTransaction transaction 
= getSupportFragmentManager().beginTransaction(); 
 704                 transaction
.remove(fileDetails
); 
 705                 transaction
.add(R
.id
.file_details_container
, new FileDetailFragment(null
, null
)); 
 706                 transaction
.commit(); 
 716     public void onFileClick(OCFile file
) { 
 718         // If we are on a large device -> update fragment 
 720             // buttons in the details view are problematic when trying to reuse an existing fragment; create always a new one solves some of them, BUT no all; downloads are 'dangerous' 
 721             FragmentTransaction transaction 
= getSupportFragmentManager().beginTransaction(); 
 722             transaction
.replace(R
.id
.file_details_container
, new FileDetailFragment(file
, AccountUtils
.getCurrentOwnCloudAccount(this)), FileDetailFragment
.FTAG
); 
 723             transaction
.setTransition(FragmentTransaction
.TRANSIT_FRAGMENT_FADE
); 
 724             transaction
.commit(); 
 726         } else {    // small or medium screen device -> new Activity 
 727             Intent showDetailsIntent 
= new Intent(this, FileDetailActivity
.class); 
 728             showDetailsIntent
.putExtra(FileDetailFragment
.EXTRA_FILE
, file
); 
 729             showDetailsIntent
.putExtra(FileDownloader
.EXTRA_ACCOUNT
, AccountUtils
.getCurrentOwnCloudAccount(this)); 
 730             startActivity(showDetailsIntent
); 
 735      *  Operations in this method should be preferably performed in onCreate to have a lighter onResume method.  
 737      *  But we need to delay them to onResume for the first start of the application, when no account exists and the login activity must be shown; and  
 738      *  put instead the ugly view that shows the 'Setup' button to restart the login activity.    
 740      *  In other way, if the users cancels or presses BACK in the login page that first time (users can be cruel sometimes) would show a blank view (the  
 741      *  FragmentList view empty). 
 743      *  This is temporal, until we found out how to get a result in this activity after launching the ADD_ACCOUNT Intent with startActivityForResult (not trivial) 
 745     private void initDelayedTilAccountAvailabe() { 
 746         setContentView(mLayoutView
);     
 747         mDualPane 
= (findViewById(R
.id
.file_details_container
) != null
); 
 748         if (mDualPane 
&& getSupportFragmentManager().findFragmentByTag(FileDetailFragment
.FTAG
) == null
) { 
 749             FragmentTransaction transaction 
= getSupportFragmentManager().beginTransaction(); 
 750             transaction
.replace(R
.id
.file_details_container
, new FileDetailFragment(null
, null
)); // empty FileDetailFragment 
 751             transaction
.commit();