diff --git a/CHANGELOG.md b/CHANGELOG.md index 667594ba7..9f0ec9b4a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,26 @@ +## v0.26.1 (2020-01-09) + +Changes: +- Fix issue with sharing cards without background color ([#343](https://github.com/brarcher/loyalty-card-locker/pull/343)) + +## v0.26 (2020-01-05) + +Changes: +- Add ability to search for a card ([#320](https://github.com/brarcher/loyalty-card-locker/pull/320)) +- Add ability to share and receive loyalty cards ([#321](https://github.com/brarcher/loyalty-card-locker/pull/321)) +- Dark mode support ([#322](https://github.com/brarcher/loyalty-card-locker/pull/322)) +- Loyalty cards can now be barcodeless (e.g. not have a barcode) ([#324](https://github.com/brarcher/loyalty-card-locker/pull/324)) +- Notes can span multiple lines ([#326](https://github.com/brarcher/loyalty-card-locker/pull/326)) +- Improvements with the sizing of notes ([#319](https://github.com/brarcher/loyalty-card-locker/pull/319)) +- Improve notification and app icon visibility ([#330](https://github.com/brarcher/loyalty-card-locker/pull/330)) +- Update target SDK to Android 10 +- Improve the following translations: + * German + * Italian + * Dutch + * Polish + * Russian + ## v0.25.4 (2019-10-04) Changes diff --git a/app/build.gradle b/app/build.gradle index 5c5b3621a..650f3a706 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -7,14 +7,14 @@ findbugs { } android { - compileSdkVersion 27 + compileSdkVersion 29 defaultConfig { applicationId "protect.card_locker" minSdkVersion 16 - targetSdkVersion 27 - versionCode 35 - versionName "0.25.4" + targetSdkVersion 29 + versionCode 37 + versionName "0.26.1" } buildTypes { release { @@ -41,19 +41,19 @@ android { dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) - compile 'com.android.support:appcompat-v7:27.0.2' - compile 'com.android.support:design:27.0.2' - compile 'com.android.support:support-v4:27.0.2' + compile 'androidx.appcompat:appcompat:1.2.0-alpha01' + compile 'com.google.android.material:material:1.2.0-alpha03' + compile 'androidx.legacy:legacy-support-v4:1.0.0' compile 'com.journeyapps:zxing-android-embedded:3.5.0@aar' compile 'com.google.zxing:core:3.3.0' compile 'org.apache.commons:commons-csv:1.5' - compile 'com.android.support.constraint:constraint-layout:1.0.2' + compile 'androidx.constraintlayout:constraintlayout:1.1.3' compile 'com.jaredrummler:colorpicker:1.0.2' compile group: 'com.google.guava', name: 'guava', version: '20.0' compile 'com.github.apl-devs:appintro:v4.2.0' compile "com.vanniktech:vntnumberpickerpreference:1.0.0" testCompile 'junit:junit:4.12' - testCompile "org.robolectric:robolectric:3.3.2" + testCompile "org.robolectric:robolectric:4.0.2" } task findbugs(type: FindBugs, dependsOn: 'assembleDebug') { diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 7a0e0be6a..d5d7644e0 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -86,7 +86,7 @@ diff --git a/app/src/main/java/protect/card_locker/BarcodeImageWriterTask.java b/app/src/main/java/protect/card_locker/BarcodeImageWriterTask.java index a03a52994..9ef6b7115 100644 --- a/app/src/main/java/protect/card_locker/BarcodeImageWriterTask.java +++ b/app/src/main/java/protect/card_locker/BarcodeImageWriterTask.java @@ -90,6 +90,11 @@ class BarcodeImageWriterTask extends AsyncTask public Bitmap doInBackground(Void... params) { + if (cardId.isEmpty()) + { + return null; + } + MultiFormatWriter writer = new MultiFormatWriter(); BitMatrix bitMatrix; try diff --git a/app/src/main/java/protect/card_locker/BarcodeSelectorActivity.java b/app/src/main/java/protect/card_locker/BarcodeSelectorActivity.java index 47552ef36..18becdcc6 100644 --- a/app/src/main/java/protect/card_locker/BarcodeSelectorActivity.java +++ b/app/src/main/java/protect/card_locker/BarcodeSelectorActivity.java @@ -5,9 +5,9 @@ import android.content.Intent; import android.os.AsyncTask; import android.os.Build; import android.os.Bundle; -import android.support.v7.app.ActionBar; -import android.support.v7.app.AppCompatActivity; -import android.support.v7.widget.Toolbar; +import androidx.appcompat.app.ActionBar; +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.widget.Toolbar; import android.text.Editable; import android.text.TextWatcher; import android.util.Log; @@ -116,6 +116,10 @@ public class BarcodeSelectorActivity extends AppCompatActivity ImageView image = findViewById(barcodeViewMap.get(key)); createBarcodeOption(image, key, s.toString()); } + + View noBarcodeButtonView = findViewById(R.id.noBarcode); + setButtonListener(noBarcodeButtonView, s.toString()); + noBarcodeButtonView.setEnabled(s.length() > 0); } @Override @@ -134,6 +138,21 @@ public class BarcodeSelectorActivity extends AppCompatActivity } } + private void setButtonListener(final View button, final String cardId) + { + button.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Log.d(TAG, "Selected no barcode"); + Intent result = new Intent(); + result.putExtra(BARCODE_FORMAT, ""); + result.putExtra(BARCODE_CONTENTS, cardId); + BarcodeSelectorActivity.this.setResult(RESULT_OK, result); + finish(); + } + }); + } + private void createBarcodeOption(final ImageView image, final String formatType, final String cardId) { final BarcodeFormat format = BarcodeFormat.valueOf(formatType); diff --git a/app/src/main/java/protect/card_locker/CardShortcutConfigure.java b/app/src/main/java/protect/card_locker/CardShortcutConfigure.java index 3e2c8f639..2917d703d 100644 --- a/app/src/main/java/protect/card_locker/CardShortcutConfigure.java +++ b/app/src/main/java/protect/card_locker/CardShortcutConfigure.java @@ -4,8 +4,8 @@ import android.content.Intent; import android.database.Cursor; import android.os.Bundle; import android.os.Parcelable; -import android.support.v7.app.AppCompatActivity; -import android.support.v7.widget.Toolbar; +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.widget.Toolbar; import android.util.Log; import android.view.View; import android.widget.AdapterView; diff --git a/app/src/main/java/protect/card_locker/CsvDatabaseImporter.java b/app/src/main/java/protect/card_locker/CsvDatabaseImporter.java index 084aa634e..7aa27fe5e 100644 --- a/app/src/main/java/protect/card_locker/CsvDatabaseImporter.java +++ b/app/src/main/java/protect/card_locker/CsvDatabaseImporter.java @@ -131,10 +131,6 @@ public class CsvDatabaseImporter implements DatabaseImporter } String barcodeType = extractString(DBHelper.LoyaltyCardDbIds.BARCODE_TYPE, record, ""); - if(barcodeType.isEmpty()) - { - throw new FormatException("No barcode type listed, but is required"); - } Integer headerColor = null; Integer headerTextColor = null; diff --git a/app/src/main/java/protect/card_locker/ImportExportActivity.java b/app/src/main/java/protect/card_locker/ImportExportActivity.java index e0be204cc..bbd4eba9a 100644 --- a/app/src/main/java/protect/card_locker/ImportExportActivity.java +++ b/app/src/main/java/protect/card_locker/ImportExportActivity.java @@ -7,19 +7,18 @@ import android.content.DialogInterface; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; -import android.database.Cursor; import android.net.Uri; import android.os.AsyncTask; import android.os.Bundle; import android.os.Environment; -import android.provider.OpenableColumns; -import android.support.v4.app.ActivityCompat; -import android.support.v4.content.ContextCompat; -import android.support.v4.content.FileProvider; -import android.support.v7.app.ActionBar; -import android.support.v7.app.AlertDialog; -import android.support.v7.app.AppCompatActivity; -import android.support.v7.widget.Toolbar; + +import androidx.core.app.ActivityCompat; +import androidx.core.content.ContextCompat; +import androidx.core.content.FileProvider; +import androidx.appcompat.app.ActionBar; +import androidx.appcompat.app.AlertDialog; +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.widget.Toolbar; import android.util.Log; import android.view.MenuItem; import android.view.View; @@ -82,36 +81,14 @@ public class ImportExportActivity extends AppCompatActivity } }); - - // Check that there is an activity that can bring up a file chooser - final Intent intentPickAction = new Intent(Intent.ACTION_PICK); - - Button importFilesystem = findViewById(R.id.importOptionFilesystemButton); - importFilesystem.setOnClickListener(new View.OnClickListener() - { - @Override - public void onClick(View v) - { - chooseFileWithIntent(intentPickAction); - } - }); - - if(isCallable(getApplicationContext(), intentPickAction) == false) - { - findViewById(R.id.dividerImportFilesystem).setVisibility(View.GONE); - findViewById(R.id.importOptionFilesystemTitle).setVisibility(View.GONE); - findViewById(R.id.importOptionFilesystemExplanation).setVisibility(View.GONE); - importFilesystem.setVisibility(View.GONE); - } - - - // Check that there is an application that can find content + // Check that there is a file manager available final Intent intentGetContentAction = new Intent(Intent.ACTION_GET_CONTENT); intentGetContentAction.addCategory(Intent.CATEGORY_OPENABLE); intentGetContentAction.setType("*/*"); - Button importApplication = findViewById(R.id.importOptionApplicationButton); - importApplication.setOnClickListener(new View.OnClickListener() + + Button importFilesystem = findViewById(R.id.importOptionFilesystemButton); + importFilesystem.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) @@ -121,6 +98,27 @@ public class ImportExportActivity extends AppCompatActivity }); if(isCallable(getApplicationContext(), intentGetContentAction) == false) + { + findViewById(R.id.dividerImportFilesystem).setVisibility(View.GONE); + findViewById(R.id.importOptionFilesystemTitle).setVisibility(View.GONE); + findViewById(R.id.importOptionFilesystemExplanation).setVisibility(View.GONE); + importFilesystem.setVisibility(View.GONE); + } + + // Check that there is an app that data can be imported from + final Intent intentPickAction = new Intent(Intent.ACTION_PICK); + + Button importApplication = findViewById(R.id.importOptionApplicationButton); + importApplication.setOnClickListener(new View.OnClickListener() + { + @Override + public void onClick(View v) + { + chooseFileWithIntent(intentPickAction); + } + }); + + if(isCallable(getApplicationContext(), intentPickAction) == false) { findViewById(R.id.dividerImportApplication).setVisibility(View.GONE); findViewById(R.id.importOptionApplicationTitle).setVisibility(View.GONE); @@ -128,7 +126,6 @@ public class ImportExportActivity extends AppCompatActivity importApplication.setVisibility(View.GONE); } - // This option, to import from the fixed location, should always be present Button importButton = findViewById(R.id.importOptionFixedButton); diff --git a/app/src/main/java/protect/card_locker/ImportURIHelper.java b/app/src/main/java/protect/card_locker/ImportURIHelper.java index d3133bcb3..5aeeb0cec 100644 --- a/app/src/main/java/protect/card_locker/ImportURIHelper.java +++ b/app/src/main/java/protect/card_locker/ImportURIHelper.java @@ -35,12 +35,24 @@ public class ImportURIHelper { } try { + // These values are allowed to be null + Integer headerColor = null; + Integer headerTextColor = null; + String store = uri.getQueryParameter(STORE); String note = uri.getQueryParameter(NOTE); String cardId = uri.getQueryParameter(CARD_ID); String barcodeType = uri.getQueryParameter(BARCODE_TYPE); - Integer headerColor = Integer.parseInt(uri.getQueryParameter(HEADER_COLOR)); - Integer headerTextColor = Integer.parseInt(uri.getQueryParameter(HEADER_TEXT_COLOR)); + String unparsedHeaderColor = uri.getQueryParameter(HEADER_COLOR); + if(unparsedHeaderColor != null) + { + headerColor = Integer.parseInt(unparsedHeaderColor); + } + String unparsedHeaderTextColor = uri.getQueryParameter(HEADER_TEXT_COLOR); + if(unparsedHeaderTextColor != null) + { + headerTextColor = Integer.parseInt(unparsedHeaderTextColor); + } return new LoyaltyCard(-1, store, note, cardId, barcodeType, headerColor, headerTextColor); } catch (NullPointerException | NumberFormatException ex) { throw new InvalidObjectException("Not a valid import URI"); @@ -57,8 +69,14 @@ public class ImportURIHelper { uriBuilder.appendQueryParameter(NOTE, loyaltyCard.note); uriBuilder.appendQueryParameter(CARD_ID, loyaltyCard.cardId); uriBuilder.appendQueryParameter(BARCODE_TYPE, loyaltyCard.barcodeType); - uriBuilder.appendQueryParameter(HEADER_COLOR, loyaltyCard.headerColor.toString()); - uriBuilder.appendQueryParameter(HEADER_TEXT_COLOR, loyaltyCard.headerTextColor.toString()); + if(loyaltyCard.headerColor != null) + { + uriBuilder.appendQueryParameter(HEADER_COLOR, loyaltyCard.headerColor.toString()); + } + if(loyaltyCard.headerTextColor != null) + { + uriBuilder.appendQueryParameter(HEADER_TEXT_COLOR, loyaltyCard.headerTextColor.toString()); + } return uriBuilder.build(); } diff --git a/app/src/main/java/protect/card_locker/LoyaltyCard.java b/app/src/main/java/protect/card_locker/LoyaltyCard.java index a1dac3a69..152d15d35 100644 --- a/app/src/main/java/protect/card_locker/LoyaltyCard.java +++ b/app/src/main/java/protect/card_locker/LoyaltyCard.java @@ -1,7 +1,7 @@ package protect.card_locker; import android.database.Cursor; -import android.support.annotation.Nullable; +import androidx.annotation.Nullable; public class LoyaltyCard { diff --git a/app/src/main/java/protect/card_locker/LoyaltyCardEditActivity.java b/app/src/main/java/protect/card_locker/LoyaltyCardEditActivity.java index 0d115c4a8..3a45918c4 100644 --- a/app/src/main/java/protect/card_locker/LoyaltyCardEditActivity.java +++ b/app/src/main/java/protect/card_locker/LoyaltyCardEditActivity.java @@ -8,11 +8,11 @@ import android.graphics.Color; import android.net.Uri; import android.os.Build; import android.os.Bundle; -import android.support.design.widget.Snackbar; -import android.support.v7.app.ActionBar; -import android.support.v7.app.AlertDialog; -import android.support.v7.app.AppCompatActivity; -import android.support.v7.widget.Toolbar; +import com.google.android.material.snackbar.Snackbar; +import androidx.appcompat.app.ActionBar; +import androidx.appcompat.app.AlertDialog; +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.widget.Toolbar; import android.util.Log; import android.view.Menu; import android.view.MenuItem; @@ -35,8 +35,9 @@ import java.io.InvalidObjectException; public class LoyaltyCardEditActivity extends AppCompatActivity { private static final String TAG = "CardLocker"; + protected static final String NO_BARCODE = "_NO_BARCODE_"; - private static final int SELECT_BARCODE_REQUEST = 1; + protected static final int SELECT_BARCODE_REQUEST = 1; EditText storeFieldEdit; EditText noteFieldEdit; @@ -115,6 +116,8 @@ public class LoyaltyCardEditActivity extends AppCompatActivity @Override public void onNewIntent(Intent intent) { + super.onNewIntent(intent); + Log.i(TAG, "Received new intent"); extractIntentFields(intent); @@ -227,42 +230,49 @@ public class LoyaltyCardEditActivity extends AppCompatActivity if(cardIdFieldView.getText().length() > 0 && barcodeTypeField.getText().length() > 0) { - String formatString = barcodeTypeField.getText().toString(); - final BarcodeFormat format = BarcodeFormat.valueOf(formatString); - final String cardIdString = cardIdFieldView.getText().toString(); - - if(barcodeImage.getHeight() == 0) + if(barcodeTypeField.getText().equals(NO_BARCODE)) { - Log.d(TAG, "ImageView size is not known known at start, waiting for load"); - // The size of the ImageView is not yet available as it has not - // yet been drawn. Wait for it to be drawn so the size is available. - barcodeImage.getViewTreeObserver().addOnGlobalLayoutListener( - new ViewTreeObserver.OnGlobalLayoutListener() - { - @Override - public void onGlobalLayout() - { - if (Build.VERSION.SDK_INT < 16) - { - barcodeImage.getViewTreeObserver().removeGlobalOnLayoutListener(this); - } - else - { - barcodeImage.getViewTreeObserver().removeOnGlobalLayoutListener(this); - } - - Log.d(TAG, "ImageView size now known"); - new BarcodeImageWriterTask(barcodeImage, cardIdString, format).execute(); - } - }); + barcodeImageLayout.setVisibility(View.GONE); } else { - Log.d(TAG, "ImageView size known known, creating barcode"); - new BarcodeImageWriterTask(barcodeImage, cardIdString, format).execute(); - } + String formatString = barcodeTypeField.getText().toString(); + final BarcodeFormat format = BarcodeFormat.valueOf(formatString); + final String cardIdString = cardIdFieldView.getText().toString(); - barcodeImageLayout.setVisibility(View.VISIBLE); + if(barcodeImage.getHeight() == 0) + { + Log.d(TAG, "ImageView size is not known known at start, waiting for load"); + // The size of the ImageView is not yet available as it has not + // yet been drawn. Wait for it to be drawn so the size is available. + barcodeImage.getViewTreeObserver().addOnGlobalLayoutListener( + new ViewTreeObserver.OnGlobalLayoutListener() + { + @Override + public void onGlobalLayout() + { + if (Build.VERSION.SDK_INT < 16) + { + barcodeImage.getViewTreeObserver().removeGlobalOnLayoutListener(this); + } + else + { + barcodeImage.getViewTreeObserver().removeOnGlobalLayoutListener(this); + } + + Log.d(TAG, "ImageView size now known"); + new BarcodeImageWriterTask(barcodeImage, cardIdString, format).execute(); + } + }); + } + else + { + Log.d(TAG, "ImageView size known known, creating barcode"); + new BarcodeImageWriterTask(barcodeImage, cardIdString, format).execute(); + } + + barcodeImageLayout.setVisibility(View.VISIBLE); + } } View.OnClickListener captureCallback = new View.OnClickListener() @@ -364,13 +374,20 @@ public class LoyaltyCardEditActivity extends AppCompatActivity String cardId = cardIdFieldView.getText().toString(); String barcodeType = barcodeTypeField.getText().toString(); + // We do not want to save the no barcode string to the database + // it is simply an empty there for no barcode + if(barcodeType.equals(NO_BARCODE)) + { + barcodeType = ""; + } + if(store.isEmpty()) { Snackbar.make(storeFieldEdit, R.string.noStoreError, Snackbar.LENGTH_LONG).show(); return; } - if(cardId.isEmpty() || barcodeType.isEmpty()) + if(cardId.isEmpty()) { Snackbar.make(cardIdFieldView, R.string.noCardIdError, Snackbar.LENGTH_LONG).show(); return; @@ -459,6 +476,8 @@ public class LoyaltyCardEditActivity extends AppCompatActivity @Override public void onActivityResult(int requestCode, int resultCode, Intent intent) { + super.onActivityResult(requestCode, resultCode, intent); + String contents = null; String format = null; @@ -480,7 +499,7 @@ public class LoyaltyCardEditActivity extends AppCompatActivity } if(contents != null && contents.isEmpty() == false && - format != null && format.isEmpty() == false) + format != null) { Log.i(TAG, "Read barcode id: " + contents); Log.i(TAG, "Read format: " + format); @@ -489,7 +508,8 @@ public class LoyaltyCardEditActivity extends AppCompatActivity cardIdView.setText(contents); final TextView barcodeTypeField = findViewById(R.id.barcodeType); - barcodeTypeField.setText(format); + // Set special NO_BARCODE value to prevent onResume from overwriting it + barcodeTypeField.setText(format.isEmpty() ? LoyaltyCardEditActivity.NO_BARCODE : format); onResume(); } } diff --git a/app/src/main/java/protect/card_locker/LoyaltyCardLockerApplication.java b/app/src/main/java/protect/card_locker/LoyaltyCardLockerApplication.java index c53584520..0705435fc 100644 --- a/app/src/main/java/protect/card_locker/LoyaltyCardLockerApplication.java +++ b/app/src/main/java/protect/card_locker/LoyaltyCardLockerApplication.java @@ -1,7 +1,7 @@ package protect.card_locker; import android.app.Application; -import android.support.v7.app.AppCompatDelegate; +import androidx.appcompat.app.AppCompatDelegate; import protect.card_locker.preferences.Settings; diff --git a/app/src/main/java/protect/card_locker/LoyaltyCardViewActivity.java b/app/src/main/java/protect/card_locker/LoyaltyCardViewActivity.java index d3db308e3..f91014d68 100644 --- a/app/src/main/java/protect/card_locker/LoyaltyCardViewActivity.java +++ b/app/src/main/java/protect/card_locker/LoyaltyCardViewActivity.java @@ -4,17 +4,24 @@ package protect.card_locker; import android.content.Intent; import android.content.pm.ActivityInfo; import android.graphics.Color; +import android.graphics.drawable.Drawable; import android.os.Build; import android.os.Bundle; -import android.support.v4.widget.TextViewCompat; -import android.support.v7.app.ActionBar; -import android.support.v7.app.AppCompatActivity; -import android.support.v7.widget.Toolbar; + +import androidx.constraintlayout.widget.ConstraintLayout; +import androidx.core.graphics.ColorUtils; +import androidx.core.graphics.drawable.DrawableCompat; +import androidx.core.widget.TextViewCompat; +import androidx.appcompat.app.ActionBar; +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.content.res.AppCompatResources; +import androidx.appcompat.widget.Toolbar; import android.util.Log; import android.util.TypedValue; import android.view.Menu; import android.view.MenuItem; import android.view.View; +import android.view.ViewGroup; import android.view.ViewTreeObserver; import android.view.Window; import android.view.WindowManager; @@ -30,6 +37,7 @@ import protect.card_locker.preferences.Settings; public class LoyaltyCardViewActivity extends AppCompatActivity { private static final String TAG = "CardLocker"; + private static final double LUMINANCE_MIDPOINT = 0.5; TextView cardIdFieldView; TextView noteView; @@ -44,6 +52,13 @@ public class LoyaltyCardViewActivity extends AppCompatActivity ImportURIHelper importURIHelper; Settings settings; + String cardIdString; + BarcodeFormat format; + + boolean backgroundNeedsDarkIcons; + boolean barcodeIsFullscreen = false; + ViewGroup.LayoutParams barcodeImageState; + private void extractIntentFields(Intent intent) { final Bundle b = intent.getExtras(); @@ -51,6 +66,22 @@ public class LoyaltyCardViewActivity extends AppCompatActivity Log.d(TAG, "View activity: id=" + loyaltyCardId); } + private Drawable getIcon(int icon, boolean dark) + { + Drawable unwrappedIcon = AppCompatResources.getDrawable(this, icon); + Drawable wrappedIcon = DrawableCompat.wrap(unwrappedIcon); + if(dark) + { + DrawableCompat.setTint(wrappedIcon, Color.BLACK); + } + else + { + DrawableCompat.setTintList(wrappedIcon, null); + } + + return wrappedIcon; + } + @Override protected void onCreate(Bundle savedInstanceState) { @@ -81,11 +112,28 @@ public class LoyaltyCardViewActivity extends AppCompatActivity collapsingToolbarLayout = findViewById(R.id.collapsingToolbarLayout); rotationEnabled = true; + + // Allow making barcode fullscreen on tap + barcodeImage.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + if(barcodeIsFullscreen) + { + setFullscreen(false); + } + else + { + setFullscreen(true); + } + } + }); } @Override public void onNewIntent(Intent intent) { + super.onNewIntent(intent); + Log.i(TAG, "Received new intent"); extractIntentFields(intent); } @@ -97,6 +145,15 @@ public class LoyaltyCardViewActivity extends AppCompatActivity Log.i(TAG, "To view card: " + loyaltyCardId); + if(barcodeIsFullscreen) + { + // Completely reset state + // + // This prevents the barcode from taking up the entire screen + // on resume and thus being stretched out of proportion. + recreate(); + } + // The brightness value is on a scale from [0, ..., 1], where // '1' is the brightest. We attempt to maximize the brightness // to help barcode readers scan the barcode. @@ -118,8 +175,8 @@ public class LoyaltyCardViewActivity extends AppCompatActivity } String formatString = loyaltyCard.barcodeType; - final BarcodeFormat format = BarcodeFormat.valueOf(formatString); - final String cardIdString = loyaltyCard.cardId; + format = !formatString.isEmpty() ? BarcodeFormat.valueOf(formatString) : null; + cardIdString = loyaltyCard.cardId; cardIdFieldView.setText(loyaltyCard.cardId); TextViewCompat.setAutoSizeTextTypeUniformWithConfiguration(cardIdFieldView, @@ -165,37 +222,70 @@ public class LoyaltyCardViewActivity extends AppCompatActivity collapsingToolbarLayout.setBackgroundColor(backgroundHeaderColor); - if(barcodeImage.getHeight() == 0) + // If the background is very bright, we should use dark icons + backgroundNeedsDarkIcons = (ColorUtils.calculateLuminance(backgroundHeaderColor) > LUMINANCE_MIDPOINT); + ActionBar actionBar = getSupportActionBar(); + if(actionBar != null) { - Log.d(TAG, "ImageView size is not known known at start, waiting for load"); - // The size of the ImageView is not yet available as it has not - // yet been drawn. Wait for it to be drawn so the size is available. - barcodeImage.getViewTreeObserver().addOnGlobalLayoutListener( - new ViewTreeObserver.OnGlobalLayoutListener() - { - @Override - public void onGlobalLayout() + actionBar.setHomeAsUpIndicator(getIcon(R.drawable.ic_arrow_back_white, backgroundNeedsDarkIcons)); + } + + // Make notification area light if dark icons are needed + if(Build.VERSION.SDK_INT >= 23) + { + window.getDecorView().setSystemUiVisibility(backgroundNeedsDarkIcons ? View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR : 0); + } + if(Build.VERSION.SDK_INT >= 21) + { + window.setStatusBarColor(Color.TRANSPARENT); + } + + // Set shadow colour of store text so even same color on same color would be readable + storeName.setShadowLayer(1, 1, 1, backgroundNeedsDarkIcons ? Color.BLACK : Color.WHITE); + + if(format != null) + { + findViewById(R.id.barcode).setVisibility(View.VISIBLE); + if(barcodeImage.getHeight() == 0) + { + Log.d(TAG, "ImageView size is not known known at start, waiting for load"); + // The size of the ImageView is not yet available as it has not + // yet been drawn. Wait for it to be drawn so the size is available. + barcodeImage.getViewTreeObserver().addOnGlobalLayoutListener( + new ViewTreeObserver.OnGlobalLayoutListener() { - if (Build.VERSION.SDK_INT < 16) - { - barcodeImage.getViewTreeObserver().removeGlobalOnLayoutListener(this); - } - else + @Override + public void onGlobalLayout() { barcodeImage.getViewTreeObserver().removeOnGlobalLayoutListener(this); - } - Log.d(TAG, "ImageView size now known"); - new BarcodeImageWriterTask(barcodeImage, cardIdString, format).execute(); - } - }); + Log.d(TAG, "ImageView size now known"); + new BarcodeImageWriterTask(barcodeImage, cardIdString, format).execute(); + } + }); + } + else + { + Log.d(TAG, "ImageView size known known, creating barcode"); + new BarcodeImageWriterTask(barcodeImage, cardIdString, format).execute(); + } } else { - Log.d(TAG, "ImageView size known known, creating barcode"); - new BarcodeImageWriterTask(barcodeImage, cardIdString, format).execute(); + findViewById(R.id.barcode).setVisibility(View.GONE); + } + } + + @Override + public void onBackPressed() { + if (barcodeIsFullscreen) + { + setFullscreen(false); + return; } + super.onBackPressed(); + return; } @Override @@ -203,13 +293,18 @@ public class LoyaltyCardViewActivity extends AppCompatActivity { getMenuInflater().inflate(R.menu.card_view_menu, menu); - if(settings.getLockBarcodeScreenOrientation()) + // Always calculate lockscreen icon, it may need a black color + boolean lockBarcodeScreenOrientation = settings.getLockBarcodeScreenOrientation(); + MenuItem item = menu.findItem(R.id.action_lock_unlock); + setOrientatonLock(item, lockBarcodeScreenOrientation); + if(lockBarcodeScreenOrientation) { - MenuItem item = menu.findItem(R.id.action_lock_unlock); - setOrientatonLock(item, true); item.setVisible(false); } + menu.findItem(R.id.action_share).setIcon(getIcon(R.drawable.ic_share_white, backgroundNeedsDarkIcons)); + menu.findItem(R.id.action_edit).setIcon(getIcon(R.drawable.ic_mode_edit_white_24dp, backgroundNeedsDarkIcons)); + return super.onCreateOptionsMenu(menu); } @@ -258,15 +353,84 @@ public class LoyaltyCardViewActivity extends AppCompatActivity { if(lock) { - item.setIcon(R.drawable.ic_lock_outline_white_24dp); + + item.setIcon(getIcon(R.drawable.ic_lock_outline_white_24dp, backgroundNeedsDarkIcons)); item.setTitle(R.string.unlockScreen); setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR); } else { - item.setIcon(R.drawable.ic_lock_open_white_24dp); + item.setIcon(getIcon(R.drawable.ic_lock_open_white_24dp, backgroundNeedsDarkIcons)); item.setTitle(R.string.lockScreen); setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR); } } -} \ No newline at end of file + + /** + * When enabled, hides the status bar and moves the barcode to the top of the screen. + * + * The purpose of this function is to make sure the barcode can be scanned from the phone + * by machines which offer no space to insert the complete device. + */ + private void setFullscreen(boolean enable) + { + ActionBar actionBar = getSupportActionBar(); + if(enable && !barcodeIsFullscreen) + { + // Save previous barcodeImage state + barcodeImageState = barcodeImage.getLayoutParams(); + + // Hide actionbar + if(actionBar != null) + { + actionBar.hide(); + } + + // Hide collapsingToolbar + collapsingToolbarLayout.setVisibility(View.GONE); + + // Set Android to fullscreen mode + getWindow().getDecorView().setSystemUiVisibility( + getWindow().getDecorView().getSystemUiVisibility() + | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY + | View.SYSTEM_UI_FLAG_FULLSCREEN + ); + + // Make barcode take all space + barcodeImage.setLayoutParams(new ConstraintLayout.LayoutParams( + ConstraintLayout.LayoutParams.MATCH_PARENT, + ConstraintLayout.LayoutParams.MATCH_PARENT + )); + + // Move barcode to top + barcodeImage.setScaleType(ImageView.ScaleType.FIT_START); + + // Set current state + barcodeIsFullscreen = true; + } + else if(!enable && barcodeIsFullscreen) + { + // Show actionbar + if(actionBar != null) + { + actionBar.show(); + } + + // Show collapsingToolbar + collapsingToolbarLayout.setVisibility(View.VISIBLE); + + // Unset fullscreen mode + getWindow().getDecorView().setSystemUiVisibility( + getWindow().getDecorView().getSystemUiVisibility() + & ~View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY + & ~View.SYSTEM_UI_FLAG_FULLSCREEN + ); + + // Turn barcode back to normal + barcodeImage.setLayoutParams(barcodeImageState); + + // Set current state + barcodeIsFullscreen = false; + } + } +} diff --git a/app/src/main/java/protect/card_locker/MainActivity.java b/app/src/main/java/protect/card_locker/MainActivity.java index 68b736ca1..6488d84ee 100644 --- a/app/src/main/java/protect/card_locker/MainActivity.java +++ b/app/src/main/java/protect/card_locker/MainActivity.java @@ -11,13 +11,12 @@ import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.res.Configuration; import android.database.Cursor; -import android.net.Uri; import android.os.Bundle; -import android.support.v7.app.AlertDialog; -import android.support.v7.app.AppCompatActivity; -import android.support.v7.app.AppCompatDelegate; -import android.support.v7.widget.SearchView; -import android.support.v7.widget.Toolbar; +import androidx.appcompat.app.AlertDialog; +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.app.AppCompatDelegate; +import androidx.appcompat.widget.SearchView; +import androidx.appcompat.widget.Toolbar; import android.util.Log; import android.view.ContextMenu; import android.view.Menu; @@ -36,7 +35,6 @@ import java.util.Calendar; import java.util.Map; import protect.card_locker.intro.IntroActivity; -import protect.card_locker.preferences.Settings; import protect.card_locker.preferences.SettingsActivity; public class MainActivity extends AppCompatActivity @@ -82,6 +80,8 @@ public class MainActivity extends AppCompatActivity @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (requestCode == MAIN_REQUEST_CODE) { // We're coming back from another view so clear the search diff --git a/app/src/main/java/protect/card_locker/intro/IntroActivity.java b/app/src/main/java/protect/card_locker/intro/IntroActivity.java index d34b0b05d..37a699ed8 100644 --- a/app/src/main/java/protect/card_locker/intro/IntroActivity.java +++ b/app/src/main/java/protect/card_locker/intro/IntroActivity.java @@ -1,7 +1,7 @@ package protect.card_locker.intro; import android.os.Bundle; -import android.support.v4.app.Fragment; +import androidx.fragment.app.Fragment; import com.github.paolorotolo.appintro.AppIntro; diff --git a/app/src/main/java/protect/card_locker/intro/IntroSlide1.java b/app/src/main/java/protect/card_locker/intro/IntroSlide1.java index 7e53d7652..beecb43c3 100644 --- a/app/src/main/java/protect/card_locker/intro/IntroSlide1.java +++ b/app/src/main/java/protect/card_locker/intro/IntroSlide1.java @@ -1,7 +1,7 @@ package protect.card_locker.intro; import android.os.Bundle; -import android.support.v4.app.Fragment; +import androidx.fragment.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; diff --git a/app/src/main/java/protect/card_locker/intro/IntroSlide2.java b/app/src/main/java/protect/card_locker/intro/IntroSlide2.java index 6ee1952b7..a1e652c51 100644 --- a/app/src/main/java/protect/card_locker/intro/IntroSlide2.java +++ b/app/src/main/java/protect/card_locker/intro/IntroSlide2.java @@ -1,7 +1,7 @@ package protect.card_locker.intro; import android.os.Bundle; -import android.support.v4.app.Fragment; +import androidx.fragment.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; diff --git a/app/src/main/java/protect/card_locker/intro/IntroSlide3.java b/app/src/main/java/protect/card_locker/intro/IntroSlide3.java index deb6927b0..5acc83e7b 100644 --- a/app/src/main/java/protect/card_locker/intro/IntroSlide3.java +++ b/app/src/main/java/protect/card_locker/intro/IntroSlide3.java @@ -1,7 +1,7 @@ package protect.card_locker.intro; import android.os.Bundle; -import android.support.v4.app.Fragment; +import androidx.fragment.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; diff --git a/app/src/main/java/protect/card_locker/intro/IntroSlide4.java b/app/src/main/java/protect/card_locker/intro/IntroSlide4.java index d47a5ac8e..1a7ad6e69 100644 --- a/app/src/main/java/protect/card_locker/intro/IntroSlide4.java +++ b/app/src/main/java/protect/card_locker/intro/IntroSlide4.java @@ -1,7 +1,7 @@ package protect.card_locker.intro; import android.os.Bundle; -import android.support.v4.app.Fragment; +import androidx.fragment.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; diff --git a/app/src/main/java/protect/card_locker/intro/IntroSlide5.java b/app/src/main/java/protect/card_locker/intro/IntroSlide5.java index 6127ab1ba..ab3b5b757 100644 --- a/app/src/main/java/protect/card_locker/intro/IntroSlide5.java +++ b/app/src/main/java/protect/card_locker/intro/IntroSlide5.java @@ -1,7 +1,7 @@ package protect.card_locker.intro; import android.os.Bundle; -import android.support.v4.app.Fragment; +import androidx.fragment.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; diff --git a/app/src/main/java/protect/card_locker/intro/IntroSlide6.java b/app/src/main/java/protect/card_locker/intro/IntroSlide6.java index d3fba4f98..217967844 100644 --- a/app/src/main/java/protect/card_locker/intro/IntroSlide6.java +++ b/app/src/main/java/protect/card_locker/intro/IntroSlide6.java @@ -1,7 +1,7 @@ package protect.card_locker.intro; import android.os.Bundle; -import android.support.v4.app.Fragment; +import androidx.fragment.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; 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 f6c9fb026..586e18769 100644 --- a/app/src/main/java/protect/card_locker/preferences/Settings.java +++ b/app/src/main/java/protect/card_locker/preferences/Settings.java @@ -3,9 +3,9 @@ package protect.card_locker.preferences; import android.content.Context; import android.content.SharedPreferences; import android.preference.PreferenceManager; -import android.support.annotation.IntegerRes; -import android.support.annotation.StringRes; -import android.support.v7.app.AppCompatDelegate; +import androidx.annotation.IntegerRes; +import androidx.annotation.StringRes; +import androidx.appcompat.app.AppCompatDelegate; import protect.card_locker.R; 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 ee1bccbbb..485626742 100644 --- a/app/src/main/java/protect/card_locker/preferences/SettingsActivity.java +++ b/app/src/main/java/protect/card_locker/preferences/SettingsActivity.java @@ -3,9 +3,9 @@ package protect.card_locker.preferences; import android.os.Bundle; import android.preference.Preference; import android.preference.PreferenceFragment; -import android.support.v7.app.ActionBar; -import android.support.v7.app.AppCompatActivity; -import android.support.v7.app.AppCompatDelegate; +import androidx.appcompat.app.ActionBar; +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.app.AppCompatDelegate; import android.view.MenuItem; import protect.card_locker.R; diff --git a/app/src/main/res/drawable-hdpi/ic_arrow_back_white.png b/app/src/main/res/drawable-hdpi/ic_arrow_back_white.png new file mode 100644 index 000000000..f782543d3 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_arrow_back_white.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_arrow_back_white.png b/app/src/main/res/drawable-mdpi/ic_arrow_back_white.png new file mode 100644 index 000000000..222690b0b Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_arrow_back_white.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_arrow_back_white.png b/app/src/main/res/drawable-xhdpi/ic_arrow_back_white.png new file mode 100644 index 000000000..c4e8d91ba Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_arrow_back_white.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_arrow_back_white.png b/app/src/main/res/drawable-xxhdpi/ic_arrow_back_white.png new file mode 100644 index 000000000..575d5075c Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_arrow_back_white.png differ diff --git a/app/src/main/res/layout/barcode_selector_activity.xml b/app/src/main/res/layout/barcode_selector_activity.xml index e5884af2e..8edd3374f 100644 --- a/app/src/main/res/layout/barcode_selector_activity.xml +++ b/app/src/main/res/layout/barcode_selector_activity.xml @@ -1,23 +1,23 @@ - + - - - + +