diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml
index ab9d4a2a1..7b6ca6d91 100644
--- a/.github/workflows/android.yml
+++ b/.github/workflows/android.yml
@@ -23,5 +23,11 @@ jobs:
run: ./gradlew lintRelease
- name: Run unit tests
run: ./gradlew testReleaseUnitTest
- - name: FindBugs
- run: ./gradlew findbugs
+ - name: SpotBugs
+ run: ./gradlew spotbugsRelease
+ - name: Archive test results
+ if: always()
+ uses: actions/upload-artifact@v1
+ with:
+ name: test-results
+ path: app/build/reports
diff --git a/.gitignore b/.gitignore
index 7473f08aa..7472a42d6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,10 +1,9 @@
*.iml
.gradle
-/local.properties
-/.idea/workspace.xml
-/.idea/libraries
+local.properties
+.idea/
.DS_Store
-/build
-/captures
-/app/release
-/app/debug
+build/
+captures/
+**/release
+**/debug
diff --git a/app/.gitignore b/app/.gitignore
deleted file mode 100644
index 796b96d1c..000000000
--- a/app/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-/build
diff --git a/app/build.gradle b/app/build.gradle
index f055a2b3f..8281e9a4f 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -1,13 +1,18 @@
-apply plugin: 'com.android.application'
-apply plugin: 'findbugs'
+import com.github.spotbugs.snom.SpotBugsTask
-findbugs {
- sourceSets = []
+apply plugin: 'com.android.application'
+apply plugin: 'com.github.spotbugs'
+
+spotbugs {
ignoreFailures = false
+ effort = 'max'
+ excludeFilter = file("./config/spotbugs/exclude.xml")
+ reportsDir = file("$buildDir/reports/spotbugs/")
}
android {
compileSdkVersion 29
+ buildToolsVersion "30.0.3"
defaultConfig {
applicationId "me.hackerchick.catima"
@@ -15,63 +20,71 @@ android {
targetSdkVersion 29
versionCode 53
versionName "1.6.1"
- vectorDrawables.useSupportLibrary = true
+
+ vectorDrawables.useSupportLibrary true
}
+
buildTypes {
release {
- minifyEnabled false
+ minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+ resValue "string", "app_name", "Catima"
}
debug {
applicationIdSuffix ".debug"
+ resValue "string", "app_name", "Catima Debug"
}
}
+
+ compileOptions {
+ encoding "UTF-8"
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+
lintOptions {
- disable "GoogleAppIndexingWarning"
- disable "ButtonStyle"
- disable "AlwaysShowAction"
- disable "MissingTranslation"
- disable "MissingPrefix"
+ disable "GoogleAppIndexingWarning", "ButtonStyle", "AlwaysShowAction",
+ "MissingTranslation", "MissingPrefix"
}
// Starting with Android Studio 3 Robolectric is unable to find resources.
// The following allows it to find the resources.
testOptions {
unitTests {
- includeAndroidResources = true
+ includeAndroidResources true
}
}
}
dependencies {
- implementation fileTree(dir: 'libs', include: ['*.jar'])
+// AndroidX
implementation 'androidx.appcompat:appcompat:1.2.0'
- implementation 'com.google.android.material:material:1.2.1'
- implementation 'androidx.legacy:legacy-support-v4:1.0.0'
- implementation 'com.journeyapps:zxing-android-embedded:4.0.2@aar'
- implementation 'com.google.zxing:core:3.3.0'
- implementation 'org.apache.commons:commons-csv:1.5'
- implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
- implementation 'com.jaredrummler:colorpicker:1.0.2'
- implementation group: 'com.google.guava', name: 'guava', version: '20.0'
- implementation "com.vanniktech:vntnumberpickerpreference:1.0.0"
implementation 'androidx.cardview:cardview:1.0.0'
- testImplementation 'junit:junit:4.12'
- testImplementation "org.robolectric:robolectric:4.0.2"
+ implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
+ implementation 'androidx.preference:preference:1.1.1'
+ implementation 'com.google.android.material:material:1.2.1'
+
+// Third-party
+ implementation 'com.journeyapps:zxing-android-embedded:4.1.0@aar'
+ implementation 'com.google.zxing:core:3.4.1'
+ implementation 'org.apache.commons:commons-csv:1.8'
+ implementation 'com.jaredrummler:colorpicker:1.1.0'
+ implementation 'com.google.guava:guava:30.1-jre'
+ implementation 'com.github.invissvenska:NumberPickerPreference:1.0.1'
+
+// Testing
+ testImplementation 'junit:junit:4.13.1'
+ testImplementation 'org.robolectric:robolectric:4.0.2'
}
-task findbugs(type: FindBugs, dependsOn: 'assembleDebug') {
+tasks.withType(SpotBugsTask) {
- description 'Run findbugs'
+ description 'Run spotbugs'
group 'verification'
- classes = fileTree('build/intermediates/javac/debug/compileDebugJavaWithJavac/classes')
- source = fileTree('src/main/java')
- classpath = files()
-
- effort = 'max'
-
- excludeFilter = file("./config/findbugs/exclude.xml")
+ //classes = fileTree('build/intermediates/javac/debug/compileDebugJavaWithJavac/classes')
+ //source = fileTree('src/main/java')
+ //classpath = files()
reports {
xml.enabled = false
diff --git a/app/config/findbugs/exclude.xml b/app/config/spotbugs/exclude.xml
similarity index 100%
rename from app/config/findbugs/exclude.xml
rename to app/config/spotbugs/exclude.xml
diff --git a/app/src/androidTest/java/protect/card_locker/ApplicationTest.java b/app/src/androidTest/java/protect/card_locker/ApplicationTest.java
deleted file mode 100644
index 2e3339b0e..000000000
--- a/app/src/androidTest/java/protect/card_locker/ApplicationTest.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package protect.card_locker;
-
-import android.app.Application;
-import android.test.ApplicationTestCase;
-
-/**
- * Testing Fundamentals
- */
-public class ApplicationTest extends ApplicationTestCase
-{
- public ApplicationTest()
- {
- super(Application.class);
- }
-}
diff --git a/app/src/main/java/protect/card_locker/AboutActivity.java b/app/src/main/java/protect/card_locker/AboutActivity.java
index 1c3efad38..0367ad75b 100644
--- a/app/src/main/java/protect/card_locker/AboutActivity.java
+++ b/app/src/main/java/protect/card_locker/AboutActivity.java
@@ -41,7 +41,7 @@ public class AboutActivity extends AppCompatActivity
.put("ZXing", "https://github.com/zxing/zxing")
.put("ZXing Android Embedded", "https://github.com/journeyapps/zxing-android-embedded")
.put("Color Picker", "https://github.com/jaredrummler/ColorPicker")
- .put("VNTNumberPickerPreference", "https://github.com/vanniktech/VNTNumberPickerPreference")
+ .put("NumberPickerPreference", "https://github.com/invissvenska/NumberPickerPreference")
.build();
final Map USED_ASSETS = ImmutableMap.of
diff --git a/app/src/main/java/protect/card_locker/CsvDatabaseImporter.java b/app/src/main/java/protect/card_locker/CsvDatabaseImporter.java
index 400436ec5..6f68d318a 100644
--- a/app/src/main/java/protect/card_locker/CsvDatabaseImporter.java
+++ b/app/src/main/java/protect/card_locker/CsvDatabaseImporter.java
@@ -47,6 +47,8 @@ public class CsvDatabaseImporter implements DatabaseImporter
default:
throw new FormatException(String.format("No code to parse version %s", version));
}
+
+ bufferedReader.close();
}
public void parseV1(DBHelper db, BufferedReader input) throws IOException, FormatException, InterruptedException
@@ -131,7 +133,6 @@ public class CsvDatabaseImporter implements DatabaseImporter
}
}
-
public void parseV2Groups(DBHelper db, SQLiteDatabase database, String data) throws IOException, FormatException, InterruptedException
{
// Parse groups
@@ -145,10 +146,10 @@ public class CsvDatabaseImporter implements DatabaseImporter
throw new InterruptedException();
}
}
-
- groupParser.close();
} catch (IllegalArgumentException | IllegalStateException e) {
throw new FormatException("Issue parsing CSV data", e);
+ } finally {
+ groupParser.close();
}
}
@@ -165,10 +166,10 @@ public class CsvDatabaseImporter implements DatabaseImporter
throw new InterruptedException();
}
}
-
- cardParser.close();
} catch (IllegalArgumentException | IllegalStateException e) {
throw new FormatException("Issue parsing CSV data", e);
+ } finally {
+ cardParser.close();
}
}
@@ -185,10 +186,10 @@ public class CsvDatabaseImporter implements DatabaseImporter
throw new InterruptedException();
}
}
-
- cardGroupParser.close();
} catch (IllegalArgumentException | IllegalStateException e) {
throw new FormatException("Issue parsing CSV data", e);
+ } finally {
+ cardGroupParser.close();
}
}
diff --git a/app/src/main/java/protect/card_locker/DBHelper.java b/app/src/main/java/protect/card_locker/DBHelper.java
index ce5ea4035..5536eaaa6 100644
--- a/app/src/main/java/protect/card_locker/DBHelper.java
+++ b/app/src/main/java/protect/card_locker/DBHelper.java
@@ -215,6 +215,7 @@ public class DBHelper extends SQLiteOpenHelper
List groups = new ArrayList<>();
if (!data.moveToFirst()) {
+ data.close();
return groups;
}
@@ -224,6 +225,8 @@ public class DBHelper extends SQLiteOpenHelper
groups.add(Group.toGroup(data));
}
+ data.close();
+
return groups;
}
@@ -395,6 +398,7 @@ public class DBHelper extends SQLiteOpenHelper
List groups = new ArrayList<>();
if (!data.moveToFirst()) {
+ data.close();
return groups;
}
@@ -404,6 +408,8 @@ public class DBHelper extends SQLiteOpenHelper
groups.add(Group.toGroup(data));
}
+ data.close();
+
return groups;
}
diff --git a/app/src/main/java/protect/card_locker/LoyaltyCardEditActivity.java b/app/src/main/java/protect/card_locker/LoyaltyCardEditActivity.java
index 8b46ffbc7..48ad0950f 100644
--- a/app/src/main/java/protect/card_locker/LoyaltyCardEditActivity.java
+++ b/app/src/main/java/protect/card_locker/LoyaltyCardEditActivity.java
@@ -446,7 +446,7 @@ public class LoyaltyCardEditActivity extends AppCompatActivity
// Nothing to do, no change made
}
});
- dialog.show(getFragmentManager(), "color-picker-dialog");
+ dialog.show(getSupportFragmentManager(), "color-picker-dialog");
}
}
diff --git a/app/src/main/java/protect/card_locker/LoyaltyCardViewActivity.java b/app/src/main/java/protect/card_locker/LoyaltyCardViewActivity.java
index 77b2b8d01..557395972 100644
--- a/app/src/main/java/protect/card_locker/LoyaltyCardViewActivity.java
+++ b/app/src/main/java/protect/card_locker/LoyaltyCardViewActivity.java
@@ -73,6 +73,7 @@ public class LoyaltyCardViewActivity extends AppCompatActivity
private Drawable getIcon(int icon, boolean dark)
{
Drawable unwrappedIcon = AppCompatResources.getDrawable(this, icon);
+ assert unwrappedIcon != null;
Drawable wrappedIcon = DrawableCompat.wrap(unwrappedIcon);
if(dark)
{
@@ -123,7 +124,7 @@ public class LoyaltyCardViewActivity extends AppCompatActivity
barcodeImage.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
- if(barcodeIsFullscreen)
+ if (barcodeIsFullscreen)
{
setFullscreen(false);
}
diff --git a/app/src/main/java/protect/card_locker/MainActivity.java b/app/src/main/java/protect/card_locker/MainActivity.java
index ef091fccd..1faf8f23f 100644
--- a/app/src/main/java/protect/card_locker/MainActivity.java
+++ b/app/src/main/java/protect/card_locker/MainActivity.java
@@ -120,13 +120,13 @@ public class MainActivity extends AppCompatActivity implements GestureDetector.O
Object group = null;
if (groupsTabLayout.getTabCount() != 0) {
- TabLayout.Tab tab = groupsTabLayout.getTabAt(0);
-
- if (selectedTab < groupsTabLayout.getTabCount()) {
- tab = groupsTabLayout.getTabAt(selectedTab);
+ TabLayout.Tab tab = groupsTabLayout.getTabAt(selectedTab);
+ if (tab == null) {
+ tab = groupsTabLayout.getTabAt(0);
}
groupsTabLayout.selectTab(tab);
+ assert tab != null;
group = tab.getTag();
}
updateLoyaltyCardList(filter, group);
@@ -361,8 +361,13 @@ public class MainActivity extends AppCompatActivity implements GestureDetector.O
filter = newText;
TabLayout groupsTabLayout = findViewById(R.id.groups);
+ TabLayout.Tab currentTab = groupsTabLayout.getTabAt(groupsTabLayout.getSelectedTabPosition());
+
+ updateLoyaltyCardList(
+ newText,
+ currentTab != null ? currentTab.getTag() : null
+ );
- updateLoyaltyCardList(newText, groupsTabLayout.getTabCount() > 0 ? groupsTabLayout.getTabAt(groupsTabLayout.getSelectedTabPosition()).getTag() : null);
return true;
}
});
diff --git a/app/src/main/java/protect/card_locker/MultiFormatImporter.java b/app/src/main/java/protect/card_locker/MultiFormatImporter.java
index a4ab4c83c..6a27af7e4 100644
--- a/app/src/main/java/protect/card_locker/MultiFormatImporter.java
+++ b/app/src/main/java/protect/card_locker/MultiFormatImporter.java
@@ -31,32 +31,23 @@ public class MultiFormatImporter
break;
}
- if(importer != null)
+ if (importer != null)
{
try
{
importer.importData(db, input);
return true;
}
- catch(IOException e)
+ catch(IOException | FormatException | InterruptedException e)
{
- Log.e(TAG, "Failed to input data", e);
- }
- catch(FormatException e)
- {
- Log.e(TAG, "Failed to input data", e);
- }
- catch(InterruptedException e)
- {
- Log.e(TAG, "Failed to input data", e);
+ Log.e(TAG, "Failed to import data", e);
}
- return false;
}
else
{
Log.e(TAG, "Unsupported data format imported: " + format.name());
- return false;
}
+ return false;
}
}
diff --git a/app/src/main/java/protect/card_locker/preferences/Settings.java b/app/src/main/java/protect/card_locker/preferences/Settings.java
index 8be423b17..b6808f352 100644
--- a/app/src/main/java/protect/card_locker/preferences/Settings.java
+++ b/app/src/main/java/protect/card_locker/preferences/Settings.java
@@ -2,7 +2,7 @@ package protect.card_locker.preferences;
import android.content.Context;
import android.content.SharedPreferences;
-import android.preference.PreferenceManager;
+import androidx.preference.PreferenceManager;
import androidx.annotation.IntegerRes;
import androidx.annotation.StringRes;
import androidx.appcompat.app.AppCompatDelegate;
diff --git a/app/src/main/java/protect/card_locker/preferences/SettingsActivity.java b/app/src/main/java/protect/card_locker/preferences/SettingsActivity.java
index 485626742..8674e8a33 100644
--- a/app/src/main/java/protect/card_locker/preferences/SettingsActivity.java
+++ b/app/src/main/java/protect/card_locker/preferences/SettingsActivity.java
@@ -1,13 +1,17 @@
package protect.card_locker.preferences;
import android.os.Bundle;
-import android.preference.Preference;
-import android.preference.PreferenceFragment;
+import androidx.fragment.app.DialogFragment;
+import androidx.fragment.app.FragmentActivity;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceFragmentCompat;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.app.AppCompatDelegate;
import android.view.MenuItem;
+import nl.invissvenska.numberpickerpreference.NumberDialogPreference;
+import nl.invissvenska.numberpickerpreference.NumberPickerPreferenceDialogFragment;
import protect.card_locker.R;
public class SettingsActivity extends AppCompatActivity
@@ -20,11 +24,11 @@ public class SettingsActivity extends AppCompatActivity
ActionBar actionBar = getSupportActionBar();
if(actionBar != null)
{
- getSupportActionBar().setDisplayHomeAsUpEnabled(true);
+ actionBar.setDisplayHomeAsUpEnabled(true);
}
// Display the fragment as the main content.
- getFragmentManager().beginTransaction()
+ getSupportFragmentManager().beginTransaction()
.replace(android.R.id.content, new SettingsFragment())
.commit();
}
@@ -43,17 +47,18 @@ public class SettingsActivity extends AppCompatActivity
return super.onOptionsItemSelected(item);
}
- public static class SettingsFragment extends PreferenceFragment
+ public static class SettingsFragment extends PreferenceFragmentCompat
{
+ private static final String DIALOG_FRAGMENT_TAG = "SettingsFragment";
@Override
- public void onCreate(final Bundle savedInstanceState)
+ public void onCreatePreferences(Bundle savedInstanceState, String rootKey)
{
- super.onCreate(savedInstanceState);
-
// Load the preferences from an XML resource
addPreferencesFromResource(R.xml.preferences);
- findPreference(getResources().getString(R.string.settings_key_theme)).setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener()
+ Preference themePreference = findPreference(getResources().getString(R.string.settings_key_theme));
+ assert themePreference != null;
+ themePreference.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener()
{
@Override
public boolean onPreferenceChange(Preference preference, Object o)
@@ -71,11 +76,36 @@ public class SettingsActivity extends AppCompatActivity
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM);
}
- getActivity().recreate();
+ FragmentActivity activity = getActivity();
+ if (activity != null) {
+ activity.recreate();
+ }
return true;
}
});
}
+
+ @Override
+ public void onDisplayPreferenceDialog(Preference preference)
+ {
+ if (preference instanceof NumberDialogPreference)
+ {
+ NumberDialogPreference dialogPreference = (NumberDialogPreference) preference;
+ DialogFragment dialogFragment = NumberPickerPreferenceDialogFragment
+ .newInstance(
+ dialogPreference.getKey(),
+ dialogPreference.getMinValue(),
+ dialogPreference.getMaxValue(),
+ dialogPreference.getUnitText()
+ );
+ dialogFragment.setTargetFragment(this, 0);
+ dialogFragment.show(getParentFragmentManager(), DIALOG_FRAGMENT_TAG);
+ }
+ else
+ {
+ super.onDisplayPreferenceDialog(preference);
+ }
+ }
}
}
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 18cd8e6b2..d75bd4cf7 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -2,7 +2,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"
xmlns:tools="http://schemas.android.com/tools">
- Catima
Search
Add
diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml
index 54a2a9397..b176a17a7 100644
--- a/app/src/main/res/xml/preferences.xml
+++ b/app/src/main/res/xml/preferences.xml
@@ -4,52 +4,60 @@
xmlns:app="http://schemas.android.com/apk/res-auto">
+ android:title="@string/settings_category_title_ui"
+ app:iconSpaceReserved="false">
+ android:entryValues="@array/theme_values"
+ app:iconSpaceReserved="false" />
-
+ app:defaultValue="@integer/settings_card_title_list_font_size_sp"
+ app:numberPickerPreference_maxValue="@integer/settings_card_title_list_max_font_size_sp"
+ app:numberPickerPreference_minValue="@integer/settings_card_title_list_min_font_size_sp"
+ app:iconSpaceReserved="false" />
-
+ app:defaultValue="@integer/settings_card_note_list_font_size_sp"
+ app:numberPickerPreference_maxValue="@integer/settings_card_note_list_max_font_size_sp"
+ app:numberPickerPreference_minValue="@integer/settings_card_note_list_min_font_size_sp"
+ app:iconSpaceReserved="false" />
-
+ app:defaultValue="@integer/settings_card_title_font_size_sp"
+ app:numberPickerPreference_maxValue="@integer/settings_card_title_max_font_size_sp"
+ app:numberPickerPreference_minValue="@integer/settings_card_title_min_font_size_sp"
+ app:iconSpaceReserved="false" />
-
+ app:defaultValue="@integer/settings_card_id_font_size_sp"
+ app:numberPickerPreference_maxValue="@integer/settings_card_id_max_font_size_sp"
+ app:numberPickerPreference_minValue="@integer/settings_card_id_min_font_size_sp"
+ app:iconSpaceReserved="false" />
-
+ android:title="@string/settings_display_barcode_max_brightness"
+ app:iconSpaceReserved="false" />
-
+ android:title="@string/settings_lock_barcode_orientation"
+ app:iconSpaceReserved="false" />
\ No newline at end of file
diff --git a/app/src/test/java/protect/card_locker/DatabaseTest.java b/app/src/test/java/protect/card_locker/DatabaseTest.java
index d9fc87520..2d4f06f0f 100644
--- a/app/src/test/java/protect/card_locker/DatabaseTest.java
+++ b/app/src/test/java/protect/card_locker/DatabaseTest.java
@@ -170,6 +170,8 @@ public class DatabaseTest
}
assertTrue(cursor.isAfterLast());
+
+ cursor.close();
}
@Test
@@ -227,6 +229,8 @@ public class DatabaseTest
}
assertTrue(cursor.isAfterLast());
+
+ cursor.close();
}
private void setupDatabaseVersion1(SQLiteDatabase database)
diff --git a/app/src/test/java/protect/card_locker/ImportExportTest.java b/app/src/test/java/protect/card_locker/ImportExportTest.java
index 64c13bd80..55dd508d7 100644
--- a/app/src/test/java/protect/card_locker/ImportExportTest.java
+++ b/app/src/test/java/protect/card_locker/ImportExportTest.java
@@ -224,6 +224,8 @@ public class ImportExportTest
{
SQLiteDatabase database = db.getWritableDatabase();
database.execSQL("delete from " + DBHelper.LoyaltyCardDbIds.TABLE);
+ database.execSQL("delete from " + DBHelper.LoyaltyCardDbGroups.TABLE);
+ database.execSQL("delete from " + DBHelper.LoyaltyCardDbIdsGroups.TABLE);
database.close();
assertEquals(0, db.getLoyaltyCardCount());
@@ -454,6 +456,8 @@ public class ImportExportTest
assertEquals(false, result);
assertEquals(0, db.getLoyaltyCardCount());
+
+ clearDatabase();
}
}
@@ -549,6 +553,8 @@ public class ImportExportTest
assertEquals("type", card.barcodeType);
assertEquals(0, card.starStatus);
assertNull(card.headerColor);
+
+ clearDatabase();
}
@Test
@@ -582,6 +588,8 @@ public class ImportExportTest
assertEquals("type", card.barcodeType);
assertEquals(0, card.starStatus);
assertNull(card.headerColor);
+
+ clearDatabase();
}
@Test
@@ -606,6 +614,8 @@ public class ImportExportTest
boolean result = MultiFormatImporter.importData(db, inStream, DataFormat.CSV);
assertEquals(false, result);
assertEquals(0, db.getLoyaltyCardCount());
+
+ clearDatabase();
}
@Test
@@ -639,6 +649,8 @@ public class ImportExportTest
assertEquals("", card.barcodeType);
assertEquals(0, card.starStatus);
assertEquals(1, (long) card.headerColor);
+
+ clearDatabase();
}
@Test
@@ -672,10 +684,10 @@ public class ImportExportTest
assertEquals("type", card.barcodeType);
assertEquals(1, card.starStatus);
assertEquals(1, (long) card.headerColor);
+
+ clearDatabase();
}
-
-
@Test
public void importWithNoStarredFieldV1() throws IOException
{
@@ -707,6 +719,8 @@ public class ImportExportTest
assertEquals("type", card.barcodeType);
assertEquals(0, card.starStatus);
assertEquals(1, (long) card.headerColor);
+
+ clearDatabase();
}
@Test
@@ -760,5 +774,7 @@ public class ImportExportTest
assertEquals("type", card.barcodeType);
assertEquals(0, card.starStatus);
assertEquals(1, (long) card.headerColor);
+
+ clearDatabase();
}
}
diff --git a/app/src/test/java/protect/card_locker/LoyaltyCardCursorAdapterTest.java b/app/src/test/java/protect/card_locker/LoyaltyCardCursorAdapterTest.java
index 2aee8e2a0..c0f6de264 100644
--- a/app/src/test/java/protect/card_locker/LoyaltyCardCursorAdapterTest.java
+++ b/app/src/test/java/protect/card_locker/LoyaltyCardCursorAdapterTest.java
@@ -4,7 +4,7 @@ import android.app.Activity;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.graphics.Color;
-import android.preference.PreferenceManager;
+import androidx.preference.PreferenceManager;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
@@ -93,6 +93,8 @@ public class LoyaltyCardCursorAdapterTest
View view = createView(cursor);
checkView(view, card.store, card.note, false);
+
+ cursor.close();
}
@Test
@@ -107,6 +109,8 @@ public class LoyaltyCardCursorAdapterTest
View view = createView(cursor);
checkView(view, card.store, card.note, false);
+
+ cursor.close();
}
@Test
@@ -125,6 +129,8 @@ public class LoyaltyCardCursorAdapterTest
setFontSizes(30, 31);
view = createView(cursor);
checkView(view, card.store, card.note, true);
+
+ cursor.close();
}
@Test
@@ -134,7 +140,6 @@ public class LoyaltyCardCursorAdapterTest
db.insertLoyaltyCard("storeB", "note", "cardId", BarcodeFormat.UPC_A.toString(), Color.BLACK, 1);
db.insertLoyaltyCard("storeC", "note", "cardId", BarcodeFormat.UPC_A.toString(), Color.BLACK, 1);
-
Cursor cursor = db.getLoyaltyCardCursor();
cursor.moveToFirst();
View view = createView(cursor);
@@ -150,5 +155,7 @@ public class LoyaltyCardCursorAdapterTest
view = createView(cursor);
star = view.findViewById(R.id.star);
assertEquals(View.GONE, star.getVisibility());
+
+ cursor.close();
}
}
diff --git a/app/src/test/java/protect/card_locker/LoyaltyCardViewActivityTest.java b/app/src/test/java/protect/card_locker/LoyaltyCardViewActivityTest.java
index 232ffde41..92c9dd413 100644
--- a/app/src/test/java/protect/card_locker/LoyaltyCardViewActivityTest.java
+++ b/app/src/test/java/protect/card_locker/LoyaltyCardViewActivityTest.java
@@ -17,7 +17,7 @@ import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.net.Uri;
import android.os.Bundle;
-import android.preference.PreferenceManager;
+import androidx.preference.PreferenceManager;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
@@ -139,6 +139,8 @@ public class LoyaltyCardViewActivityTest
}
assertNotNull(card.headerColor);
assertNotNull(card.headerTextColor);
+
+ db.close();
}
/**
@@ -287,6 +289,8 @@ public class LoyaltyCardViewActivityTest
noteField.setText("note");
activity.findViewById(R.id.fabSave).performClick();
assertEquals(0, db.getLoyaltyCardCount());
+
+ db.close();
}
@Test
@@ -416,6 +420,8 @@ public class LoyaltyCardViewActivityTest
activityController.resume();
checkAllFields(activity, ViewMode.UPDATE_CARD, "store", "note", BARCODE_DATA, BARCODE_TYPE);
+
+ db.close();
}
@Test
@@ -432,6 +438,8 @@ public class LoyaltyCardViewActivityTest
activityController.resume();
checkAllFields(activity, ViewMode.VIEW_CARD, "store", "note", BARCODE_DATA, BARCODE_TYPE);
+
+ db.close();
}
@Test
@@ -453,6 +461,8 @@ public class LoyaltyCardViewActivityTest
captureBarcodeWithResult(activity, true);
checkAllFields(activity, ViewMode.UPDATE_CARD, "store", "note", BARCODE_DATA, BARCODE_TYPE);
+
+ db.close();
}
@Test
@@ -488,6 +498,8 @@ public class LoyaltyCardViewActivityTest
shadowOf(activity).clickMenuItem(android.R.id.home);
assertEquals(false, activity.hasChanged);
assertEquals(true, activity.isFinishing());
+
+ db.close();
}
@Test
@@ -512,6 +524,8 @@ public class LoyaltyCardViewActivityTest
assertEquals("Block Rotation", menu.findItem(R.id.action_lock_unlock).getTitle().toString());
assertEquals("Share", menu.findItem(R.id.action_share).getTitle().toString());
assertEquals("Add to favorites", menu.findItem(R.id.action_star_unstar).getTitle().toString());
+
+ db.close();
}
@Test
@@ -550,6 +564,8 @@ public class LoyaltyCardViewActivityTest
assertEquals(false, activity.isFinishing());
shadowOf(activity).clickMenuItem(android.R.id.home);
assertEquals(true, activity.isFinishing());
+
+ db.close();
}
@Test
@@ -568,6 +584,8 @@ public class LoyaltyCardViewActivityTest
assertEquals(false, activity.isFinishing());
shadowOf(activity).clickMenuItem(android.R.id.home);
assertEquals(true, activity.isFinishing());
+
+ db.close();
}
@Test
@@ -585,6 +603,8 @@ public class LoyaltyCardViewActivityTest
// Save and check the loyalty card
saveLoyaltyCardWithArguments(activity, "store", "note", BARCODE_DATA, BARCODE_TYPE, false);
+
+ db.close();
}
@Test
@@ -602,6 +622,8 @@ public class LoyaltyCardViewActivityTest
// Save and check the loyalty card
saveLoyaltyCardWithArguments(activity, "store", "note", BARCODE_DATA, activity.getApplicationContext().getString(R.string.noBarcode), false);
+
+ db.close();
}
@Test
@@ -629,6 +651,8 @@ public class LoyaltyCardViewActivityTest
// Check if the special NO_BARCODE string doesn't get saved
saveLoyaltyCardWithArguments(activity, "store", "note", BARCODE_DATA, activity.getApplicationContext().getString(R.string.noBarcode), false);
+
+ db.close();
}
@Test
@@ -665,6 +689,8 @@ public class LoyaltyCardViewActivityTest
shadowOf(activity).clickMenuItem(android.R.id.home);
assertEquals(true, activity.isFinishing());
+
+ db.close();
}
@Test
@@ -701,6 +727,8 @@ public class LoyaltyCardViewActivityTest
String title = item.getTitle().toString();
assertEquals(title, activity.getString(R.string.lockScreen));
}
+
+ db.close();
}
}
@@ -731,6 +759,8 @@ public class LoyaltyCardViewActivityTest
shadowOf(activity).clickMenuItem(R.id.action_star_unstar);
assertEquals("Add to favorites", menu.findItem(R.id.action_star_unstar).getTitle().toString());
+
+ db.close();
}
@Test
@@ -794,6 +824,8 @@ public class LoyaltyCardViewActivityTest
// Pressing back when not in full screen should finish activity
activity.onBackPressed();
assertEquals(true, activity.isFinishing());
+
+ db.close();
}
@Test
diff --git a/app/src/test/java/protect/card_locker/MainActivityTest.java b/app/src/test/java/protect/card_locker/MainActivityTest.java
index ba57759d5..05cb3b229 100644
--- a/app/src/test/java/protect/card_locker/MainActivityTest.java
+++ b/app/src/test/java/protect/card_locker/MainActivityTest.java
@@ -111,6 +111,8 @@ public class MainActivityTest
assertEquals(1, list.getAdapter().getCount());
Cursor cursor = (Cursor)list.getAdapter().getItem(0);
assertNotNull(cursor);
+
+ db.close();
}
@Test
@@ -161,6 +163,8 @@ public class MainActivityTest
cursor = (Cursor)list.getAdapter().getItem(3);
assertNotNull(cursor);
assertEquals("storeB",cursor.getString(cursor.getColumnIndex("store")));
+
+ db.close();
}
@Test
@@ -209,6 +213,8 @@ public class MainActivityTest
activityController.pause();
activityController.resume();
assertEquals(0, groupTabs.getTabCount());
+
+ db.close();
}
@Test
@@ -434,5 +440,7 @@ public class MainActivityTest
assertEquals(View.VISIBLE, list.getVisibility());
assertEquals(2, list.getCount());
+
+ db.close();
}
}
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index e95b2f8d5..90a00d30e 100644
--- a/build.gradle
+++ b/build.gradle
@@ -2,13 +2,15 @@
buildscript {
repositories {
- jcenter()
-
- // For the Android Gradle plugin
google()
+ jcenter()
+ maven { url "https://jitpack.io" }
+ maven { url "https://plugins.gradle.org/m2/" }
}
+
dependencies {
- classpath 'com.android.tools.build:gradle:3.2.0'
+ classpath 'com.android.tools.build:gradle:4.1.1'
+ classpath 'gradle.plugin.com.github.spotbugs.snom:spotbugs-gradle-plugin:4.6.0'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
@@ -17,9 +19,10 @@ buildscript {
allprojects {
repositories {
- jcenter()
- maven { url 'https://jitpack.io' }
google()
+ jcenter()
+ maven { url "https://jitpack.io" }
+ maven { url "https://plugins.gradle.org/m2/" }
}
}
diff --git a/gradle.properties b/gradle.properties
index a74d1fa9b..acf164f6c 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -16,11 +16,5 @@
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
-
-# The aapt2 tool creates an APK which fails to install on Android 5 and below if it contains
-# a bug. Build tools 27.0.1 has a mitigation. Avoiding aapt2 also avoids hitting the bug.
-# See: https://issuetracker.google.com/issues/64434571
-android.enableAapt2=false
android.enableJetifier=true
android.useAndroidX=true
-android.enableUnitTestBinaryResources=true
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
index 05ef575b0..e708b1c02 100644
Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 9013ee43f..1f3fdbc52 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,5 @@
-#Sun Jul 19 15:12:56 CEST 2020
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-all.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-4.8.1-all.zip
diff --git a/gradlew b/gradlew
index 9d82f7891..4f906e0c8 100755
--- a/gradlew
+++ b/gradlew
@@ -1,4 +1,20 @@
-#!/usr/bin/env bash
+#!/usr/bin/env sh
+
+#
+# Copyright 2015 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
##############################################################################
##
@@ -6,42 +22,6 @@
##
##############################################################################
-# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-DEFAULT_JVM_OPTS=""
-
-APP_NAME="Gradle"
-APP_BASE_NAME=`basename "$0"`
-
-# Use the maximum available, or set MAX_FD != -1 to use that value.
-MAX_FD="maximum"
-
-warn ( ) {
- echo "$*"
-}
-
-die ( ) {
- echo
- echo "$*"
- echo
- exit 1
-}
-
-# OS specific support (must be 'true' or 'false').
-cygwin=false
-msys=false
-darwin=false
-case "`uname`" in
- CYGWIN* )
- cygwin=true
- ;;
- Darwin* )
- darwin=true
- ;;
- MINGW* )
- msys=true
- ;;
-esac
-
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
@@ -60,8 +40,49 @@ cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
@@ -85,7 +106,7 @@ location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
-if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
@@ -105,10 +126,11 @@ if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
-# For Cygwin, switch paths to Windows format before running java
-if $cygwin ; then
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
@@ -134,27 +156,30 @@ if $cygwin ; then
else
eval `echo args$i`="\"$arg\""
fi
- i=$((i+1))
+ i=`expr $i + 1`
done
case $i in
- (0) set -- ;;
- (1) set -- "$args0" ;;
- (2) set -- "$args0" "$args1" ;;
- (3) set -- "$args0" "$args1" "$args2" ;;
- (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
- (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
- (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
- (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
- (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
- (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ 0) set -- ;;
+ 1) set -- "$args0" ;;
+ 2) set -- "$args0" "$args1" ;;
+ 3) set -- "$args0" "$args1" "$args2" ;;
+ 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
-# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
-function splitJvmOpts() {
- JVM_OPTS=("$@")
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
}
-eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
-JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+APP_ARGS=`save "$@"`
-exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+exec "$JAVACMD" "$@"
diff --git a/gradlew.bat b/gradlew.bat
index aec99730b..ac1b06f93 100644
--- a/gradlew.bat
+++ b/gradlew.bat
@@ -1,3 +1,19 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@@ -8,20 +24,23 @@
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
-@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-set DEFAULT_JVM_OPTS=
-
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
-if "%ERRORLEVEL%" == "0" goto init
+if "%ERRORLEVEL%" == "0" goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@@ -35,7 +54,7 @@ goto fail
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
-if exist "%JAVA_EXE%" goto init
+if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
@@ -45,34 +64,14 @@ echo location of your Java installation.
goto fail
-:init
-@rem Get command-line arguments, handling Windowz variants
-
-if not "%OS%" == "Windows_NT" goto win9xME_args
-if "%@eval[2+2]" == "4" goto 4NT_args
-
-:win9xME_args
-@rem Slurp the command line arguments.
-set CMD_LINE_ARGS=
-set _SKIP=2
-
-:win9xME_args_slurp
-if "x%~1" == "x" goto execute
-
-set CMD_LINE_ARGS=%*
-goto execute
-
-:4NT_args
-@rem Get arguments from the 4NT Shell from JP Software
-set CMD_LINE_ARGS=%$
-
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell