33import  android .app .Activity ;
44import  android .content .Context ;
55import  android .content .Intent ;
6+ import  android .graphics .Bitmap ;
7+ import  android .graphics .BitmapFactory ;
68import  androidx .annotation .NonNull ;
9+ import  android .util .Base64 ;
710import  java .util .*;
811
912import  io .flutter .embedding .engine .plugins .activity .ActivityAware ;
2427import  com .microblink .blinkcard .uisettings .UISettings ;
2528import  com .microblink .blinkcard .uisettings .ActivityRunner ;
2629import  com .microblink .blinkcard .locale .LanguageUtils ;
30+ import  com .microblink .blinkcard .directApi .DirectApiErrorListener ;
31+ import  com .microblink .blinkcard .directApi .RecognizerRunner ;
32+ import  com .microblink .blinkcard .entities .recognizers .RecognizerBundle ;
33+ import  com .microblink .blinkcard .hardware .orientation .Orientation ;
34+ import  com .microblink .blinkcard .metadata .MetadataCallbacks ;
35+ import  com .microblink .blinkcard .metadata .recognition .FirstSideRecognitionCallback ;
36+ import  com .microblink .blinkcard .recognition .RecognitionSuccessType ;
37+ import  com .microblink .blinkcard .view .recognition .ScanResultListener ;
2738
2839
2940import  com .microblink .blinkcard .flutter .recognizers .RecognizerSerializers ;
@@ -39,16 +50,21 @@ public class BlinkCardFlutterPlugin implements FlutterPlugin, MethodCallHandler,
3950  private  static  final  String  CHANNEL  = "blinkcard_scanner" ;
4051
4152  private  static  final  int  SCAN_REQ_CODE  = 1904 ;
42-   private  static  final  String  METHOD_SCAN  = "scanWithCamera" ;
53+   private  static  final  String  METHOD_SCAN_CAMERA  = "scanWithCamera" ;
54+   private  static  final  String  METHOD_SCAN_DIRECT_API  = "scanWithDirectApi" ;
4355
4456  private  static  final  String  ARG_LICENSE  = "license" ;
4557  private  static  final  String  ARG_LICENSE_KEY  = "licenseKey" ;
4658  private  static  final  String  ARG_LICENSEE  = "licensee" ;
4759  private  static  final  String  ARG_SHOW_LICENSE_WARNING  = "showTimeLimitedLicenseKeyWarning" ;
4860  private  static  final  String  ARG_RECOGNIZER_COLLECTION  = "recognizerCollection" ;
4961  private  static  final  String  ARG_OVERLAY_SETTINGS  = "overlaySettings" ;
62+   private  static  final  String  ARG_FRONT_IMAGE  = "frontImage" ;
63+   private  static  final  String  ARG_BACK_IMAGE  = "backImage" ;
5064
65+   private  boolean  mFirstSideScanned  = false ;
5166  private  RecognizerBundle  mRecognizerBundle ;
67+   private  RecognizerRunner  mRecognizerRunner ;
5268
5369  private  MethodChannel  channel ;
5470  private  Context  context ;
@@ -85,21 +101,26 @@ private void setupPlugin(Context context, BinaryMessenger messenger) {
85101  public  void  onMethodCall (@ NonNull  MethodCall  call , @ NonNull  Result  result ) {
86102    setLicense ((Map )call .argument (ARG_LICENSE ));
87103
88-     if  (call .method .equals (METHOD_SCAN )) {
104+     if  (call .method .equals (METHOD_SCAN_CAMERA )) {
89105      pendingResult  = result ;
90106
91107      JSONObject  jsonOverlaySettings  = new  JSONObject ((Map )call .argument (ARG_OVERLAY_SETTINGS ));
92108      JSONObject  jsonRecognizerCollection  = new  JSONObject ((Map )call .argument (ARG_RECOGNIZER_COLLECTION ));
93-       try  {
94-           LanguageUtils .setLanguageAndCountry (jsonOverlaySettings .getString ("language" ),
95-                   jsonOverlaySettings .getString ("country" ),
96-                   context );
97-       } catch  (Exception  e ) {}
109+       setLanguage (jsonOverlaySettings );
98110      mRecognizerBundle  = RecognizerSerializers .INSTANCE .deserializeRecognizerCollection (jsonRecognizerCollection );
99111      UISettings  uiSettings  = OverlaySettingsSerializers .INSTANCE .getOverlaySettings (context , jsonOverlaySettings , mRecognizerBundle );
100112
101113      startScanning (SCAN_REQ_CODE , uiSettings );
102114
115+       } else  if  (call .method .equals (METHOD_SCAN_DIRECT_API )) {
116+         pendingResult  = result ;
117+ 
118+         JSONObject  jsonRecognizerCollection  = new  JSONObject ((Map )call .argument (ARG_RECOGNIZER_COLLECTION ));
119+         String  frontImage  = call .argument (ARG_FRONT_IMAGE );
120+         String  backImage  = call .argument (ARG_BACK_IMAGE );
121+ 
122+         scanWithDirectApi (jsonRecognizerCollection , frontImage , backImage );
123+ 
103124    } else  {
104125      result .notImplemented ();
105126    }
@@ -108,18 +129,30 @@ public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) {
108129
109130  @ SuppressWarnings ("unchecked" )
110131  private  void  setLicense (Map  licenseMap ) {
111-       MicroblinkSDK .setShowTrialLicenseWarning ((boolean )licenseMap .getOrDefault (ARG_SHOW_LICENSE_WARNING , true ));
132+       if  (licenseMap .get (ARG_SHOW_LICENSE_WARNING ) != null ) {
133+           MicroblinkSDK .setShowTrialLicenseWarning ((boolean ) licenseMap .get (ARG_SHOW_LICENSE_WARNING ));
134+       } else  {
135+           MicroblinkSDK .setShowTrialLicenseWarning (true );
136+       }
112137
113-       String  licenseKey  = (String )licenseMap .get (ARG_LICENSE_KEY );
114-       String  licensee  = (String )licenseMap .getOrDefault (ARG_LICENSEE ,  null );
138+       String  licenseKey  = (String )  licenseMap .get (ARG_LICENSE_KEY );
139+       String  licensee  = (String )  licenseMap .get (ARG_LICENSEE );
115140
116141      if  (licensee  == null ) {
117142          MicroblinkSDK .setLicenseKey (licenseKey , context );
118143      } else  {
119144          MicroblinkSDK .setLicenseKey (licenseKey , licensee , context );
120145      }
121146
122-       MicroblinkSDK .setIntentDataTransferMode (IntentDataTransferMode .PERSISTED_OPTIMISED );
147+       MicroblinkSDK .setIntentDataTransferMode (IntentDataTransferMode .PERSISTED_OPTIMISED );  
148+   }
149+ 
150+   private  void  setLanguage (JSONObject  jsonOverlaySettings ) {
151+       try  {
152+           LanguageUtils .setLanguageAndCountry (jsonOverlaySettings .getString ("language" ),
153+                   jsonOverlaySettings .getString ("country" ),
154+                   context );
155+       } catch  (Exception  e ) {}
123156  }
124157
125158  private  void  startScanning (int  requestCode , UISettings  uiSettings ) {
@@ -132,6 +165,113 @@ private void startScanning(int requestCode, UISettings uiSettings) {
132165      }
133166  }
134167
168+   private  void  scanWithDirectApi (JSONObject  jsonRecognizerCollection , String  frontImage , String  backImage ) {
169+       ScanResultListener  mScanResultListenerBackSide  = new  ScanResultListener () {
170+           @ Override 
171+           public  void  onScanningDone (@ NonNull  RecognitionSuccessType  recognitionSuccessType ) {
172+               mFirstSideScanned  = false ;
173+               handleDirectApiResult (recognitionSuccessType );
174+           }
175+           @ Override 
176+           public  void  onUnrecoverableError (@ NonNull  Throwable  throwable ) {
177+             handleDirectApiError (throwable .getMessage ());
178+           }
179+       };
180+ 
181+       FirstSideRecognitionCallback  mFirstSideRecognitionCallback  = new  FirstSideRecognitionCallback () {
182+           @ Override 
183+           public  void  onFirstSideRecognitionFinished () {
184+               mFirstSideScanned  = true ;
185+           }
186+       };
187+ 
188+       ScanResultListener  mScanResultListenerFrontSide  = new  ScanResultListener () {
189+           @ Override 
190+           public  void  onScanningDone (@ NonNull  RecognitionSuccessType  recognitionSuccessType ) {
191+               if  (mFirstSideScanned ) {
192+                   //multiside recognizer used 
193+                   if  (!backImage .isEmpty () && backImage  != null ) {
194+                       processImage (backImage , mScanResultListenerBackSide );
195+                   } else  if  (recognitionSuccessType  != RecognitionSuccessType .UNSUCCESSFUL ) {
196+                       handleDirectApiResult (recognitionSuccessType );
197+                   } else  {
198+                       handleDirectApiError ("Could not extract the information from the front side and back side is empty!" );
199+                   }
200+               } else  if  (!mFirstSideScanned  && recognitionSuccessType  != RecognitionSuccessType .UNSUCCESSFUL ){
201+                   //singleside recognizer used 
202+                   handleDirectApiResult (recognitionSuccessType );
203+               } else  {
204+                   mFirstSideScanned  = false ;
205+                   handleDirectApiError ("Could not extract the information with DirectAPI!" );
206+               }
207+           }
208+           @ Override 
209+           public  void  onUnrecoverableError (@ NonNull  Throwable  throwable ) {
210+             handleDirectApiError (throwable .getMessage ());
211+           }
212+       };
213+ 
214+       setupRecognizerRunner (jsonRecognizerCollection , mFirstSideRecognitionCallback );
215+ 
216+       if  (!frontImage .isEmpty ()) {
217+           processImage (frontImage , mScanResultListenerFrontSide );
218+       } else  {
219+           handleDirectApiError ("The provided image for the 'frontImage' parameter is empty!" );
220+       }
221+   }
222+ 
223+     private  void  setupRecognizerRunner (JSONObject  jsonRecognizerCollection , FirstSideRecognitionCallback  mFirstSideRecognitionCallback ) {
224+       if  (mRecognizerRunner  != null ) {
225+           mRecognizerRunner .terminate ();
226+       }
227+       mRecognizerBundle  = RecognizerSerializers .INSTANCE .deserializeRecognizerCollection (jsonRecognizerCollection );
228+       try  {
229+           mRecognizerRunner  = RecognizerRunner .getSingletonInstance ();
230+       } catch  (Exception  e ) {
231+           handleDirectApiError ("DirectAPI not supported: "  + e );
232+       }
233+ 
234+       MetadataCallbacks  metadataCallbacks  = new  MetadataCallbacks ();
235+       metadataCallbacks .setFirstSideRecognitionCallback (mFirstSideRecognitionCallback );
236+       mRecognizerRunner .setMetadataCallbacks (metadataCallbacks );
237+       mRecognizerRunner .initialize (context , mRecognizerBundle , throwable  -> handleDirectApiError ("Failed to initialize recognizer with DirectAPI: "  + throwable .getMessage ()));
238+     }
239+ 
240+     private  void  processImage (String  base64Image , ScanResultListener  scanResultListener ) {
241+         Bitmap  image  = base64ToBitmap (base64Image );
242+         if  (image  != null ) {
243+             mRecognizerRunner .recognizeBitmap (
244+                     base64ToBitmap (base64Image ),
245+                     Orientation .ORIENTATION_LANDSCAPE_RIGHT ,
246+                     scanResultListener 
247+             );
248+         } else  {
249+             handleDirectApiError ("Could not decode the Base64 image!" );
250+         }
251+     }
252+ 
253+     private  void  handleDirectApiResult (RecognitionSuccessType  recognitionSuccessType ) {
254+         if  (recognitionSuccessType  != RecognitionSuccessType .UNSUCCESSFUL ) {
255+             if  (pendingResult  == null ) {
256+                 return ;
257+             }
258+             JSONArray  resultList  = RecognizerSerializers .INSTANCE .serializeRecognizerResults (mRecognizerBundle .getRecognizers ());
259+             pendingResult .success (resultList .toString ());
260+         }
261+         pendingResult  = null ;
262+     }
263+     private  Bitmap  base64ToBitmap (String  base64String ) {
264+         byte [] decodedBytes  = android .util .Base64 .decode (base64String , Base64 .DEFAULT );
265+         return  BitmapFactory .decodeByteArray (decodedBytes , 0 , decodedBytes .length );
266+     }
267+ 
268+     private  void  handleDirectApiError (String  errorMessage ) {
269+         pendingResult .error ("" , errorMessage , null );
270+         if  (mRecognizerRunner  != null ) {
271+             mRecognizerRunner .resetRecognitionState (true );
272+         }
273+     }
274+ 
135275  @ Override 
136276  public  void  onDetachedFromActivity () {}
137277
@@ -185,5 +325,4 @@ public boolean onActivityResult(int requestCode, int resultCode, Intent data) {
185325      pendingResult  = null ;
186326      return  true ;
187327  }
188- }
189- 
328+ }
0 commit comments