downloading file
[pub/Android/ownCloud.git] / src / eu / alefzero / owncloud / Uploader.java
1 package eu.alefzero.owncloud;
2
3 import java.io.File;
4 import java.net.FileNameMap;
5 import java.net.URI;
6 import java.net.URLConnection;
7 import java.util.ArrayList;
8 import java.util.Stack;
9
10 import android.accounts.Account;
11 import android.accounts.AccountManager;
12 import android.app.AlertDialog;
13 import android.app.Dialog;
14 import android.app.ListActivity;
15 import android.app.ProgressDialog;
16 import android.app.AlertDialog.Builder;
17 import android.content.ContentValues;
18 import android.content.Context;
19 import android.content.DialogInterface;
20 import android.content.Intent;
21 import android.content.DialogInterface.OnCancelListener;
22 import android.content.DialogInterface.OnClickListener;
23 import android.database.Cursor;
24 import android.net.Uri;
25 import android.os.Bundle;
26 import android.os.Handler;
27 import android.os.Parcelable;
28 import android.provider.MediaStore.Images.Media;
29 import android.util.Log;
30 import android.view.View;
31 import android.view.Window;
32 import android.view.ViewGroup.LayoutParams;
33 import android.widget.AdapterView;
34 import android.widget.Button;
35 import android.widget.EditText;
36 import android.widget.LinearLayout;
37 import android.widget.ListView;
38 import android.widget.SimpleCursorAdapter;
39 import android.widget.Toast;
40 import android.widget.AdapterView.OnItemClickListener;
41 import eu.alefzero.owncloud.authenticator.AccountAuthenticator;
42 import eu.alefzero.owncloud.db.ProviderMeta;
43 import eu.alefzero.owncloud.db.ProviderMeta.ProviderTableMeta;
44 import eu.alefzero.webdav.WebdavUtils;
45
46 public class Uploader extends ListActivity implements OnItemClickListener, android.view.View.OnClickListener {
47 private static final String TAG = "ownCloudUploader";
48
49 private Account mAccount;
50 private AccountManager mAccountManager;
51 private String mUsername, mPassword;
52 private Cursor mCursor;
53 private Stack<String> mParents;
54 private Thread mUploadThread;
55 private Handler mHandler;
56 private ArrayList<Parcelable> mStreamsToUpload;
57
58 private final static int DIALOG_NO_ACCOUNT = 0;
59 private final static int DIALOG_WAITING = 1;
60 private final static int DIALOG_NO_STREAM = 2;
61 private final static int DIALOG_MULTIPLE_ACCOUNT = 3;
62 private final static int DIALOG_GET_DIRNAME = 4;
63
64 private final static int REQUEST_CODE_SETUP_ACCOUNT = 0;
65
66 @Override
67 protected void onCreate(Bundle savedInstanceState) {
68 super.onCreate(savedInstanceState);
69 getWindow().requestFeature(Window.FEATURE_NO_TITLE);
70 mParents = new Stack<String>();
71 mHandler = new Handler();
72 if (getIntent().hasExtra(Intent.EXTRA_STREAM)) {
73 prepareStreamsToUpload();
74 mAccountManager = (AccountManager)getSystemService(Context.ACCOUNT_SERVICE);
75 Account[] accounts = mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE);
76 if (accounts.length == 0) {
77 Log.i(TAG, "No ownCloud account is available");
78 showDialog(DIALOG_NO_ACCOUNT);
79 } else if (accounts.length > 1) {
80 Log.i(TAG, "More then one ownCloud is available");
81 showDialog(DIALOG_MULTIPLE_ACCOUNT);
82 } else {
83 mAccount = accounts[0];
84 setContentView(R.layout.uploader_layout);
85 populateDirectoryList();
86 }
87 } else {
88 showDialog(DIALOG_NO_STREAM);
89 }
90 }
91
92 @Override
93 protected Dialog onCreateDialog(final int id) {
94 final AlertDialog.Builder builder = new Builder(this);
95 switch (id) {
96 case DIALOG_WAITING:
97 ProgressDialog pDialog = new ProgressDialog(this);
98 pDialog.setIndeterminate(false);
99 pDialog.setCancelable(false);
100 pDialog.setMessage(getResources().getString(R.string.uploader_info_uploading));
101 return pDialog;
102 case DIALOG_NO_ACCOUNT:
103 builder.setIcon(android.R.drawable.ic_dialog_alert);
104 builder.setTitle(R.string.uploader_wrn_no_account_title);
105 builder.setMessage(R.string.uploader_wrn_no_account_text);
106 builder.setCancelable(false);
107 builder.setPositiveButton(R.string.uploader_wrn_no_account_setup_btn_text, new OnClickListener() {
108 public void onClick(DialogInterface dialog, int which) {
109 if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.ECLAIR_MR1) {
110 // using string value since in API7 this constatn is not defined
111 // in API7 < this constatant is defined in Settings.ADD_ACCOUNT_SETTINGS
112 // and Settings.EXTRA_AUTHORITIES
113 Intent intent = new Intent("android.settings.ADD_ACCOUNT_SETTINGS");
114 intent.putExtra("authorities", new String[] {AccountAuthenticator.AUTH_TOKEN_TYPE});
115 startActivityForResult(intent, REQUEST_CODE_SETUP_ACCOUNT);
116 } else {
117 // since in API7 there is no direct call for account setup, so we need to
118 // show our own AccountSetupAcricity, get desired results and setup
119 // everything for ourself
120 Intent intent = new Intent(getBaseContext(), AccountAuthenticator.class);
121 startActivityForResult(intent, REQUEST_CODE_SETUP_ACCOUNT);
122 }
123 }
124 });
125 builder.setNegativeButton(R.string.uploader_wrn_no_account_quit_btn_text, new OnClickListener() {
126 public void onClick(DialogInterface dialog, int which) {
127 finish();
128 }
129 });
130 return builder.create();
131 case DIALOG_GET_DIRNAME:
132 final EditText dirName = new EditText(getBaseContext());
133 builder.setView(dirName);
134 builder.setTitle(R.string.uploader_info_dirname);
135 String pathToUpload;
136 if (mParents.empty()) {
137 pathToUpload = "/";
138 } else {
139 mCursor = managedQuery(Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_FILE, mParents.peek()),
140 null,
141 null,
142 null,
143 null);
144 mCursor.moveToFirst();
145 pathToUpload = mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_PATH)) +
146 mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_NAME)).replace(" ", "%20");
147 }
148 a a = new a(pathToUpload, dirName);
149 builder.setPositiveButton(R.string.common_ok, a);
150 builder.setNegativeButton(R.string.common_cancel, new OnClickListener() {
151 public void onClick(DialogInterface dialog, int which) {
152 dialog.cancel();
153 }
154 });
155 return builder.create();
156 case DIALOG_MULTIPLE_ACCOUNT:
157 CharSequence ac[] = new CharSequence[mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE).length];
158 for (int i = 0; i < ac.length; ++i) {
159 ac[i] = mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE)[i].name;
160 }
161 builder.setTitle(R.string.common_choose_account);
162 builder.setItems(ac, new OnClickListener() {
163 public void onClick(DialogInterface dialog, int which) {
164 mAccount = mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE)[which];
165 populateDirectoryList();
166 }
167 });
168 builder.setCancelable(true);
169 builder.setOnCancelListener(new OnCancelListener() {
170 public void onCancel(DialogInterface dialog) {
171 dialog.cancel();
172 finish();
173 }
174 });
175 return builder.create();
176 default:
177 throw new IllegalArgumentException("Unknown dialog id: " + id);
178 }
179 }
180
181 class a implements OnClickListener {
182 String mPath;
183 EditText mDirname;
184 public a(String path, EditText dirname) {
185 mPath = path; mDirname = dirname;
186 }
187 public void onClick(DialogInterface dialog, int which) {
188 showDialog(DIALOG_WAITING);
189 mUploadThread = new Thread(new BackgroundUploader(mPath+mDirname.getText().toString(), mStreamsToUpload, mHandler, true));
190 mUploadThread.start();
191 }
192 }
193
194 @Override
195 public void onBackPressed() {
196
197 if (mParents.size()==0) {
198 super.onBackPressed();
199 return;
200 } else if (mParents.size() == 1) {
201 mParents.pop();
202 mCursor = managedQuery(ProviderTableMeta.CONTENT_URI,
203 null,
204 ProviderTableMeta.FILE_CONTENT_TYPE+"=?",
205 new String[]{"DIR"},
206 null);
207 } else {
208 mParents.pop();
209 mCursor = managedQuery(Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_DIR, mParents.peek()),
210 null,
211 ProviderTableMeta.FILE_CONTENT_TYPE+"=?",
212 new String[]{"DIR"},
213 null);
214 }
215
216 SimpleCursorAdapter sca = new SimpleCursorAdapter(this, R.layout.uploader_list_item_layout,
217 mCursor,
218 new String[]{ProviderTableMeta.FILE_NAME},
219 new int[]{R.id.textView1});
220 setListAdapter(sca);
221 }
222
223 public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
224 if (!mCursor.moveToPosition(position)) {
225 throw new IndexOutOfBoundsException("Incorrect item selected");
226 }
227 String _id = mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta._ID));
228 mParents.push(_id);
229
230 mCursor.close();
231 mCursor = managedQuery(Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_DIR, _id),
232 null,
233 ProviderTableMeta.FILE_CONTENT_TYPE+"=?",
234 new String[]{"DIR"},
235 null);
236 SimpleCursorAdapter sca = new SimpleCursorAdapter(this, R.layout.uploader_list_item_layout,
237 mCursor,
238 new String[]{ProviderTableMeta.FILE_NAME},
239 new int[]{R.id.textView1});
240 setListAdapter(sca);
241 getListView().invalidate();
242 }
243
244 public void onClick(View v) {
245 switch (v.getId()) {
246 case R.id.uploader_choose_folder:
247 String pathToUpload = null;
248 if (mParents.empty()) {
249 pathToUpload = "/";
250 } else {
251 mCursor = managedQuery(Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_FILE, mParents.peek()),
252 null,
253 null,
254 null,
255 null);
256 mCursor.moveToFirst();
257 pathToUpload = mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_PATH)) +
258 mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_NAME)).replace(" ", "%20");
259 }
260
261 showDialog(DIALOG_WAITING);
262 mUploadThread = new Thread(new BackgroundUploader(pathToUpload, mStreamsToUpload, mHandler));
263 mUploadThread.start();
264
265 break;
266 case android.R.id.button1: // dynamic action for create aditional dir
267 showDialog(DIALOG_GET_DIRNAME);
268 break;
269 default:
270 throw new IllegalArgumentException("Wrong element clicked");
271 }
272 }
273
274 public void onUploadComplete(boolean uploadSucc, String message) {
275 dismissDialog(DIALOG_WAITING);
276 Log.i(TAG, "UploadSucc: " + uploadSucc + " message: " + message);
277 if (uploadSucc) {
278 Toast.makeText(this, getResources().getString(R.string.uploader_upload_succeed), Toast.LENGTH_SHORT).show();
279 } else {
280 Toast.makeText(this, getResources().getString(R.string.uploader_upload_failed) + message, Toast.LENGTH_LONG).show();
281 }
282 finish();
283 }
284
285 @Override
286 protected void onActivityResult(int requestCode, int resultCode, Intent data) {
287 super.onActivityResult(requestCode, resultCode, data);
288 Log.i(TAG, "result received. req: " + requestCode + " res: " + resultCode);
289 if (requestCode == REQUEST_CODE_SETUP_ACCOUNT) {
290 dismissDialog(DIALOG_NO_ACCOUNT);
291 if (resultCode == RESULT_CANCELED) {
292 finish();
293 }
294 Account[] accounts = mAccountManager.getAccountsByType(AccountAuthenticator.AUTH_TOKEN_TYPE);
295 if (accounts.length == 0) {
296 showDialog(DIALOG_NO_ACCOUNT);
297 } else {
298 // there is no need for checking for is there more then one account at this point
299 // since account setup can set only one account at time
300 mAccount = accounts[0];
301 populateDirectoryList();
302 }
303 }
304 }
305
306 private void populateDirectoryList() {
307 mUsername = mAccount.name.substring(0, mAccount.name.indexOf('@'));
308 mPassword = mAccountManager.getPassword(mAccount);
309 setContentView(R.layout.uploader_layout);
310 mCursor = managedQuery(ProviderMeta.ProviderTableMeta.CONTENT_URI,
311 null,
312 ProviderTableMeta.FILE_CONTENT_TYPE+"=? AND " + ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?",
313 new String[]{"DIR", mAccount.name},
314 null);
315
316 ListView lv = getListView();
317 lv.setOnItemClickListener(this);
318 SimpleCursorAdapter sca = new SimpleCursorAdapter(this,
319 R.layout.uploader_list_item_layout,
320 mCursor,
321 new String[]{ProviderTableMeta.FILE_NAME},
322 new int[]{R.id.textView1});
323 setListAdapter(sca);
324 Button btn = (Button) findViewById(R.id.uploader_choose_folder);
325 btn.setOnClickListener(this);
326 // insert create new directory for multiple items uploading
327 if (getIntent().getAction().equals(Intent.ACTION_SEND_MULTIPLE)) {
328 Button createDirBtn = new Button(this);
329 createDirBtn.setId(android.R.id.button1);
330 createDirBtn.setText(R.string.uploader_btn_create_dir_text);
331 createDirBtn.setOnClickListener(this);
332 ((LinearLayout)findViewById(R.id.linearLayout1)).addView(createDirBtn, LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);
333 }
334 }
335
336 private void prepareStreamsToUpload() {
337 if (getIntent().getAction().equals(Intent.ACTION_SEND)) {
338 mStreamsToUpload = new ArrayList<Parcelable>();
339 mStreamsToUpload.add(getIntent().getParcelableExtra(Intent.EXTRA_STREAM));
340 } else if (getIntent().getAction().equals(Intent.ACTION_SEND_MULTIPLE)) {
341 mStreamsToUpload = getIntent().getParcelableArrayListExtra(Intent.EXTRA_STREAM);
342 } else {
343 // unknow action inserted
344 throw new IllegalArgumentException("Unknown action given: " + getIntent().getAction());
345 }
346 }
347
348 public void PartialupdateUpload(String fileLocalPath, String filename, String filepath, String contentType, String contentLength) {
349 ContentValues cv = new ContentValues();
350 cv.put(ProviderTableMeta.FILE_NAME, filename);
351 cv.put(ProviderTableMeta.FILE_PATH, filepath);
352 cv.put(ProviderTableMeta.FILE_STORAGE_PATH, fileLocalPath);
353 cv.put(ProviderTableMeta.FILE_MODIFIED, WebdavUtils.DISPLAY_DATE_FORMAT.format(new java.util.Date()));
354 cv.put(ProviderTableMeta.FILE_CONTENT_TYPE, contentType);
355 cv.put(ProviderTableMeta.FILE_CONTENT_LENGTH, contentLength);
356 cv.put(ProviderTableMeta.FILE_ACCOUNT_OWNER, mAccount.name);
357 Log.d(TAG, filename+" ++ "+filepath+" ++ " + contentLength + " ++ " + contentType + " ++ " + fileLocalPath);
358 if (!mParents.empty()) {
359 Cursor c = managedQuery(Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_FILE, mParents.peek()),
360 null,
361 null,
362 null,
363 null);
364 c.moveToFirst();
365 cv.put(ProviderTableMeta.FILE_PARENT, c.getString(c.getColumnIndex(ProviderTableMeta._ID)));
366 c.close();
367 }
368 getContentResolver().insert(ProviderTableMeta.CONTENT_URI_FILE, cv);
369 }
370
371 class BackgroundUploader implements Runnable {
372 private ArrayList<Parcelable> mUploadStreams;
373 private Handler mHandler;
374 private String mUploadPath;
375 private boolean mCreateDir;
376
377 public BackgroundUploader(String pathToUpload, ArrayList<Parcelable> streamsToUpload,
378 Handler handler) {
379 mUploadStreams = streamsToUpload;
380 mHandler = handler;
381 mUploadPath = pathToUpload.replace(" ", "%20");
382 mCreateDir = false;
383 }
384
385 public BackgroundUploader(String pathToUpload, ArrayList<Parcelable> streamsToUpload,
386 Handler handler, boolean createDir) {
387 mUploadStreams = streamsToUpload;
388 mHandler = handler;
389 mUploadPath = pathToUpload.replace(" ", "%20");
390 mCreateDir = createDir;
391 }
392
393 public void run() {
394 WebdavClient wdc = new WebdavClient(Uri.parse(mAccountManager.getUserData(mAccount,
395 AccountAuthenticator.KEY_OC_URL)));
396 wdc.setCredentials(mUsername, mPassword);
397 wdc.allowUnsignedCertificates();
398
399 // create last directory in path if nessesary
400 if (mCreateDir) {
401 wdc.createDirectory(mUploadPath);
402 }
403
404 for (int i = 0; i < mUploadStreams.size(); ++i) {
405 Uri uri = (Uri) mUploadStreams.get(i);
406 if (uri.getScheme().equals("content")) {
407 final Cursor c = getContentResolver().query((Uri) mUploadStreams.get(i), null, null, null, null);
408 c.moveToFirst();
409
410 if (!wdc.putFile(c.getString(c.getColumnIndex(Media.DATA)),
411 mUploadPath+"/"+c.getString(c.getColumnIndex(Media.DISPLAY_NAME)),
412 c.getString(c.getColumnIndex(Media.MIME_TYPE)))) {
413 mHandler.post(new Runnable() {
414 public void run() {
415 Uploader.this.onUploadComplete(false, "Error while uploading file: " + c.getString(c.getColumnIndex(Media.DISPLAY_NAME)));
416 }
417 });
418 }
419 } else if (uri.getScheme().equals("file")) {
420 final File file = new File(Uri.decode(uri.toString()).replace(uri.getScheme()+"://", ""));
421 FileNameMap fileNameMap = URLConnection.getFileNameMap();
422 String contentType = fileNameMap.getContentTypeFor(uri.toString());
423 if (contentType == null) {
424 contentType = "text/plain";
425 }
426 if (!wdc.putFile(file.getAbsolutePath(), mUploadPath+"/"+file.getName(), contentType)) {
427 mHandler.post(new Runnable() {
428 public void run() {
429 Uploader.this.onUploadComplete(false, "Error while uploading file: " + file.getName());
430 }
431 });
432 }
433 }
434
435 }
436 mHandler.post(new Runnable() {
437 public void run() {
438 Uploader.this.onUploadComplete(true, null);
439 }
440 });
441 }
442
443 }
444
445 }