Uploader.java 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405
  1. /* ownCloud Android client application
  2. * Copyright (C) 2012 Bartek Przybylski
  3. *
  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.
  8. *
  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.
  13. *
  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/>.
  16. *
  17. */
  18. package com.owncloud.android;
  19. import java.io.File;
  20. import java.util.ArrayList;
  21. import java.util.HashMap;
  22. import java.util.LinkedList;
  23. import java.util.List;
  24. import java.util.Stack;
  25. import java.util.Vector;
  26. import com.owncloud.android.authenticator.AccountAuthenticator;
  27. import com.owncloud.android.datamodel.DataStorageManager;
  28. import com.owncloud.android.datamodel.FileDataStorageManager;
  29. import com.owncloud.android.datamodel.OCFile;
  30. import com.owncloud.android.files.services.FileUploader;
  31. import android.accounts.Account;
  32. import android.accounts.AccountManager;
  33. import android.app.AlertDialog;
  34. import android.app.AlertDialog.Builder;
  35. import android.app.Dialog;
  36. import android.app.ListActivity;
  37. import android.app.ProgressDialog;
  38. import android.content.Context;
  39. import android.content.DialogInterface;
  40. import android.content.DialogInterface.OnCancelListener;
  41. import android.content.DialogInterface.OnClickListener;
  42. import android.content.Intent;
  43. import android.database.Cursor;
  44. import android.net.Uri;
  45. import android.os.Bundle;
  46. import android.os.Parcelable;
  47. import android.provider.MediaStore.Images.Media;
  48. import android.util.Log;
  49. import android.view.View;
  50. import android.view.Window;
  51. import android.widget.AdapterView;
  52. import android.widget.AdapterView.OnItemClickListener;
  53. import android.widget.Button;
  54. import android.widget.EditText;
  55. import android.widget.SimpleAdapter;
  56. import android.widget.Toast;
  57. import com.owncloud.android.R;
  58. /**
  59. * This can be used to upload things to an ownCloud instance.
  60. *
  61. * @author Bartek Przybylski
  62. *
  63. */
  64. public class Uploader extends ListActivity implements OnItemClickListener, android.view.View.OnClickListener {
  65. private static final String TAG = "ownCloudUploader";
  66. private Account mAccount;
  67. private AccountManager mAccountManager;
  68. private Stack<String> mParents;
  69. private ArrayList<Parcelable> mStreamsToUpload;
  70. private boolean mCreateDir;
  71. private String mUploadPath;
  72. private static final String[] CONTENT_PROJECTION = { Media.DATA, Media.DISPLAY_NAME, Media.MIME_TYPE, Media.SIZE };
  73. private DataStorageManager mStorageManager;
  74. private OCFile mFile;
  75. private final static int DIALOG_NO_ACCOUNT = 0;
  76. private final static int DIALOG_WAITING = 1;
  77. private final static int DIALOG_NO_STREAM = 2;
  78. private final static int DIALOG_MULTIPLE_ACCOUNT = 3;
  79. //private final static int DIALOG_GET_DIRNAME = 4;
  80. private final static int REQUEST_CODE_SETUP_ACCOUNT = 0;
  81. @Override
  82. protected void onCreate(Bundle savedInstanceState) {
  83. super.onCreate(savedInstanceState);
  84. getWindow().requestFeature(Window.FEATURE_NO_TITLE);
  85. mParents = new Stack<String>();
  86. mParents.add("");
  87. /*if (getIntent().hasExtra(Intent.EXTRA_STREAM)) {
  88. prepareStreamsToUpload();*/
  89. if (prepareStreamsToUpload()) {
  90. mAccountManager = (AccountManager) getSystemService(Context.ACCOUNT_SERVICE);
  91. Account[] accounts = mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE);
  92. if (accounts.length == 0) {
  93. Log.i(TAG, "No ownCloud account is available");
  94. showDialog(DIALOG_NO_ACCOUNT);
  95. } else if (accounts.length > 1) {
  96. Log.i(TAG, "More then one ownCloud is available");
  97. showDialog(DIALOG_MULTIPLE_ACCOUNT);
  98. } else {
  99. mAccount = accounts[0];
  100. mStorageManager = new FileDataStorageManager(mAccount, getContentResolver());
  101. populateDirectoryList();
  102. }
  103. } else {
  104. showDialog(DIALOG_NO_STREAM);
  105. }
  106. }
  107. @Override
  108. protected Dialog onCreateDialog(final int id) {
  109. final AlertDialog.Builder builder = new Builder(this);
  110. switch (id) {
  111. case DIALOG_WAITING:
  112. ProgressDialog pDialog = new ProgressDialog(this);
  113. pDialog.setIndeterminate(false);
  114. pDialog.setCancelable(false);
  115. pDialog.setMessage(getResources().getString(R.string.uploader_info_uploading));
  116. return pDialog;
  117. case DIALOG_NO_ACCOUNT:
  118. builder.setIcon(android.R.drawable.ic_dialog_alert);
  119. builder.setTitle(R.string.uploader_wrn_no_account_title);
  120. builder.setMessage(String.format(getString(R.string.uploader_wrn_no_account_text), getString(R.string.app_name)));
  121. builder.setCancelable(false);
  122. builder.setPositiveButton(R.string.uploader_wrn_no_account_setup_btn_text, new OnClickListener() {
  123. @Override
  124. public void onClick(DialogInterface dialog, int which) {
  125. if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.ECLAIR_MR1) {
  126. // using string value since in API7 this
  127. // constatn is not defined
  128. // in API7 < this constatant is defined in
  129. // Settings.ADD_ACCOUNT_SETTINGS
  130. // and Settings.EXTRA_AUTHORITIES
  131. Intent intent = new Intent("android.settings.ADD_ACCOUNT_SETTINGS");
  132. intent.putExtra("authorities", new String[] { AccountAuthenticator.AUTH_TOKEN_TYPE });
  133. startActivityForResult(intent, REQUEST_CODE_SETUP_ACCOUNT);
  134. } else {
  135. // since in API7 there is no direct call for
  136. // account setup, so we need to
  137. // show our own AccountSetupAcricity, get
  138. // desired results and setup
  139. // everything for ourself
  140. Intent intent = new Intent(getBaseContext(), AccountAuthenticator.class);
  141. startActivityForResult(intent, REQUEST_CODE_SETUP_ACCOUNT);
  142. }
  143. }
  144. });
  145. builder.setNegativeButton(R.string.uploader_wrn_no_account_quit_btn_text, new OnClickListener() {
  146. @Override
  147. public void onClick(DialogInterface dialog, int which) {
  148. finish();
  149. }
  150. });
  151. return builder.create();
  152. /*case DIALOG_GET_DIRNAME:
  153. final EditText dirName = new EditText(getBaseContext());
  154. builder.setView(dirName);
  155. builder.setTitle(R.string.uploader_info_dirname);
  156. String pathToUpload;
  157. if (mParents.empty()) {
  158. pathToUpload = "/";
  159. } else {
  160. mCursor = managedQuery(Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_FILE, mParents.peek()), null,
  161. null, null, null);
  162. mCursor.moveToFirst();
  163. pathToUpload = mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_PATH))
  164. + mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_NAME)).replace(" ", "%20"); // TODO don't make this ; use WebdavUtils.encode in the right moment
  165. }
  166. a a = new a(pathToUpload, dirName);
  167. builder.setPositiveButton(R.string.common_ok, a);
  168. builder.setNegativeButton(R.string.common_cancel, new OnClickListener() {
  169. public void onClick(DialogInterface dialog, int which) {
  170. dialog.cancel();
  171. }
  172. });
  173. return builder.create();*/
  174. case DIALOG_MULTIPLE_ACCOUNT:
  175. CharSequence ac[] = new CharSequence[mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE).length];
  176. for (int i = 0; i < ac.length; ++i) {
  177. ac[i] = mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE)[i].name;
  178. }
  179. builder.setTitle(R.string.common_choose_account);
  180. builder.setItems(ac, new OnClickListener() {
  181. @Override
  182. public void onClick(DialogInterface dialog, int which) {
  183. mAccount = mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE)[which];
  184. mStorageManager = new FileDataStorageManager(mAccount, getContentResolver());
  185. populateDirectoryList();
  186. }
  187. });
  188. builder.setCancelable(true);
  189. builder.setOnCancelListener(new OnCancelListener() {
  190. @Override
  191. public void onCancel(DialogInterface dialog) {
  192. dialog.cancel();
  193. finish();
  194. }
  195. });
  196. return builder.create();
  197. case DIALOG_NO_STREAM:
  198. builder.setIcon(android.R.drawable.ic_dialog_alert);
  199. builder.setTitle(R.string.uploader_wrn_no_content_title);
  200. builder.setMessage(R.string.uploader_wrn_no_content_text);
  201. builder.setCancelable(false);
  202. builder.setNegativeButton(R.string.common_cancel, new OnClickListener() {
  203. @Override
  204. public void onClick(DialogInterface dialog, int which) {
  205. finish();
  206. }
  207. });
  208. return builder.create();
  209. default:
  210. throw new IllegalArgumentException("Unknown dialog id: " + id);
  211. }
  212. }
  213. class a implements OnClickListener {
  214. String mPath;
  215. EditText mDirname;
  216. public a(String path, EditText dirname) {
  217. mPath = path;
  218. mDirname = dirname;
  219. }
  220. @Override
  221. public void onClick(DialogInterface dialog, int which) {
  222. Uploader.this.mUploadPath = mPath + mDirname.getText().toString();
  223. Uploader.this.mCreateDir = true;
  224. uploadFiles();
  225. }
  226. }
  227. @Override
  228. public void onBackPressed() {
  229. if (mParents.size() <= 1) {
  230. super.onBackPressed();
  231. return;
  232. } else {
  233. mParents.pop();
  234. populateDirectoryList();
  235. }
  236. }
  237. @Override
  238. public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
  239. // click on folder in the list
  240. Log.d(TAG, "on item click");
  241. Vector<OCFile> tmpfiles = mStorageManager.getDirectoryContent(mFile);
  242. if (tmpfiles.size() <= 0) return;
  243. // filter on dirtype
  244. Vector<OCFile> files = new Vector<OCFile>();
  245. for (OCFile f : tmpfiles)
  246. if (f.isDirectory())
  247. files.add(f);
  248. if (files.size() < position) {
  249. throw new IndexOutOfBoundsException("Incorrect item selected");
  250. }
  251. mParents.push(files.get(position).getFileName());
  252. populateDirectoryList();
  253. }
  254. @Override
  255. public void onClick(View v) {
  256. // click on button
  257. switch (v.getId()) {
  258. case R.id.uploader_choose_folder:
  259. mUploadPath = ""; // first element in mParents is root dir, represented by ""; init mUploadPath with "/" results in a "//" prefix
  260. for (String p : mParents)
  261. mUploadPath += p + OCFile.PATH_SEPARATOR;
  262. Log.d(TAG, "Uploading file to dir " + mUploadPath);
  263. uploadFiles();
  264. break;
  265. /*case android.R.id.button1: // dynamic action for create aditional dir
  266. showDialog(DIALOG_GET_DIRNAME);
  267. break;*/
  268. default:
  269. throw new IllegalArgumentException("Wrong element clicked");
  270. }
  271. }
  272. @Override
  273. protected void onActivityResult(int requestCode, int resultCode, Intent data) {
  274. super.onActivityResult(requestCode, resultCode, data);
  275. Log.i(TAG, "result received. req: " + requestCode + " res: " + resultCode);
  276. if (requestCode == REQUEST_CODE_SETUP_ACCOUNT) {
  277. dismissDialog(DIALOG_NO_ACCOUNT);
  278. if (resultCode == RESULT_CANCELED) {
  279. finish();
  280. }
  281. Account[] accounts = mAccountManager.getAccountsByType(AccountAuthenticator.AUTH_TOKEN_TYPE);
  282. if (accounts.length == 0) {
  283. showDialog(DIALOG_NO_ACCOUNT);
  284. } else {
  285. // there is no need for checking for is there more then one
  286. // account at this point
  287. // since account setup can set only one account at time
  288. mAccount = accounts[0];
  289. populateDirectoryList();
  290. }
  291. }
  292. }
  293. private void populateDirectoryList() {
  294. setContentView(R.layout.uploader_layout);
  295. String full_path = "";
  296. for (String a : mParents)
  297. full_path += a + "/";
  298. Log.d(TAG, "Populating view with content of : " + full_path);
  299. mFile = mStorageManager.getFileByPath(full_path);
  300. if (mFile != null) {
  301. Vector<OCFile> files = mStorageManager.getDirectoryContent(mFile);
  302. List<HashMap<String, Object>> data = new LinkedList<HashMap<String,Object>>();
  303. for (OCFile f : files) {
  304. HashMap<String, Object> h = new HashMap<String, Object>();
  305. if (f.isDirectory()) {
  306. h.put("dirname", f.getFileName());
  307. data.add(h);
  308. }
  309. }
  310. SimpleAdapter sa = new SimpleAdapter(this,
  311. data,
  312. R.layout.uploader_list_item_layout,
  313. new String[] {"dirname"},
  314. new int[] {R.id.textView1});
  315. setListAdapter(sa);
  316. Button btn = (Button) findViewById(R.id.uploader_choose_folder);
  317. btn.setOnClickListener(this);
  318. getListView().setOnItemClickListener(this);
  319. }
  320. }
  321. private boolean prepareStreamsToUpload() {
  322. if (getIntent().getAction().equals(Intent.ACTION_SEND)) {
  323. mStreamsToUpload = new ArrayList<Parcelable>();
  324. mStreamsToUpload.add(getIntent().getParcelableExtra(Intent.EXTRA_STREAM));
  325. } else if (getIntent().getAction().equals(Intent.ACTION_SEND_MULTIPLE)) {
  326. mStreamsToUpload = getIntent().getParcelableArrayListExtra(Intent.EXTRA_STREAM);
  327. }
  328. return (mStreamsToUpload != null && mStreamsToUpload.get(0) != null);
  329. }
  330. public void uploadFiles() {
  331. try {
  332. /* TODO - mCreateDir can never be true at this moment; we will replace wdc.createDirectory by CreateFolderOperation when that is fixed
  333. WebdavClient wdc = OwnCloudClientUtils.createOwnCloudClient(mAccount, getApplicationContext());
  334. // create last directory in path if necessary
  335. if (mCreateDir) {
  336. wdc.createDirectory(mUploadPath);
  337. }
  338. */
  339. String[] local = new String[mStreamsToUpload.size()], remote = new String[mStreamsToUpload.size()];
  340. for (int i = 0; i < mStreamsToUpload.size(); ++i) {
  341. Uri uri = (Uri) mStreamsToUpload.get(i);
  342. if (uri.getScheme().equals("content")) {
  343. Cursor c = getContentResolver().query((Uri) mStreamsToUpload.get(i),
  344. CONTENT_PROJECTION,
  345. null,
  346. null,
  347. null);
  348. if (!c.moveToFirst())
  349. continue;
  350. final String display_name = c.getString(c.getColumnIndex(Media.DISPLAY_NAME)),
  351. data = c.getString(c.getColumnIndex(Media.DATA));
  352. local[i] = data;
  353. remote[i] = mUploadPath + display_name;
  354. } else if (uri.getScheme().equals("file")) {
  355. final File file = new File(Uri.decode(uri.toString()).replace(uri.getScheme() + "://", ""));
  356. local[i] = file.getAbsolutePath();
  357. remote[i] = mUploadPath + file.getName();
  358. }
  359. }
  360. Intent intent = new Intent(getApplicationContext(), FileUploader.class);
  361. intent.putExtra(FileUploader.KEY_UPLOAD_TYPE, FileUploader.UPLOAD_MULTIPLE_FILES);
  362. intent.putExtra(FileUploader.KEY_LOCAL_FILE, local);
  363. intent.putExtra(FileUploader.KEY_REMOTE_FILE, remote);
  364. intent.putExtra(FileUploader.KEY_ACCOUNT, mAccount);
  365. startService(intent);
  366. finish();
  367. } catch (SecurityException e) {
  368. String message = String.format(getString(R.string.uploader_error_forbidden_content), getString(R.string.app_name));
  369. Toast.makeText(this, message, Toast.LENGTH_LONG).show();
  370. }
  371. }
  372. }