/** * Docutain SDK Cordova Plugin * Copyright (c) INFOSOFT Informations- und Dokumentationssysteme GmbH. All rights reserved. * * Docutain SDK Cordova Plugin is a commercial product and requires a license. * Details found in the LICENSE file in the root directory of this source tree. */ package com.docutain.sdk.plugin.cordova import android.app.Activity import android.content.Intent import android.net.Uri import android.os.Environment import android.util.Log import org.apache.cordova.CallbackContext import org.apache.cordova.CordovaPlugin import org.apache.cordova.PluginResult import org.json.JSONArray import org.json.JSONException import org.json.JSONObject import java.io.File import java.util.Base64 import de.docutain.sdk.Document import de.docutain.sdk.DocutainSDK import de.docutain.sdk.Logger import de.docutain.sdk.dataextraction.AnalyzeConfiguration import de.docutain.sdk.dataextraction.DocumentDataReader import de.docutain.sdk.ui.DocumentScanner import de.docutain.sdk.ui.BaseScannerConfiguration import de.docutain.sdk.ui.ButtonConfiguration import de.docutain.sdk.ui.ColorConfiguration import de.docutain.sdk.ui.PageEditConfiguration import de.docutain.sdk.ui.TextConfiguration import de.docutain.sdk.ui.DocutainButton import de.docutain.sdk.ui.DocutainColor import de.docutain.sdk.ui.ScanFilter import de.docutain.sdk.ui.Source import de.docutain.sdk.ui.StatusBarAppearance import de.docutain.sdk.ui.NavigationBarAppearance import de.docutain.sdk.ui.Onboarding import de.docutain.sdk.ui.scantips.ScanTips import de.docutain.sdk.ui.ScanHintPopup import de.docutain.sdk.ui.DocutainListItem import de.docutain.sdk.ui.EmptyResultScreen import de.docutain.sdk.ui.DocumentScannerConfiguration import de.docutain.sdk.ui.photopayment.PhotoPaymentResult import de.docutain.sdk.ui.photopayment.PhotoPaymentConfiguration import de.docutain.sdk.ui.photopayment.PaymentAnalyzeConfiguration class DocutainSdkPlugin : CordovaPlugin() { private val logTag = "DocutainSdk" private val SCAN_DOCUMENT_RESULT_CODE = 1 private val START_PHOTOPAYMENT_RESULT_CODE = 2 private var AktCallbackContext: CallbackContext? = null; private var InitSDKOk:Boolean = false; private val canceledState = "CANCELED" override fun onActivityResult(requestCode: Int, resultCode: Int, intent: Intent?) { Log.v(logTag, "onActivityResult:" + requestCode) if (requestCode == SCAN_DOCUMENT_RESULT_CODE) { val ret = JSONObject() ret.put("status", if(resultCode == Activity.RESULT_OK) "SUCCESS" else "CANCELED") AktCallbackContext?.success(ret); } if (requestCode == START_PHOTOPAYMENT_RESULT_CODE) { if(resultCode == Activity.RESULT_OK) { AktCallbackContext?.success(intent?.getStringExtra("analyzeData")) } else { AktCallbackContext?.error(canceledState) } } } @Throws(JSONException::class) override fun execute(action: String, args: JSONArray, callbackContext: CallbackContext): Boolean { Log.v(logTag, "Plugin execute:$action") when (action) { "initSDK"-> { val licenseKey = args.getString(0) initSDK(licenseKey, callbackContext) } "deleteTempFiles"-> { val deleteTraceFileContent = args.getBoolean(0) deleteTempFiles(deleteTraceFileContent, callbackContext) } "scanDocument"-> scanDocument(args.getJSONObject(0), callbackContext) "setAnalyzeConfiguration" -> setAnalyzeConfiguration(args.getJSONObject(0), callbackContext) "loadFile"-> { val filePath = args.getString(0) loadFile(filePath, callbackContext) } "writePDF" ->{ val PageFormat = args.optString(0,"A4") val filepath = args.optString(1) val overWrite = args.optBoolean(2,true) writePDF(filepath, overWrite, PageFormat, callbackContext) } "writeImage" ->{ val pageNumber = args.getInt(0) val filepath = args.getString(1) writeImage(filepath, pageNumber, callbackContext) } "getText"-> getText(callbackContext) "getTextPage"-> { val pageNumber = args.getInt(0) getTextPage(pageNumber, callbackContext) } "analyze" -> analyze(callbackContext) "pageCount" -> pageCount(callbackContext) "setLogLevel" -> { val logLevel = args.getString(0) setLogLevel(logLevel, callbackContext) } "getImageBytes"-> { val pageNumber = args.getInt(0) val pageSourceType = args.getString(1) getImageBytes(pageNumber, pageSourceType, callbackContext) } "getTraceFile"-> getTraceFile(callbackContext) "startPhotoPayment"-> startPhotoPayment(args.getJSONObject(0), callbackContext) "resetOnboarding"-> { val onboardung = args.optBoolean(0,true) val scanHintPopup = args.optBoolean(1,true) resetOboarding(onboardung,scanHintPopup, callbackContext) } "onboardingDefaultItems"-> onboardingDefaultItems(callbackContext) "scanTipsDefaultItems"-> scanTipsDefaultItems(callbackContext) "emptyResultScreenDefaultItems"-> emptyResultScreenDefaultItems(callbackContext) else -> { Log.e(logTag, "Plugin execute:$action unknown") return false; } } return true; } private fun initSDK(licenseKey: String, callbackContext: CallbackContext) { if(InitSDKOk) { callbackContext.success(); return; } Log.v(logTag, "InitSDK Start") val context = this.cordova.getActivity().getApplicationContext(); if(!DocutainSDK.initSDK(context as android.app.Application, licenseKey)){ //init of Docutain SDK failed, get the last error message InitSDKOk = false; Log.e(logTag, "Initialization of the Docutain SDK failed: "+ DocutainSDK.getLastError()) callbackContext.error(DocutainSDK.getLastError()) } else { InitSDKOk = true; Log.d(logTag, "initSDK Ok: \$licenseKey") callbackContext.success(); } } private fun deleteTempFiles(deleteTraceFileContent: Boolean ,callbackContext: CallbackContext) { try { Log.v(logTag, "deleteTempFiles" + deleteTraceFileContent) if(DocutainSDK.deleteTempFiles(deleteTraceFileContent)) callbackContext.success() else callbackContext.error(DocutainSDK.getLastError()) } catch(ex:Exception ) { Log.e(logTag, "deleteTempFiles Exception"+ ex) callbackContext.error("deleteTempFiles Exception"+ ex) } } private fun setLogLevel(LogLevel: String, callbackContext: CallbackContext) { Log.v(logTag, "setLogLevel:" + LogLevel) if(LogLevel.isNullOrEmpty()) { callbackContext.error("LogLevel is null") } else { try { val logLevel: Logger.Level = getLogLevelFromString(LogLevel); Log.d(logTag, "setLogLevel " + logLevel) Logger.setLogLevel(logLevel); callbackContext.success() } catch (ex: Exception) { Log.e(logTag, "setLogLevel Exception" + ex) callbackContext.error("setLogLevel Exception"+ ex) } } } private fun getTraceFile(callbackContext: CallbackContext) { try { val text = Logger.getTraceFile().getPath() callbackContext.success(text) } catch(ex:Exception ) { Log.e(logTag, "getTraceFile Exception"+ ex) callbackContext.error("getTraceFile Exception"+ ex) } } private fun setAnalyzeConfiguration(config: JSONObject, callbackContext: CallbackContext) { Log.v(logTag, "setAnalyzeConfiguration") val analyzeConfig = AnalyzeConfiguration() mapAnalyzeConfiguration(config, analyzeConfig); if(!DocumentDataReader.setAnalyzeConfiguration(analyzeConfig)){ Log.e(logTag,"Setting AnalyzeConfiguration failed: "+ DocutainSDK.getLastError()) callbackContext.error(DocutainSDK.getLastError()) } else { callbackContext.success() } } private fun scanDocument(ScannerConfiguration: JSONObject, callbackContext: CallbackContext) { Log.v(logTag, "scanDocument Start") try { AktCallbackContext = callbackContext; val nativeScanConfig = DocumentScannerConfiguration() if(!mapDocumentScannerConfiguration(ScannerConfiguration, nativeScanConfig, true)) { callbackContext.error("scanDocument config not valid"); } else{ val currentActivity = this.cordova.getActivity(); val intent = DocumentScanner.newScanIntent(currentActivity.getApplicationContext(), nativeScanConfig) cordova.startActivityForResult(this as CordovaPlugin, intent, SCAN_DOCUMENT_RESULT_CODE) Log.v(logTag, "scanDocument start OK") } } catch(ex:Exception ) { Log.e(logTag, "scanDocument Exception"+ ex) callbackContext.error("scanDocument Exception"+ ex); } } private fun loadFile(filepath: String, callbackContext: CallbackContext) { try { Log.v(logTag, "loadFile:" + filepath) val fileUri: Uri = Uri.parse(filepath) val rc = DocumentDataReader.loadFile(fileUri) Log.d(logTag, "loadFile rc:" + rc) if(rc == true) callbackContext.success(); else callbackContext.error(DocutainSDK.getLastError()) } catch(ex:Exception ) { Log.e(logTag, "loadFile Exception"+ ex) callbackContext.error("loadFile Exception"+ ex); } } private fun writePDF(filepath: String, overWrite: Boolean, PageFormat: String, callbackContext: CallbackContext) { Log.v(logTag, "writePDF:" + filepath) Log.v(logTag, "PageFormat:" + PageFormat) try { val PDFFormat: Document.PDFPageFormat = getPDFPageFormatFromString(PageFormat); Log.d(logTag, "PDFFormat:" + PDFFormat) var filepathLoc = filepath; var overWriteLoc: Boolean = overWrite; if(filepathLoc == "null" || filepathLoc.length == 0) { overWriteLoc = true; filepathLoc = DocutainSDK.context.getFilesDir().absolutePath + "/Docutain/Temp/Docutain.pdf"; } val file = File(filepathLoc); val rc = Document.writePDF(file,overWriteLoc, PDFFormat) Log.d(logTag, "writePDF rc absolutePath:" + rc?.absolutePath) if(rc == null){ callbackContext.error(DocutainSDK.getLastError()) } else{ callbackContext.success(rc.absolutePath) } } catch(ex:Exception ) { Log.e(logTag, "writePDF Exception"+ ex) callbackContext.error("writePDF Exception"+ ex) } } private fun writeImage(filepath: String, pageNumber: Int, callbackContext: CallbackContext) { Log.v(logTag, "writeImage:" + filepath) Log.v(logTag, "pageNumber:" + pageNumber) try { //needs to be an absolut path to the file var filepathLoc = filepath.replace("file://", "") if(filepathLoc == "null" || filepathLoc.length == 0) { filepathLoc = DocutainSDK.context.getFilesDir().absolutePath + "/Docutain/Temp/Docutain_"+pageNumber +".jpg"; } val file = File(filepathLoc); val rc = Document.writeImage(pageNumber, file) Log.d(logTag, "writeImage rc absolutePath:" + rc?.absolutePath) if(rc == null){ callbackContext.error(DocutainSDK.getLastError()) } else{ callbackContext.success(Uri.fromFile(rc).toString()) } } catch(ex:Exception ) { Log.e(logTag, "writeImage Exception"+ ex) callbackContext.error("writeImage Exception"+ ex) } } private fun getImageBytes(pageNumber: Int, pageSourceType: String, callbackContext: CallbackContext) { try { val sourceType: Document.PageSourceType = getPageSourceTypeFromString(pageSourceType); val bytes = Document.getImageBytes(pageNumber, sourceType) if(bytes == null){ callbackContext.error(DocutainSDK.getLastError()) } else{ callbackContext.success(Base64.getEncoder().encodeToString(bytes)) } } catch(ex:Exception ) { Log.e(logTag, "getImageBytes Exception"+ ex) callbackContext.error("getImageBytes Exception"+ ex); } } private fun getText(callbackContext: CallbackContext) { Log.v(logTag, "getText") try { val text = DocumentDataReader.getText() callbackContext.success(text) /* ToDo if(text == null) { callbackContext.error(DocutainSDK.getLastError()) } else { callbackContext.success(text) } */ } catch(ex:Exception ) { Log.e(logTag, "getText Exception"+ ex) callbackContext.error("getText Exception"+ ex) } } private fun getTextPage(pageNumber: Int, callbackContext: CallbackContext) { try { val text = DocumentDataReader.getText(pageNumber) callbackContext.success(text) /* ToDo if(text == null) { callbackContext.error(DocutainSDK.getLastError()) } else { callbackContext.success(text) } */ } catch(ex:Exception ) { Log.e(logTag, "getTextPage Exception"+ ex) callbackContext.error("getTextPage Exception"+ ex); } } private fun analyze(callbackContext: CallbackContext) { Log.v(logTag, "analyze") try { val text = DocumentDataReader.analyze() Log.d(logTag, "analyze:" + text) callbackContext.success(text) } catch(ex:Exception ) { Log.e(logTag, "analyze Exception"+ ex) callbackContext.error("analyze Exception"+ ex) } } private fun pageCount(callbackContext: CallbackContext) { try { callbackContext.success(Document.pageCount()) } catch(ex:Exception ) { Log.e(logTag, "pageCount Exception" + ex) callbackContext.error("pageCount Exception"+ ex); } } private fun startPhotoPayment(PhotoPaymentConfiguration: JSONObject, callbackContext: CallbackContext) { Log.v(logTag, "startPhotoPayment Start") try { AktCallbackContext = callbackContext; val nativePhotoPaymentConfig = PhotoPaymentConfiguration() if(!mapPhotoPaymentConfiguration(PhotoPaymentConfiguration, nativePhotoPaymentConfig)) { callbackContext.error("scanDocument config not valid"); } else{ val currentActivity = this.cordova.getActivity(); val intent = PhotoPaymentResult().createIntent(currentActivity.getApplicationContext(), nativePhotoPaymentConfig) cordova.startActivityForResult(this as CordovaPlugin, intent, START_PHOTOPAYMENT_RESULT_CODE) Log.v(logTag, "scanDocument start OK") } } catch(ex:Exception ) { Log.e(logTag, "startPhotoPayment Exception"+ ex) callbackContext.error("startPhotoPayment Exception"+ ex); } } private fun resetOboarding(onboardingReset: Boolean, scanHintPopup: Boolean, callbackContext: CallbackContext) { try { val onboarding = Onboarding(); onboarding.reset(onboardingReset, scanHintPopup) callbackContext.success() } catch(ex:Exception ) { Log.e(logTag, "resetOnboarding Exception"+ ex) callbackContext.error("getImageBytes Exception"+ ex); } } fun onboardingDefaultItems(callbackContext: CallbackContext) { try { callbackContext.success(defaultItemsToJSONArray(Onboarding.defaultItems)) } catch(ex:Exception ) { Log.e(logTag, "onboardingDefaultItems Exception" + ex) callbackContext.error("onboardingDefaultItems"+ ex); } } fun emptyResultScreenDefaultItems(callbackContext: CallbackContext) { try { callbackContext.success(defaultItemsToJSONArray(EmptyResultScreen.defaultItems)) } catch(ex:Exception ) { Log.e(logTag, "emptyResultScreenDefaultItems Exception" + ex) callbackContext.error("emptyResultScreenDefaultItems" + ex); } } fun scanTipsDefaultItems(callbackContext: CallbackContext) { try { callbackContext.success(defaultItemsToJSONArray(ScanTips.defaultItems)) } catch(ex:Exception ) { Log.e(logTag, "scanTipsDefaultItems Exception" + ex) callbackContext.error("scanTipsDefaultItems" + ex); } } private fun getLogLevelFromString(loglevel: String) : Logger.Level { when (loglevel.uppercase()) { "DISABLE" -> return Logger.Level.DISABLE; "ASSERT" -> return Logger.Level.ASSERT; "ERROR" -> return Logger.Level.ERROR; "WARNING" -> return Logger.Level.WARNING; "INFO" -> return Logger.Level.INFO; "DEBUG" -> return Logger.Level.DEBUG; "VERBOSE" -> return Logger.Level.VERBOSE; else -> return Logger.Level.ERROR; } } private fun getScanFilterFromString(scanFilter: String) : ScanFilter { when (scanFilter.uppercase()) { "AUTO" -> return ScanFilter.AUTO; "GRAY" -> return ScanFilter.GRAY; "BLACKWHITE" -> return ScanFilter.BLACKWHITE; "ORIGINAL" -> return ScanFilter.ORIGINAL; "TEXT" -> return ScanFilter.TEXT; "AUTO2" -> return ScanFilter.AUTO2; "ILLUSTRATION" -> return ScanFilter.ILLUSTRATION; else -> return ScanFilter.ILLUSTRATION; } } private fun getScanSourceFromString(scanSource: String) : Source { when (scanSource.uppercase()) { "CAMERA" -> return Source.CAMERA; "IMAGE" -> return Source.IMAGE; "GALLERY" -> return Source.GALLERY; "GALLERY_MULTIPLE" -> return Source.GALLERY_MULTIPLE; "CAMERA_IMPORT" -> return Source.CAMERA_IMPORT; else -> return Source.CAMERA; } } private fun getPDFPageFormatFromString(pageFormat: String) : Document.PDFPageFormat { when (pageFormat.uppercase()) { "FIT_TO_PAGES" -> return Document.PDFPageFormat.FIT_TO_PAGES; "A4" -> return Document.PDFPageFormat.A4; "A4_LANDSCAPE" -> return Document.PDFPageFormat.A4_LANDSCAPE; "A5" -> return Document.PDFPageFormat.A5; "A5_LANDSCAPE" -> return Document.PDFPageFormat.A5_LANDSCAPE; "LETTER" -> return Document.PDFPageFormat.LETTER; "LETTER_LANDSCAPE" -> return Document.PDFPageFormat.LETTER_LANDSCAPE; "LEGAL" -> return Document.PDFPageFormat.LEGAL; "LEGAL_LANDSCAPE" -> return Document.PDFPageFormat.LEGAL_LANDSCAPE; else -> return Document.PDFPageFormat.A4; } } private fun getPageSourceTypeFromString(pageSourceType: String) : Document.PageSourceType { when (pageSourceType.uppercase()) { "ORIGINAL" -> return Document.PageSourceType.ORIGINAL; "CUT_FILTER" -> return Document.PageSourceType.CUT_FILTER; "CUT_ONLY" -> return Document.PageSourceType.CUT_ONLY; else -> return Document.PageSourceType.CUT_FILTER; } } private fun getStatusBarAppearanceFromString(statusBarAppearance: String) : StatusBarAppearance { when (statusBarAppearance.uppercase()) { "LIGHT" -> return StatusBarAppearance.LIGHT; else -> return StatusBarAppearance.DARK; } } private fun getNavigationBarAppearanceFromString(navigationBarAppearance: String) : NavigationBarAppearance { when (navigationBarAppearance.uppercase()) { "LIGHT" -> return NavigationBarAppearance.LIGHT; else -> return NavigationBarAppearance.DARK; } } private fun mapAnalyzeConfiguration(config: JSONObject, analyzeConfig: AnalyzeConfiguration) { if(config.has("readBIC")) analyzeConfig.readBIC = config.getBoolean("readBIC") if(config.has("readPaymentState")) analyzeConfig.readPaymentState = config.getBoolean("readPaymentState") if(config.has("readSEPACreditor")) analyzeConfig.readSEPACreditor = config.getBoolean("readSEPACreditor") } private fun setButtonConfig(docutainButton: DocutainButton, docutainButtonEntry: JSONObject?) { if(docutainButtonEntry!=null) { if (docutainButtonEntry.has("title")) docutainButton.title = docutainButtonEntry.getString("title"); if (docutainButtonEntry.has("icon")){ val imgSource = docutainButtonEntry.getString("icon") val imgIdentifier = DocutainSDK.context.resources.getIdentifier(imgSource, "drawable", DocutainSDK.context.packageName) docutainButton.icon = imgIdentifier } } } private fun setPageEditConfig(pageEditConfig: PageEditConfiguration, optionsPageEditConfig: JSONObject?) { if(optionsPageEditConfig != null){ if (optionsPageEditConfig.has("allowPageFilter")) { pageEditConfig.allowPageFilter = optionsPageEditConfig.getBoolean("allowPageFilter") } if (optionsPageEditConfig.has("allowPageRotation")) { pageEditConfig.allowPageRotation = optionsPageEditConfig.getBoolean("allowPageRotation") } if(optionsPageEditConfig.has("allowPageArrangement")) { pageEditConfig.allowPageArrangement = optionsPageEditConfig.getBoolean("allowPageArrangement") } if(optionsPageEditConfig.has("allowPageCropping")) { pageEditConfig.allowPageCropping = optionsPageEditConfig.getBoolean("allowPageCropping") } if(optionsPageEditConfig.has("allowPageRetake")) { pageEditConfig.allowPageRetake = optionsPageEditConfig.getBoolean("allowPageRetake") } if(optionsPageEditConfig.has("allowPageAdd")) { pageEditConfig.allowPageAdd = optionsPageEditConfig.getBoolean("allowPageAdd") } if(optionsPageEditConfig.has("allowPageDeletion")) { pageEditConfig.allowPageDeletion = optionsPageEditConfig.getBoolean("allowPageDeletion") } if(optionsPageEditConfig.has("pageArrangementShowDeleteButton")) { pageEditConfig.pageArrangementShowDeleteButton = optionsPageEditConfig.getBoolean("pageArrangementShowDeleteButton") } if(optionsPageEditConfig.has("pageArrangementShowPageNumber")) { pageEditConfig.pageArrangementShowPageNumber = optionsPageEditConfig.getBoolean("pageArrangementShowPageNumber") } } } private fun setColorConfig(colorConfig: ColorConfiguration, optionsColorConfig: JSONObject?) { if(optionsColorConfig != null) { val keysIter = optionsColorConfig.keys(); while (keysIter.hasNext()) { val key = keysIter.next() val docutainColorEntry = optionsColorConfig.optJSONObject(key) if(docutainColorEntry != null){ if(docutainColorEntry.has("Light") && docutainColorEntry.has("Dark")) { val docutainColor = DocutainColor(docutainColorEntry.getString("Light"), docutainColorEntry.getString("Dark")) when (key.uppercase()) { "COLORPRIMARY" -> colorConfig.colorPrimary = docutainColor "COLORONPRIMARY" -> colorConfig.colorOnPrimary = docutainColor "COLORSECONDARY" -> colorConfig.colorSecondary = docutainColor "COLORONSECONDARY" -> colorConfig.colorOnSecondary = docutainColor "COLORSCANBUTTONSLAYOUTBACKGROUND" -> colorConfig.colorScanButtonsLayoutBackground = docutainColor "COLORSCANBUTTONSFOREGROUND" -> colorConfig.colorScanButtonsForeground = docutainColor "COLORSCANPOLYGON" -> colorConfig.colorScanPolygon = docutainColor "COLORBOTTOMBARBACKGROUND" -> colorConfig.colorBottomBarBackground = docutainColor "COLORBOTTOMBARFOREGROUND" -> colorConfig.colorBottomBarForeground = docutainColor "COLORTOPBARBACKGROUND" -> colorConfig.colorTopBarBackground = docutainColor "COLORTOPBARFOREGROUND" -> colorConfig.colorTopBarForeground = docutainColor "COLORTOPBARTITLE" -> colorConfig.colorTopBarTitle = docutainColor else -> Log.e("DocutainSdkFull", "mapDocumentScannerConfiguration color not valid "+ key) } } } } } } private fun setTextConfig(textConfig: TextConfiguration, optionsTextConfig: JSONObject?) { if(optionsTextConfig != null){ if (optionsTextConfig.has("textSizeBottomToolbar")) textConfig.textSizeBottomToolbar = optionsTextConfig.getDouble("textSizeBottomToolbar").toFloat() if (optionsTextConfig.has("textSizeTopToolbar")) textConfig.textSizeTopToolbar = optionsTextConfig.getDouble("textSizeTopToolbar").toFloat() if (optionsTextConfig.has("textSizeScanButtons")) textConfig.textSizeScanButtons = optionsTextConfig.getDouble("textSizeScanButtons").toFloat() if (optionsTextConfig.has("textSizeTitle")) textConfig.textSizeTitle = optionsTextConfig.getDouble("textSizeTitle").toFloat() if (optionsTextConfig.has("textTitleScanPage")) textConfig.textTitleScanPage = optionsTextConfig.getString("textTitleScanPage") if (optionsTextConfig.has("textTitleEditPage")) textConfig.textTitleEditPage = optionsTextConfig.getString("textTitleEditPage") if (optionsTextConfig.has("textTitleFilterPage")) textConfig.textTitleFilterPage = optionsTextConfig.getString("textTitleFilterPage") if (optionsTextConfig.has("textTitleCroppingPage")) textConfig.textTitleCroppingPage = optionsTextConfig.getString("textTitleCroppingPage") if (optionsTextConfig.has("textTitleArrangementPage")) textConfig.textTitleArrangementPage = optionsTextConfig.getString("textTitleArrangementPage") if (optionsTextConfig.has("textTitleConfirmationPage")) textConfig.textTitleConfirmationPage = optionsTextConfig.getString("textTitleConfirmationPage") if (optionsTextConfig.has("textDocumentTitle")) textConfig.textDocumentTitle = optionsTextConfig.getString("textDocumentTitle") if (optionsTextConfig.has("textFocusHint")) textConfig.textFocusHint = optionsTextConfig.getString("textFocusHint") if (optionsTextConfig.has("textFirstPageHint")) textConfig.textFirstPageHint = optionsTextConfig.getString("textFirstPageHint") if (optionsTextConfig.has("textLastPageHint")) textConfig.textLastPageHint = optionsTextConfig.getString("textLastPageHint") if (optionsTextConfig.has("textOnePageHint")) textConfig.textOnePageHint = optionsTextConfig.getString("textOnePageHint") if (optionsTextConfig.has("textScanProgress")) textConfig.textScanProgress = optionsTextConfig.getString("textScanProgress") if (optionsTextConfig.has("textDeleteDialogCurrentPage")) textConfig.textDeleteDialogCurrentPage = optionsTextConfig.getString("textDeleteDialogCurrentPage") if (optionsTextConfig.has("textDeleteDialogAllPages")) textConfig.textDeleteDialogAllPages = optionsTextConfig.getString("textDeleteDialogAllPages") if (optionsTextConfig.has("textDeleteDialogCancel")) textConfig.textDeleteDialogCancel = optionsTextConfig.getString("textDeleteDialogCancel") if (optionsTextConfig.has("textTitleScanTipsPage")) textConfig.textTitleScanTipsPage = optionsTextConfig.getString("textTitleScanTipsPage") } } private fun setButtonConfig(buttonConfig: ButtonConfiguration, optionsButtonConfig: JSONObject?) { if (optionsButtonConfig != null) { val keysIter = optionsButtonConfig.keys(); while (keysIter.hasNext()) { val key = keysIter.next() val docutainButtonEntry = optionsButtonConfig.optJSONObject(key) if (docutainButtonEntry != null) { when (key.uppercase()) { "BUTTONEDITROTATE" -> setButtonConfig( buttonConfig.buttonEditRotate, docutainButtonEntry ) "BUTTONEDITCROP" -> setButtonConfig( buttonConfig.buttonEditCrop, docutainButtonEntry ) "BUTTONEDITFILTER" -> setButtonConfig( buttonConfig.buttonEditFilter, docutainButtonEntry ) "BUTTONEDITARRANGE" -> setButtonConfig( buttonConfig.buttonEditArrange, docutainButtonEntry ) "BUTTONEDITRETAKE" -> setButtonConfig( buttonConfig.buttonEditRetake, docutainButtonEntry ) "BUTTONEDITDELETE" -> setButtonConfig( buttonConfig.buttonEditDelete, docutainButtonEntry ) "BUTTONEDITFINISH" -> setButtonConfig( buttonConfig.buttonEditFinish, docutainButtonEntry ) "BUTTONCROPEXPAND" -> setButtonConfig( buttonConfig.buttonCropExpand, docutainButtonEntry ) "BUTTONCROPSNAP" -> setButtonConfig( buttonConfig.buttonCropSnap, docutainButtonEntry ) "BUTTONCROPFINISH" -> setButtonConfig( buttonConfig.buttonCropFinish, docutainButtonEntry ) "BUTTONSCANAUTOCAPTUREON" -> setButtonConfig( buttonConfig.buttonScanAutoCaptureOn, docutainButtonEntry ) "BUTTONSCANAUTOCAPTUREOFF" -> setButtonConfig( buttonConfig.buttonScanAutoCaptureOff, docutainButtonEntry ) "BUTTONSCANTORCH" -> setButtonConfig( buttonConfig.buttonScanTorch, docutainButtonEntry ) "BUTTONSCANCAPTURE" -> setButtonConfig( buttonConfig.buttonScanCapture, docutainButtonEntry ) "BUTTONSCANFINISH" -> setButtonConfig( buttonConfig.buttonScanFinish, docutainButtonEntry ) "BUTTONCONFIRMATIONFINISH" -> setButtonConfig( buttonConfig.buttonConfirmationFinish, docutainButtonEntry ) "BUTTONEDITADDPAGE" -> setButtonConfig( buttonConfig.buttonEditAddPage, docutainButtonEntry ) "BUTTONSCANIMPORT" -> setButtonConfig( buttonConfig.buttonScanImport, docutainButtonEntry ) else -> Log.e( "DocutainSdkFull", "mapDocumentScannerConfiguration button not valid " + key ) } } } } } private fun setOnboardingConfig(scanConfig: BaseScannerConfiguration, optionsOnboarding: JSONObject) { var onboarding: Onboarding? = scanConfig.onboarding if(onboarding == null) { onboarding = Onboarding() scanConfig.onboarding = onboarding } readButtonConfig("buttonNext", onboarding.buttonNext, optionsOnboarding) readButtonConfig("buttonFinish", onboarding.buttonFinish, optionsOnboarding) readButtonConfig("buttonSkip", onboarding.buttonSkip, optionsOnboarding) if (optionsOnboarding.has("buttonBack")) { onboarding.buttonBack = DocutainButton() readButtonConfig("buttonBack", onboarding.buttonBack!!, optionsOnboarding) } if(optionsOnboarding.has("scanHintPopup")) { val optionsScanHintPopup = optionsOnboarding.optJSONObject("scanHintPopup") if(optionsScanHintPopup == null) { onboarding.scanHintPopup = null } else { var scanHintPopup: ScanHintPopup? = onboarding.scanHintPopup if(scanHintPopup == null) { scanHintPopup = ScanHintPopup() onboarding.scanHintPopup = scanHintPopup } if (optionsScanHintPopup.has("title")) scanHintPopup.title = optionsScanHintPopup.optString("title") if (optionsScanHintPopup.has("message")) scanHintPopup.message = optionsScanHintPopup.optString("message") if (optionsScanHintPopup.has("closeButton")) scanHintPopup.closeButton = optionsScanHintPopup.optString("closeButton") val imageSource = getImageSource(optionsScanHintPopup) if(imageSource != null) scanHintPopup.imageSource = imageSource } } val optionsOnboardingItems = optionsOnboarding.optJSONArray("items") if(optionsOnboardingItems != null) { val items = ArrayList() for (i in 0 until optionsOnboardingItems.length()) { val docutainListItemEntry = optionsOnboardingItems.getJSONObject(i) items.add(readDocutainListItemConfig(docutainListItemEntry)) } if(items.isNullOrEmpty()){ onboarding.items = null; } else { onboarding.items = items; } } } private fun setScanTipsConfig(scanConfig: BaseScannerConfiguration, optionsScanTips: JSONObject) { var scanTips: ScanTips? = scanConfig.scanTips if(scanTips == null) { scanTips = ScanTips() scanConfig.scanTips = scanTips } readButtonConfig("toolbarItem", scanTips.toolbarItem, optionsScanTips, true) val optionsScanTipsItems = optionsScanTips.optJSONArray("items") if(optionsScanTipsItems != null) { val items = ArrayList() for (i in 0 until optionsScanTipsItems.length()) { val docutainListItemEntry = optionsScanTipsItems.getJSONObject(i) items.add(readDocutainListItemConfig(docutainListItemEntry)) } if (items.isNullOrEmpty()) { scanTips.items = null; } else { scanTips.items = items; } } } private fun setSourceImagesConfig(scanConfig: BaseScannerConfiguration, sourceImages: JSONArray?) { if(sourceImages != null) { val sourceImageFiles = ArrayList() for (i in 0..sourceImages.length() - 1) { //needs to be an absolut path to the file val filepath = sourceImages.getString(i).replace("file://", "") sourceImageFiles.add(java.io.File(filepath)) } scanConfig.sourceImages = sourceImageFiles } } private fun mapDocumentScannerConfiguration(options: JSONObject, scanConfig: BaseScannerConfiguration, NeedToMigrate: Boolean = false): Boolean { try { setPageEditConfig(scanConfig.pageEditConfig, options.optJSONObject("pageEditConfig")) //switched to lowercase on October 7, 2024, capitalization still included for compatibility reasons //should be removed after 1-2 years and only allow lowercase if(options.has("colorConfig") || options.has("ColorConfig")) { setColorConfig(scanConfig.colorConfig, options.optJSONObject("colorConfig")?:options.optJSONObject("ColorConfig")) } if(options.has("allowCaptureModeSetting")) scanConfig.allowCaptureModeSetting = options.getBoolean("allowCaptureModeSetting") if(options.has("autoCapture")) scanConfig.autoCapture = options.getBoolean("autoCapture") if(options.has("defaultScanFilter")) scanConfig.defaultScanFilter = getScanFilterFromString(options.getString("defaultScanFilter")) if(options.has("source")) scanConfig.source = getScanSourceFromString(options.getString("source")) if(options.has("sourceImages")) setSourceImagesConfig(scanConfig, options.get("sourceImages") as JSONArray?) if(options.has("autoCrop")) scanConfig.autoCrop = options.getBoolean("autoCrop") if(options.has("multiPage")) scanConfig.multiPage = options.getBoolean("multiPage") if(options.has("preCaptureFocus")) scanConfig.preCaptureFocus = options.getBoolean("preCaptureFocus") setTextConfig(scanConfig.textConfig, options.optJSONObject("textConfig")) setButtonConfig(scanConfig.buttonConfig, options.optJSONObject("buttonConfig")) if(options.has("confirmPages")) scanConfig.confirmPages = options.getBoolean("confirmPages") if(options.has("allowPageEditing")) scanConfig.allowPageEditing = options.getBoolean("allowPageEditing") if(options.has("statusBarAppearance")) scanConfig.statusBarAppearance = getStatusBarAppearanceFromString(options.getString("statusBarAppearance")) if(options.has("navigationBarAppearance")) scanConfig.navigationBarAppearance = getNavigationBarAppearanceFromString(options.getString("navigationBarAppearance")) if(options.has("vibrateOnCapture")) scanConfig.vibrateOnCapture = options.getBoolean("vibrateOnCapture") if(options.has("onboarding")) { val value = options.optJSONObject("onboarding") if(value == null) { scanConfig.onboarding = null } else { setOnboardingConfig(scanConfig, options.optJSONObject("onboarding")!!) } } if(options.has("scanTips")) { val value = options.optJSONObject("scanTips") if(value == null) { scanConfig.scanTips = null } else { setScanTipsConfig(scanConfig, options.getJSONObject("scanTips")) } } if(NeedToMigrate && scanConfig.onboarding != null && scanConfig.onboarding!!.scanHintPopup != null) { val scanHintPopup = scanConfig.onboarding!!.scanHintPopup!!; // CheckMigration val optionsOnboarding = options.optJSONObject("onboarding") var optionsScanHintPopup : JSONObject? = null; if(optionsOnboarding != null) optionsScanHintPopup = optionsOnboarding.optJSONObject("scanHintPopup") if (options.has("onboardingImageSource") && (optionsScanHintPopup==null || !optionsScanHintPopup.has("imageSource"))) { val imgSource = options.getString("onboardingImageSource") scanHintPopup.imageSource = DocutainSDK.context.resources.getIdentifier( imgSource, "drawable", DocutainSDK.context.packageName ) } var optionsTextConfig = options.optJSONObject("textConfig") if(optionsTextConfig != null) { if (optionsTextConfig.has("textOnboardingTitle") && (optionsScanHintPopup==null || !optionsScanHintPopup.has("title"))) scanHintPopup.title = optionsTextConfig.getString("textOnboardingTitle") if (optionsTextConfig.has("textOnboardingMessage") && (optionsScanHintPopup==null || !optionsScanHintPopup.has("message"))) scanHintPopup.message = optionsTextConfig.getString("textOnboardingMessage") if (optionsTextConfig.has("textOnboardingCloseButton") && (optionsScanHintPopup==null || !optionsScanHintPopup.has("closeButton"))) scanHintPopup.closeButton = optionsTextConfig.getString("textOnboardingCloseButton") } } } catch(ex:Exception ) { Log.e(logTag, "mapDocumentScannerConfiguration Exception "+ ex) return false } return true } fun defaultItemsToJSONArray(defaultItems: List) : JSONArray { val array = JSONArray() defaultItems.forEach{ val item = JSONObject("{\"image\": "+ it.image+ ";\"title\":\""+ it.title+"\""+ ";\"message\":\""+ it.message+"\""+"}") array.put(item) } return array } private fun getImageSource(entry: JSONObject):Int? { if (entry.has("imageSource")) { val imgSource = entry.getString("imageSource") return DocutainSDK.context.resources.getIdentifier( imgSource, "drawable", DocutainSDK.context.packageName ) } return null } private fun readButtonConfig(key: String, docutainButton: DocutainButton , entry: JSONObject?, toolbarButton: Boolean=false) { if (entry != null) { val docutainButtonEntry = entry.optJSONObject(key) if (docutainButtonEntry != null) { if (docutainButtonEntry.has("title")) { docutainButton.title = docutainButtonEntry.getString("title"); if(toolbarButton) { docutainButton.icon = null; return } } if (docutainButtonEntry.has("icon")) { val imgSource = docutainButtonEntry.getString("icon") val imgIdentifier = DocutainSDK.context.resources.getIdentifier( imgSource, "drawable", DocutainSDK.context.packageName ) docutainButton.icon = imgIdentifier } } } } private fun readDocutainListItemConfig( entry: JSONObject) : DocutainListItem { var imgIdentifier = 0 if(entry.has("image")){ val imgSource = entry.getString("image") imgIdentifier = DocutainSDK.context.resources.getIdentifier( imgSource, "drawable", DocutainSDK.context.packageName ) } return DocutainListItem(imgIdentifier, entry.optString("title",""), entry.optString("message","")) } private fun mapPhotoPaymentConfiguration(data: JSONObject, photoPaymentConfig: PhotoPaymentConfiguration): Boolean { if(!mapDocumentScannerConfiguration(data, photoPaymentConfig)) return false; try { val optionsAnalyzeConfig : JSONObject? = data.optJSONObject("analyzeConfig") if (optionsAnalyzeConfig != null) { if(optionsAnalyzeConfig.has("readBIC")) photoPaymentConfig.analyzeConfig.readBIC = optionsAnalyzeConfig.getBoolean("readBIC") if(optionsAnalyzeConfig.has("readPaymentState")) photoPaymentConfig.analyzeConfig.readPaymentState = optionsAnalyzeConfig.getBoolean("readPaymentState") if(optionsAnalyzeConfig.has("readSEPACreditor")) photoPaymentConfig.analyzeConfig.readSEPACreditor = optionsAnalyzeConfig.getBoolean("readSEPACreditor") } if(data.has("emptyResultScreen")) { val optionsEmptyResultScreen = data.optJSONObject("emptyResultScreen") if(optionsEmptyResultScreen == null) { photoPaymentConfig.emptyResultScreen = null } else { var emptyResultScreen: EmptyResultScreen? = photoPaymentConfig.emptyResultScreen if (emptyResultScreen == null) { emptyResultScreen = EmptyResultScreen() photoPaymentConfig.emptyResultScreen = emptyResultScreen } if (optionsEmptyResultScreen.has("title")) emptyResultScreen.title = optionsEmptyResultScreen.getString("title") readButtonConfig( "repeatButton", emptyResultScreen.repeatButton, optionsEmptyResultScreen ) val optionsEmptyResultScreenItems = optionsEmptyResultScreen.optJSONArray("items") if (optionsEmptyResultScreenItems != null) { val items = ArrayList() for (i in 0 until optionsEmptyResultScreenItems.length()) { val docutainListItemEntry = optionsEmptyResultScreenItems.getJSONObject(i) items.add(readDocutainListItemConfig(docutainListItemEntry)) } if (items.isNullOrEmpty()) { emptyResultScreen.items = null; } else { emptyResultScreen.items = items; } } } } } catch(ex:Exception ) { Log.e(logTag, "mapPhotoPaymentConfiguration Exception "+ ex) return false } return true } }