Skip to content

Commit

Permalink
Fix widget not refreshing on auto updates
Browse files Browse the repository at this point in the history
Before this change:
* when the banks were auto updated
* and the bank's balance change was lower than the notification
  threshold
... then the widget wasn't updated.

With this change in place the widget is actually updated even in this
case.

This change also adds unit testing of the auto update data retrieval
code.
  • Loading branch information
walles authored and goober committed Sep 28, 2016
1 parent 84b30ea commit 42b6615
Show file tree
Hide file tree
Showing 5 changed files with 178 additions and 30 deletions.
1 change: 1 addition & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ Please view this file on the master branch, on stable branches it's out of date.

v1.9.10.8
* Add a Volatile account to the Test Bank that always changes its balance.
* Fix widget not updating when the balance change was lower than the notification threshold.

v1.9.10.7 (2016-08-18)
* Update certificates for AmericanExpress and Coop
Expand Down
3 changes: 2 additions & 1 deletion CONTRIBUTORS.txt
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,12 @@ Development
Mikael Eriksson https://github.com/mikaeler
Mikael Auno https://github.com/auno
robho https://github.com/robho
Johan Walles https://github.com/walles


Stats at:
https://github.com/liato/android-bankdroid/graphs/contributors?type=a

--------------------------------------------------------------------------------
Beta testing
--------------------------------------------------------------------------------
Expand Down
3 changes: 3 additions & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -80,4 +80,7 @@ dependencies {
compile('com.crashlytics.sdk.android:crashlytics:2.2.1@aar') {
transitive = true;
}

testCompile 'junit:junit:4.12'
testCompile 'org.mockito:mockito-core:1.10.19'
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,19 @@

package com.liato.bankdroid.appwidget;

import com.crashlytics.android.Crashlytics;
import com.liato.bankdroid.Helpers;
import com.liato.bankdroid.MainActivity;
import com.liato.bankdroid.R;
import com.liato.bankdroid.banking.Account;
import com.liato.bankdroid.banking.Bank;
import com.liato.bankdroid.banking.BankFactory;
import com.liato.bankdroid.banking.exceptions.BankChoiceException;
import com.liato.bankdroid.banking.exceptions.BankException;
import com.liato.bankdroid.banking.exceptions.LoginException;
import com.liato.bankdroid.db.DBAdapter;
import com.liato.bankdroid.liveview.LiveViewService;

import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.PendingIntent.CanceledException;
Expand All @@ -32,26 +45,15 @@
import android.os.IBinder;
import android.os.SystemClock;
import android.preference.PreferenceManager;
import android.support.annotation.NonNull;
import android.support.v4.app.NotificationCompat;
import android.util.Log;

import com.crashlytics.android.Crashlytics;
import com.liato.bankdroid.Helpers;
import com.liato.bankdroid.MainActivity;
import com.liato.bankdroid.R;
import com.liato.bankdroid.banking.Account;
import com.liato.bankdroid.banking.Bank;
import com.liato.bankdroid.banking.BankFactory;
import com.liato.bankdroid.banking.exceptions.BankChoiceException;
import com.liato.bankdroid.banking.exceptions.BankException;
import com.liato.bankdroid.banking.exceptions.LoginException;
import com.liato.bankdroid.db.DBAdapter;
import com.liato.bankdroid.liveview.LiveViewService;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;

public class AutoRefreshService extends Service {

Expand Down Expand Up @@ -208,7 +210,7 @@ private void handleStart(Intent intent, int startId) {
ni.isConnected() &&
shouldUpdateOnRoaming(ni)) {
if (InsideUpdatePeriod()) {
new DataRetrieverTask().execute();
new DataRetrieverTask(this).execute();
} else {
Log.v(TAG, "Skipping update due to not in update period.");
stopSelf();
Expand Down Expand Up @@ -253,32 +255,54 @@ public IBinder onBind(final Intent intent) {
return null;
}

private class DataRetrieverTask extends AsyncTask<String, String, Void> {
static class DataRetrieverTask extends AsyncTask<String, String, Void> {

SharedPreferences prefs = PreferenceManager
.getDefaultSharedPreferences(AutoRefreshService.this);
private final SharedPreferences prefs;

private ArrayList<String> errors;
protected final AutoRefreshService autoRefreshService;

private Resources res;

public DataRetrieverTask() {
// This constructor is for unit testing only
protected DataRetrieverTask(AutoRefreshService autoRefreshService, SharedPreferences prefs) {
this.autoRefreshService = autoRefreshService;
this.prefs = prefs;
}

public DataRetrieverTask(AutoRefreshService autoRefreshService) {
this(autoRefreshService,
PreferenceManager.getDefaultSharedPreferences(autoRefreshService));
}

@Override
protected void onPreExecute() {
}

protected List<Bank> getBanks() {
return BankFactory.banksFromDb(autoRefreshService, true);
}

@NonNull
protected DBAdapter getDBAdapter() {
return new DBAdapter(autoRefreshService);
}

protected void sendWidgetRefresh() {
final Intent updateIntent = new Intent(BROADCAST_MAIN_REFRESH);
autoRefreshService.sendBroadcast(updateIntent);
AutoRefreshService.sendWidgetRefresh(autoRefreshService);
}

@Override
protected Void doInBackground(final String... args) {
errors = new ArrayList<String>();
Boolean refreshWidgets = false;
final ArrayList<Bank> banks = BankFactory.banksFromDb(
AutoRefreshService.this, true);
final List<Bank> banks = getBanks();
if (banks.isEmpty()) {
return null;
}
final DBAdapter db = new DBAdapter(AutoRefreshService.this);
final DBAdapter db = getDBAdapter();
BigDecimal currentBalance;
BigDecimal diff;
BigDecimal minDelta = new BigDecimal(prefs.getString("notify_min_delta", "0"));
Expand All @@ -304,6 +328,11 @@ protected Void doInBackground(final String... args) {
}
bank.update();
diff = currentBalance.subtract(bank.getBalance());

if (diff.compareTo(BigDecimal.ZERO) != 0) {
refreshWidgets = true;
}

if (diff.compareTo(new BigDecimal(0)) != 0
&& diff.abs().compareTo(minDelta) != -1) {
Account oldAccount;
Expand Down Expand Up @@ -343,10 +372,8 @@ protected Void doInBackground(final String... args) {
diff = account.getBalance().subtract(
oldAccount.getBalance());
showNotification(bank, account, diff,
AutoRefreshService.this);
autoRefreshService);
}

refreshWidgets = true;
}
}
}
Expand All @@ -362,7 +389,7 @@ protected Void doInBackground(final String... args) {
// database transaction history
if (prefs.getBoolean("content_provider_enabled", false)) {
for (final Account account : bank.getAccounts()) {
broadcastTransactionUpdate(getBaseContext(),
broadcastTransactionUpdate(autoRefreshService.getBaseContext(),
bank.getDbId(), account.getId());
}
}
Expand All @@ -385,9 +412,7 @@ protected Void doInBackground(final String... args) {
}

if (refreshWidgets) {
final Intent updateIntent = new Intent(BROADCAST_MAIN_REFRESH);
sendBroadcast(updateIntent);
sendWidgetRefresh(AutoRefreshService.this);
sendWidgetRefresh();
}
return null;
}
Expand All @@ -410,7 +435,7 @@ protected void onPostExecute(final Void unused) {
Editor edit = prefs.edit();
edit.putLong("autoupdates_last_update", System.currentTimeMillis());
edit.commit();
AutoRefreshService.this.stopSelf();
autoRefreshService.stopSelf();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
package com.liato.bankdroid.appwidget;

import com.liato.bankdroid.banking.Account;
import com.liato.bankdroid.banking.Bank;
import com.liato.bankdroid.db.DBAdapter;

import org.junit.Assert;
import org.junit.Test;
import org.mockito.Mockito;

import android.content.Context;
import android.content.SharedPreferences;
import android.support.annotation.NonNull;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

public class DataRetrieverTaskTest {
private static class TestableBank extends Bank {
private final int balanceBeforeUpdate;
private final int balanceAfterUpdate;
private boolean hasUpdated = false;

public TestableBank(int balanceBeforeUpdate, int balanceAfterUpdate) {
super(Mockito.mock(Context.class));

this.balanceBeforeUpdate = balanceBeforeUpdate;
this.balanceAfterUpdate = balanceAfterUpdate;
}

@Override
public void update() {
hasUpdated = true;
}

@Override
public ArrayList<Account> getAccounts() {
int balance;
if (hasUpdated) {
balance = balanceAfterUpdate;
} else {
balance = balanceBeforeUpdate;
}

Account account = Mockito.mock(Account.class);
Mockito.when(account.getBalance()).thenReturn(BigDecimal.valueOf(balance));

ArrayList<Account> accounts = new ArrayList<>();
accounts.add(account);

return accounts;
}

@Override
public BigDecimal getBalance() {
return getAccounts().get(0).getBalance();
}
}

private static class TestableDataRetrieverTask extends AutoRefreshService.DataRetrieverTask {
private final Bank bank;
private boolean hasRefreshedWidget = false;

private TestableDataRetrieverTask(
AutoRefreshService autoRefreshService, SharedPreferences prefs, Bank bank) {
super(autoRefreshService, prefs);

this.bank = bank;
}

@Override
protected List<Bank> getBanks() {
List<Bank> returnMe = new ArrayList<>();
returnMe.add(bank);
return returnMe;
}

@NonNull
@Override
protected DBAdapter getDBAdapter() {
return Mockito.mock(DBAdapter.class);
}

@Override
protected void sendWidgetRefresh() {
hasRefreshedWidget = true;
}
}

@Test
public void testIncreaseLessThanNotificationThreshold() throws Exception {
AutoRefreshService autoRefreshService = Mockito.mock(AutoRefreshService.class);

SharedPreferences prefs = Mockito.mock(SharedPreferences.class);
Mockito.when(prefs.getString("notify_min_delta", "0")).thenReturn("300");

TestableDataRetrieverTask testMe =
new TestableDataRetrieverTask(autoRefreshService, prefs, new TestableBank(100, 200));
testMe.doInBackground();

Assert.assertTrue("Widget should have been refreshed", testMe.hasRefreshedWidget);
}

@Test
public void testNoChange() throws Exception {
AutoRefreshService autoRefreshService = Mockito.mock(AutoRefreshService.class);

SharedPreferences prefs = Mockito.mock(SharedPreferences.class);
Mockito.when(prefs.getString("notify_min_delta", "0")).thenReturn("0");

TestableDataRetrieverTask testMe =
new TestableDataRetrieverTask(autoRefreshService, prefs, new TestableBank(100, 100));
testMe.doInBackground();

Assert.assertFalse("Widget shouldn't have been refreshed", testMe.hasRefreshedWidget);
}
}

0 comments on commit 42b6615

Please sign in to comment.