From c86819fc7447f61d582daa20c96fb65d85d0a409 Mon Sep 17 00:00:00 2001 From: Branden Archer Date: Mon, 23 May 2016 08:43:52 -0400 Subject: [PATCH] Allow user to enter a barcode manually If a user is unable to scan a barcode, this commit allows a user to enter is manually. If the user selects to Enter Card instead of Capture Card, the user may enter the card's id. As it may not be known which barcode format the user expects, and the user may not know what barcode type is what, all barcode types are generated from the user input. Those that are valid are displayed to the user. The user may then select the barcode image which matches what the user wants. Italian translations provided by Michael Moroni (Airon90) Dutch translations provided by PanderMusubi --- app/src/main/AndroidManifest.xml | 6 + .../card_locker/BarcodeSelectorActivity.java | 202 +++++++++++++++++ .../card_locker/LoyaltyCardViewActivity.java | 74 ++++--- .../res/layout/barcode_selector_activity.xml | 205 ++++++++++++++++++ .../res/layout/loyalty_card_view_activity.xml | 5 + app/src/main/res/values-it/strings.xml | 3 + app/src/main/res/values-nl/strings.xml | 3 + app/src/main/res/values/strings.xml | 4 + 8 files changed, 468 insertions(+), 34 deletions(-) create mode 100644 app/src/main/java/protect/card_locker/BarcodeSelectorActivity.java create mode 100644 app/src/main/res/layout/barcode_selector_activity.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 9a900e199..59b46dad5 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -37,6 +37,12 @@ android:theme="@style/AppTheme.NoActionBar" android:configChanges="orientation|screenSize" android:windowSoftInputMode="stateHidden"/> + SUPPORTED_BARCODE_TYPES = Collections.unmodifiableList( + Arrays.asList( + BarcodeFormat.AZTEC.name(), + BarcodeFormat.CODE_39.name(), + BarcodeFormat.CODE_128.name(), + BarcodeFormat.CODABAR.name(), + BarcodeFormat.DATA_MATRIX.name(), + BarcodeFormat.EAN_8.name(), + BarcodeFormat.EAN_13.name(), + BarcodeFormat.ITF.name(), + BarcodeFormat.PDF_417.name(), + BarcodeFormat.QR_CODE.name(), + BarcodeFormat.UPC_A.name() + )); + + private Map barcodeViewMap; + private LinkedList barcodeGeneratorTasks = new LinkedList<>(); + + @Override + protected void onCreate(Bundle savedInstanceState) + { + super.onCreate(savedInstanceState); + + setContentView(R.layout.barcode_selector_activity); + Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); + setSupportActionBar(toolbar); + ActionBar actionBar = getSupportActionBar(); + if(actionBar != null) + { + actionBar.setDisplayHomeAsUpEnabled(true); + } + + barcodeViewMap = ImmutableMap.builder() + .put(BarcodeFormat.AZTEC.name(), R.id.aztecBarcode) + .put(BarcodeFormat.CODE_39.name(), R.id.code39Barcode) + .put(BarcodeFormat.CODE_128.name(), R.id.code128Barcode) + .put(BarcodeFormat.CODABAR.name(), R.id.codabarBarcode) + .put(BarcodeFormat.DATA_MATRIX.name(), R.id.datamatrixBarcode) + .put(BarcodeFormat.EAN_8.name(), R.id.ean8Barcode) + .put(BarcodeFormat.EAN_13.name(), R.id.ean13Barcode) + .put(BarcodeFormat.ITF.name(), R.id.itfBarcode) + .put(BarcodeFormat.PDF_417.name(), R.id.pdf417Barcode) + .put(BarcodeFormat.QR_CODE.name(), R.id.qrcodeBarcode) + .put(BarcodeFormat.UPC_A.name(), R.id.upcaBarcode) + .build(); + + EditText cardId = (EditText) findViewById(R.id.cardId); + cardId.addTextChangedListener(new TextWatcher() + { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) + { + // Noting to do + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) + { + Log.d(TAG, "Entered text: " + s); + + // Stop any async tasks which may not have been started yet + for(AsyncTask task : barcodeGeneratorTasks) + { + task.cancel(false); + } + barcodeGeneratorTasks.clear(); + + // Update barcodes + for(String key : barcodeViewMap.keySet()) + { + ImageView image = (ImageView)findViewById(barcodeViewMap.get(key)); + createBarcodeOption(image, key, s.toString()); + } + } + + @Override + public void afterTextChanged(Editable s) + { + // Noting to do + } + }); + } + + private void createBarcodeOption(final ImageView image, final String formatType, final String cardId) + { + final BarcodeFormat format = BarcodeFormat.valueOf(formatType); + if(format == null) + { + Log.w(TAG, "Unsupported barcode format: " + formatType); + return; + } + + image.setImageBitmap(null); + image.setVisibility(View.GONE); + image.setOnClickListener(new View.OnClickListener() + { + @Override + public void onClick(View v) + { + Log.d(TAG, "Selected barcode type " + formatType); + Intent result = new Intent(); + result.putExtra(BARCODE_FORMAT, formatType); + result.putExtra(BARCODE_CONTENTS, cardId); + BarcodeSelectorActivity.this.setResult(RESULT_OK, result); + finish(); + } + }); + + if(image.getHeight() == 0) + { + // 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. + image.getViewTreeObserver().addOnGlobalLayoutListener( + new ViewTreeObserver.OnGlobalLayoutListener() + { + @Override + public void onGlobalLayout() + { + Log.d(TAG, "Global layout finished, type: + " + formatType + ", width: " + image.getWidth()); + if (Build.VERSION.SDK_INT < 16) + { + image.getViewTreeObserver().removeGlobalOnLayoutListener(this); + } + else + { + image.getViewTreeObserver().removeOnGlobalLayoutListener(this); + } + + Log.d(TAG, "Generating barcode for type " + formatType); + BarcodeImageWriterTask task = new BarcodeImageWriterTask(image, cardId, format); + barcodeGeneratorTasks.add(task); + task.execute(); + } + }); + } + else + { + Log.d(TAG, "Generating barcode for type " + formatType); + BarcodeImageWriterTask task = new BarcodeImageWriterTask(image, cardId, format); + barcodeGeneratorTasks.add(task); + task.execute(); + } + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) + { + if (item.getItemId() == android.R.id.home) + { + setResult(Activity.RESULT_CANCELED); + finish(); + return true; + } + + return super.onOptionsItemSelected(item); + } +} diff --git a/app/src/main/java/protect/card_locker/LoyaltyCardViewActivity.java b/app/src/main/java/protect/card_locker/LoyaltyCardViewActivity.java index 621f63c9a..3b8f72a9c 100644 --- a/app/src/main/java/protect/card_locker/LoyaltyCardViewActivity.java +++ b/app/src/main/java/protect/card_locker/LoyaltyCardViewActivity.java @@ -1,6 +1,7 @@ package protect.card_locker; +import android.app.Activity; import android.content.Intent; import android.os.Build; import android.os.Bundle; @@ -21,31 +22,12 @@ import com.google.zxing.BarcodeFormat; import com.google.zxing.integration.android.IntentIntegrator; import com.google.zxing.integration.android.IntentResult; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; - public class LoyaltyCardViewActivity extends AppCompatActivity { private static final String TAG = "CardLocker"; - // These are all the barcode types that the zxing library - // is able to generate a barcode for, and thus should be - // the only barcodes which we should attempt to scan. - Collection supportedBarcodeTypes = Collections.unmodifiableList(Arrays.asList( - BarcodeFormat.AZTEC.name(), - BarcodeFormat.CODE_39.name(), - BarcodeFormat.CODE_128.name(), - BarcodeFormat.CODABAR.name(), - BarcodeFormat.DATA_MATRIX.name(), - BarcodeFormat.EAN_8.name(), - BarcodeFormat.EAN_13.name(), - BarcodeFormat.ITF.name(), - BarcodeFormat.PDF_417.name(), - BarcodeFormat.QR_CODE.name(), - BarcodeFormat.UPC_A.name() - )); + private static final int SELECT_BARCODE_REQUEST = 1; @Override protected void onCreate(Bundle savedInstanceState) @@ -85,6 +67,7 @@ public class LoyaltyCardViewActivity extends AppCompatActivity final View barcodeCaptureLayout = findViewById(R.id.barcodeCaptureLayout); final Button captureButton = (Button) findViewById(R.id.captureButton); + final Button enterButton = (Button) findViewById(R.id.enterButton); final Button saveButton = (Button) findViewById(R.id.saveButton); final Button cancelButton = (Button) findViewById(R.id.cancelButton); @@ -192,7 +175,7 @@ public class LoyaltyCardViewActivity extends AppCompatActivity public void onClick(View v) { IntentIntegrator integrator = new IntentIntegrator(LoyaltyCardViewActivity.this); - integrator.setDesiredBarcodeFormats(supportedBarcodeTypes); + integrator.setDesiredBarcodeFormats(BarcodeSelectorActivity.SUPPORTED_BARCODE_TYPES); String prompt = getResources().getString(R.string.scanCardBarcode); integrator.setPrompt(prompt); @@ -202,6 +185,16 @@ public class LoyaltyCardViewActivity extends AppCompatActivity captureButton.setOnClickListener(captureCallback); + enterButton.setOnClickListener(new View.OnClickListener() + { + @Override + public void onClick(View v) + { + Intent i = new Intent(getApplicationContext(), BarcodeSelectorActivity.class); + startActivityForResult(i, SELECT_BARCODE_REQUEST); + } + }); + saveButton.setOnClickListener(new View.OnClickListener() { @Override @@ -305,24 +298,37 @@ public class LoyaltyCardViewActivity extends AppCompatActivity @Override public void onActivityResult(int requestCode, int resultCode, Intent intent) { + String contents = null; + String format = null; + IntentResult result = IntentIntegrator.parseActivityResult(requestCode, resultCode, intent); if (result != null) { - String contents = result.getContents(); - String format = result.getFormatName(); - if(contents != null && contents.isEmpty() == false && - format != null && format.isEmpty() == false) - { - Log.i(TAG, "Read Contents from scan: " + contents); - Log.i(TAG, "Read Format: " + format); + Log.i(TAG, "Received barcode information from capture"); + contents = result.getContents(); + format = result.getFormatName(); + } - final EditText cardIdField = (EditText) findViewById(R.id.cardId); - cardIdField.setText(contents); - final EditText barcodeTypeField = (EditText) findViewById(R.id.barcodeType); - barcodeTypeField.setText(format); - onResume(); - } + if(requestCode == SELECT_BARCODE_REQUEST && resultCode == Activity.RESULT_OK) + { + Log.i(TAG, "Received barcode information from capture"); + + contents = intent.getStringExtra(BarcodeSelectorActivity.BARCODE_CONTENTS); + format = intent.getStringExtra(BarcodeSelectorActivity.BARCODE_FORMAT); + } + + if(contents != null && contents.isEmpty() == false && + format != null && format.isEmpty() == false) + { + Log.i(TAG, "Read barcode id: " + contents); + Log.i(TAG, "Read format: " + format); + + final EditText cardIdField = (EditText) findViewById(R.id.cardId); + cardIdField.setText(contents); + final EditText barcodeTypeField = (EditText) findViewById(R.id.barcodeType); + barcodeTypeField.setText(format); + onResume(); } } } \ No newline at end of file diff --git a/app/src/main/res/layout/barcode_selector_activity.xml b/app/src/main/res/layout/barcode_selector_activity.xml new file mode 100644 index 000000000..e5884af2e --- /dev/null +++ b/app/src/main/res/layout/barcode_selector_activity.xml @@ -0,0 +1,205 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/loyalty_card_view_activity.xml b/app/src/main/res/layout/loyalty_card_view_activity.xml index 13cb6113c..c42b02138 100644 --- a/app/src/main/res/layout/loyalty_card_view_activity.xml +++ b/app/src/main/res/layout/loyalty_card_view_activity.xml @@ -136,6 +136,11 @@ android:layout_height="wrap_content" android:text="@string/capture" android:layout_weight="1.0"/> +