diff --git a/bin/templates/cordova/lib/emulator.js b/bin/templates/cordova/lib/emulator.js index fbbe520a..6828176b 100644 --- a/bin/templates/cordova/lib/emulator.js +++ b/bin/templates/cordova/lib/emulator.js @@ -21,6 +21,7 @@ /* jshint sub:true */ +var android_versions = require('android-versions'); var retry = require('./retry'); var build = require('./build'); var path = require('path'); @@ -169,15 +170,29 @@ module.exports.list_images_using_android = function () { } */ module.exports.list_images = function () { - if (forgivingWhichSync('avdmanager')) { - return module.exports.list_images_using_avdmanager(); - } else if (forgivingWhichSync('android')) { - return module.exports.list_images_using_android(); - } else { - return Q().then(function () { - throw new CordovaError('Could not find either `android` or `avdmanager` on your $PATH! Are you sure the Android SDK is installed and available?'); + return Q.fcall(function () { + if (forgivingWhichSync('avdmanager')) { + return module.exports.list_images_using_avdmanager(); + } else if (forgivingWhichSync('android')) { + return module.exports.list_images_using_android(); + } else { + return Q().then(function () { + throw new CordovaError('Could not find either `android` or `avdmanager` on your $PATH! Are you sure the Android SDK is installed and available?'); + }); + } + }).then(function (avds) { + // In case we're missing the Android OS version string from the target description, add it. + return avds.map(function (avd) { + if (avd.target && avd.target.indexOf('Android API') > -1 && avd.target.indexOf('API level') < 0) { + var api_level = avd.target.match(/\d+/); + if (api_level) { + var level = android_versions.get(api_level); + avd.target = 'Android ' + level.semver + ' (API level ' + api_level + ')'; + } + } + return avd; }); - } + }); }; /** diff --git a/package.json b/package.json index 1b3ff4e7..cf06c5b3 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,7 @@ "author": "Apache Software Foundation", "license": "Apache-2.0", "dependencies": { + "android-versions": "^1.2.0", "cordova-common": "^2.1.0", "elementtree": "0.1.6", "nopt": "^3.0.1", diff --git a/spec/unit/emulator.spec.js b/spec/unit/emulator.spec.js index b6db7614..551ab6d0 100644 --- a/spec/unit/emulator.spec.js +++ b/spec/unit/emulator.spec.js @@ -75,7 +75,7 @@ describe('emulator', function () { return cmd; }); }); - it('should try to parse AVD information using `avdmanager` first', function () { + it('should try to parse AVD information using `avdmanager` first', function (done) { spyOn(shelljs, 'which').and.callFake(function (cmd) { if (cmd === 'avdmanager') { return true; @@ -83,11 +83,18 @@ describe('emulator', function () { return false; } }); - var avdmanager_spy = spyOn(emu, 'list_images_using_avdmanager').and.returnValue({catch: function () {}}); - emu.list_images(); - expect(avdmanager_spy).toHaveBeenCalled(); + var deferred = Q.defer(); + var avdmanager_spy = spyOn(emu, 'list_images_using_avdmanager').and.returnValue(deferred.promise); + deferred.resolve([]); + emu.list_images().then(function () { + expect(avdmanager_spy).toHaveBeenCalled(); + }).fail(function (err) { + expect(err).toBeUndefined(); + }).fin(function () { + done(); + }); }); - it('should delegate to `android` if `avdmanager` cant be found and `android` can', function () { + it('should delegate to `android` if `avdmanager` cant be found and `android` can', function (done) { spyOn(shelljs, 'which').and.callFake(function (cmd) { if (cmd === 'avdmanager') { return false; @@ -95,9 +102,50 @@ describe('emulator', function () { return true; } }); - var android_spy = spyOn(emu, 'list_images_using_android'); - emu.list_images(); - expect(android_spy).toHaveBeenCalled(); + var deferred = Q.defer(); + var android_spy = spyOn(emu, 'list_images_using_android').and.returnValue(deferred.promise); + deferred.resolve([]); + emu.list_images().then(function () { + expect(android_spy).toHaveBeenCalled(); + }).fail(function (err) { + expect(err).toBeUndefined(); + }).fin(function () { + done(); + }); + }); + it('should correct api level information and fill in the blanks about api level if exists', function (done) { + spyOn(shelljs, 'which').and.callFake(function (cmd) { + if (cmd === 'avdmanager') { + return true; + } else { + return false; + } + }); + var deferred = Q.defer(); + spyOn(emu, 'list_images_using_avdmanager').and.returnValue(deferred.promise); + deferred.resolve([ + { + name: 'Pixel_7.0', + device: 'pixel (Google)', + path: '/Users/maj/.android/avd/Pixel_7.0.avd', + abi: 'google_apis/x86_64', + target: 'Android 7.0 (API level 24)' + }, { + name: 'Pixel_8.0', + device: 'pixel (Google)', + path: '/Users/maj/.android/avd/Pixel_8.0.avd', + abi: 'google_apis/x86', + target: 'Android API 26' + } + ]); + emu.list_images().then(function (avds) { + expect(avds[1].target).toContain('Android 8'); + expect(avds[1].target).toContain('API level 26'); + }).fail(function (err) { + expect(err).toBeUndefined(); + }).fin(function () { + done(); + }); }); it('should throw an error if neither `avdmanager` nor `android` are able to be found', function (done) { spyOn(shelljs, 'which').and.returnValue(false);