-/* ownCloud Android client application\r
- * Copyright (C) 2011 Bartek Przybylski\r
- *\r
- * This program is free software: you can redistribute it and/or modify\r
- * it under the terms of the GNU General Public License as published by\r
- * the Free Software Foundation, either version 3 of the License, or\r
- * (at your option) any later version.\r
- *\r
- * This program is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
- * GNU General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU General Public License\r
- * along with this program. If not, see <http://www.gnu.org/licenses/>.\r
- *\r
- */\r
-package eu.alefzero.owncloud;\r
-\r
-import java.io.File;\r
-import java.net.FileNameMap;\r
-import java.net.URI;\r
-import java.net.URLConnection;\r
-import java.util.ArrayList;\r
-import java.util.Stack;\r
-\r
-import android.accounts.Account;\r
-import android.accounts.AccountManager;\r
-import android.app.AlertDialog;\r
-import android.app.Dialog;\r
-import android.app.ListActivity;\r
-import android.app.ProgressDialog;\r
-import android.app.AlertDialog.Builder;\r
-import android.content.ContentValues;\r
-import android.content.Context;\r
-import android.content.DialogInterface;\r
-import android.content.Intent;\r
-import android.content.DialogInterface.OnCancelListener;\r
-import android.content.DialogInterface.OnClickListener;\r
-import android.database.Cursor;\r
-import android.net.Uri;\r
-import android.os.Bundle;\r
-import android.os.Handler;\r
-import android.os.Parcelable;\r
-import android.provider.MediaStore.Images.Media;\r
-import android.util.Log;\r
-import android.view.View;\r
-import android.view.Window;\r
-import android.view.ViewGroup.LayoutParams;\r
-import android.widget.AdapterView;\r
-import android.widget.Button;\r
-import android.widget.EditText;\r
-import android.widget.LinearLayout;\r
-import android.widget.ListView;\r
-import android.widget.SimpleCursorAdapter;\r
-import android.widget.Toast;\r
-import android.widget.AdapterView.OnItemClickListener;\r
-import eu.alefzero.owncloud.authenticator.AccountAuthenticator;\r
-import eu.alefzero.owncloud.db.ProviderMeta;\r
-import eu.alefzero.owncloud.db.ProviderMeta.ProviderTableMeta;\r
-import eu.alefzero.webdav.WebdavClient;\r
-import eu.alefzero.webdav.WebdavUtils;\r
-\r
-/**\r
- * This can be used to upload things to an ownCloud instance.\r
- * @author Bartek Przybylski\r
- *\r
- */\r
-public class Uploader extends ListActivity implements OnItemClickListener, android.view.View.OnClickListener {\r
- private static final String TAG = "ownCloudUploader";\r
-\r
- private Account mAccount;\r
- private AccountManager mAccountManager;\r
- private String mUsername, mPassword;\r
- private Cursor mCursor;\r
- private Stack<String> mParents;\r
- private Thread mUploadThread;\r
- private Handler mHandler;\r
- private ArrayList<Parcelable> mStreamsToUpload;\r
-\r
- private final static int DIALOG_NO_ACCOUNT = 0;\r
- private final static int DIALOG_WAITING = 1;\r
- private final static int DIALOG_NO_STREAM = 2;\r
- private final static int DIALOG_MULTIPLE_ACCOUNT = 3;\r
- private final static int DIALOG_GET_DIRNAME = 4;\r
-\r
- private final static int REQUEST_CODE_SETUP_ACCOUNT = 0;\r
-\r
- @Override\r
- protected void onCreate(Bundle savedInstanceState) {\r
- super.onCreate(savedInstanceState);\r
- getWindow().requestFeature(Window.FEATURE_NO_TITLE);\r
- mParents = new Stack<String>();\r
- mHandler = new Handler();\r
- if (getIntent().hasExtra(Intent.EXTRA_STREAM)) {\r
- prepareStreamsToUpload();\r
- mAccountManager = (AccountManager)getSystemService(Context.ACCOUNT_SERVICE);\r
- Account[] accounts = mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE);\r
- if (accounts.length == 0) {\r
- Log.i(TAG, "No ownCloud account is available");\r
- showDialog(DIALOG_NO_ACCOUNT);\r
- } else if (accounts.length > 1) {\r
- Log.i(TAG, "More then one ownCloud is available");\r
- showDialog(DIALOG_MULTIPLE_ACCOUNT);\r
- } else {\r
- mAccount = accounts[0];\r
- setContentView(R.layout.uploader_layout);\r
- populateDirectoryList();\r
- }\r
- } else {\r
- showDialog(DIALOG_NO_STREAM);\r
- }\r
- }\r
-\r
- @Override\r
- protected Dialog onCreateDialog(final int id) {\r
- final AlertDialog.Builder builder = new Builder(this);\r
- switch (id) {\r
- case DIALOG_WAITING:\r
- ProgressDialog pDialog = new ProgressDialog(this);\r
- pDialog.setIndeterminate(false);\r
- pDialog.setCancelable(false);\r
- pDialog.setMessage(getResources().getString(R.string.uploader_info_uploading));\r
- return pDialog;\r
- case DIALOG_NO_ACCOUNT:\r
- builder.setIcon(android.R.drawable.ic_dialog_alert);\r
- builder.setTitle(R.string.uploader_wrn_no_account_title);\r
- builder.setMessage(R.string.uploader_wrn_no_account_text);\r
- builder.setCancelable(false);\r
- builder.setPositiveButton(R.string.uploader_wrn_no_account_setup_btn_text, new OnClickListener() {\r
- public void onClick(DialogInterface dialog, int which) {\r
- if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.ECLAIR_MR1) {\r
- // using string value since in API7 this constatn is not defined\r
- // in API7 < this constatant is defined in Settings.ADD_ACCOUNT_SETTINGS\r
- // and Settings.EXTRA_AUTHORITIES\r
- Intent intent = new Intent("android.settings.ADD_ACCOUNT_SETTINGS");\r
- intent.putExtra("authorities", new String[] {AccountAuthenticator.AUTH_TOKEN_TYPE});\r
- startActivityForResult(intent, REQUEST_CODE_SETUP_ACCOUNT);\r
- } else {\r
- // since in API7 there is no direct call for account setup, so we need to\r
- // show our own AccountSetupAcricity, get desired results and setup\r
- // everything for ourself\r
- Intent intent = new Intent(getBaseContext(), AccountAuthenticator.class);\r
- startActivityForResult(intent, REQUEST_CODE_SETUP_ACCOUNT);\r
- }\r
- }\r
- });\r
- builder.setNegativeButton(R.string.uploader_wrn_no_account_quit_btn_text, new OnClickListener() {\r
- public void onClick(DialogInterface dialog, int which) {\r
- finish();\r
- }\r
- });\r
- return builder.create();\r
- case DIALOG_GET_DIRNAME:\r
- final EditText dirName = new EditText(getBaseContext());\r
- builder.setView(dirName);\r
- builder.setTitle(R.string.uploader_info_dirname);\r
- String pathToUpload;\r
- if (mParents.empty()) {\r
- pathToUpload = "/";\r
- } else {\r
- mCursor = managedQuery(Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_FILE, mParents.peek()), \r
- null,\r
- null,\r
- null,\r
- null);\r
- mCursor.moveToFirst();\r
- pathToUpload = mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_PATH)) +\r
- mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_NAME)).replace(" ", "%20");\r
- }\r
- a a = new a(pathToUpload, dirName);\r
- builder.setPositiveButton(R.string.common_ok, a);\r
- builder.setNegativeButton(R.string.common_cancel, new OnClickListener() {\r
- public void onClick(DialogInterface dialog, int which) {\r
- dialog.cancel();\r
- }\r
- });\r
- return builder.create();\r
- case DIALOG_MULTIPLE_ACCOUNT:\r
- CharSequence ac[] = new CharSequence[mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE).length];\r
- for (int i = 0; i < ac.length; ++i) {\r
- ac[i] = mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE)[i].name;\r
- }\r
- builder.setTitle(R.string.common_choose_account);\r
- builder.setItems(ac, new OnClickListener() {\r
- public void onClick(DialogInterface dialog, int which) {\r
- mAccount = mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE)[which];\r
- populateDirectoryList();\r
- }\r
- });\r
- builder.setCancelable(true);\r
- builder.setOnCancelListener(new OnCancelListener() {\r
- public void onCancel(DialogInterface dialog) {\r
- dialog.cancel();\r
- finish();\r
- }\r
- });\r
- return builder.create();\r
- default:\r
- throw new IllegalArgumentException("Unknown dialog id: " + id);\r
- }\r
- }\r
- \r
- class a implements OnClickListener {\r
- String mPath;\r
- EditText mDirname;\r
- public a(String path, EditText dirname) {\r
- mPath = path; mDirname = dirname;\r
- }\r
- public void onClick(DialogInterface dialog, int which) {\r
- showDialog(DIALOG_WAITING);\r
- mUploadThread = new Thread(new BackgroundUploader(mPath+mDirname.getText().toString(), mStreamsToUpload, mHandler, true));\r
- mUploadThread.start();\r
- }\r
- }\r
- \r
- @Override\r
- public void onBackPressed() {\r
- \r
- if (mParents.size()==0) {\r
- super.onBackPressed();\r
- return;\r
- } else if (mParents.size() == 1) {\r
- mParents.pop();\r
- mCursor = managedQuery(ProviderTableMeta.CONTENT_URI,\r
- null,\r
- ProviderTableMeta.FILE_CONTENT_TYPE+"=?",\r
- new String[]{"DIR"},\r
- null);\r
- } else {\r
- mParents.pop();\r
- mCursor = managedQuery(Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_DIR, mParents.peek()),\r
- null,\r
- ProviderTableMeta.FILE_CONTENT_TYPE+"=?",\r
- new String[]{"DIR"},\r
- null);\r
- }\r
- \r
- SimpleCursorAdapter sca = new SimpleCursorAdapter(this, R.layout.uploader_list_item_layout,\r
- mCursor,\r
- new String[]{ProviderTableMeta.FILE_NAME},\r
- new int[]{R.id.textView1});\r
- setListAdapter(sca);\r
- }\r
- \r
- public void onItemClick(AdapterView<?> parent, View view, int position, long id) {\r
- if (!mCursor.moveToPosition(position)) {\r
- throw new IndexOutOfBoundsException("Incorrect item selected");\r
- }\r
- String _id = mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta._ID));\r
- mParents.push(_id);\r
- \r
- mCursor.close();\r
- mCursor = managedQuery(Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_DIR, _id),\r
- null,\r
- ProviderTableMeta.FILE_CONTENT_TYPE+"=?",\r
- new String[]{"DIR"},\r
- null);\r
- SimpleCursorAdapter sca = new SimpleCursorAdapter(this, R.layout.uploader_list_item_layout,\r
- mCursor,\r
- new String[]{ProviderTableMeta.FILE_NAME},\r
- new int[]{R.id.textView1});\r
- setListAdapter(sca);\r
- getListView().invalidate();\r
- }\r
-\r
- public void onClick(View v) {\r
- switch (v.getId()) {\r
- case R.id.uploader_choose_folder:\r
- String pathToUpload = null;\r
- if (mParents.empty()) {\r
- pathToUpload = "/";\r
- } else {\r
- mCursor = managedQuery(Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_FILE, mParents.peek()), \r
- null,\r
- null,\r
- null,\r
- null);\r
- mCursor.moveToFirst();\r
- pathToUpload = mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_PATH)) +\r
- mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_NAME)).replace(" ", "%20");\r
- }\r
- \r
- showDialog(DIALOG_WAITING);\r
- mUploadThread = new Thread(new BackgroundUploader(pathToUpload, mStreamsToUpload, mHandler));\r
- mUploadThread.start();\r
- \r
- break;\r
- case android.R.id.button1: // dynamic action for create aditional dir\r
- showDialog(DIALOG_GET_DIRNAME);\r
- break;\r
- default:\r
- throw new IllegalArgumentException("Wrong element clicked");\r
- }\r
- }\r
-\r
- public void onUploadComplete(boolean uploadSucc, String message) {\r
- dismissDialog(DIALOG_WAITING);\r
- Log.i(TAG, "UploadSucc: " + uploadSucc + " message: " + message);\r
- if (uploadSucc) {\r
- Toast.makeText(this, getResources().getString(R.string.uploader_upload_succeed), Toast.LENGTH_SHORT).show();\r
- } else {\r
- Toast.makeText(this, getResources().getString(R.string.uploader_upload_failed) + message, Toast.LENGTH_LONG).show();\r
- }\r
- finish();\r
- }\r
- \r
- @Override\r
- protected void onActivityResult(int requestCode, int resultCode, Intent data) {\r
- super.onActivityResult(requestCode, resultCode, data);\r
- Log.i(TAG, "result received. req: " + requestCode + " res: " + resultCode);\r
- if (requestCode == REQUEST_CODE_SETUP_ACCOUNT) {\r
- dismissDialog(DIALOG_NO_ACCOUNT);\r
- if (resultCode == RESULT_CANCELED) {\r
- finish();\r
- }\r
- Account[] accounts = mAccountManager.getAccountsByType(AccountAuthenticator.AUTH_TOKEN_TYPE);\r
- if (accounts.length == 0) {\r
- showDialog(DIALOG_NO_ACCOUNT);\r
- } else {\r
- // there is no need for checking for is there more then one account at this point\r
- // since account setup can set only one account at time\r
- mAccount = accounts[0];\r
- populateDirectoryList();\r
- }\r
- }\r
- }\r
- \r
- private void populateDirectoryList() {\r
- mUsername = mAccount.name.substring(0, mAccount.name.indexOf('@'));\r
- mPassword = mAccountManager.getPassword(mAccount);\r
- setContentView(R.layout.uploader_layout);\r
- mCursor = managedQuery(ProviderMeta.ProviderTableMeta.CONTENT_URI,\r
- null,\r
- ProviderTableMeta.FILE_CONTENT_TYPE+"=? AND " + ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?",\r
- new String[]{"DIR", mAccount.name},\r
- null);\r
-\r
- ListView lv = getListView();\r
- lv.setOnItemClickListener(this);\r
- SimpleCursorAdapter sca = new SimpleCursorAdapter(this,\r
- R.layout.uploader_list_item_layout,\r
- mCursor,\r
- new String[]{ProviderTableMeta.FILE_NAME},\r
- new int[]{R.id.textView1});\r
- setListAdapter(sca);\r
- Button btn = (Button) findViewById(R.id.uploader_choose_folder);\r
- btn.setOnClickListener(this);\r
- // insert create new directory for multiple items uploading\r
- if (getIntent().getAction().equals(Intent.ACTION_SEND_MULTIPLE)) {\r
- Button createDirBtn = new Button(this);\r
- createDirBtn.setId(android.R.id.button1);\r
- createDirBtn.setText(R.string.uploader_btn_create_dir_text);\r
- createDirBtn.setOnClickListener(this);\r
- ((LinearLayout)findViewById(R.id.linearLayout1)).addView(createDirBtn, LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);\r
- }\r
- }\r
- \r
- private void prepareStreamsToUpload() {\r
- if (getIntent().getAction().equals(Intent.ACTION_SEND)) {\r
- mStreamsToUpload = new ArrayList<Parcelable>();\r
- mStreamsToUpload.add(getIntent().getParcelableExtra(Intent.EXTRA_STREAM));\r
- } else if (getIntent().getAction().equals(Intent.ACTION_SEND_MULTIPLE)) {\r
- mStreamsToUpload = getIntent().getParcelableArrayListExtra(Intent.EXTRA_STREAM);\r
- } else {\r
- // unknow action inserted\r
- throw new IllegalArgumentException("Unknown action given: " + getIntent().getAction());\r
- }\r
- }\r
- \r
- public void PartialupdateUpload(String fileLocalPath, String filename, String filepath, String contentType, String contentLength) {\r
- ContentValues cv = new ContentValues();\r
- cv.put(ProviderTableMeta.FILE_NAME, filename);\r
- cv.put(ProviderTableMeta.FILE_PATH, filepath);\r
- cv.put(ProviderTableMeta.FILE_STORAGE_PATH, fileLocalPath);\r
- cv.put(ProviderTableMeta.FILE_MODIFIED, WebdavUtils.DISPLAY_DATE_FORMAT.format(new java.util.Date()));\r
- cv.put(ProviderTableMeta.FILE_CONTENT_TYPE, contentType);\r
- cv.put(ProviderTableMeta.FILE_CONTENT_LENGTH, contentLength);\r
- cv.put(ProviderTableMeta.FILE_ACCOUNT_OWNER, mAccount.name);\r
- Log.d(TAG, filename+" ++ "+filepath+" ++ " + contentLength + " ++ " + contentType + " ++ " + fileLocalPath);\r
- if (!mParents.empty()) {\r
- Cursor c = managedQuery(Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_FILE, mParents.peek()),\r
- null,\r
- null,\r
- null,\r
- null);\r
- c.moveToFirst();\r
- cv.put(ProviderTableMeta.FILE_PARENT, c.getString(c.getColumnIndex(ProviderTableMeta._ID)));\r
- c.close();\r
- }\r
- getContentResolver().insert(ProviderTableMeta.CONTENT_URI_FILE, cv);\r
- }\r
- \r
- class BackgroundUploader implements Runnable {\r
- private ArrayList<Parcelable> mUploadStreams;\r
- private Handler mHandler;\r
- private String mUploadPath;\r
- private boolean mCreateDir;\r
- \r
- public BackgroundUploader(String pathToUpload, ArrayList<Parcelable> streamsToUpload,\r
- Handler handler) {\r
- mUploadStreams = streamsToUpload;\r
- mHandler = handler;\r
- mUploadPath = pathToUpload.replace(" ", "%20");\r
- mCreateDir = false;\r
- }\r
-\r
- public BackgroundUploader(String pathToUpload, ArrayList<Parcelable> streamsToUpload,\r
- Handler handler, boolean createDir) {\r
- mUploadStreams = streamsToUpload;\r
- mHandler = handler;\r
- mUploadPath = pathToUpload.replace(" ", "%20");\r
- mCreateDir = createDir;\r
- }\r
-\r
- public void run() {\r
- WebdavClient wdc = new WebdavClient(Uri.parse(mAccountManager.getUserData(mAccount,\r
- AccountAuthenticator.KEY_OC_URL)));\r
- wdc.setCredentials(mUsername, mPassword);\r
- wdc.allowUnsignedCertificates();\r
-\r
- // create last directory in path if nessesary\r
- if (mCreateDir) {\r
- wdc.createDirectory(mUploadPath);\r
- }\r
- \r
- for (int i = 0; i < mUploadStreams.size(); ++i) {\r
- Uri uri = (Uri) mUploadStreams.get(i);\r
- if (uri.getScheme().equals("content")) {\r
- final Cursor c = getContentResolver().query((Uri) mUploadStreams.get(i), null, null, null, null);\r
- c.moveToFirst();\r
- \r
- if (!wdc.putFile(c.getString(c.getColumnIndex(Media.DATA)),\r
- mUploadPath+"/"+c.getString(c.getColumnIndex(Media.DISPLAY_NAME)),\r
- c.getString(c.getColumnIndex(Media.MIME_TYPE)))) {\r
- mHandler.post(new Runnable() {\r
- public void run() {\r
- Uploader.this.onUploadComplete(false, "Error while uploading file: " + c.getString(c.getColumnIndex(Media.DISPLAY_NAME)));\r
- }\r
- });\r
- } else {\r
- mHandler.post(new Runnable() {\r
- public void run() {\r
- Uploader.this.PartialupdateUpload(c.getString(c.getColumnIndex(Media.DATA)),\r
- c.getString(c.getColumnIndex(Media.DISPLAY_NAME)),\r
- mUploadPath+"/"+c.getString(c.getColumnIndex(Media.DISPLAY_NAME)),\r
- c.getString(c.getColumnIndex(Media.MIME_TYPE)),\r
- c.getString(c.getColumnIndex(Media.SIZE)));\r
- }\r
- });\r
- }\r
- } else if (uri.getScheme().equals("file")) {\r
- final File file = new File(Uri.decode(uri.toString()).replace(uri.getScheme()+"://", ""));\r
- FileNameMap fileNameMap = URLConnection.getFileNameMap();\r
- String contentType = fileNameMap.getContentTypeFor(uri.toString());\r
- if (contentType == null) {\r
- contentType = "text/plain";\r
- }\r
- if (!wdc.putFile(file.getAbsolutePath(), mUploadPath+"/"+file.getName(), contentType)) {\r
- mHandler.post(new Runnable() {\r
- public void run() {\r
- Uploader.this.onUploadComplete(false, "Error while uploading file: " + file.getName());\r
- }\r
- });\r
- }\r
- }\r
- \r
- }\r
- mHandler.post(new Runnable() {\r
- public void run() {\r
- Uploader.this.onUploadComplete(true, null);\r
- }\r
- });\r
- }\r
-\r
- }\r
- \r
-}\r