diff --git a/bin/templates/cordova/lib/prepare.js b/bin/templates/cordova/lib/prepare.js
index ac63f8a6..9dc85ff3 100644
--- a/bin/templates/cordova/lib/prepare.js
+++ b/bin/templates/cordova/lib/prepare.js
@@ -265,6 +265,14 @@ function getImageResourcePath (resourcesDir, type, density, name, sourceName) {
return resourcePath;
}
+function getAdaptiveImageResourcePath (resourcesDir, type, density, name, sourceName) {
+ if (/\.9\.png$/.test(sourceName)) {
+ name = name.replace(/\.png$/, '.9.png');
+ }
+ var resourcePath = path.join(resourcesDir, (density ? type + '-' + density + '-v26' : type), name);
+ return resourcePath;
+}
+
function updateSplashes (cordovaProject, platformResourcesDir) {
var resources = cordovaProject.projectConfig.getSplashScreens('android');
@@ -314,20 +322,197 @@ function cleanSplashes (projectRoot, projectConfig, platformResourcesDir) {
}
function updateIcons (cordovaProject, platformResourcesDir) {
- var icons = cordovaProject.projectConfig.getIcons('android');
+ let icons = cordovaProject.projectConfig.getIcons('android');
- // if there are icon elements in config.xml
+ // Skip if there are no app defined icons in config.xml
if (icons.length === 0) {
events.emit('verbose', 'This app does not have launcher icons defined');
return;
}
- var resourceMap = mapImageResources(cordovaProject.root, platformResourcesDir, 'mipmap', 'icon.png');
+ // 1. loop icons determin if there is an error in the setup.
+ // 2. during initial loop, also setup for legacy support.
+ let errorMissingAttributes = [];
+ let errorLegacyIconNeeded = [];
+ let hasAdaptive = false;
+ icons.forEach((icon, key) => {
+ if (
+ (icon.background && !icon.foreground)
+ || (!icon.background && icon.foreground)
+ || (!icon.background && !icon.foreground && !icon.src)
+ ) {
+ errorMissingAttributes.push(icon.density ? icon.density : 'size=' + (icon.height || icon.width));
+ }
- var android_icons = {};
- var default_icon;
+ if (icon.foreground) {
+ hasAdaptive = true;
+
+ if (
+ !icon.src
+ && (
+ icon.foreground.startsWith('@color')
+ || path.extname(path.basename(icon.foreground)) === '.xml'
+ )
+ ) {
+ errorLegacyIconNeeded.push(icon.density ? icon.density : 'size=' + (icon.height || icon.width));
+ } else if (!icon.src) {
+ icons[key].src = icon.foreground;
+ }
+ }
+ });
+
+ let errorMessage = [];
+ if (errorMissingAttributes.length > 0) {
+ errorMessage.push('One of the following attributes are set but missing the other for the density type: ' + errorMissingAttributes.join(', ') + '. Please ensure that all require attributes are defined.');
+ }
+
+ if (errorLegacyIconNeeded.length > 0) {
+ errorMessage.push('For the following icons with the density of: ' + errorLegacyIconNeeded.join(', ') + ', adaptive foreground with a defined color or vector can not be used as a standard fallback icon for older Android devices. To support older Android environments, please provide a value for the src attribute.');
+ }
+
+ if (errorMessage.length > 0) {
+ throw new CordovaError(errorMessage.join(' '));
+ }
+
+ let resourceMap = Object.assign(
+ {},
+ mapImageResources(cordovaProject.root, platformResourcesDir, 'mipmap', 'ic_launcher.png'),
+ mapImageResources(cordovaProject.root, platformResourcesDir, 'mipmap', 'ic_launcher_foreground.png'),
+ mapImageResources(cordovaProject.root, platformResourcesDir, 'mipmap', 'ic_launcher_background.png'),
+ mapImageResources(cordovaProject.root, platformResourcesDir, 'mipmap', 'ic_launcher_foreground.xml'),
+ mapImageResources(cordovaProject.root, platformResourcesDir, 'mipmap', 'ic_launcher_background.xml'),
+ mapImageResources(cordovaProject.root, platformResourcesDir, 'mipmap', 'ic_launcher.xml')
+ );
+
+ let preparedIcons = prepareIcons(icons);
+
+ if (hasAdaptive) {
+ resourceMap = updateIconResourceForAdaptive(preparedIcons, resourceMap, platformResourcesDir);
+ }
+
+ resourceMap = updateIconResourceForLegacy(preparedIcons, resourceMap, platformResourcesDir);
+
+ events.emit('verbose', 'Updating icons at ' + platformResourcesDir);
+ FileUpdater.updatePaths(resourceMap, { rootDir: cordovaProject.root }, logFileOp);
+}
+
+function updateIconResourceForAdaptive (preparedIcons, resourceMap, platformResourcesDir) {
+ let android_icons = preparedIcons.android_icons;
+ let default_icon = preparedIcons.default_icon;
+
+ // The source paths for icons and splashes are relative to
+ // project's config.xml location, so we use it as base path.
+ let background;
+ let foreground;
+ let targetPathBackground;
+ let targetPathForeground;
+
+ for (let density in android_icons) {
+ let backgroundVal = '@mipmap/ic_launcher_background';
+ let foregroundVal = '@mipmap/ic_launcher_foreground';
+
+ background = android_icons[density].background;
+ foreground = android_icons[density].foreground;
+
+ if (background.startsWith('@color')) {
+ // Colors Use Case
+ backgroundVal = background; // Example: @color/background_foobar_1
+ } else if (path.extname(path.basename(background)) === '.xml') {
+ // Vector Use Case
+ targetPathBackground = getAdaptiveImageResourcePath(platformResourcesDir, 'mipmap', density, 'ic_launcher_background.xml', path.basename(android_icons[density].background));
+ resourceMap[targetPathBackground] = android_icons[density].background;
+ } else if (path.extname(path.basename(background)) === '.png') {
+ // Images Use Case
+ targetPathBackground = getAdaptiveImageResourcePath(platformResourcesDir, 'mipmap', density, 'ic_launcher_background.png', path.basename(android_icons[density].background));
+ resourceMap[targetPathBackground] = android_icons[density].background;
+ }
+
+ if (foreground.startsWith('@color')) {
+ // Colors Use Case
+ foregroundVal = foreground;
+ } else if (path.extname(path.basename(foreground)) === '.xml') {
+ // Vector Use Case
+ targetPathForeground = getAdaptiveImageResourcePath(platformResourcesDir, 'mipmap', density, 'ic_launcher_foreground.xml', path.basename(android_icons[density].foreground));
+ resourceMap[targetPathForeground] = android_icons[density].foreground;
+ } else if (path.extname(path.basename(foreground)) === '.png') {
+ // Images Use Case
+ targetPathForeground = getAdaptiveImageResourcePath(platformResourcesDir, 'mipmap', density, 'ic_launcher_foreground.png', path.basename(android_icons[density].foreground));
+ resourceMap[targetPathForeground] = android_icons[density].foreground;
+ }
+
+ // create an XML for DPI and set color
+ const icLauncherTemplate = `
+
+
+
+`;
+
+ let launcherXmlPath = path.join(platformResourcesDir, 'mipmap-' + density + '-v26', 'ic_launcher.xml');
+
+ // Remove the XML from the resourceMap so the file does not get removed.
+ delete resourceMap[launcherXmlPath];
+
+ fs.writeFileSync(path.resolve(launcherXmlPath), icLauncherTemplate);
+ }
+
+ // There's no "default" drawable, so assume default == mdpi.
+ if (default_icon && !android_icons.mdpi) {
+ let defaultTargetPathBackground;
+ let defaultTargetPathForeground;
+
+ if (background.startsWith('@color')) {
+ // Colors Use Case
+ targetPathBackground = default_icon.background;
+ } else if (path.extname(path.basename(background)) === '.xml') {
+ // Vector Use Case
+ defaultTargetPathBackground = getAdaptiveImageResourcePath(platformResourcesDir, 'mipmap', 'mdpi', 'ic_launcher_background.xml', path.basename(default_icon.background));
+ resourceMap[defaultTargetPathBackground] = default_icon.background;
+ } else if (path.extname(path.basename(background)) === '.png') {
+ // Images Use Case
+ defaultTargetPathBackground = getAdaptiveImageResourcePath(platformResourcesDir, 'mipmap', 'mdpi', 'ic_launcher_background.png', path.basename(default_icon.background));
+ resourceMap[defaultTargetPathBackground] = default_icon.background;
+ }
+
+ if (foreground.startsWith('@color')) {
+ // Colors Use Case
+ targetPathForeground = default_icon.foreground;
+ } else if (path.extname(path.basename(foreground)) === '.xml') {
+ // Vector Use Case
+ defaultTargetPathForeground = getAdaptiveImageResourcePath(platformResourcesDir, 'mipmap', 'mdpi', 'ic_launcher_foreground.xml', path.basename(default_icon.foreground));
+ resourceMap[defaultTargetPathForeground] = default_icon.foreground;
+ } else if (path.extname(path.basename(foreground)) === '.png') {
+ // Images Use Case
+ defaultTargetPathForeground = getAdaptiveImageResourcePath(platformResourcesDir, 'mipmap', 'mdpi', 'ic_launcher_foreground.png', path.basename(default_icon.foreground));
+ resourceMap[defaultTargetPathForeground] = default_icon.foreground;
+ }
+ }
+
+ return resourceMap;
+}
+
+function updateIconResourceForLegacy (preparedIcons, resourceMap, platformResourcesDir) {
+ let android_icons = preparedIcons.android_icons;
+ let default_icon = preparedIcons.default_icon;
+
+ // The source paths for icons and splashes are relative to
+ // project's config.xml location, so we use it as base path.
+ for (var density in android_icons) {
+ var targetPath = getImageResourcePath(platformResourcesDir, 'mipmap', density, 'ic_launcher.png', path.basename(android_icons[density].src));
+ resourceMap[targetPath] = android_icons[density].src;
+ }
+
+ // There's no "default" drawable, so assume default == mdpi.
+ if (default_icon && !android_icons.mdpi) {
+ var defaultTargetPath = getImageResourcePath(platformResourcesDir, 'mipmap', 'mdpi', 'ic_launcher.png', path.basename(default_icon.src));
+ resourceMap[defaultTargetPath] = default_icon.src;
+ }
+
+ return resourceMap;
+}
+
+function prepareIcons (icons) {
// http://developer.android.com/design/style/iconography.html
- var sizeToDensityMap = {
+ const SIZE_TO_DENSITY_MAP = {
36: 'ldpi',
48: 'mdpi',
72: 'hdpi',
@@ -335,11 +520,15 @@ function updateIcons (cordovaProject, platformResourcesDir) {
144: 'xxhdpi',
192: 'xxxhdpi'
};
+
+ let android_icons = {};
+ let default_icon;
+
// find the best matching icon for a given density or size
// @output android_icons
var parseIcon = function (icon, icon_size) {
// do I have a platform icon for that density already
- var density = icon.density || sizeToDensityMap[icon_size];
+ var density = icon.density || SIZE_TO_DENSITY_MAP[icon_size];
if (!density) {
// invalid icon defition ( or unsupported size)
return;
@@ -355,12 +544,34 @@ function updateIcons (cordovaProject, platformResourcesDir) {
for (var i = 0; i < icons.length; i++) {
var icon = icons[i];
var size = icon.width;
+
if (!size) {
size = icon.height;
}
+
if (!size && !icon.density) {
if (default_icon) {
- events.emit('verbose', 'Found extra default icon: ' + icon.src + ' (ignoring in favor of ' + default_icon.src + ')');
+ let found = {};
+ let favor = {};
+
+ // populating found icon.
+ if (icon.background && icon.foreground) {
+ found.background = icon.background;
+ found.foreground = icon.foreground;
+ }
+ if (icon.src) {
+ found.src = icon.src;
+ }
+
+ if (default_icon.background && default_icon.foreground) {
+ favor.background = default_icon.background;
+ favor.foreground = default_icon.foreground;
+ }
+ if (default_icon.src) {
+ favor.src = default_icon.src;
+ }
+
+ events.emit('verbose', 'Found extra default icon: ' + JSON.stringify(found) + ' and ignoring in favor of ' + JSON.stringify(favor) + '.');
} else {
default_icon = icon;
}
@@ -369,36 +580,35 @@ function updateIcons (cordovaProject, platformResourcesDir) {
}
}
- // The source paths for icons and splashes are relative to
- // project's config.xml location, so we use it as base path.
- for (var density in android_icons) {
- var targetPath = getImageResourcePath(
- platformResourcesDir, 'mipmap', density, 'icon.png', path.basename(android_icons[density].src));
- resourceMap[targetPath] = android_icons[density].src;
- }
-
- // There's no "default" drawable, so assume default == mdpi.
- if (default_icon && !android_icons.mdpi) {
- var defaultTargetPath = getImageResourcePath(
- platformResourcesDir, 'mipmap', 'mdpi', 'icon.png', path.basename(default_icon.src));
- resourceMap[defaultTargetPath] = default_icon.src;
- }
-
- events.emit('verbose', 'Updating icons at ' + platformResourcesDir);
- FileUpdater.updatePaths(
- resourceMap, { rootDir: cordovaProject.root }, logFileOp);
+ return {
+ android_icons: android_icons,
+ default_icon: default_icon
+ };
}
function cleanIcons (projectRoot, projectConfig, platformResourcesDir) {
var icons = projectConfig.getIcons('android');
- if (icons.length > 0) {
- var resourceMap = mapImageResources(projectRoot, platformResourcesDir, 'mipmap', 'icon.png');
- events.emit('verbose', 'Cleaning icons at ' + platformResourcesDir);
- // No source paths are specified in the map, so updatePaths() will delete the target files.
- FileUpdater.updatePaths(
- resourceMap, { rootDir: projectRoot, all: true }, logFileOp);
+ // Skip if there are no app defined icons in config.xml
+ if (icons.length === 0) {
+ events.emit('verbose', 'This app does not have launcher icons defined');
+ return;
}
+
+ let resourceMap = Object.assign(
+ {},
+ mapImageResources(projectRoot, platformResourcesDir, 'mipmap', 'ic_launcher.png'),
+ mapImageResources(projectRoot, platformResourcesDir, 'mipmap', 'ic_launcher_foreground.png'),
+ mapImageResources(projectRoot, platformResourcesDir, 'mipmap', 'ic_launcher_background.png'),
+ mapImageResources(projectRoot, platformResourcesDir, 'mipmap', 'ic_launcher_foreground.xml'),
+ mapImageResources(projectRoot, platformResourcesDir, 'mipmap', 'ic_launcher_background.xml'),
+ mapImageResources(projectRoot, platformResourcesDir, 'mipmap', 'ic_launcher.xml')
+ );
+
+ events.emit('verbose', 'Cleaning icons at ' + platformResourcesDir);
+
+ // No source paths are specified in the map, so updatePaths() will delete the target files.
+ FileUpdater.updatePaths(resourceMap, { rootDir: projectRoot, all: true }, logFileOp);
}
/**
diff --git a/bin/templates/project/AndroidManifest.xml b/bin/templates/project/AndroidManifest.xml
index e0c53aaa..9c36963a 100644
--- a/bin/templates/project/AndroidManifest.xml
+++ b/bin/templates/project/AndroidManifest.xml
@@ -30,7 +30,7 @@
-
+
+
+
+
\ No newline at end of file
diff --git a/bin/templates/project/res/mipmap-hdpi-v26/ic_launcher_background.png b/bin/templates/project/res/mipmap-hdpi-v26/ic_launcher_background.png
new file mode 100644
index 00000000..021da864
Binary files /dev/null and b/bin/templates/project/res/mipmap-hdpi-v26/ic_launcher_background.png differ
diff --git a/bin/templates/project/res/mipmap-hdpi/icon.png b/bin/templates/project/res/mipmap-hdpi-v26/ic_launcher_foreground.png
similarity index 100%
rename from bin/templates/project/res/mipmap-hdpi/icon.png
rename to bin/templates/project/res/mipmap-hdpi-v26/ic_launcher_foreground.png
diff --git a/bin/templates/project/res/mipmap-hdpi/ic_launcher.png b/bin/templates/project/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 00000000..53842612
Binary files /dev/null and b/bin/templates/project/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/bin/templates/project/res/mipmap-ldpi-v26/ic_launcher.xml b/bin/templates/project/res/mipmap-ldpi-v26/ic_launcher.xml
new file mode 100644
index 00000000..be316184
--- /dev/null
+++ b/bin/templates/project/res/mipmap-ldpi-v26/ic_launcher.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/bin/templates/project/res/mipmap-ldpi-v26/ic_launcher_background.png b/bin/templates/project/res/mipmap-ldpi-v26/ic_launcher_background.png
new file mode 100644
index 00000000..da47a979
Binary files /dev/null and b/bin/templates/project/res/mipmap-ldpi-v26/ic_launcher_background.png differ
diff --git a/bin/templates/project/res/mipmap-ldpi-v26/ic_launcher_foreground.png b/bin/templates/project/res/mipmap-ldpi-v26/ic_launcher_foreground.png
new file mode 100644
index 00000000..203223af
Binary files /dev/null and b/bin/templates/project/res/mipmap-ldpi-v26/ic_launcher_foreground.png differ
diff --git a/bin/templates/project/res/mipmap-ldpi/icon.png b/bin/templates/project/res/mipmap-ldpi/ic_launcher.png
similarity index 100%
rename from bin/templates/project/res/mipmap-ldpi/icon.png
rename to bin/templates/project/res/mipmap-ldpi/ic_launcher.png
diff --git a/bin/templates/project/res/mipmap-mdpi-v26/ic_launcher.xml b/bin/templates/project/res/mipmap-mdpi-v26/ic_launcher.xml
new file mode 100644
index 00000000..be316184
--- /dev/null
+++ b/bin/templates/project/res/mipmap-mdpi-v26/ic_launcher.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/bin/templates/project/res/mipmap-mdpi-v26/ic_launcher_background.png b/bin/templates/project/res/mipmap-mdpi-v26/ic_launcher_background.png
new file mode 100644
index 00000000..74e56e5b
Binary files /dev/null and b/bin/templates/project/res/mipmap-mdpi-v26/ic_launcher_background.png differ
diff --git a/bin/templates/project/res/mipmap-mdpi-v26/ic_launcher_foreground.png b/bin/templates/project/res/mipmap-mdpi-v26/ic_launcher_foreground.png
new file mode 100644
index 00000000..8ca658e7
Binary files /dev/null and b/bin/templates/project/res/mipmap-mdpi-v26/ic_launcher_foreground.png differ
diff --git a/bin/templates/project/res/mipmap-mdpi/icon.png b/bin/templates/project/res/mipmap-mdpi/ic_launcher.png
similarity index 100%
rename from bin/templates/project/res/mipmap-mdpi/icon.png
rename to bin/templates/project/res/mipmap-mdpi/ic_launcher.png
diff --git a/bin/templates/project/res/mipmap-xhdpi-v26/ic_launcher.xml b/bin/templates/project/res/mipmap-xhdpi-v26/ic_launcher.xml
new file mode 100644
index 00000000..be316184
--- /dev/null
+++ b/bin/templates/project/res/mipmap-xhdpi-v26/ic_launcher.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/bin/templates/project/res/mipmap-xhdpi-v26/ic_launcher_background.png b/bin/templates/project/res/mipmap-xhdpi-v26/ic_launcher_background.png
new file mode 100644
index 00000000..d0cb62dd
Binary files /dev/null and b/bin/templates/project/res/mipmap-xhdpi-v26/ic_launcher_background.png differ
diff --git a/bin/templates/project/res/mipmap-xhdpi-v26/ic_launcher_foreground.png b/bin/templates/project/res/mipmap-xhdpi-v26/ic_launcher_foreground.png
new file mode 100644
index 00000000..ae324f2d
Binary files /dev/null and b/bin/templates/project/res/mipmap-xhdpi-v26/ic_launcher_foreground.png differ
diff --git a/bin/templates/project/res/mipmap-xhdpi/icon.png b/bin/templates/project/res/mipmap-xhdpi/ic_launcher.png
similarity index 100%
rename from bin/templates/project/res/mipmap-xhdpi/icon.png
rename to bin/templates/project/res/mipmap-xhdpi/ic_launcher.png
diff --git a/bin/templates/project/res/mipmap-xxhdpi-v26/ic_launcher.xml b/bin/templates/project/res/mipmap-xxhdpi-v26/ic_launcher.xml
new file mode 100644
index 00000000..be316184
--- /dev/null
+++ b/bin/templates/project/res/mipmap-xxhdpi-v26/ic_launcher.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/bin/templates/project/res/mipmap-xxhdpi-v26/ic_launcher_background.png b/bin/templates/project/res/mipmap-xxhdpi-v26/ic_launcher_background.png
new file mode 100644
index 00000000..ec38d403
Binary files /dev/null and b/bin/templates/project/res/mipmap-xxhdpi-v26/ic_launcher_background.png differ
diff --git a/bin/templates/project/res/mipmap-xxhdpi-v26/ic_launcher_foreground.png b/bin/templates/project/res/mipmap-xxhdpi-v26/ic_launcher_foreground.png
new file mode 100644
index 00000000..7983ef45
Binary files /dev/null and b/bin/templates/project/res/mipmap-xxhdpi-v26/ic_launcher_foreground.png differ
diff --git a/bin/templates/project/res/mipmap-xxhdpi/icon.png b/bin/templates/project/res/mipmap-xxhdpi/ic_launcher.png
similarity index 100%
rename from bin/templates/project/res/mipmap-xxhdpi/icon.png
rename to bin/templates/project/res/mipmap-xxhdpi/ic_launcher.png
diff --git a/bin/templates/project/res/mipmap-xxxhdpi-v26/ic_launcher.xml b/bin/templates/project/res/mipmap-xxxhdpi-v26/ic_launcher.xml
new file mode 100644
index 00000000..be316184
--- /dev/null
+++ b/bin/templates/project/res/mipmap-xxxhdpi-v26/ic_launcher.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/bin/templates/project/res/mipmap-xxxhdpi-v26/ic_launcher_background.png b/bin/templates/project/res/mipmap-xxxhdpi-v26/ic_launcher_background.png
new file mode 100644
index 00000000..d652c084
Binary files /dev/null and b/bin/templates/project/res/mipmap-xxxhdpi-v26/ic_launcher_background.png differ
diff --git a/bin/templates/project/res/mipmap-xxxhdpi-v26/ic_launcher_foreground.png b/bin/templates/project/res/mipmap-xxxhdpi-v26/ic_launcher_foreground.png
new file mode 100644
index 00000000..6857bef7
Binary files /dev/null and b/bin/templates/project/res/mipmap-xxxhdpi-v26/ic_launcher_foreground.png differ
diff --git a/bin/templates/project/res/mipmap-xxxhdpi/icon.png b/bin/templates/project/res/mipmap-xxxhdpi/ic_launcher.png
similarity index 100%
rename from bin/templates/project/res/mipmap-xxxhdpi/icon.png
rename to bin/templates/project/res/mipmap-xxxhdpi/ic_launcher.png
diff --git a/spec/unit/prepare.spec.js b/spec/unit/prepare.spec.js
new file mode 100644
index 00000000..3b133c15
--- /dev/null
+++ b/spec/unit/prepare.spec.js
@@ -0,0 +1,757 @@
+/**
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ 'License'); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ 'AS IS' BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+*/
+
+var rewire = require('rewire');
+var path = require('path');
+var CordovaError = require('cordova-common').CordovaError;
+
+const PATH_RESOURCE = path.join('platforms', 'android', 'app', 'src', 'main', 'res');
+
+/**
+ * Creates blank resource map object, used for testing.
+ *
+ * @param {String} target specific resource item
+ */
+function createResourceMap (target) {
+ let resources = {};
+
+ [
+ 'mipmap-ldpi',
+ 'mipmap-mdpi',
+ 'mipmap-hdpi',
+ 'mipmap-xhdpi',
+ 'mipmap-xxhdpi',
+ 'mipmap-xxxhdpi',
+ 'mipmap-ldpi-v26',
+ 'mipmap-mdpi-v26',
+ 'mipmap-hdpi-v26',
+ 'mipmap-xhdpi-v26',
+ 'mipmap-xxhdpi-v26',
+ 'mipmap-xxxhdpi-v26'
+ ].forEach((mipmap) => {
+ if (!target || target === 'ic_launcher.png') resources[path.join(PATH_RESOURCE, mipmap, 'ic_launcher.png')] = null;
+ if (!target || target === 'ic_launcher_foreground.png') resources[path.join(PATH_RESOURCE, mipmap, 'ic_launcher_foreground.png')] = null;
+ if (!target || target === 'ic_launcher_background.png') resources[path.join(PATH_RESOURCE, mipmap, 'ic_launcher_background.png')] = null;
+ if (!target || target === 'ic_launcher_foreground.xml') resources[path.join(PATH_RESOURCE, mipmap, 'ic_launcher_foreground.xml')] = null;
+ if (!target || target === 'ic_launcher_background.xml') resources[path.join(PATH_RESOURCE, mipmap, 'ic_launcher_background.xml')] = null;
+
+ if (
+ !mipmap.includes('-v26') &&
+ (!target || target === 'ic_launcher.xml')
+ ) {
+ resources[path.join(PATH_RESOURCE, mipmap, 'ic_launcher.xml')] = null;
+ }
+ });
+
+ return resources;
+}
+
+/**
+ * Create a mock item from the getIcon collection with the supplied updated data.
+ *
+ * @param {Object} data Changes to apply to the mock getIcon item
+ */
+function mockGetIconItem (data) {
+ return Object.assign({}, {
+ src: undefined,
+ target: undefined,
+ density: undefined,
+ platform: 'android',
+ width: undefined,
+ height: undefined,
+ background: undefined,
+ foreground: undefined
+ }, data);
+}
+
+describe('updateIcons method', function () {
+ // Rewire
+ let prepare;
+
+ // Spies
+ let updateIconResourceForAdaptiveSpy;
+ let updateIconResourceForLegacySpy;
+ let emitSpy;
+ let updatePathsSpy;
+
+ // Mock Data
+ let cordovaProject;
+ let platformResourcesDir;
+
+ beforeEach(function () {
+ prepare = rewire('../../bin/templates/cordova/lib/prepare');
+
+ cordovaProject = {
+ root: '/mock',
+ projectConfig: {
+ path: '/mock/config.xml',
+ cdvNamespacePrefix: 'cdv'
+ },
+ locations: {
+ plugins: '/mock/plugins',
+ www: '/mock/www'
+ }
+ };
+ platformResourcesDir = PATH_RESOURCE;
+
+ emitSpy = jasmine.createSpy('emit');
+ prepare.__set__('events', {
+ emit: emitSpy
+ });
+
+ updatePathsSpy = jasmine.createSpy('updatePaths');
+ prepare.__set__('FileUpdater', {
+ updatePaths: updatePathsSpy
+ });
+
+ // mocking initial responses for mapImageResources
+ prepare.__set__('mapImageResources', function (rootDir, subDir, type, resourceName) {
+ if (resourceName.includes('ic_launcher.png')) {
+ return createResourceMap('ic_launcher.png');
+ } else if (resourceName.includes('ic_launcher_foreground.png')) {
+ return createResourceMap('ic_launcher_foreground.png');
+ } else if (resourceName.includes('ic_launcher_background.png')) {
+ return createResourceMap('ic_launcher_background.png');
+ } else if (resourceName.includes('ic_launcher_foreground.xml')) {
+ return createResourceMap('ic_launcher_foreground.xml');
+ } else if (resourceName.includes('ic_launcher_background.xml')) {
+ return createResourceMap('ic_launcher_background.xml');
+ } else if (resourceName.includes('ic_launcher.xml')) {
+ return createResourceMap('ic_launcher.xml');
+ }
+ });
+ });
+
+ it('Test#001 : Should detect no defined icons.', function () {
+ const updateIcons = prepare.__get__('updateIcons');
+
+ // mock data.
+ cordovaProject.projectConfig.getIcons = function () {
+ return [];
+ };
+
+ updateIcons(cordovaProject, platformResourcesDir);
+
+ // The emit was called
+ expect(emitSpy).toHaveBeenCalled();
+
+ // The emit message was.
+ let actual = emitSpy.calls.argsFor(0)[1];
+ let expected = 'This app does not have launcher icons defined';
+ expect(actual).toEqual(expected);
+ });
+
+ it('Test#002 : Should detech incorrect configrations for adaptive icon and throws error.', function () {
+ const updateIcons = prepare.__get__('updateIcons');
+
+ // mock data.
+ cordovaProject.projectConfig.getIcons = function () {
+ return [mockGetIconItem({
+ density: 'mdpi',
+ background: 'res/icon/android/mdpi-background.png'
+ })];
+ };
+
+ expect(function () {
+ updateIcons(cordovaProject, platformResourcesDir);
+ }).toThrow(
+ new CordovaError('One of the following attributes are set but missing the other for the density type: mdpi. Please ensure that all require attributes are defined.')
+ );
+ });
+
+ it('Test#003 : Should detech incorrect configrations (missing foreground) for adaptive icon and throw an error.', function () {
+ const updateIcons = prepare.__get__('updateIcons');
+
+ // mock data.
+ cordovaProject.projectConfig.getIcons = function () {
+ return [mockGetIconItem({
+ density: 'mdpi',
+ background: 'res/icon/android/mdpi-background.png'
+ })];
+ };
+
+ expect(function () {
+ updateIcons(cordovaProject, platformResourcesDir);
+ }).toThrow(
+ new CordovaError('One of the following attributes are set but missing the other for the density type: mdpi. Please ensure that all require attributes are defined.')
+ );
+ });
+
+ it('Test#004 : Should detech incorrect configrations (missing background) for adaptive icon and throw an error.', function () {
+ const updateIcons = prepare.__get__('updateIcons');
+
+ // mock data.
+ cordovaProject.projectConfig.getIcons = function () {
+ return [mockGetIconItem({
+ density: 'mdpi',
+ foreground: 'res/icon/android/mdpi-foreground.png'
+ })];
+ };
+
+ expect(function () {
+ updateIcons(cordovaProject, platformResourcesDir);
+ }).toThrow(
+ new CordovaError('One of the following attributes are set but missing the other for the density type: mdpi. Please ensure that all require attributes are defined.')
+ );
+ });
+
+ it('Test#005 : Should detech incorrect configrations and throw an error.', function () {
+ const updateIcons = prepare.__get__('updateIcons');
+
+ // mock data.
+ cordovaProject.projectConfig.getIcons = function () {
+ return [mockGetIconItem({density: 'mdpi'})];
+ };
+
+ expect(function () {
+ updateIcons(cordovaProject, platformResourcesDir);
+ }).toThrow(
+ new CordovaError('One of the following attributes are set but missing the other for the density type: mdpi. Please ensure that all require attributes are defined.')
+ );
+ });
+
+ it('Test#006 : Should display incorrect configuration with density in message.', function () {
+ const updateIcons = prepare.__get__('updateIcons');
+
+ // mock data.
+ cordovaProject.projectConfig.getIcons = function () {
+ return [mockGetIconItem({density: 'mdpi'})];
+ };
+
+ expect(function () {
+ updateIcons(cordovaProject, platformResourcesDir);
+ }).toThrow(
+ new CordovaError('One of the following attributes are set but missing the other for the density type: mdpi. Please ensure that all require attributes are defined.')
+ );
+ });
+
+ it('Test#007 : Should display incorrect configuration with size in message from height.', function () {
+ const updateIcons = prepare.__get__('updateIcons');
+
+ // mock data.
+ cordovaProject.projectConfig.getIcons = function () {
+ return [mockGetIconItem({height: '192'})];
+ };
+
+ expect(function () {
+ updateIcons(cordovaProject, platformResourcesDir);
+ }).toThrow(
+ new CordovaError('One of the following attributes are set but missing the other for the density type: size=192. Please ensure that all require attributes are defined.')
+ );
+ });
+
+ it('Test#008 : Should display incorrect configuration with size in message from width.', function () {
+ const updateIcons = prepare.__get__('updateIcons');
+
+ // mock data.
+ cordovaProject.projectConfig.getIcons = function () {
+ return [mockGetIconItem({width: '192'})];
+ };
+
+ expect(function () {
+ updateIcons(cordovaProject, platformResourcesDir);
+ }).toThrow(
+ new CordovaError('One of the following attributes are set but missing the other for the density type: size=192. Please ensure that all require attributes are defined.')
+ );
+ });
+
+ it('Test#009 : Should detech incorrect configrations (missing background) for adaptive icon and throw an error.', function () {
+ const updateIcons = prepare.__get__('updateIcons');
+
+ // mock data.
+ cordovaProject.projectConfig.getIcons = function () {
+ return [mockGetIconItem({
+ density: 'mdpi',
+ foreground: 'res/icon/android/mdpi-foreground.png'
+ })];
+ };
+
+ expect(function () {
+ updateIcons(cordovaProject, platformResourcesDir);
+ }).toThrow(
+ new CordovaError('One of the following attributes are set but missing the other for the density type: mdpi. Please ensure that all require attributes are defined.')
+ );
+ });
+
+ it('Test#010 : Should detech adaptive icon with vector foreground and throws error for missing backwards compatability settings.', function () {
+ const updateIcons = prepare.__get__('updateIcons');
+
+ // mock data.
+ cordovaProject.projectConfig.getIcons = function () {
+ return [mockGetIconItem({
+ density: 'mdpi',
+ background: 'res/icon/android/mdpi-background.png',
+ foreground: 'res/icon/android/mdpi-foreground.xml'
+ })];
+ };
+
+ expect(function () {
+ updateIcons(cordovaProject, platformResourcesDir);
+ }).toThrow(
+ new CordovaError('For the following icons with the density of: mdpi, adaptive foreground with a defined color or vector can not be used as a standard fallback icon for older Android devices. To support older Android environments, please provide a value for the src attribute.')
+ );
+ });
+
+ it('Test#011 : Should detech adaptive icon with color foreground and throws error for missing backwards compatability settings.', function () {
+ const updateIcons = prepare.__get__('updateIcons');
+
+ // mock data.
+ cordovaProject.projectConfig.getIcons = function () {
+ return [mockGetIconItem({
+ density: 'mdpi',
+ background: 'res/icon/android/mdpi-background.png',
+ foreground: '@color/background'
+ })];
+ };
+
+ expect(function () {
+ updateIcons(cordovaProject, platformResourcesDir);
+ }).toThrow(
+ new CordovaError('For the following icons with the density of: mdpi, adaptive foreground with a defined color or vector can not be used as a standard fallback icon for older Android devices. To support older Android environments, please provide a value for the src attribute.')
+ );
+ });
+
+ it('Test#012 : Should update paths with adaptive and standard icons. Standard icon comes from adaptive foreground', function () {
+ const updateIcons = prepare.__get__('updateIcons');
+
+ // mock data.
+ cordovaProject.projectConfig.getIcons = function () {
+ return [mockGetIconItem({
+ density: 'mdpi',
+ background: 'res/icon/android/mdpi-background.png',
+ foreground: 'res/icon/android/mdpi-foreground.png'
+ })];
+ };
+
+ // Creating Spies
+ let resourceMap = createResourceMap();
+ let phaseOneModification = {};
+ phaseOneModification[path.join(PATH_RESOURCE, 'mipmap-mdpi-v26', 'ic_launcher_foreground.png')] = 'res/icon/android/mdpi-foreground.png';
+ phaseOneModification[path.join(PATH_RESOURCE, 'mipmap-mdpi-v26', 'ic_launcher_background.png')] = 'res/icon/android/mdpi-background.png';
+ let phaseOneUpdatedIconsForAdaptive = Object.assign({}, resourceMap, phaseOneModification);
+
+ updateIconResourceForAdaptiveSpy = jasmine.createSpy('updateIconResourceForAdaptiveSpy');
+ prepare.__set__('updateIconResourceForAdaptive', function (preparedIcons, resourceMap, platformResourcesDir) {
+ updateIconResourceForAdaptiveSpy();
+ return phaseOneUpdatedIconsForAdaptive;
+ });
+
+ let phaseTwoModification = {};
+ phaseTwoModification[path.join(PATH_RESOURCE, 'mipmap-mdpi', 'ic_launcher.png')] = 'res/icon/android/mdpi-foreground.png';
+ phaseTwoModification[path.join(PATH_RESOURCE, 'mipmap-mdpi-v26', 'ic_launcher_background.png')] = 'res/icon/android/mdpi-background.png';
+ let phaseTwoUpdatedIconsForLegacy = Object.assign({}, phaseOneUpdatedIconsForAdaptive, phaseTwoModification);
+
+ updateIconResourceForLegacySpy = jasmine.createSpy('updateIconResourceForLegacySpy');
+ prepare.__set__('updateIconResourceForLegacy', function (preparedIcons, resourceMap, platformResourcesDir) {
+ updateIconResourceForLegacySpy();
+ return phaseTwoUpdatedIconsForLegacy;
+ });
+
+ updateIcons(cordovaProject, platformResourcesDir);
+
+ // The emit was called
+ expect(emitSpy).toHaveBeenCalled();
+
+ // The emit message was.
+ let actual = emitSpy.calls.argsFor(0)[1];
+ let expected = 'Updating icons at ' + PATH_RESOURCE;
+ expect(actual).toEqual(expected);
+
+ // Expected to be called.
+ expect(updatePathsSpy).toHaveBeenCalled();
+ expect(updateIconResourceForAdaptiveSpy).toHaveBeenCalled();
+ expect(updateIconResourceForLegacySpy).toHaveBeenCalled();
+
+ let actualResourceMap = updatePathsSpy.calls.argsFor(0)[0];
+ let expectedResourceMap = phaseTwoUpdatedIconsForLegacy;
+ expect(actualResourceMap).toEqual(expectedResourceMap);
+ });
+
+ it('Test#013 : Should update paths with adaptive and standard icons.', function () {
+ const updateIcons = prepare.__get__('updateIcons');
+
+ // mock data.
+ cordovaProject.projectConfig.getIcons = function () {
+ return [mockGetIconItem({
+ density: 'mdpi',
+ src: 'res/icon/android/mdpi-icon.png',
+ background: 'res/icon/android/mdpi-background.png',
+ foreground: 'res/icon/android/mdpi-foreground.png'
+ })];
+ };
+
+ // Creating Spies
+ let resourceMap = createResourceMap();
+ let phaseOneModification = {};
+ phaseOneModification[path.join(PATH_RESOURCE, 'mipmap-mdpi-v26', 'ic_launcher_foreground.png')] = 'res/icon/android/mdpi-foreground.png';
+ phaseOneModification[path.join(PATH_RESOURCE, 'mipmap-mdpi-v26', 'ic_launcher_background.png')] = 'res/icon/android/mdpi-background.png';
+ let phaseOneUpdatedIconsForAdaptive = Object.assign({}, resourceMap, phaseOneModification);
+
+ updateIconResourceForAdaptiveSpy = jasmine.createSpy('updateIconResourceForAdaptiveSpy');
+ prepare.__set__('updateIconResourceForAdaptive', function (preparedIcons, resourceMap, platformResourcesDir) {
+ updateIconResourceForAdaptiveSpy();
+ return phaseOneUpdatedIconsForAdaptive;
+ });
+
+ let phaseTwoModification = {};
+ phaseTwoModification[path.join(PATH_RESOURCE, 'mipmap-mdpi', 'ic_launcher.png')] = 'res/icon/android/mdpi-foreground.png';
+ phaseTwoModification[path.join(PATH_RESOURCE, 'mipmap-mdpi-v26', 'ic_launcher_background.png')] = 'res/icon/android/mdpi-background.png';
+ let phaseTwoUpdatedIconsForLegacy = Object.assign({}, phaseOneUpdatedIconsForAdaptive, phaseTwoModification);
+
+ updateIconResourceForLegacySpy = jasmine.createSpy('updateIconResourceForLegacySpy');
+ prepare.__set__('updateIconResourceForLegacy', function (preparedIcons, resourceMap, platformResourcesDir) {
+ updateIconResourceForLegacySpy();
+ return phaseTwoUpdatedIconsForLegacy;
+ });
+
+ updateIcons(cordovaProject, platformResourcesDir);
+
+ // The emit was called
+ expect(emitSpy).toHaveBeenCalled();
+
+ // The emit message was.
+ let actual = emitSpy.calls.argsFor(0)[1];
+ let expected = 'Updating icons at ' + PATH_RESOURCE;
+ expect(actual).toEqual(expected);
+
+ // Expected to be called.
+ expect(updatePathsSpy).toHaveBeenCalled();
+ expect(updateIconResourceForAdaptiveSpy).toHaveBeenCalled();
+ expect(updateIconResourceForLegacySpy).toHaveBeenCalled();
+
+ let actualResourceMap = updatePathsSpy.calls.argsFor(0)[0];
+ let expectedResourceMap = phaseTwoUpdatedIconsForLegacy;
+ expect(actualResourceMap).toEqual(expectedResourceMap);
+ });
+
+ it('Test#014 : Should update paths with standard icons.', function () {
+ const updateIcons = prepare.__get__('updateIcons');
+
+ // mock data.
+ cordovaProject.projectConfig.getIcons = function () {
+ return [mockGetIconItem({
+ density: 'mdpi',
+ src: 'res/icon/android/mdpi-icon.png'
+ })];
+ };
+
+ // Creating Spies
+ let phaseOneUpdatedIconsForAdaptive = createResourceMap();
+
+ updateIconResourceForAdaptiveSpy = jasmine.createSpy('updateIconResourceForAdaptiveSpy');
+ prepare.__set__('updateIconResourceForAdaptive', function (preparedIcons, resourceMap, platformResourcesDir) {
+ updateIconResourceForAdaptiveSpy();
+ return phaseOneUpdatedIconsForAdaptive;
+ });
+
+ let phaseTwoModification = {};
+ phaseTwoModification[path.join(PATH_RESOURCE, 'mipmap-mdpi', 'ic_launcher.png')] = 'res/icon/android/mdpi-icon.png';
+ let phaseTwoUpdatedIconsForLegacy = Object.assign({}, phaseOneUpdatedIconsForAdaptive, phaseTwoModification);
+
+ updateIconResourceForLegacySpy = jasmine.createSpy('updateIconResourceForLegacySpy');
+ prepare.__set__('updateIconResourceForLegacy', function (preparedIcons, resourceMap, platformResourcesDir) {
+ updateIconResourceForLegacySpy();
+ return phaseTwoUpdatedIconsForLegacy;
+ });
+
+ updateIcons(cordovaProject, platformResourcesDir);
+
+ // The emit was called
+ expect(emitSpy).toHaveBeenCalled();
+
+ // The emit message was.
+ let actual = emitSpy.calls.argsFor(0)[1];
+ let expected = 'Updating icons at ' + PATH_RESOURCE;
+ expect(actual).toEqual(expected);
+
+ // Expected to be called.
+ expect(updatePathsSpy).toHaveBeenCalled();
+ expect(updateIconResourceForAdaptiveSpy).not.toHaveBeenCalled();
+ expect(updateIconResourceForLegacySpy).toHaveBeenCalled();
+
+ let actualResourceMap = updatePathsSpy.calls.argsFor(0)[0];
+ let expectedResourceMap = phaseTwoUpdatedIconsForLegacy;
+ expect(actualResourceMap).toEqual(expectedResourceMap);
+ });
+});
+
+describe('prepareIcons method', function () {
+ let prepare;
+ let emitSpy;
+ let prepareIcons;
+
+ beforeEach(function () {
+ prepare = rewire('../../bin/templates/cordova/lib/prepare');
+
+ prepareIcons = prepare.__get__('prepareIcons');
+
+ // Creating Spies
+ emitSpy = jasmine.createSpy('emit');
+ prepare.__set__('events', {
+ emit: emitSpy
+ });
+ });
+
+ it('Test#001 : should emit extra default icon found for adaptive use case.', function () {
+ // mock data.
+ let ldpi = mockGetIconItem({
+ density: 'ldpi',
+ background: 'res/icon/android/ldpi-background.png',
+ foreground: 'res/icon/android/ldpi-foreground.png'
+ });
+
+ let mdpi = mockGetIconItem({
+ density: 'mdpi',
+ background: 'res/icon/android/mdpi-background.png',
+ foreground: 'res/icon/android/mdpi-foreground.png'
+ });
+
+ let icons = [ldpi, mdpi];
+ let actual = prepareIcons(icons);
+ let expected = {
+ android_icons: {ldpi, mdpi},
+ default_icon: undefined
+ };
+
+ expect(expected).toEqual(actual);
+
+ });
+
+ it('Test#002 : should emit extra default icon found for legacy use case.', function () {
+ // mock data.
+ let ldpi = mockGetIconItem({
+ src: 'res/icon/android/ldpi-icon.png',
+ density: 'ldpi'
+ });
+
+ let mdpi = mockGetIconItem({
+ src: 'res/icon/android/mdpi-icon.png',
+ density: 'mdpi'
+ });
+
+ let icons = [ldpi, mdpi];
+ let actual = prepareIcons(icons);
+ let expected = {
+ android_icons: {ldpi, mdpi},
+ default_icon: undefined
+ };
+
+ expect(expected).toEqual(actual);
+
+ });
+});
+
+describe('updateIconResourceForLegacy method', function () {
+ let prepare;
+
+ // Spies
+ let fsWriteFileSyncSpy;
+
+ // Mock Data
+ let platformResourcesDir;
+ let preparedIcons;
+ let resourceMap;
+
+ beforeEach(function () {
+ prepare = rewire('../../bin/templates/cordova/lib/prepare');
+
+ // Mocked Data
+ platformResourcesDir = PATH_RESOURCE;
+ preparedIcons = {
+ android_icons: {
+ mdpi: mockGetIconItem({
+ src: 'res/icon/android/mdpi-icon.png',
+ density: 'mdpi'
+ })
+ },
+ default_icon: undefined
+ };
+
+ resourceMap = createResourceMap();
+
+ fsWriteFileSyncSpy = jasmine.createSpy('writeFileSync');
+ prepare.__set__('fs', {
+ writeFileSync: fsWriteFileSyncSpy
+ });
+ });
+
+ it('Test#001 : Should update resource map with prepared icons.', function () {
+ // Get method for testing
+ const updateIconResourceForLegacy = prepare.__get__('updateIconResourceForLegacy');
+
+ // Run Test
+ let expectedModification = {};
+ expectedModification[path.join(PATH_RESOURCE, 'mipmap-mdpi', 'ic_launcher.png')] = 'res/icon/android/mdpi-icon.png';
+ let expected = Object.assign({}, resourceMap, expectedModification);
+ let actual = updateIconResourceForLegacy(preparedIcons, resourceMap, platformResourcesDir);
+
+ expect(actual).toEqual(expected);
+
+ });
+});
+
+describe('updateIconResourceForAdaptive method', function () {
+ let prepare;
+
+ // Spies
+ let fsWriteFileSyncSpy;
+
+ // Mock Data
+ let platformResourcesDir;
+ let preparedIcons;
+ let resourceMap;
+
+ beforeEach(function () {
+ prepare = rewire('../../bin/templates/cordova/lib/prepare');
+
+ // Mocked Data
+ platformResourcesDir = PATH_RESOURCE;
+ preparedIcons = {
+ android_icons: {
+ mdpi: mockGetIconItem({
+ density: 'mdpi',
+ background: 'res/icon/android/mdpi-background.png',
+ foreground: 'res/icon/android/mdpi-foreground.png'
+ })
+ },
+ default_icon: undefined
+ };
+
+ resourceMap = createResourceMap();
+
+ fsWriteFileSyncSpy = jasmine.createSpy('writeFileSync');
+ prepare.__set__('fs', {
+ writeFileSync: fsWriteFileSyncSpy
+ });
+ });
+
+ it('Test#001 : Should update resource map with prepared icons.', function () {
+ // Get method for testing
+ const updateIconResourceForAdaptive = prepare.__get__('updateIconResourceForAdaptive');
+
+ // Run Test
+ let expectedModification = {};
+ expectedModification[path.join(PATH_RESOURCE, 'mipmap-mdpi-v26', 'ic_launcher_background.png')] = 'res/icon/android/mdpi-background.png';
+ expectedModification[path.join(PATH_RESOURCE, 'mipmap-mdpi-v26', 'ic_launcher_foreground.png')] = 'res/icon/android/mdpi-foreground.png';
+
+ let expected = Object.assign({}, resourceMap, expectedModification);
+ let actual = updateIconResourceForAdaptive(preparedIcons, resourceMap, platformResourcesDir);
+
+ expect(actual).toEqual(expected);
+
+ });
+});
+
+describe('cleanIcons method', function () {
+ let prepare;
+ let emitSpy;
+ let updatePathsSpy;
+
+ beforeEach(function () {
+ prepare = rewire('../../bin/templates/cordova/lib/prepare');
+
+ emitSpy = jasmine.createSpy('emit');
+ prepare.__set__('events', {
+ emit: emitSpy
+ });
+
+ updatePathsSpy = jasmine.createSpy('updatePaths');
+ prepare.__set__('FileUpdater', {
+ updatePaths: updatePathsSpy
+ });
+ });
+
+ it('Test#001 : should detect that the app does not have defined icons.', function () {
+ // Mock
+ let icons = [];
+ let projectRoot = '/mock';
+ let projectConfig = {
+ getIcons: function () { return icons; },
+ path: '/mock/config.xml',
+ cdvNamespacePrefix: 'cdv'
+ };
+ let platformResourcesDir = PATH_RESOURCE;
+
+ const cleanIcons = prepare.__get__('cleanIcons');
+ cleanIcons(projectRoot, projectConfig, platformResourcesDir);
+
+ let actualEmitMessage = emitSpy.calls.argsFor(0)[1];
+ expect(actualEmitMessage).toContain('This app does not have launcher icons defined');
+ });
+
+ it('Test#002 : Should clean paths for adaptive icons.', function () {
+ // Mock
+ let icons = [mockGetIconItem({
+ density: 'mdpi',
+ background: 'res/icon/android/mdpi-background.png',
+ foreground: 'res/icon/android/mdpi-foreground.png'
+ })];
+ let projectRoot = '/mock';
+ let projectConfig = {
+ getIcons: function () { return icons; },
+ path: '/mock/config.xml',
+ cdvNamespacePrefix: 'cdv'
+ };
+ let platformResourcesDir = PATH_RESOURCE;
+
+ var expectedResourceMapBackground = createResourceMap('ic_launcher_background.png');
+
+ // mocking initial responses for mapImageResources
+ prepare.__set__('mapImageResources', function (rootDir, subDir, type, resourceName) {
+ if (resourceName.includes('ic_launcher_background.png')) {
+ return expectedResourceMapBackground;
+ }
+ });
+
+ const cleanIcons = prepare.__get__('cleanIcons');
+ cleanIcons(projectRoot, projectConfig, platformResourcesDir);
+
+ let actualResourceMapBackground = updatePathsSpy.calls.argsFor(0)[0];
+ expect(actualResourceMapBackground).toEqual(expectedResourceMapBackground);
+ });
+
+ it('Test#003 : Should clean paths for legacy icons.', function () {
+ // Mock
+ let icons = [mockGetIconItem({
+ src: 'res/icon/android/mdpi.png',
+ density: 'mdpi'
+ })];
+
+ let projectRoot = '/mock';
+ let projectConfig = {
+ getIcons: function () { return icons; },
+ path: '/mock/config.xml',
+ cdvNamespacePrefix: 'cdv'
+ };
+ let platformResourcesDir = PATH_RESOURCE;
+
+ var expectedResourceMap = createResourceMap();
+
+ // mocking initial responses for mapImageResources
+ prepare.__set__('mapImageResources', function (rootDir, subDir, type, resourceName) {
+ return expectedResourceMap;
+ });
+
+ const cleanIcons = prepare.__get__('cleanIcons');
+ cleanIcons(projectRoot, projectConfig, platformResourcesDir);
+
+ let actualResourceMap = updatePathsSpy.calls.argsFor(0)[0];
+ expect(actualResourceMap).toEqual(expectedResourceMap);
+ });
+});