X-Git-Url: http://git.linex4red.de/pub/Android/ownCloud.git/blobdiff_plain/ab946b9af69f3f299d72026db69f5f650096d8e8..6ace8ab1c18b23a4c016986256075cfda8e50104:/src/com/owncloud/android/ui/activity/UploadFilesActivity.java diff --git a/src/com/owncloud/android/ui/activity/UploadFilesActivity.java b/src/com/owncloud/android/ui/activity/UploadFilesActivity.java new file mode 100644 index 00000000..ab7bb463 --- /dev/null +++ b/src/com/owncloud/android/ui/activity/UploadFilesActivity.java @@ -0,0 +1,395 @@ +/* ownCloud Android client application + * Copyright (C) 2012-2013 ownCloud Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package com.owncloud.android.ui.activity; + +import java.io.File; + +import android.accounts.Account; +import android.content.Intent; +import android.os.AsyncTask; +import android.os.Bundle; +import android.os.Environment; +import android.support.v4.app.DialogFragment; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.TextView; + +import com.actionbarsherlock.app.ActionBar; +import com.actionbarsherlock.app.ActionBar.OnNavigationListener; +import com.actionbarsherlock.view.MenuItem; +import com.owncloud.android.Log_OC; +import com.owncloud.android.R; +import com.owncloud.android.ui.CustomButton; +import com.owncloud.android.ui.dialog.IndeterminateProgressDialog; +import com.owncloud.android.ui.fragment.ConfirmationDialogFragment; +import com.owncloud.android.ui.fragment.LocalFileListFragment; +import com.owncloud.android.ui.fragment.ConfirmationDialogFragment.ConfirmationDialogFragmentListener; +import com.owncloud.android.utils.FileStorageUtils; + + +/** + * Displays local files and let the user choose what of them wants to upload + * to the current ownCloud account + * + * @author David A. Velasco + * + */ + +public class UploadFilesActivity extends FileActivity implements + LocalFileListFragment.ContainerActivity, OnNavigationListener, OnClickListener, ConfirmationDialogFragmentListener { + + private ArrayAdapter mDirectories; + private File mCurrentDir = null; + private LocalFileListFragment mFileListFragment; + private CustomButton mCancelBtn; + private CustomButton mUploadBtn; + private Account mAccountOnCreation; + private DialogFragment mCurrentDialog; + + public static final String EXTRA_CHOSEN_FILES = UploadFilesActivity.class.getCanonicalName() + ".EXTRA_CHOSEN_FILES"; + + public static final int RESULT_OK_AND_MOVE = RESULT_FIRST_USER; + + private static final String KEY_DIRECTORY_PATH = UploadFilesActivity.class.getCanonicalName() + ".KEY_DIRECTORY_PATH"; + private static final String TAG = "UploadFilesActivity"; + private static final String WAIT_DIALOG_TAG = "WAIT"; + private static final String QUERY_TO_MOVE_DIALOG_TAG = "QUERY_TO_MOVE"; + + + @Override + public void onCreate(Bundle savedInstanceState) { + Log_OC.d(TAG, "onCreate() start"); + super.onCreate(savedInstanceState); + + if(savedInstanceState != null) { + mCurrentDir = new File(savedInstanceState.getString(UploadFilesActivity.KEY_DIRECTORY_PATH)); + } else { + mCurrentDir = Environment.getExternalStorageDirectory(); + } + + mAccountOnCreation = getAccount(); + + /// USER INTERFACE + + // Drop-down navigation + mDirectories = new CustomArrayAdapter(this, R.layout.sherlock_spinner_dropdown_item); + File currDir = mCurrentDir; + while(currDir != null && currDir.getParentFile() != null) { + mDirectories.add(currDir.getName()); + currDir = currDir.getParentFile(); + } + mDirectories.add(File.separator); + + // Inflate and set the layout view + setContentView(R.layout.upload_files_layout); + mFileListFragment = (LocalFileListFragment) getSupportFragmentManager().findFragmentById(R.id.local_files_list); + + + // Set input controllers + mCancelBtn = (CustomButton) findViewById(R.id.upload_files_btn_cancel); + mCancelBtn.setOnClickListener(this); + mUploadBtn = (CustomButton) findViewById(R.id.upload_files_btn_upload); + mUploadBtn.setOnClickListener(this); + + + // Action bar setup + ActionBar actionBar = getSupportActionBar(); + actionBar.setHomeButtonEnabled(true); // mandatory since Android ICS, according to the official documentation + actionBar.setDisplayHomeAsUpEnabled(mCurrentDir != null && mCurrentDir.getName() != null); + actionBar.setDisplayShowTitleEnabled(false); + actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST); + actionBar.setListNavigationCallbacks(mDirectories, this); + + // wait dialog + if (mCurrentDialog != null) { + mCurrentDialog.dismiss(); + mCurrentDialog = null; + } + + Log_OC.d(TAG, "onCreate() end"); + } + + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + boolean retval = true; + switch (item.getItemId()) { + case android.R.id.home: { + if(mCurrentDir != null && mCurrentDir.getParentFile() != null){ + onBackPressed(); + } + break; + } + default: + retval = super.onOptionsItemSelected(item); + } + return retval; + } + + + @Override + public boolean onNavigationItemSelected(int itemPosition, long itemId) { + int i = itemPosition; + while (i-- != 0) { + onBackPressed(); + } + // the next operation triggers a new call to this method, but it's necessary to + // ensure that the name exposed in the action bar is the current directory when the + // user selected it in the navigation list + if (itemPosition != 0) + getSupportActionBar().setSelectedNavigationItem(0); + return true; + } + + + @Override + public void onBackPressed() { + if (mDirectories.getCount() <= 1) { + finish(); + return; + } + popDirname(); + mFileListFragment.onNavigateUp(); + mCurrentDir = mFileListFragment.getCurrentDirectory(); + + if(mCurrentDir.getParentFile() == null){ + ActionBar actionBar = getSupportActionBar(); + actionBar.setDisplayHomeAsUpEnabled(false); + } + } + + + @Override + protected void onSaveInstanceState(Bundle outState) { + // responsibility of restore is preferred in onCreate() before than in onRestoreInstanceState when there are Fragments involved + Log_OC.d(TAG, "onSaveInstanceState() start"); + super.onSaveInstanceState(outState); + outState.putString(UploadFilesActivity.KEY_DIRECTORY_PATH, mCurrentDir.getAbsolutePath()); + Log_OC.d(TAG, "onSaveInstanceState() end"); + } + + + /** + * Pushes a directory to the drop down list + * @param directory to push + * @throws IllegalArgumentException If the {@link File#isDirectory()} returns false. + */ + public void pushDirname(File directory) { + if(!directory.isDirectory()){ + throw new IllegalArgumentException("Only directories may be pushed!"); + } + mDirectories.insert(directory.getName(), 0); + mCurrentDir = directory; + } + + /** + * Pops a directory name from the drop down list + * @return True, unless the stack is empty + */ + public boolean popDirname() { + mDirectories.remove(mDirectories.getItem(0)); + return !mDirectories.isEmpty(); + } + + + // Custom array adapter to override text colors + private class CustomArrayAdapter extends ArrayAdapter { + + public CustomArrayAdapter(UploadFilesActivity ctx, int view) { + super(ctx, view); + } + + public View getView(int position, View convertView, ViewGroup parent) { + View v = super.getView(position, convertView, parent); + + ((TextView) v).setTextColor(getResources().getColorStateList( + android.R.color.white)); + return v; + } + + public View getDropDownView(int position, View convertView, + ViewGroup parent) { + View v = super.getDropDownView(position, convertView, parent); + + ((TextView) v).setTextColor(getResources().getColorStateList( + android.R.color.white)); + + return v; + } + + } + + /** + * {@inheritDoc} + */ + @Override + public void onDirectoryClick(File directory) { + pushDirname(directory); + ActionBar actionBar = getSupportActionBar(); + actionBar.setDisplayHomeAsUpEnabled(true); + } + + + /** + * {@inheritDoc} + */ + @Override + public void onFileClick(File file) { + // nothing to do + } + + /** + * {@inheritDoc} + */ + @Override + public File getInitialDirectory() { + return mCurrentDir; + } + + + /** + * Performs corresponding action when user presses 'Cancel' or 'Upload' button + * + * TODO Make here the real request to the Upload service ; will require to receive the account and + * target folder where the upload must be done in the received intent. + */ + @Override + public void onClick(View v) { + if (v.getId() == R.id.upload_files_btn_cancel) { + setResult(RESULT_CANCELED); + finish(); + + } else if (v.getId() == R.id.upload_files_btn_upload) { + new CheckAvailableSpaceTask().execute(); + } + } + + + /** + * Asynchronous task checking if there is space enough to copy all the files chosen + * to upload into the ownCloud local folder. + * + * Maybe an AsyncTask is not strictly necessary, but who really knows. + * + * @author David A. Velasco + */ + private class CheckAvailableSpaceTask extends AsyncTask { + + /** + * Updates the UI before trying the movement + */ + @Override + protected void onPreExecute () { + /// progress dialog and disable 'Move' button + mCurrentDialog = IndeterminateProgressDialog.newInstance(R.string.wait_a_moment, false); + mCurrentDialog.show(getSupportFragmentManager(), WAIT_DIALOG_TAG); + } + + + /** + * Checks the available space + * + * @return 'True' if there is space enough. + */ + @Override + protected Boolean doInBackground(Void... params) { + String[] checkedFilePaths = mFileListFragment.getCheckedFilePaths(); + long total = 0; + for (int i=0; checkedFilePaths != null && i < checkedFilePaths.length ; i++) { + String localPath = checkedFilePaths[i]; + File localFile = new File(localPath); + total += localFile.length(); + } + return (FileStorageUtils.getUsableSpace(mAccountOnCreation.name) >= total); + } + + /** + * Updates the activity UI after the check of space is done. + * + * If there is not space enough. shows a new dialog to query the user if wants to move the files instead + * of copy them. + * + * @param result 'True' when there is space enough to copy all the selected files. + */ + @Override + protected void onPostExecute(Boolean result) { + mCurrentDialog.dismiss(); + mCurrentDialog = null; + + if (result) { + // return the list of selected files (success) + Intent data = new Intent(); + data.putExtra(EXTRA_CHOSEN_FILES, mFileListFragment.getCheckedFilePaths()); + setResult(RESULT_OK, data); + finish(); + + } else { + // show a dialog to query the user if wants to move the selected files to the ownCloud folder instead of copying + String[] args = {getString(R.string.app_name)}; + ConfirmationDialogFragment dialog = ConfirmationDialogFragment.newInstance(R.string.upload_query_move_foreign_files, args, R.string.common_yes, -1, R.string.common_no); + dialog.setOnConfirmationListener(UploadFilesActivity.this); + dialog.show(getSupportFragmentManager(), QUERY_TO_MOVE_DIALOG_TAG); + } + } + } + + @Override + public void onConfirmation(String callerTag) { + Log_OC.d(TAG, "Positive button in dialog was clicked; dialog tag is " + callerTag); + if (callerTag.equals(QUERY_TO_MOVE_DIALOG_TAG)) { + // return the list of selected files to the caller activity (success), signaling that they should be moved to the ownCloud folder, instead of copied + Intent data = new Intent(); + data.putExtra(EXTRA_CHOSEN_FILES, mFileListFragment.getCheckedFilePaths()); + setResult(RESULT_OK_AND_MOVE, data); + finish(); + } + } + + + @Override + public void onNeutral(String callerTag) { + Log_OC.d(TAG, "Phantom neutral button in dialog was clicked; dialog tag is " + callerTag); + } + + + @Override + public void onCancel(String callerTag) { + /// nothing to do; don't finish, let the user change the selection + Log_OC.d(TAG, "Negative button in dialog was clicked; dialog tag is " + callerTag); + } + + + @Override + protected void onAccountSet(boolean stateWasRecovered) { + if (getAccount() != null) { + if (!mAccountOnCreation.equals(getAccount())) { + setResult(RESULT_CANCELED); + finish(); + } + + } else { + Log_OC.wtf(TAG, "onAccountChanged was called with NULL account associated!"); + setResult(RESULT_CANCELED); + finish(); + } + } + + +}