357 lines
12 KiB
Plaintext
357 lines
12 KiB
Plaintext
import Activity from 'android.app.Activity'
|
|
import Intent from 'android.content.Intent'
|
|
|
|
import { OpenCodeScan, CodeScanErrorCode, CodeScanOptions, CodeScanSuccess } from '../interface.uts'
|
|
import { CodeScanFailImpl } from '../unierror.uts'
|
|
|
|
const LAUNCH_REQ: Int = 53011
|
|
const EXTRA_PAYLOAD = 'mas_content'
|
|
const EXTRA_FORMAT = 'mas_format'
|
|
const EXTRA_TITLE = 'mas_title'
|
|
const EXTRA_HINT = 'mas_hint'
|
|
const EXTRA_SUCCESS_HINT = 'mas_success_hint'
|
|
const EXTRA_EMPTY_HINT = 'mas_empty_hint'
|
|
const EXTRA_SMART_ZOOM = 'mas_smart_zoom'
|
|
const EXTRA_TORCH_MODE = 'mas_torch_mode'
|
|
const EXTRA_RESULT_MODE = 'mas_result_mode'
|
|
const EXTRA_SHOW_PAUSE_BUTTON = 'mas_show_pause_button'
|
|
const EXTRA_VIBRATE = 'mas_vibrate'
|
|
const EXTRA_CONTINUOUS = 'mas_continuous'
|
|
const EXTRA_FROM_ALBUM = 'mas_from_album'
|
|
const EXTRA_FORMATS = 'mas_formats'
|
|
const EXTRA_SCAN_REGION_ENABLED = 'mas_scan_region_enabled'
|
|
const EXTRA_SCAN_REGION = 'mas_scan_region'
|
|
const EXTRA_SCAN_STYLE_SHOW_MASK = 'mas_scan_style_show_mask'
|
|
const EXTRA_SCAN_STYLE_SHOW_BEAM = 'mas_scan_style_show_beam'
|
|
const EXTRA_SCAN_STYLE_BORDER_COLOR = 'mas_scan_style_border_color'
|
|
const EXTRA_SCAN_STYLE_MASK_COLOR = 'mas_scan_style_mask_color'
|
|
const EXTRA_SCAN_STYLE_BEAM_COLOR = 'mas_scan_style_beam_color'
|
|
const EXTRA_SCAN_STYLE_BEAM_DURATION = 'mas_scan_style_beam_duration'
|
|
const EXTRA_SCAN_STYLE_CORNER = 'mas_scan_style_corner'
|
|
const EXTRA_SCAN_STYLE_CORNER_RADIUS = 'mas_scan_style_corner_radius'
|
|
const EXTRA_SCAN_TIMEOUT = 'mas_scan_timeout'
|
|
const EXTRA_CONTINUOUS_SUCCESS_DURATION = 'mas_continuous_success_duration'
|
|
const EXTRA_ERR = 'mas_err'
|
|
const EXTRA_FROM_ALBUM_RESULT = 'mas_result_from_album'
|
|
const EXTRA_HAD_HITS = 'mas_had_hits'
|
|
const CAPTURE_ACTIVITY = 'uts.sdk.modules.masCodeScan.CodeCaptureActivity'
|
|
|
|
let activityResultHook: ((requestCode: Int, resultCode: Int, data?: Intent) => void) | null = null
|
|
let activeOptions: CodeScanOptions | null = null
|
|
let continuousHitCount: Int = 0
|
|
let pollTimerId: number = -1
|
|
let sessionContinuous: boolean = false
|
|
let continuousSuccess: ((res: CodeScanSuccess) => void) | null = null
|
|
|
|
@UTSJS.keepAlive
|
|
export function openCodeScan(options?: CodeScanOptions | null): void {
|
|
const opts = options != null ? options : null
|
|
const host = UTSAndroid.getUniActivity()
|
|
if (host == null) {
|
|
emitFailure(opts, 9021001)
|
|
return
|
|
}
|
|
launchCapture(host, opts)
|
|
}
|
|
|
|
function clearPollTimer() {
|
|
if (pollTimerId >= 0) {
|
|
clearInterval(pollTimerId)
|
|
pollTimerId = -1
|
|
}
|
|
}
|
|
|
|
function drainHits() {
|
|
const current = activeOptions
|
|
const success = continuousSuccess
|
|
if (current == null || success == null) return
|
|
while (true) {
|
|
const hit = CodeScanHitBus.pollHit()
|
|
if (hit == null) break
|
|
const content = hit[0]
|
|
const format = hit[1]
|
|
const fromAlbumFlag = hit[2]
|
|
if (content == null || format == null || fromAlbumFlag == null) continue
|
|
continuousHitCount++
|
|
const ok: CodeScanSuccess = {
|
|
content: content,
|
|
format: format,
|
|
fromAlbum: fromAlbumFlag == '1'
|
|
}
|
|
success(ok)
|
|
}
|
|
}
|
|
|
|
function launchCapture(host: Activity, opts: CodeScanOptions | null): void {
|
|
if (activityResultHook != null) {
|
|
UTSAndroid.offAppActivityResult(activityResultHook)
|
|
activityResultHook = null
|
|
}
|
|
clearPollTimer()
|
|
CodeScanHitBus.detach()
|
|
activeOptions = opts
|
|
continuousHitCount = 0
|
|
sessionContinuous = opts != null && opts.continuous == true
|
|
continuousSuccess = sessionContinuous && opts != null ? opts.success : null
|
|
if (sessionContinuous) {
|
|
pollTimerId = setInterval(() => {
|
|
drainHits()
|
|
}, 120)
|
|
}
|
|
|
|
const onResult = (requestCode: Int, resultCode: Int, data?: Intent) => {
|
|
if (requestCode != LAUNCH_REQ) {
|
|
return
|
|
}
|
|
|
|
UTSAndroid.offAppActivityResult()
|
|
activityResultHook = null
|
|
drainHits()
|
|
clearPollTimer()
|
|
CodeScanHitBus.detach()
|
|
|
|
const current = activeOptions
|
|
const wasContinuous = sessionContinuous
|
|
sessionContinuous = false
|
|
|
|
if (resultCode != Activity.RESULT_OK) {
|
|
let errCode: CodeScanErrorCode = 9021003
|
|
if (data != null) {
|
|
const nativeErr = data.getIntExtra(EXTRA_ERR, 0)
|
|
if (nativeErr >= 9021002 && nativeErr <= 9021011) {
|
|
errCode = nativeErr as CodeScanErrorCode
|
|
}
|
|
}
|
|
// 连续扫已有命中:关闭只 complete,不 fail
|
|
if (wasContinuous && continuousHitCount > 0) {
|
|
if (current != null) {
|
|
current.complete?.({ closed: true, hitCount: continuousHitCount })
|
|
}
|
|
activeOptions = null
|
|
continuousSuccess = null
|
|
return
|
|
}
|
|
if (wasContinuous && data != null && data.getBooleanExtra(EXTRA_HAD_HITS, false)) {
|
|
if (current != null) {
|
|
current.complete?.({ closed: true, hitCount: continuousHitCount })
|
|
}
|
|
activeOptions = null
|
|
continuousSuccess = null
|
|
return
|
|
}
|
|
if (wasContinuous && current != null) {
|
|
emitFailure(current, errCode)
|
|
const complete = current.complete
|
|
if (complete != null) {
|
|
complete({ closed: true, hitCount: continuousHitCount, failed: true, errCode: errCode })
|
|
}
|
|
activeOptions = null
|
|
continuousSuccess = null
|
|
return
|
|
}
|
|
emitFailure(current, errCode)
|
|
activeOptions = null
|
|
continuousSuccess = null
|
|
return
|
|
}
|
|
|
|
if (wasContinuous) {
|
|
if (current != null) {
|
|
current.complete?.({ closed: true, hitCount: continuousHitCount })
|
|
}
|
|
activeOptions = null
|
|
continuousSuccess = null
|
|
return
|
|
}
|
|
|
|
let payload = ''
|
|
let formatName = ''
|
|
let fromAlbum = false
|
|
if (data != null) {
|
|
const rawPayload = data.getStringExtra(EXTRA_PAYLOAD)
|
|
const rawFormat = data.getStringExtra(EXTRA_FORMAT)
|
|
payload = rawPayload != null ? rawPayload : ''
|
|
formatName = rawFormat != null ? rawFormat : ''
|
|
fromAlbum = data.getBooleanExtra(EXTRA_FROM_ALBUM_RESULT, false)
|
|
}
|
|
|
|
if (payload == '') {
|
|
emitFailure(current, 9021004)
|
|
activeOptions = null
|
|
continuousSuccess = null
|
|
return
|
|
}
|
|
|
|
const ok: CodeScanSuccess = {
|
|
content: payload,
|
|
format: formatName,
|
|
fromAlbum: fromAlbum
|
|
}
|
|
if (current != null) {
|
|
current.success?.(ok)
|
|
current.complete?.(ok)
|
|
}
|
|
activeOptions = null
|
|
continuousSuccess = null
|
|
}
|
|
|
|
activityResultHook = onResult
|
|
UTSAndroid.onAppActivityResult(onResult)
|
|
|
|
let pageTitle = '扫一扫'
|
|
let scanHint = '请将条码放入扫描框内'
|
|
let successHint = '扫码成功'
|
|
let emptyHint = '未识别到有效条码'
|
|
let useSmartZoom = true
|
|
let useTorchMode = 'off'
|
|
let useResultMode = 'immediate'
|
|
let useShowPauseButton = false
|
|
let useVibrate = true
|
|
let useContinuous = false
|
|
let useFromAlbum = false
|
|
let useScanRegion = false
|
|
let regionWidth = 0.74
|
|
let regionHeight = 0.74
|
|
let regionCenterX = 0.5
|
|
let regionCenterY = 0.5
|
|
let formatsCsv = ''
|
|
let styleShowMask = true
|
|
let styleShowBeam = true
|
|
let styleBorderColor = '#19be6b'
|
|
let styleMaskColor = 'rgba(0, 0, 0, 0.45)'
|
|
let styleBeamColor = '#12e880'
|
|
let styleBeamDuration = 1800
|
|
let styleCorner = 'corner'
|
|
let styleCornerRadius = 20
|
|
let scanTimeout = 0
|
|
let continuousSuccessDuration = 1000
|
|
if (opts != null) {
|
|
if (opts.title != null && opts.title!.trim().length > 0) {
|
|
pageTitle = opts.title!.trim()
|
|
}
|
|
if (opts.hint != null && opts.hint!.trim().length > 0) {
|
|
scanHint = opts.hint!.trim()
|
|
}
|
|
if (opts.successHint != null && opts.successHint!.trim().length > 0) {
|
|
successHint = opts.successHint!.trim()
|
|
}
|
|
if (opts.emptyHint != null && opts.emptyHint!.trim().length > 0) {
|
|
emptyHint = opts.emptyHint!.trim()
|
|
}
|
|
if (opts.smartZoom != null) {
|
|
useSmartZoom = opts.smartZoom!
|
|
}
|
|
if (opts.torch == 'on' || opts.torch == 'auto' || opts.torch == 'off') {
|
|
useTorchMode = opts.torch!
|
|
}
|
|
if (opts.resultMode == 'confirm' || opts.resultMode == 'pause' || opts.resultMode == 'immediate') {
|
|
useResultMode = opts.resultMode!
|
|
}
|
|
if (opts.showPauseButton != null) {
|
|
useShowPauseButton = opts.showPauseButton!
|
|
}
|
|
if (opts.vibrate != null) {
|
|
useVibrate = opts.vibrate!
|
|
}
|
|
if (opts.continuous != null) {
|
|
useContinuous = opts.continuous!
|
|
}
|
|
if (opts.fromAlbum != null) {
|
|
useFromAlbum = opts.fromAlbum!
|
|
}
|
|
if (opts.scanRegion != null) {
|
|
useScanRegion = opts.scanRegion!.fullScreen != true
|
|
if (opts.scanRegion!.width != null) {
|
|
regionWidth = opts.scanRegion!.width!
|
|
}
|
|
if (opts.scanRegion!.height != null) {
|
|
regionHeight = opts.scanRegion!.height!
|
|
}
|
|
if (opts.scanRegion!.centerX != null) {
|
|
regionCenterX = opts.scanRegion!.centerX!
|
|
}
|
|
if (opts.scanRegion!.centerY != null) {
|
|
regionCenterY = opts.scanRegion!.centerY!
|
|
}
|
|
}
|
|
if (opts.scanTimeout != null) {
|
|
scanTimeout = Math.floor(opts.scanTimeout!)
|
|
}
|
|
if (opts.continuousSuccessDuration != null) {
|
|
continuousSuccessDuration = Math.max(0, Math.min(600000, Math.floor(opts.continuousSuccessDuration!)))
|
|
}
|
|
if (opts.scanStyle != null) {
|
|
if (opts.scanStyle!.showMask != null) {
|
|
styleShowMask = opts.scanStyle!.showMask!
|
|
}
|
|
if (opts.scanStyle!.showBeam != null) {
|
|
styleShowBeam = opts.scanStyle!.showBeam!
|
|
}
|
|
if (opts.scanStyle!.borderColor != null) {
|
|
styleBorderColor = opts.scanStyle!.borderColor!
|
|
}
|
|
if (opts.scanStyle!.maskColor != null) {
|
|
styleMaskColor = opts.scanStyle!.maskColor!
|
|
}
|
|
if (opts.scanStyle!.beamColor != null) {
|
|
styleBeamColor = opts.scanStyle!.beamColor!
|
|
}
|
|
if (opts.scanStyle!.beamDuration != null) {
|
|
styleBeamDuration = opts.scanStyle!.beamDuration!
|
|
}
|
|
if (opts.scanStyle!.cornerStyle == 'full' || opts.scanStyle!.cornerStyle == 'corner' || opts.scanStyle!.cornerStyle == 'rounded' || opts.scanStyle!.cornerStyle == 'rounded-corner') {
|
|
styleCorner = opts.scanStyle!.cornerStyle!
|
|
}
|
|
if (opts.scanStyle!.cornerRadius != null) {
|
|
styleCornerRadius = Math.max(0, Math.min(160, Math.floor(opts.scanStyle!.cornerRadius!)))
|
|
}
|
|
}
|
|
if (opts.formats != null && opts.formats!.length > 0) {
|
|
const parts: string[] = []
|
|
for (let i = 0; i < opts.formats!.length; i++) {
|
|
const item = opts.formats![i]
|
|
if (item != null && item.length > 0) {
|
|
parts.push(item)
|
|
}
|
|
}
|
|
formatsCsv = parts.join(',')
|
|
}
|
|
}
|
|
|
|
const intent = new Intent()
|
|
intent.setClassName(host, CAPTURE_ACTIVITY)
|
|
intent.putExtra(EXTRA_TITLE, pageTitle)
|
|
intent.putExtra(EXTRA_HINT, scanHint)
|
|
intent.putExtra(EXTRA_SUCCESS_HINT, successHint)
|
|
intent.putExtra(EXTRA_EMPTY_HINT, emptyHint)
|
|
intent.putExtra(EXTRA_SMART_ZOOM, useSmartZoom)
|
|
intent.putExtra(EXTRA_TORCH_MODE, useTorchMode)
|
|
intent.putExtra(EXTRA_RESULT_MODE, useResultMode)
|
|
intent.putExtra(EXTRA_SHOW_PAUSE_BUTTON, useShowPauseButton)
|
|
intent.putExtra(EXTRA_VIBRATE, useVibrate)
|
|
intent.putExtra(EXTRA_CONTINUOUS, useContinuous)
|
|
intent.putExtra(EXTRA_FROM_ALBUM, useFromAlbum)
|
|
intent.putExtra(EXTRA_FORMATS, formatsCsv)
|
|
intent.putExtra(EXTRA_SCAN_REGION_ENABLED, useScanRegion)
|
|
intent.putExtra(EXTRA_SCAN_REGION, `${regionWidth},${regionHeight},${regionCenterX},${regionCenterY}`)
|
|
intent.putExtra(EXTRA_SCAN_STYLE_SHOW_MASK, styleShowMask)
|
|
intent.putExtra(EXTRA_SCAN_STYLE_SHOW_BEAM, styleShowBeam)
|
|
intent.putExtra(EXTRA_SCAN_STYLE_BORDER_COLOR, styleBorderColor)
|
|
intent.putExtra(EXTRA_SCAN_STYLE_MASK_COLOR, styleMaskColor)
|
|
intent.putExtra(EXTRA_SCAN_STYLE_BEAM_COLOR, styleBeamColor)
|
|
intent.putExtra(EXTRA_SCAN_STYLE_BEAM_DURATION, styleBeamDuration)
|
|
intent.putExtra(EXTRA_SCAN_STYLE_CORNER, styleCorner)
|
|
intent.putExtra(EXTRA_SCAN_STYLE_CORNER_RADIUS, styleCornerRadius)
|
|
intent.putExtra(EXTRA_SCAN_TIMEOUT, scanTimeout)
|
|
intent.putExtra(EXTRA_CONTINUOUS_SUCCESS_DURATION, continuousSuccessDuration)
|
|
host.startActivityForResult(intent, LAUNCH_REQ)
|
|
}
|
|
|
|
function emitFailure(opts: CodeScanOptions | null, code: CodeScanErrorCode): void {
|
|
const err = new CodeScanFailImpl(code)
|
|
if (opts != null) {
|
|
opts.fail?.(err)
|
|
opts.complete?.(err)
|
|
}
|
|
}
|