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
.net
.URLEncoder
; 
  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
.database
.Cursor
; 
  37 import android
.net
.Uri
; 
  38 import android
.os
.Bundle
; 
  39 import android
.provider
.MediaStore
; 
  40 import android
.util
.Log
; 
  41 import android
.view
.View
; 
  42 import android
.view
.ViewGroup
; 
  43 import android
.widget
.ArrayAdapter
; 
  44 import android
.widget
.EditText
; 
  45 import android
.widget
.TextView
; 
  47 import com
.actionbarsherlock
.app
.ActionBar
; 
  48 import com
.actionbarsherlock
.app
.ActionBar
.OnNavigationListener
; 
  49 import com
.actionbarsherlock
.app
.SherlockFragmentActivity
; 
  50 import com
.actionbarsherlock
.view
.Menu
; 
  51 import com
.actionbarsherlock
.view
.MenuInflater
; 
  52 import com
.actionbarsherlock
.view
.MenuItem
; 
  53 import com
.actionbarsherlock
.view
.Window
; 
  55 import eu
.alefzero
.owncloud
.AccountUtils
; 
  56 import eu
.alefzero
.owncloud
.R
; 
  57 import eu
.alefzero
.owncloud
.authenticator
.AccountAuthenticator
; 
  58 import eu
.alefzero
.owncloud
.datamodel
.DataStorageManager
; 
  59 import eu
.alefzero
.owncloud
.datamodel
.FileDataStorageManager
; 
  60 import eu
.alefzero
.owncloud
.datamodel
.OCFile
; 
  61 import eu
.alefzero
.owncloud
.files
.services
.FileUploader
; 
  62 import eu
.alefzero
.owncloud
.syncadapter
.FileSyncService
; 
  63 import eu
.alefzero
.owncloud
.ui
.fragment
.FileListFragment
; 
  64 import eu
.alefzero
.owncloud
.utils
.OwnCloudVersion
; 
  65 import eu
.alefzero
.webdav
.WebdavClient
; 
  68  * Displays, what files the user has available in his ownCloud. 
  70  * @author Bartek Przybylski 
  74 public class FileDisplayActivity 
extends SherlockFragmentActivity 
implements 
  75         OnNavigationListener
, OnClickListener 
{ 
  76     private ArrayAdapter
<String
> mDirectories
; 
  77     private DataStorageManager mStorageManager
; 
  79     private SyncBroadcastReceiver syncBroadcastRevceiver
; 
  81     private static final int DIALOG_SETUP_ACCOUNT 
= 0; 
  82     private static final int DIALOG_CREATE_DIR 
= 1; 
  84     private static final int REQUEST_ACCOUNT_SETUP 
= 0; 
  85     private static final int ACTION_SELECT_FILE 
= 1; 
  87     public void pushPath(String path
) { 
  88         mDirectories
.insert(path
, 0); 
  91     public boolean popPath() { 
  92         mDirectories
.remove(mDirectories
.getItem(0)); 
  93         return !mDirectories
.isEmpty(); 
  97     protected Dialog 
onCreateDialog(int id
) { 
  99         AlertDialog
.Builder builder
; 
 101         case DIALOG_SETUP_ACCOUNT
: 
 102             builder 
= new AlertDialog
.Builder(this); 
 103             builder
.setTitle(R
.string
.main_tit_accsetup
); 
 104             builder
.setMessage(R
.string
.main_wrn_accsetup
); 
 105             builder
.setCancelable(false
); 
 106             builder
.setPositiveButton(android
.R
.string
.ok
, this); 
 107             builder
.setNegativeButton(android
.R
.string
.cancel
, this); 
 108             dialog 
= builder
.create(); 
 110         case DIALOG_CREATE_DIR
: { 
 111             builder 
= new Builder(this); 
 112             final EditText dirName 
= new EditText(getBaseContext()); 
 113             final Account a 
= AccountUtils
.getCurrentOwnCloudAccount(this); 
 114             builder
.setView(dirName
); 
 115             builder
.setTitle(R
.string
.uploader_info_dirname
); 
 116             int typed_color 
= getResources().getColor(R
.color
.setup_text_typed
); 
 117             dirName
.setTextColor(typed_color
); 
 119             builder
.setPositiveButton(android
.R
.string
.ok
, 
 120                     new OnClickListener() { 
 121                         public void onClick(DialogInterface dialog
, int which
) { 
 122                             String s 
= dirName
.getText().toString(); 
 123                             if (s
.trim().length() == 0) { 
 129                             for (int i 
= mDirectories
.getCount() - 2; i 
>= 0; --i
) { 
 130                                 path 
+= "/" + mDirectories
.getItem(i
); 
 132                             OCFile parent 
= mStorageManager
.getFileByPath(path
 
 135                             Thread thread 
= new Thread(new DirectoryCreator( 
 139                             OCFile new_file 
= new OCFile(path
); 
 140                             new_file
.setMimetype("DIR"); 
 141                             new_file
.setParentId(parent
.getParentId()); 
 142                             mStorageManager
.saveFile(new_file
); 
 147             builder
.setNegativeButton(R
.string
.common_cancel
, 
 148                     new OnClickListener() { 
 149                         public void onClick(DialogInterface dialog
, int which
) { 
 153             dialog 
= builder
.create(); 
 164     public void onCreate(Bundle savedInstanceState
) { 
 165         super.onCreate(savedInstanceState
); 
 167         if (!accountsAreSetup()) { 
 168             showDialog(DIALOG_SETUP_ACCOUNT
); 
 172         requestWindowFeature(Window
.FEATURE_INDETERMINATE_PROGRESS
); 
 173         setProgressBarIndeterminateVisibility(false
); 
 174         // if (getSupportFragmentManager().findFragmentById(R.id.fileList) == 
 176         setContentView(R
.layout
.files
); 
 181     public boolean onOptionsItemSelected(MenuItem item
) { 
 182         boolean retval 
= true
; 
 183         switch (item
.getItemId()) { 
 184         case R
.id
.settingsItem
: { 
 185             Intent i 
= new Intent(this, Preferences
.class); 
 189         case R
.id
.createDirectoryItem
: { 
 190             showDialog(DIALOG_CREATE_DIR
); 
 193         case R
.id
.startSync
: { 
 194             Bundle bundle 
= new Bundle(); 
 195             bundle
.putBoolean(ContentResolver
.SYNC_EXTRAS_MANUAL
, true
); 
 196             ContentResolver
.requestSync( 
 197                     AccountUtils
.getCurrentOwnCloudAccount(this), 
 198                     "org.owncloud", bundle
); 
 201         case R
.id
.action_upload
: { 
 202             Intent action 
= new Intent(Intent
.ACTION_GET_CONTENT
); 
 203             action 
= action
.setType("*/*") 
 204                     .addCategory(Intent
.CATEGORY_OPENABLE
); 
 205             startActivityForResult( 
 206                     Intent
.createChooser(action
, "Upload file from..."), 
 211         case android
.R
.id
.home
: { 
 212             Intent i 
= new Intent(this, AccountSelectActivity
.class); 
 224     public void onBackPressed() { 
 225         if (mDirectories
.getCount() == 1) { 
 230         ((FileListFragment
) getSupportFragmentManager().findFragmentById( 
 231                 R
.id
.fileList
)).onNavigateUp(); 
 235     public boolean onCreateOptionsMenu(Menu menu
) { 
 236         MenuInflater inflater 
= getSherlock().getMenuInflater(); 
 237         inflater
.inflate(R
.menu
.menu
, menu
); 
 242     protected void onRestoreInstanceState(Bundle savedInstanceState
) { 
 243         super.onRestoreInstanceState(savedInstanceState
); 
 244         // Check, if there are ownCloud accounts 
 245         if (!accountsAreSetup()) { 
 246             showDialog(DIALOG_SETUP_ACCOUNT
); 
 251     protected void onResume() { 
 253         if (!accountsAreSetup()) { 
 254             showDialog(DIALOG_SETUP_ACCOUNT
); 
 258         IntentFilter f 
= new IntentFilter(FileSyncService
.SYNC_MESSAGE
); 
 259         syncBroadcastRevceiver 
= new SyncBroadcastReceiver(); 
 260         registerReceiver(syncBroadcastRevceiver
, f
); 
 262         mDirectories 
= new CustomArrayAdapter
<String
>(this, 
 263                 R
.layout
.sherlock_spinner_dropdown_item
); 
 264         mDirectories
.add("/"); 
 266         mStorageManager 
= new FileDataStorageManager( 
 267                 AccountUtils
.getCurrentOwnCloudAccount(this), 
 268                 getContentResolver()); 
 269         ActionBar action_bar 
= getSupportActionBar(); 
 270         action_bar
.setNavigationMode(ActionBar
.NAVIGATION_MODE_LIST
); 
 271         action_bar
.setDisplayShowTitleEnabled(false
); 
 272         action_bar
.setListNavigationCallbacks(mDirectories
, this); 
 273         action_bar
.setDisplayHomeAsUpEnabled(true
); 
 276     public void onActivityResult(int requestCode
, int resultCode
, Intent data
) { 
 277         Log
.e("ASD", requestCode 
+ " " + resultCode
); 
 278         if (resultCode 
== RESULT_OK
) { 
 279             if (requestCode 
== ACTION_SELECT_FILE
) { 
 280                 Uri selectedImageUri 
= data
.getData(); 
 282                 String filemanagerstring 
= selectedImageUri
.getPath(); 
 283                 String selectedImagePath 
= getPath(selectedImageUri
); 
 286                 if (selectedImagePath 
!= null
) 
 287                     filepath 
= selectedImagePath
; 
 289                     filepath 
= filemanagerstring
; 
 291                 if (filepath 
== null
) { 
 292                     Log
.e("FileDisplay", "Couldnt resolve path to file"); 
 296                 Intent i 
= new Intent(this, FileUploader
.class); 
 297                 i
.putExtra(FileUploader
.KEY_ACCOUNT
, 
 298                         AccountUtils
.getCurrentOwnCloudAccount(this)); 
 299                 String remotepath 
= new String(); 
 300                 for (int j 
= mDirectories
.getCount() - 2; j 
>= 0; --j
) { 
 301                     remotepath 
+= "/" + mDirectories
.getItem(j
); 
 303                 if (!remotepath
.endsWith("/")) 
 305                 remotepath 
+= new File(filepath
).getName(); 
 306                 Log
.e("ASD", remotepath 
+ ""); 
 308                 i
.putExtra(FileUploader
.KEY_LOCAL_FILE
, filepath
); 
 309                 i
.putExtra(FileUploader
.KEY_REMOTE_FILE
, remotepath
); 
 310                 i
.putExtra(FileUploader
.KEY_UPLOAD_TYPE
, 
 311                         FileUploader
.UPLOAD_SINGLE_FILE
); 
 317     public String 
getPath(Uri uri
) { 
 318         String
[] projection 
= { MediaStore
.Images
.Media
.DATA 
}; 
 319         Cursor cursor 
= managedQuery(uri
, projection
, null
, null
, null
); 
 320         if (cursor 
!= null
) { 
 321             int column_index 
= cursor
 
 322                     .getColumnIndexOrThrow(MediaStore
.Images
.Media
.DATA
); 
 323             cursor
.moveToFirst(); 
 324             return cursor
.getString(column_index
); 
 330     protected void onPause() { 
 332         if (syncBroadcastRevceiver 
!= null
) { 
 333             unregisterReceiver(syncBroadcastRevceiver
); 
 334             syncBroadcastRevceiver 
= null
; 
 340     public boolean onNavigationItemSelected(int itemPosition
, long itemId
) { 
 341         int i 
= itemPosition
; 
 348     private class DirectoryCreator 
implements Runnable 
{ 
 349         private String mTargetPath
; 
 350         private Account mAccount
; 
 351         private AccountManager mAm
; 
 353         public DirectoryCreator(String targetPath
, Account account
) { 
 354             mTargetPath 
= targetPath
; 
 356             mAm 
= (AccountManager
) getSystemService(ACCOUNT_SERVICE
); 
 361             WebdavClient wdc 
= new WebdavClient(Uri
.parse(mAm
.getUserData( 
 362                     mAccount
, AccountAuthenticator
.KEY_OC_URL
))); 
 364             String username 
= mAccount
.name
.substring(0, 
 365                     mAccount
.name
.lastIndexOf('@')); 
 366             String password 
= mAm
.getPassword(mAccount
); 
 368             wdc
.setCredentials(username
, password
); 
 369             wdc
.allowUnsignedCertificates(); 
 370             wdc
.createDirectory(mTargetPath
); 
 375     // Custom array adapter to override text colors 
 376     private class CustomArrayAdapter
<T
> extends ArrayAdapter
<T
> { 
 378         public CustomArrayAdapter(FileDisplayActivity ctx
, int view
) { 
 382         public View 
getView(int position
, View convertView
, ViewGroup parent
) { 
 383             View v 
= super.getView(position
, convertView
, parent
); 
 385             ((TextView
) v
).setTextColor(getResources().getColorStateList( 
 386                     android
.R
.color
.white
)); 
 390         public View 
getDropDownView(int position
, View convertView
, 
 392             View v 
= super.getDropDownView(position
, convertView
, parent
); 
 394             ((TextView
) v
).setTextColor(getResources().getColorStateList( 
 395                     android
.R
.color
.white
)); 
 402     public void onClick(DialogInterface dialog
, int which
) { 
 403         // In any case - we won't need it anymore 
 406         case DialogInterface
.BUTTON_POSITIVE
: 
 407             Intent intent 
= new Intent("android.settings.ADD_ACCOUNT_SETTINGS"); 
 408             intent
.putExtra("authorities", 
 409                     new String
[] { AccountAuthenticator
.AUTH_TOKEN_TYPE 
}); 
 410             startActivity(intent
); 
 412         case DialogInterface
.BUTTON_NEGATIVE
: 
 419      * Checks, whether or not there are any ownCloud accounts setup. 
 421      * @return true, if there is at least one account. 
 423     private boolean accountsAreSetup() { 
 424         AccountManager accMan 
= AccountManager
.get(this); 
 425         Account
[] accounts 
= accMan
 
 426                 .getAccountsByType(AccountAuthenticator
.ACCOUNT_TYPE
); 
 427         return accounts
.length 
> 0; 
 430     private class SyncBroadcastReceiver 
extends BroadcastReceiver 
{ 
 432          * {@link BroadcastReceiver} to enable syncing feedback in UI 
 435         public void onReceive(Context context
, Intent intent
) { 
 436             boolean inProgress 
= intent
.getBooleanExtra( 
 437                     FileSyncService
.IN_PROGRESS
, false
); 
 438             String account_name 
= intent
 
 439                     .getStringExtra(FileSyncService
.ACCOUNT_NAME
); 
 440             Log
.d("FileDisplay", "sync of account " + account_name
 
 441                     + " is in_progress: " + inProgress
); 
 442             setProgressBarIndeterminateVisibility(inProgress
); 
 444                 FileListFragment fileListFramgent 
= (FileListFragment
) getSupportFragmentManager() 
 445                         .findFragmentById(R
.id
.fileList
); 
 446                 if (fileListFramgent 
!= null
) 
 447                     fileListFramgent
.populateFileList();