I'm following the quickstart-android repo for ML Kit barcode scanning. In my implementation, I am noticing that in the onSuccess callback is triggered when I first launch my camera to detect barcodes, which is fine. However, the barcodes list itself is empty when I hold the camera up to valid barcodes. The onSuccess callback is called, but the barcode list is empty.
When I background the app, then foreground it, then the barcodes list starts being populated (barcodes.size() is no longer zero).
Does anyone have any idea why this would be happening?
final FirebaseVisionImage firebaseImage =
FirebaseVisionImage.fromMediaImage(image, rotation);
FirebaseVisionBarcodeDetectorOptions options = new
FirebaseVisionBarcodeDetectorOptions.Builder().setBarcodeFormats(
FirebaseVisionBarcode.FORMAT_ALL_FORMATS).build();
barcodeDetector = FirebaseVision.getInstance().getVisionBarcodeDetector(options)
barcodeDetector.detectInImage(firebaseImage).addOnSuccessListener((barcodes) ->
{
// note that the success callback is called and I do get here
// but barcode list is empty initially
for (FirebaseVisionBarcode barcode : barcodes)
{
// we never get here since barcodes.size() is 0
// until I background the app, then foreground it
// after backgrounding, then foregrounding, we start
// detecting barcodes
}
}).addOnFailureListener((exception) -> {
//TODO: handle failure
});
Related
I was looking at the flow documentation on the Android Developer site and I have a question.
https://developer.android.com/kotlin/flow#callback
If you look at the above link, you will see code like this.
class FirestoreUserEventsDataSource(
private val firestore: FirebaseFirestore
) {
// Method to get user events from the Firestore database
fun getUserEvents(): Flow<UserEvents> = callbackFlow {
// Reference to use in Firestore
var eventsCollection: CollectionReference? = null
try {
eventsCollection = FirebaseFirestore.getInstance()
.collection("collection")
.document("app")
} catch (e: Throwable) {
// If Firebase cannot be initialized, close the stream of data
// flow consumers will stop collecting and the coroutine will resume
close(e)
}
// Registers callback to firestore, which will be called on new events
val subscription = eventsCollection?.addSnapshotListener { snapshot, _ ->
if (snapshot == null) { return#addSnapshotListener }
// Sends events to the flow! Consumers will get the new events
try {
offer(snapshot.getEvents())
} catch (e: Throwable) {
// Event couldn't be sent to the flow
}
}
// The callback inside awaitClose will be executed when the flow is
// either closed or cancelled.
// In this case, remove the callback from Firestore
awaitClose { subscription?.remove() }
}
}
In the code above, awaitClose is explained to be executed when the coroutine is closed or cancelled.
But, there is no close() in the code except for the try-catch statement that initializes the eventsCollection.
Additionally, says offer does not add the element to the channel and **returns false** immediately at the bottom of the Android Developer page.
My question is, in the code above, when offer(snapshot.getEvents()) is executed, does the coroutine cancel with return false, so awaitClose is executed?
Expectation:
As the documentation says:
When you try to add a new element to a full channel, send suspends the
producer until there's space for the new element, whereas offer does
not add the element to the channel and returns false immediately.
Ergo:
It Immediately adds the specified element to this channel, if this doesn’t violate its capacity restrictions, and returns the successful result. Otherwise, returns failed or closed result. This is synchronous variant of send, which backs off in situations when send suspends or throws.
So when trySend call returns a non-successful result, it guarantees that the element was not delivered to the consumer, and it does not call onUndeliveredElement that was installed for this channel. See “Undelivered elements” section in Channel documentation for details on handling undelivered elements.
Conclusion:
A typical usage for onDeliveredElement is to close a resource that is being transferred via the channel. The following code pattern guarantees that opened resources are closed even if producer, consumer, and/or channel are cancelled. Resources are never lost. So no it doesn't return false.
I am trying to implement manual focus on CameraX. but i don't know how to check that where startFocusAndMetering completed or not.
I tried something like this
val focusListenableFuture = camera?.cameraControl?.startFocusAndMetering(action)
I found that there is a method isDone() which can check weather focusing completed or not
how can i use it with focusListenableFuture?.addListener() to listen weather focusing completed or not
You can use FocusMeteringResult#isFocusSuccessful():
Returns if auto focus is successful.
If AF is requested in FocusMeteringAction but current camera does not
support AF, it will return true. If AF is not requested, it will
return false.
val focusListenableFuture = camera?.cameraControl?.startFocusAndMetering(action)
focusListenableFuture.addListener( {
val result = focusListenableFuture.get()
val isSuccessful = result.isFocusSuccessful
}, ContextCompat.getMainExecutor(context))
In my app for Zebra MC330M I use EMDK: Zebra Technologies Corp:EMDK APIs:26
I have a activity that implements listener and I override onOpened function:
#Override
public void onOpened(EMDKManager emdkManager) {
this.emdkManager = emdkManager;
try {
initializeScanner();
} catch (ScannerException e) {
Log.e("ON_OPENED", e.getMessage());
e.printStackTrace();
}
}
And as documentation said in Link: Basic Scanning Tutorial using Barcode API - Zebra Technologies Techdocs
I put in the initializeScanner function:
if (scanner == null) {
// Get the Barcode Manager object
barcodeManager = (BarcodeManager) emdkManager.getInstance(FEATURE_TYPE.BARCODE);
// Add connection listener
if (barcodeManager != null) {
barcodeManager.addConnectionListener(this);
}
// Get default scanner defined on the device
scanner = barcodeManager.getDevice(BarcodeManager.DeviceIdentifier.DEFAULT);
// Add data and status listeners
scanner.addDataListener(this);
scanner.addStatusListener(this);
// Hard trigger. When this mode is set, the user has to manually
// press the trigger on the device after issuing the read call.
scanner.triggerType = TriggerType.HARD;
// Enable the scanner
scanner.enable();
startRead = true;
}
But when call scanner.enable() it throws
ScannerException
exception with message:
"Failure"
But seems that error is shown only in debug mode when I try to compile my app and launch when device is standby mode or when the device is in standby for many time.
Someone else has this problem?
I've used successfully the ContinuousScan from ZXing for xamarin using mvvmcross, I just press a button in one of my viewmodels and the camera show up. I used a delay between continuous scans I of 4000 to allow the user to read the barcodes at a slow pace. The first time enter to the view model and enter to the scanner, everything works perfect. Then I press back and i have a list with the codes, I press back again and leave the view model. I enter again to the view model and open the scanner and it just barely has focus on a barcode and it scans it two or three times without waiting for the 4000ms delay that originally was set to it. What am i missing here?
public MvxCommand ObtainCommand()
{
return new MvxCommand(delegate
{
if (HandleScanResultEvent != null) HandleScanResultEvent(this, null);
MobileBarcodeScanner.Initialize(Application);
var scanner = new MobileBarcodeScanner();
scanner.UseCustomOverlay = false;
scanner.TopText = Ts.TopTextScanContiniously;
scanner.BottomText = Ts.BottomTextScan;
var opt = new MobileBarcodeScanningOptions();
opt.DelayBetweenContinuousScans = 5000;
//Start scanning
scanner.ScanContinuously(opt, HandleScanResult);
});
}
The Handle result raise an event to the view model with the barcode read.
void HandleScanResult(ZXing.Result r)
{
if (r != null)
{
var opa = new OperationArgument
{
Operation = new Operation
{
Data r.Text,
Format = FromXingFormat(r.BarcodeFormat)
}
};
if (DataObtained != null && !(String.IsNullOrWhiteSpace(r.Text)))
{
DataObtained(this, opa);
}
}
}
the barcode scanner is opened via an mvxCommand assigned to the viewmodel. The posted code is in a class registered as a singleton.
I am evaluating the Multi-Tracker sample and I want to get hold of the RawValue of the barcode detector once one is available.
I would like to dismiss the Tracker once a valid RawValue has been obtained and use the value elsewhere.
Any suggestions on the items below will be helpful.
How to dismiss the tracker once a detection has been made
How to hold and pass the RawValue up the the activity. For example, echo it in a Toast
Thanks
See the discussion in this thread about passing the RawValue to the activity:
How to capture barcode values using the new Barcode API in Google Play Services?
The tracker is active as long as the associated CameraSource/Detector is active (i.e., the release() method has not been called). But if you want to avoid receiving updates beyond the initial detection, you could have the tracker suppress sending updates beyond the first one. For example:
#Override
public void onUpdate(Detector.Detections<Barcode> detectionResults, Barcode item) {
if (!mFoundCalled) {
mCallback.onFound(item.rawValue);
mFoundCalled = true;
}
...
}
And you also can use the callback in: onNewItem
#Override
public void onNewItem(int id, Barcode item) {
mGraphic.setId(id);
callback.onBarcodeFound(item.rawValue);
}