Cleaned stuff , add a history delete button and renamed
[pub/Android/ownCloud.git] / src / com / owncloud / android / ui / activity / InstantUploadActivity.java
1 /* ownCloud Android client application
2 * Copyright (C) 2012-2013 ownCloud Inc.
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.ui.activity;
19
20 import java.util.ArrayList;
21 import java.util.List;
22
23 import android.accounts.Account;
24 import android.app.Activity;
25 import android.content.Intent;
26 import android.database.Cursor;
27 import android.graphics.Bitmap;
28 import android.graphics.BitmapFactory;
29 import android.os.Bundle;
30 import android.util.Log;
31 import android.util.SparseArray;
32 import android.view.Gravity;
33 import android.view.View;
34 import android.view.View.OnClickListener;
35 import android.view.ViewGroup;
36 import android.widget.Button;
37 import android.widget.CheckBox;
38 import android.widget.CompoundButton;
39 import android.widget.CompoundButton.OnCheckedChangeListener;
40 import android.widget.ImageButton;
41 import android.widget.LinearLayout;
42 import android.widget.Toast;
43
44 import com.owncloud.android.AccountUtils;
45 import com.owncloud.android.Log_OC;
46 import com.owncloud.android.R;
47 import com.owncloud.android.db.DbHandler;
48 import com.owncloud.android.files.InstantUploadBroadcastReceiver;
49 import com.owncloud.android.files.services.FileUploader;
50 import com.owncloud.android.files.services.InstantUploadService;
51
52 /**
53 * This Activity is used to display a list with images they could not be
54 * uploaded instantly. The images can be selected for delete or for a try again
55 * upload
56 *
57 * The entrypoint for this activity is the 'Failed upload Notification" and a
58 * submenue underneath the 'Upload' menuentry
59 *
60 * @author andomaex / Matthias Baumann
61 *
62 * This program is free software: you can redistribute it and/or modify
63 * it under the terms of the GNU General Public License as published by
64 * the Free Software Foundation, either version 3 of the License, or (at
65 * your option) any later version.
66 *
67 * This program is distributed in the hope that it will be useful, but
68 * WITHOUT ANY WARRANTY; without even the implied warranty of
69 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
70 * General Public License for more de/
71 */
72 public class InstantUploadActivity extends Activity {
73
74 private static final String LOG_TAG = InstantUploadActivity.class.getSimpleName();
75 private LinearLayout listView;
76 private static final String retry_chexbox_tag = "retry_chexbox_tag";
77 private static int MAX_LOAD_IMAGES = 5;
78 private int lastLoadImageIdx = 0;
79
80 private SparseArray<String> fileList = null;
81
82 @Override
83 protected void onCreate(Bundle savedInstanceState) {
84 super.onCreate(savedInstanceState);
85 setContentView(R.layout.failed_upload_files);
86
87 Button delete_all_btn = (Button) findViewById(R.id.failed_upload_delete_all_btn);
88 delete_all_btn.setOnClickListener(getDeleteListner());
89 Button retry_all_btn = (Button) findViewById(R.id.failed_upload_retry_all_btn);
90 retry_all_btn.setOnClickListener(getRetryListner());
91 CheckBox failed_upload_all_cb = (CheckBox) findViewById(R.id.failed_upload_headline_cb);
92 failed_upload_all_cb.setOnCheckedChangeListener(getCheckAllListener());
93 listView = (LinearLayout) findViewById(R.id.failed_upload_scrollviewlayout);
94
95 loadListView(true);
96
97 }
98
99 /**
100 * init the listview with ImageButtons, checkboxes and filename for every
101 * Image that was not successfully uploaded
102 *
103 * this method is call at Activity creation and on delete one ore more
104 * list-entry an on retry the upload by clicking the ImageButton or by click
105 * to the 'retry all' button
106 *
107 */
108 private void loadListView(boolean reset) {
109 DbHandler db = new DbHandler(getApplicationContext());
110 Cursor c = db.getFailedFiles();
111
112 if (reset) {
113 fileList = new SparseArray<String>();
114 listView.removeAllViews();
115 lastLoadImageIdx = 0;
116 }
117 if (c != null) {
118 try {
119 c.moveToPosition(lastLoadImageIdx);
120
121 while (c.moveToNext()) {
122
123 lastLoadImageIdx++;
124 String imp_path = c.getString(1);
125 fileList.put(lastLoadImageIdx, imp_path);
126 LinearLayout rowLayout = getLinearLayout(lastLoadImageIdx);
127 rowLayout.addView(getFileCheckbox(lastLoadImageIdx));
128 rowLayout.addView(getImageButton(imp_path, lastLoadImageIdx));
129 rowLayout.addView(getFileButton(imp_path, lastLoadImageIdx));
130 listView.addView(rowLayout);
131 Log_OC.d(LOG_TAG, imp_path + " on idx: " + lastLoadImageIdx);
132 if (lastLoadImageIdx % MAX_LOAD_IMAGES == 0) {
133 break;
134 }
135 }
136 if (lastLoadImageIdx > 0) {
137 addLoadMoreButton(listView);
138 }
139 } finally {
140 db.close();
141 }
142 }
143 }
144
145 private void addLoadMoreButton(LinearLayout listView) {
146 if (listView != null) {
147 Button loadmoreBtn = null;
148 View oldButton = listView.findViewById(42);
149 if (oldButton != null) {
150 // remove existing button
151 listView.removeView(oldButton);
152 // to add the button at the end
153 loadmoreBtn = (Button) oldButton;
154 } else {
155 // create a new button to add to the scoll view
156 loadmoreBtn = new Button(this);
157 loadmoreBtn.setId(42);
158 loadmoreBtn.setText(getString(R.string.failed_upload_load_more_images));
159 loadmoreBtn.setBackgroundResource(R.color.owncloud_white);
160 loadmoreBtn.setTextSize(12);
161 loadmoreBtn.setOnClickListener(new OnClickListener() {
162 @Override
163 public void onClick(View v) {
164 loadListView(false);
165 }
166
167 });
168 }
169 listView.addView(loadmoreBtn);
170 }
171 }
172
173 /**
174 * provide a list of CheckBox instances, looked up from parent listview this
175 * list ist used to select/deselect all checkboxes at the list
176 *
177 * @return List<CheckBox>
178 */
179 private List<CheckBox> getCheckboxList() {
180 List<CheckBox> list = new ArrayList<CheckBox>();
181 for (int i = 0; i < listView.getChildCount(); i++) {
182 Log_OC.d(LOG_TAG, "ListView has Childs: " + listView.getChildCount());
183 View childView = listView.getChildAt(i);
184 if (childView != null && childView instanceof ViewGroup) {
185 View checkboxView = getChildViews((ViewGroup) childView);
186 if (checkboxView != null && checkboxView instanceof CheckBox) {
187 Log_OC.d(LOG_TAG, "found Child: " + checkboxView.getId() + " " + checkboxView.getClass());
188 list.add((CheckBox) checkboxView);
189 }
190 }
191 }
192 return list;
193 }
194
195 /**
196 * recursive called method, used from getCheckboxList method
197 *
198 * @param View
199 * @return View
200 */
201 private View getChildViews(ViewGroup view) {
202 if (view != null) {
203 for (int i = 0; i < view.getChildCount(); i++) {
204 View cb = view.getChildAt(i);
205 if (cb != null && cb instanceof ViewGroup) {
206 return getChildViews((ViewGroup) cb);
207 } else if (cb instanceof CheckBox) {
208 return cb;
209 }
210 }
211 }
212 return null;
213 }
214
215 /**
216 * create a new OnCheckedChangeListener for the 'check all' checkbox *
217 *
218 * @return OnCheckedChangeListener to select all checkboxes at the list
219 */
220 private OnCheckedChangeListener getCheckAllListener() {
221 return new OnCheckedChangeListener() {
222 @Override
223 public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
224 List<CheckBox> list = getCheckboxList();
225 for (CheckBox checkbox : list) {
226 ((CheckBox) checkbox).setChecked(isChecked);
227 }
228 }
229
230 };
231 }
232
233 /**
234 * Button click Listener for the retry button at the headline
235 *
236 * @return a Listener to perform a retry for all selected images
237 */
238 private OnClickListener getRetryListner() {
239 return new OnClickListener() {
240
241 @Override
242 public void onClick(View v) {
243
244 try {
245 List<CheckBox> list = getCheckboxList();
246 for (CheckBox checkbox : list) {
247 boolean to_retry = checkbox.isChecked();
248
249 Log_OC.d(LOG_TAG, "Checkbox for " + checkbox.getId() + " was checked: " + to_retry);
250 String img_path = fileList.get(checkbox.getId());
251 if (to_retry) {
252
253 final String msg = "Image-Path " + checkbox.getId() + " was checked: " + img_path;
254 Log_OC.d(LOG_TAG, msg);
255 startUpload(img_path);
256 }
257
258 }
259 } finally {
260 // refresh the List
261 listView.removeAllViews();
262 loadListView(true);
263 }
264
265 }
266 };
267 }
268
269 /**
270 * Button click Listener for the delete button at the headline
271 *
272 * @return a Listener to perform a delete for all selected images
273 */
274 private OnClickListener getDeleteListner() {
275
276 return new OnClickListener() {
277
278 @Override
279 public void onClick(View v) {
280 final DbHandler dbh = new DbHandler(getApplicationContext());
281 try {
282 List<CheckBox> list = getCheckboxList();
283 for (CheckBox checkbox : list) {
284 boolean to_be_delete = checkbox.isChecked();
285
286 Log_OC.d(LOG_TAG, "Checkbox for " + checkbox.getId() + " was checked: " + to_be_delete);
287 String img_path = fileList.get(checkbox.getId());
288 Log_OC.d(LOG_TAG, "Image-Path " + checkbox.getId() + " was checked: " + img_path);
289 if (to_be_delete) {
290 boolean deleted = dbh.removeIUPendingFile(img_path);
291 Log_OC.d(LOG_TAG, "removing " + checkbox.getId() + " was : " + deleted);
292
293 }
294
295 }
296 } finally {
297 dbh.close();
298 // refresh the List
299 listView.removeAllViews();
300 loadListView(true);
301 }
302
303 }
304 };
305 }
306
307 private LinearLayout getLinearLayout(int id) {
308 LinearLayout linearLayout = new LinearLayout(getApplicationContext());
309 linearLayout.setId(id);
310 linearLayout.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
311 LinearLayout.LayoutParams.MATCH_PARENT));
312 linearLayout.setGravity(Gravity.RIGHT);
313 linearLayout.setOrientation(LinearLayout.HORIZONTAL);
314 return linearLayout;
315 }
316
317 private Button getFileButton(final String img_path, int id) {
318 Button retryButton = new Button(this);
319 retryButton.setId(id);
320 retryButton.setText(img_path);
321 retryButton.setBackgroundResource(R.color.owncloud_white);
322 retryButton.setTextSize(8);
323 retryButton.setOnClickListener(getImageButtonOnClickListener(img_path));
324 return retryButton;
325 }
326
327 private CheckBox getFileCheckbox(int id) {
328 CheckBox retryCB = new CheckBox(this);
329 retryCB.setId(id);
330 retryCB.setBackgroundResource(R.color.owncloud_white);
331 retryCB.setTextSize(8);
332 retryCB.setTag(retry_chexbox_tag);
333 return retryCB;
334 }
335
336 private ImageButton getImageButton(String img_path, int id) {
337 ImageButton imageButton = new ImageButton(this);
338 imageButton.setId(id);
339 imageButton.setClickable(true);
340 imageButton.setOnClickListener(getImageButtonOnClickListener(img_path));
341
342 // scale and add a thumbnail to the imagebutton
343 int base_scale_size = 32;
344 if (img_path != null) {
345 Log_OC.d(LOG_TAG, "add " + img_path + " to Image Button");
346 BitmapFactory.Options options = new BitmapFactory.Options();
347 options.inJustDecodeBounds = true;
348 Bitmap bitmap = BitmapFactory.decodeFile(img_path, options);
349 int width_tpm = options.outWidth, height_tmp = options.outHeight;
350 int scale = 3;
351 while (true) {
352 if (width_tpm / 2 < base_scale_size || height_tmp / 2 < base_scale_size) {
353 break;
354 }
355 width_tpm /= 2;
356 height_tmp /= 2;
357 scale++;
358 }
359
360 Log_OC.d(LOG_TAG, "scale Imgae with: " + scale);
361 BitmapFactory.Options options2 = new BitmapFactory.Options();
362 options2.inSampleSize = scale;
363 bitmap = BitmapFactory.decodeFile(img_path, options2);
364
365 if (bitmap != null) {
366 Log_OC.d(LOG_TAG, "loaded Bitmap Bytes: " + bitmap.getRowBytes());
367 imageButton.setImageBitmap(bitmap);
368 } else {
369 Log_OC.d(LOG_TAG, "could not load imgage: " + img_path);
370 }
371 }
372 return imageButton;
373 }
374
375 private OnClickListener getImageButtonOnClickListener(final String img_path) {
376 return new OnClickListener() {
377
378 @Override
379 public void onClick(View v) {
380 startUpload(img_path);
381 loadListView(true);
382 }
383
384 };
385 }
386
387 /**
388 * start uploading a file to the INSTANT_UPLOD_DIR
389 *
390 * @param img_path
391 */
392 private void startUpload(String img_path) {
393 // extract filename
394 String filename = img_path.substring(img_path.lastIndexOf('/'), img_path.length());
395 if (canInstantUpload()) {
396 Account account = AccountUtils.getCurrentOwnCloudAccount(InstantUploadActivity.this);
397 // add file again to upload queue
398 DbHandler db = new DbHandler(InstantUploadActivity.this);
399 try {
400 db.updateFileState(img_path, DbHandler.UPLOAD_STATUS_UPLOAD_LATER);
401 } finally {
402 db.close();
403 }
404
405 Intent i = new Intent(InstantUploadActivity.this, FileUploader.class);
406 i.putExtra(FileUploader.KEY_ACCOUNT, account);
407 i.putExtra(FileUploader.KEY_LOCAL_FILE, img_path);
408 i.putExtra(FileUploader.KEY_REMOTE_FILE, InstantUploadService.INSTANT_UPLOAD_DIR + "/" + filename);
409 i.putExtra(FileUploader.KEY_UPLOAD_TYPE, FileUploader.UPLOAD_SINGLE_FILE);
410 i.putExtra(com.owncloud.android.files.services.FileUploader.KEY_INSTANT_UPLOAD, true);
411
412 final String msg = "try to upload file with name :" + filename;
413 Log_OC.d(LOG_TAG, msg);
414 Toast toast = Toast.makeText(InstantUploadActivity.this, getString(R.string.failed_upload_retry_text)
415 + filename, Toast.LENGTH_LONG);
416 toast.show();
417
418 startService(i);
419 } else {
420 Toast toast = Toast.makeText(InstantUploadActivity.this,
421 getString(R.string.failed_upload_retry_do_nothing_text) + filename, Toast.LENGTH_LONG);
422 toast.show();
423 }
424 }
425
426 private boolean canInstantUpload() {
427
428 if (!InstantUploadBroadcastReceiver.isOnline(this)
429 || (InstantUploadBroadcastReceiver.instantUploadViaWiFiOnly(this) && !InstantUploadBroadcastReceiver
430 .isConnectedViaWiFi(this))) {
431 return false;
432 } else {
433 return true;
434 }
435 }
436
437 }