@Override
    protected String[] doInBackground(Void... params) {

      try {
        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mParent);
        int activeAccount = prefs.getInt(Constants.KEY_ACTIVE_ACCOUNT, -1);

        JSONObject balance = RpcManager.getInstance().callGet(mParent, "account/balance");
        JSONObject exchangeRates =
            RpcManager.getInstance().callGet(mParent, "currencies/exchange_rates");

        String userHomeCurrency =
            prefs
                .getString(
                    String.format(Constants.KEY_ACCOUNT_NATIVE_CURRENCY, activeAccount), "usd")
                .toLowerCase(Locale.CANADA);
        BigDecimal homeAmount =
            new BigDecimal(balance.getString("amount"))
                .multiply(new BigDecimal(exchangeRates.getString("btc_to_" + userHomeCurrency)));

        String balanceString = Utils.formatCurrencyAmount(balance.getString("amount"));
        String balanceHomeString =
            Utils.formatCurrencyAmount(homeAmount, false, CurrencyType.TRADITIONAL);

        String[] result =
            new String[] {
              balanceString, balance.getString("currency"),
              balanceHomeString, userHomeCurrency.toUpperCase(Locale.CANADA)
            };

        // Save balance in preferences
        Editor editor = prefs.edit();
        editor.putString(String.format(Constants.KEY_ACCOUNT_BALANCE, activeAccount), result[0]);
        editor.putString(
            String.format(Constants.KEY_ACCOUNT_BALANCE_CURRENCY, activeAccount), result[1]);
        editor.putString(
            String.format(Constants.KEY_ACCOUNT_BALANCE_HOME, activeAccount), result[2]);
        editor.putString(
            String.format(Constants.KEY_ACCOUNT_BALANCE_HOME_CURRENCY, activeAccount), result[3]);
        editor.commit();

        return result;

      } catch (IOException e) {

        e.printStackTrace();
      } catch (JSONException e) {

        ACRA.getErrorReporter().handleException(new RuntimeException("LoadBalance", e));
        e.printStackTrace();
      }

      return null;
    }
    private Map<String, JSONObject> fetchTransferData() {

      try {

        Map<String, JSONObject> transfers = new HashMap<String, JSONObject>();

        int numTransferPages = 1;
        for (int i = 1; i <= Math.min(numTransferPages, MAX_TRANSFER_SYNC_PAGES); i++) {

          List<BasicNameValuePair> getParams = new ArrayList<BasicNameValuePair>();
          getParams.add(new BasicNameValuePair("page", Integer.toString(i)));
          JSONObject response = RpcManager.getInstance().callGet(mParent, "transfers", getParams);
          JSONArray transfersArray = response.optJSONArray("transfers");

          if (transfersArray == null || transfersArray.length() == 0) {
            return null; // No transfers
          }

          numTransferPages = response.getInt("num_pages");

          for (int j = 0; j < transfersArray.length(); j++) {

            JSONObject transfer = transfersArray.getJSONObject(j).getJSONObject("transfer");
            transfers.put(transfer.optString("transaction_id"), transfer);
          }
        }

        return transfers;

      } catch (IOException e) {
        e.printStackTrace();
      } catch (JSONException e) {
        ACRA.getErrorReporter()
            .handleException(new RuntimeException("SyncTransactions:transfers", e));
        e.printStackTrace();
      }

      Log.e("Coinbase", "Could not fetch transfer data");
      return null;
    }
    @Override
    protected Boolean doInBackground(Integer... params) {

      List<JSONObject> transactions = new ArrayList<JSONObject>();
      Map<String, JSONObject> transfers = null;
      String currentUserId = null;
      SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mParent);
      int activeAccount = prefs.getInt(Constants.KEY_ACTIVE_ACCOUNT, -1);

      int startPage = (params.length == 0 || params[0] == null) ? 0 : params[0];
      int loadedPage;

      // Make API call to download list of transactions
      try {

        int numPages = 1; // Real value will be set after first list iteration
        loadedPage = startPage;

        // Loop is required to sync all pages of transaction history
        for (int i = startPage + 1; i <= startPage + Math.min(numPages, MAX_PAGES); i++) {

          List<BasicNameValuePair> getParams = new ArrayList<BasicNameValuePair>();
          getParams.add(new BasicNameValuePair("page", Integer.toString(i)));
          JSONObject response =
              RpcManager.getInstance().callGet(mParent, "transactions", getParams);

          currentUserId = response.getJSONObject("current_user").getString("id");

          JSONArray transactionsArray = response.optJSONArray("transactions");
          numPages = response.getInt("num_pages");

          if (transactionsArray == null) {
            // No transactions
            continue;
          }

          for (int j = 0; j < transactionsArray.length(); j++) {

            JSONObject transaction =
                transactionsArray.getJSONObject(j).getJSONObject("transaction");
            transactions.add(transaction);
          }

          loadedPage++;
        }

        if (startPage == 0) {
          transfers = fetchTransferData();
        }

        mMaxPage = numPages;

      } catch (IOException e) {
        Log.e("Coinbase", "I/O error refreshing transactions.");
        e.printStackTrace();

        return false;
      } catch (JSONException e) {
        // Malformed response from Coinbase.
        Log.e(
            "Coinbase",
            "Could not parse JSON response from Coinbase, aborting refresh of transactions.");
        ACRA.getErrorReporter().handleException(new RuntimeException("SyncTransactions", e));
        e.printStackTrace();

        return false;
      }

      DatabaseObject db = DatabaseObject.getInstance();

      synchronized (db.databaseLock) {
        db.beginTransaction(mParent);
        try {

          if (startPage == 0) {
            // Remove all old transactions
            db.delete(
                mParent,
                TransactionEntry.TABLE_NAME,
                TransactionEntry.COLUMN_NAME_ACCOUNT + " = ?",
                new String[] {Integer.toString(activeAccount)});
          }

          // Update user ID
          Editor editor = prefs.edit();
          editor.putString(String.format(Constants.KEY_ACCOUNT_ID, activeAccount), currentUserId);
          editor.commit();

          for (JSONObject transaction : transactions) {

            ContentValues values = new ContentValues();

            String createdAtStr = transaction.optString("created_at", null);
            long createdAt;
            try {
              if (createdAtStr != null) {
                createdAt = ISO8601.toCalendar(createdAtStr).getTimeInMillis();
              } else {
                createdAt = -1;
              }
            } catch (ParseException e) {
              // Error parsing createdAt
              e.printStackTrace();
              createdAt = -1;
            }

            JSONObject transferData = null;

            if (transfers != null) {

              String id = transaction.optString("id");
              transferData = transfers.get(id);
            }

            values.put(TransactionEntry._ID, transaction.getString("id"));
            values.put(TransactionEntry.COLUMN_NAME_JSON, transaction.toString());
            values.put(TransactionEntry.COLUMN_NAME_TIME, createdAt);
            values.put(TransactionEntry.COLUMN_NAME_ACCOUNT, activeAccount);
            values.put(
                TransactionEntry.COLUMN_NAME_TRANSFER_JSON,
                transferData == null ? null : transferData.toString());
            values.put(TransactionEntry.COLUMN_NAME_IS_TRANSFER, transferData == null ? 0 : 1);

            db.insert(mParent, TransactionEntry.TABLE_NAME, null, values);
          }

          db.setTransactionSuccessful(mParent);
          mLastLoadedPage = loadedPage;

          // Update list
          loadTransactionsList();

          // Update transaction widgets
          updateWidgets();

          // Update the buy / sell history list
          mParent.getBuySellFragment().onTransactionsSynced();

          return true;

        } catch (JSONException e) {
          // Malformed response from Coinbase.
          Log.e(
              "Coinbase",
              "Could not parse JSON response from Coinbase, aborting refresh of transactions.");
          e.printStackTrace();

          return false;
        } finally {

          db.endTransaction(mParent);
        }
      }
    }