X-Git-Url: https://git.ktnx.net/?p=mobile-ledger.git;a=blobdiff_plain;f=app%2Fsrc%2Fmain%2Fjava%2Fnet%2Fktnx%2Fmobileledger%2Fasync%2FRetrieveTransactionsTask.java;h=6a2700f36480c870d1fedc01517107c785bf2d83;hp=f4d246a66a80f19e02fa388578b11a8ffa94d901;hb=83cac114e375728080194fb09758b49c50a8119b;hpb=e2054be1e2bd9e4e97f5f80db61a0dc4172bd4d5 diff --git a/app/src/main/java/net/ktnx/mobileledger/async/RetrieveTransactionsTask.java b/app/src/main/java/net/ktnx/mobileledger/async/RetrieveTransactionsTask.java index f4d246a6..6a2700f3 100644 --- a/app/src/main/java/net/ktnx/mobileledger/async/RetrieveTransactionsTask.java +++ b/app/src/main/java/net/ktnx/mobileledger/async/RetrieveTransactionsTask.java @@ -1,18 +1,18 @@ /* * Copyright © 2019 Damyan Ivanov. - * This file is part of Mobile-Ledger. - * Mobile-Ledger is free software: you can distribute it and/or modify it + * This file is part of MoLe. + * MoLe is free software: you can distribute it and/or modify it * under the term of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your opinion), any later version. * - * Mobile-Ledger is distributed in the hope that it will be useful, + * MoLe is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License terms for details. * * You should have received a copy of the GNU General Public License - * along with Mobile-Ledger. If not, see . + * along with MoLe. If not, see . */ package net.ktnx.mobileledger.async; @@ -23,7 +23,12 @@ import android.os.AsyncTask; import android.os.OperationCanceledException; import android.util.Log; -import net.ktnx.mobileledger.R; +import net.ktnx.mobileledger.err.HTTPException; +import net.ktnx.mobileledger.json.AccountListParser; +import net.ktnx.mobileledger.json.ParsedBalance; +import net.ktnx.mobileledger.json.ParsedLedgerAccount; +import net.ktnx.mobileledger.json.ParsedLedgerTransaction; +import net.ktnx.mobileledger.json.TransactionListParser; import net.ktnx.mobileledger.model.Data; import net.ktnx.mobileledger.model.LedgerAccount; import net.ktnx.mobileledger.model.LedgerTransaction; @@ -34,7 +39,6 @@ import net.ktnx.mobileledger.utils.MLDB; import net.ktnx.mobileledger.utils.NetworkUtil; import java.io.BufferedReader; -import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; @@ -42,8 +46,9 @@ import java.lang.ref.WeakReference; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URLDecoder; +import java.nio.charset.StandardCharsets; +import java.text.ParseException; import java.util.ArrayList; -import java.util.Date; import java.util.HashMap; import java.util.Stack; import java.util.regex.Matcher; @@ -51,28 +56,27 @@ import java.util.regex.Pattern; public class RetrieveTransactionsTask - extends AsyncTask { + extends AsyncTask { private static final int MATCHING_TRANSACTIONS_LIMIT = 50; - private static final Pattern commentPattern = Pattern.compile("^\\s*;"); - private static final Pattern transactionStartPattern = Pattern.compile("([\\d.-]+)"); - private static final Pattern transactionDescriptionPattern = + private static final Pattern reComment = Pattern.compile("^\\s*;"); + private static final Pattern reTransactionStart = Pattern.compile("([\\d.-]+)"); + private static final Pattern reTransactionDescription = Pattern.compile(" contextRef; private int error; // %3A is '=' - private boolean success; - private Pattern account_name_re = Pattern.compile("/register\\?q=inacct%3A([a-zA-Z0-9%]+)\""); - private Pattern account_value_re = Pattern.compile( + private Pattern reAccountName = Pattern.compile("/register\\?q=inacct%3A([a-zA-Z0-9%]+)\""); + private Pattern reAccountValue = Pattern.compile( "\\s*([-+]?[\\d.,]+)(?:\\s+(\\S+))?"); public RetrieveTransactionsTask(WeakReference contextRef) { this.contextRef = contextRef; } private static void L(String msg) { - Log.d("transaction-parser", msg); + //Log.d("transaction-parser", msg); } @Override protected void onProgressUpdate(Progress... values) { @@ -89,219 +93,231 @@ public class RetrieveTransactionsTask context.onRetrieveStart(); } @Override - protected void onPostExecute(Void aVoid) { - super.onPostExecute(aVoid); + protected void onPostExecute(String error) { + super.onPostExecute(error); MainActivity context = getContext(); if (context == null) return; - context.onRetrieveDone(success); + context.onRetrieveDone(error); } @Override protected void onCancelled() { super.onCancelled(); MainActivity context = getContext(); if (context == null) return; - context.onRetrieveDone(false); + context.onRetrieveDone(null); } - @SuppressLint("DefaultLocale") - @Override - protected Void doInBackground(Void... params) { - MobileLedgerProfile profile = Data.profile.get(); + private String retrieveTransactionListLegacy(MobileLedgerProfile profile) + throws IOException, ParseException, HTTPException { Progress progress = new Progress(); int maxTransactionId = Progress.INDETERMINATE; - success = false; ArrayList accountList = new ArrayList<>(); - ArrayList transactionList = new ArrayList<>(); HashMap accountNames = new HashMap<>(); - LedgerAccount lastAccount = null; - Data.backgroundTaskCount.incrementAndGet(); - try { - HttpURLConnection http = NetworkUtil.prepare_connection("journal"); - http.setAllowUserInteraction(false); - publishProgress(progress); - MainActivity ctx = getContext(); - if (ctx == null) return null; - try (SQLiteDatabase db = MLDB.getWritableDatabase()) { - try (InputStream resp = http.getInputStream()) { - if (http.getResponseCode() != 200) throw new IOException( - String.format("HTTP error %d", http.getResponseCode())); - db.beginTransaction(); - try { - db.execSQL("UPDATE transactions set keep=0"); - db.execSQL("update account_values set keep=0;"); - db.execSQL("update accounts set keep=0;"); - - ParserState state = ParserState.EXPECTING_ACCOUNT; - String line; - BufferedReader buf = - new BufferedReader(new InputStreamReader(resp, "UTF-8")); - - int processedTransactionCount = 0; - int transactionId = 0; - int matchedTransactionsCount = 0; - LedgerTransaction transaction = null; - LINES: - while ((line = buf.readLine()) != null) { - throwIfCancelled(); - Matcher m; - m = commentPattern.matcher(line); - if (m.find()) { - // TODO: comments are ignored for now - Log.v("transaction-parser", "Ignoring comment"); - continue; - } - //L(String.format("State is %d", updating)); - switch (state) { - case EXPECTING_ACCOUNT: - if (line.equals("

General Journal

")) { - state = ParserState.EXPECTING_TRANSACTION; - L("→ expecting transaction"); - Data.accounts.set(accountList); - continue; - } - m = account_name_re.matcher(line); - if (m.find()) { - String acct_encoded = m.group(1); - String acct_name = URLDecoder.decode(acct_encoded, "UTF-8"); - acct_name = acct_name.replace("\"", ""); - L(String.format("found account: %s", acct_name)); + LedgerAccount lastAccount = null, prevAccount = null; + boolean onlyStarred = Data.optShowOnlyStarred.get(); + + HttpURLConnection http = NetworkUtil.prepareConnection(profile, "journal"); + http.setAllowUserInteraction(false); + publishProgress(progress); + switch (http.getResponseCode()) { + case 200: + break; + default: + throw new HTTPException(http.getResponseCode(), http.getResponseMessage()); + } + try (SQLiteDatabase db = MLDB.getDatabase()) { + try (InputStream resp = http.getInputStream()) { + if (http.getResponseCode() != 200) + throw new IOException(String.format("HTTP error %d", http.getResponseCode())); + db.beginTransaction(); + try { + prepareDbForRetrieval(db, profile); + + int matchedTransactionsCount = 0; + + + ParserState state = ParserState.EXPECTING_ACCOUNT; + String line; + BufferedReader buf = + new BufferedReader(new InputStreamReader(resp, StandardCharsets.UTF_8)); - profile.storeAccount(acct_name); + int processedTransactionCount = 0; + int transactionId = 0; + LedgerTransaction transaction = null; + LINES: + while ((line = buf.readLine()) != null) { + throwIfCancelled(); + Matcher m; + m = reComment.matcher(line); + if (m.find()) { + // TODO: comments are ignored for now + Log.v("transaction-parser", "Ignoring comment"); + continue; + } + //L(String.format("State is %d", updating)); + switch (state) { + case EXPECTING_ACCOUNT: + if (line.equals("

General Journal

")) { + state = ParserState.EXPECTING_TRANSACTION; + L("→ expecting transaction"); + // commit the current transaction and start a new one + // the account list in the UI should reflect the (committed) + // state of the database + db.setTransactionSuccessful(); + db.endTransaction(); + Data.accounts.setList(accountList); + db.beginTransaction(); + continue; + } + m = reAccountName.matcher(line); + if (m.find()) { + String acct_encoded = m.group(1); + String acct_name = URLDecoder.decode(acct_encoded, "UTF-8"); + acct_name = acct_name.replace("\"", ""); + L(String.format("found account: %s", acct_name)); + + prevAccount = lastAccount; + lastAccount = profile.tryLoadAccount(db, acct_name); + if (lastAccount == null) lastAccount = new LedgerAccount(acct_name); + else lastAccount.removeAmounts(); + profile.storeAccount(db, lastAccount); - // make sure the parent account(s) are present, - // synthesising them if necessary - String parentName = lastAccount.getParentName(); - if (parentName != null) { - Stack toAppend = new Stack<>(); - while (parentName != null) { - if (accountNames.containsKey(parentName)) break; - toAppend.push(parentName); - parentName = new LedgerAccount(parentName) - .getParentName(); - } - while (!toAppend.isEmpty()) { - String aName = toAppend.pop(); - LedgerAccount acc = new LedgerAccount(aName); - accountList.add(acc); - L(String.format("gap-filling with %s", aName)); - accountNames.put(aName, null); - profile.storeAccount(aName); - } + if (prevAccount != null) prevAccount + .setHasSubAccounts(prevAccount.isParentOf(lastAccount)); + // make sure the parent account(s) are present, + // synthesising them if necessary + String parentName = lastAccount.getParentName(); + if (parentName != null) { + Stack toAppend = new Stack<>(); + while (parentName != null) { + if (accountNames.containsKey(parentName)) break; + toAppend.push(parentName); + parentName = + new LedgerAccount(parentName).getParentName(); } + while (!toAppend.isEmpty()) { + String aName = toAppend.pop(); + LedgerAccount acc = new LedgerAccount(aName); + acc.setHiddenByStar(lastAccount.isHiddenByStar()); + acc.setHasSubAccounts(true); + if ((!onlyStarred || !acc.isHiddenByStar()) && + acc.isVisible(accountList)) accountList.add(acc); + L(String.format("gap-filling with %s", aName)); + accountNames.put(aName, null); + profile.storeAccount(db, acc); + } + } + if ((!onlyStarred || !lastAccount.isHiddenByStar()) && + lastAccount.isVisible(accountList)) accountList.add(lastAccount); - accountNames.put(acct_name, null); + accountNames.put(acct_name, null); - state = ParserState.EXPECTING_ACCOUNT_AMOUNT; - L("→ expecting account amount"); - } - break; + state = ParserState.EXPECTING_ACCOUNT_AMOUNT; + L("→ expecting account amount"); + } + break; - case EXPECTING_ACCOUNT_AMOUNT: - m = account_value_re.matcher(line); - boolean match_found = false; - while (m.find()) { - throwIfCancelled(); + case EXPECTING_ACCOUNT_AMOUNT: + m = reAccountValue.matcher(line); + boolean match_found = false; + while (m.find()) { + throwIfCancelled(); - match_found = true; - String value = m.group(1); - String currency = m.group(2); - if (currency == null) currency = ""; - value = value.replace(',', '.'); - L("curr=" + currency + ", value=" + value); - profile.storeAccountValue(lastAccount.getName(), currency, - Float.valueOf(value)); - lastAccount.addAmount(Float.parseFloat(value), currency); - } + match_found = true; + String value = m.group(1); + String currency = m.group(2); + if (currency == null) currency = ""; + value = value.replace(',', '.'); + L("curr=" + currency + ", value=" + value); + profile.storeAccountValue(db, lastAccount.getName(), currency, + Float.valueOf(value)); + lastAccount.addAmount(Float.parseFloat(value), currency); + } - if (match_found) { - state = ParserState.EXPECTING_ACCOUNT; - L("→ expecting account"); - } + if (match_found) { + state = ParserState.EXPECTING_ACCOUNT; + L("→ expecting account"); + } - break; + break; - case EXPECTING_TRANSACTION: - if (!line.isEmpty() && (line.charAt(0) == ' ')) continue; - m = transactionStartPattern.matcher(line); - if (m.find()) { - transactionId = Integer.valueOf(m.group(1)); - state = ParserState.EXPECTING_TRANSACTION_DESCRIPTION; - L(String.format( - "found transaction %d → expecting description", - transactionId)); - progress.setProgress(++processedTransactionCount); - if (maxTransactionId < transactionId) - maxTransactionId = transactionId; - if ((progress.getTotal() == Progress.INDETERMINATE) || - (progress.getTotal() < transactionId)) - progress.setTotal(transactionId); - publishProgress(progress); + case EXPECTING_TRANSACTION: + if (!line.isEmpty() && (line.charAt(0) == ' ')) continue; + m = reTransactionStart.matcher(line); + if (m.find()) { + transactionId = Integer.valueOf(m.group(1)); + state = ParserState.EXPECTING_TRANSACTION_DESCRIPTION; + L(String.format("found transaction %d → expecting description", + transactionId)); + progress.setProgress(++processedTransactionCount); + if (maxTransactionId < transactionId) + maxTransactionId = transactionId; + if ((progress.getTotal() == Progress.INDETERMINATE) || + (progress.getTotal() < transactionId)) + progress.setTotal(transactionId); + publishProgress(progress); + } + m = reEnd.matcher(line); + if (m.find()) { + L("--- transaction value complete ---"); + break LINES; + } + break; + + case EXPECTING_TRANSACTION_DESCRIPTION: + if (!line.isEmpty() && (line.charAt(0) == ' ')) continue; + m = reTransactionDescription.matcher(line); + if (m.find()) { + if (transactionId == 0) throw new TransactionParserException( + "Transaction Id is 0 while expecting " + "description"); + + String date = m.group(1); + try { + int equalsIndex = date.indexOf('='); + if (equalsIndex >= 0) + date = date.substring(equalsIndex + 1); + transaction = new LedgerTransaction(transactionId, date, + m.group(2)); } - m = endPattern.matcher(line); - if (m.find()) { - L("--- transaction value complete ---"); - success = true; - break LINES; + catch (ParseException e) { + e.printStackTrace(); + return String.format("Error parsing date '%s'", date); } - break; + state = ParserState.EXPECTING_TRANSACTION_DETAILS; + L(String.format("transaction %d created for %s (%s) →" + + " expecting details", transactionId, date, + m.group(2))); + } + break; - case EXPECTING_TRANSACTION_DESCRIPTION: - if (!line.isEmpty() && (line.charAt(0) == ' ')) continue; - m = transactionDescriptionPattern.matcher(line); - if (m.find()) { - if (transactionId == 0) - throw new TransactionParserException( - "Transaction Id is 0 while expecting " + - "description"); - - transaction = - new LedgerTransaction(transactionId, m.group(1), - m.group(2)); - state = ParserState.EXPECTING_TRANSACTION_DETAILS; - L(String.format("transaction %d created for %s (%s) →" + - " expecting details", transactionId, - m.group(1), m.group(2))); - } - break; - - case EXPECTING_TRANSACTION_DETAILS: - if (line.isEmpty()) { - // transaction data collected - if (transaction.existsInDb(db)) { - db.execSQL("UPDATE transactions SET keep = 1 WHERE " + - "profile = ? and id=?", - new Object[]{profile.getUuid(), - transaction.getId() - }); - matchedTransactionsCount++; - - if (matchedTransactionsCount == - MATCHING_TRANSACTIONS_LIMIT) - { - db.execSQL("UPDATE transactions SET keep=1 WHERE " + - "profile = ? and id < ?", - new Object[]{profile.getUuid(), - transaction.getId() - }); - success = true; - progress.setTotal(progress.getProgress()); - publishProgress(progress); - break LINES; - } - } - else { - profile.storeTransaction(transaction); - matchedTransactionsCount = 0; - progress.setTotal(maxTransactionId); + case EXPECTING_TRANSACTION_DETAILS: + if (line.isEmpty()) { + // transaction data collected + if (transaction.existsInDb(db)) { + profile.markTransactionAsPresent(db, transaction); + matchedTransactionsCount++; + + if (matchedTransactionsCount == + MATCHING_TRANSACTIONS_LIMIT) + { + profile.markTransactionsBeforeTransactionAsPresent(db, + transaction); + progress.setTotal(progress.getProgress()); + publishProgress(progress); + break LINES; } + } + else { + profile.storeTransaction(db, transaction); + matchedTransactionsCount = 0; + progress.setTotal(maxTransactionId); + } - state = ParserState.EXPECTING_TRANSACTION; - L(String.format( - "transaction %s saved → expecting transaction", - transaction.getId())); - transaction.finishLoading(); - transactionList.add(transaction); + state = ParserState.EXPECTING_TRANSACTION; + L(String.format("transaction %s saved → expecting transaction", + transaction.getId())); + transaction.finishLoading(); // sounds like a good idea, but transaction-1 may not be the first one chronologically // for example, when you add the initial seeding transaction after entering some others @@ -310,71 +326,234 @@ public class RetrieveTransactionsTask // "parser"); // break LINES; // } + } + else { + m = reTransactionDetails.matcher(line); + if (m.find()) { + String acc_name = m.group(1); + String amount = m.group(2); + String currency = m.group(3); + if (currency == null) currency = ""; + amount = amount.replace(',', '.'); + transaction.addAccount( + new LedgerTransactionAccount(acc_name, + Float.valueOf(amount), currency)); + L(String.format("%d: %s = %s", transaction.getId(), + acc_name, amount)); } - else { - m = transactionDetailsPattern.matcher(line); - if (m.find()) { - String acc_name = m.group(1); - String amount = m.group(2); - String currency = m.group(3); - if (currency == null) currency = ""; - amount = amount.replace(',', '.'); - transaction.addAccount( - new LedgerTransactionAccount(acc_name, - Float.valueOf(amount), currency)); - L(String.format("%d: %s = %s", transaction.getId(), - acc_name, amount)); - } - else throw new IllegalStateException(String.format( - "Can't parse transaction %d " + "details: %s", - transactionId, line)); - } - break; - default: - throw new RuntimeException( - String.format("Unknown parser updating %s", - state.name())); - } + else throw new IllegalStateException(String.format( + "Can't parse transaction %d " + "details: %s", + transactionId, line)); + } + break; + default: + throw new RuntimeException( + String.format("Unknown parser updating %s", state.name())); } + } - throwIfCancelled(); + throwIfCancelled(); + + profile.deleteNotPresentTransactions(db); + db.setTransactionSuccessful(); - db.execSQL("DELETE FROM transactions WHERE profile=? AND keep = 0", - new String[]{profile.getUuid()}); - db.setTransactionSuccessful(); + profile.setLastUpdateStamp(); - Log.d("db", "Updating transaction value stamp"); - Date now = new Date(); - profile.set_option_value(MLDB.OPT_LAST_SCRAPE, now.getTime()); - Data.lastUpdateDate.set(now); - Data.transactions.set(transactionList); + return null; + } + finally { + db.endTransaction(); + } + } + } + } + private void prepareDbForRetrieval(SQLiteDatabase db, MobileLedgerProfile profile) { + db.execSQL("UPDATE transactions set keep=0 where profile=?", + new String[]{profile.getUuid()}); + db.execSQL("update account_values set keep=0 where profile=?;", + new String[]{profile.getUuid()}); + db.execSQL("update accounts set keep=0 where profile=?;", new String[]{profile.getUuid()}); + } + private boolean retrieveAccountList(MobileLedgerProfile profile) + throws IOException, HTTPException { + Progress progress = new Progress(); + + HttpURLConnection http = NetworkUtil.prepareConnection(profile, "accounts"); + http.setAllowUserInteraction(false); + switch (http.getResponseCode()) { + case 200: + break; + case 404: + return false; + default: + throw new HTTPException(http.getResponseCode(), http.getResponseMessage()); + } + publishProgress(progress); + SQLiteDatabase db = MLDB.getDatabase(); + ArrayList accountList = new ArrayList<>(); + boolean listFilledOK = false; + try (InputStream resp = http.getInputStream()) { + if (http.getResponseCode() != 200) + throw new IOException(String.format("HTTP error %d", http.getResponseCode())); + + db.beginTransaction(); + try { + profile.markAccountsAsNotPresent(db); + + AccountListParser parser = new AccountListParser(resp); + + LedgerAccount prevAccount = null; + + while (true) { + throwIfCancelled(); + ParsedLedgerAccount parsedAccount = parser.nextAccount(); + if (parsedAccount == null) break; + + LedgerAccount acc = profile.tryLoadAccount(db, parsedAccount.getAname()); + if (acc == null) acc = new LedgerAccount(parsedAccount.getAname()); + else acc.removeAmounts(); + + profile.storeAccount(db, acc); + for (ParsedBalance b : parsedAccount.getAebalance()) { + profile.storeAccountValue(db, acc.getName(), b.getAcommodity(), + b.getAquantity().asFloat()); } - finally { - db.endTransaction(); + + if (acc.isVisible(accountList)) accountList.add(acc); + + if (prevAccount != null) { + prevAccount.setHasSubAccounts( + acc.getName().startsWith(prevAccount.getName() + ":")); } + + prevAccount = acc; } + throwIfCancelled(); + + profile.deleteNotPresentAccounts(db); + throwIfCancelled(); + db.setTransactionSuccessful(); + listFilledOK = true; + } + finally { + db.endTransaction(); } } + // should not be set in the DB transaction, because of a possible deadlock + // with the main and DbOpQueueRunner threads + if (listFilledOK) Data.accounts.setList(accountList); + + return true; + } + private boolean retrieveTransactionList(MobileLedgerProfile profile) + throws IOException, ParseException, HTTPException { + Progress progress = new Progress(); + int maxTransactionId = Progress.INDETERMINATE; + + HttpURLConnection http = NetworkUtil.prepareConnection(profile, "transactions"); + http.setAllowUserInteraction(false); + publishProgress(progress); + switch (http.getResponseCode()) { + case 200: + break; + case 404: + return false; + default: + throw new HTTPException(http.getResponseCode(), http.getResponseMessage()); + } + SQLiteDatabase db = MLDB.getDatabase(); + try (InputStream resp = http.getInputStream()) { + if (http.getResponseCode() != 200) + throw new IOException(String.format("HTTP error %d", http.getResponseCode())); + throwIfCancelled(); + db.beginTransaction(); + try { + profile.markTransactionsAsNotPresent(db); + + int matchedTransactionsCount = 0; + TransactionListParser parser = new TransactionListParser(resp); + + int processedTransactionCount = 0; + + while (true) { + throwIfCancelled(); + ParsedLedgerTransaction parsedTransaction = parser.nextTransaction(); + throwIfCancelled(); + if (parsedTransaction == null) break; + LedgerTransaction transaction = parsedTransaction.asLedgerTransaction(); + if (transaction.existsInDb(db)) { + profile.markTransactionAsPresent(db, transaction); + matchedTransactionsCount++; + + if (matchedTransactionsCount == MATCHING_TRANSACTIONS_LIMIT) { + profile.markTransactionsBeforeTransactionAsPresent(db, transaction); + progress.setTotal(progress.getProgress()); + publishProgress(progress); + db.setTransactionSuccessful(); + profile.setLastUpdateStamp(); + return true; + } + } + else { + profile.storeTransaction(db, transaction); + matchedTransactionsCount = 0; + progress.setTotal(maxTransactionId); + } + + if ((progress.getTotal() == Progress.INDETERMINATE) || + (progress.getTotal() < transaction.getId())) + progress.setTotal(transaction.getId()); + + progress.setProgress(++processedTransactionCount); + publishProgress(progress); + } + + throwIfCancelled(); + profile.deleteNotPresentTransactions(db); + throwIfCancelled(); + db.setTransactionSuccessful(); + profile.setLastUpdateStamp(); + } + finally { + db.endTransaction(); + } + } + + return true; + } + @SuppressLint("DefaultLocale") + @Override + protected String doInBackground(Void... params) { + MobileLedgerProfile profile = Data.profile.get(); + Data.backgroundTaskCount.incrementAndGet(); + try { + if (!retrieveAccountList(profile) || !retrieveTransactionList(profile)) + return retrieveTransactionListLegacy(profile); + return null; + } catch (MalformedURLException e) { - error = R.string.err_bad_backend_url; e.printStackTrace(); + return "Invalid server URL"; } - catch (FileNotFoundException e) { - error = R.string.err_bad_auth; + catch (HTTPException e) { e.printStackTrace(); + return String.format("HTTP error %d: %s", e.getResponseCode(), e.getResponseMessage()); } catch (IOException e) { - error = R.string.err_net_io_error; e.printStackTrace(); + return e.getLocalizedMessage(); + } + catch (ParseException e) { + e.printStackTrace(); + return "Network error"; } catch (OperationCanceledException e) { - error = R.string.err_cancelled; e.printStackTrace(); + return "Operation cancelled"; } finally { Data.backgroundTaskCount.decrementAndGet(); } - return null; } private MainActivity getContext() { return contextRef.get();