|
|
/*jshint node: true */ /* global Q, resolveLocalFileSystemURL, Camera, cordova */ /* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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 * * http://www.apache.org/licenses/LICENSE-2.0
* * 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. * */
'use strict';
var cameraConstants = require('../../www/CameraConstants');
function findKeyByValue(set, value) { for (var k in set) { if (set.hasOwnProperty(k)) { if (set[k] == value) { return k; } } } return undefined; }
function getDescription(spec) { var desc = '';
desc += 'sourceType: ' + findKeyByValue(cameraConstants.PictureSourceType, spec.options.sourceType); desc += ', destinationType: ' + findKeyByValue(cameraConstants.DestinationType, spec.options.destinationType); desc += ', encodingType: ' + findKeyByValue(cameraConstants.EncodingType, spec.options.encodingType); desc += ', allowEdit: ' + spec.options.allowEdit.toString(); desc += ', correctOrientation: ' + spec.options.correctOrientation.toString();
return desc; }
module.exports.generateSpecs = function (sourceTypes, destinationTypes, encodingTypes, allowEditOptions, correctOrientationOptions) { var destinationType, sourceType, encodingType, allowEdit, correctOrientation, specs = [], id = 1; for (destinationType in destinationTypes) { if (destinationTypes.hasOwnProperty(destinationType)) { for (sourceType in sourceTypes) { if (sourceTypes.hasOwnProperty(sourceType)) { for (encodingType in encodingTypes) { if (encodingTypes.hasOwnProperty(encodingType)) { for (allowEdit in allowEditOptions) { if (allowEditOptions.hasOwnProperty(allowEdit)) { for (correctOrientation in correctOrientationOptions) { // if taking picture from photolibrary, don't vary 'correctOrientation' option
if ((sourceTypes[sourceType] === cameraConstants.PictureSourceType.PHOTOLIBRARY || sourceTypes[sourceType] === cameraConstants.PictureSourceType.SAVEDPHOTOALBUM) && correctOrientation === true) { continue; } var spec = { 'id': id++, 'options': { 'destinationType': destinationTypes[destinationType], 'sourceType': sourceTypes[sourceType], 'encodingType': encodingTypes[encodingType], 'allowEdit': allowEditOptions[allowEdit], 'saveToPhotoAlbum': false, 'correctOrientation': correctOrientationOptions[correctOrientation] } }; spec.description = getDescription(spec); specs.push(spec); } } } } } } } } } return specs; };
// calls getPicture() and saves the result in promise
// note that this function is executed in the context of tested app
// and not in the context of tests
module.exports.getPicture = function (opts, pid) { if (navigator._appiumPromises[pid - 1]) { navigator._appiumPromises[pid - 1] = null; } navigator._appiumPromises[pid] = Q.defer(); navigator.camera.getPicture(function (result) { navigator._appiumPromises[pid].resolve(result); }, function (err) { navigator._appiumPromises[pid].reject(err); }, opts); };
// verifies taken picture when the promise is resolved,
// calls a callback with 'OK' if everything is good,
// calls a callback with 'ERROR: <error message>' if something is wrong
// note that this function is executed in the context of tested app
// and not in the context of tests
module.exports.checkPicture = function (pid, options, cb) { var isIos = cordova.platformId === "ios"; var isAndroid = cordova.platformId === "android"; // skip image type check if it's unmodified on Android:
// https://github.com/apache/cordova-plugin-camera/#android-quirks-1
var skipFileTypeCheckAndroid = isAndroid && options.quality === 100 && !options.targetWidth && !options.targetHeight && !options.correctOrientation;
// Skip image type check if destination is NATIVE_URI and source - device's photoalbum
// https://github.com/apache/cordova-plugin-camera/#ios-quirks-1
var skipFileTypeCheckiOS = isIos && options.destinationType === Camera.DestinationType.NATIVE_URI && (options.sourceType === Camera.PictureSourceType.PHOTOLIBRARY || options.sourceType === Camera.PictureSourceType.SAVEDPHOTOALBUM);
var skipFileTypeCheck = skipFileTypeCheckAndroid || skipFileTypeCheckiOS;
var desiredType = 'JPEG'; var mimeType = 'image/jpeg'; if (options.encodingType === Camera.EncodingType.PNG) { desiredType = 'PNG'; mimeType = 'image/png'; }
function errorCallback(msg) { if (msg.hasOwnProperty('message')) { msg = msg.message; } cb('ERROR: ' + msg); }
// verifies the image we get from plugin
function verifyResult(result) { if (result.length === 0) { errorCallback('The result is empty.'); return; } else if (isIos && options.destinationType === Camera.DestinationType.NATIVE_URI && result.indexOf('assets-library:') !== 0) { errorCallback('Expected "' + result.substring(0, 150) + '"to start with "assets-library:"'); return; } else if (isIos && options.destinationType === Camera.DestinationType.FILE_URI && result.indexOf('file:') !== 0) { errorCallback('Expected "' + result.substring(0, 150) + '"to start with "file:"'); return; }
try { window.atob(result); // if we got here it is a base64 string (DATA_URL)
result = "data:" + mimeType + ";base64," + result; } catch (e) { // not DATA_URL
if (options.destinationType === Camera.DestinationType.DATA_URL) { errorCallback('Expected ' + result.substring(0, 150) + 'not to be DATA_URL'); return; } }
try { if (result.indexOf('file:') === 0 || result.indexOf('content:') === 0 || result.indexOf('assets-library:') === 0) {
if (!window.resolveLocalFileSystemURL) { errorCallback('Cannot read file. Please install cordova-plugin-file to fix this.'); return; } resolveLocalFileSystemURL(result, function (entry) { if (skipFileTypeCheck) { displayFile(entry); } else { verifyFile(entry); } }, function (err) { errorCallback(err); }); } else { displayImage(result); } } catch (e) { errorCallback(e); } }
// verifies that the file type matches the requested type
function verifyFile(entry) { try { var reader = new FileReader(); reader.onloadend = function(e) { var arr = (new Uint8Array(e.target.result)).subarray(0, 4); var header = ''; for(var i = 0; i < arr.length; i++) { header += arr[i].toString(16); } var actualType = 'unknown';
switch (header) { case "89504e47": actualType = 'PNG'; break; case 'ffd8ffe0': case 'ffd8ffe1': case 'ffd8ffe2': actualType = 'JPEG'; break; }
if (actualType === desiredType) { displayFile(entry); } else { errorCallback('File type mismatch. Expected ' + desiredType + ', got ' + actualType); } }; reader.onerror = function (e) { errorCallback(e); }; entry.file(function (file) { reader.readAsArrayBuffer(file); }, function (e) { errorCallback(e); }); } catch (e) { errorCallback(e); } }
// reads the file, then displays the image
function displayFile(entry) { function onFileReceived(file) { var reader = new FileReader(); reader.onerror = function (e) { errorCallback(e); }; reader.onloadend = function (evt) { displayImage(evt.target.result); }; reader.readAsDataURL(file); }
entry.file(onFileReceived, function (e) { errorCallback(e); }); }
function displayImage(image) { try { var imgEl = document.getElementById('camera_test_image'); if (!imgEl) { imgEl = document.createElement('img'); imgEl.id = 'camera_test_image'; document.body.appendChild(imgEl); } var timedOut = false; var loadTimeout = setTimeout(function () { timedOut = true; imgEl.src = ''; errorCallback('The image did not load: ' + image.substring(0, 150)); }, 10000); var done = function (status) { if (!timedOut) { clearTimeout(loadTimeout); imgEl.src = ''; cb(status); } }; imgEl.onload = function () { try { // aspect ratio is preserved so only one dimension should match
if ((typeof options.targetWidth === 'number' && imgEl.naturalWidth !== options.targetWidth) && (typeof options.targetHeight === 'number' && imgEl.naturalHeight !== options.targetHeight)) { done('ERROR: Wrong image size: ' + imgEl.naturalWidth + 'x' + imgEl.naturalHeight + '. Requested size: ' + options.targetWidth + 'x' + options.targetHeight); } else { done('OK'); } } catch (e) { errorCallback(e); } }; imgEl.src = image; } catch (e) { errorCallback(e); } }
navigator._appiumPromises[pid].promise .then(function (result) { verifyResult(result); }) .fail(function (e) { errorCallback(e); }); };
|