cronapp-cordova-plugin-barcodescanner 2.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,738 @@
1
+ /*
2
+ * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
5
+ *
6
+ * http://www.apache.org/licenses/LICENSE-2.0
7
+ *
8
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
9
+ */
10
+
11
+ var urlutil = require('cordova/urlutil');
12
+
13
+ var CAMERA_STREAM_STATE_CHECK_RETRY_TIMEOUT = 200; // milliseconds
14
+ var OPERATION_IS_IN_PROGRESS = -2147024567;
15
+ var REGDB_E_CLASSNOTREG = -2147221164;
16
+ var INITIAL_FOCUS_DELAY = 200; // milliseconds
17
+ var CHECK_PLAYING_TIMEOUT = 100; // milliseconds
18
+
19
+ /**
20
+ * List of supported barcode formats from ZXing library. Used to return format
21
+ * name instead of number code as per plugin spec.
22
+ *
23
+ * @enum {String}
24
+ */
25
+ var BARCODE_FORMAT = {
26
+ 1: 'AZTEC',
27
+ 2: 'CODABAR',
28
+ 4: 'CODE_39',
29
+ 8: 'CODE_93',
30
+ 16: 'CODE_128',
31
+ 32: 'DATA_MATRIX',
32
+ 64: 'EAN_8',
33
+ 128: 'EAN_13',
34
+ 256: 'ITF',
35
+ 512: 'MAXICODE',
36
+ 1024: 'PDF_417',
37
+ 2048: 'QR_CODE',
38
+ 4096: 'RSS_14',
39
+ 8192: 'RSS_EXPANDED',
40
+ 16384: 'UPC_A',
41
+ 32768: 'UPC_E',
42
+ 61918: 'All_1D',
43
+ 65536: 'UPC_EAN_EXTENSION',
44
+ 131072: 'MSI',
45
+ 262144: 'PLESSEY'
46
+ };
47
+
48
+ /**
49
+ * Detects the first appropriate camera located at the back panel of device. If
50
+ * there is no back cameras, returns the first available.
51
+ *
52
+ * @returns {Promise<String>} Camera id
53
+ */
54
+ function findCamera() {
55
+ var Devices = Windows.Devices.Enumeration;
56
+
57
+ // Enumerate cameras and add them to the list
58
+ return Devices.DeviceInformation.findAllAsync(Devices.DeviceClass.videoCapture)
59
+ .then(function (cameras) {
60
+
61
+ if (!cameras || cameras.length === 0) {
62
+ throw new Error("No cameras found");
63
+ }
64
+
65
+ var backCameras = cameras.filter(function (camera) {
66
+ return camera.enclosureLocation && camera.enclosureLocation.panel === Devices.Panel.back;
67
+ });
68
+
69
+ // If there is back cameras, return the id of the first,
70
+ // otherwise take the first available device's id
71
+ return (backCameras[0] || cameras[0]).id;
72
+ });
73
+ }
74
+
75
+ /**
76
+ * @param {Windows.Graphics.Display.DisplayOrientations} displayOrientation
77
+ * @return {Number}
78
+ */
79
+ function videoPreviewRotationLookup(displayOrientation, isMirrored) {
80
+ var degreesToRotate;
81
+
82
+ switch (displayOrientation) {
83
+ case Windows.Graphics.Display.DisplayOrientations.landscape:
84
+ degreesToRotate = 0;
85
+ break;
86
+ case Windows.Graphics.Display.DisplayOrientations.portrait:
87
+ if (isMirrored) {
88
+ degreesToRotate = 270;
89
+ } else {
90
+ degreesToRotate = 90;
91
+ }
92
+ break;
93
+ case Windows.Graphics.Display.DisplayOrientations.landscapeFlipped:
94
+ degreesToRotate = 180;
95
+ break;
96
+ case Windows.Graphics.Display.DisplayOrientations.portraitFlipped:
97
+ if (isMirrored) {
98
+ degreesToRotate = 90;
99
+ } else {
100
+ degreesToRotate = 270;
101
+ }
102
+ break;
103
+ default:
104
+ degreesToRotate = 0;
105
+ break;
106
+ }
107
+
108
+ return degreesToRotate;
109
+ }
110
+
111
+ /**
112
+ * The pure JS implementation of barcode reader from WinRTBarcodeReader.winmd.
113
+ * Works only on Windows 10 devices and more efficient than original one.
114
+ *
115
+ * @class {BarcodeReader}
116
+ */
117
+ function BarcodeReader () {
118
+ this._promise = null;
119
+ this._cancelled = false;
120
+ }
121
+
122
+ /**
123
+ * Returns an instance of Barcode reader, depending on capabilities of Media
124
+ * Capture API
125
+ *
126
+ * @static
127
+ * @constructs {BarcodeReader}
128
+ *
129
+ * @param {MediaCapture} mediaCaptureInstance Instance of
130
+ * Windows.Media.Capture.MediaCapture class
131
+ *
132
+ * @return {BarcodeReader} BarcodeReader instance that could be used for
133
+ * scanning
134
+ */
135
+ BarcodeReader.get = function (mediaCaptureInstance) {
136
+ if (mediaCaptureInstance.getPreviewFrameAsync && ZXing.BarcodeReader) {
137
+ return new BarcodeReader();
138
+ }
139
+
140
+ // If there is no corresponding API (Win8/8.1/Phone8.1) use old approach with WinMD library
141
+ return new WinRTBarcodeReader.Reader();
142
+
143
+ };
144
+
145
+ /**
146
+ * Initializes instance of reader.
147
+ *
148
+ * @param {MediaCapture} capture Instance of
149
+ * Windows.Media.Capture.MediaCapture class, used for acquiring images/ video
150
+ * stream for barcode scanner.
151
+ * @param {Number} width Video/image frame width
152
+ * @param {Number} height Video/image frame height
153
+ */
154
+ BarcodeReader.prototype.init = function (capture, width, height) {
155
+ this._capture = capture;
156
+ this._width = width;
157
+ this._height = height;
158
+ this._zxingReader = new ZXing.BarcodeReader();
159
+ this._zxingReader.tryHarder = true;
160
+
161
+ var formatsList = BarcodeReader.scanCallArgs.args.length > 0 && BarcodeReader.scanCallArgs.args[0].formats;
162
+ if (formatsList) {
163
+ var possibleFormats = formatsList
164
+ .split(",")
165
+ .map(format => {
166
+ for (var index in BARCODE_FORMAT) {
167
+ if (BARCODE_FORMAT[index] === format) {
168
+ return index;
169
+ }
170
+ }
171
+ });
172
+
173
+ this._zxingReader.possibleFormats = possibleFormats;
174
+ }
175
+ };
176
+
177
+ /**
178
+ * Starts barcode search routines asyncronously.
179
+ *
180
+ * @return {Promise<ScanResult>} barcode scan result or null if search
181
+ * cancelled.
182
+ */
183
+ BarcodeReader.prototype.readCode = function () {
184
+
185
+ /**
186
+ * Grabs a frame from preview stream uning Win10-only API and tries to
187
+ * get a barcode using zxing reader provided. If there is no barcode
188
+ * found, returns null.
189
+ */
190
+ function scanBarcodeAsync(mediaCapture, zxingReader, frameWidth, frameHeight) {
191
+ // Shortcuts for namespaces
192
+ var Imaging = Windows.Graphics.Imaging;
193
+ var Streams = Windows.Storage.Streams;
194
+
195
+ var frame = new Windows.Media.VideoFrame(Imaging.BitmapPixelFormat.bgra8, frameWidth, frameHeight);
196
+ return mediaCapture.getPreviewFrameAsync(frame)
197
+ .then(function (capturedFrame) {
198
+
199
+ // Copy captured frame to buffer for further deserialization
200
+ var bitmap = capturedFrame.softwareBitmap;
201
+ var rawBuffer = new Streams.Buffer(bitmap.pixelWidth * bitmap.pixelHeight * 4);
202
+ capturedFrame.softwareBitmap.copyToBuffer(rawBuffer);
203
+ capturedFrame.close();
204
+
205
+ // Get raw pixel data from buffer
206
+ var data = new Uint8Array(rawBuffer.length);
207
+ var dataReader = Streams.DataReader.fromBuffer(rawBuffer);
208
+ dataReader.readBytes(data);
209
+ dataReader.close();
210
+
211
+ return zxingReader.decode(data, frameWidth, frameHeight, ZXing.BitmapFormat.bgra32);
212
+ });
213
+ }
214
+
215
+ var self = this;
216
+ return scanBarcodeAsync(this._capture, this._zxingReader, this._width, this._height)
217
+ .then(function (result) {
218
+ if (self._cancelled)
219
+ return null;
220
+
221
+ return result || (self._promise = self.readCode());
222
+ });
223
+ };
224
+
225
+ /**
226
+ * Stops barcode search
227
+ */
228
+ BarcodeReader.prototype.stop = function () {
229
+ this._cancelled = true;
230
+ };
231
+
232
+ function degreesToRotation(degrees) {
233
+ switch (degrees) {
234
+ // portrait
235
+ case 90:
236
+ return Windows.Media.Capture.VideoRotation.clockwise90Degrees;
237
+ // landscape
238
+ case 0:
239
+ return Windows.Media.Capture.VideoRotation.none;
240
+ // portrait-flipped
241
+ case 270:
242
+ return Windows.Media.Capture.VideoRotation.clockwise270Degrees;
243
+ // landscape-flipped
244
+ case 180:
245
+ return Windows.Media.Capture.VideoRotation.clockwise180Degrees;
246
+ default:
247
+ // Falling back to portrait default
248
+ return Windows.Media.Capture.VideoRotation.clockwise90Degrees;
249
+ }
250
+ }
251
+
252
+ module.exports = {
253
+
254
+ /**
255
+ * Scans image via device camera and retieves barcode from it.
256
+ * @param {function} success Success callback
257
+ * @param {function} fail Error callback
258
+ * @param {array} args Arguments array
259
+ */
260
+ scan: function (success, fail, args) {
261
+ var capturePreview,
262
+ capturePreviewAlignmentMark,
263
+ captureCancelButton,
264
+ navigationButtonsDiv,
265
+ previewMirroring,
266
+ closeButton,
267
+ capture,
268
+ reader;
269
+
270
+ // Save call state for suspend/resume
271
+ BarcodeReader.scanCallArgs = {
272
+ success: success,
273
+ fail: fail,
274
+ args: args
275
+ };
276
+
277
+ function updatePreviewForRotation(evt) {
278
+ if (!capture) {
279
+ return;
280
+ }
281
+
282
+ var displayInformation = (evt && evt.target) || Windows.Graphics.Display.DisplayInformation.getForCurrentView();
283
+ var currentOrientation = displayInformation.currentOrientation;
284
+
285
+ previewMirroring = capture.getPreviewMirroring();
286
+
287
+ // Lookup up the rotation degrees.
288
+ var rotDegree = videoPreviewRotationLookup(currentOrientation, previewMirroring);
289
+
290
+ capture.setPreviewRotation(degreesToRotation(rotDegree));
291
+ return WinJS.Promise.as();
292
+ }
293
+
294
+ /**
295
+ * Creates a preview frame and necessary objects
296
+ */
297
+ function createPreview() {
298
+
299
+ // Create fullscreen preview
300
+ var capturePreviewFrameStyle = document.createElement('link');
301
+ capturePreviewFrameStyle.rel = "stylesheet";
302
+ capturePreviewFrameStyle.type = "text/css";
303
+ capturePreviewFrameStyle.href = urlutil.makeAbsolute("/www/css/plugin-barcodeScanner.css");
304
+
305
+ document.head.appendChild(capturePreviewFrameStyle);
306
+
307
+ capturePreviewFrame = document.createElement('div');
308
+ capturePreviewFrame.className = "barcode-scanner-wrap";
309
+
310
+ capturePreview = document.createElement("video");
311
+ capturePreview.className = "barcode-scanner-preview";
312
+ capturePreview.addEventListener('click', function () {
313
+ focus();
314
+ });
315
+
316
+ capturePreviewAlignmentMark = document.createElement('div');
317
+ capturePreviewAlignmentMark.className = "barcode-scanner-mark";
318
+
319
+ navigationButtonsDiv = document.createElement("div");
320
+ navigationButtonsDiv.className = "barcode-scanner-app-bar";
321
+ navigationButtonsDiv.onclick = function (e) {
322
+ e.cancelBubble = true;
323
+ };
324
+
325
+ closeButton = document.createElement("div");
326
+ closeButton.innerText = "close";
327
+ closeButton.className = "app-bar-action action-close";
328
+ navigationButtonsDiv.appendChild(closeButton);
329
+
330
+ BarcodeReader.scanCancelled = false;
331
+ closeButton.addEventListener("click", cancelPreview, false);
332
+ document.addEventListener('backbutton', cancelPreview, false);
333
+
334
+ [capturePreview, capturePreviewAlignmentMark, navigationButtonsDiv].forEach(function (element) {
335
+ capturePreviewFrame.appendChild(element);
336
+ });
337
+ }
338
+
339
+ function focus(controller) {
340
+
341
+ var result = WinJS.Promise.wrap();
342
+
343
+ if (!capturePreview || capturePreview.paused) {
344
+ // If the preview is not yet playing, there is no sense in running focus
345
+ return result;
346
+ }
347
+
348
+ if (!controller) {
349
+ try {
350
+ controller = capture && capture.videoDeviceController;
351
+ } catch (err) {
352
+ console.log('Failed to access focus control for current camera: ' + err);
353
+ return result;
354
+ }
355
+ }
356
+
357
+ if (!controller.focusControl || !controller.focusControl.supported) {
358
+ console.log('Focus control for current camera is not supported');
359
+ return result;
360
+ }
361
+
362
+ // Multiple calls to focusAsync leads to internal focusing hang on some Windows Phone 8.1 devices
363
+ // Also need to wrap in try/catch to avoid crash on Surface 3 - looks like focusState property
364
+ // somehow is not accessible there. See https://github.com/phonegap/phonegap-plugin-barcodescanner/issues/288
365
+ try {
366
+ if (controller.focusControl.focusState === Windows.Media.Devices.MediaCaptureFocusState.searching) {
367
+ return result;
368
+ }
369
+ } catch (e) {
370
+ // Nothing to do - just continue w/ focusing
371
+ }
372
+
373
+ // The delay prevents focus hang on slow devices
374
+ return WinJS.Promise.timeout(INITIAL_FOCUS_DELAY)
375
+ .then(function () {
376
+ try {
377
+ return controller.focusControl.focusAsync().then(function () {
378
+ return result;
379
+ }, function (e) {
380
+ // This happens on mutliple taps
381
+ if (e.number !== OPERATION_IS_IN_PROGRESS) {
382
+ console.error('focusAsync failed: ' + e);
383
+ return WinJS.Promise.wrapError(e);
384
+ }
385
+ return result;
386
+ });
387
+ } catch (e) {
388
+ // This happens on mutliple taps
389
+ if (e.number !== OPERATION_IS_IN_PROGRESS) {
390
+ console.error('focusAsync failed: ' + e);
391
+ return WinJS.Promise.wrapError(e);
392
+ }
393
+ return result;
394
+ }
395
+ });
396
+ }
397
+
398
+ function setupFocus(focusControl) {
399
+
400
+ function supportsFocusMode(mode) {
401
+ return focusControl.supportedFocusModes.indexOf(mode).returnValue;
402
+ }
403
+
404
+ if (!focusControl || !focusControl.supported || !focusControl.configure) {
405
+ return WinJS.Promise.wrap();
406
+ }
407
+
408
+ var FocusMode = Windows.Media.Devices.FocusMode;
409
+ var focusConfig = new Windows.Media.Devices.FocusSettings();
410
+ focusConfig.autoFocusRange = Windows.Media.Devices.AutoFocusRange.normal;
411
+
412
+ // Determine a focus position if the focus search fails:
413
+ focusConfig.disableDriverFallback = false;
414
+
415
+ if (supportsFocusMode(FocusMode.continuous)) {
416
+ console.log("Device supports continuous focus mode");
417
+ focusConfig.mode = FocusMode.continuous;
418
+ } else if (supportsFocusMode(FocusMode.auto)) {
419
+ console.log("Device doesn\'t support continuous focus mode, switching to autofocus mode");
420
+ focusConfig.mode = FocusMode.auto;
421
+ }
422
+
423
+ focusControl.configure(focusConfig);
424
+
425
+ // Continuous focus should start only after preview has started. See 'Remarks' at
426
+ // https://msdn.microsoft.com/en-us/library/windows/apps/windows.media.devices.focuscontrol.configure.aspx
427
+ function waitForIsPlaying() {
428
+ var isPlaying = !capturePreview.paused && !capturePreview.ended && capturePreview.readyState > 2;
429
+
430
+ if (!isPlaying) {
431
+ return WinJS.Promise.timeout(CHECK_PLAYING_TIMEOUT)
432
+ .then(function () {
433
+ return waitForIsPlaying();
434
+ });
435
+ }
436
+
437
+ return focus();
438
+ }
439
+
440
+ return waitForIsPlaying();
441
+ }
442
+
443
+ function disableZoomAndScroll() {
444
+ document.body.classList.add('no-zoom');
445
+ document.body.classList.add('no-scroll');
446
+ }
447
+
448
+ function enableZoomAndScroll() {
449
+ document.body.classList.remove('no-zoom');
450
+ document.body.classList.remove('no-scroll');
451
+ }
452
+
453
+ /**
454
+ * Starts stream transmission to preview frame and then run barcode search
455
+ */
456
+ function startPreview() {
457
+ return findCamera()
458
+ .then(function (id) {
459
+ var captureSettings;
460
+
461
+ try {
462
+ captureSettings = new Windows.Media.Capture.MediaCaptureInitializationSettings();
463
+ } catch (e) {
464
+ if (e.number === REGDB_E_CLASSNOTREG) {
465
+ throw new Error('Ensure that you have Windows Media Player and Media Feature pack installed.');
466
+ }
467
+
468
+ throw e;
469
+ }
470
+
471
+ captureSettings.streamingCaptureMode = Windows.Media.Capture.StreamingCaptureMode.video;
472
+ captureSettings.photoCaptureSource = Windows.Media.Capture.PhotoCaptureSource.videoPreview;
473
+ captureSettings.videoDeviceId = id;
474
+
475
+ capture = new Windows.Media.Capture.MediaCapture();
476
+ return capture.initializeAsync(captureSettings);
477
+ })
478
+ .then(function () {
479
+
480
+ var controller = capture.videoDeviceController;
481
+ var deviceProps = controller.getAvailableMediaStreamProperties(Windows.Media.Capture.MediaStreamType.videoPreview);
482
+
483
+ deviceProps = Array.prototype.slice.call(deviceProps);
484
+ deviceProps = deviceProps.filter(function (prop) {
485
+ // filter out streams with "unknown" subtype - causes errors on some devices
486
+ return prop.subtype !== "Unknown";
487
+ }).sort(function (propA, propB) {
488
+ // sort properties by resolution
489
+ return propB.width - propA.width;
490
+ });
491
+
492
+ var preferredProps = deviceProps.filter(function(prop){
493
+ // Filter out props where frame size is between 640*480 and 1280*720
494
+ return prop.width >= 640 && prop.height >= 480 && prop.width <= 1280 && prop.height <= 720;
495
+ });
496
+
497
+ // prefer video frame size between between 640*480 and 1280*720
498
+ // use maximum resolution otherwise
499
+ var maxResProps = preferredProps[0] || deviceProps[0];
500
+ return controller.setMediaStreamPropertiesAsync(Windows.Media.Capture.MediaStreamType.videoPreview, maxResProps)
501
+ .then(function () {
502
+ return {
503
+ capture: capture,
504
+ width: maxResProps.width,
505
+ height: maxResProps.height
506
+ };
507
+ });
508
+ })
509
+ .then(function (captureSettings) {
510
+
511
+ capturePreview.msZoom = true;
512
+ capturePreview.src = URL.createObjectURL(capture);
513
+ capturePreview.play();
514
+
515
+ // Insert preview frame and controls into page
516
+ document.body.appendChild(capturePreviewFrame);
517
+
518
+ disableZoomAndScroll();
519
+
520
+ return setupFocus(captureSettings.capture.videoDeviceController.focusControl)
521
+ .then(function () {
522
+ Windows.Graphics.Display.DisplayInformation.getForCurrentView().addEventListener("orientationchanged", updatePreviewForRotation, false);
523
+ return updatePreviewForRotation();
524
+ })
525
+ .then(function () {
526
+
527
+ if (!Windows.Media.Devices.CameraStreamState) {
528
+ // CameraStreamState is available starting with Windows 10 so skip this check for 8.1
529
+ // https://msdn.microsoft.com/en-us/library/windows/apps/windows.media.devices.camerastreamstate
530
+ return WinJS.Promise.as();
531
+ }
532
+
533
+ function checkCameraStreamState() {
534
+ if (capture.cameraStreamState !== Windows.Media.Devices.CameraStreamState.streaming) {
535
+
536
+ // Using loop as MediaCapture.CameraStreamStateChanged does not fire with CameraStreamState.streaming state.
537
+ return WinJS.Promise.timeout(CAMERA_STREAM_STATE_CHECK_RETRY_TIMEOUT)
538
+ .then(function () {
539
+ return checkCameraStreamState();
540
+ });
541
+ }
542
+
543
+ return WinJS.Promise.as();
544
+ }
545
+
546
+ // Ensure CameraStreamState is Streaming
547
+ return checkCameraStreamState();
548
+ })
549
+ .then(function () {
550
+ return captureSettings;
551
+ });
552
+ });
553
+ }
554
+
555
+ /**
556
+ * Removes preview frame and corresponding objects from window
557
+ */
558
+ function destroyPreview() {
559
+ var promise = WinJS.Promise.as();
560
+
561
+ Windows.Graphics.Display.DisplayInformation.getForCurrentView().removeEventListener("orientationchanged", updatePreviewForRotation, false);
562
+ document.removeEventListener('backbutton', cancelPreview);
563
+
564
+ if (capturePreview) {
565
+ var isPlaying = !capturePreview.paused && !capturePreview.ended && capturePreview.readyState > 2;
566
+ if (isPlaying) {
567
+ capturePreview.pause();
568
+ }
569
+
570
+ // http://stackoverflow.com/a/28060352/4177762
571
+ capturePreview.src = "";
572
+ if (capturePreview.load) {
573
+ capturePreview.load();
574
+ }
575
+ }
576
+
577
+ if (capturePreviewFrame) {
578
+ try {
579
+ document.body.removeChild(capturePreviewFrame);
580
+ } catch (e) {
581
+ // Catching NotFoundError
582
+ console.error(e);
583
+ }
584
+ }
585
+ capturePreviewFrame = null;
586
+
587
+ reader && reader.stop();
588
+ reader = null;
589
+
590
+ if (capture) {
591
+ try {
592
+ promise = capture.stopRecordAsync();
593
+ } catch (e) {
594
+ // Catching NotFoundError
595
+ console.error(e);
596
+ }
597
+ }
598
+ capture = null;
599
+
600
+ enableZoomAndScroll();
601
+
602
+ return promise;
603
+ }
604
+
605
+ /**
606
+ * Stops preview and then call success callback with cancelled=true
607
+ * See https://github.com/phonegap-build/BarcodeScanner#using-the-plugin
608
+ */
609
+ function cancelPreview() {
610
+ BarcodeReader.scanCancelled = true;
611
+ reader && reader.stop();
612
+ }
613
+
614
+ function checkCancelled() {
615
+ if (BarcodeReader.scanCancelled || BarcodeReader.suspended) {
616
+ throw new Error('Canceled');
617
+ }
618
+ }
619
+
620
+ // Timeout is needed so that the .done finalizer below can be attached to the promise.
621
+ BarcodeReader.scanPromise = WinJS.Promise.timeout()
622
+ .then(function() {
623
+ createPreview();
624
+ checkCancelled();
625
+ return startPreview();
626
+ })
627
+ .then(function (captureSettings) {
628
+ checkCancelled();
629
+ reader = BarcodeReader.get(captureSettings.capture);
630
+ reader.init(captureSettings.capture, captureSettings.width, captureSettings.height);
631
+
632
+ // Add a small timeout before capturing first frame otherwise
633
+ // we would get an 'Invalid state' error from 'getPreviewFrameAsync'
634
+ return WinJS.Promise.timeout(200)
635
+ .then(function () {
636
+ checkCancelled();
637
+ return reader.readCode();
638
+ });
639
+ })
640
+ .then(function (result) {
641
+ // Suppress null result (cancel) on suspending
642
+ if (BarcodeReader.suspended) {
643
+ return;
644
+ }
645
+
646
+ destroyPreview();
647
+ success({
648
+ text: result && result.text,
649
+ format: result && BARCODE_FORMAT[result.barcodeFormat],
650
+ cancelled: !result
651
+ });
652
+ });
653
+
654
+ // Catching any errors here
655
+ BarcodeReader.scanPromise.done(function () { }, function (error) {
656
+ // Suppress null result (cancel) on suspending
657
+ if (BarcodeReader.suspended) {
658
+ return;
659
+ }
660
+
661
+ destroyPreview();
662
+ if (error.message == 'Canceled') {
663
+ success({
664
+ cancelled: true
665
+ });
666
+ } else {
667
+ fail(error);
668
+ }
669
+ });
670
+
671
+ BarcodeReader.videoPreviewIsVisible = function () {
672
+ return capturePreviewFrame !== null;
673
+ }
674
+
675
+ BarcodeReader.destroyPreview = destroyPreview;
676
+ },
677
+
678
+ /**
679
+ * Encodes specified data into barcode
680
+ * @param {function} success Success callback
681
+ * @param {function} fail Error callback
682
+ * @param {array} args Arguments array
683
+ */
684
+ encode: function (success, fail, args) {
685
+ fail("Not implemented yet");
686
+ }
687
+ };
688
+
689
+ var app = WinJS.Application;
690
+
691
+ function waitForScanEnd() {
692
+ return BarcodeReader.scanPromise || WinJS.Promise.as();
693
+ }
694
+
695
+ function suspend(args) {
696
+ BarcodeReader.suspended = true;
697
+ if (args) {
698
+ args.setPromise(BarcodeReader.destroyPreview()
699
+ .then(waitForScanEnd, waitForScanEnd));
700
+ } else {
701
+ BarcodeReader.destroyPreview();
702
+ }
703
+ }
704
+
705
+ function resume() {
706
+ BarcodeReader.suspended = false;
707
+ module.exports.scan(BarcodeReader.scanCallArgs.success, BarcodeReader.scanCallArgs.fail, BarcodeReader.scanCallArgs.args);
708
+ }
709
+
710
+ function onVisibilityChanged() {
711
+ if (document.visibilityState === 'hidden'
712
+ && BarcodeReader.videoPreviewIsVisible && BarcodeReader.videoPreviewIsVisible() && BarcodeReader.destroyPreview) {
713
+ suspend();
714
+ } else if (BarcodeReader.suspended) {
715
+ resume();
716
+ }
717
+ }
718
+
719
+ // Windows 8.1 projects
720
+ document.addEventListener('msvisibilitychange', onVisibilityChanged);
721
+ // Windows 10 projects
722
+ document.addEventListener('visibilitychange', onVisibilityChanged);
723
+
724
+ // About to be suspended
725
+ app.addEventListener('checkpoint', function (args) {
726
+ if (BarcodeReader.videoPreviewIsVisible && BarcodeReader.videoPreviewIsVisible() && BarcodeReader.destroyPreview) {
727
+ suspend(args);
728
+ }
729
+ });
730
+
731
+ // Resuming from a user suspension
732
+ Windows.UI.WebUI.WebUIApplication.addEventListener("resuming", function () {
733
+ if (BarcodeReader.suspended) {
734
+ resume();
735
+ }
736
+ }, false);
737
+
738
+ require("cordova/exec/proxy").add("BarcodeScanner", module.exports);