From 8c488d607ed277beebf429ad4a2874a19878a718 Mon Sep 17 00:00:00 2001 From: Nguyen Ngoc Long Date: Thu, 11 Sep 2025 11:06:31 +0700 Subject: [PATCH 1/2] fix-anr-when-checking-if-model-downloaded --- .../GenericModelManager.java | 118 +++++++++------ .../DigitalInkRecognizer.java | 140 ++++++++++-------- .../ImageLabelDetector.java | 71 ++++++--- .../ObjectDetector.java | 95 +++++++----- 4 files changed, 256 insertions(+), 168 deletions(-) diff --git a/packages/google_mlkit_commons/android/src/main/java/com/google_mlkit_commons/GenericModelManager.java b/packages/google_mlkit_commons/android/src/main/java/com/google_mlkit_commons/GenericModelManager.java index 6cd19193..4761fa3b 100644 --- a/packages/google_mlkit_commons/android/src/main/java/com/google_mlkit_commons/GenericModelManager.java +++ b/packages/google_mlkit_commons/android/src/main/java/com/google_mlkit_commons/GenericModelManager.java @@ -1,17 +1,9 @@ package com.google_mlkit_commons; -import com.google.android.gms.tasks.Task; -import com.google.android.gms.tasks.Tasks; import com.google.mlkit.common.model.DownloadConditions; import com.google.mlkit.common.model.RemoteModel; import com.google.mlkit.common.model.RemoteModelManager; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; - import io.flutter.plugin.common.MethodCall; import io.flutter.plugin.common.MethodChannel; @@ -20,16 +12,25 @@ public class GenericModelManager { private static final String DELETE = "delete"; private static final String CHECK = "check"; - public RemoteModelManager remoteModelManager = RemoteModelManager.getInstance(); + public interface CheckModelIsDownloadedCallback { + void onModelDownloaded(Boolean isDownloaded); + + void onError(Exception e); + } - //To avoid downloading models in the main thread as they are around 20MB and may crash the app. - private final ExecutorService executorService = Executors.newCachedThreadPool(); + public RemoteModelManager remoteModelManager = RemoteModelManager.getInstance(); public void manageModel(final RemoteModel model, final MethodCall call, final MethodChannel.Result result) { String task = call.argument("task"); + + if (task == null) { + result.notImplemented(); + return; + } + switch (task) { case DOWNLOAD: - boolean isWifiReqRequired = call.argument("wifi"); + boolean isWifiReqRequired = Boolean.TRUE.equals(call.argument("wifi")); DownloadConditions downloadConditions; if (isWifiReqRequired) downloadConditions = new DownloadConditions.Builder().requireWifi().build(); @@ -41,9 +42,20 @@ public void manageModel(final RemoteModel model, final MethodCall call, final Me deleteModel(model, result); break; case CHECK: - Boolean downloaded = isModelDownloaded(model); - if (downloaded != null) result.success(downloaded); - else result.error("error", null, null); + isModelDownloaded( + model, + new CheckModelIsDownloadedCallback() { + @Override + public void onModelDownloaded(Boolean isDownloaded) { + result.success(isDownloaded); + } + + @Override + public void onError(Exception e) { + result.error("error", e.toString(), null); + } + } + ); break; default: result.notImplemented(); @@ -51,42 +63,56 @@ public void manageModel(final RemoteModel model, final MethodCall call, final Me } public void downloadModel(RemoteModel remoteModel, DownloadConditions downloadConditions, final MethodChannel.Result result) { - if (isModelDownloaded(remoteModel)) { - result.success("success"); - return; - } - remoteModelManager.download(remoteModel, downloadConditions).addOnSuccessListener(aVoid -> result.success("success")).addOnFailureListener(e -> result.error("error", e.toString(), null)); - } + isModelDownloaded( + remoteModel, + new CheckModelIsDownloadedCallback() { + @Override + public void onModelDownloaded(Boolean isDownloaded) { + if (isDownloaded) { + result.success("success"); + return; + } - public void deleteModel(RemoteModel remoteModel, final MethodChannel.Result result) { - if (!isModelDownloaded(remoteModel)) { - result.success("success"); - return; - } - remoteModelManager.deleteDownloadedModel(remoteModel).addOnSuccessListener(aVoid -> result.success("success")).addOnFailureListener(e -> result.error("error", e.toString(), null)); - } + remoteModelManager.download(remoteModel, downloadConditions) + .addOnSuccessListener(aVoid -> result.success("success")) + .addOnFailureListener(e -> result.error("error", e.toString(), null)); + } - public Boolean isModelDownloaded(RemoteModel model) { - IsModelDownloaded myCallable = new IsModelDownloaded(remoteModelManager.isModelDownloaded(model)); - Future taskResult = executorService.submit(myCallable); - try { - return taskResult.get(); - } catch (InterruptedException | ExecutionException e) { - e.printStackTrace(); - } - return null; + @Override + public void onError(Exception e) { + result.error("error", e.toString(), null); + } + } + ); } -} -class IsModelDownloaded implements Callable { - final Task booleanTask; + public void deleteModel(RemoteModel remoteModel, final MethodChannel.Result result) { + isModelDownloaded(remoteModel, new CheckModelIsDownloadedCallback() { + @Override + public void onModelDownloaded(Boolean isDownloaded) { + if (!isDownloaded) { + result.success("success"); + return; + } + remoteModelManager.deleteDownloadedModel(remoteModel) + .addOnSuccessListener(aVoid -> result.success("success")) + .addOnFailureListener(e -> result.error("error", e.toString(), null)); + } - public IsModelDownloaded(Task booleanTask) { - this.booleanTask = booleanTask; + @Override + public void onError(Exception e) { + result.error("error", e.toString(), null); + } + }); } - @Override - public Boolean call() throws Exception { - return Tasks.await(booleanTask); + public void isModelDownloaded(RemoteModel model, CheckModelIsDownloadedCallback callback) { + try { + remoteModelManager.isModelDownloaded(model) + .addOnFailureListener(e -> callback.onError(e)) + .addOnSuccessListener(isDownloaded -> callback.onModelDownloaded(isDownloaded)); + } catch (Exception e) { + callback.onError(e); + } } -} +} \ No newline at end of file diff --git a/packages/google_mlkit_digital_ink_recognition/android/src/main/java/com/google_mlkit_digital_ink_recognition/DigitalInkRecognizer.java b/packages/google_mlkit_digital_ink_recognition/android/src/main/java/com/google_mlkit_digital_ink_recognition/DigitalInkRecognizer.java index 14005216..2afd39a6 100644 --- a/packages/google_mlkit_digital_ink_recognition/android/src/main/java/com/google_mlkit_digital_ink_recognition/DigitalInkRecognizer.java +++ b/packages/google_mlkit_digital_ink_recognition/android/src/main/java/com/google_mlkit_digital_ink_recognition/DigitalInkRecognizer.java @@ -54,71 +54,85 @@ private void handleDetection(MethodCall call, final MethodChannel.Result result) DigitalInkRecognitionModel model = getModel(tag, result); if (model == null) return; - if (!genericModelManager.isModelDownloaded(model)) { - result.error("Model Error", "Model has not been downloaded yet ", null); - return; - } - - String id = call.argument("id"); - com.google.mlkit.vision.digitalink.DigitalInkRecognizer recognizer = instances.get(id); - if (recognizer == null) { - recognizer = DigitalInkRecognition.getClient(DigitalInkRecognizerOptions.builder(model).build()); - instances.put(id, recognizer); - } - Map inkMap = call.argument("ink"); - List> strokeList = (List>) inkMap.get("strokes"); - Ink.Builder inkBuilder = Ink.builder(); - for (final Map strokeMap : strokeList) { - Ink.Stroke.Builder strokeBuilder = Ink.Stroke.builder(); - List> pointsList = (List>) strokeMap.get("points"); - for (final Map point : pointsList) { - float x = (float) (double) point.get("x"); - float y = (float) (double) point.get("y"); - Object t0 = point.get("t"); - long t; - if (t0 instanceof Integer) { - t = (int) t0; - } else { - t = (long) t0; + genericModelManager.isModelDownloaded( + model, + new GenericModelManager.CheckModelIsDownloadedCallback() { + @Override + public void onModelDownloaded(Boolean isDownloaded) { + if (!isDownloaded) { + result.error("Model Error", "Model has not been downloaded yet ", null); + return; + } + + String id = call.argument("id"); + com.google.mlkit.vision.digitalink.DigitalInkRecognizer recognizer = instances.get(id); + if (recognizer == null) { + recognizer = DigitalInkRecognition.getClient(DigitalInkRecognizerOptions.builder(model).build()); + instances.put(id, recognizer); + } + + Map inkMap = call.argument("ink"); + List> strokeList = (List>) inkMap.get("strokes"); + Ink.Builder inkBuilder = Ink.builder(); + for (final Map strokeMap : strokeList) { + Ink.Stroke.Builder strokeBuilder = Ink.Stroke.builder(); + List> pointsList = (List>) strokeMap.get("points"); + for (final Map point : pointsList) { + float x = (float) (double) point.get("x"); + float y = (float) (double) point.get("y"); + Object t0 = point.get("t"); + long t; + if (t0 instanceof Integer) { + t = (int) t0; + } else { + t = (long) t0; + } + Ink.Point strokePoint = Ink.Point.create(x, y, t); + strokeBuilder.addPoint(strokePoint); + } + inkBuilder.addStroke(strokeBuilder.build()); + } + Ink ink = inkBuilder.build(); + + RecognitionContext context = null; + Map contextMap = call.argument("context"); + if (contextMap != null) { + RecognitionContext.Builder builder = RecognitionContext.builder(); + String preContext = (String) contextMap.get("preContext"); + if (preContext != null) { + builder.setPreContext(preContext); + } else { + builder.setPreContext(""); + } + + Map writingAreaMap = (Map) contextMap.get("writingArea"); + if (writingAreaMap != null) { + float width = (float) (double) writingAreaMap.get("width"); + float height = (float) (double) writingAreaMap.get("height"); + builder.setWritingArea(new WritingArea(width, height)); + } + + context = builder.build(); + } + + if (context != null) { + recognizer.recognize(ink, context) + .addOnSuccessListener(recognitionResult -> process(recognitionResult, result)) + .addOnFailureListener(e -> result.error("recognition Error", e.toString(), null)); + } else { + recognizer.recognize(ink) + .addOnSuccessListener(recognitionResult -> process(recognitionResult, result)) + .addOnFailureListener(e -> result.error("recognition Error", e.toString(), null)); + } + } + + @Override + public void onError(Exception e) { + result.error("error", e.toString(), null); + } } - Ink.Point strokePoint = Ink.Point.create(x, y, t); - strokeBuilder.addPoint(strokePoint); - } - inkBuilder.addStroke(strokeBuilder.build()); - } - Ink ink = inkBuilder.build(); - - RecognitionContext context = null; - Map contextMap = call.argument("context"); - if (contextMap != null) { - RecognitionContext.Builder builder = RecognitionContext.builder(); - String preContext = (String) contextMap.get("preContext"); - if (preContext != null) { - builder.setPreContext(preContext); - } else { - builder.setPreContext(""); - } - - Map writingAreaMap = (Map) contextMap.get("writingArea"); - if (writingAreaMap != null) { - float width = (float) (double) writingAreaMap.get("width"); - float height = (float) (double) writingAreaMap.get("height"); - builder.setWritingArea(new WritingArea(width, height)); - } - - context = builder.build(); - } - - if (context != null) { - recognizer.recognize(ink, context) - .addOnSuccessListener(recognitionResult -> process(recognitionResult, result)) - .addOnFailureListener(e -> result.error("recognition Error", e.toString(), null)); - } else { - recognizer.recognize(ink) - .addOnSuccessListener(recognitionResult -> process(recognitionResult, result)) - .addOnFailureListener(e -> result.error("recognition Error", e.toString(), null)); - } + ); } private void process(RecognitionResult recognitionResult, final MethodChannel.Result result) { diff --git a/packages/google_mlkit_image_labeling/android/src/main/java/com/google_mlkit_image_labeling/ImageLabelDetector.java b/packages/google_mlkit_image_labeling/android/src/main/java/com/google_mlkit_image_labeling/ImageLabelDetector.java index 16a4729d..40c61c75 100644 --- a/packages/google_mlkit_image_labeling/android/src/main/java/com/google_mlkit_image_labeling/ImageLabelDetector.java +++ b/packages/google_mlkit_image_labeling/android/src/main/java/com/google_mlkit_image_labeling/ImageLabelDetector.java @@ -79,12 +79,53 @@ private void handleDetection(MethodCall call, final MethodChannel.Result result) CustomImageLabelerOptions labelerOptions = getLocalOptions(options); imageLabeler = ImageLabeling.getClient(labelerOptions); } else if (type.equals("remote")) { - CustomImageLabelerOptions labelerOptions = getRemoteOptions(options); - if (labelerOptions == null) { - result.error("Error Model has not been downloaded yet", "Model has not been downloaded yet", "Model has not been downloaded yet"); - return; - } - imageLabeler = ImageLabeling.getClient(labelerOptions); + float confidenceThreshold = (float) (double) options.get("confidenceThreshold"); + int maxCount = (int) options.get("maxCount"); + String name = (String) options.get("modelName"); + + FirebaseModelSource firebaseModelSource = new FirebaseModelSource.Builder(name).build(); + CustomRemoteModel remoteModel = new CustomRemoteModel.Builder(firebaseModelSource).build(); + + genericModelManager.isModelDownloaded( + remoteModel, + new GenericModelManager.CheckModelIsDownloadedCallback() { + @Override + public void onModelDownloaded(Boolean isDownloaded) { + if (!isDownloaded) { + result.error("Error Model has not been downloaded yet", "Model has not been downloaded yet", "Model has not been downloaded yet"); + return; + } + + CustomImageLabelerOptions labelerOptions = new CustomImageLabelerOptions.Builder(remoteModel) + .setConfidenceThreshold(confidenceThreshold) + .setMaxResultCount(maxCount) + .build(); + + ImageLabeling.getClient(labelerOptions).process(inputImage) + .addOnSuccessListener(imageLabels -> { + List> labels = new ArrayList<>(imageLabels.size()); + for (ImageLabel label : imageLabels) { + Map labelData = new HashMap<>(); + labelData.put("text", label.getText()); + labelData.put("confidence", label.getConfidence()); + labelData.put("index", label.getIndex()); + labels.add(labelData); + } + + result.success(labels); + }) + .addOnFailureListener(e -> result.error("ImageLabelDetectorError", e.toString(), null)); + ; + } + + @Override + public void onError(Exception e) { + result.error("Error", e.getMessage(), e); + } + } + ); + + return; } else { String error = "Invalid model type: " + type; result.error(type, error, error); @@ -131,24 +172,6 @@ private CustomImageLabelerOptions getLocalOptions(Map labelerOpt .build(); } - //Options for labeler to work with custom model. - private CustomImageLabelerOptions getRemoteOptions(Map labelerOptions) { - float confidenceThreshold = (float) (double) labelerOptions.get("confidenceThreshold"); - int maxCount = (int) labelerOptions.get("maxCount"); - String name = (String) labelerOptions.get("modelName"); - - FirebaseModelSource firebaseModelSource = new FirebaseModelSource.Builder(name).build(); - CustomRemoteModel remoteModel = new CustomRemoteModel.Builder(firebaseModelSource).build(); - if (!genericModelManager.isModelDownloaded(remoteModel)) { - return null; - } - - return new CustomImageLabelerOptions.Builder(remoteModel) - .setConfidenceThreshold(confidenceThreshold) - .setMaxResultCount(maxCount) - .build(); - } - private void closeDetector(MethodCall call) { String id = call.argument("id"); ImageLabeler imageLabeler = instances.get(id); diff --git a/packages/google_mlkit_object_detection/android/src/main/java/com/google_mlkit_object_detection/ObjectDetector.java b/packages/google_mlkit_object_detection/android/src/main/java/com/google_mlkit_object_detection/ObjectDetector.java index f15cc4ab..19b5a513 100644 --- a/packages/google_mlkit_object_detection/android/src/main/java/com/google_mlkit_object_detection/ObjectDetector.java +++ b/packages/google_mlkit_object_detection/android/src/main/java/com/google_mlkit_object_detection/ObjectDetector.java @@ -58,7 +58,7 @@ public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result } private void handleDetection(MethodCall call, final MethodChannel.Result result) { - Map imageData = (Map) call.argument("imageData"); + Map imageData = call.argument("imageData"); InputImage inputImage = InputImageConverter.getInputImageFromData(imageData, context, result); if (inputImage == null) return; @@ -79,12 +79,65 @@ private void handleDetection(MethodCall call, final MethodChannel.Result result) CustomObjectDetectorOptions detectorOptions = getLocalOptions(options); objectDetector = ObjectDetection.getClient(detectorOptions); } else if (type.equals("remote")) { - CustomObjectDetectorOptions detectorOptions = getRemoteOptions(options); - if (detectorOptions == null) { - result.error("Error Model has not been downloaded yet", "Model has not been downloaded yet", "Model has not been downloaded yet"); - return; - } - objectDetector = ObjectDetection.getClient(detectorOptions); + int mode = (int) options.get("mode"); + int finalMode = mode == 0 ? + CustomObjectDetectorOptions.STREAM_MODE : + CustomObjectDetectorOptions.SINGLE_IMAGE_MODE; + boolean classify = (boolean) options.get("classify"); + boolean multiple = (boolean) options.get("multiple"); + double threshold = (double) options.get("threshold"); + int maxLabels = (int) options.get("maxLabels"); + String name = (String) options.get("modelName"); + + FirebaseModelSource firebaseModelSource = new FirebaseModelSource.Builder(name) + .build(); + CustomRemoteModel remoteModel = new CustomRemoteModel.Builder(firebaseModelSource) + .build(); + + genericModelManager.isModelDownloaded( + remoteModel, + new GenericModelManager.CheckModelIsDownloadedCallback() { + @Override + public void onModelDownloaded(Boolean isDownloaded) { + if (!isDownloaded) { + result.error("Error Model has not been downloaded yet", "Model has not been downloaded yet", "Model has not been downloaded yet"); + return; + } + + CustomObjectDetectorOptions.Builder builder = new CustomObjectDetectorOptions.Builder(remoteModel) + .setDetectorMode(finalMode) + .setMaxPerObjectLabelCount(maxLabels) + .setClassificationConfidenceThreshold((float) threshold); + if (classify) builder.enableClassification(); + if (multiple) builder.enableMultipleObjects(); + + CustomObjectDetectorOptions customObjectDetectorOptions = builder.build(); + + ObjectDetection.getClient(customObjectDetectorOptions).process(inputImage).addOnSuccessListener(detectedObjects -> { + List> objects = new ArrayList<>(); + for (DetectedObject detectedObject : detectedObjects) { + Map objectMap = new HashMap<>(); + addData(objectMap, + detectedObject.getTrackingId(), + detectedObject.getBoundingBox(), + detectedObject.getLabels()); + objects.add(objectMap); + } + result.success(objects); + }).addOnFailureListener(e -> { + e.printStackTrace(); + result.error("ObjectDetectionError", e.toString(), null); + }); + } + + @Override + public void onError(Exception e) { + + } + } + ); + + return; } else { String error = "Invalid model type: " + type; result.error(type, error, error); @@ -149,34 +202,6 @@ private CustomObjectDetectorOptions getLocalOptions(Map options) return builder.build(); } - private CustomObjectDetectorOptions getRemoteOptions(Map options) { - int mode = (int) options.get("mode"); - mode = mode == 0 ? - CustomObjectDetectorOptions.STREAM_MODE : - CustomObjectDetectorOptions.SINGLE_IMAGE_MODE; - boolean classify = (boolean) options.get("classify"); - boolean multiple = (boolean) options.get("multiple"); - double threshold = (double) options.get("threshold"); - int maxLabels = (int) options.get("maxLabels"); - String name = (String) options.get("modelName"); - - FirebaseModelSource firebaseModelSource = new FirebaseModelSource.Builder(name) - .build(); - CustomRemoteModel remoteModel = new CustomRemoteModel.Builder(firebaseModelSource) - .build(); - if (!genericModelManager.isModelDownloaded(remoteModel)) { - return null; - } - - CustomObjectDetectorOptions.Builder builder = new CustomObjectDetectorOptions.Builder(remoteModel); - builder.setDetectorMode(mode); - if (classify) builder.enableClassification(); - if (multiple) builder.enableMultipleObjects(); - builder.setMaxPerObjectLabelCount(maxLabels); - builder.setClassificationConfidenceThreshold((float) threshold); - return builder.build(); - } - private void addData(Map addTo, Integer trackingId, Rect rect, From 023f83ea07e8ca58675c146b7569e5d5725bf8c0 Mon Sep 17 00:00:00 2001 From: Nguyen Ngoc Long Date: Fri, 12 Sep 2025 10:16:56 +0700 Subject: [PATCH 2/2] update lints --- .../GenericModelManager.java | 14 +- .../DigitalInkRecognizer.java | 134 ++++++++++-------- .../ImageLabelDetector.java | 38 +++-- .../ObjectDetector.java | 32 ++--- 4 files changed, 109 insertions(+), 109 deletions(-) diff --git a/packages/google_mlkit_commons/android/src/main/java/com/google_mlkit_commons/GenericModelManager.java b/packages/google_mlkit_commons/android/src/main/java/com/google_mlkit_commons/GenericModelManager.java index 4761fa3b..6b3a45e6 100644 --- a/packages/google_mlkit_commons/android/src/main/java/com/google_mlkit_commons/GenericModelManager.java +++ b/packages/google_mlkit_commons/android/src/main/java/com/google_mlkit_commons/GenericModelManager.java @@ -13,7 +13,7 @@ public class GenericModelManager { private static final String CHECK = "check"; public interface CheckModelIsDownloadedCallback { - void onModelDownloaded(Boolean isDownloaded); + void onCheckResult(Boolean isDownloaded); void onError(Exception e); } @@ -30,7 +30,7 @@ public void manageModel(final RemoteModel model, final MethodCall call, final Me switch (task) { case DOWNLOAD: - boolean isWifiReqRequired = Boolean.TRUE.equals(call.argument("wifi")); + boolean isWifiReqRequired = call.argument("wifi"); DownloadConditions downloadConditions; if (isWifiReqRequired) downloadConditions = new DownloadConditions.Builder().requireWifi().build(); @@ -46,7 +46,7 @@ public void manageModel(final RemoteModel model, final MethodCall call, final Me model, new CheckModelIsDownloadedCallback() { @Override - public void onModelDownloaded(Boolean isDownloaded) { + public void onCheckResult(Boolean isDownloaded) { result.success(isDownloaded); } @@ -67,7 +67,7 @@ public void downloadModel(RemoteModel remoteModel, DownloadConditions downloadCo remoteModel, new CheckModelIsDownloadedCallback() { @Override - public void onModelDownloaded(Boolean isDownloaded) { + public void onCheckResult(Boolean isDownloaded) { if (isDownloaded) { result.success("success"); return; @@ -89,7 +89,7 @@ public void onError(Exception e) { public void deleteModel(RemoteModel remoteModel, final MethodChannel.Result result) { isModelDownloaded(remoteModel, new CheckModelIsDownloadedCallback() { @Override - public void onModelDownloaded(Boolean isDownloaded) { + public void onCheckResult(Boolean isDownloaded) { if (!isDownloaded) { result.success("success"); return; @@ -109,8 +109,8 @@ public void onError(Exception e) { public void isModelDownloaded(RemoteModel model, CheckModelIsDownloadedCallback callback) { try { remoteModelManager.isModelDownloaded(model) - .addOnFailureListener(e -> callback.onError(e)) - .addOnSuccessListener(isDownloaded -> callback.onModelDownloaded(isDownloaded)); + .addOnFailureListener(callback::onError) + .addOnSuccessListener(callback::onCheckResult); } catch (Exception e) { callback.onError(e); } diff --git a/packages/google_mlkit_digital_ink_recognition/android/src/main/java/com/google_mlkit_digital_ink_recognition/DigitalInkRecognizer.java b/packages/google_mlkit_digital_ink_recognition/android/src/main/java/com/google_mlkit_digital_ink_recognition/DigitalInkRecognizer.java index 2afd39a6..e100fe4c 100644 --- a/packages/google_mlkit_digital_ink_recognition/android/src/main/java/com/google_mlkit_digital_ink_recognition/DigitalInkRecognizer.java +++ b/packages/google_mlkit_digital_ink_recognition/android/src/main/java/com/google_mlkit_digital_ink_recognition/DigitalInkRecognizer.java @@ -59,82 +59,90 @@ private void handleDetection(MethodCall call, final MethodChannel.Result result) model, new GenericModelManager.CheckModelIsDownloadedCallback() { @Override - public void onModelDownloaded(Boolean isDownloaded) { + public void onCheckResult(Boolean isDownloaded) { if (!isDownloaded) { result.error("Model Error", "Model has not been downloaded yet ", null); return; } - String id = call.argument("id"); - com.google.mlkit.vision.digitalink.DigitalInkRecognizer recognizer = instances.get(id); - if (recognizer == null) { - recognizer = DigitalInkRecognition.getClient(DigitalInkRecognizerOptions.builder(model).build()); - instances.put(id, recognizer); - } - - Map inkMap = call.argument("ink"); - List> strokeList = (List>) inkMap.get("strokes"); - Ink.Builder inkBuilder = Ink.builder(); - for (final Map strokeMap : strokeList) { - Ink.Stroke.Builder strokeBuilder = Ink.Stroke.builder(); - List> pointsList = (List>) strokeMap.get("points"); - for (final Map point : pointsList) { - float x = (float) (double) point.get("x"); - float y = (float) (double) point.get("y"); - Object t0 = point.get("t"); - long t; - if (t0 instanceof Integer) { - t = (int) t0; - } else { - t = (long) t0; - } - Ink.Point strokePoint = Ink.Point.create(x, y, t); - strokeBuilder.addPoint(strokePoint); - } - inkBuilder.addStroke(strokeBuilder.build()); - } - Ink ink = inkBuilder.build(); - - RecognitionContext context = null; - Map contextMap = call.argument("context"); - if (contextMap != null) { - RecognitionContext.Builder builder = RecognitionContext.builder(); - String preContext = (String) contextMap.get("preContext"); - if (preContext != null) { - builder.setPreContext(preContext); - } else { - builder.setPreContext(""); - } - - Map writingAreaMap = (Map) contextMap.get("writingArea"); - if (writingAreaMap != null) { - float width = (float) (double) writingAreaMap.get("width"); - float height = (float) (double) writingAreaMap.get("height"); - builder.setWritingArea(new WritingArea(width, height)); - } - - context = builder.build(); - } - - if (context != null) { - recognizer.recognize(ink, context) - .addOnSuccessListener(recognitionResult -> process(recognitionResult, result)) - .addOnFailureListener(e -> result.error("recognition Error", e.toString(), null)); - } else { - recognizer.recognize(ink) - .addOnSuccessListener(recognitionResult -> process(recognitionResult, result)) - .addOnFailureListener(e -> result.error("recognition Error", e.toString(), null)); - } + handleInkDetectionIfModelDownloaded(call, result, model); } @Override public void onError(Exception e) { - result.error("error", e.toString(), null); + result.error("Model download check failed", e.toString(), e); } } ); } + private void handleInkDetectionIfModelDownloaded( + MethodCall call, + final MethodChannel.Result result, + DigitalInkRecognitionModel model + ) { + String id = call.argument("id"); + com.google.mlkit.vision.digitalink.DigitalInkRecognizer recognizer = instances.get(id); + if (recognizer == null) { + recognizer = DigitalInkRecognition.getClient(DigitalInkRecognizerOptions.builder(model).build()); + instances.put(id, recognizer); + } + + Map inkMap = call.argument("ink"); + List> strokeList = (List>) inkMap.get("strokes"); + Ink.Builder inkBuilder = Ink.builder(); + for (final Map strokeMap : strokeList) { + Ink.Stroke.Builder strokeBuilder = Ink.Stroke.builder(); + List> pointsList = (List>) strokeMap.get("points"); + for (final Map point : pointsList) { + float x = (float) (double) point.get("x"); + float y = (float) (double) point.get("y"); + Object t0 = point.get("t"); + long t; + if (t0 instanceof Integer) { + t = (int) t0; + } else { + t = (long) t0; + } + Ink.Point strokePoint = Ink.Point.create(x, y, t); + strokeBuilder.addPoint(strokePoint); + } + inkBuilder.addStroke(strokeBuilder.build()); + } + Ink ink = inkBuilder.build(); + + RecognitionContext context = null; + Map contextMap = call.argument("context"); + if (contextMap != null) { + RecognitionContext.Builder builder = RecognitionContext.builder(); + String preContext = (String) contextMap.get("preContext"); + if (preContext != null) { + builder.setPreContext(preContext); + } else { + builder.setPreContext(""); + } + + Map writingAreaMap = (Map) contextMap.get("writingArea"); + if (writingAreaMap != null) { + float width = (float) (double) writingAreaMap.get("width"); + float height = (float) (double) writingAreaMap.get("height"); + builder.setWritingArea(new WritingArea(width, height)); + } + + context = builder.build(); + } + + if (context != null) { + recognizer.recognize(ink, context) + .addOnSuccessListener(recognitionResult -> process(recognitionResult, result)) + .addOnFailureListener(e -> result.error("recognition Error", e.toString(), null)); + } else { + recognizer.recognize(ink) + .addOnSuccessListener(recognitionResult -> process(recognitionResult, result)) + .addOnFailureListener(e -> result.error("recognition Error", e.toString(), null)); + } + } + private void process(RecognitionResult recognitionResult, final MethodChannel.Result result) { List> candidatesList = new ArrayList<>(recognitionResult.getCandidates().size()); for (RecognitionCandidate candidate : recognitionResult.getCandidates()) { @@ -178,4 +186,4 @@ private DigitalInkRecognitionModel getModel(String tag, final MethodChannel.Resu } return DigitalInkRecognitionModel.builder(modelIdentifier).build(); } -} +} \ No newline at end of file diff --git a/packages/google_mlkit_image_labeling/android/src/main/java/com/google_mlkit_image_labeling/ImageLabelDetector.java b/packages/google_mlkit_image_labeling/android/src/main/java/com/google_mlkit_image_labeling/ImageLabelDetector.java index 40c61c75..93bc20e5 100644 --- a/packages/google_mlkit_image_labeling/android/src/main/java/com/google_mlkit_image_labeling/ImageLabelDetector.java +++ b/packages/google_mlkit_image_labeling/android/src/main/java/com/google_mlkit_image_labeling/ImageLabelDetector.java @@ -90,37 +90,27 @@ private void handleDetection(MethodCall call, final MethodChannel.Result result) remoteModel, new GenericModelManager.CheckModelIsDownloadedCallback() { @Override - public void onModelDownloaded(Boolean isDownloaded) { + public void onCheckResult(Boolean isDownloaded) { if (!isDownloaded) { result.error("Error Model has not been downloaded yet", "Model has not been downloaded yet", "Model has not been downloaded yet"); return; } - CustomImageLabelerOptions labelerOptions = new CustomImageLabelerOptions.Builder(remoteModel) - .setConfidenceThreshold(confidenceThreshold) - .setMaxResultCount(maxCount) - .build(); - - ImageLabeling.getClient(labelerOptions).process(inputImage) - .addOnSuccessListener(imageLabels -> { - List> labels = new ArrayList<>(imageLabels.size()); - for (ImageLabel label : imageLabels) { - Map labelData = new HashMap<>(); - labelData.put("text", label.getText()); - labelData.put("confidence", label.getConfidence()); - labelData.put("index", label.getIndex()); - labels.add(labelData); - } - - result.success(labels); - }) - .addOnFailureListener(e -> result.error("ImageLabelDetectorError", e.toString(), null)); - ; + startImageLabelDetector( + ImageLabeling.getClient( + new CustomImageLabelerOptions.Builder(remoteModel) + .setConfidenceThreshold(confidenceThreshold) + .setMaxResultCount(maxCount) + .build() + ), + inputImage, + result + ); } @Override public void onError(Exception e) { - result.error("Error", e.getMessage(), e); + result.error("Model download check failed", e.getMessage(), e); } } ); @@ -134,6 +124,10 @@ public void onError(Exception e) { instances.put(id, imageLabeler); } + startImageLabelDetector(imageLabeler, inputImage, result); + } + + private void startImageLabelDetector(ImageLabeler imageLabeler, InputImage inputImage, MethodChannel.Result result) { imageLabeler.process(inputImage) .addOnSuccessListener(imageLabels -> { List> labels = new ArrayList<>(imageLabels.size()); diff --git a/packages/google_mlkit_object_detection/android/src/main/java/com/google_mlkit_object_detection/ObjectDetector.java b/packages/google_mlkit_object_detection/android/src/main/java/com/google_mlkit_object_detection/ObjectDetector.java index 19b5a513..45cd674b 100644 --- a/packages/google_mlkit_object_detection/android/src/main/java/com/google_mlkit_object_detection/ObjectDetector.java +++ b/packages/google_mlkit_object_detection/android/src/main/java/com/google_mlkit_object_detection/ObjectDetector.java @@ -98,7 +98,7 @@ private void handleDetection(MethodCall call, final MethodChannel.Result result) remoteModel, new GenericModelManager.CheckModelIsDownloadedCallback() { @Override - public void onModelDownloaded(Boolean isDownloaded) { + public void onCheckResult(Boolean isDownloaded) { if (!isDownloaded) { result.error("Error Model has not been downloaded yet", "Model has not been downloaded yet", "Model has not been downloaded yet"); return; @@ -113,26 +113,16 @@ public void onModelDownloaded(Boolean isDownloaded) { CustomObjectDetectorOptions customObjectDetectorOptions = builder.build(); - ObjectDetection.getClient(customObjectDetectorOptions).process(inputImage).addOnSuccessListener(detectedObjects -> { - List> objects = new ArrayList<>(); - for (DetectedObject detectedObject : detectedObjects) { - Map objectMap = new HashMap<>(); - addData(objectMap, - detectedObject.getTrackingId(), - detectedObject.getBoundingBox(), - detectedObject.getLabels()); - objects.add(objectMap); - } - result.success(objects); - }).addOnFailureListener(e -> { - e.printStackTrace(); - result.error("ObjectDetectionError", e.toString(), null); - }); + startObjectDetection( + ObjectDetection.getClient(customObjectDetectorOptions), + inputImage, + result + ); } @Override public void onError(Exception e) { - + result.error("Model download check failed", e.getMessage(), e); } } ); @@ -146,6 +136,14 @@ public void onError(Exception e) { instances.put(id, objectDetector); } + startObjectDetection(objectDetector, inputImage, result); + } + + private void startObjectDetection( + com.google.mlkit.vision.objects.ObjectDetector objectDetector, + InputImage inputImage, + MethodChannel.Result result + ) { objectDetector.process(inputImage).addOnSuccessListener(detectedObjects -> { List> objects = new ArrayList<>(); for (DetectedObject detectedObject : detectedObjects) {