blob: 9c539cf06ff8f4b26e4c2a9a82d94797df0ebd40 [file] [log] [blame]
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed 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.
*/
package com.android.build.gradle.internal;
import com.android.annotations.NonNull;
import com.android.annotations.Nullable;
import com.android.builder.model.DimensionAware;
import com.android.utils.StringHelper;
import com.google.common.base.Predicates;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.Lists;
import java.util.List;
import org.gradle.api.Named;
/**
* A combination of product flavors for a variant, each belonging to a different flavor dimension.
*/
public class ProductFlavorCombo<T extends DimensionAware & Named> {
private String name;
@NonNull
private final List<T> flavorList;
/**
* Create a ProductFlavorCombo.
* @param flavors Lists of ProductFlavor.
*/
public ProductFlavorCombo(@NonNull T... flavors) {
flavorList = ImmutableList.copyOf(flavors);
}
public ProductFlavorCombo(@NonNull Iterable<T> flavors) {
flavorList = ImmutableList.copyOf(flavors);
}
@NonNull
public String getName() {
if (name == null) {
boolean first = true;
StringBuilder sb = new StringBuilder();
for (T flavor : flavorList) {
if (first) {
sb.append(flavor.getName());
first = false;
} else {
StringHelper.appendCapitalized(sb, flavor.getName());
}
}
name = sb.toString();
}
return name;
}
@NonNull
public List<T> getFlavorList() {
return flavorList;
}
/**
* Creates a list containing all combinations of ProductFlavors of the given dimensions.
* @param flavorDimensions The dimensions each product flavor can belong to.
* @param productFlavors An iterable of all ProductFlavors in the project..
* @return A list of ProductFlavorCombo representing all combinations of ProductFlavors.
*/
@NonNull
public static <S extends DimensionAware & Named> List<ProductFlavorCombo<S>> createCombinations(
@Nullable List<String> flavorDimensions,
@NonNull Iterable<S> productFlavors) {
List <ProductFlavorCombo<S>> result = Lists.newArrayList();
if (flavorDimensions == null || flavorDimensions.isEmpty()) {
for (S flavor : productFlavors) {
result.add(new ProductFlavorCombo<>(ImmutableList.of(flavor)));
}
} else {
// need to group the flavor per dimension.
// First a map of dimension -> list(ProductFlavor)
ArrayListMultimap<String, S> map = ArrayListMultimap.create();
for (S flavor : productFlavors) {
String flavorDimension = flavor.getDimension();
if (flavorDimension == null) {
throw new RuntimeException(String.format(
"Flavor '%1$s' has no flavor dimension.", flavor.getName()));
}
if (!flavorDimensions.contains(flavorDimension)) {
throw new RuntimeException(String.format(
"Flavor '%1$s' has unknown dimension '%2$s'.",
flavor.getName(), flavor.getDimension()));
}
map.put(flavorDimension, flavor);
}
createProductFlavorCombinations(result,
Lists.<S>newArrayListWithCapacity(flavorDimensions.size()),
0, flavorDimensions, map);
}
return result;
}
private static <S extends DimensionAware & Named> void createProductFlavorCombinations(
List<ProductFlavorCombo<S>> flavorGroups,
List<S> group,
int index,
List<String> flavorDimensionList,
ListMultimap<String, S> map) {
if (index == flavorDimensionList.size()) {
flavorGroups.add(new ProductFlavorCombo<>(Iterables.filter(group, Predicates.notNull())));
return;
}
// fill the array at the current index.
// get the dimension name that matches the index we are filling.
String dimension = flavorDimensionList.get(index);
// from our map, get all the possible flavors in that dimension.
List<S> flavorList = map.get(dimension);
// loop on all the flavors to add them to the current index and recursively fill the next
// indices.
if (flavorList.isEmpty()) {
throw new RuntimeException(String.format(
"No flavor is associated with flavor dimension '%1$s'.", dimension));
} else {
for (S flavor : flavorList) {
group.add(flavor);
createProductFlavorCombinations(
flavorGroups, group, index + 1, flavorDimensionList, map);
group.remove(group.size() - 1);
}
}
}
}