From 57b177f3fb84d752aeef964117bb4aa148df474d Mon Sep 17 00:00:00 2001 From: Alexander Sorokin Date: Wed, 27 Apr 2016 18:02:48 +0300 Subject: [PATCH 01/40] CB-11162 Appium tests: retry spec on failure --- appium-tests/android/android.spec.js | 263 +++++++++++++++------------ 1 file changed, 149 insertions(+), 114 deletions(-) diff --git a/appium-tests/android/android.spec.js b/appium-tests/android/android.spec.js index 7a9a71b..4bfae8a 100644 --- a/appium-tests/android/android.spec.js +++ b/appium-tests/android/android.spec.js @@ -157,7 +157,7 @@ describe('Camera tests Android.', function () { }) .fail(function (failure) { console.log(failure); - fail(failure); + throw failure; }); } @@ -170,30 +170,20 @@ describe('Camera tests Android.', function () { .executeAsync(cameraHelper.checkPicture, [getCurrentPromiseId()]) .then(function (result) { if (shouldLoad) { - expect(result.length).toBeGreaterThan(0); + if (result.length === 0) { + throw 'The result is an empty string.'; + } if (result.indexOf('ERROR') >= 0) { - return fail(result); + throw result; } } else { if (result.indexOf('ERROR') === -1) { - return fail('Unexpected success callback with result: ' + result); + throw 'Unexpected success callback with result: ' + result; } - expect(result.indexOf('ERROR')).toBe(0); } }); } - function runCombinedSpec(spec) { - return driver - .then(function () { - return getPicture(spec.options); - }) - .then(function () { - return checkPicture(true); - }) - .fail(saveScreenshotAndFail); - } - // deletes the latest image from the gallery function deleteImage() { var holdTile = new wd.TouchAction(); @@ -229,6 +219,41 @@ describe('Camera tests Android.', function () { }); } + function recreateSession() { + return driver + .quit() + .finally(function () { + return getDriver(); + }); + } + + function tryRunSpec(spec) { + return driver + .then(spec) + .fail(function () { + return recreateSession() + .then(spec) + .fail(function() { + return recreateSession() + .then(spec); + }); + }) + .fail(saveScreenshotAndFail); + } + + function runCombinedSpec(s) { + var spec = function () { + return driver + .then(function () { + return getPicture(s.options); + }) + .then(function () { + return checkPicture(true); + }); + }; + return tryRunSpec(spec); + } + it('camera.ui.util configuring driver and starting a session', function (done) { getDriver() .fail(fail) @@ -253,128 +278,138 @@ describe('Camera tests Android.', function () { describe('Specs.', function () { // getPicture() with saveToPhotoLibrary = true - it('camera.ui.spec.1 Saving the picture to photo library', function (done) { - var options = { - quality: 50, - allowEdit: false, - sourceType: cameraConstants.PictureSourceType.CAMERA, - saveToPhotoAlbum: true + it('camera.ui.spec.1 Saving a picture to the photo library', function (done) { + var spec = function() { + var options = { + quality: 50, + allowEdit: false, + sourceType: cameraConstants.PictureSourceType.CAMERA, + saveToPhotoAlbum: true + }; + return driver + .then(function () { + return getPicture(options); + }) + .then(function () { + isTestPictureSaved = true; + return checkPicture(true); + }); }; - driver - .then(function () { - return getPicture(options); - }) - .then(function () { - isTestPictureSaved = true; - return checkPicture(true); - }) - .fail(saveScreenshotAndFail) + + return tryRunSpec(spec) .done(done); - }, 3 * MINUTE); + }, 10 * MINUTE); // getPicture() with mediaType: VIDEO, sourceType: PHOTOLIBRARY it('camera.ui.spec.2 Selecting only videos', function (done) { - var options = { sourceType: cameraConstants.PictureSourceType.PHOTOLIBRARY, - mediaType: cameraConstants.MediaType.VIDEO }; - driver - .then(function () { - return getPicture(options, true); - }) - .context('NATIVE_APP') - .then(function () { - // try to find "Gallery" menu item - // if there's none, the gallery should be already opened - return driver - .elementByXPath('//android.widget.TextView[@text="Gallery"]') - .then(function (element) { - return element.click(); - }, function () { - return driver; - }); - }) - .then(function () { - // if the gallery is opened on the videos page, - // there should be a "Choose video" caption - return driver - .elementByXPath('//*[@text="Choose video"]') - .fail(function () { - throw 'Couldn\'t find "Choose video" element.'; - }); - }) - .deviceKeyEvent(BACK_BUTTON) - .elementByXPath('//android.widget.TextView[@text="Gallery"]') - .deviceKeyEvent(BACK_BUTTON) - .finally(function () { - return driver - .elementById('action_bar_title') - .then(function () { - // success means we're still in native app - return driver - .deviceKeyEvent(BACK_BUTTON); - }, function () { - // error means we're already in webview - return driver; - }); - }) - .fail(saveScreenshotAndFail) + var spec = function () { + var options = { sourceType: cameraConstants.PictureSourceType.PHOTOLIBRARY, + mediaType: cameraConstants.MediaType.VIDEO }; + return driver + .then(function () { + return getPicture(options, true); + }) + .context('NATIVE_APP') + .then(function () { + // try to find "Gallery" menu item + // if there's none, the gallery should be already opened + return driver + .elementByXPath('//android.widget.TextView[@text="Gallery"]') + .then(function (element) { + return element.click(); + }, function () { + return driver; + }); + }) + .then(function () { + // if the gallery is opened on the videos page, + // there should be a "Choose video" caption + return driver + .elementByXPath('//*[@text="Choose video"]') + .fail(function () { + throw 'Couldn\'t find "Choose video" element.'; + }); + }) + .deviceKeyEvent(BACK_BUTTON) + .elementByXPath('//android.widget.TextView[@text="Gallery"]') + .deviceKeyEvent(BACK_BUTTON) + .finally(function () { + return driver + .elementById('action_bar_title') + .then(function () { + // success means we're still in native app + return driver + .deviceKeyEvent(BACK_BUTTON); + }, function () { + // error means we're already in webview + return driver; + }); + }); + }; + return tryRunSpec(spec) .done(done); - }, 3 * MINUTE); + }, 10 * MINUTE); // getPicture(), then dismiss // wait for the error callback to be called it('camera.ui.spec.3 Dismissing the camera', function (done) { - var options = { quality: 50, - allowEdit: true, - sourceType: cameraConstants.PictureSourceType.CAMERA, - destinationType: cameraConstants.DestinationType.FILE_URI }; - driver - .then(function () { - return getPicture(options, true); - }) - .context("NATIVE_APP") - .waitForElementByXPath('//android.widget.ImageView[contains(@resource-id,\'cancel\')]', MINUTE / 2) - .click() - .then(function () { - return checkPicture(false); - }) - .fail(saveScreenshotAndFail) + var spec = function () { + var options = { quality: 50, + allowEdit: true, + sourceType: cameraConstants.PictureSourceType.CAMERA, + destinationType: cameraConstants.DestinationType.FILE_URI }; + return driver + .then(function () { + return getPicture(options, true); + }) + .context("NATIVE_APP") + .waitForElementByXPath('//android.widget.ImageView[contains(@resource-id,\'cancel\')]', MINUTE / 2) + .click() + .then(function () { + return checkPicture(false); + }); + }; + + return tryRunSpec(spec) .done(done); - }, 3 * MINUTE); + }, 10 * MINUTE); // getPicture(), then take picture but dismiss the edit // wait for the error callback to be called it('camera.ui.spec.4 Dismissing the edit', function (done) { - var options = { quality: 50, - allowEdit: true, - sourceType: cameraConstants.PictureSourceType.CAMERA, - destinationType: cameraConstants.DestinationType.FILE_URI }; - driver - .then(function () { - return getPicture(options, true); - }) - .context('NATIVE_APP') - .waitForElementByXPath('//android.widget.ImageView[contains(@resource-id,\'shutter\')]', MINUTE / 2) - .click() - .waitForElementByXPath('//android.widget.ImageView[contains(@resource-id,\'done\')]', MINUTE / 2) - .click() - .waitForElementByXPath('//*[contains(@resource-id,\'discard\')]', MINUTE / 2) - .click() - .then(function () { - return checkPicture(false); - }) - .fail(saveScreenshotAndFail) + var spec = function () { + var options = { quality: 50, + allowEdit: true, + sourceType: cameraConstants.PictureSourceType.CAMERA, + destinationType: cameraConstants.DestinationType.FILE_URI }; + return driver + .then(function () { + return getPicture(options, true); + }) + .context('NATIVE_APP') + .waitForElementByXPath('//android.widget.ImageView[contains(@resource-id,\'shutter\')]', MINUTE / 2) + .click() + .waitForElementByXPath('//android.widget.ImageView[contains(@resource-id,\'done\')]', MINUTE / 2) + .click() + .waitForElementByXPath('//*[contains(@resource-id,\'discard\')]', MINUTE / 2) + .click() + .then(function () { + return checkPicture(false); + }); + }; + + return tryRunSpec(spec) .done(done); - }, 3 * MINUTE); + }, 10 * MINUTE); // combine various options for getPicture() generateSpecs().forEach(function (spec) { it('camera.ui.spec.5.' + spec.id + ' Combining options. ' + spec.description, function (done) { runCombinedSpec(spec) .done(done); - }, 3 * MINUTE); + }, 10 * MINUTE); }); - it('camera.ui.util Delete test image from device library', function (done) { if (!isTestPictureSaved) { // couldn't save test picture earlier, so nothing to delete here From af98d57417514cc1f3ecd89d0c1f4e4319b139cb Mon Sep 17 00:00:00 2001 From: Keith M Date: Sat, 7 May 2016 19:51:58 -0400 Subject: [PATCH 02/40] CB-11227 browser: Fix incorrect mime type This closes #211 --- src/browser/CameraProxy.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/browser/CameraProxy.js b/src/browser/CameraProxy.js index 8f95c6f..23ace0b 100644 --- a/src/browser/CameraProxy.js +++ b/src/browser/CameraProxy.js @@ -69,7 +69,7 @@ function capture(success, errorCallback) { canvas.getContext('2d').drawImage(video, 0, 0, 320, 240); // convert image stored in canvas to base64 encoded image - var imageData = canvas.toDataURL('img/png'); + var imageData = canvas.toDataURL('image/png'); imageData = imageData.replace('data:image/png;base64,', ''); // stop video stream, remove video and button. From 2a7469e065e9c1e48493689a584d8ceb420467e8 Mon Sep 17 00:00:00 2001 From: Nikhil Khandelwal Date: Mon, 9 May 2016 17:00:51 -0700 Subject: [PATCH 03/40] Stale PRs: closes #149, closes #148, closes #155, closes #107, closes #71, closes #55, closes #14 From 7551778e13ff96d1d712b7e7d2caa87ad079ca71 Mon Sep 17 00:00:00 2001 From: Keith M Date: Sat, 7 May 2016 14:36:33 -0400 Subject: [PATCH 04/40] CB-10139 browser: Respect target width and height This closes #210 --- src/browser/CameraProxy.js | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/browser/CameraProxy.js b/src/browser/CameraProxy.js index 23ace0b..89ee3cc 100644 --- a/src/browser/CameraProxy.js +++ b/src/browser/CameraProxy.js @@ -23,7 +23,7 @@ var HIGHEST_POSSIBLE_Z_INDEX = 2147483647; function takePicture(success, error, opts) { if (opts && opts[2] === 1) { - capture(success, error); + capture(success, error, opts); } else { var input = document.createElement('input'); input.style.position = 'relative'; @@ -48,8 +48,13 @@ function takePicture(success, error, opts) { } } -function capture(success, errorCallback) { +function capture(success, errorCallback, opts) { var localMediaStream; + var targetWidth = opts[3]; + var targetHeight = opts[4]; + + targetWidth = targetWidth == -1?320:targetWidth; + targetHeight = targetHeight == -1?240:targetHeight; var video = document.createElement('video'); var button = document.createElement('button'); @@ -59,14 +64,16 @@ function capture(success, errorCallback) { parent.appendChild(video); parent.appendChild(button); - video.width = 320; - video.height = 240; + video.width = targetWidth; + video.height = targetHeight; button.innerHTML = 'Capture!'; button.onclick = function() { // create a canvas and capture a frame from video stream var canvas = document.createElement('canvas'); - canvas.getContext('2d').drawImage(video, 0, 0, 320, 240); + canvas.width = targetWidth; + canvas.height = targetHeight; + canvas.getContext('2d').drawImage(video, 0, 0, targetWidth, targetHeight); // convert image stored in canvas to base64 encoded image var imageData = canvas.toDataURL('image/png'); From 39bff2f41dd38e64d4f90dc14c7a9b67c847065f Mon Sep 17 00:00:00 2001 From: Keith M Date: Sat, 7 May 2016 20:49:30 -0400 Subject: [PATCH 05/40] CB-11228 browser: Add classes for styling purposes This closes #212 --- src/browser/CameraProxy.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/browser/CameraProxy.js b/src/browser/CameraProxy.js index 89ee3cc..635a9fb 100644 --- a/src/browser/CameraProxy.js +++ b/src/browser/CameraProxy.js @@ -28,6 +28,7 @@ function takePicture(success, error, opts) { var input = document.createElement('input'); input.style.position = 'relative'; input.style.zIndex = HIGHEST_POSSIBLE_Z_INDEX; + input.className = 'cordova-camera-select'; input.type = 'file'; input.name = 'files[]'; @@ -61,6 +62,7 @@ function capture(success, errorCallback, opts) { var parent = document.createElement('div'); parent.style.position = 'relative'; parent.style.zIndex = HIGHEST_POSSIBLE_Z_INDEX; + parent.className = 'cordova-camera-capture'; parent.appendChild(video); parent.appendChild(button); From cf35b1bb2a880398fc201d184af28a37ac3651b5 Mon Sep 17 00:00:00 2001 From: Nikhil Khandelwal Date: Tue, 10 May 2016 11:35:48 -0700 Subject: [PATCH 06/40] Add pull request template. This closes #213 --- .github/PULL_REQUEST_TEMPLATE.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 .github/PULL_REQUEST_TEMPLATE.md diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..0edec15 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,15 @@ +### Platforms affected + + +### What does this PR do? + + +### What testing has been done on this change? + + +### Checklist +Please make sure these boxes are checked before submitting the PR. This checklist is intended as a quick reference, for complete details please see our [Contributor Guidelines](http://cordova.apache.org/contribute/contribute_guidelines.html). Thanks! +- [ ] [ICLA](http://www.apache.org/licenses/icla.txt) has been signed and submitted to secretary@apache.org. +- [ ] [Reported an issue](http://cordova.apache.org/contribute/issues.html) in the JIRA database +- [ ] Commit message follows the format: "CB-3232: (android) Fix bug with resolving file paths", where CB-xxxx is the JIRA ID & "android" is the platform affected. +- [ ] Add automated test coverage as appropriate for this change. From 2eef09686173cb0ea6f62b29953b702769f88858 Mon Sep 17 00:00:00 2001 From: Richard Knoll Date: Fri, 13 May 2016 12:14:03 -0700 Subject: [PATCH 07/40] Moving message in PR template to a comment --- .github/PULL_REQUEST_TEMPLATE.md | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 0edec15..4bd6da9 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,3 +1,12 @@ + + ### Platforms affected @@ -8,8 +17,7 @@ ### Checklist -Please make sure these boxes are checked before submitting the PR. This checklist is intended as a quick reference, for complete details please see our [Contributor Guidelines](http://cordova.apache.org/contribute/contribute_guidelines.html). Thanks! - [ ] [ICLA](http://www.apache.org/licenses/icla.txt) has been signed and submitted to secretary@apache.org. -- [ ] [Reported an issue](http://cordova.apache.org/contribute/issues.html) in the JIRA database +- [ ] [Reported an issue](http://cordova.apache.org/contribute/issues.html) in the JIRA database - [ ] Commit message follows the format: "CB-3232: (android) Fix bug with resolving file paths", where CB-xxxx is the JIRA ID & "android" is the platform affected. -- [ ] Add automated test coverage as appropriate for this change. +- [ ] Added automated test coverage as appropriate for this change. From 0115458ce8c0ab3476ddf5f2bf4ba3d5452965cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julio=20C=C3=A9sar?= Date: Mon, 16 May 2016 19:43:01 +0200 Subject: [PATCH 08/40] Set android quality default value to 50 on the java code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Default value is set to 80 on the java code, but doc says that default value is 50. I’m changing it just for making code clearer, but default value is set to 50 to all platforms in Camera.js if no value is passed --- src/android/CameraLauncher.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/android/CameraLauncher.java b/src/android/CameraLauncher.java index 4d15bdf..9db9911 100644 --- a/src/android/CameraLauncher.java +++ b/src/android/CameraLauncher.java @@ -138,7 +138,7 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect this.targetWidth = 0; this.encodingType = JPEG; this.mediaType = PICTURE; - this.mQuality = 80; + this.mQuality = 50; //Take the values from the arguments if they're not already defined (this is tricky) this.destType = args.getInt(1); From cc840b6cef649c5cdd523a467e656d93355bd326 Mon Sep 17 00:00:00 2001 From: Nikhil Khandelwal Date: Mon, 16 May 2016 12:48:57 -0700 Subject: [PATCH 09/40] Closing stale PRs. Close #147 From 3586ea58a20e9a8558fd3472e7e791e909304a15 Mon Sep 17 00:00:00 2001 From: Nikhil Khandelwal Date: Mon, 16 May 2016 12:51:33 -0700 Subject: [PATCH 10/40] Closing stale PRs. Close #167 From a831e15a917eb8666be91e23869e7fb0263e5782 Mon Sep 17 00:00:00 2001 From: Mikejo5001 Date: Tue, 26 Apr 2016 13:30:38 -0700 Subject: [PATCH 11/40] fixed some bad formatting that hid HTML tags and added link to sample This closes #207 --- README.md | 19 ++----------------- jsdoc2md/TEMPLATE.md | 4 ++-- 2 files changed, 4 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 8102670..7f5a9cf 100644 --- a/README.md +++ b/README.md @@ -73,7 +73,7 @@ Documentation consists of template and API docs produced from the plugin JS code --- -# API Reference +# API Reference * [camera](#module_camera) @@ -98,10 +98,8 @@ Documentation consists of template and API docs produced from the plugin JS code --- - ## camera - ### camera.getPicture(successCallback, errorCallback, options) Takes a photo using the camera, or retrieves a photo from the device's image gallery. The image is passed to the success callback as a @@ -169,7 +167,6 @@ More examples [here](#camera-getPicture-examples). Quirks [here](#camera-getPict navigator.camera.getPicture(cameraSuccess, cameraError, cameraOptions); ``` - ### camera.cleanup() Removes intermediate image files that are kept in temporary storage after calling [`camera.getPicture`](#module_camera.getPicture). Applies only when the value of @@ -194,7 +191,6 @@ function onFail(message) { } ``` - ### camera.onError : function Callback function that provides an error message. @@ -205,7 +201,6 @@ Callback function that provides an error message. | message | string | The message is provided by the device's native code. | - ### camera.onSuccess : function Callback function that provides the image data. @@ -225,7 +220,6 @@ function cameraCallback(imageData) { } ``` - ### camera.CameraOptions : Object Optional parameters to customize the camera settings. * [Quirks](#CameraOptions-quirks) @@ -251,10 +245,8 @@ Optional parameters to customize the camera settings. --- - ## Camera - ### Camera.DestinationType : enum **Kind**: static enum property of [Camera](#module_Camera) **Properties** @@ -266,7 +258,6 @@ Optional parameters to customize the camera settings. | NATIVE_URI | number | 2 | Return native uri (eg. asset-library://... for iOS) | - ### Camera.EncodingType : enum **Kind**: static enum property of [Camera](#module_Camera) **Properties** @@ -277,7 +268,6 @@ Optional parameters to customize the camera settings. | PNG | number | 1 | Return PNG encoded image | - ### Camera.MediaType : enum **Kind**: static enum property of [Camera](#module_Camera) **Properties** @@ -289,7 +279,6 @@ Optional parameters to customize the camera settings. | ALLMEDIA | number | 2 | Allow selection from all media types | - ### Camera.PictureSourceType : enum **Kind**: static enum property of [Camera](#module_Camera) **Properties** @@ -301,7 +290,6 @@ Optional parameters to customize the camera settings. | SAVEDPHOTOALBUM | number | 2 | Choose image from picture library (same as PHOTOLIBRARY for Android) | - ### Camera.PopoverArrowDirection : enum Matches iOS UIPopoverArrowDirection constants to specify arrow location on popover. @@ -317,7 +305,6 @@ Matches iOS UIPopoverArrowDirection constants to specify arrow location on popov | ARROW_ANY | number | 15 | - ### Camera.Direction : enum **Kind**: static enum property of [Camera](#module_Camera) **Properties** @@ -330,7 +317,6 @@ Matches iOS UIPopoverArrowDirection constants to specify arrow location on popov --- - ## CameraPopoverOptions iOS-only parameters that specify the anchor element location and arrow direction of the popover when selecting images from an iPad's library @@ -352,7 +338,6 @@ location. --- - ## CameraPopoverHandle A handle to an image picker popover. @@ -618,7 +603,7 @@ function displayImage(imgUri) { } ``` -To display the image on some platforms, you might need to include the main part of the URI in the Content-Security-Policy element in index.html. For example, on Windows 10, you can include `ms-appdata:` in your element. Here is an example. +To display the image on some platforms, you might need to include the main part of the URI in the Content-Security-Policy `` element in index.html. For example, on Windows 10, you can include `ms-appdata:` in your `` element. Here is an example. ```html diff --git a/jsdoc2md/TEMPLATE.md b/jsdoc2md/TEMPLATE.md index d554107..64bce32 100644 --- a/jsdoc2md/TEMPLATE.md +++ b/jsdoc2md/TEMPLATE.md @@ -15,7 +15,7 @@ the system's image library. --- -# API Reference +# API Reference {{#orphans~}} {{>member-index}} @@ -274,7 +274,7 @@ function displayImage(imgUri) { } ``` -To display the image on some platforms, you might need to include the main part of the URI in the Content-Security-Policy element in index.html. For example, on Windows 10, you can include `ms-appdata:` in your element. Here is an example. +To display the image on some platforms, you might need to include the main part of the URI in the Content-Security-Policy `` element in index.html. For example, on Windows 10, you can include `ms-appdata:` in your `` element. Here is an example. ```html From f283502545aac4c90522e85760c108f16a4930ad Mon Sep 17 00:00:00 2001 From: Raghav Katyal Date: Tue, 17 May 2016 11:38:59 -0700 Subject: [PATCH 12/40] Closing stale PRs. This closes #85, closes #93 From d7ca7edf8826f9d8e2bfbeb36eff9eaeeb2e9adb Mon Sep 17 00:00:00 2001 From: Raghav Katyal Date: Tue, 17 May 2016 14:10:36 -0700 Subject: [PATCH 13/40] Closing stale PRs. This closes #114, closes #104 From 278b5277027ba62d621cbc2dea10079abb2ef0c9 Mon Sep 17 00:00:00 2001 From: Alexander Sorokin Date: Wed, 18 May 2016 11:48:29 +0300 Subject: [PATCH 14/40] CB-11183 Appium tests: Added image verification --- appium-tests/android/android.spec.js | 183 ++++++++++++++++++-------- appium-tests/helpers/cameraHelper.js | 190 ++++++++++++++++++++++++++- appium-tests/ios/ios.spec.js | 180 +++++++++++++++++++++---- 3 files changed, 472 insertions(+), 81 deletions(-) diff --git a/appium-tests/android/android.spec.js b/appium-tests/android/android.spec.js index 4bfae8a..25f662c 100644 --- a/appium-tests/android/android.spec.js +++ b/appium-tests/android/android.spec.js @@ -72,9 +72,9 @@ describe('Camera tests Android.', function () { }); } - // generates test specs by combining all the specified options + // combinines specified options in all possible variations // you can add more options to test more scenarios - function generateSpecs() { + function generateOptions() { var sourceTypes = [ cameraConstants.PictureSourceType.CAMERA, cameraConstants.PictureSourceType.PHOTOLIBRARY @@ -156,30 +156,27 @@ describe('Camera tests Android.', function () { } }) .fail(function (failure) { - console.log(failure); throw failure; }); } // checks if the picture was successfully taken // if shouldLoad is falsy, ensures that the error callback was called - function checkPicture(shouldLoad) { + function checkPicture(shouldLoad, options) { + if (!options) { + options = {}; + } return driver .context(webviewContext) .setAsyncScriptTimeout(MINUTE) - .executeAsync(cameraHelper.checkPicture, [getCurrentPromiseId()]) + .executeAsync(cameraHelper.checkPicture, [getCurrentPromiseId(), options]) .then(function (result) { if (shouldLoad) { - if (result.length === 0) { - throw 'The result is an empty string.'; - } - if (result.indexOf('ERROR') >= 0) { - throw result; - } - } else { - if (result.indexOf('ERROR') === -1) { - throw 'Unexpected success callback with result: ' + result; + if (result !== 'OK') { + fail(result); } + } else if (result.indexOf('ERROR') === -1) { + throw 'Unexpected success callback with result: ' + result; } }); } @@ -241,17 +238,19 @@ describe('Camera tests Android.', function () { .fail(saveScreenshotAndFail); } - function runCombinedSpec(s) { - var spec = function () { + // produces a generic spec function which + // takes a picture with specified options + // and then verifies it + function generateSpec(options) { + return function () { return driver .then(function () { - return getPicture(s.options); + return getPicture(options); }) .then(function () { - return checkPicture(true); + return checkPicture(true, options); }); }; - return tryRunSpec(spec); } it('camera.ui.util configuring driver and starting a session', function (done) { @@ -279,24 +278,17 @@ describe('Camera tests Android.', function () { describe('Specs.', function () { // getPicture() with saveToPhotoLibrary = true it('camera.ui.spec.1 Saving a picture to the photo library', function (done) { - var spec = function() { - var options = { - quality: 50, - allowEdit: false, - sourceType: cameraConstants.PictureSourceType.CAMERA, - saveToPhotoAlbum: true - }; - return driver - .then(function () { - return getPicture(options); - }) - .then(function () { - isTestPictureSaved = true; - return checkPicture(true); - }); - }; + var spec = generateSpec({ + quality: 50, + allowEdit: false, + sourceType: cameraConstants.PictureSourceType.CAMERA, + saveToPhotoAlbum: true + }); - return tryRunSpec(spec) + tryRunSpec(spec) + .then(function () { + isTestPictureSaved = true; + }) .done(done); }, 10 * MINUTE); @@ -346,18 +338,19 @@ describe('Camera tests Android.', function () { }); }); }; - return tryRunSpec(spec) - .done(done); + tryRunSpec(spec).done(done); }, 10 * MINUTE); // getPicture(), then dismiss // wait for the error callback to be called it('camera.ui.spec.3 Dismissing the camera', function (done) { var spec = function () { - var options = { quality: 50, - allowEdit: true, - sourceType: cameraConstants.PictureSourceType.CAMERA, - destinationType: cameraConstants.DestinationType.FILE_URI }; + var options = { + quality: 50, + allowEdit: true, + sourceType: cameraConstants.PictureSourceType.CAMERA, + destinationType: cameraConstants.DestinationType.FILE_URI + }; return driver .then(function () { return getPicture(options, true); @@ -370,18 +363,19 @@ describe('Camera tests Android.', function () { }); }; - return tryRunSpec(spec) - .done(done); + tryRunSpec(spec).done(done); }, 10 * MINUTE); // getPicture(), then take picture but dismiss the edit // wait for the error callback to be called it('camera.ui.spec.4 Dismissing the edit', function (done) { var spec = function () { - var options = { quality: 50, - allowEdit: true, - sourceType: cameraConstants.PictureSourceType.CAMERA, - destinationType: cameraConstants.DestinationType.FILE_URI }; + var options = { + quality: 50, + allowEdit: true, + sourceType: cameraConstants.PictureSourceType.CAMERA, + destinationType: cameraConstants.DestinationType.FILE_URI + }; return driver .then(function () { return getPicture(options, true); @@ -398,15 +392,96 @@ describe('Camera tests Android.', function () { }); }; - return tryRunSpec(spec) - .done(done); + tryRunSpec(spec).done(done); + }, 10 * MINUTE); + + it('camera.ui.spec.5 Verifying target image size, sourceType=CAMERA', function (done) { + var spec = generateSpec({ + quality: 50, + allowEdit: false, + sourceType: cameraConstants.PictureSourceType.CAMERA, + saveToPhotoAlbum: false, + targetWidth: 210, + targetHeight: 210 + }); + + tryRunSpec(spec).done(done); + }, 10 * MINUTE); + + it('camera.ui.spec.6 Verifying target image size, sourceType=PHOTOLIBRARY', function (done) { + var spec = generateSpec({ + quality: 50, + allowEdit: false, + sourceType: cameraConstants.PictureSourceType.PHOTOLIBRARY, + saveToPhotoAlbum: false, + targetWidth: 210, + targetHeight: 210 + }); + + tryRunSpec(spec).done(done); + }, 10 * MINUTE); + + it('camera.ui.spec.7 Verifying target image size, sourceType=CAMERA, DestinationType=NATIVE_URI', function (done) { + var spec = generateSpec({ + quality: 50, + allowEdit: false, + sourceType: cameraConstants.PictureSourceType.CAMERA, + destinationType: cameraConstants.DestinationType.NATIVE_URI, + saveToPhotoAlbum: false, + targetWidth: 210, + targetHeight: 210 + }); + + tryRunSpec(spec).done(done); + }, 10 * MINUTE); + + it('camera.ui.spec.8 Verifying target image size, sourceType=PHOTOLIBRARY, DestinationType=NATIVE_URI', function (done) { + var spec = generateSpec({ + quality: 50, + allowEdit: false, + sourceType: cameraConstants.PictureSourceType.PHOTOLIBRARY, + destinationType: cameraConstants.DestinationType.NATIVE_URI, + saveToPhotoAlbum: false, + targetWidth: 210, + targetHeight: 210 + }); + + tryRunSpec(spec).done(done); + }, 10 * MINUTE); + + it('camera.ui.spec.9 Verifying target image size, sourceType=CAMERA, DestinationType=NATIVE_URI, quality=100', function (done) { + var spec = generateSpec({ + quality: 100, + allowEdit: true, + sourceType: cameraConstants.PictureSourceType.CAMERA, + destinationType: cameraConstants.DestinationType.NATIVE_URI, + saveToPhotoAlbum: false, + targetWidth: 305, + targetHeight: 305 + }); + + tryRunSpec(spec).done(done); + }, 10 * MINUTE); + + it('camera.ui.spec.10 Verifying target image size, sourceType=PHOTOLIBRARY, DestinationType=NATIVE_URI, quality=100', function (done) { + var spec = generateSpec({ + quality: 100, + allowEdit: true, + sourceType: cameraConstants.PictureSourceType.PHOTOLIBRARY, + destinationType: cameraConstants.DestinationType.NATIVE_URI, + saveToPhotoAlbum: false, + targetWidth: 305, + targetHeight: 305 + }); + + tryRunSpec(spec).done(done); }, 10 * MINUTE); // combine various options for getPicture() - generateSpecs().forEach(function (spec) { - it('camera.ui.spec.5.' + spec.id + ' Combining options. ' + spec.description, function (done) { - runCombinedSpec(spec) - .done(done); + generateOptions().forEach(function (spec) { + it('camera.ui.spec.11.' + spec.id + ' Combining options. ' + spec.description, function (done) { + var s = generateSpec(spec.options); + tryRunSpec(s).done(done); }, 10 * MINUTE); }); diff --git a/appium-tests/helpers/cameraHelper.js b/appium-tests/helpers/cameraHelper.js index 4f33163..544a9e7 100644 --- a/appium-tests/helpers/cameraHelper.js +++ b/appium-tests/helpers/cameraHelper.js @@ -1,5 +1,5 @@ /*jshint node: true */ -/* global Q */ +/* global Q, resolveLocalFileSystemURI, Camera, cordova */ /* * * Licensed to the Apache Software Foundation (ASF) under one @@ -94,7 +94,13 @@ module.exports.generateSpecs = function (sourceTypes, destinationTypes, encoding 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); @@ -103,11 +109,185 @@ module.exports.getPicture = function (opts, pid) { }, opts); }; -module.exports.checkPicture = function (pid, cb) { +// verifies taken picture when the promise is resolved, +// calls a callback with 'OK' if everything is good, +// calls a callback with 'ERROR: ' 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 skipFileTypeCheck = isAndroid && + options.quality === 100 && + !options.targetWidth && !options.targetHeight && + !options.correctOrientation; + 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.resolveLocalFileSystemURI) { + errorCallback('Cannot read file. Please install cordova-plugin-file to fix this.'); + return; + } + resolveLocalFileSystemURI(result, function (entry) { + if (skipFileTypeCheck) { + displayFile(entry); + } else { + verifyFile(entry); + } + }); + } 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.createElement('img'); + document.body.appendChild(imgEl); + var timedOut = false; + var loadTimeout = setTimeout(function () { + timedOut = true; + document.body.removeChild(imgEl); + errorCallback('The image did not load: ' + image.substring(0, 150)); + }, 10000); + var done = function (status) { + if (!timedOut) { + clearTimeout(loadTimeout); + document.body.removeChild(imgEl); + 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) { - cb(result); - }, function (err) { - cb('ERROR: ' + err); + verifyResult(result); + }) + .fail(function (e) { + errorCallback(e); }); }; diff --git a/appium-tests/ios/ios.spec.js b/appium-tests/ios/ios.spec.js index ea856a7..ec257b1 100644 --- a/appium-tests/ios/ios.spec.js +++ b/appium-tests/ios/ios.spec.js @@ -66,7 +66,7 @@ describe('Camera tests iOS.', function () { // generates test specs by combining all the specified options // you can add more options to test more scenarios - function generateSpecs() { + function generateOptions() { var sourceTypes = cameraConstants.PictureSourceType; var destinationTypes = cameraConstants.DestinationType; var encodingTypes = cameraConstants.EncodingType; @@ -149,33 +149,34 @@ describe('Camera tests iOS.', function () { // checks if the picture was successfully taken // if shouldLoad is falsy, ensures that the error callback was called - function checkPicture(shouldLoad) { + function checkPicture(shouldLoad, options) { + if (!options) { + options = {}; + } return driver .context(webviewContext) .setAsyncScriptTimeout(MINUTE) - .executeAsync(cameraHelper.checkPicture, [getCurrentPromiseId()]) + .executeAsync(cameraHelper.checkPicture, [getCurrentPromiseId(), options]) .then(function (result) { if (shouldLoad) { - expect(result.length).toBeGreaterThan(0); - if (result.indexOf('ERROR') >= 0) { - return fail(result); + if (result !== 'OK') { + fail(result); } - } else { - if (result.indexOf('ERROR') === -1) { - return fail('Unexpected success callback with result: ' + result); - } - expect(result.indexOf('ERROR')).toBe(0); + } else if (result.indexOf('ERROR') === -1) { + throw 'Unexpected success callback with result: ' + result; } }); } - function runCombinedSpec(spec) { + // takes a picture with the specified options + // and then verifies it + function runSpec(options) { return driver .then(function () { - return getPicture(spec.options); + return getPicture(options); }) .then(function () { - return checkPicture(true); + return checkPicture(true, options); }) .fail(saveScreenshotAndFail); } @@ -219,9 +220,8 @@ describe('Camera tests iOS.', function () { // getPicture(), then dismiss // wait for the error callback to be called it('camera.ui.spec.2 Dismissing the camera', function (done) { - // camera is not available on the iOS simulator if (!isDevice) { - pending(); + pending('Camera is not available on iOS simulator'); } var options = { sourceType: cameraConstants.PictureSourceType.CAMERA }; driver @@ -235,20 +235,156 @@ describe('Camera tests iOS.', function () { .done(done); }, 3 * MINUTE); + it('camera.ui.spec.3 Verifying target image size, sourceType=CAMERA', function (done) { + if (!isDevice) { + pending('Camera is not available on iOS simulator'); + } + var options = { + quality: 50, + allowEdit: false, + sourceType: cameraConstants.PictureSourceType.CAMERA, + saveToPhotoAlbum: false, + targetWidth: 210, + targetHeight: 210 + }; + + runSpec(options).done(done); + }, 3 * MINUTE); + + it('camera.ui.spec.4 Verifying target image size, sourceType=SAVEDPHOTOALBUM', function (done) { + var options = { + quality: 50, + allowEdit: false, + sourceType: cameraConstants.PictureSourceType.SAVEDPHOTOALBUM, + saveToPhotoAlbum: false, + targetWidth: 210, + targetHeight: 210 + }; + + runSpec(options).done(done); + }, 3 * MINUTE); + + it('camera.ui.spec.5 Verifying target image size, sourceType=PHOTOLIBRARY', function (done) { + var options = { + quality: 50, + allowEdit: false, + sourceType: cameraConstants.PictureSourceType.PHOTOLIBRARY, + saveToPhotoAlbum: false, + targetWidth: 210, + targetHeight: 210 + }; + + runSpec(options).done(done); + }, 3 * MINUTE); + + it('camera.ui.spec.6 Verifying target image size, sourceType=CAMERA, destinationType=NATIVE_URI', function (done) { + if (!isDevice) { + pending('Camera is not available on iOS simulator'); + } + var options = { + quality: 50, + allowEdit: false, + sourceType: cameraConstants.PictureSourceType.CAMERA, + destinationType: cameraConstants.DestinationType.NATIVE_URI, + saveToPhotoAlbum: false, + targetWidth: 210, + targetHeight: 210 + }; + + runSpec(options).done(done); + }, 3 * MINUTE); + + it('camera.ui.spec.7 Verifying target image size, sourceType=SAVEDPHOTOALBUM, destinationType=NATIVE_URI', function (done) { + var options = { + quality: 50, + allowEdit: false, + sourceType: cameraConstants.PictureSourceType.SAVEDPHOTOALBUM, + destinationType: cameraConstants.DestinationType.NATIVE_URI, + saveToPhotoAlbum: false, + targetWidth: 210, + targetHeight: 210 + }; + + runSpec(options).done(done); + }, 3 * MINUTE); + + it('camera.ui.spec.8 Verifying target image size, sourceType=PHOTOLIBRARY, destinationType=NATIVE_URI', function (done) { + var options = { + quality: 50, + allowEdit: false, + sourceType: cameraConstants.PictureSourceType.PHOTOLIBRARY, + destinationType: cameraConstants.DestinationType.NATIVE_URI, + saveToPhotoAlbum: false, + targetWidth: 210, + targetHeight: 210 + }; + + runSpec(options).done(done); + }, 3 * MINUTE); + + it('camera.ui.spec.9 Verifying target image size, sourceType=CAMERA, destinationType=NATIVE_URI, quality=100', function (done) { + if (!isDevice) { + pending('Camera is not available on iOS simulator'); + } + var options = { + quality: 100, + allowEdit: false, + sourceType: cameraConstants.PictureSourceType.CAMERA, + destinationType: cameraConstants.DestinationType.NATIVE_URI, + saveToPhotoAlbum: false, + targetWidth: 305, + targetHeight: 305 + }; + runSpec(options).done(done); + }, 3 * MINUTE); + + it('camera.ui.spec.10 Verifying target image size, sourceType=SAVEDPHOTOALBUM, destinationType=NATIVE_URI, quality=100', function (done) { + var options = { + quality: 100, + allowEdit: false, + sourceType: cameraConstants.PictureSourceType.SAVEDPHOTOALBUM, + destinationType: cameraConstants.DestinationType.NATIVE_URI, + saveToPhotoAlbum: false, + targetWidth: 305, + targetHeight: 305 + }; + + runSpec(options).done(done); + }, 3 * MINUTE); + + it('camera.ui.spec.11 Verifying target image size, sourceType=PHOTOLIBRARY, destinationType=NATIVE_URI, quality=100', function (done) { + var options = { + quality: 100, + allowEdit: false, + sourceType: cameraConstants.PictureSourceType.PHOTOLIBRARY, + destinationType: cameraConstants.DestinationType.NATIVE_URI, + saveToPhotoAlbum: false, + targetWidth: 305, + targetHeight: 305 + }; + + runSpec(options).done(done); + }, 3 * MINUTE); + // combine various options for getPicture() - generateSpecs().forEach(function (spec) { - it('camera.ui.spec.3.' + spec.id + ' Combining options. ' + spec.description, function (done) { - // camera is not available on iOS simulator + generateOptions().forEach(function (spec) { + it('camera.ui.spec.12.' + spec.id + ' Combining options. ' + spec.description, function (done) { if (!isDevice && spec.options.sourceType === cameraConstants.PictureSourceType.CAMERA) { - pending(); + pending('Camera is not available on iOS simulator'); } - runCombinedSpec(spec).done(done); + if (spec.options.sourceType === cameraConstants.PictureSourceType.CAMERA && + spec.options.destinationType === cameraConstants.DestinationType.NATIVE_URI) { + pending('Skipping: cannot prevent iOS from saving the picture to photo library and cannot delete it. ' + + 'For more info, see iOS quirks here: https://github.com/apache/cordova-plugin-camera#ios-quirks-1'); + } + + runSpec(spec.options).done(done); }, 3 * MINUTE); }); }); - it('camera.ui.util.4 Destroy the session', function (done) { + it('camera.ui.util Destroy the session', function (done) { driver .quit() .done(done); From dcc81bfbe16244cb460d3c5da79fe6ec22795ce7 Mon Sep 17 00:00:00 2001 From: Alexander Sorokin Date: Wed, 11 May 2016 17:51:43 +0300 Subject: [PATCH 15/40] CB-11232 Appium tests: fixed element tapping on iOS 9 --- appium-tests/ios/ios.spec.js | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/appium-tests/ios/ios.spec.js b/appium-tests/ios/ios.spec.js index ec257b1..3f5a68c 100644 --- a/appium-tests/ios/ios.spec.js +++ b/appium-tests/ios/ios.spec.js @@ -81,17 +81,8 @@ describe('Camera tests iOS.', function () { .elementByXPath('//*[@label="Use"]') .click() .fail(function () { - return driver - // For some reason "Choose" element is not clickable by standard Appium methods - // So getting its position and tapping there using TouchAction - .elementByXPath('//UIAButton[@label="Choose"]') - .getLocation() - .then(function (loc) { - var tapChoose = new wd.TouchAction(); - tapChoose.tap(loc); - return driver - .performTouchAction(tapChoose); - }); + // For some reason "Choose" element is not clickable by standard Appium methods + return wdHelper.tapElementByXPath('//UIAButton[@label="Choose"]', driver); }); } From a05f169984aff9b1db1ddf4f04618b78c2b81664 Mon Sep 17 00:00:00 2001 From: Alexander Sorokin Date: Thu, 19 May 2016 18:08:07 +0300 Subject: [PATCH 16/40] CB-11296: Appium: Better element clicking and session error handling --- appium-tests/android/android.spec.js | 55 ++++++++++++++++++++++++++-- appium-tests/helpers/cameraHelper.js | 12 ++++-- appium-tests/ios/ios.spec.js | 46 ++++++++++++++++++++--- 3 files changed, 99 insertions(+), 14 deletions(-) diff --git a/appium-tests/android/android.spec.js b/appium-tests/android/android.spec.js index 25f662c..e6dec6d 100644 --- a/appium-tests/android/android.spec.js +++ b/appium-tests/android/android.spec.js @@ -52,6 +52,8 @@ describe('Camera tests Android.', function () { var screenHeight = DEFAULT_SCREEN_HEIGHT; // promise count to use in promise ID var promiseCount = 0; + // going to set this to false if session is created successfully + var failedToStart = true; function getNextPromiseId() { promiseCount += 1; @@ -127,10 +129,18 @@ describe('Camera tests Android.', function () { .performTouchAction(tapTile); } return driver + .waitForElementByXPath('//android.widget.TextView[@text="Gallery"]', 20000) + .elementByXPath('//android.widget.TextView[@text="Gallery"]') + .elementByXPath('//android.widget.TextView[@text="Gallery"]') + .elementByXPath('//android.widget.TextView[@text="Gallery"]') .elementByXPath('//android.widget.TextView[@text="Gallery"]') .fail(function () { return driver .performTouchAction(swipeRight) + .waitForElementByXPath('//android.widget.TextView[@text="Gallery"]', 20000) + .elementByXPath('//android.widget.TextView[@text="Gallery"]') + .elementByXPath('//android.widget.TextView[@text="Gallery"]') + .elementByXPath('//android.widget.TextView[@text="Gallery"]') .elementByXPath('//android.widget.TextView[@text="Gallery"]'); }) .click() @@ -140,9 +150,13 @@ describe('Camera tests Android.', function () { } // taking a picture from camera return driver - .waitForElementByXPath('//android.widget.ImageView[contains(@resource-id,\'shutter\')]', MINUTE) + .waitForElementByXPath('//android.widget.ImageView[contains(@resource-id,\'shutter\')]', MINUTE / 2) + .elementByXPath('//android.widget.ImageView[contains(@resource-id,\'shutter\')]') + .elementByXPath('//android.widget.ImageView[contains(@resource-id,\'shutter\')]') .click() - .waitForElementByXPath('//android.widget.ImageView[contains(@resource-id,\'done\')]', MINUTE) + .waitForElementByXPath('//android.widget.ImageView[contains(@resource-id,\'done\')]', MINUTE / 2) + .elementByXPath('//android.widget.ImageView[contains(@resource-id,\'done\')]') + .elementByXPath('//android.widget.ImageView[contains(@resource-id,\'done\')]') .click(); }) .then(function () { @@ -168,7 +182,7 @@ describe('Camera tests Android.', function () { } return driver .context(webviewContext) - .setAsyncScriptTimeout(MINUTE) + .setAsyncScriptTimeout(MINUTE / 2) .executeAsync(cameraHelper.checkPicture, [getCurrentPromiseId(), options]) .then(function (result) { if (shouldLoad) { @@ -253,13 +267,23 @@ describe('Camera tests Android.', function () { }; } + function checkSession(done) { + if (failedToStart) { + fail('Failed to start a session'); + done(); + } + } + it('camera.ui.util configuring driver and starting a session', function (done) { getDriver() - .fail(fail) + .then(function () { + failedToStart = false; + }, fail) .done(done); }, 5 * MINUTE); it('camera.ui.util determine screen dimensions', function (done) { + checkSession(done); return driver .context(webviewContext) .execute(function () { @@ -278,6 +302,7 @@ describe('Camera tests Android.', function () { describe('Specs.', function () { // getPicture() with saveToPhotoLibrary = true it('camera.ui.spec.1 Saving a picture to the photo library', function (done) { + checkSession(done); var spec = generateSpec({ quality: 50, allowEdit: false, @@ -294,6 +319,7 @@ describe('Camera tests Android.', function () { // getPicture() with mediaType: VIDEO, sourceType: PHOTOLIBRARY it('camera.ui.spec.2 Selecting only videos', function (done) { + checkSession(done); var spec = function () { var options = { sourceType: cameraConstants.PictureSourceType.PHOTOLIBRARY, mediaType: cameraConstants.MediaType.VIDEO }; @@ -306,6 +332,8 @@ describe('Camera tests Android.', function () { // try to find "Gallery" menu item // if there's none, the gallery should be already opened return driver + .waitForElementByXPath('//android.widget.TextView[@text="Gallery"]', 20000) + .elementByXPath('//android.widget.TextView[@text="Gallery"]') .elementByXPath('//android.widget.TextView[@text="Gallery"]') .then(function (element) { return element.click(); @@ -344,6 +372,7 @@ describe('Camera tests Android.', function () { // getPicture(), then dismiss // wait for the error callback to be called it('camera.ui.spec.3 Dismissing the camera', function (done) { + checkSession(done); var spec = function () { var options = { quality: 50, @@ -357,6 +386,8 @@ describe('Camera tests Android.', function () { }) .context("NATIVE_APP") .waitForElementByXPath('//android.widget.ImageView[contains(@resource-id,\'cancel\')]', MINUTE / 2) + .elementByXPath('//android.widget.ImageView[contains(@resource-id,\'cancel\')]') + .elementByXPath('//android.widget.ImageView[contains(@resource-id,\'cancel\')]') .click() .then(function () { return checkPicture(false); @@ -369,6 +400,7 @@ describe('Camera tests Android.', function () { // getPicture(), then take picture but dismiss the edit // wait for the error callback to be called it('camera.ui.spec.4 Dismissing the edit', function (done) { + checkSession(done); var spec = function () { var options = { quality: 50, @@ -382,10 +414,16 @@ describe('Camera tests Android.', function () { }) .context('NATIVE_APP') .waitForElementByXPath('//android.widget.ImageView[contains(@resource-id,\'shutter\')]', MINUTE / 2) + .elementByXPath('//android.widget.ImageView[contains(@resource-id,\'shutter\')]') + .elementByXPath('//android.widget.ImageView[contains(@resource-id,\'shutter\')]') .click() .waitForElementByXPath('//android.widget.ImageView[contains(@resource-id,\'done\')]', MINUTE / 2) + .elementByXPath('//android.widget.ImageView[contains(@resource-id,\'done\')]') + .elementByXPath('//android.widget.ImageView[contains(@resource-id,\'done\')]') .click() .waitForElementByXPath('//*[contains(@resource-id,\'discard\')]', MINUTE / 2) + .elementByXPath('//*[contains(@resource-id,\'discard\')]') + .elementByXPath('//*[contains(@resource-id,\'discard\')]') .click() .then(function () { return checkPicture(false); @@ -396,6 +434,7 @@ describe('Camera tests Android.', function () { }, 10 * MINUTE); it('camera.ui.spec.5 Verifying target image size, sourceType=CAMERA', function (done) { + checkSession(done); var spec = generateSpec({ quality: 50, allowEdit: false, @@ -409,6 +448,7 @@ describe('Camera tests Android.', function () { }, 10 * MINUTE); it('camera.ui.spec.6 Verifying target image size, sourceType=PHOTOLIBRARY', function (done) { + checkSession(done); var spec = generateSpec({ quality: 50, allowEdit: false, @@ -422,6 +462,7 @@ describe('Camera tests Android.', function () { }, 10 * MINUTE); it('camera.ui.spec.7 Verifying target image size, sourceType=CAMERA, DestinationType=NATIVE_URI', function (done) { + checkSession(done); var spec = generateSpec({ quality: 50, allowEdit: false, @@ -436,6 +477,7 @@ describe('Camera tests Android.', function () { }, 10 * MINUTE); it('camera.ui.spec.8 Verifying target image size, sourceType=PHOTOLIBRARY, DestinationType=NATIVE_URI', function (done) { + checkSession(done); var spec = generateSpec({ quality: 50, allowEdit: false, @@ -450,6 +492,7 @@ describe('Camera tests Android.', function () { }, 10 * MINUTE); it('camera.ui.spec.9 Verifying target image size, sourceType=CAMERA, DestinationType=NATIVE_URI, quality=100', function (done) { + checkSession(done); var spec = generateSpec({ quality: 100, allowEdit: true, @@ -464,6 +507,7 @@ describe('Camera tests Android.', function () { }, 10 * MINUTE); it('camera.ui.spec.10 Verifying target image size, sourceType=PHOTOLIBRARY, DestinationType=NATIVE_URI, quality=100', function (done) { + checkSession(done); var spec = generateSpec({ quality: 100, allowEdit: true, @@ -480,12 +524,14 @@ describe('Camera tests Android.', function () { // combine various options for getPicture() generateOptions().forEach(function (spec) { it('camera.ui.spec.11.' + spec.id + ' Combining options. ' + spec.description, function (done) { + checkSession(done); var s = generateSpec(spec.options); tryRunSpec(s).done(done); }, 10 * MINUTE); }); it('camera.ui.util Delete test image from device library', function (done) { + checkSession(done); if (!isTestPictureSaved) { // couldn't save test picture earlier, so nothing to delete here done(); @@ -518,6 +564,7 @@ describe('Camera tests Android.', function () { }); it('camera.ui.util Destroy the session', function (done) { + checkSession(done); driver .quit() .done(done); diff --git a/appium-tests/helpers/cameraHelper.js b/appium-tests/helpers/cameraHelper.js index 544a9e7..5f60bc3 100644 --- a/appium-tests/helpers/cameraHelper.js +++ b/appium-tests/helpers/cameraHelper.js @@ -247,18 +247,22 @@ module.exports.checkPicture = function (pid, options, cb) { function displayImage(image) { try { - var imgEl = document.createElement('img'); - document.body.appendChild(imgEl); + 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; - document.body.removeChild(imgEl); + imgEl.src = ''; errorCallback('The image did not load: ' + image.substring(0, 150)); }, 10000); var done = function (status) { if (!timedOut) { clearTimeout(loadTimeout); - document.body.removeChild(imgEl); + imgEl.src = ''; cb(status); } }; diff --git a/appium-tests/ios/ios.spec.js b/appium-tests/ios/ios.spec.js index 3f5a68c..224190e 100644 --- a/appium-tests/ios/ios.spec.js +++ b/appium-tests/ios/ios.spec.js @@ -30,7 +30,6 @@ var wdHelper = global.WD_HELPER; var screenshotHelper = global.SCREENSHOT_HELPER; -var wd = wdHelper.getWD(); var isDevice = global.DEVICE; var cameraConstants = require('../../www/CameraConstants'); var cameraHelper = require('../helpers/cameraHelper'); @@ -44,6 +43,8 @@ describe('Camera tests iOS.', function () { var webviewContext = DEFAULT_WEBVIEW_CONTEXT; // promise count to use in promise ID var promiseCount = 0; + // going to set this to false if session is created successfully + var failedToStart = true; function getNextPromiseId() { promiseCount += 1; @@ -127,12 +128,14 @@ describe('Camera tests iOS.', function () { if (cancelCamera) { return driver .waitForElementByXPath('//*[@label="Cancel"]', MINUTE / 2) + .elementByXPath('//*[@label="Cancel"]') + .elementByXPath('//*[@label="Cancel"]') .click(); } return driver .waitForElementByXPath('//*[@label="Take Picture"]', MINUTE / 2) .click() - .elementByXPath('//*[@label="Use Photo"]') + .waitForElementByXPath('//*[@label="Use Photo"]', MINUTE / 2) .click(); }) .fail(fail); @@ -146,7 +149,7 @@ describe('Camera tests iOS.', function () { } return driver .context(webviewContext) - .setAsyncScriptTimeout(MINUTE) + .setAsyncScriptTimeout(MINUTE / 2) .executeAsync(cameraHelper.checkPicture, [getCurrentPromiseId(), options]) .then(function (result) { if (shouldLoad) { @@ -187,15 +190,25 @@ describe('Camera tests iOS.', function () { }); } + function checkSession(done) { + if (failedToStart) { + fail('Failed to start a session'); + done(); + } + } + it('camera.ui.util configure driver and start a session', function (done) { getDriver() - .fail(fail) - .finally(done); + .then(function () { + failedToStart = false; + }, fail) + .done(done); }, 5 * MINUTE); describe('Specs.', function () { // getPicture() with mediaType: VIDEO, sourceType: PHOTOLIBRARY it('camera.ui.spec.1 Selecting only videos', function (done) { + checkSession(done); var options = { sourceType: cameraConstants.PictureSourceType.PHOTOLIBRARY, mediaType: cameraConstants.MediaType.VIDEO }; driver @@ -211,10 +224,12 @@ describe('Camera tests iOS.', function () { // getPicture(), then dismiss // wait for the error callback to be called it('camera.ui.spec.2 Dismissing the camera', function (done) { + checkSession(done); if (!isDevice) { pending('Camera is not available on iOS simulator'); } - var options = { sourceType: cameraConstants.PictureSourceType.CAMERA }; + var options = { sourceType: cameraConstants.PictureSourceType.CAMERA, + saveToPhotoAlbum: false }; driver .then(function () { return getPicture(options, true); @@ -227,6 +242,7 @@ describe('Camera tests iOS.', function () { }, 3 * MINUTE); it('camera.ui.spec.3 Verifying target image size, sourceType=CAMERA', function (done) { + checkSession(done); if (!isDevice) { pending('Camera is not available on iOS simulator'); } @@ -243,6 +259,7 @@ describe('Camera tests iOS.', function () { }, 3 * MINUTE); it('camera.ui.spec.4 Verifying target image size, sourceType=SAVEDPHOTOALBUM', function (done) { + checkSession(done); var options = { quality: 50, allowEdit: false, @@ -256,6 +273,7 @@ describe('Camera tests iOS.', function () { }, 3 * MINUTE); it('camera.ui.spec.5 Verifying target image size, sourceType=PHOTOLIBRARY', function (done) { + checkSession(done); var options = { quality: 50, allowEdit: false, @@ -269,6 +287,10 @@ describe('Camera tests iOS.', function () { }, 3 * MINUTE); it('camera.ui.spec.6 Verifying target image size, sourceType=CAMERA, destinationType=NATIVE_URI', function (done) { + // remove this line if you don't mind the tests leaving a photo saved on device + pending('Cannot prevent iOS from saving the picture to photo library'); + + checkSession(done); if (!isDevice) { pending('Camera is not available on iOS simulator'); } @@ -286,6 +308,7 @@ describe('Camera tests iOS.', function () { }, 3 * MINUTE); it('camera.ui.spec.7 Verifying target image size, sourceType=SAVEDPHOTOALBUM, destinationType=NATIVE_URI', function (done) { + checkSession(done); var options = { quality: 50, allowEdit: false, @@ -300,6 +323,7 @@ describe('Camera tests iOS.', function () { }, 3 * MINUTE); it('camera.ui.spec.8 Verifying target image size, sourceType=PHOTOLIBRARY, destinationType=NATIVE_URI', function (done) { + checkSession(done); var options = { quality: 50, allowEdit: false, @@ -314,6 +338,10 @@ describe('Camera tests iOS.', function () { }, 3 * MINUTE); it('camera.ui.spec.9 Verifying target image size, sourceType=CAMERA, destinationType=NATIVE_URI, quality=100', function (done) { + // remove this line if you don't mind the tests leaving a photo saved on device + pending('Cannot prevent iOS from saving the picture to photo library'); + + checkSession(done); if (!isDevice) { pending('Camera is not available on iOS simulator'); } @@ -330,6 +358,7 @@ describe('Camera tests iOS.', function () { }, 3 * MINUTE); it('camera.ui.spec.10 Verifying target image size, sourceType=SAVEDPHOTOALBUM, destinationType=NATIVE_URI, quality=100', function (done) { + checkSession(done); var options = { quality: 100, allowEdit: false, @@ -344,6 +373,7 @@ describe('Camera tests iOS.', function () { }, 3 * MINUTE); it('camera.ui.spec.11 Verifying target image size, sourceType=PHOTOLIBRARY, destinationType=NATIVE_URI, quality=100', function (done) { + checkSession(done); var options = { quality: 100, allowEdit: false, @@ -360,9 +390,12 @@ describe('Camera tests iOS.', function () { // combine various options for getPicture() generateOptions().forEach(function (spec) { it('camera.ui.spec.12.' + spec.id + ' Combining options. ' + spec.description, function (done) { + checkSession(done); if (!isDevice && spec.options.sourceType === cameraConstants.PictureSourceType.CAMERA) { pending('Camera is not available on iOS simulator'); } + + // remove this check if you don't mind the tests leaving a photo saved on device if (spec.options.sourceType === cameraConstants.PictureSourceType.CAMERA && spec.options.destinationType === cameraConstants.DestinationType.NATIVE_URI) { pending('Skipping: cannot prevent iOS from saving the picture to photo library and cannot delete it. ' + @@ -376,6 +409,7 @@ describe('Camera tests iOS.', function () { }); it('camera.ui.util Destroy the session', function (done) { + checkSession(done); driver .quit() .done(done); From 8a7326969f8a62ce387a7eef2983b6b154ca2e4e Mon Sep 17 00:00:00 2001 From: Vladimir Kotikov Date: Fri, 10 Jun 2016 11:14:03 +0300 Subject: [PATCH 17/40] Add badges for paramedic builds on Jenkins --- README.md | 19 ++++++++++++++++++- jsdoc2md/TEMPLATE.md | 4 +++- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 7f5a9cf..0258903 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,9 @@ description: Take pictures with the device camera. # under the License. --> -[![Build Status](https://travis-ci.org/apache/cordova-plugin-camera.svg?branch=master)](https://travis-ci.org/apache/cordova-plugin-camera) +|Android|iOS| Windows 8.1 Store | Windows 8.1 Phone | Windows 10 Store | Travis CI | +|:-:|:-:|:-:|:-:|:-:|:-:| +|[![Build Status](http://cordova-ci.cloudapp.net:8080/buildStatus/icon?job=cordova-periodic-build/PLATFORM=android,PLUGIN=cordova-plugin-camera)](http://cordova-ci.cloudapp.net:8080/job/cordova-periodic-build/PLATFORM=android,PLUGIN=cordova-plugin-camera/)|[![Build Status](http://cordova-ci.cloudapp.net:8080/buildStatus/icon?job=cordova-periodic-build/PLATFORM=ios,PLUGIN=cordova-plugin-camera)](http://cordova-ci.cloudapp.net:8080/job/cordova-periodic-build/PLATFORM=ios,PLUGIN=cordova-plugin-camera/)|[![Build Status](http://cordova-ci.cloudapp.net:8080/buildStatus/icon?job=cordova-periodic-build/PLATFORM=windows-8.1-store,PLUGIN=cordova-plugin-camera)](http://cordova-ci.cloudapp.net:8080/job/cordova-periodic-build/PLATFORM=windows-8.1-store,PLUGIN=cordova-plugin-camera/)|[![Build Status](http://cordova-ci.cloudapp.net:8080/buildStatus/icon?job=cordova-periodic-build/PLATFORM=windows-8.1-phone,PLUGIN=cordova-plugin-camera)](http://cordova-ci.cloudapp.net:8080/job/cordova-periodic-build/PLATFORM=windows-8.1-phone,PLUGIN=cordova-plugin-camera/)|[![Build Status](http://cordova-ci.cloudapp.net:8080/buildStatus/icon?job=cordova-periodic-build/PLATFORM=windows-10-store,PLUGIN=cordova-plugin-camera)](http://cordova-ci.cloudapp.net:8080/job/cordova-periodic-build/PLATFORM=windows-10-store,PLUGIN=cordova-plugin-camera/)|[![Build Status](https://travis-ci.org/apache/cordova-plugin-camera.svg?branch=master)](https://travis-ci.org/apache/cordova-plugin-camera) # cordova-plugin-camera @@ -98,8 +100,10 @@ Documentation consists of template and API docs produced from the plugin JS code --- + ## camera + ### camera.getPicture(successCallback, errorCallback, options) Takes a photo using the camera, or retrieves a photo from the device's image gallery. The image is passed to the success callback as a @@ -167,6 +171,7 @@ More examples [here](#camera-getPicture-examples). Quirks [here](#camera-getPict navigator.camera.getPicture(cameraSuccess, cameraError, cameraOptions); ``` + ### camera.cleanup() Removes intermediate image files that are kept in temporary storage after calling [`camera.getPicture`](#module_camera.getPicture). Applies only when the value of @@ -191,6 +196,7 @@ function onFail(message) { } ``` + ### camera.onError : function Callback function that provides an error message. @@ -201,6 +207,7 @@ Callback function that provides an error message. | message | string | The message is provided by the device's native code. | + ### camera.onSuccess : function Callback function that provides the image data. @@ -220,6 +227,7 @@ function cameraCallback(imageData) { } ``` + ### camera.CameraOptions : Object Optional parameters to customize the camera settings. * [Quirks](#CameraOptions-quirks) @@ -245,8 +253,10 @@ Optional parameters to customize the camera settings. --- + ## Camera + ### Camera.DestinationType : enum **Kind**: static enum property of [Camera](#module_Camera) **Properties** @@ -258,6 +268,7 @@ Optional parameters to customize the camera settings. | NATIVE_URI | number | 2 | Return native uri (eg. asset-library://... for iOS) | + ### Camera.EncodingType : enum **Kind**: static enum property of [Camera](#module_Camera) **Properties** @@ -268,6 +279,7 @@ Optional parameters to customize the camera settings. | PNG | number | 1 | Return PNG encoded image | + ### Camera.MediaType : enum **Kind**: static enum property of [Camera](#module_Camera) **Properties** @@ -279,6 +291,7 @@ Optional parameters to customize the camera settings. | ALLMEDIA | number | 2 | Allow selection from all media types | + ### Camera.PictureSourceType : enum **Kind**: static enum property of [Camera](#module_Camera) **Properties** @@ -290,6 +303,7 @@ Optional parameters to customize the camera settings. | SAVEDPHOTOALBUM | number | 2 | Choose image from picture library (same as PHOTOLIBRARY for Android) | + ### Camera.PopoverArrowDirection : enum Matches iOS UIPopoverArrowDirection constants to specify arrow location on popover. @@ -305,6 +319,7 @@ Matches iOS UIPopoverArrowDirection constants to specify arrow location on popov | ARROW_ANY | number | 15 | + ### Camera.Direction : enum **Kind**: static enum property of [Camera](#module_Camera) **Properties** @@ -317,6 +332,7 @@ Matches iOS UIPopoverArrowDirection constants to specify arrow location on popov --- + ## CameraPopoverOptions iOS-only parameters that specify the anchor element location and arrow direction of the popover when selecting images from an iPad's library @@ -338,6 +354,7 @@ location. --- + ## CameraPopoverHandle A handle to an image picker popover. diff --git a/jsdoc2md/TEMPLATE.md b/jsdoc2md/TEMPLATE.md index 64bce32..95ef23c 100644 --- a/jsdoc2md/TEMPLATE.md +++ b/jsdoc2md/TEMPLATE.md @@ -4,7 +4,9 @@ description: Take pictures with the device camera. --- {{>cdv-license~}} -[![Build Status](https://travis-ci.org/apache/cordova-plugin-camera.svg?branch=master)](https://travis-ci.org/apache/cordova-plugin-camera) +|Android|iOS| Windows 8.1 Store | Windows 8.1 Phone | Windows 10 Store | Travis CI | +|:-:|:-:|:-:|:-:|:-:|:-:| +|[![Build Status](http://cordova-ci.cloudapp.net:8080/buildStatus/icon?job=cordova-periodic-build/PLATFORM=android,PLUGIN=cordova-plugin-camera)](http://cordova-ci.cloudapp.net:8080/job/cordova-periodic-build/PLATFORM=android,PLUGIN=cordova-plugin-camera/)|[![Build Status](http://cordova-ci.cloudapp.net:8080/buildStatus/icon?job=cordova-periodic-build/PLATFORM=ios,PLUGIN=cordova-plugin-camera)](http://cordova-ci.cloudapp.net:8080/job/cordova-periodic-build/PLATFORM=ios,PLUGIN=cordova-plugin-camera/)|[![Build Status](http://cordova-ci.cloudapp.net:8080/buildStatus/icon?job=cordova-periodic-build/PLATFORM=windows-8.1-store,PLUGIN=cordova-plugin-camera)](http://cordova-ci.cloudapp.net:8080/job/cordova-periodic-build/PLATFORM=windows-8.1-store,PLUGIN=cordova-plugin-camera/)|[![Build Status](http://cordova-ci.cloudapp.net:8080/buildStatus/icon?job=cordova-periodic-build/PLATFORM=windows-8.1-phone,PLUGIN=cordova-plugin-camera)](http://cordova-ci.cloudapp.net:8080/job/cordova-periodic-build/PLATFORM=windows-8.1-phone,PLUGIN=cordova-plugin-camera/)|[![Build Status](http://cordova-ci.cloudapp.net:8080/buildStatus/icon?job=cordova-periodic-build/PLATFORM=windows-10-store,PLUGIN=cordova-plugin-camera)](http://cordova-ci.cloudapp.net:8080/job/cordova-periodic-build/PLATFORM=windows-10-store,PLUGIN=cordova-plugin-camera/)|[![Build Status](https://travis-ci.org/apache/cordova-plugin-camera.svg?branch=master)](https://travis-ci.org/apache/cordova-plugin-camera) # cordova-plugin-camera From acff98058f3230bf64f0cc7bef974ff10d63a77c Mon Sep 17 00:00:00 2001 From: Alexander Sorokin Date: Tue, 28 Jun 2016 16:20:24 +0300 Subject: [PATCH 18/40] CB-11498 [Android] Appium tests should not fail when there is no camera --- appium-tests/android/android.spec.js | 73 +++++++++++++++++++++++----- 1 file changed, 62 insertions(+), 11 deletions(-) diff --git a/appium-tests/android/android.spec.js b/appium-tests/android/android.spec.js index e6dec6d..6c91609 100644 --- a/appium-tests/android/android.spec.js +++ b/appium-tests/android/android.spec.js @@ -52,8 +52,12 @@ describe('Camera tests Android.', function () { var screenHeight = DEFAULT_SCREEN_HEIGHT; // promise count to use in promise ID var promiseCount = 0; - // going to set this to false if session is created successfully - var failedToStart = true; + // determine if Appium session is created successfully + var appiumSessionStarted = false; + // determine if camera is present on the device/emulator + var cameraAvailable = false; + // a path to the image we add to the gallery before test run + var fillerImagePath; function getNextPromiseId() { promiseCount += 1; @@ -217,16 +221,24 @@ describe('Camera tests Android.', function () { function getDriver() { driver = wdHelper.getDriver('Android'); - return wdHelper.getWebviewContext(driver) + return driver.getWebviewContext() .then(function(context) { webviewContext = context; return driver.context(webviewContext); }) + .waitForDeviceReady() + .injectLibraries() + .deleteFillerImage(fillerImagePath) .then(function () { - return wdHelper.waitForDeviceReady(driver); + fillerImagePath = null; }) - .then(function () { - return wdHelper.injectLibraries(driver); + .addFillerImage() + .then(function (result) { + if (result && result.indexOf('ERROR:') === 0) { + throw new Error(result); + } else { + fillerImagePath = result; + } }); } @@ -268,23 +280,29 @@ describe('Camera tests Android.', function () { } function checkSession(done) { - if (failedToStart) { + if (!appiumSessionStarted) { fail('Failed to start a session'); done(); } } + function checkCamera(pending) { + if (!cameraAvailable) { + pending('This test requires camera'); + } + } + it('camera.ui.util configuring driver and starting a session', function (done) { getDriver() .then(function () { - failedToStart = false; + appiumSessionStarted = true; }, fail) .done(done); }, 5 * MINUTE); it('camera.ui.util determine screen dimensions', function (done) { checkSession(done); - return driver + driver .context(webviewContext) .execute(function () { return { @@ -299,10 +317,28 @@ describe('Camera tests Android.', function () { .done(done); }, MINUTE); + it('camera.ui.util determine camera availability', function (done) { + checkSession(done); + var opts = { + sourceType: cameraConstants.PictureSourceType.CAMERA, + saveToPhotoAlbum: false + }; + + return driver + .then(function () { + return getPicture(opts); + }) + .then(function () { + cameraAvailable = true; + }) + .finally(done); + }, 5 * MINUTE); + describe('Specs.', function () { // getPicture() with saveToPhotoLibrary = true it('camera.ui.spec.1 Saving a picture to the photo library', function (done) { checkSession(done); + checkCamera(pending); var spec = generateSpec({ quality: 50, allowEdit: false, @@ -373,6 +409,7 @@ describe('Camera tests Android.', function () { // wait for the error callback to be called it('camera.ui.spec.3 Dismissing the camera', function (done) { checkSession(done); + checkCamera(pending); var spec = function () { var options = { quality: 50, @@ -401,6 +438,7 @@ describe('Camera tests Android.', function () { // wait for the error callback to be called it('camera.ui.spec.4 Dismissing the edit', function (done) { checkSession(done); + checkCamera(pending); var spec = function () { var options = { quality: 50, @@ -435,6 +473,7 @@ describe('Camera tests Android.', function () { it('camera.ui.spec.5 Verifying target image size, sourceType=CAMERA', function (done) { checkSession(done); + checkCamera(pending); var spec = generateSpec({ quality: 50, allowEdit: false, @@ -463,6 +502,7 @@ describe('Camera tests Android.', function () { it('camera.ui.spec.7 Verifying target image size, sourceType=CAMERA, DestinationType=NATIVE_URI', function (done) { checkSession(done); + checkCamera(pending); var spec = generateSpec({ quality: 50, allowEdit: false, @@ -493,6 +533,7 @@ describe('Camera tests Android.', function () { it('camera.ui.spec.9 Verifying target image size, sourceType=CAMERA, DestinationType=NATIVE_URI, quality=100', function (done) { checkSession(done); + checkCamera(pending); var spec = generateSpec({ quality: 100, allowEdit: true, @@ -525,12 +566,22 @@ describe('Camera tests Android.', function () { generateOptions().forEach(function (spec) { it('camera.ui.spec.11.' + spec.id + ' Combining options. ' + spec.description, function (done) { checkSession(done); + if (spec.options.sourceType == cameraConstants.PictureSourceType.CAMERA) { + checkCamera(pending); + } var s = generateSpec(spec.options); tryRunSpec(s).done(done); }, 10 * MINUTE); }); - it('camera.ui.util Delete test image from device library', function (done) { + it('camera.ui.util Delete filler picture from device library', function (done) { + driver + .context(webviewContext) + .deleteFillerImage(fillerImagePath) + .done(done); + }, MINUTE); + + it('camera.ui.util Delete taken picture from device library', function (done) { checkSession(done); if (!isTestPictureSaved) { // couldn't save test picture earlier, so nothing to delete here @@ -539,7 +590,7 @@ describe('Camera tests Android.', function () { } // delete exactly one latest picture // this should be the picture we've taken in the first spec - return driver + driver .context('NATIVE_APP') .deviceKeyEvent(BACK_BUTTON) .sleep(1000) From b69571724035f41642f3ee612c5b66e1f0c4386c Mon Sep 17 00:00:00 2001 From: Alexander Sorokin Date: Mon, 11 Jul 2016 16:16:52 +0300 Subject: [PATCH 19/40] CB-11553 Pend failing Appium tests on Sauce Labs for the time being --- appium-tests/android/android.spec.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/appium-tests/android/android.spec.js b/appium-tests/android/android.spec.js index 6c91609..6dc69e1 100644 --- a/appium-tests/android/android.spec.js +++ b/appium-tests/android/android.spec.js @@ -292,6 +292,12 @@ describe('Camera tests Android.', function () { } } + function checkSauce(pending) { + if (global.USE_SAUCE) { + pending('This test cannot run on Sauce Labs yet. We\'re working on it!'); + } + } + it('camera.ui.util configuring driver and starting a session', function (done) { getDriver() .then(function () { @@ -356,6 +362,7 @@ describe('Camera tests Android.', function () { // getPicture() with mediaType: VIDEO, sourceType: PHOTOLIBRARY it('camera.ui.spec.2 Selecting only videos', function (done) { checkSession(done); + checkSauce(pending); var spec = function () { var options = { sourceType: cameraConstants.PictureSourceType.PHOTOLIBRARY, mediaType: cameraConstants.MediaType.VIDEO }; @@ -488,6 +495,7 @@ describe('Camera tests Android.', function () { it('camera.ui.spec.6 Verifying target image size, sourceType=PHOTOLIBRARY', function (done) { checkSession(done); + checkSauce(pending); var spec = generateSpec({ quality: 50, allowEdit: false, @@ -518,6 +526,7 @@ describe('Camera tests Android.', function () { it('camera.ui.spec.8 Verifying target image size, sourceType=PHOTOLIBRARY, DestinationType=NATIVE_URI', function (done) { checkSession(done); + checkSauce(pending); var spec = generateSpec({ quality: 50, allowEdit: false, @@ -549,6 +558,7 @@ describe('Camera tests Android.', function () { it('camera.ui.spec.10 Verifying target image size, sourceType=PHOTOLIBRARY, DestinationType=NATIVE_URI, quality=100', function (done) { checkSession(done); + checkSauce(pending); var spec = generateSpec({ quality: 100, allowEdit: true, @@ -566,6 +576,7 @@ describe('Camera tests Android.', function () { generateOptions().forEach(function (spec) { it('camera.ui.spec.11.' + spec.id + ' Combining options. ' + spec.description, function (done) { checkSession(done); + checkSauce(pending); if (spec.options.sourceType == cameraConstants.PictureSourceType.CAMERA) { checkCamera(pending); } From 7129fb2c12910f2f5505686d97635c4037b4223f Mon Sep 17 00:00:00 2001 From: Alexander Sorokin Date: Tue, 12 Jul 2016 12:28:58 +0300 Subject: [PATCH 20/40] CB-11553 Pend failing Appium tests on Sauce Labs for the time being (reverted from commit b69571724035f41642f3ee612c5b66e1f0c4386c) --- appium-tests/android/android.spec.js | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/appium-tests/android/android.spec.js b/appium-tests/android/android.spec.js index 6dc69e1..6c91609 100644 --- a/appium-tests/android/android.spec.js +++ b/appium-tests/android/android.spec.js @@ -292,12 +292,6 @@ describe('Camera tests Android.', function () { } } - function checkSauce(pending) { - if (global.USE_SAUCE) { - pending('This test cannot run on Sauce Labs yet. We\'re working on it!'); - } - } - it('camera.ui.util configuring driver and starting a session', function (done) { getDriver() .then(function () { @@ -362,7 +356,6 @@ describe('Camera tests Android.', function () { // getPicture() with mediaType: VIDEO, sourceType: PHOTOLIBRARY it('camera.ui.spec.2 Selecting only videos', function (done) { checkSession(done); - checkSauce(pending); var spec = function () { var options = { sourceType: cameraConstants.PictureSourceType.PHOTOLIBRARY, mediaType: cameraConstants.MediaType.VIDEO }; @@ -495,7 +488,6 @@ describe('Camera tests Android.', function () { it('camera.ui.spec.6 Verifying target image size, sourceType=PHOTOLIBRARY', function (done) { checkSession(done); - checkSauce(pending); var spec = generateSpec({ quality: 50, allowEdit: false, @@ -526,7 +518,6 @@ describe('Camera tests Android.', function () { it('camera.ui.spec.8 Verifying target image size, sourceType=PHOTOLIBRARY, DestinationType=NATIVE_URI', function (done) { checkSession(done); - checkSauce(pending); var spec = generateSpec({ quality: 50, allowEdit: false, @@ -558,7 +549,6 @@ describe('Camera tests Android.', function () { it('camera.ui.spec.10 Verifying target image size, sourceType=PHOTOLIBRARY, DestinationType=NATIVE_URI, quality=100', function (done) { checkSession(done); - checkSauce(pending); var spec = generateSpec({ quality: 100, allowEdit: true, @@ -576,7 +566,6 @@ describe('Camera tests Android.', function () { generateOptions().forEach(function (spec) { it('camera.ui.spec.11.' + spec.id + ' Combining options. ' + spec.description, function (done) { checkSession(done); - checkSauce(pending); if (spec.options.sourceType == cameraConstants.PictureSourceType.CAMERA) { checkCamera(pending); } From 2027d696062cd50972ba4dd0a26cd5b01ad2f413 Mon Sep 17 00:00:00 2001 From: Vladimir Kotikov Date: Tue, 26 Jul 2016 11:15:26 +0300 Subject: [PATCH 21/40] CB-11447 Resolve iOS tests failures due to iOS quirks * Skip image type verification if source is gallery and destination is native uri * Update docs t oclarify how camera works on iOS in some edge cases --- README.md | 16 +++++++++++++--- appium-tests/helpers/cameraHelper.js | 13 +++++++++++-- appium-tests/ios/ios.spec.js | 24 ++++++++++++------------ jsdoc2md/TEMPLATE.md | 2 ++ www/Camera.js | 3 --- www/CameraConstants.js | 13 +++++++++++++ 6 files changed, 51 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 0258903..391b5cf 100644 --- a/README.md +++ b/README.md @@ -126,16 +126,13 @@ one of the following formats, depending on the specified `cameraOptions`: - A `String` containing the Base64-encoded photo image. - - A `String` representing the image file location on local storage (default). You can do whatever you want with the encoded image or URI, for example: - Render the image in an `` tag, as in the example below - - Save the data locally (`LocalStorage`, [Lawnchair](http://brianleroux.github.com/lawnchair/), etc.) - - Post the data to a remote server __NOTE__: Photo resolution on newer devices is quite good. Photos @@ -258,6 +255,12 @@ Optional parameters to customize the camera settings. ### Camera.DestinationType : enum +Defines the output format of `Camera.getPicture` call. +_Note:_ On iOS passing `DestinationType.NATIVE_URI` along with +`PictureSourceType.PHOTOLIBRARY` or `PictureSourceType.SAVEDPHOTOALBUM` will +disable any image modifications (resize, quality change, cropping, etc.) due +to implementation specific. + **Kind**: static enum property of [Camera](#module_Camera) **Properties** @@ -293,6 +296,11 @@ Optional parameters to customize the camera settings. ### Camera.PictureSourceType : enum +Defines the output format of `Camera.getPicture` call. +_Note:_ On iOS passing `PictureSourceType.PHOTOLIBRARY` or `PictureSourceType.SAVEDPHOTOALBUM` +along with `DestinationType.NATIVE_URI` will disable any image modifications (resize, quality +change, cropping, etc.) due to implementation specific. + **Kind**: static enum property of [Camera](#module_Camera) **Properties** @@ -531,6 +539,8 @@ Tizen only supports a `destinationType` of - When using `destinationType.NATIVE_URI` and `sourceType.CAMERA`, photos are saved in the saved photo album regardless on the value of `saveToPhotoAlbum` parameter. +- When using `destinationType.NATIVE_URI` and `sourceType.PHOTOLIBRARY` or `sourceType.SAVEDPHOTOALBUM`, all editing options are ignored and link is returned to original picture. + #### Tizen Quirks - options not supported diff --git a/appium-tests/helpers/cameraHelper.js b/appium-tests/helpers/cameraHelper.js index 5f60bc3..00578a9 100644 --- a/appium-tests/helpers/cameraHelper.js +++ b/appium-tests/helpers/cameraHelper.js @@ -119,10 +119,19 @@ module.exports.checkPicture = function (pid, options, cb) { 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 skipFileTypeCheck = isAndroid && - options.quality === 100 && + 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 + // TODO: correct link above + 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) { diff --git a/appium-tests/ios/ios.spec.js b/appium-tests/ios/ios.spec.js index 224190e..af12fd8 100644 --- a/appium-tests/ios/ios.spec.js +++ b/appium-tests/ios/ios.spec.js @@ -286,7 +286,7 @@ describe('Camera tests iOS.', function () { runSpec(options).done(done); }, 3 * MINUTE); - it('camera.ui.spec.6 Verifying target image size, sourceType=CAMERA, destinationType=NATIVE_URI', function (done) { + it('camera.ui.spec.6 Verifying target image size, sourceType=CAMERA, destinationType=FILE_URL', function (done) { // remove this line if you don't mind the tests leaving a photo saved on device pending('Cannot prevent iOS from saving the picture to photo library'); @@ -298,7 +298,7 @@ describe('Camera tests iOS.', function () { quality: 50, allowEdit: false, sourceType: cameraConstants.PictureSourceType.CAMERA, - destinationType: cameraConstants.DestinationType.NATIVE_URI, + destinationType: cameraConstants.DestinationType.FILE_URL, saveToPhotoAlbum: false, targetWidth: 210, targetHeight: 210 @@ -307,13 +307,13 @@ describe('Camera tests iOS.', function () { runSpec(options).done(done); }, 3 * MINUTE); - it('camera.ui.spec.7 Verifying target image size, sourceType=SAVEDPHOTOALBUM, destinationType=NATIVE_URI', function (done) { + it('camera.ui.spec.7 Verifying target image size, sourceType=SAVEDPHOTOALBUM, destinationType=FILE_URL', function (done) { checkSession(done); var options = { quality: 50, allowEdit: false, sourceType: cameraConstants.PictureSourceType.SAVEDPHOTOALBUM, - destinationType: cameraConstants.DestinationType.NATIVE_URI, + destinationType: cameraConstants.DestinationType.FILE_URL, saveToPhotoAlbum: false, targetWidth: 210, targetHeight: 210 @@ -322,13 +322,13 @@ describe('Camera tests iOS.', function () { runSpec(options).done(done); }, 3 * MINUTE); - it('camera.ui.spec.8 Verifying target image size, sourceType=PHOTOLIBRARY, destinationType=NATIVE_URI', function (done) { + it('camera.ui.spec.8 Verifying target image size, sourceType=PHOTOLIBRARY, destinationType=FILE_URL', function (done) { checkSession(done); var options = { quality: 50, allowEdit: false, sourceType: cameraConstants.PictureSourceType.PHOTOLIBRARY, - destinationType: cameraConstants.DestinationType.NATIVE_URI, + destinationType: cameraConstants.DestinationType.FILE_URL, saveToPhotoAlbum: false, targetWidth: 210, targetHeight: 210 @@ -337,7 +337,7 @@ describe('Camera tests iOS.', function () { runSpec(options).done(done); }, 3 * MINUTE); - it('camera.ui.spec.9 Verifying target image size, sourceType=CAMERA, destinationType=NATIVE_URI, quality=100', function (done) { + it('camera.ui.spec.9 Verifying target image size, sourceType=CAMERA, destinationType=FILE_URL, quality=100', function (done) { // remove this line if you don't mind the tests leaving a photo saved on device pending('Cannot prevent iOS from saving the picture to photo library'); @@ -349,7 +349,7 @@ describe('Camera tests iOS.', function () { quality: 100, allowEdit: false, sourceType: cameraConstants.PictureSourceType.CAMERA, - destinationType: cameraConstants.DestinationType.NATIVE_URI, + destinationType: cameraConstants.DestinationType.FILE_URL, saveToPhotoAlbum: false, targetWidth: 305, targetHeight: 305 @@ -357,13 +357,13 @@ describe('Camera tests iOS.', function () { runSpec(options).done(done); }, 3 * MINUTE); - it('camera.ui.spec.10 Verifying target image size, sourceType=SAVEDPHOTOALBUM, destinationType=NATIVE_URI, quality=100', function (done) { + it('camera.ui.spec.10 Verifying target image size, sourceType=SAVEDPHOTOALBUM, destinationType=FILE_URL, quality=100', function (done) { checkSession(done); var options = { quality: 100, allowEdit: false, sourceType: cameraConstants.PictureSourceType.SAVEDPHOTOALBUM, - destinationType: cameraConstants.DestinationType.NATIVE_URI, + destinationType: cameraConstants.DestinationType.FILE_URL, saveToPhotoAlbum: false, targetWidth: 305, targetHeight: 305 @@ -372,13 +372,13 @@ describe('Camera tests iOS.', function () { runSpec(options).done(done); }, 3 * MINUTE); - it('camera.ui.spec.11 Verifying target image size, sourceType=PHOTOLIBRARY, destinationType=NATIVE_URI, quality=100', function (done) { + it('camera.ui.spec.11 Verifying target image size, sourceType=PHOTOLIBRARY, destinationType=FILE_URL, quality=100', function (done) { checkSession(done); var options = { quality: 100, allowEdit: false, sourceType: cameraConstants.PictureSourceType.PHOTOLIBRARY, - destinationType: cameraConstants.DestinationType.NATIVE_URI, + destinationType: cameraConstants.DestinationType.FILE_URL, saveToPhotoAlbum: false, targetWidth: 305, targetHeight: 305 diff --git a/jsdoc2md/TEMPLATE.md b/jsdoc2md/TEMPLATE.md index 95ef23c..2e53a89 100644 --- a/jsdoc2md/TEMPLATE.md +++ b/jsdoc2md/TEMPLATE.md @@ -187,6 +187,8 @@ Tizen only supports a `destinationType` of - When using `destinationType.NATIVE_URI` and `sourceType.CAMERA`, photos are saved in the saved photo album regardless on the value of `saveToPhotoAlbum` parameter. +- When using `destinationType.NATIVE_URI` and `sourceType.PHOTOLIBRARY` or `sourceType.SAVEDPHOTOALBUM`, all editing options are ignored and link is returned to original picture. + #### Tizen Quirks - options not supported diff --git a/www/Camera.js b/www/Camera.js index 2f9154b..04d13d9 100644 --- a/www/Camera.js +++ b/www/Camera.js @@ -99,16 +99,13 @@ for (var key in Camera) { * `cameraOptions`: * * - A `String` containing the Base64-encoded photo image. - * * - A `String` representing the image file location on local storage (default). * * You can do whatever you want with the encoded image or URI, for * example: * * - Render the image in an `` tag, as in the example below - * * - Save the data locally (`LocalStorage`, [Lawnchair](http://brianleroux.github.com/lawnchair/), etc.) - * * - Post the data to a remote server * * __NOTE__: Photo resolution on newer devices is quite good. Photos diff --git a/www/CameraConstants.js b/www/CameraConstants.js index f4b0694..c13dba3 100644 --- a/www/CameraConstants.js +++ b/www/CameraConstants.js @@ -24,6 +24,13 @@ */ module.exports = { /** + * @description + * Defines the output format of `Camera.getPicture` call. + * _Note:_ On iOS passing `DestinationType.NATIVE_URI` along with + * `PictureSourceType.PHOTOLIBRARY` or `PictureSourceType.SAVEDPHOTOALBUM` will + * disable any image modifications (resize, quality change, cropping, etc.) due + * to implementation specific. + * * @enum {number} */ DestinationType:{ @@ -55,6 +62,12 @@ module.exports = { ALLMEDIA : 2 }, /** + * @description + * Defines the output format of `Camera.getPicture` call. + * _Note:_ On iOS passing `PictureSourceType.PHOTOLIBRARY` or `PictureSourceType.SAVEDPHOTOALBUM` + * along with `DestinationType.NATIVE_URI` will disable any image modifications (resize, quality + * change, cropping, etc.) due to implementation specific. + * * @enum {number} */ PictureSourceType:{ From fed798e6c7f56e23bff994ab2c11d316c8257a78 Mon Sep 17 00:00:00 2001 From: Vladimir Kotikov Date: Tue, 26 Jul 2016 15:17:44 +0300 Subject: [PATCH 22/40] CB-11447 Respect output format when retrieving images from gallery --- src/android/CameraLauncher.java | 39 ++++++++++++++++++++++++--------- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/src/android/CameraLauncher.java b/src/android/CameraLauncher.java index 9db9911..060103b 100644 --- a/src/android/CameraLauncher.java +++ b/src/android/CameraLauncher.java @@ -365,7 +365,7 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect intent.putExtra("aspectX", 1); intent.putExtra("aspectY", 1); } - File photo = createCaptureFile(encodingType); + File photo = createCaptureFile(JPEG); croppedUri = Uri.fromFile(photo); intent.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, croppedUri); } else { @@ -592,15 +592,29 @@ private void refreshGallery(Uri contentUri) this.cordova.getActivity().sendBroadcast(mediaScanIntent); } + /** + * Converts output image format int value to string value of mime type. + * @param outputFormat int Output format of camera API. + * Must be value of either JPEG or PNG constant + * @return String String value of mime type or empty string if mime type is not supported + */ + private String getMimetypeForFormat(int outputFormat) { + if (outputFormat == PNG) return "image/png"; + if (outputFormat == JPEG) return "image/jpeg"; + return ""; + } -private String ouputModifiedBitmap(Bitmap bitmap, Uri uri) throws IOException { + private String ouputModifiedBitmap(Bitmap bitmap, Uri uri) throws IOException { // Some content: URIs do not map to file paths (e.g. picasa). String realPath = FileHelper.getRealPath(uri, this.cordova); // Get filename from uri String fileName = realPath != null ? - realPath.substring(realPath.lastIndexOf('/') + 1) : - "modified." + (this.encodingType == JPEG ? "jpg" : "png"); + realPath.substring(realPath.lastIndexOf('/') + 1, realPath.lastIndexOf(".") + 1) : + "modified."; + + // Append filename extension based on output encoding type + fileName += (this.encodingType == JPEG ? "jpg" : "png"); String modifiedPath = getTempDirectoryPath() + "/" + fileName; @@ -660,15 +674,18 @@ private String ouputModifiedBitmap(Bitmap bitmap, Uri uri) throws IOException { this.callbackContext.success(fileLocation); } else { + String uriString = uri.toString(); + // Get the path to the image. Makes loading so much easier. + String mimeType = FileHelper.getMimeType(uriString, this.cordova); + // This is a special case to just return the path as no scaling, // rotating, nor compressing needs to be done if (this.targetHeight == -1 && this.targetWidth == -1 && - (destType == FILE_URI || destType == NATIVE_URI) && !this.correctOrientation) { - this.callbackContext.success(uri.toString()); + (destType == FILE_URI || destType == NATIVE_URI) && !this.correctOrientation && + mimeType.equalsIgnoreCase(getMimetypeForFormat(encodingType))) + { + this.callbackContext.success(uriString); } else { - String uriString = uri.toString(); - // Get the path to the image. Makes loading so much easier. - String mimeType = FileHelper.getMimeType(uriString, this.cordova); // If we don't have a valid image so quit. if (!("image/jpeg".equalsIgnoreCase(mimeType) || "image/png".equalsIgnoreCase(mimeType))) { Log.d(LOG_TAG, "I either have a null image path or bitmap"); @@ -710,7 +727,9 @@ private String ouputModifiedBitmap(Bitmap bitmap, Uri uri) throws IOException { else if (destType == FILE_URI || destType == NATIVE_URI) { // Did we modify the image? if ( (this.targetHeight > 0 && this.targetWidth > 0) || - (this.correctOrientation && this.orientationCorrected) ) { + (this.correctOrientation && this.orientationCorrected) || + !mimeType.equalsIgnoreCase(getMimetypeForFormat(encodingType))) + { try { String modifiedPath = this.ouputModifiedBitmap(bitmap, uri); // The modified image is cached by the app in order to get around this and not have to delete you From 4e439d85c326fef1c0fbcc3d7001c78325351ad6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julio=20C=C3=A9sar?= Date: Sun, 31 Jul 2016 18:06:39 +0200 Subject: [PATCH 23/40] CB-9070. (ios) Fixed CameraPopoverHandle documentation This closes #225 --- README.md | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 391b5cf..3f660e4 100644 --- a/README.md +++ b/README.md @@ -93,9 +93,11 @@ Documentation consists of template and API docs produced from the plugin JS code * [.PictureSourceType](#module_Camera.PictureSourceType) : enum * [.PopoverArrowDirection](#module_Camera.PopoverArrowDirection) : enum * [.Direction](#module_Camera.Direction) : enum + +* [CameraPopoverOptions](#module_CameraPopoverOptions) * [CameraPopoverHandle](#module_CameraPopoverHandle) -* [CameraPopoverOptions](#module_CameraPopoverOptions) + * [.setPosition(options)](#module_CameraPopoverHandle.setPosition) --- @@ -116,10 +118,7 @@ Once the user snaps the photo, the camera application closes and the application If `Camera.sourceType` is `Camera.PictureSourceType.PHOTOLIBRARY` or `Camera.PictureSourceType.SAVEDPHOTOALBUM`, then a dialog displays -that allows users to select an existing image. The -`camera.getPicture` function returns a [`CameraPopoverHandle`](#module_CameraPopoverHandle) object, -which can be used to reposition the image selection dialog, for -example, when the device orientation changes. +that allows users to select an existing image. The return value is sent to the [`cameraSuccess`](#module_camera.onSuccess) callback function, in one of the following formats, depending on the specified @@ -364,7 +363,17 @@ location. ## CameraPopoverHandle -A handle to an image picker popover. +A handle to the image picker popover. + + + +### CameraPopoverHandle.setPosition(options) +Can be used to reposition the image selection dialog, for example, when the device orientation changes. + + +| Param | Type | Description | +| --- | --- | --- | +| options | [CameraPopoverOptions](#module_CameraPopoverOptions) | CameraPopoverOptions | __Supported Platforms__ @@ -372,7 +381,7 @@ __Supported Platforms__ **Example** ```js -var cameraPopoverHandle = navigator.camera.getPicture(onSuccess, onFail, +navigator.camera.getPicture(onSuccess, onFail, { destinationType: Camera.DestinationType.FILE_URI, sourceType: Camera.PictureSourceType.PHOTOLIBRARY, @@ -381,6 +390,7 @@ var cameraPopoverHandle = navigator.camera.getPicture(onSuccess, onFail, // Reposition the popover if the orientation changes. window.onorientationchange = function() { + var cameraPopoverHandle = new CameraPopoverHandle(); var cameraPopoverOptions = new CameraPopoverOptions(0, 0, 100, 100, Camera.PopoverArrowDirection.ARROW_ANY); cameraPopoverHandle.setPosition(cameraPopoverOptions); } From 3f8c53f7f35970f9ceb9fa5eee18febfd6febb9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julio=20C=C3=A9sar?= Date: Sun, 31 Jul 2016 17:13:57 +0200 Subject: [PATCH 24/40] CB-11410: (ios) fix cameraPopoverHandle.setPosition This closes #224 --- src/ios/CDVCamera.m | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/ios/CDVCamera.m b/src/ios/CDVCamera.m index 42dd469..f2b17f4 100644 --- a/src/ios/CDVCamera.m +++ b/src/ios/CDVCamera.m @@ -240,9 +240,13 @@ static NSString* toBase64(NSData* data) { - (void)repositionPopover:(CDVInvokedUrlCommand*)command { - NSDictionary* options = [command argumentAtIndex:0 withDefault:nil]; + if (([[self pickerController] pickerPopoverController] != nil) && [[[self pickerController] pickerPopoverController] isPopoverVisible]) { - [self displayPopover:options]; + [[[self pickerController] pickerPopoverController] dismissPopoverAnimated:NO]; + + NSDictionary* options = [command argumentAtIndex:0 withDefault:nil]; + [self displayPopover:options]; + } } - (NSInteger)integerValueForKey:(NSDictionary*)dict key:(NSString*)key defaultValue:(NSInteger)defaultValue From 7e8fe0bae98beb088bb0c6c8bf622af197dfdd23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julio=20C=C3=A9sar?= Date: Mon, 1 Aug 2016 00:23:01 +0200 Subject: [PATCH 25/40] CB-10067: (ios) clarifications on PictureSourceType This closes #227 --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 3f660e4..c5f594b 100644 --- a/README.md +++ b/README.md @@ -305,9 +305,9 @@ change, cropping, etc.) due to implementation specific. | Name | Type | Default | Description | | --- | --- | --- | --- | -| PHOTOLIBRARY | number | 0 | Choose image from picture library (same as SAVEDPHOTOALBUM for Android) | +| PHOTOLIBRARY | number | 0 | Choose image from the device's photo library (same as SAVEDPHOTOALBUM for Android) | | CAMERA | number | 1 | Take picture from camera | -| SAVEDPHOTOALBUM | number | 2 | Choose image from picture library (same as PHOTOLIBRARY for Android) | +| SAVEDPHOTOALBUM | number | 2 | Choose image only from the device's Camera Roll album (same as PHOTOLIBRARY for Android) | From c13e9f327b1f2a8d3cc96c3ae20c403dea2b0c97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julio=20C=C3=A9sar?= Date: Sun, 31 Jul 2016 20:15:49 +0200 Subject: [PATCH 26/40] CB-11376: (ios): fix CameraUsesGeolocation error If it's not a camera picture don't use geolocation This closes #226 --- src/ios/CDVCamera.m | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/ios/CDVCamera.m b/src/ios/CDVCamera.m index f2b17f4..019141b 100644 --- a/src/ios/CDVCamera.m +++ b/src/ios/CDVCamera.m @@ -524,9 +524,11 @@ static NSString* toBase64(NSData* data) { NSString* mediaType = [info objectForKey:UIImagePickerControllerMediaType]; if ([mediaType isEqualToString:(NSString*)kUTTypeImage]) { [weakSelf resultForImage:cameraPicker.pictureOptions info:info completion:^(CDVPluginResult* res) { - [weakSelf.commandDelegate sendPluginResult:res callbackId:cameraPicker.callbackId]; - weakSelf.hasPendingOperation = NO; - weakSelf.pickerController = nil; + if (![self usesGeolocation] || picker.sourceType != UIImagePickerControllerSourceTypeCamera) { + [weakSelf.commandDelegate sendPluginResult:res callbackId:cameraPicker.callbackId]; + weakSelf.hasPendingOperation = NO; + weakSelf.pickerController = nil; + } }]; } else { From 5807458a1d5d58bb84f0b060bc069b4b50d2215b Mon Sep 17 00:00:00 2001 From: Alexander Sorokin Date: Tue, 2 Aug 2016 13:05:01 +0300 Subject: [PATCH 27/40] CB-11656 (Android) Appium tests: Fixed side menu opening on certain resolutions --- appium-tests/android/android.spec.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/appium-tests/android/android.spec.js b/appium-tests/android/android.spec.js index 6c91609..eb65153 100644 --- a/appium-tests/android/android.spec.js +++ b/appium-tests/android/android.spec.js @@ -118,12 +118,12 @@ describe('Camera tests Android.', function () { tapTile .tap({ x: Math.round(screenWidth / 4), - y: Math.round(screenHeight / 5) + y: Math.round(screenHeight / 4) }); swipeRight .press({x: 10, y: 100}) .wait(300) - .moveTo({x: Math.round(screenWidth / 2), y: 0}) + .moveTo({x: Math.round(screenWidth - (screenWidth / 8)), y: 0}) .release() .wait(1000); if (options.allowEdit) { @@ -306,8 +306,8 @@ describe('Camera tests Android.', function () { .context(webviewContext) .execute(function () { return { - 'width': window.innerWidth, - 'height': window.innerHeight + 'width': screen.availWidth, + 'height': screen.availHeight }; }, []) .then(function (size) { @@ -330,8 +330,10 @@ describe('Camera tests Android.', function () { }) .then(function () { cameraAvailable = true; + }, function () { + return recreateSession(); }) - .finally(done); + .done(done); }, 5 * MINUTE); describe('Specs.', function () { From fee72c7c0439037d1d7ee44603271c528eda769c Mon Sep 17 00:00:00 2001 From: Alexander Sorokin Date: Tue, 2 Aug 2016 18:11:19 +0300 Subject: [PATCH 28/40] CB-11656 (Android) Appium tests: Fixed side menu opening on some more resolutions --- appium-tests/android/android.spec.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/appium-tests/android/android.spec.js b/appium-tests/android/android.spec.js index eb65153..733c18a 100644 --- a/appium-tests/android/android.spec.js +++ b/appium-tests/android/android.spec.js @@ -121,9 +121,10 @@ describe('Camera tests Android.', function () { y: Math.round(screenHeight / 4) }); swipeRight - .press({x: 10, y: 100}) + .press({x: 10, y: 150}) .wait(300) .moveTo({x: Math.round(screenWidth - (screenWidth / 8)), y: 0}) + .wait(1500) .release() .wait(1000); if (options.allowEdit) { From e588907ac732e58e1a319da3d4e5635ecd8e8414 Mon Sep 17 00:00:00 2001 From: Alexander Sorokin Date: Sat, 13 Aug 2016 16:58:33 +0300 Subject: [PATCH 29/40] CB-11631 Appium tests: A fix for a flaky "selection cancelled" failure --- appium-tests/android/android.spec.js | 4 +++- appium-tests/helpers/cameraHelper.js | 1 - 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/appium-tests/android/android.spec.js b/appium-tests/android/android.spec.js index 733c18a..7be0359 100644 --- a/appium-tests/android/android.spec.js +++ b/appium-tests/android/android.spec.js @@ -398,7 +398,9 @@ describe('Camera tests Android.', function () { .then(function () { // success means we're still in native app return driver - .deviceKeyEvent(BACK_BUTTON); + .deviceKeyEvent(BACK_BUTTON) + // give native app some time to close + .sleep(2000); }, function () { // error means we're already in webview return driver; diff --git a/appium-tests/helpers/cameraHelper.js b/appium-tests/helpers/cameraHelper.js index 00578a9..cb22ec5 100644 --- a/appium-tests/helpers/cameraHelper.js +++ b/appium-tests/helpers/cameraHelper.js @@ -125,7 +125,6 @@ module.exports.checkPicture = function (pid, options, cb) { // Skip image type check if destination is NATIVE_URI and source - device's photoalbum // https://github.com/apache/cordova-plugin-camera/#ios-quirks-1 - // TODO: correct link above var skipFileTypeCheckiOS = isIos && options.destinationType === Camera.DestinationType.NATIVE_URI && (options.sourceType === Camera.PictureSourceType.PHOTOLIBRARY || options.sourceType === Camera.PictureSourceType.SAVEDPHOTOALBUM); From 0accbf560baeb2116f434f554a917cb427183b99 Mon Sep 17 00:00:00 2001 From: Alexander Sorokin Date: Tue, 16 Aug 2016 14:03:09 +0300 Subject: [PATCH 30/40] CB-11695 Increased session creation timeout for Appium tests --- appium-tests/android/android.spec.js | 2 +- appium-tests/ios/ios.spec.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/appium-tests/android/android.spec.js b/appium-tests/android/android.spec.js index 7be0359..c8b2963 100644 --- a/appium-tests/android/android.spec.js +++ b/appium-tests/android/android.spec.js @@ -299,7 +299,7 @@ describe('Camera tests Android.', function () { appiumSessionStarted = true; }, fail) .done(done); - }, 5 * MINUTE); + }, 10 * MINUTE); it('camera.ui.util determine screen dimensions', function (done) { checkSession(done); diff --git a/appium-tests/ios/ios.spec.js b/appium-tests/ios/ios.spec.js index af12fd8..cab45f6 100644 --- a/appium-tests/ios/ios.spec.js +++ b/appium-tests/ios/ios.spec.js @@ -203,7 +203,7 @@ describe('Camera tests iOS.', function () { failedToStart = false; }, fail) .done(done); - }, 5 * MINUTE); + }, 10 * MINUTE); describe('Specs.', function () { // getPicture() with mediaType: VIDEO, sourceType: PHOTOLIBRARY From 92d67d990dde1d5a0286241f89f09d8bc555c168 Mon Sep 17 00:00:00 2001 From: Alexander Sorokin Date: Tue, 16 Aug 2016 14:29:26 +0300 Subject: [PATCH 31/40] Closing invalid PR This closes #219 From 62d1b01e811753db006a3c75e599a5496b6205fc Mon Sep 17 00:00:00 2001 From: Alexander Sorokin Date: Tue, 16 Aug 2016 19:19:22 +0300 Subject: [PATCH 32/40] CB-11709 Tests should use resolveLocalFileSystemURL() instead of deprecated resolveFileSystemURI() --- appium-tests/helpers/cameraHelper.js | 6 +++--- tests/tests.js | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/appium-tests/helpers/cameraHelper.js b/appium-tests/helpers/cameraHelper.js index cb22ec5..a16916f 100644 --- a/appium-tests/helpers/cameraHelper.js +++ b/appium-tests/helpers/cameraHelper.js @@ -1,5 +1,5 @@ /*jshint node: true */ -/* global Q, resolveLocalFileSystemURI, Camera, cordova */ +/* global Q, resolveLocalFileSystemURL, Camera, cordova */ /* * * Licensed to the Apache Software Foundation (ASF) under one @@ -174,11 +174,11 @@ module.exports.checkPicture = function (pid, options, cb) { result.indexOf('content:') === 0 || result.indexOf('assets-library:') === 0) { - if (!window.resolveLocalFileSystemURI) { + if (!window.resolveLocalFileSystemURL) { errorCallback('Cannot read file. Please install cordova-plugin-file to fix this.'); return; } - resolveLocalFileSystemURI(result, function (entry) { + resolveLocalFileSystemURL(result, function (entry) { if (skipFileTypeCheck) { displayFile(entry); } else { diff --git a/tests/tests.js b/tests/tests.js index 1513f14..222a839 100644 --- a/tests/tests.js +++ b/tests/tests.js @@ -19,7 +19,7 @@ * */ -/* globals Camera, resolveLocalFileSystemURI, FileEntry, CameraPopoverOptions, FileTransfer, FileUploadOptions, LocalFileSystem, MSApp */ +/* globals Camera, resolveLocalFileSystemURL, FileEntry, CameraPopoverOptions, FileTransfer, FileUploadOptions, LocalFileSystem, MSApp */ /* jshint jasmine: true */ exports.defineAutoTests = function () { @@ -142,11 +142,11 @@ exports.defineManualTests = function (contentEl, createActionButton) { 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) { - resolveLocalFileSystemURI(data, function (e) { + resolveLocalFileSystemURL(data, function (e) { fileEntry = e; - logCallback('resolveLocalFileSystemURI()', true)(e.toURL()); + logCallback('resolveLocalFileSystemURL()', true)(e.toURL()); readFile(); - }, logCallback('resolveLocalFileSystemURI()', false)); + }, logCallback('resolveLocalFileSystemURL()', false)); } else if (pictureUrl.indexOf('data:image/jpeg;base64') === 0) { // do nothing } else { @@ -251,7 +251,7 @@ exports.defineManualTests = function (contentEl, createActionButton) { //cleanup //rename moved file back to original name so other tests can reference image - resolveLocalFileSystemURI(destDirEntry.nativeURL+'moved_file.png', function(fileEntry) { + 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 () { @@ -259,7 +259,7 @@ exports.defineManualTests = function (contentEl, createActionButton) { }); //remove copied file - resolveLocalFileSystemURI(destDirEntry.nativeURL+'copied_file.png', function(fileEntry) { + 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 () { From 9f159d757a505af663c5764dd4d44558d15d261d Mon Sep 17 00:00:00 2001 From: Alexander Sorokin Date: Wed, 17 Aug 2016 17:35:23 +0300 Subject: [PATCH 33/40] CB-11631 Appium tests: A working fix for a flaky "selection canceled" failure --- appium-tests/android/android.spec.js | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/appium-tests/android/android.spec.js b/appium-tests/android/android.spec.js index c8b2963..0e00bab 100644 --- a/appium-tests/android/android.spec.js +++ b/appium-tests/android/android.spec.js @@ -400,7 +400,18 @@ describe('Camera tests Android.', function () { return driver .deviceKeyEvent(BACK_BUTTON) // give native app some time to close - .sleep(2000); + .sleep(2000) + // try again! because every ~30th build + // on Sauce Labs this backbutton doesn't work + .elementById('action_bar_title') + .then(function () { + // success means we're still in native app + return driver + .deviceKeyEvent(BACK_BUTTON); + }, function () { + // error means we're already in webview + return driver; + }); }, function () { // error means we're already in webview return driver; From 6e19147b09c2341896ee48bd9117e7b57beec9cb Mon Sep 17 00:00:00 2001 From: Simon MacDonald Date: Mon, 22 Aug 2016 15:52:52 -0400 Subject: [PATCH 34/40] Plugin uses Android Log class and not Cordova LOG class --- src/android/CameraLauncher.java | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/android/CameraLauncher.java b/src/android/CameraLauncher.java index 060103b..50003a4 100644 --- a/src/android/CameraLauncher.java +++ b/src/android/CameraLauncher.java @@ -57,7 +57,6 @@ import android.os.Bundle; import android.os.Environment; import android.provider.MediaStore; import android.util.Base64; -import android.util.Log; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PermissionInfo; @@ -426,14 +425,14 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect cropIntent, CROP_CAMERA + destType); } } catch (ActivityNotFoundException anfe) { - Log.e(LOG_TAG, "Crop operation not supported on this device"); + LOG.e(LOG_TAG, "Crop operation not supported on this device"); try { processResultFromCamera(destType, cameraIntent); } catch (IOException e) { e.printStackTrace(); - Log.e(LOG_TAG, "Unable to write to file"); + LOG.e(LOG_TAG, "Unable to write to file"); } } } @@ -494,7 +493,7 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect // Double-check the bitmap. if (bitmap == null) { - Log.d(LOG_TAG, "I either have a null image path or bitmap"); + LOG.d(LOG_TAG, "I either have a null image path or bitmap"); this.failPicture("Unable to create bitmap!"); return; } @@ -537,7 +536,7 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect // Double-check the bitmap. if (bitmap == null) { - Log.d(LOG_TAG, "I either have a null image path or bitmap"); + LOG.d(LOG_TAG, "I either have a null image path or bitmap"); this.failPicture("Unable to create bitmap!"); return; } @@ -666,7 +665,7 @@ private void refreshGallery(Uri contentUri) int rotate = 0; String fileLocation = FileHelper.getRealPath(uri, this.cordova); - Log.d(LOG_TAG, "File locaton is: " + fileLocation); + LOG.d(LOG_TAG, "File locaton is: " + fileLocation); // If you ask for video or all media type you will automatically get back a file URI // and there will be no attempt to resize any returned data @@ -688,7 +687,7 @@ private void refreshGallery(Uri contentUri) } else { // If we don't have a valid image so quit. if (!("image/jpeg".equalsIgnoreCase(mimeType) || "image/png".equalsIgnoreCase(mimeType))) { - Log.d(LOG_TAG, "I either have a null image path or bitmap"); + LOG.d(LOG_TAG, "I either have a null image path or bitmap"); this.failPicture("Unable to retrieve path to picture!"); return; } @@ -699,7 +698,7 @@ private void refreshGallery(Uri contentUri) e.printStackTrace(); } if (bitmap == null) { - Log.d(LOG_TAG, "I either have a null image path or bitmap"); + LOG.d(LOG_TAG, "I either have a null image path or bitmap"); this.failPicture("Unable to create bitmap!"); return; } @@ -779,7 +778,7 @@ private void refreshGallery(Uri contentUri) processResultFromCamera(destType, intent); } catch (IOException e) { e.printStackTrace(); - Log.e(LOG_TAG, "Unable to write to file"); + LOG.e(LOG_TAG, "Unable to write to file"); } }// If cancelled From 7813ad9befd00b419f0caf3a6d0c0d9af87a4be5 Mon Sep 17 00:00:00 2001 From: Vladimir Kotikov Date: Tue, 23 Aug 2016 16:14:11 +0300 Subject: [PATCH 35/40] CB-9070 Update CameraPopoverHandle docs to reflect README update --- README.md | 20 ++++---------------- www/Camera.js | 5 +---- www/ios/CameraPopoverHandle.js | 10 ++++++++-- 3 files changed, 13 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index c5f594b..4294bd2 100644 --- a/README.md +++ b/README.md @@ -93,11 +93,9 @@ Documentation consists of template and API docs produced from the plugin JS code * [.PictureSourceType](#module_Camera.PictureSourceType) : enum * [.PopoverArrowDirection](#module_Camera.PopoverArrowDirection) : enum * [.Direction](#module_Camera.Direction) : enum - -* [CameraPopoverOptions](#module_CameraPopoverOptions) * [CameraPopoverHandle](#module_CameraPopoverHandle) - * [.setPosition(options)](#module_CameraPopoverHandle.setPosition) +* [CameraPopoverOptions](#module_CameraPopoverOptions) --- @@ -305,9 +303,9 @@ change, cropping, etc.) due to implementation specific. | Name | Type | Default | Description | | --- | --- | --- | --- | -| PHOTOLIBRARY | number | 0 | Choose image from the device's photo library (same as SAVEDPHOTOALBUM for Android) | +| PHOTOLIBRARY | number | 0 | Choose image from picture library (same as SAVEDPHOTOALBUM for Android) | | CAMERA | number | 1 | Take picture from camera | -| SAVEDPHOTOALBUM | number | 2 | Choose image only from the device's Camera Roll album (same as PHOTOLIBRARY for Android) | +| SAVEDPHOTOALBUM | number | 2 | Choose image from picture library (same as PHOTOLIBRARY for Android) | @@ -363,17 +361,7 @@ location. ## CameraPopoverHandle -A handle to the image picker popover. - - - -### CameraPopoverHandle.setPosition(options) -Can be used to reposition the image selection dialog, for example, when the device orientation changes. - - -| Param | Type | Description | -| --- | --- | --- | -| options | [CameraPopoverOptions](#module_CameraPopoverOptions) | CameraPopoverOptions | +A handle to an image picker popover. __Supported Platforms__ diff --git a/www/Camera.js b/www/Camera.js index 04d13d9..d006787 100644 --- a/www/Camera.js +++ b/www/Camera.js @@ -89,10 +89,7 @@ for (var key in Camera) { * * If `Camera.sourceType` is `Camera.PictureSourceType.PHOTOLIBRARY` or * `Camera.PictureSourceType.SAVEDPHOTOALBUM`, then a dialog displays - * that allows users to select an existing image. The - * `camera.getPicture` function returns a [`CameraPopoverHandle`]{@link module:CameraPopoverHandle} object, - * which can be used to reposition the image selection dialog, for - * example, when the device orientation changes. + * that allows users to select an existing image. * * The return value is sent to the [`cameraSuccess`]{@link module:camera.onSuccess} callback function, in * one of the following formats, depending on the specified diff --git a/www/ios/CameraPopoverHandle.js b/www/ios/CameraPopoverHandle.js index 3990e18..8b92137 100644 --- a/www/ios/CameraPopoverHandle.js +++ b/www/ios/CameraPopoverHandle.js @@ -33,7 +33,7 @@ var exec = require('cordova/exec'); * - iOS * * @example - * var cameraPopoverHandle = navigator.camera.getPicture(onSuccess, onFail, + * navigator.camera.getPicture(onSuccess, onFail, * { * destinationType: Camera.DestinationType.FILE_URI, * sourceType: Camera.PictureSourceType.PHOTOLIBRARY, @@ -42,13 +42,19 @@ var exec = require('cordova/exec'); * * // Reposition the popover if the orientation changes. * window.onorientationchange = function() { + * var cameraPopoverHandle = new CameraPopoverHandle(); * var cameraPopoverOptions = new CameraPopoverOptions(0, 0, 100, 100, Camera.PopoverArrowDirection.ARROW_ANY); * cameraPopoverHandle.setPosition(cameraPopoverOptions); * } * @module CameraPopoverHandle */ var CameraPopoverHandle = function() { - /** Set the position of the popover. + /** + * Can be used to reposition the image selection dialog, + * for example, when the device orientation changes. + * @memberof CameraPopoverHandle + * @instance + * @method setPosition * @param {module:CameraPopoverOptions} popoverOptions */ this.setPosition = function(popoverOptions) { From 1beeafb6e8b2296d7748d545128686bf8296bbb7 Mon Sep 17 00:00:00 2001 From: Vladimir Kotikov Date: Tue, 23 Aug 2016 16:14:59 +0300 Subject: [PATCH 36/40] CB-10067 Update PictureSourceType JSDoc to reflect README update --- README.md | 4 ++-- www/CameraConstants.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 4294bd2..fef0049 100644 --- a/README.md +++ b/README.md @@ -303,9 +303,9 @@ change, cropping, etc.) due to implementation specific. | Name | Type | Default | Description | | --- | --- | --- | --- | -| PHOTOLIBRARY | number | 0 | Choose image from picture library (same as SAVEDPHOTOALBUM for Android) | +| PHOTOLIBRARY | number | 0 | Choose image from the device's photo library (same as SAVEDPHOTOALBUM for Android) | | CAMERA | number | 1 | Take picture from camera | -| SAVEDPHOTOALBUM | number | 2 | Choose image from picture library (same as PHOTOLIBRARY for Android) | +| SAVEDPHOTOALBUM | number | 2 | Choose image only from the device's Camera Roll album (same as PHOTOLIBRARY for Android) | diff --git a/www/CameraConstants.js b/www/CameraConstants.js index c13dba3..9974c15 100644 --- a/www/CameraConstants.js +++ b/www/CameraConstants.js @@ -71,11 +71,11 @@ module.exports = { * @enum {number} */ PictureSourceType:{ - /** Choose image from picture library (same as SAVEDPHOTOALBUM for Android) */ + /** Choose image from the device's photo library (same as SAVEDPHOTOALBUM for Android) */ PHOTOLIBRARY : 0, /** Take picture from camera */ CAMERA : 1, - /** Choose image from picture library (same as PHOTOLIBRARY for Android) */ + /** Choose image only from the device's Camera Roll album (same as PHOTOLIBRARY for Android) */ SAVEDPHOTOALBUM : 2 }, /** From b89645c7498d6002d1f6cdf2bdf3a93f56310165 Mon Sep 17 00:00:00 2001 From: Vladimir Kotikov Date: Tue, 23 Aug 2016 16:15:38 +0300 Subject: [PATCH 37/40] CB-11295 Add WP8.1 quirk when choosing image from photoalbum --- README.md | 10 ++++++++++ jsdoc2md/TEMPLATE.md | 10 ++++++++++ 2 files changed, 20 insertions(+) diff --git a/README.md b/README.md index fef0049..a15680c 100644 --- a/README.md +++ b/README.md @@ -472,6 +472,16 @@ displays: Invoking the native camera application while the device is connected via Zune does not work, and triggers an error callback. +#### Windows quirks + +On Windows Phone 8.1 using `SAVEDPHOTOALBUM` or `PHOTOLIBRARY` as a source type causes application to suspend until file picker returns the selected image and +then restore with start page as defined in app's `config.xml`. In case when `camera.getPicture` was called from different page, this will lead to reloading +start page from scratch and success and error callbacks will never be called. + +To avoid this we suggest using SPA pattern or call `camera.getPicture` only from your app's start page. + +More information about Windows Phone 8.1 picker APIs is here: [How to continue your Windows Phone app after calling a file picker](https://msdn.microsoft.com/en-us/library/windows/apps/dn720490.aspx) + #### Tizen Quirks Tizen only supports a `destinationType` of diff --git a/jsdoc2md/TEMPLATE.md b/jsdoc2md/TEMPLATE.md index 2e53a89..65cdbbc 100644 --- a/jsdoc2md/TEMPLATE.md +++ b/jsdoc2md/TEMPLATE.md @@ -122,6 +122,16 @@ displays: Invoking the native camera application while the device is connected via Zune does not work, and triggers an error callback. +#### Windows quirks + +On Windows Phone 8.1 using `SAVEDPHOTOALBUM` or `PHOTOLIBRARY` as a source type causes application to suspend until file picker returns the selected image and +then restore with start page as defined in app's `config.xml`. In case when `camera.getPicture` was called from different page, this will lead to reloading +start page from scratch and success and error callbacks will never be called. + +To avoid this we suggest using SPA pattern or call `camera.getPicture` only from your app's start page. + +More information about Windows Phone 8.1 picker APIs is here: [How to continue your Windows Phone app after calling a file picker](https://msdn.microsoft.com/en-us/library/windows/apps/dn720490.aspx) + #### Tizen Quirks Tizen only supports a `destinationType` of From c98607c613602a0ae2d0f1004af27732227244ee Mon Sep 17 00:00:00 2001 From: Tyler Pham Date: Sun, 21 Aug 2016 17:50:35 -0400 Subject: [PATCH 38/40] CB-11714: (windows) added more explicit content-type when converting to target data on canvas This closes #232 --- src/windows/CameraProxy.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/windows/CameraProxy.js b/src/windows/CameraProxy.js index 0862f35..eb10cd2 100644 --- a/src/windows/CameraProxy.js +++ b/src/windows/CameraProxy.js @@ -79,10 +79,14 @@ var HIGHEST_POSSIBLE_Z_INDEX = 2147483647; // Resize method function resizeImage(successCallback, errorCallback, file, targetWidth, targetHeight, encodingType) { var tempPhotoFileName = ""; + var targetContentType = ""; + if (encodingType == Camera.EncodingType.PNG) { tempPhotoFileName = "camera_cordova_temp_return.png"; + targetContentType = "image/png"; } else { tempPhotoFileName = "camera_cordova_temp_return.jpg"; + targetContentType = "image/jpeg"; } var storageFolder = getAppData().localFolder; @@ -108,7 +112,7 @@ function resizeImage(successCallback, errorCallback, file, targetWidth, targetHe canvas.getContext("2d").drawImage(this, 0, 0, imageWidth, imageHeight); - var fileContent = canvas.toDataURL(file.contentType).split(',')[1]; + var fileContent = canvas.toDataURL(targetContentType).split(',')[1]; var storageFolder = getAppData().localFolder; @@ -745,7 +749,7 @@ function takePictureFromCameraWindows(successCallback, errorCallback, args) { cameraCaptureUI.photoSettings.maxResolution = maxRes; var cameraPicture; - + // define focus handler for windows phone 10.0 var savePhotoOnFocus = function () { window.removeEventListener("focus", savePhotoOnFocus); @@ -760,7 +764,7 @@ function takePictureFromCameraWindows(successCallback, errorCallback, args) { }; // if windows phone 10, add and delete focus eventHandler to capture the focus back from cameraUI to app - if (navigator.appVersion.indexOf('Windows Phone 10.0') >= 0) { + if (navigator.appVersion.indexOf('Windows Phone 10.0') >= 0) { window.addEventListener("focus", savePhotoOnFocus); } From a3af38ad5b3d826216f2538bd9aad5d217df4a12 Mon Sep 17 00:00:00 2001 From: mhartington Date: Thu, 11 Aug 2016 15:22:39 -0400 Subject: [PATCH 39/40] CB-11661: (ios) Add mandatory iOS 10 privacy description --- README.md | 54 ++++++++++++++++++++++++++++++++---------------------- plugin.xml | 5 +++++ 2 files changed, 37 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index a15680c..9f37f9a 100644 --- a/README.md +++ b/README.md @@ -50,6 +50,16 @@ It is also possible to install via repo url directly ( unstable ) cordova plugin add https://github.com/apache/cordova-plugin-camera.git +### iOS Quirks + +Since iOS 10 it's mandatory to add a `NSCameraUsageDescription` entry in the info.plist. + +`NSCameraUsageDescription` describes the reason that the app accesses the user’s camera. When the system prompts the user to allow access, this string is displayed as part of the dialog box. To add this entry you can pass the variable `CAMERA_USAGE_DESCRIPTION` on plugin install. + +Example: +`cordova plugin add cordova-plugin-camera --variable CAMERA_USAGE_DESCRIPTION="your usage message"` + +If you don't pass the variable, the plugin will add an empty string as value. ## How to Contribute @@ -68,8 +78,8 @@ In order for your changes to be accepted, you need to sign and submit an Apache ## This documentation is generated by a tool -:warning: Run `npm install` in the plugin repo to enable automatic docs generation if you plan to send a PR. -[jsdoc-to-markdown](https://www.npmjs.com/package/jsdoc-to-markdown) is used to generate the docs. +:warning: Run `npm install` in the plugin repo to enable automatic docs generation if you plan to send a PR. +[jsdoc-to-markdown](https://www.npmjs.com/package/jsdoc-to-markdown) is used to generate the docs. Documentation consists of template and API docs produced from the plugin JS code and should be regenerated before each commit (done automatically via [husky](https://github.com/typicode/husky), running `npm run gen-docs` script as a `precommit` hook - see `package.json` for details). @@ -152,7 +162,7 @@ __Supported Platforms__ More examples [here](#camera-getPicture-examples). Quirks [here](#camera-getPicture-quirks). -**Kind**: static method of [camera](#module_camera) +**Kind**: static method of [camera](#module_camera) | Param | Type | Description | | --- | --- | --- | @@ -160,7 +170,7 @@ More examples [here](#camera-getPicture-examples). Quirks [here](#camera-getPict | errorCallback | [onError](#module_camera.onError) | | | options | [CameraOptions](#module_camera.CameraOptions) | CameraOptions | -**Example** +**Example** ```js navigator.camera.getPicture(cameraSuccess, cameraError, cameraOptions); ``` @@ -176,8 +186,8 @@ __Supported Platforms__ - iOS -**Kind**: static method of [camera](#module_camera) -**Example** +**Kind**: static method of [camera](#module_camera) +**Example** ```js navigator.camera.cleanup(onSuccess, onFail); @@ -194,7 +204,7 @@ function onFail(message) { ### camera.onError : function Callback function that provides an error message. -**Kind**: static typedef of [camera](#module_camera) +**Kind**: static typedef of [camera](#module_camera) | Param | Type | Description | | --- | --- | --- | @@ -205,13 +215,13 @@ Callback function that provides an error message. ### camera.onSuccess : function Callback function that provides the image data. -**Kind**: static typedef of [camera](#module_camera) +**Kind**: static typedef of [camera](#module_camera) | Param | Type | Description | | --- | --- | --- | | imageData | string | Base64 encoding of the image data, _or_ the image file URI, depending on [`cameraOptions`](#module_camera.CameraOptions) in effect. | -**Example** +**Example** ```js // Show image // @@ -226,7 +236,7 @@ function cameraCallback(imageData) { Optional parameters to customize the camera settings. * [Quirks](#CameraOptions-quirks) -**Kind**: static typedef of [camera](#module_camera) +**Kind**: static typedef of [camera](#module_camera) **Properties** | Name | Type | Default | Description | @@ -258,7 +268,7 @@ _Note:_ On iOS passing `DestinationType.NATIVE_URI` along with disable any image modifications (resize, quality change, cropping, etc.) due to implementation specific. -**Kind**: static enum property of [Camera](#module_Camera) +**Kind**: static enum property of [Camera](#module_Camera) **Properties** | Name | Type | Default | Description | @@ -270,7 +280,7 @@ to implementation specific. ### Camera.EncodingType : enum -**Kind**: static enum property of [Camera](#module_Camera) +**Kind**: static enum property of [Camera](#module_Camera) **Properties** | Name | Type | Default | Description | @@ -281,7 +291,7 @@ to implementation specific. ### Camera.MediaType : enum -**Kind**: static enum property of [Camera](#module_Camera) +**Kind**: static enum property of [Camera](#module_Camera) **Properties** | Name | Type | Default | Description | @@ -298,7 +308,7 @@ _Note:_ On iOS passing `PictureSourceType.PHOTOLIBRARY` or `PictureSourceType.SA along with `DestinationType.NATIVE_URI` will disable any image modifications (resize, quality change, cropping, etc.) due to implementation specific. -**Kind**: static enum property of [Camera](#module_Camera) +**Kind**: static enum property of [Camera](#module_Camera) **Properties** | Name | Type | Default | Description | @@ -312,21 +322,21 @@ change, cropping, etc.) due to implementation specific. ### Camera.PopoverArrowDirection : enum Matches iOS UIPopoverArrowDirection constants to specify arrow location on popover. -**Kind**: static enum property of [Camera](#module_Camera) +**Kind**: static enum property of [Camera](#module_Camera) **Properties** | Name | Type | Default | | --- | --- | --- | -| ARROW_UP | number | 1 | -| ARROW_DOWN | number | 2 | -| ARROW_LEFT | number | 4 | -| ARROW_RIGHT | number | 8 | -| ARROW_ANY | number | 15 | +| ARROW_UP | number | 1 | +| ARROW_DOWN | number | 2 | +| ARROW_LEFT | number | 4 | +| ARROW_RIGHT | number | 8 | +| ARROW_ANY | number | 15 | ### Camera.Direction : enum -**Kind**: static enum property of [Camera](#module_Camera) +**Kind**: static enum property of [Camera](#module_Camera) **Properties** | Name | Type | Default | Description | @@ -367,7 +377,7 @@ __Supported Platforms__ - iOS -**Example** +**Example** ```js navigator.camera.getPicture(onSuccess, onFail, { diff --git a/plugin.xml b/plugin.xml index 99769ab..0911fb8 100644 --- a/plugin.xml +++ b/plugin.xml @@ -150,6 +150,11 @@ + + + $CAMERA_USAGE_DESCRIPTION + + From fa58e83fca7517d120aedddb5e23ae9b9bcc7888 Mon Sep 17 00:00:00 2001 From: Steve Gill Date: Thu, 25 Aug 2016 16:20:16 -0700 Subject: [PATCH 40/40] close #229 --- README.md | 54 ++++++++++++++++++++++-------------------------------- 1 file changed, 22 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index 9f37f9a..a15680c 100644 --- a/README.md +++ b/README.md @@ -50,16 +50,6 @@ It is also possible to install via repo url directly ( unstable ) cordova plugin add https://github.com/apache/cordova-plugin-camera.git -### iOS Quirks - -Since iOS 10 it's mandatory to add a `NSCameraUsageDescription` entry in the info.plist. - -`NSCameraUsageDescription` describes the reason that the app accesses the user’s camera. When the system prompts the user to allow access, this string is displayed as part of the dialog box. To add this entry you can pass the variable `CAMERA_USAGE_DESCRIPTION` on plugin install. - -Example: -`cordova plugin add cordova-plugin-camera --variable CAMERA_USAGE_DESCRIPTION="your usage message"` - -If you don't pass the variable, the plugin will add an empty string as value. ## How to Contribute @@ -78,8 +68,8 @@ In order for your changes to be accepted, you need to sign and submit an Apache ## This documentation is generated by a tool -:warning: Run `npm install` in the plugin repo to enable automatic docs generation if you plan to send a PR. -[jsdoc-to-markdown](https://www.npmjs.com/package/jsdoc-to-markdown) is used to generate the docs. +:warning: Run `npm install` in the plugin repo to enable automatic docs generation if you plan to send a PR. +[jsdoc-to-markdown](https://www.npmjs.com/package/jsdoc-to-markdown) is used to generate the docs. Documentation consists of template and API docs produced from the plugin JS code and should be regenerated before each commit (done automatically via [husky](https://github.com/typicode/husky), running `npm run gen-docs` script as a `precommit` hook - see `package.json` for details). @@ -162,7 +152,7 @@ __Supported Platforms__ More examples [here](#camera-getPicture-examples). Quirks [here](#camera-getPicture-quirks). -**Kind**: static method of [camera](#module_camera) +**Kind**: static method of [camera](#module_camera) | Param | Type | Description | | --- | --- | --- | @@ -170,7 +160,7 @@ More examples [here](#camera-getPicture-examples). Quirks [here](#camera-getPict | errorCallback | [onError](#module_camera.onError) | | | options | [CameraOptions](#module_camera.CameraOptions) | CameraOptions | -**Example** +**Example** ```js navigator.camera.getPicture(cameraSuccess, cameraError, cameraOptions); ``` @@ -186,8 +176,8 @@ __Supported Platforms__ - iOS -**Kind**: static method of [camera](#module_camera) -**Example** +**Kind**: static method of [camera](#module_camera) +**Example** ```js navigator.camera.cleanup(onSuccess, onFail); @@ -204,7 +194,7 @@ function onFail(message) { ### camera.onError : function Callback function that provides an error message. -**Kind**: static typedef of [camera](#module_camera) +**Kind**: static typedef of [camera](#module_camera) | Param | Type | Description | | --- | --- | --- | @@ -215,13 +205,13 @@ Callback function that provides an error message. ### camera.onSuccess : function Callback function that provides the image data. -**Kind**: static typedef of [camera](#module_camera) +**Kind**: static typedef of [camera](#module_camera) | Param | Type | Description | | --- | --- | --- | | imageData | string | Base64 encoding of the image data, _or_ the image file URI, depending on [`cameraOptions`](#module_camera.CameraOptions) in effect. | -**Example** +**Example** ```js // Show image // @@ -236,7 +226,7 @@ function cameraCallback(imageData) { Optional parameters to customize the camera settings. * [Quirks](#CameraOptions-quirks) -**Kind**: static typedef of [camera](#module_camera) +**Kind**: static typedef of [camera](#module_camera) **Properties** | Name | Type | Default | Description | @@ -268,7 +258,7 @@ _Note:_ On iOS passing `DestinationType.NATIVE_URI` along with disable any image modifications (resize, quality change, cropping, etc.) due to implementation specific. -**Kind**: static enum property of [Camera](#module_Camera) +**Kind**: static enum property of [Camera](#module_Camera) **Properties** | Name | Type | Default | Description | @@ -280,7 +270,7 @@ to implementation specific. ### Camera.EncodingType : enum -**Kind**: static enum property of [Camera](#module_Camera) +**Kind**: static enum property of [Camera](#module_Camera) **Properties** | Name | Type | Default | Description | @@ -291,7 +281,7 @@ to implementation specific. ### Camera.MediaType : enum -**Kind**: static enum property of [Camera](#module_Camera) +**Kind**: static enum property of [Camera](#module_Camera) **Properties** | Name | Type | Default | Description | @@ -308,7 +298,7 @@ _Note:_ On iOS passing `PictureSourceType.PHOTOLIBRARY` or `PictureSourceType.SA along with `DestinationType.NATIVE_URI` will disable any image modifications (resize, quality change, cropping, etc.) due to implementation specific. -**Kind**: static enum property of [Camera](#module_Camera) +**Kind**: static enum property of [Camera](#module_Camera) **Properties** | Name | Type | Default | Description | @@ -322,21 +312,21 @@ change, cropping, etc.) due to implementation specific. ### Camera.PopoverArrowDirection : enum Matches iOS UIPopoverArrowDirection constants to specify arrow location on popover. -**Kind**: static enum property of [Camera](#module_Camera) +**Kind**: static enum property of [Camera](#module_Camera) **Properties** | Name | Type | Default | | --- | --- | --- | -| ARROW_UP | number | 1 | -| ARROW_DOWN | number | 2 | -| ARROW_LEFT | number | 4 | -| ARROW_RIGHT | number | 8 | -| ARROW_ANY | number | 15 | +| ARROW_UP | number | 1 | +| ARROW_DOWN | number | 2 | +| ARROW_LEFT | number | 4 | +| ARROW_RIGHT | number | 8 | +| ARROW_ANY | number | 15 | ### Camera.Direction : enum -**Kind**: static enum property of [Camera](#module_Camera) +**Kind**: static enum property of [Camera](#module_Camera) **Properties** | Name | Type | Default | Description | @@ -377,7 +367,7 @@ __Supported Platforms__ - iOS -**Example** +**Example** ```js navigator.camera.getPicture(onSuccess, onFail, {