Skip to content

Commit f153a6f

Browse files
committed
Ensure the user is always informed of errors sending files to the export target
2 parents 48d67e3 + cdba3cb commit f153a6f

3 files changed

Lines changed: 128 additions & 132 deletions

File tree

app/src/main/java/org/gnucash/android/export/ExportAsyncTask.java

Lines changed: 126 additions & 130 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@
3535

3636
import com.crashlytics.android.Crashlytics;
3737
import com.dropbox.sync.android.DbxAccountManager;
38-
import com.dropbox.sync.android.DbxException;
3938
import com.dropbox.sync.android.DbxFile;
4039
import com.dropbox.sync.android.DbxFileSystem;
4140
import com.dropbox.sync.android.DbxPath;
@@ -142,21 +141,7 @@ protected void onPreExecute() {
142141
@Override
143142
protected Boolean doInBackground(ExportParams... params) {
144143
mExportParams = params[0];
145-
146-
switch (mExportParams.getExportFormat()) {
147-
case QIF:
148-
mExporter = new QifExporter(mExportParams, mDb);
149-
break;
150-
151-
case OFX:
152-
mExporter = new OfxExporter(mExportParams, mDb);
153-
break;
154-
155-
case XML:
156-
default:
157-
mExporter = new GncXmlExporter(mExportParams, mDb);
158-
break;
159-
}
144+
mExporter = getExporter();
160145

161146
try {
162147
// FIXME: detect if there aren't transactions to export and inform the user
@@ -179,91 +164,35 @@ public void run() {
179164
return false;
180165
}
181166

182-
switch (mExportParams.getExportTarget()) {
183-
case SHARING:
184-
List<String> sdCardExportedFiles = moveExportToSDCard();
185-
shareFiles(sdCardExportedFiles);
186-
return true;
187-
188-
case DROPBOX:
189-
moveExportToDropbox();
190-
return true;
191-
192-
case GOOGLE_DRIVE:
193-
moveExportToGoogleDrive();
194-
return true;
195-
196-
case OWNCLOUD:
197-
moveExportToOwnCloud();
198-
return true;
199-
200-
case SD_CARD:
201-
moveExportToSDCard();
202-
return true;
167+
try {
168+
moveToTarget();
169+
} catch (Exporter.ExporterException e) {
170+
Crashlytics.log(Log.ERROR, TAG, "Error sending exported files to target: " + e.getMessage());
171+
return false;
203172
}
204-
205-
return false;
173+
return true;
206174
}
207175

208176
/**
209177
* Transmits the exported transactions to the designated location, either SD card or third-party application
210178
* Finishes the activity if the export was starting in the context of an activity
211-
* @param exportResult Result of background export execution
179+
* @param exportSuccessful Result of background export execution
212180
*/
213181
@Override
214-
protected void onPostExecute(Boolean exportResult) {
215-
if (mContext instanceof Activity) {
216-
if (!exportResult) {
182+
protected void onPostExecute(Boolean exportSuccessful) {
183+
if (exportSuccessful) {
184+
if (mContext instanceof Activity)
185+
reportSuccess();
186+
187+
if (mExportParams.shouldDeleteTransactionsAfterExport()) {
188+
backupAndDeleteTransactions();
189+
refreshViews();
190+
}
191+
} else {
192+
if (mContext instanceof Activity) {
217193
Toast.makeText(mContext,
218194
mContext.getString(R.string.toast_export_error, mExportParams.getExportFormat().name()),
219195
Toast.LENGTH_LONG).show();
220-
return;
221-
} else {
222-
String targetLocation;
223-
switch (mExportParams.getExportTarget()){
224-
case SD_CARD:
225-
targetLocation = "SD card";
226-
break;
227-
case DROPBOX:
228-
targetLocation = "DropBox -> Apps -> GnuCash";
229-
break;
230-
case GOOGLE_DRIVE:
231-
targetLocation = "Google Drive -> " + mContext.getString(R.string.app_name);
232-
break;
233-
case OWNCLOUD:
234-
targetLocation = mContext.getSharedPreferences(
235-
mContext.getString(R.string.owncloud_pref),
236-
Context.MODE_PRIVATE).getBoolean(
237-
mContext.getString(R.string.owncloud_sync), false) ?
238-
239-
"ownCloud -> " +
240-
mContext.getSharedPreferences(
241-
mContext.getString(R.string.owncloud_pref),
242-
Context.MODE_PRIVATE).getString(
243-
mContext.getString(R.string.key_owncloud_dir), null) :
244-
"ownCloud sync not enabled";
245-
break;
246-
default:
247-
targetLocation = mContext.getString(R.string.label_export_target_external_service);
248-
}
249-
Toast.makeText(mContext,
250-
String.format(mContext.getString(R.string.toast_exported_to), targetLocation),
251-
Toast.LENGTH_LONG).show();
252-
}
253-
}
254-
255-
if (mExportParams.shouldDeleteTransactionsAfterExport()) {
256-
Log.i(TAG, "Backup and deleting transactions after export");
257-
backupAndDeleteTransactions();
258-
259-
//now refresh the respective views
260-
if (mContext instanceof AccountsActivity){
261-
AccountsListFragment fragment = ((AccountsActivity) mContext).getCurrentAccountListFragment();
262-
if (fragment != null)
263-
fragment.refresh();
264-
}
265-
if (mContext instanceof TransactionsActivity){
266-
((TransactionsActivity) mContext).refresh();
267196
}
268197
}
269198

@@ -274,16 +203,58 @@ protected void onPostExecute(Boolean exportResult) {
274203
}
275204
}
276205

277-
private void moveExportToGoogleDrive(){
206+
private Exporter getExporter() {
207+
switch (mExportParams.getExportFormat()) {
208+
case QIF:
209+
return new QifExporter(mExportParams, mDb);
210+
211+
case OFX:
212+
return new OfxExporter(mExportParams, mDb);
213+
214+
case XML:
215+
default:
216+
return new GncXmlExporter(mExportParams, mDb);
217+
}
218+
}
219+
220+
private void moveToTarget() throws Exporter.ExporterException {
221+
switch (mExportParams.getExportTarget()) {
222+
case SHARING:
223+
List<String> sdCardExportedFiles = moveExportToSDCard();
224+
shareFiles(sdCardExportedFiles);
225+
break;
226+
227+
case DROPBOX:
228+
moveExportToDropbox();
229+
break;
230+
231+
case GOOGLE_DRIVE:
232+
moveExportToGoogleDrive();
233+
break;
234+
235+
case OWNCLOUD:
236+
moveExportToOwnCloud();
237+
break;
238+
239+
case SD_CARD:
240+
moveExportToSDCard();
241+
break;
242+
243+
default:
244+
throw new Exporter.ExporterException(mExportParams, "Invalid target");
245+
}
246+
}
247+
248+
private void moveExportToGoogleDrive() throws Exporter.ExporterException {
278249
Log.i(TAG, "Moving exported file to Google Drive");
279250
final GoogleApiClient googleApiClient = BackupPreferenceFragment.getGoogleApiClient(GnuCashApplication.getAppContext());
280251
googleApiClient.blockingConnect();
281252

282253
DriveApi.DriveContentsResult driveContentsResult =
283254
Drive.DriveApi.newDriveContents(googleApiClient).await(1, TimeUnit.MINUTES);
284255
if (!driveContentsResult.getStatus().isSuccess()) {
285-
Log.e(TAG, "Error while trying to create new file contents");
286-
return;
256+
throw new Exporter.ExporterException(mExportParams,
257+
"Error while trying to create new file contents");
287258
}
288259
final DriveContents driveContents = driveContentsResult.getDriveContents();
289260
DriveFolder.DriveFileResult driveFileResult = null;
@@ -316,22 +287,19 @@ private void moveExportToGoogleDrive(){
316287
.await(1, TimeUnit.MINUTES);
317288
}
318289
} catch (IOException e) {
319-
Crashlytics.logException(e);
320-
Log.e(TAG, e.getMessage());
290+
throw new Exporter.ExporterException(mExportParams, e);
321291
}
322292

323293
if (driveFileResult == null)
324-
return;
294+
throw new Exporter.ExporterException(mExportParams, "No result received");
325295

326-
if (!driveFileResult.getStatus().isSuccess()) {
327-
Log.e(TAG, "Error creating file in Google Drive");
328-
showToastFromNonUiThread("Couldn't create the file in Google Drive", Toast.LENGTH_LONG);
329-
} else {
330-
Log.i(TAG, "Created file with id: " + driveFileResult.getDriveFile().getDriveId());
331-
}
296+
if (!driveFileResult.getStatus().isSuccess())
297+
throw new Exporter.ExporterException(mExportParams, "Error creating file in Google Drive");
298+
299+
Log.i(TAG, "Created file with id: " + driveFileResult.getDriveFile().getDriveId());
332300
}
333301

334-
private void moveExportToDropbox() {
302+
private void moveExportToDropbox() throws Exporter.ExporterException {
335303
Log.i(TAG, "Copying exported file to DropBox");
336304
String dropboxAppKey = mContext.getString(R.string.dropbox_app_key, BackupPreferenceFragment.DROPBOX_APP_KEY);
337305
String dropboxAppSecret = mContext.getString(R.string.dropbox_app_secret, BackupPreferenceFragment.DROPBOX_APP_SECRET);
@@ -346,30 +314,24 @@ private void moveExportToDropbox() {
346314
dbExportFile.writeFromExistingFile(exportedFile, false);
347315
exportedFile.delete();
348316
}
349-
} catch (DbxException.Unauthorized unauthorized) {
350-
Crashlytics.logException(unauthorized);
351-
Log.e(TAG, unauthorized.getMessage());
352-
throw new Exporter.ExporterException(mExportParams);
353317
} catch (IOException e) {
354-
Crashlytics.logException(e);
355-
Log.e(TAG, e.getMessage());
318+
throw new Exporter.ExporterException(mExportParams);
356319
} finally {
357320
if (dbExportFile != null) {
358321
dbExportFile.close();
359322
}
360323
}
361324
}
362325

363-
private void moveExportToOwnCloud() {
326+
private void moveExportToOwnCloud() throws Exporter.ExporterException {
364327
Log.i(TAG, "Copying exported file to ownCloud");
365328

366329
SharedPreferences mPrefs = mContext.getSharedPreferences(mContext.getString(R.string.owncloud_pref), Context.MODE_PRIVATE);
367330

368331
Boolean mOC_sync = mPrefs.getBoolean(mContext.getString(R.string.owncloud_sync), false);
369332

370-
if(!mOC_sync){
371-
Log.e(TAG, "ownCloud not enabled.");
372-
return;
333+
if (!mOC_sync) {
334+
throw new Exporter.ExporterException(mExportParams, "ownCloud not enabled.");
373335
}
374336

375337
String mOC_server = mPrefs.getString(mContext.getString(R.string.key_owncloud_server), null);
@@ -386,8 +348,10 @@ private void moveExportToOwnCloud() {
386348
if (mOC_dir.length() != 0) {
387349
RemoteOperationResult dirResult = new CreateRemoteFolderOperation(
388350
mOC_dir, true).execute(mClient);
389-
if (!dirResult.isSuccess())
390-
Log.e(TAG, dirResult.getLogMessage(), dirResult.getException());
351+
if (!dirResult.isSuccess()) {
352+
Log.w(TAG, "Error creating folder (it may happen if it already exists): "
353+
+ dirResult.getLogMessage());
354+
}
391355
}
392356
for (String exportedFilePath : mExportedFiles) {
393357
String remotePath = mOC_dir + FileUtils.PATH_SEPARATOR + stripPathPart(exportedFilePath);
@@ -397,10 +361,9 @@ private void moveExportToOwnCloud() {
397361
exportedFilePath, remotePath, mimeType).execute(mClient);
398362

399363
if (!result.isSuccess())
400-
Log.e(TAG, result.getLogMessage(), result.getException());
401-
else {
402-
new File(exportedFilePath).delete();
403-
}
364+
throw new Exporter.ExporterException(mExportParams, result.getLogMessage());
365+
366+
new File(exportedFilePath).delete();
404367
}
405368
}
406369

@@ -409,7 +372,7 @@ private void moveExportToOwnCloud() {
409372
* external storage, which is accessible to the user.
410373
* @return The list of files moved to the SD card.
411374
*/
412-
private List<String> moveExportToSDCard() {
375+
private List<String> moveExportToSDCard() throws Exporter.ExporterException {
413376
Log.i(TAG, "Moving exported file to external storage");
414377
new File(Exporter.getExportFolderPath(mExporter.mBookUID));
415378
List<String> dstFiles = new ArrayList<>();
@@ -420,8 +383,6 @@ private List<String> moveExportToSDCard() {
420383
moveFile(src, dst);
421384
dstFiles.add(dst);
422385
} catch (IOException e) {
423-
Crashlytics.logException(e);
424-
Log.e(TAG, e.getMessage());
425386
throw new Exporter.ExporterException(mExportParams, e);
426387
}
427388
}
@@ -439,6 +400,7 @@ private String stripPathPart(String fullPathName) {
439400
* and deletes all non-template transactions in the database.
440401
*/
441402
private void backupAndDeleteTransactions(){
403+
Log.i(TAG, "Backup and deleting transactions after export");
442404
GncXmlExporter.createBackup(); //create backup before deleting everything
443405
List<Transaction> openingBalances = new ArrayList<>();
444406
boolean preserveOpeningBalances = GnuCashApplication.shouldSaveOpeningBalances(false);
@@ -533,14 +495,48 @@ public void moveFile(String src, String dst) throws IOException {
533495
srcFile.delete();
534496
}
535497

536-
private void showToastFromNonUiThread(final String message, final int duration) {
537-
if (mContext instanceof Activity) {
538-
((Activity) mContext).runOnUiThread(new Runnable() {
539-
@Override
540-
public void run() {
541-
Toast.makeText(mContext, message, duration).show();
542-
}
543-
});
498+
private void reportSuccess() {
499+
String targetLocation;
500+
switch (mExportParams.getExportTarget()){
501+
case SD_CARD:
502+
targetLocation = "SD card";
503+
break;
504+
case DROPBOX:
505+
targetLocation = "DropBox -> Apps -> GnuCash";
506+
break;
507+
case GOOGLE_DRIVE:
508+
targetLocation = "Google Drive -> " + mContext.getString(R.string.app_name);
509+
break;
510+
case OWNCLOUD:
511+
targetLocation = mContext.getSharedPreferences(
512+
mContext.getString(R.string.owncloud_pref),
513+
Context.MODE_PRIVATE).getBoolean(
514+
mContext.getString(R.string.owncloud_sync), false) ?
515+
516+
"ownCloud -> " +
517+
mContext.getSharedPreferences(
518+
mContext.getString(R.string.owncloud_pref),
519+
Context.MODE_PRIVATE).getString(
520+
mContext.getString(R.string.key_owncloud_dir), null) :
521+
"ownCloud sync not enabled";
522+
break;
523+
default:
524+
targetLocation = mContext.getString(R.string.label_export_target_external_service);
525+
}
526+
Toast.makeText(mContext,
527+
String.format(mContext.getString(R.string.toast_exported_to), targetLocation),
528+
Toast.LENGTH_LONG).show();
529+
}
530+
531+
private void refreshViews() {
532+
if (mContext instanceof AccountsActivity){
533+
AccountsListFragment fragment =
534+
((AccountsActivity) mContext).getCurrentAccountListFragment();
535+
if (fragment != null)
536+
fragment.refresh();
537+
}
538+
if (mContext instanceof TransactionsActivity){
539+
((TransactionsActivity) mContext).refresh();
544540
}
545541
}
546542
}

app/src/main/java/org/gnucash/android/export/Exporter.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,7 @@ public String getExportMimeType(){
254254
return "text/plain";
255255
}
256256

257-
public static class ExporterException extends RuntimeException{
257+
public static class ExporterException extends Exception {
258258

259259
public ExporterException(ExportParams params){
260260
super("Failed to generate export with parameters: " + params.toString());

app/src/test/java/org/gnucash/android/test/unit/export/BackupTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ public void shouldCreateBackup(){
6262
}
6363

6464
@Test
65-
public void shouldCreateBackupFileName(){
65+
public void shouldCreateBackupFileName() throws Exporter.ExporterException {
6666
Exporter exporter = new GncXmlExporter(new ExportParams(ExportFormat.XML));
6767
List<String> xmlFiles = exporter.generateExport();
6868

0 commit comments

Comments
 (0)