Skip to content

Commit

Permalink
Barcode (#85)
Browse files Browse the repository at this point in the history
* Very rough Barcode Scanning

* Polished the barcode scanner giving users more options
  • Loading branch information
Sami-Jagirdar authored Nov 28, 2023
1 parent 642f8e3 commit 520bd7a
Show file tree
Hide file tree
Showing 7 changed files with 187 additions and 7 deletions.
1 change: 1 addition & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ dependencies {
implementation("androidx.navigation:navigation-fragment:2.7.5")
implementation("androidx.core:core:1.12.0")
testImplementation("junit:junit:4.13.2")
implementation("com.google.mlkit:barcode-scanning:17.2.0")
androidTestImplementation("androidx.test.ext:junit:1.1.5")
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
androidTestImplementation("androidx.test.uiautomator:uiautomator:2.2.0")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import com.example.househomey.Item;
import com.example.househomey.MainActivity;
import com.example.househomey.R;
import com.example.househomey.scanner.BarcodeImageScanner;
import com.example.househomey.scanner.SNImageScanner;
import com.example.househomey.scanner.ScannerPickerDialog;
import com.google.android.material.datepicker.MaterialDatePicker;
Expand All @@ -43,13 +44,16 @@
*
* @author Owen Cooke
*/
public abstract class ItemFormFragment extends Fragment implements ImagePickerDialog.OnImagePickedListener, PhotoAdapter.OnButtonClickListener, SNImageScanner.OnImageScannedListener {
public abstract class ItemFormFragment extends Fragment implements ImagePickerDialog.OnImagePickedListener,
PhotoAdapter.OnButtonClickListener, SNImageScanner.OnImageScannedListener,
BarcodeImageScanner.OnBarcodeScannedListener {
protected Date dateAcquired;
private TextInputEditText dateTextView;
protected CollectionReference itemRef;
protected ArrayList<String> photoUris = new ArrayList<>();
protected PhotoAdapter photoAdapter;
private TextInputEditText sNTextView;
private TextInputEditText descriptionTextView;
private final ArrayList<String> photosToDelete = new ArrayList<>();
private ImagePickerDialog imagePickerDialog;

Expand All @@ -72,6 +76,7 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle sa
// Get item collection reference from main activity
itemRef = ((MainActivity) requireActivity()).getItemRef();
sNTextView = rootView.findViewById(R.id.add_item_serial_number);
descriptionTextView = rootView.findViewById(R.id.add_item_description);
View scanButton = rootView.findViewById(R.id.add_item_scan_button);
scanButton.setOnClickListener(v -> launchScannerPicker());
return rootView;
Expand Down Expand Up @@ -265,6 +270,22 @@ public void onSNScanningComplete(String serialNumber) {
sNTextView.setText(serialNumber);
}

/**
* Sets the item description field to the decoded barcode value after scanning image
* @param description the decoded barcode value to set as description
*/
@Override
public void onBarcodeOKPressed(String description) {
descriptionTextView.setText(description);
}

/**
* Sets the item serial number field to the decoded barcode value after scanning image
* @param serialNumber the decoded barcode value to set as serial number
*/
@Override
public void onSerialNumberOKPressed(String serialNumber) {sNTextView.setText(serialNumber);}

/**
* Uploads a local image to Firebase Cloud Storage and returns its UUID.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
package com.example.househomey.scanner;

import android.app.AlertDialog;
import android.content.Context;
import android.net.Uri;
import android.util.Log;
import android.widget.Toast;

import androidx.annotation.NonNull;

import com.google.android.gms.tasks.OnFailureListener;
import com.google.android.gms.tasks.OnSuccessListener;
import com.google.android.gms.tasks.Task;
import com.google.mlkit.vision.barcode.BarcodeScanner;
import com.google.mlkit.vision.barcode.BarcodeScannerOptions;
import com.google.mlkit.vision.barcode.BarcodeScanning;
import com.google.mlkit.vision.barcode.common.Barcode;
import com.google.mlkit.vision.common.InputImage;

import java.io.IOException;
import java.util.List;

/**
* A class for handling the scanning and decoding of barcodes
* and updating item information accordingly
* @author Sami
*/
public class BarcodeImageScanner extends ImageScanner{

private InputImage image;
private BarcodeScanner scanner;
private Context context;
private final OnBarcodeScannedListener listener;

/**
* Constructs a new BarcodeImageScanner
* @param context context of this scanner
* @param listener listener that handles the action when barcode is scanned
*/
public BarcodeImageScanner(Context context, OnBarcodeScannedListener listener) {
this.context = context;
this.listener = listener;

}

/**
* Scans image for barcodes using Google's MLKit API and handles information extraction
* @param imageUri Image to scan
*/
@Override
public void scanImage(String imageUri) {
try {
image = InputImage.fromFilePath(context, Uri.parse(imageUri));
} catch (IOException e) {
e.printStackTrace();
}
scanner = BarcodeScanning.getClient();
Task<List<Barcode>> result = scanner.process(image)
.addOnSuccessListener(new OnSuccessListener<List<Barcode>>() {
@Override
public void onSuccess(List<Barcode> barcodes) {
selectProductInfoFromBarcode(barcodes,context);
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
Toast.makeText(context.getApplicationContext(),
("Failure in scanning barcode!"),
Toast.LENGTH_SHORT).show();
Log.e("Scanner","faied to scan");
}
});

}

/**
* Ensures that only 1 barcode was scanned and extracts the value encoded into the barcode
* Depending on the value type, lets user set it as either item description or Serial Number
* @param barcodes List of barcodes detected and scanned by the scanner
* @param context context in which the scanner is being used in the app
*/
private void selectProductInfoFromBarcode(List<Barcode> barcodes, Context context) {
if (barcodes.size() == 0) {
Toast.makeText(context.getApplicationContext(),
("No barcodes were detected. Please use a different image."),
Toast.LENGTH_LONG).show();
}
else if (barcodes.size()==1){
String productInfo = barcodes.get(0).getDisplayValue();

if (barcodes.get(0).getValueType() == 7 || barcodes.get(0).getValueType() == 5) {
new AlertDialog.Builder(context)
.setTitle("Item info from decoded barcode: ")
.setMessage(productInfo +
"\n \nDecoded value may be a serial number. Set as:")
.setPositiveButton("Description",(dialog,which)->{
listener.onBarcodeOKPressed(productInfo);
})
.setNegativeButton("Serial Number",(dialog,which)->{
listener.onSerialNumberOKPressed(productInfo);
})
.setNeutralButton("Cancel", null)
.show();
}
else {
new AlertDialog.Builder(context)
.setTitle("Item info from decoded barcode: ")
.setMessage(productInfo +
"\n \nSet info as item description?")
.setPositiveButton("YES",(dialog,which)->{
listener.onBarcodeOKPressed(productInfo);
})
.setNegativeButton("NO", null)
.show();
}

}
else {
Toast.makeText(context.getApplicationContext(),
("Multiple barcodes detected. Please choose an image with one barcode."),
Toast.LENGTH_LONG).show();
}
}

/**
* Interface to handle how the decoded value of the barcode is used after scanning
*/
public interface OnBarcodeScannedListener {
void onBarcodeOKPressed(String description);
void onSerialNumberOKPressed(String serialNumber);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@

import java.io.IOException;

/**
* A class for handling the scanning of serial numbers and updating item information accordingly
* @author Lukas
*/
public class SNImageScanner extends ImageScanner {
private Context context;
private OnImageScannedListener listener;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,15 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle sa
// Set up listeners to open the camera/gallery
Button barcodeButton = rootView.findViewById(R.id.barcode_button);
Button serialNumButton = rootView.findViewById(R.id.serialNum_button);
//barcodeButton.setOnClickListener(v -> launchImageIntent(true));
barcodeButton.setOnClickListener(v -> launchBarcodeScanner());
serialNumButton.setOnClickListener(v -> launchSerialNumScanner());
imagePickerDialog = new ImagePickerDialog();
return rootView;
}

/**
* Launches a new serial num scanner and brings up image picker dialog
* to choose the image to scan
*/
private void launchSerialNumScanner() {
SNImageScanner.OnImageScannedListener listener;
Expand All @@ -56,6 +57,22 @@ private void launchSerialNumScanner() {
imagePickerDialog.show(getChildFragmentManager(), imagePickerDialog.getTag());
}

/**
* Launches a new Barcode scanner and brings up the image picker dialog
* to choose the image to scan
*/
private void launchBarcodeScanner() {
BarcodeImageScanner.OnBarcodeScannedListener listener;
Fragment parent = requireParentFragment();
if (parent instanceof BarcodeImageScanner.OnBarcodeScannedListener) {
listener = (BarcodeImageScanner.OnBarcodeScannedListener) parent;
} else {
throw new ClassCastException(parent + " must implement OnImagePickedListener");
}
scanner = new BarcodeImageScanner(getContext(), listener);
imagePickerDialog.show(getChildFragmentManager(), imagePickerDialog.getTag());
}

/**
* Scans a given image using the appropriate scanner
* @param imageUri uri of the image to scan
Expand Down
6 changes: 4 additions & 2 deletions app/src/main/res/layout/dialog_photo_choices.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,12 @@
android:layout_height="wrap_content"
android:paddingHorizontal="24dp"
android:text="Take photo"
android:textSize="24sp"
android:textAlignment="textStart"
android:textColor="@color/white"
app:icon="@drawable/baseline_camera_alt_24"
app:iconGravity="textStart"
app:iconSize="24dp"
app:iconSize="32dp"
app:iconTint="@color/white" />

<com.google.android.material.divider.MaterialDivider
Expand All @@ -30,12 +31,13 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingHorizontal="24dp"
android:textSize="24sp"
android:text="Select from gallery"
android:textAlignment="textStart"
android:textColor="@color/white"
app:icon="@drawable/baseline_insert_photo_24"
app:iconGravity="textStart"
app:iconSize="24dp"
app:iconSize="32dp"
app:iconTint="@color/white" />

</LinearLayout>
8 changes: 5 additions & 3 deletions app/src/main/res/layout/dialog_scanning_choices.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@
android:textAlignment="textStart"
android:textColor="@color/white"
app:icon="@drawable/number_sign_icon"
android:textSize="24sp"
app:iconGravity="textStart"
app:iconSize="24dp"
app:iconSize="32dp"
app:iconTint="@color/white" />

<com.google.android.material.divider.MaterialDivider
Expand All @@ -30,12 +31,13 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingHorizontal="24dp"
android:text="Select from gallery"
android:text="Scan Barcode"
android:textAlignment="textStart"
android:textColor="@color/white"
app:icon="@drawable/baseline_barcode_scanner_24"
app:iconGravity="textStart"
app:iconSize="24dp"
android:textSize="24sp"
app:iconSize="32dp"
app:iconTint="@color/white" />

</LinearLayout>

0 comments on commit 520bd7a

Please sign in to comment.