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