123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510 |
- /*
- *
- * 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.
- *
- */
- /* globals Camera, resolveLocalFileSystemURL, FileEntry, CameraPopoverOptions, FileTransfer, FileUploadOptions, LocalFileSystem, MSApp */
- /* jshint jasmine: true */
- exports.defineAutoTests = function () {
- describe('Camera (navigator.camera)', function () {
- it("should exist", function () {
- expect(navigator.camera).toBeDefined();
- });
- it("should contain a getPicture function", function () {
- expect(navigator.camera.getPicture).toBeDefined();
- expect(typeof navigator.camera.getPicture == 'function').toBe(true);
- });
- });
- describe('Camera Constants (window.Camera + navigator.camera)', function () {
- it("camera.spec.1 window.Camera should exist", function () {
- expect(window.Camera).toBeDefined();
- });
- it("camera.spec.2 should contain three DestinationType constants", function () {
- expect(Camera.DestinationType.DATA_URL).toBe(0);
- expect(Camera.DestinationType.FILE_URI).toBe(1);
- expect(Camera.DestinationType.NATIVE_URI).toBe(2);
- expect(navigator.camera.DestinationType.DATA_URL).toBe(0);
- expect(navigator.camera.DestinationType.FILE_URI).toBe(1);
- expect(navigator.camera.DestinationType.NATIVE_URI).toBe(2);
- });
- it("camera.spec.3 should contain two EncodingType constants", function () {
- expect(Camera.EncodingType.JPEG).toBe(0);
- expect(Camera.EncodingType.PNG).toBe(1);
- expect(navigator.camera.EncodingType.JPEG).toBe(0);
- expect(navigator.camera.EncodingType.PNG).toBe(1);
- });
- it("camera.spec.4 should contain three MediaType constants", function () {
- expect(Camera.MediaType.PICTURE).toBe(0);
- expect(Camera.MediaType.VIDEO).toBe(1);
- expect(Camera.MediaType.ALLMEDIA).toBe(2);
- expect(navigator.camera.MediaType.PICTURE).toBe(0);
- expect(navigator.camera.MediaType.VIDEO).toBe(1);
- expect(navigator.camera.MediaType.ALLMEDIA).toBe(2);
- });
- it("camera.spec.5 should contain three PictureSourceType constants", function () {
- expect(Camera.PictureSourceType.PHOTOLIBRARY).toBe(0);
- expect(Camera.PictureSourceType.CAMERA).toBe(1);
- expect(Camera.PictureSourceType.SAVEDPHOTOALBUM).toBe(2);
- expect(navigator.camera.PictureSourceType.PHOTOLIBRARY).toBe(0);
- expect(navigator.camera.PictureSourceType.CAMERA).toBe(1);
- expect(navigator.camera.PictureSourceType.SAVEDPHOTOALBUM).toBe(2);
- });
- });
- };
- /******************************************************************************/
- /******************************************************************************/
- /******************************************************************************/
- exports.defineManualTests = function (contentEl, createActionButton) {
- var pictureUrl = null;
- var fileObj = null;
- var fileEntry = null;
- var pageStartTime = +new Date();
- //default camera options
- var camQualityDefault = ['50', 50];
- var camDestinationTypeDefault = ['FILE_URI', 1];
- var camPictureSourceTypeDefault = ['CAMERA', 1];
- var camAllowEditDefault = ['allowEdit', false];
- var camEncodingTypeDefault = ['JPEG', 0];
- var camMediaTypeDefault = ['mediaType', 0];
- var camCorrectOrientationDefault = ['correctOrientation', false];
- var camSaveToPhotoAlbumDefault = ['saveToPhotoAlbum', true];
- function log(value) {
- console.log(value);
- document.getElementById('camera_status').textContent += (new Date() - pageStartTime) / 1000 + ': ' + value + '\n';
- }
- function clearStatus() {
- document.getElementById('camera_status').innerHTML = '';
- document.getElementById('camera_image').src = 'about:blank';
- var canvas = document.getElementById('canvas');
- canvas.width = canvas.height = 1;
- pictureUrl = null;
- fileObj = null;
- fileEntry = null;
- }
- function setPicture(url, callback) {
- try {
- window.atob(url);
- // if we got here it is a base64 string (DATA_URL)
- url = "data:image/jpeg;base64," + url;
- } catch (e) {
- // not DATA_URL
- }
- log('URL: "' + url.slice(0, 90) + '"');
- pictureUrl = url;
- var img = document.getElementById('camera_image');
- var startTime = new Date();
- img.src = url;
- img.onload = function () {
- log('Img size: ' + img.naturalWidth + 'x' + img.naturalHeight);
- log('Image tag load time: ' + (new Date() - startTime));
- if (callback) {
- callback();
- }
- };
- }
- function onGetPictureError(e) {
- log('Error getting picture: ' + (e.code || e));
- }
- function getPictureWin(data) {
- setPicture(data);
- // TODO: Fix resolveLocalFileSystemURI to work with native-uri.
- if (pictureUrl.indexOf('file:') === 0 || pictureUrl.indexOf('content:') === 0 || pictureUrl.indexOf('ms-appdata:') === 0 || pictureUrl.indexOf('assets-library:') === 0) {
- resolveLocalFileSystemURL(data, function (e) {
- fileEntry = e;
- logCallback('resolveLocalFileSystemURL()', true)(e.toURL());
- readFile();
- }, logCallback('resolveLocalFileSystemURL()', false));
- } else if (pictureUrl.indexOf('data:image/jpeg;base64') === 0) {
- // do nothing
- } else {
- var path = pictureUrl.replace(/^file:\/\/(localhost)?/, '').replace(/%20/g, ' ');
- fileEntry = new FileEntry('image_name.png', path);
- }
- }
- function getPicture() {
- clearStatus();
- var options = extractOptions();
- log('Getting picture with options: ' + JSON.stringify(options));
- var popoverHandle = navigator.camera.getPicture(getPictureWin, onGetPictureError, options);
- // Reposition the popover if the orientation changes.
- window.onorientationchange = function () {
- var newPopoverOptions = new CameraPopoverOptions(0, 0, 100, 100, 0);
- popoverHandle.setPosition(newPopoverOptions);
- };
- }
- function uploadImage() {
- var ft = new FileTransfer(),
- options = new FileUploadOptions();
- options.fileKey = "photo";
- options.fileName = 'test.jpg';
- options.mimeType = "image/jpeg";
- ft.onprogress = function (progressEvent) {
- console.log('progress: ' + progressEvent.loaded + ' of ' + progressEvent.total);
- };
- var server = "http://cordova-filetransfer.jitsu.com";
- ft.upload(pictureUrl, server + '/upload', win, fail, options);
- function win(information_back) {
- log('upload complete');
- }
- function fail(message) {
- log('upload failed: ' + JSON.stringify(message));
- }
- }
- function logCallback(apiName, success) {
- return function () {
- log('Call to ' + apiName + (success ? ' success: ' : ' failed: ') + JSON.stringify([].slice.call(arguments)));
- };
- }
- /**
- * Select image from library using a NATIVE_URI destination type
- * This calls FileEntry.getMetadata, FileEntry.setMetadata, FileEntry.getParent, FileEntry.file, and FileReader.readAsDataURL.
- */
- function readFile() {
- function onFileReadAsDataURL(evt) {
- var img = document.getElementById('camera_image');
- img.style.visibility = "visible";
- img.style.display = "block";
- img.src = evt.target.result;
- log("FileReader.readAsDataURL success");
- }
- function onFileReceived(file) {
- log('Got file: ' + JSON.stringify(file));
- fileObj = file;
- var reader = new FileReader();
- reader.onload = function () {
- log('FileReader.readAsDataURL() - length = ' + reader.result.length);
- };
- reader.onerror = logCallback('FileReader.readAsDataURL', false);
- reader.onloadend = onFileReadAsDataURL;
- reader.readAsDataURL(file);
- }
- // Test out onFileReceived when the file object was set via a native <input> elements.
- if (fileObj) {
- onFileReceived(fileObj);
- } else {
- fileEntry.file(onFileReceived, logCallback('FileEntry.file', false));
- }
- }
- function getFileInfo() {
- // Test FileEntry API here.
- fileEntry.getMetadata(logCallback('FileEntry.getMetadata', true), logCallback('FileEntry.getMetadata', false));
- fileEntry.setMetadata(logCallback('FileEntry.setMetadata', true), logCallback('FileEntry.setMetadata', false), { "com.apple.MobileBackup": 1 });
- fileEntry.getParent(logCallback('FileEntry.getParent', true), logCallback('FileEntry.getParent', false));
- fileEntry.getParent(logCallback('FileEntry.getParent', true), logCallback('FileEntry.getParent', false));
- }
- /**
- * Copy image from library using a NATIVE_URI destination type
- * This calls FileEntry.copyTo and FileEntry.moveTo.
- */
- function copyImage() {
- var onFileSystemReceived = function (fileSystem) {
- var destDirEntry = fileSystem.root;
- var origName = fileEntry.name;
- // Test FileEntry API here.
- fileEntry.copyTo(destDirEntry, 'copied_file.png', logCallback('FileEntry.copyTo', true), logCallback('FileEntry.copyTo', false));
- fileEntry.moveTo(destDirEntry, 'moved_file.png', logCallback('FileEntry.moveTo', true), logCallback('FileEntry.moveTo', false));
- //cleanup
- //rename moved file back to original name so other tests can reference image
- resolveLocalFileSystemURL(destDirEntry.nativeURL+'moved_file.png', function(fileEntry) {
- fileEntry.moveTo(destDirEntry, origName, logCallback('FileEntry.moveTo', true), logCallback('FileEntry.moveTo', false));
- console.log('Cleanup: successfully renamed file back to original name');
- }, function () {
- console.log('Cleanup: failed to rename file back to original name');
- });
- //remove copied file
- resolveLocalFileSystemURL(destDirEntry.nativeURL+'copied_file.png', function(fileEntry) {
- fileEntry.remove(logCallback('FileEntry.remove', true), logCallback('FileEntry.remove', false));
- console.log('Cleanup: successfully removed copied file');
- }, function () {
- console.log('Cleanup: failed to remove copied file');
- });
- };
- window.requestFileSystem(LocalFileSystem.TEMPORARY, 0, onFileSystemReceived, null);
- }
- /**
- * Write image to library using a NATIVE_URI destination type
- * This calls FileEntry.createWriter, FileWriter.write, and FileWriter.truncate.
- */
- function writeImage() {
- var onFileWriterReceived = function (fileWriter) {
- fileWriter.onwrite = logCallback('FileWriter.write', true);
- fileWriter.onerror = logCallback('FileWriter.write', false);
- fileWriter.write("some text!");
- };
- var onFileTruncateWriterReceived = function (fileWriter) {
- fileWriter.onwrite = logCallback('FileWriter.truncate', true);
- fileWriter.onerror = logCallback('FileWriter.truncate', false);
- fileWriter.truncate(10);
- };
- fileEntry.createWriter(onFileWriterReceived, logCallback('FileEntry.createWriter', false));
- fileEntry.createWriter(onFileTruncateWriterReceived, null);
- }
- function displayImageUsingCanvas() {
- var canvas = document.getElementById('canvas');
- var img = document.getElementById('camera_image');
- var w = img.width;
- var h = img.height;
- h = 100 / w * h;
- w = 100;
- canvas.width = w;
- canvas.height = h;
- var context = canvas.getContext('2d');
- context.drawImage(img, 0, 0, w, h);
- }
- /**
- * Remove image from library using a NATIVE_URI destination type
- * This calls FileEntry.remove.
- */
- function removeImage() {
- fileEntry.remove(logCallback('FileEntry.remove', true), logCallback('FileEntry.remove', false));
- }
- function testInputTag(inputEl) {
- clearStatus();
- // iOS 6 likes to dead-lock in the onchange context if you
- // do any alerts or try to remote-debug.
- window.setTimeout(function () {
- testNativeFile2(inputEl);
- }, 0);
- }
- function testNativeFile2(inputEl) {
- if (!inputEl.value) {
- alert('No file selected.');
- return;
- }
- fileObj = inputEl.files[0];
- if (!fileObj) {
- alert('Got value but no file.');
- return;
- }
- var URLApi = window.URL || window.webkitURL;
- if (URLApi) {
- var blobURL = URLApi.createObjectURL(fileObj);
- if (blobURL) {
- setPicture(blobURL, function () {
- URLApi.revokeObjectURL(blobURL);
- });
- } else {
- log('URL.createObjectURL returned null');
- }
- } else {
- log('URL.createObjectURL() not supported.');
- }
- }
- function extractOptions() {
- var els = document.querySelectorAll('#image-options select');
- var ret = {};
- /*jshint -W084 */
- for (var i = 0, el; el = els[i]; ++i) {
- var value = el.value;
- if (value === '') continue;
- value = +value;
- if (el.isBool) {
- ret[el.getAttribute("name")] = !!value;
- } else {
- ret[el.getAttribute("name")] = value;
- }
- }
- /*jshint +W084 */
- return ret;
- }
- function createOptionsEl(name, values, selectionDefault) {
- var openDiv = '<div style="display: inline-block">' + name + ': ';
- var select = '<select name=' + name + ' id="' + name + '">';
- var defaultOption = '';
- if (selectionDefault === undefined) {
- defaultOption = '<option value="">default</option>';
- }
- var options = '';
- if (typeof values == 'boolean') {
- values = { 'true': 1, 'false': 0 };
- }
- for (var k in values) {
- var isSelected = '';
- if (selectionDefault) {
- if (selectionDefault[0] == k) {
- isSelected = 'selected';
- }
- }
- options += '<option value="' + values[k] + '" ' + isSelected + '>' + k + '</option>';
- }
- var closeDiv = '</select></div>';
- return openDiv + select + defaultOption + options + closeDiv;
- }
- /******************************************************************************/
- var info_div = '<h1>Camera</h1>' +
- '<div id="info">' +
- '<b>Status:</b> <div id="camera_status"></div>' +
- 'img: <img width="100" id="camera_image">' +
- 'canvas: <canvas id="canvas" width="1" height="1"></canvas>' +
- '</div>',
- options_div = '<h2>Cordova Camera API Options</h2>' +
- '<div id="image-options">' +
- createOptionsEl('sourceType', Camera.PictureSourceType, camPictureSourceTypeDefault) +
- createOptionsEl('destinationType', Camera.DestinationType, camDestinationTypeDefault) +
- createOptionsEl('encodingType', Camera.EncodingType, camEncodingTypeDefault) +
- createOptionsEl('mediaType', Camera.MediaType, camMediaTypeDefault) +
- createOptionsEl('quality', { '0': 0, '50': 50, '80': 80, '100': 100 }, camQualityDefault) +
- createOptionsEl('targetWidth', { '50': 50, '200': 200, '800': 800, '2048': 2048 }) +
- createOptionsEl('targetHeight', { '50': 50, '200': 200, '800': 800, '2048': 2048 }) +
- createOptionsEl('allowEdit', true, camAllowEditDefault) +
- createOptionsEl('correctOrientation', true, camCorrectOrientationDefault) +
- createOptionsEl('saveToPhotoAlbum', true, camSaveToPhotoAlbumDefault) +
- createOptionsEl('cameraDirection', Camera.Direction) +
- '</div>',
- getpicture_div = '<div id="getpicture"></div>',
- test_procedure = '<h4>Recommended Test Procedure</h4>' +
- 'Options not specified should be the default value' +
- '<br>Status box should update with image and info whenever an image is taken or selected from library' +
- '</p><div style="background:#B0C4DE;border:1px solid #FFA07A;margin:15px 6px 0px;min-width:295px;max-width:97%;padding:4px 0px 2px 10px;min-height:160px;max-height:200px;overflow:auto">' +
- '<ol> <li>All default options. Should be able to edit once picture is taken and will be saved to library.</li>' +
- '</p><li>sourceType=PHOTOLIBRARY<br>Should be able to see picture that was just taken in previous test and edit when selected</li>' +
- '</p><li>sourceType=Camera<br>allowEdit=false<br>saveToPhotoAlbum=false<br>Should not be able to edit when taken and will not save to library</li>' +
- '</p><li>encodingType=PNG<br>allowEdit=true<br>saveToPhotoAlbum=true<br>cameraDirection=FRONT<br>Should bring up front camera. Verify in status box info URL that image is encoded as PNG.</li>' +
- '</p><li>sourceType=SAVEDPHOTOALBUM<br>mediaType=VIDEO<br>Should only be able to select a video</li>' +
- '</p><li>sourceType=SAVEDPHOTOALBUM<br>mediaType=PICTURE<br>allowEdit=false<br>Should only be able to select a picture and not edit</li>' +
- '</p><li>sourceType=PHOTOLIBRARY<br>mediaType=ALLMEDIA<br>allowEdit=true<br>Should be able to select pics and videos and edit picture if selected</li>' +
- '</p><li>sourceType=CAMERA<br>targetWidth & targetHeight=50<br>allowEdit=false<br>Do Get File Metadata test below and take note of size<br>Repeat test but with width and height=800. Size should be significantly larger.</li>' +
- '</p><li>quality=0<br>targetWidth & targetHeight=default<br>allowEdit=false<br>Do Get File Metadata test below and take note of size<br>Repeat test but with quality=80. Size should be significantly larger.</li>' +
- '</ol></div>',
- inputs_div = '<h2>Native File Inputs</h2>' +
- 'For the following tests, status box should update with file selected' +
- '</p><div>input type=file <input type="file" class="testInputTag"></div>' +
- '<div>capture=camera <input type="file" accept="image/*;capture=camera" class="testInputTag"></div>' +
- '<div>capture=camcorder <input type="file" accept="video/*;capture=camcorder" class="testInputTag"></div>' +
- '<div>capture=microphone <input type="file" accept="audio/*;capture=microphone" class="testInputTag"></div>',
- actions_div = '<h2>Actions</h2>' +
- 'For the following tests, ensure that an image is set in status box' +
- '</p><div id="metadata"></div>' +
- 'Expected result: Get metadata about file selected.<br>Status box will show, along with the metadata, "Call to FileEntry.getMetadata success, Call to FileEntry.setMetadata success, Call to FileEntry.getParent success"' +
- '</p><div id="reader"></div>' +
- 'Expected result: Read contents of file.<br>Status box will show "Got file: {some metadata}, FileReader.readAsDataURL() - length = someNumber"' +
- '</p><div id="copy"></div>' +
- 'Expected result: Copy image to new location and move file to different location.<br>Status box will show "Call to FileEntry.copyTo success:{some metadata}, Call to FileEntry.moveTo success:{some metadata}"' +
- '</p><div id="write"></div>' +
- 'Expected result: Write image to library.<br>Status box will show "Call to FileWriter.write success:{some metadata}, Call to FileWriter.truncate success:{some metadata}"' +
- '</p><div id="upload"></div>' +
- 'Expected result: Upload image to server.<br>Status box may print out progress. Once finished will show "upload complete"' +
- '</p><div id="draw_canvas"></div>' +
- 'Expected result: Display image using canvas.<br>Image will be displayed in status box under "canvas:"' +
- '</p><div id="remove"></div>' +
- 'Expected result: Remove image from library.<br>Status box will show "FileEntry.remove success:["OK"]';
- // We need to wrap this code due to Windows security restrictions
- // see http://msdn.microsoft.com/en-us/library/windows/apps/hh465380.aspx#differences for details
- if (window.MSApp && window.MSApp.execUnsafeLocalFunction) {
- MSApp.execUnsafeLocalFunction(function() {
- contentEl.innerHTML = info_div + options_div + getpicture_div + test_procedure + inputs_div + actions_div;
- });
- } else {
- contentEl.innerHTML = info_div + options_div + getpicture_div + test_procedure + inputs_div + actions_div;
- }
- var elements = document.getElementsByClassName("testInputTag");
- var listener = function (e) {
- testInputTag(e.target);
- };
- for (var i = 0; i < elements.length; ++i) {
- var item = elements[i];
- item.addEventListener("change", listener, false);
- }
- createActionButton('Get picture', function () {
- getPicture();
- }, 'getpicture');
- createActionButton('Clear Status', function () {
- clearStatus();
- }, 'getpicture');
- createActionButton('Get File Metadata', function () {
- getFileInfo();
- }, 'metadata');
- createActionButton('Read with FileReader', function () {
- readFile();
- }, 'reader');
- createActionButton('Copy Image', function () {
- copyImage();
- }, 'copy');
- createActionButton('Write Image', function () {
- writeImage();
- }, 'write');
- createActionButton('Upload Image', function () {
- uploadImage();
- }, 'upload');
- createActionButton('Draw Using Canvas', function () {
- displayImageUsingCanvas();
- }, 'draw_canvas');
- createActionButton('Remove Image', function () {
- removeImage();
- }, 'remove');
- };
|