refactor: convert ScanActivity.java to Kotlin.

bug: fix indentation and several bugs, convert more code blocks into apply blocks.
This commit is contained in:
Zechen Ma
2025-10-24 06:20:24 +11:00
parent 27c16c2faf
commit ff1683d5b4

View File

@@ -1,56 +1,46 @@
package protect.card_locker;
package protect.card_locker
import static protect.card_locker.BarcodeSelectorActivity.BARCODE_CONTENTS;
import static protect.card_locker.BarcodeSelectorActivity.BARCODE_FORMAT;
import android.Manifest;
import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Color;
import android.net.Uri;
import android.os.Bundle;
import android.provider.Settings;
import android.text.InputType;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.TypedValue;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.ListAdapter;
import android.widget.SimpleAdapter;
import android.widget.TextView;
import android.widget.Toast;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.widget.Toolbar;
import androidx.core.content.ContextCompat;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.zxing.DecodeHintType;
import com.google.zxing.ResultPoint;
import com.google.zxing.client.android.Intents;
import com.journeyapps.barcodescanner.BarcodeCallback;
import com.journeyapps.barcodescanner.BarcodeResult;
import com.journeyapps.barcodescanner.CaptureManager;
import com.journeyapps.barcodescanner.DecoratedBarcodeView;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import protect.card_locker.databinding.CustomBarcodeScannerBinding;
import protect.card_locker.databinding.ScanActivityBinding;
import android.Manifest
import android.content.ActivityNotFoundException
import android.content.Intent
import android.content.pm.PackageManager
import android.graphics.Color
import android.net.Uri
import android.os.Bundle
import android.provider.Settings
import android.text.InputType
import android.util.DisplayMetrics
import android.util.Log
import android.util.TypedValue
import android.view.KeyEvent
import android.view.Menu
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import android.view.WindowManager
import android.widget.EditText
import android.widget.LinearLayout
import android.widget.ListAdapter
import android.widget.SimpleAdapter
import android.widget.TextView
import android.widget.Toast
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AlertDialog
import androidx.core.content.ContextCompat
import androidx.core.widget.doAfterTextChanged
import androidx.core.widget.doOnTextChanged
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.zxing.DecodeHintType
import com.google.zxing.ResultPoint
import com.google.zxing.client.android.Intents
import com.journeyapps.barcodescanner.BarcodeCallback
import com.journeyapps.barcodescanner.BarcodeResult
import com.journeyapps.barcodescanner.CaptureManager
import com.journeyapps.barcodescanner.DecoratedBarcodeView
import protect.card_locker.databinding.CustomBarcodeScannerBinding
import protect.card_locker.databinding.ScanActivityBinding
/**
* Custom Scannner Activity extending from Activity to display a custom layout form scanner view.
@@ -58,484 +48,552 @@ import protect.card_locker.databinding.ScanActivityBinding;
* Based on https://github.com/journeyapps/zxing-android-embedded/blob/0fdfbce9fb3285e985bad9971c5f7c0a7a334e7b/sample/src/main/java/example/zxing/CustomScannerActivity.java
* originally licensed under Apache 2.0
*/
public class ScanActivity extends CatimaAppCompatActivity {
private ScanActivityBinding binding;
private CustomBarcodeScannerBinding customBarcodeScannerBinding;
private static final String TAG = "Catima";
class ScanActivity : CatimaAppCompatActivity() {
private lateinit var binding: ScanActivityBinding
private lateinit var customBarcodeScannerBinding: CustomBarcodeScannerBinding
private static final int MEDIUM_SCALE_FACTOR_DIP = 460;
private static final int COMPAT_SCALE_FACTOR_DIP = 320;
companion object {
private const val TAG = "Catima"
private static final int PERMISSION_SCAN_ADD_FROM_IMAGE = 100;
private static final int PERMISSION_SCAN_ADD_FROM_PDF = 101;
private static final int PERMISSION_SCAN_ADD_FROM_PKPASS = 102;
private const val MEDIUM_SCALE_FACTOR_DIP = 460
private const val COMPAT_SCALE_FACTOR_DIP = 320
private CaptureManager capture;
private DecoratedBarcodeView barcodeScannerView;
private const val PERMISSION_SCAN_ADD_FROM_IMAGE = 100
private const val PERMISSION_SCAN_ADD_FROM_PDF = 101
private const val PERMISSION_SCAN_ADD_FROM_PKPASS = 102
private String cardId;
private String addGroup;
private boolean torch = false;
private ActivityResultLauncher<Intent> manualAddLauncher;
// can't use the pre-made contract because that launches the file manager for image type instead of gallery
private ActivityResultLauncher<Intent> photoPickerLauncher;
private ActivityResultLauncher<Intent> pdfPickerLauncher;
private ActivityResultLauncher<Intent> pkpassPickerLauncher;
static final String STATE_SCANNER_ACTIVE = "scannerActive";
private boolean mScannerActive = true;
private boolean mHasError = false;
private void extractIntentFields(Intent intent) {
final Bundle b = intent.getExtras();
cardId = b != null ? b.getString(LoyaltyCard.BUNDLE_LOYALTY_CARD_CARD_ID) : null;
addGroup = b != null ? b.getString(LoyaltyCardEditActivity.BUNDLE_ADDGROUP) : null;
Log.d(TAG, "Scan activity: id=" + cardId);
private const val STATE_SCANNER_ACTIVE = "scannerActive"
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ScanActivityBinding.inflate(getLayoutInflater());
customBarcodeScannerBinding = CustomBarcodeScannerBinding.bind(binding.zxingBarcodeScanner);
setTitle(R.string.scanCardBarcode);
setContentView(binding.getRoot());
Utils.applyWindowInsets(binding.getRoot());
Toolbar toolbar = binding.toolbar;
setSupportActionBar(toolbar);
enableToolbarBackButton();
private lateinit var capture: CaptureManager
private lateinit var barcodeScannerView: DecoratedBarcodeView
private var cardId: String? = null
private var addGroup: String? = null
private var torch = false
extractIntentFields(getIntent());
private lateinit var manualAddLauncher: ActivityResultLauncher<Intent>
private lateinit var photoPickerLauncher: ActivityResultLauncher<Intent>
private lateinit var pdfPickerLauncher: ActivityResultLauncher<Intent>
private lateinit var pkpassPickerLauncher: ActivityResultLauncher<Intent>
manualAddLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> handleActivityResult(Utils.SELECT_BARCODE_REQUEST, result.getResultCode(), result.getData()));
photoPickerLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> handleActivityResult(Utils.BARCODE_IMPORT_FROM_IMAGE_FILE, result.getResultCode(), result.getData()));
pdfPickerLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> handleActivityResult(Utils.BARCODE_IMPORT_FROM_PDF_FILE, result.getResultCode(), result.getData()));
pkpassPickerLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> handleActivityResult(Utils.BARCODE_IMPORT_FROM_PKPASS_FILE, result.getResultCode(), result.getData()));
customBarcodeScannerBinding.fabOtherOptions.setOnClickListener(view -> {
setScannerActive(false);
private var mScannerActive = true
private var mHasError = false
ArrayList<HashMap<String, Object>> list = new ArrayList<>();
String[] texts = new String[]{
private fun extractIntentFields(intent: Intent) {
val b = intent.extras
cardId = b?.getString(LoyaltyCard.BUNDLE_LOYALTY_CARD_CARD_ID)
addGroup = b?.getString(LoyaltyCardEditActivity.BUNDLE_ADDGROUP)
Log.d(TAG, "Scan activity: id=$cardId")
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ScanActivityBinding.inflate(layoutInflater)
customBarcodeScannerBinding = CustomBarcodeScannerBinding.bind(binding.zxingBarcodeScanner)
setTitle(R.string.scanCardBarcode)
setContentView(binding.root)
Utils.applyWindowInsets(binding.root)
setSupportActionBar(binding.toolbar)
enableToolbarBackButton()
extractIntentFields(intent)
manualAddLauncher =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
handleActivityResult(
Utils.SELECT_BARCODE_REQUEST,
result.resultCode,
result.data
)
}
photoPickerLauncher =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
handleActivityResult(
Utils.BARCODE_IMPORT_FROM_IMAGE_FILE,
result.resultCode,
result.data
)
}
pdfPickerLauncher =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
handleActivityResult(
Utils.BARCODE_IMPORT_FROM_PDF_FILE,
result.resultCode,
result.data
)
}
pkpassPickerLauncher =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
handleActivityResult(
Utils.BARCODE_IMPORT_FROM_PKPASS_FILE,
result.resultCode,
result.data
)
}
customBarcodeScannerBinding.fabOtherOptions.setOnClickListener {
setScannerActive(false)
val list: ArrayList<HashMap<String, Any>> = arrayListOf()
val texts = arrayOf(
getString(R.string.addWithoutBarcode),
getString(R.string.addManually),
getString(R.string.addFromImage),
getString(R.string.addFromPdfFile),
getString(R.string.addFromPkpass)
};
Object[] icons = new Object[]{
)
val icons = arrayOf(
R.drawable.baseline_block_24,
R.drawable.ic_edit,
R.drawable.baseline_image_24,
R.drawable.baseline_picture_as_pdf_24,
R.drawable.local_activity_24px
};
String[] columns = new String[]{"text", "icon"};
)
val columns = arrayOf("text", "icon")
for (int i = 0; i < texts.length; i++) {
HashMap<String, Object> map = new HashMap<>();
map.put(columns[0], texts[i]);
map.put(columns[1], icons[i]);
list.add(map);
for (i in 0 until texts.size) {
val map: HashMap<String, Any> = hashMapOf()
map.put(columns[0], texts[i])
map.put(columns[1], icons[i])
list.add(map)
}
ListAdapter adapter = new SimpleAdapter(
ScanActivity.this,
val adapter: ListAdapter = SimpleAdapter(
this,
list,
R.layout.alertdialog_row_with_icon,
columns,
new int[]{R.id.textView, R.id.imageView}
);
intArrayOf(R.id.textView, R.id.imageView)
)
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(ScanActivity.this);
builder.setTitle(getString(R.string.add_a_card_in_a_different_way));
builder.setAdapter(
adapter,
(dialogInterface, i) -> {
switch (i) {
case 0:
addWithoutBarcode();
break;
case 1:
addManually();
break;
case 2:
addFromImage();
break;
case 3:
addFromPdf();
break;
case 4:
addFromPkPass();
break;
default:
throw new IllegalArgumentException("Unknown 'Add a card in a different way' dialog option");
}
val builder = MaterialAlertDialogBuilder(this).apply {
setTitle(getString(R.string.add_a_card_in_a_different_way))
setAdapter(adapter) { _, i ->
when (i) {
0 -> addWithoutBarcode()
1 -> addManually()
2 -> addFromImage()
3 -> addFromPdf()
4 -> addFromPkPass()
else -> throw IllegalArgumentException(
"Unknown 'Add a card in a different way' dialog option: $i"
)
}
);
builder.setOnCancelListener(dialogInterface -> setScannerActive(true));
builder.show();
});
}
setOnCancelListener { _ -> setScannerActive(true) }
}
builder.show()
}
// Configure barcodeScanner
barcodeScannerView = binding.zxingBarcodeScanner;
Intent barcodeScannerIntent = new Intent();
Bundle barcodeScannerIntentBundle = new Bundle();
barcodeScannerIntentBundle.putBoolean(DecodeHintType.ALSO_INVERTED.name(), Boolean.TRUE);
barcodeScannerIntent.putExtras(barcodeScannerIntentBundle);
barcodeScannerView.initializeFromIntent(barcodeScannerIntent);
barcodeScannerView = binding.zxingBarcodeScanner
val barcodeScannerIntent = Intent().apply {
val barcodeScannerIntentBundle = Bundle().apply {
putBoolean(DecodeHintType.ALSO_INVERTED.name, true)
}
putExtras(barcodeScannerIntentBundle)
}
barcodeScannerView.initializeFromIntent(barcodeScannerIntent)
// Even though we do the actual decoding with the barcodeScannerView
// CaptureManager needs to be running to show the camera and scanning bar
capture = new CatimaCaptureManager(this, barcodeScannerView, this::onCaptureManagerError);
Intent captureIntent = new Intent();
Bundle captureIntentBundle = new Bundle();
captureIntentBundle.putBoolean(Intents.Scan.BEEP_ENABLED, false);
captureIntent.putExtras(captureIntentBundle);
capture.initializeFromIntent(captureIntent, savedInstanceState);
capture = CatimaCaptureManager(this, barcodeScannerView, this::onCaptureManagerError)
val captureIntent = Intent().apply {
val captureIntentBundle = Bundle().apply {
putBoolean(DecodeHintType.ALSO_INVERTED.name, false)
}
putExtras(captureIntentBundle)
}
capture.initializeFromIntent(captureIntent, savedInstanceState)
barcodeScannerView.decodeSingle(new BarcodeCallback() {
@Override
public void barcodeResult(BarcodeResult result) {
LoyaltyCard loyaltyCard = new LoyaltyCard();
loyaltyCard.setCardId(result.getText());
loyaltyCard.setBarcodeType(CatimaBarcode.fromBarcode(result.getBarcodeFormat()));
barcodeScannerView.decodeSingle(object : BarcodeCallback {
override fun barcodeResult(result: BarcodeResult) {
val loyaltyCard = LoyaltyCard().apply {
setCardId(result.text)
setBarcodeType(CatimaBarcode.fromBarcode(result.barcodeFormat))
}
returnResult(new ParseResult(ParseResultType.BARCODE_ONLY, loyaltyCard));
returnResult(ParseResult(ParseResultType.BARCODE_ONLY, loyaltyCard))
}
@Override
public void possibleResultPoints(List<ResultPoint> resultPoints) {
}
});
override fun possibleResultPoints(resultPoints: List<ResultPoint?>?) {}
})
}
@Override
protected void onResume() {
super.onResume();
override fun onResume() {
super.onResume()
if (mScannerActive) {
capture.onResume();
capture.onResume()
}
if (!Utils.deviceHasCamera(this)) {
showCameraError(getString(R.string.noCameraFoundGuideText), false);
} else if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
showCameraPermissionMissingText();
showCameraError(getString(R.string.noCameraFoundGuideText), false)
} else if (ContextCompat.checkSelfPermission(
this,
Manifest.permission.CAMERA
) != PackageManager.PERMISSION_GRANTED
) {
showCameraPermissionMissingText()
} else {
hideCameraError();
hideCameraError()
}
scaleScreen();
scaleScreen()
}
@Override
protected void onPause() {
super.onPause();
capture.onPause();
override fun onPause() {
super.onPause()
capture.onPause()
}
@Override
protected void onDestroy() {
super.onDestroy();
capture.onDestroy();
override fun onDestroy() {
super.onDestroy()
capture.onDestroy()
}
@Override
protected void onSaveInstanceState(Bundle savedInstanceState) {
super.onSaveInstanceState(savedInstanceState);
capture.onSaveInstanceState(savedInstanceState);
override fun onSaveInstanceState(savedInstanceState: Bundle) {
super.onSaveInstanceState(savedInstanceState)
capture.onSaveInstanceState(savedInstanceState)
savedInstanceState.putBoolean(STATE_SCANNER_ACTIVE, mScannerActive);
savedInstanceState.putBoolean(STATE_SCANNER_ACTIVE, mScannerActive)
}
@Override
public void onRestoreInstanceState(@NonNull Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
override fun onRestoreInstanceState(savedInstanceState: Bundle) {
super.onRestoreInstanceState(savedInstanceState)
mScannerActive = savedInstanceState.getBoolean(STATE_SCANNER_ACTIVE);
mScannerActive = savedInstanceState.getBoolean(STATE_SCANNER_ACTIVE)
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
return barcodeScannerView.onKeyDown(keyCode, event) || super.onKeyDown(keyCode, event);
override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean {
return barcodeScannerView.onKeyDown(keyCode, event) || super.onKeyDown(keyCode, event)
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_FLASH)) {
getMenuInflater().inflate(R.menu.scan_menu, menu);
override fun onCreateOptionsMenu(menu: Menu): Boolean {
if (packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_FLASH)) {
menuInflater.inflate(R.menu.scan_menu, menu)
}
barcodeScannerView.setTorchOff();
barcodeScannerView.setTorchOff()
return super.onCreateOptionsMenu(menu);
return super.onCreateOptionsMenu(menu)
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
setResult(Activity.RESULT_CANCELED);
finish();
return true;
} else if (item.getItemId() == R.id.action_toggle_flashlight) {
override fun onOptionsItemSelected(item: MenuItem): Boolean {
if (item.itemId == android.R.id.home) {
setResult(RESULT_CANCELED)
finish()
return true
} else if (item.itemId == R.id.action_toggle_flashlight) {
if (torch) {
torch = false;
barcodeScannerView.setTorchOff();
item.setTitle(R.string.turn_flashlight_on);
item.setIcon(R.drawable.ic_flashlight_off_white_24dp);
torch = false
barcodeScannerView.setTorchOff()
item.setTitle(R.string.turn_flashlight_on)
item.setIcon(R.drawable.ic_flashlight_off_white_24dp)
} else {
torch = true;
barcodeScannerView.setTorchOn();
item.setTitle(R.string.turn_flashlight_off);
item.setIcon(R.drawable.ic_flashlight_on_white_24dp);
torch = true
barcodeScannerView.setTorchOn()
item.setTitle(R.string.turn_flashlight_off)
item.setIcon(R.drawable.ic_flashlight_on_white_24dp)
}
}
return super.onOptionsItemSelected(item);
return super.onOptionsItemSelected(item)
}
private void setScannerActive(boolean isActive) {
private fun setScannerActive(isActive: Boolean) {
if (isActive) {
barcodeScannerView.resume();
barcodeScannerView.resume()
} else {
barcodeScannerView.pause();
barcodeScannerView.pause()
}
mScannerActive = isActive;
mScannerActive = isActive
}
private void returnResult(ParseResult parseResult) {
Intent result = new Intent();
Bundle bundle = parseResult.toLoyaltyCardBundle(ScanActivity.this);
if (addGroup != null) {
bundle.putString(LoyaltyCardEditActivity.BUNDLE_ADDGROUP, addGroup);
private fun returnResult(parseResult: ParseResult) {
val bundle = parseResult.toLoyaltyCardBundle(this).apply {
addGroup?.let { putString(LoyaltyCardEditActivity.BUNDLE_ADDGROUP, it) }
}
result.putExtras(bundle);
ScanActivity.this.setResult(RESULT_OK, result);
finish();
val result = Intent().apply { putExtras(bundle) }
this.setResult(RESULT_OK, result)
finish()
}
private void handleActivityResult(int requestCode, int resultCode, Intent intent) {
super.onActivityResult(requestCode, resultCode, intent);
private fun handleActivityResult(requestCode: Int, resultCode: Int, intent: Intent?) {
super.onActivityResult(resultCode, resultCode, intent)
List<ParseResult> parseResultList = Utils.parseSetBarcodeActivityResult(requestCode, resultCode, intent, this);
val parseResultList: List<ParseResult> =
Utils.parseSetBarcodeActivityResult(requestCode, resultCode, intent, this)
if (parseResultList.isEmpty()) {
setScannerActive(true);
return;
setScannerActive(true)
return
}
Utils.makeUserChooseParseResultFromList(this, parseResultList, new ParseResultListDisambiguatorCallback() {
@Override
public void onUserChoseParseResult(ParseResult parseResult) {
returnResult(parseResult);
}
@Override
public void onUserDismissedSelector() {
setScannerActive(true);
}
});
Utils.makeUserChooseParseResultFromList(
this,
parseResultList,
object : ParseResultListDisambiguatorCallback {
override fun onUserChoseParseResult(parseResult: ParseResult) {
returnResult(parseResult)
}
override fun onUserDismissedSelector() {
setScannerActive(true)
}
})
}
private void addWithoutBarcode() {
AlertDialog.Builder builder = new MaterialAlertDialogBuilder(this);
builder.setOnCancelListener(dialogInterface -> setScannerActive(true));
// Header
builder.setTitle(R.string.addWithoutBarcode);
private fun addWithoutBarcode() {
val builder: AlertDialog.Builder = MaterialAlertDialogBuilder(this).apply {
setOnCancelListener { dialogInterface -> setScannerActive(true) }
// Header
setTitle(R.string.addWithoutBarcode)
}
// Layout
LinearLayout layout = new LinearLayout(this);
layout.setOrientation(LinearLayout.VERTICAL);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT
);
int contentPadding = getResources().getDimensionPixelSize(R.dimen.alert_dialog_content_padding);
params.leftMargin = contentPadding;
params.topMargin = contentPadding / 2;
params.rightMargin = contentPadding;
val layout = LinearLayout(this).apply {
orientation = LinearLayout.VERTICAL
}
val contentPadding = resources.getDimensionPixelSize(R.dimen.alert_dialog_content_padding)
val params = LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT
).apply {
leftMargin = contentPadding
topMargin = contentPadding / 2
rightMargin = contentPadding
}
// Description
TextView currentTextview = new TextView(this);
currentTextview.setText(getString(R.string.enter_card_id));
currentTextview.setLayoutParams(params);
layout.addView(currentTextview);
val currentTextview = TextView(this).apply {
text = getString(R.string.enter_card_id)
layoutParams = params
}
layout.addView(currentTextview)
// EditText with spacing
final EditText input = new EditText(this);
input.setInputType(InputType.TYPE_CLASS_TEXT);
input.setLayoutParams(params);
layout.addView(input);
//EditText with spacing
val input = EditText(this).apply {
inputType = InputType.TYPE_CLASS_TEXT
layoutParams = params
}
layout.addView(input)
// Set layout
builder.setView(layout);
builder.setView(layout).apply {
// Buttons
builder.setPositiveButton(getString(R.string.ok), (dialog, which) -> {
LoyaltyCard loyaltyCard = new LoyaltyCard();
loyaltyCard.setCardId(input.getText().toString());
returnResult(new ParseResult(ParseResultType.BARCODE_ONLY, loyaltyCard));
});
builder.setNegativeButton(getString(R.string.cancel), (dialog, which) -> dialog.cancel());
AlertDialog dialog = builder.create();
setPositiveButton(getString(R.string.ok)) { _, _ ->
val loyaltyCard = LoyaltyCard()
loyaltyCard.cardId = input.text.toString()
returnResult(ParseResult(ParseResultType.BARCODE_ONLY, loyaltyCard))
}
setNegativeButton(getString(R.string.cancel)) { dialog, _ ->
dialog.cancel()
}
}
val dialog: AlertDialog = builder.create()
// Now that the dialog exists, we can bind something that affects the OK button
input.addTextChangedListener(new SimpleTextWatcher() {
public void onTextChanged(CharSequence s, int start, int before, int count) {
if (s.length() == 0) {
input.setError(getString(R.string.card_id_must_not_be_empty));
dialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(false);
} else {
input.setError(null);
dialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(true);
}
input.doOnTextChanged { text, _, _, _ ->
if (text.isNullOrEmpty()) {
input.error = getString(R.string.card_id_must_not_be_empty)
dialog.getButton(AlertDialog.BUTTON_POSITIVE).isEnabled = false
} else {
input.error = null
dialog.getButton(AlertDialog.BUTTON_POSITIVE).isEnabled = true
}
});
}
dialog.show();
dialog.show()
// Disable button (must be done **after** dialog is shown to prevent crash
dialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(false);
dialog.getButton(AlertDialog.BUTTON_POSITIVE).isEnabled = false
// Set focus on input field
dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
input.requestFocus();
dialog.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE)
input.requestFocus()
}
public void addManually() {
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(ScanActivity.this);
builder.setTitle(R.string.add_manually_warning_title);
builder.setMessage(R.string.add_manually_warning_message);
builder.setPositiveButton(R.string.continue_, (dialog, which) -> {
Intent i = new Intent(getApplicationContext(), BarcodeSelectorActivity.class);
if (cardId != null) {
final Bundle b = new Bundle();
b.putString(LoyaltyCard.BUNDLE_LOYALTY_CARD_CARD_ID, cardId);
i.putExtras(b);
fun addManually() {
val builder = MaterialAlertDialogBuilder(this).apply {
setTitle(R.string.add_manually_warning_title)
setMessage(R.string.add_manually_warning_message)
setPositiveButton(R.string.continue_) { _, _ ->
val i = Intent(applicationContext, BarcodeSelectorActivity::class.java)
if (cardId != null) {
val b = Bundle()
b.putString(LoyaltyCard.BUNDLE_LOYALTY_CARD_CARD_ID, cardId)
i.putExtras(b)
}
manualAddLauncher.launch(i)
}
manualAddLauncher.launch(i);
});
builder.setNegativeButton(R.string.cancel, (dialog, which) -> setScannerActive(true));
builder.setOnCancelListener(dialog -> setScannerActive(true));
builder.show();
setNegativeButton(R.string.cancel) { _, _ -> setScannerActive(true) }
setOnCancelListener { _ -> setScannerActive(true) }
}
builder.show()
}
public void addFromImage() {
PermissionUtils.requestStorageReadPermission(this, PERMISSION_SCAN_ADD_FROM_IMAGE);
fun addFromImage() {
PermissionUtils.requestStorageReadPermission(this, PERMISSION_SCAN_ADD_FROM_IMAGE)
}
public void addFromPdf() {
PermissionUtils.requestStorageReadPermission(this, PERMISSION_SCAN_ADD_FROM_PDF);
fun addFromPdf() {
PermissionUtils.requestStorageReadPermission(this, PERMISSION_SCAN_ADD_FROM_PDF)
}
public void addFromPkPass() {
PermissionUtils.requestStorageReadPermission(this, PERMISSION_SCAN_ADD_FROM_PKPASS);
fun addFromPkPass() {
PermissionUtils.requestStorageReadPermission(this, PERMISSION_SCAN_ADD_FROM_PKPASS)
}
private void addFromImageOrFileAfterPermission(String mimeType, ActivityResultLauncher<Intent> launcher, int chooserText, int errorMessage) {
Intent photoPickerIntent = new Intent(Intent.ACTION_PICK);
photoPickerIntent.setType(mimeType);
Intent contentIntent = new Intent(Intent.ACTION_GET_CONTENT);
contentIntent.setType(mimeType);
private fun addFromImageOrFileAfterPermission(
mimeType: String,
launcher: ActivityResultLauncher<Intent>,
chooserText: Int,
errorMessage: Int
) {
val photoPickerIntent = Intent(Intent.ACTION_PICK)
photoPickerIntent.type = mimeType
val contentIntent = Intent(Intent.ACTION_GET_CONTENT)
contentIntent.type = mimeType
Intent chooserIntent = Intent.createChooser(photoPickerIntent, getString(chooserText));
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, new Intent[] { contentIntent });
val chooserIntent = Intent.createChooser(photoPickerIntent, getString(chooserText))
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, arrayOf(contentIntent))
try {
launcher.launch(chooserIntent);
} catch (ActivityNotFoundException e) {
setScannerActive(true);
Toast.makeText(getApplicationContext(), errorMessage, Toast.LENGTH_LONG).show();
Log.e(TAG, "No activity found to handle intent", e);
launcher.launch(chooserIntent)
} catch (e: ActivityNotFoundException) {
setScannerActive(true)
Toast.makeText(applicationContext, errorMessage, Toast.LENGTH_LONG).show()
Log.e(TAG, "No activity found to handle intent", e)
}
}
public void onCaptureManagerError(String errorMessage) {
fun onCaptureManagerError(errorMessage: String) {
if (mHasError) {
// We're already showing an error, ignore this new error
return;
return
}
showCameraError(errorMessage, false);
showCameraError(errorMessage, false)
}
private void showCameraPermissionMissingText() {
showCameraError(getString(R.string.noCameraPermissionDirectToSystemSetting), true);
private fun showCameraPermissionMissingText() {
showCameraError(getString(R.string.noCameraPermissionDirectToSystemSetting), true)
}
private void showCameraError(String message, boolean setOnClick) {
customBarcodeScannerBinding.cameraErrorLayout.cameraErrorMessage.setText(message);
private fun showCameraError(message: String, setOnClick: Boolean) {
customBarcodeScannerBinding.cameraErrorLayout.cameraErrorMessage.text = message
setCameraErrorState(true, setOnClick);
setCameraErrorState(true, setOnClick)
}
private void hideCameraError() {
setCameraErrorState(false, false);
private fun hideCameraError() {
setCameraErrorState(false, false)
}
private void setCameraErrorState(boolean visible, boolean setOnClick) {
mHasError = visible;
customBarcodeScannerBinding.cameraErrorLayout.cameraErrorClickableArea.setOnClickListener(visible && setOnClick ? v -> {
navigateToSystemPermissionSetting();
} : null);
customBarcodeScannerBinding.cardInputContainer.setBackgroundColor(visible ? obtainThemeAttribute(com.google.android.material.R.attr.colorSurface) : Color.TRANSPARENT);
customBarcodeScannerBinding.cameraErrorLayout.getRoot().setVisibility(visible ? View.VISIBLE : View.GONE);
private fun setCameraErrorState(visible: Boolean, setOnClick: Boolean) {
mHasError = visible
customBarcodeScannerBinding.cameraErrorLayout.cameraErrorClickableArea.setOnClickListener(
if (visible && setOnClick) { _ -> navigateToSystemPermissionSetting() }
else null
)
customBarcodeScannerBinding.cardInputContainer.setBackgroundColor(
if (visible) obtainThemeAttribute(com.google.android.material.R.attr.colorSurface)
else Color.TRANSPARENT
)
customBarcodeScannerBinding.cameraErrorLayout.root.visibility =
if (visible) View.VISIBLE else View.GONE
}
private void scaleScreen() {
DisplayMetrics displayMetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
int screenHeight = displayMetrics.heightPixels;
float mediumSizePx = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,MEDIUM_SCALE_FACTOR_DIP,getResources().getDisplayMetrics());
boolean shouldScaleSmaller = screenHeight < mediumSizePx;
private fun scaleScreen() {
val displayMetrics = DisplayMetrics()
windowManager.defaultDisplay.getMetrics(displayMetrics)
val screenHeight: Int = displayMetrics.heightPixels
val mediumSizePx: Float = TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
MEDIUM_SCALE_FACTOR_DIP.toFloat(),
resources.displayMetrics
)
val shouldScaleSmaller = screenHeight < mediumSizePx
customBarcodeScannerBinding.cameraErrorLayout.cameraErrorIcon.setVisibility(shouldScaleSmaller ? View.GONE : View.VISIBLE);
customBarcodeScannerBinding.cameraErrorLayout.cameraErrorTitle.setVisibility(shouldScaleSmaller ? View.GONE : View.VISIBLE);
customBarcodeScannerBinding.cameraErrorLayout.cameraErrorIcon.visibility =
if (shouldScaleSmaller) View.GONE else View.VISIBLE
customBarcodeScannerBinding.cameraErrorLayout.cameraErrorTitle.visibility =
if (shouldScaleSmaller) View.GONE else View.VISIBLE
}
private int obtainThemeAttribute(int attribute) {
TypedValue typedValue = new TypedValue();
getTheme().resolveAttribute(attribute, typedValue, true);
return typedValue.data;
private fun obtainThemeAttribute(attribute: Int): Int {
val typedValue = TypedValue()
theme.resolveAttribute(attribute, typedValue, true)
return typedValue.data
}
private void navigateToSystemPermissionSetting() {
Intent permissionIntent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, Uri.fromParts("package", getPackageName(), null));
permissionIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(permissionIntent);
private fun navigateToSystemPermissionSetting() {
val permissionIntent = Intent(
Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
Uri.fromParts("package", getPackageName(), null)
)
permissionIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
startActivity(permissionIntent)
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<String?>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
onMockedRequestPermissionsResult(requestCode, permissions, grantResults);
onMockedRequestPermissionsResult(requestCode, permissions, grantResults)
}
public void onMockedRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
boolean granted = grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED;
override fun onMockedRequestPermissionsResult(
requestCode: Int,
permissions: Array<String?>,
grantResults: IntArray
) {
val granted =
grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED
if (requestCode == CaptureManager.getCameraPermissionReqCode()) {
if (granted) {
hideCameraError();
hideCameraError()
} else {
showCameraPermissionMissingText();
showCameraPermissionMissingText()
}
} else if (requestCode == PERMISSION_SCAN_ADD_FROM_IMAGE || requestCode == PERMISSION_SCAN_ADD_FROM_PDF || requestCode == PERMISSION_SCAN_ADD_FROM_PKPASS) {
} else if (requestCode in listOf(
PERMISSION_SCAN_ADD_FROM_IMAGE,
PERMISSION_SCAN_ADD_FROM_PDF,
PERMISSION_SCAN_ADD_FROM_PKPASS
)
) {
if (granted) {
if (requestCode == PERMISSION_SCAN_ADD_FROM_IMAGE) {
addFromImageOrFileAfterPermission("image/*", photoPickerLauncher, R.string.addFromImage, R.string.failedLaunchingPhotoPicker);
addFromImageOrFileAfterPermission(
"image/*",
photoPickerLauncher,
R.string.addFromImage,
R.string.failedLaunchingPhotoPicker
)
} else if (requestCode == PERMISSION_SCAN_ADD_FROM_PDF) {
addFromImageOrFileAfterPermission("application/pdf", pdfPickerLauncher, R.string.addFromPdfFile, R.string.failedLaunchingFileManager);
addFromImageOrFileAfterPermission(
"application/pdf",
pdfPickerLauncher,
R.string.addFromPdfFile,
R.string.failedLaunchingFileManager
)
} else {
addFromImageOrFileAfterPermission("application/*", pkpassPickerLauncher, R.string.addFromPkpass, R.string.failedLaunchingFileManager);
addFromImageOrFileAfterPermission(
"application/*",
pkpassPickerLauncher,
R.string.addFromPkpass,
R.string.failedLaunchingFileManager
)
}
} else {
setScannerActive(true);
Toast.makeText(this, R.string.storageReadPermissionRequired, Toast.LENGTH_LONG).show();
setScannerActive(true)
Toast.makeText(this, R.string.storageReadPermissionRequired, Toast.LENGTH_LONG)
.show()
}
}
}