summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorŁukasz Paczos <lukas.paczos@gmail.com>2018-08-20 19:38:16 +0200
committerŁukasz Paczos <lukas.paczos@gmail.com>2018-08-21 18:36:13 +0200
commit216448524b262b636d0b83c9dc31390f1359c98e (patch)
treefa64acb01a9f1896dd50d30db91798ac81cbab1e
parent5ce64b786cfd2fbfdc28ccfbcf9c1a5216346281 (diff)
downloadqtlocation-mapboxgl-upstream/12268-android-collator-wrapper.tar.gz
[android] "collator" and "resolved-locale" expressions supportupstream/12268-android-collator-wrapper
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/expressions/Expression.java596
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/style/expressions/ExpressionTest.java77
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/ExpressionTest.java63
3 files changed, 701 insertions, 35 deletions
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/expressions/Expression.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/expressions/Expression.java
index 1aa0ce9093..bd4d5d7d4b 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/expressions/Expression.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/expressions/Expression.java
@@ -4,17 +4,22 @@ import android.support.annotation.ColorInt;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.Size;
+
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonNull;
+import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import com.mapbox.mapboxsdk.style.layers.PropertyFactory;
import com.mapbox.mapboxsdk.style.layers.PropertyValue;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.HashMap;
import java.util.List;
+import java.util.Locale;
+import java.util.Map;
/**
* The value for any layout property, paint property, or filter may be specified as an expression.
@@ -345,7 +350,8 @@ public class Expression {
* @return expression
* @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-rgba">Style specification</a>
*/
- public static Expression rgba(@NonNull Number red, @NonNull Number green, @NonNull Number blue, @NonNull Number alpha) {
+ public static Expression rgba(@NonNull Number red, @NonNull Number green, @NonNull Number blue, @NonNull Number
+ alpha) {
return rgba(literal(red), literal(green), literal(blue), literal(alpha));
}
@@ -386,6 +392,32 @@ public class Expression {
/**
* Returns true if the input values are equal, false otherwise.
+ * The inputs must be numbers, strings, or booleans, and both of the same type.
+ * <p>
+ * Example usage:
+ * </p>
+ * <pre>
+ * {@code
+ * FillLayer fillLayer = new FillLayer("layer-id", "source-id");
+ * fillLayer.setFilter(
+ * eq(get("keyToValue"), get("keyToOtherValue"), collator(true, false))
+ * );
+ * }
+ * </pre>
+ *
+ * @param compareOne the first expression
+ * @param compareTwo the second expression
+ * @param collator the collator expression
+ * @return expression
+ * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-==">Style specification</a>
+ */
+ public static Expression eq(@NonNull Expression compareOne, @NonNull Expression compareTwo,
+ @NonNull Expression collator) {
+ return new Expression("==", compareOne, compareTwo, collator);
+ }
+
+ /**
+ * Returns true if the input values are equal, false otherwise.
* <p>
* Example usage:
* </p>
@@ -432,6 +464,32 @@ public class Expression {
/**
* Returns true if the input values are equal, false otherwise.
+ * The inputs must be numbers, strings, or booleans, and both of the same type.
+ * <p>
+ * Example usage:
+ * </p>
+ * <pre>
+ * {@code
+ * FillLayer fillLayer = new FillLayer("layer-id", "source-id");
+ * fillLayer.setFilter(
+ * eq(get("keyToValue"), get("keyToOtherValue"), collator(true, false))
+ * );
+ * }
+ * </pre>
+ *
+ * @param compareOne the first expression
+ * @param compareTwo the second String
+ * @param collator the collator expression
+ * @return expression
+ * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-==">Style specification</a>
+ */
+ public static Expression eq(@NonNull Expression compareOne, @NonNull String compareTwo,
+ @NonNull Expression collator) {
+ return eq(compareOne, literal(compareTwo), collator);
+ }
+
+ /**
+ * Returns true if the input values are equal, false otherwise.
* <p>
* Example usage:
* </p>
@@ -478,6 +536,32 @@ public class Expression {
}
/**
+ * Returns true if the input values are not equal, false otherwise.
+ * The inputs must be numbers, strings, or booleans, and both of the same type.
+ * <p>
+ * Example usage:
+ * </p>
+ * <pre>
+ * {@code
+ * FillLayer fillLayer = new FillLayer("layer-id", "source-id");
+ * fillLayer.setFilter(
+ * neq(get("keyToValue"), get("keyToOtherValue"), collator(true, false))
+ * );
+ * }
+ * </pre>
+ *
+ * @param compareOne the first expression
+ * @param compareTwo the second expression
+ * @param collator the collator expression
+ * @return expression
+ * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-!=">Style specification</a>
+ */
+ public static Expression neq(@NonNull Expression compareOne, @NonNull Expression compareTwo,
+ @NonNull Expression collator) {
+ return new Expression("!=", compareOne, compareTwo, collator);
+ }
+
+ /**
* Returns true if the input values are equal, false otherwise.
* <p>
* Example usage:
@@ -524,6 +608,32 @@ public class Expression {
}
/**
+ * Returns true if the input values are not equal, false otherwise.
+ * The inputs must be numbers, strings, or booleans, and both of the same type.
+ * <p>
+ * Example usage:
+ * </p>
+ * <pre>
+ * {@code
+ * FillLayer fillLayer = new FillLayer("layer-id", "source-id");
+ * fillLayer.setFilter(
+ * neq(get("keyToValue"), get("keyToOtherValue"), collator(true, false))
+ * );
+ * }
+ * </pre>
+ *
+ * @param compareOne the first expression
+ * @param compareTwo the second String
+ * @param collator the collator expression
+ * @return expression
+ * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-!=">Style specification</a>
+ */
+ public static Expression neq(@NonNull Expression compareOne, @NonNull String compareTwo,
+ @NonNull Expression collator) {
+ return new Expression("!=", compareOne, literal(compareTwo), collator);
+ }
+
+ /**
* Returns `true` if the input values are not equal, `false` otherwise.
* <p>
* Example usage:
@@ -572,6 +682,32 @@ public class Expression {
/**
* Returns true if the first input is strictly greater than the second, false otherwise.
+ * The inputs must be numbers or strings, and both of the same type.
+ * <p>
+ * Example usage:
+ * </p>
+ * <pre>
+ * {@code
+ * FillLayer fillLayer = new FillLayer("layer-id", "source-id");
+ * fillLayer.setFilter(
+ * gt(get("keyToValue"), get("keyToOtherValue"), collator(true, false))
+ * );
+ * }
+ * </pre>
+ *
+ * @param compareOne the first expression
+ * @param compareTwo the second expression
+ * @param collator the collator expression
+ * @return expression
+ * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-%3E">Style specification</a>
+ */
+ public static Expression gt(@NonNull Expression compareOne, @NonNull Expression compareTwo,
+ @NonNull Expression collator) {
+ return new Expression(">", compareOne, compareTwo, collator);
+ }
+
+ /**
+ * Returns true if the first input is strictly greater than the second, false otherwise.
* <p>
* Example usage:
* </p>
@@ -617,6 +753,32 @@ public class Expression {
}
/**
+ * Returns true if the first input is strictly greater than the second, false otherwise.
+ * The inputs must be numbers or strings, and both of the same type.
+ * <p>
+ * Example usage:
+ * </p>
+ * <pre>
+ * {@code
+ * FillLayer fillLayer = new FillLayer("layer-id", "source-id");
+ * fillLayer.setFilter(
+ * gt(get("keyToValue"), get("keyToOtherValue"), collator(true, false))
+ * );
+ * }
+ * </pre>
+ *
+ * @param compareOne the first expression
+ * @param compareTwo the second String
+ * @param collator the collator expression
+ * @return expression
+ * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-%3E">Style specification</a>
+ */
+ public static Expression gt(@NonNull Expression compareOne, @NonNull String compareTwo,
+ @NonNull Expression collator) {
+ return new Expression(">", compareOne, literal(compareTwo), collator);
+ }
+
+ /**
* Returns true if the first input is strictly less than the second, false otherwise.
* The inputs must be numbers or strings, and both of the same type.
* <p>
@@ -626,13 +788,13 @@ public class Expression {
* {@code
* FillLayer fillLayer = new FillLayer("layer-id", "source-id");
* fillLayer.setFilter(
- * lt(get("keyToValue"), get("keyToOtherValue"))
+ * lt(get("keyToValue"), get("keyToOtherValue"), collator(true, false))
* );
* }
* </pre>
*
* @param compareOne the first expression
- * @param compareTwo the second number
+ * @param compareTwo the second expression
* @return expression
* @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-%3C">Style specification</a>
*/
@@ -642,6 +804,32 @@ public class Expression {
/**
* Returns true if the first input is strictly less than the second, false otherwise.
+ * The inputs must be numbers or strings, and both of the same type.
+ * <p>
+ * Example usage:
+ * </p>
+ * <pre>
+ * {@code
+ * FillLayer fillLayer = new FillLayer("layer-id", "source-id");
+ * fillLayer.setFilter(
+ * lt(get("keyToValue"), get("keyToOtherValue"), collator(true, false))
+ * );
+ * }
+ * </pre>
+ *
+ * @param compareOne the first expression
+ * @param compareTwo the second number
+ * @param collator the collator expression
+ * @return expression
+ * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-%3C">Style specification</a>
+ */
+ public static Expression lt(@NonNull Expression compareOne, @NonNull Expression compareTwo,
+ @NonNull Expression collator) {
+ return new Expression("<", compareOne, compareTwo, collator);
+ }
+
+ /**
+ * Returns true if the first input is strictly less than the second, false otherwise.
* <p>
* Example usage:
* </p>
@@ -687,6 +875,32 @@ public class Expression {
}
/**
+ * Returns true if the first input is strictly less than the second, false otherwise.
+ * The inputs must be numbers or strings, and both of the same type.
+ * <p>
+ * Example usage:
+ * </p>
+ * <pre>
+ * {@code
+ * FillLayer fillLayer = new FillLayer("layer-id", "source-id");
+ * fillLayer.setFilter(
+ * lt(get("keyToValue"), get("keyToOtherValue"), collator(true, false))
+ * );
+ * }
+ * </pre>
+ *
+ * @param compareOne the first expression
+ * @param compareTwo the second String
+ * @param collator the collator expression
+ * @return expression
+ * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-%3C">Style specification</a>
+ */
+ public static Expression lt(@NonNull Expression compareOne, @NonNull String compareTwo,
+ @NonNull Expression collator) {
+ return new Expression("<", compareOne, literal(compareTwo), collator);
+ }
+
+ /**
* Returns true if the first input is greater than or equal to the second, false otherwise.
* The inputs must be numbers or strings, and both of the same type.
* <p>
@@ -712,6 +926,32 @@ public class Expression {
/**
* Returns true if the first input is greater than or equal to the second, false otherwise.
+ * The inputs must be numbers or strings, and both of the same type.
+ * <p>
+ * Example usage:
+ * </p>
+ * <pre>
+ * {@code
+ * FillLayer fillLayer = new FillLayer("layer-id", "source-id");
+ * fillLayer.setFilter(
+ * gte(get("keyToValue"), get("keyToOtherValue"), collator(true, false))
+ * );
+ * }
+ * </pre>
+ *
+ * @param compareOne the first expression
+ * @param compareTwo the second expression
+ * @param collator the collator expression
+ * @return expression
+ * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-%3E%3D">Style specification</a>
+ */
+ public static Expression gte(@NonNull Expression compareOne, @NonNull Expression compareTwo,
+ @NonNull Expression collator) {
+ return new Expression(">=", compareOne, compareTwo, collator);
+ }
+
+ /**
+ * Returns true if the first input is greater than or equal to the second, false otherwise.
* <p>
* Example usage:
* </p>
@@ -757,6 +997,32 @@ public class Expression {
}
/**
+ * Returns true if the first input is greater than or equal to the second, false otherwise.
+ * The inputs must be numbers or strings, and both of the same type.
+ * <p>
+ * Example usage:
+ * </p>
+ * <pre>
+ * {@code
+ * FillLayer fillLayer = new FillLayer("layer-id", "source-id");
+ * fillLayer.setFilter(
+ * gte(get("keyToValue"), get("keyToOtherValue"), collator(true, false))
+ * );
+ * }
+ * </pre>
+ *
+ * @param compareOne the first expression
+ * @param compareTwo the second String
+ * @param collator the collator expression
+ * @return expression
+ * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-%3E%3D">Style specification</a>
+ */
+ public static Expression gte(@NonNull Expression compareOne, @NonNull String compareTwo,
+ @NonNull Expression collator) {
+ return new Expression(">=", compareOne, literal(compareTwo), collator);
+ }
+
+ /**
* Returns true if the first input is less than or equal to the second, false otherwise.
* The inputs must be numbers or strings, and both of the same type.
* <p>
@@ -782,6 +1048,32 @@ public class Expression {
/**
* Returns true if the first input is less than or equal to the second, false otherwise.
+ * The inputs must be numbers or strings, and both of the same type.
+ * <p>
+ * Example usage:
+ * </p>
+ * <pre>
+ * {@code
+ * FillLayer fillLayer = new FillLayer("layer-id", "source-id");
+ * fillLayer.setFilter(
+ * lte(get("keyToValue"), get("keyToOtherValue"), collator(true, false))
+ * );
+ * }
+ * </pre>
+ *
+ * @param compareOne the first expression
+ * @param compareTwo the second expression
+ * @param collator the collator expression
+ * @return expression
+ * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-%3C%3D">Style specification</a>
+ */
+ public static Expression lte(@NonNull Expression compareOne, @NonNull Expression compareTwo,
+ @NonNull Expression collator) {
+ return new Expression("<=", compareOne, compareTwo, collator);
+ }
+
+ /**
+ * Returns true if the first input is less than or equal to the second, false otherwise.
* <p>
* Example usage:
* </p>
@@ -827,6 +1119,32 @@ public class Expression {
}
/**
+ * Returns true if the first input is less than or equal to the second, false otherwise.
+ * The inputs must be numbers or strings, and both of the same type.
+ * <p>
+ * Example usage:
+ * </p>
+ * <pre>
+ * {@code
+ * FillLayer fillLayer = new FillLayer("layer-id", "source-id");
+ * fillLayer.setFilter(
+ * lte(get("keyToValue"), get("keyToOtherValue"), collator(true, false))
+ * );
+ * }
+ * </pre>
+ *
+ * @param compareOne the first expression
+ * @param compareTwo the second String
+ * @param collator the collator expression
+ * @return expression
+ * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-%3C%3D">Style specification</a>
+ */
+ public static Expression lte(@NonNull Expression compareOne, @NonNull String compareTwo,
+ @NonNull Expression collator) {
+ return new Expression("<=", compareOne, literal(compareTwo), collator);
+ }
+
+ /**
* Returns `true` if all the inputs are `true`, `false` otherwise.
* <p>
* The inputs are evaluated in order, and evaluation is short-circuiting:
@@ -2479,6 +2797,32 @@ public class Expression {
}
/**
+ * Returns the IETF language tag of the locale being used by the provided collator.
+ * This can be used to determine the default system locale,
+ * or to determine if a requested locale was successfully loaded.
+ * <p>
+ * Example usage:
+ * </p>
+ * <pre>
+ * {@code
+ * CircleLayer circleLayer = new CircleLayer("layer-id", "source-id");
+ * circleLayer.setProperties(
+ * circleColor(switchCase(
+ eq(literal("it"), resolvedLocale(collator(true, true, "it"))), literal(ColorUtils.colorToRgbaString(Color.GREEN)),
+ literal(ColorUtils.colorToRgbaString(Color.RED))))
+ * );
+ * }
+ * </pre>
+ *
+ * @param collator the collator expression
+ * @return expression
+ * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-resolved-locale">Style specification</a>
+ */
+ public static Expression resolvedLocale(Expression collator) {
+ return new Expression("resolved-locale", collator);
+ }
+
+ /**
* Returns the input string converted to uppercase.
* <p>
* Follows the Unicode Default Case Conversion algorithm
@@ -2697,6 +3041,104 @@ public class Expression {
}
/**
+ * Returns a collator for use in locale-dependent comparison operations.
+ * The case-sensitive and diacritic-sensitive options default to false.
+ * The locale argument specifies the IETF language tag of the locale to use.
+ * If none is provided, the default locale is used. If the requested locale is not available,
+ * the collator will use a system-defined fallback locale.
+ * Use resolved-locale to test the results of locale fallback behavior.
+ *
+ * @param caseSensitive case sensitive flag
+ * @param diacriticSensitive diacritic sensitive flag
+ * @param locale locale
+ * @return expression
+ * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-types-collator">Style specification</a>
+ */
+ public static Expression collator(boolean caseSensitive, boolean diacriticSensitive, Locale locale) {
+ Map<String, Expression> map = new HashMap<>();
+ map.put("case-sensitive", literal(caseSensitive));
+ map.put("diacritic-sensitive", literal(diacriticSensitive));
+
+ StringBuilder localeStringBuilder = new StringBuilder();
+
+ String language = locale.getLanguage();
+ if (language != null && !language.isEmpty()) {
+ localeStringBuilder.append(language);
+ }
+
+ String country = locale.getCountry();
+ if (country != null && !country.isEmpty()) {
+ localeStringBuilder.append("-");
+ localeStringBuilder.append(country);
+ }
+
+ map.put("locale", literal(localeStringBuilder.toString()));
+ return new Expression("collator", new ExpressionMap(map));
+ }
+
+ /**
+ * Returns a collator for use in locale-dependent comparison operations.
+ * The case-sensitive and diacritic-sensitive options default to false.
+ * The locale argument specifies the IETF language tag of the locale to use.
+ * If none is provided, the default locale is used. If the requested locale is not available,
+ * the collator will use a system-defined fallback locale.
+ * Use resolved-locale to test the results of locale fallback behavior.
+ *
+ * @param caseSensitive case sensitive flag
+ * @param diacriticSensitive diacritic sensitive flag
+ * @return expression
+ * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-types-collator">Style specification</a>
+ */
+ public static Expression collator(boolean caseSensitive, boolean diacriticSensitive) {
+ Map<String, Expression> map = new HashMap<>();
+ map.put("case-sensitive", literal(caseSensitive));
+ map.put("diacritic-sensitive", literal(diacriticSensitive));
+ return new Expression("collator", new ExpressionMap(map));
+ }
+
+ /**
+ * Returns a collator for use in locale-dependent comparison operations.
+ * The case-sensitive and diacritic-sensitive options default to false.
+ * The locale argument specifies the IETF language tag of the locale to use.
+ * If none is provided, the default locale is used. If the requested locale is not available,
+ * the collator will use a system-defined fallback locale.
+ * Use resolved-locale to test the results of locale fallback behavior.
+ *
+ * @param caseSensitive case sensitive flag
+ * @param diacriticSensitive diacritic sensitive flag
+ * @param locale locale
+ * @return expression
+ * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-types-collator">Style specification</a>
+ */
+ public static Expression collator(Expression caseSensitive, Expression diacriticSensitive, Expression locale) {
+ Map<String, Expression> map = new HashMap<>();
+ map.put("case-sensitive", caseSensitive);
+ map.put("diacritic-sensitive", diacriticSensitive);
+ map.put("locale", locale);
+ return new Expression("collator", new ExpressionMap(map));
+ }
+
+ /**
+ * Returns a collator for use in locale-dependent comparison operations.
+ * The case-sensitive and diacritic-sensitive options default to false.
+ * The locale argument specifies the IETF language tag of the locale to use.
+ * If none is provided, the default locale is used. If the requested locale is not available,
+ * the collator will use a system-defined fallback locale.
+ * Use resolved-locale to test the results of locale fallback behavior.
+ *
+ * @param caseSensitive case sensitive flag
+ * @param diacriticSensitive diacritic sensitive flag
+ * @return expression
+ * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-types-collator">Style specification</a>
+ */
+ public static Expression collator(Expression caseSensitive, Expression diacriticSensitive) {
+ Map<String, Expression> map = new HashMap<>();
+ map.put("case-sensitive", caseSensitive);
+ map.put("diacritic-sensitive", diacriticSensitive);
+ return new Expression("collator", new ExpressionMap(map));
+ }
+
+ /**
* Asserts that the input value is an object. If it is not, the expression is an error
* The asserted input value is returned as result.
*
@@ -3422,8 +3864,8 @@ public class Expression {
array.add(operator);
if (arguments != null) {
for (Expression argument : arguments) {
- if (argument instanceof Expression.ExpressionLiteral) {
- array.add(toValue((ExpressionLiteral) argument));
+ if (argument instanceof ValueExpression) {
+ array.add(((ValueExpression) argument).toValue());
} else {
array.add(argument.toArray());
}
@@ -3433,22 +3875,6 @@ public class Expression {
}
/**
- * Converts the expression value to an Object.
- *
- * @param expressionValue the expression value to convert
- * @return the converted object expression
- */
- private Object toValue(ExpressionLiteral expressionValue) {
- Object value = expressionValue.toValue();
- if (value instanceof PropertyValue) {
- throw new IllegalArgumentException("PropertyValue are not allowed as an expression literal, use value instead.");
- } else if (value instanceof Expression.ExpressionLiteral) {
- return toValue((ExpressionLiteral) value);
- }
- return value;
- }
-
- /**
* Returns a string representation of the object that matches the definition set in the style specification.
* <p>
* If this expression contains a coma (,) delimited literal, like 'rgba(r, g, b, a)`,
@@ -3549,7 +3975,7 @@ public class Expression {
* {@link #literal(String)} and {@link #literal(Object)}.
* </p>
*/
- public static class ExpressionLiteral extends Expression {
+ public static class ExpressionLiteral extends Expression implements ValueExpression {
protected Object literal;
@@ -3572,7 +3998,14 @@ public class Expression {
*
* @return the literal object
*/
- Object toValue() {
+ @Override
+ public Object toValue() {
+ if (literal instanceof PropertyValue) {
+ throw new IllegalArgumentException(
+ "PropertyValue are not allowed as an expression literal, use value instead.");
+ } else if (literal instanceof Expression.ExpressionLiteral) {
+ return ((ExpressionLiteral) literal).toValue();
+ }
return literal;
}
@@ -3589,7 +4022,13 @@ public class Expression {
*/
@Override
public String toString() {
- return literal.toString();
+ String string;
+ if (literal instanceof String) {
+ string = "\"" + literal + "\"";
+ } else {
+ string = literal.toString();
+ }
+ return string;
}
/**
@@ -3627,7 +4066,7 @@ public class Expression {
return result;
}
- private String unwrapStringLiteral(String value) {
+ private static String unwrapStringLiteral(String value) {
if (value.length() > 1 &&
value.charAt(0) == '\"' && value.charAt(value.length() - 1) == '\"') {
return value.substring(1, value.length() - 1);
@@ -3727,20 +4166,36 @@ public class Expression {
JsonElement jsonElement;
for (int i = 1; i < jsonArray.size(); i++) {
jsonElement = jsonArray.get(i);
- if (jsonElement instanceof JsonArray) {
- arguments.add(convert((JsonArray) jsonElement));
- } else if (jsonElement instanceof JsonPrimitive) {
- arguments.add(convert((JsonPrimitive) jsonElement));
- } else if (jsonElement instanceof JsonNull) {
- arguments.add(new Expression.ExpressionLiteral(""));
- } else {
- throw new RuntimeException("Unsupported expression conversion for " + jsonElement.getClass());
- }
+ arguments.add(convert(jsonElement));
}
return new Expression(operator, arguments.toArray(new Expression[arguments.size()]));
}
/**
+ * Converts a JsonElement to an expression
+ *
+ * @param jsonElement the json element to convert
+ * @return the expression
+ */
+ private static Expression convert(@NonNull JsonElement jsonElement) {
+ if (jsonElement instanceof JsonArray) {
+ return convert((JsonArray) jsonElement);
+ } else if (jsonElement instanceof JsonPrimitive) {
+ return convert((JsonPrimitive) jsonElement);
+ } else if (jsonElement instanceof JsonNull) {
+ return new Expression.ExpressionLiteral("");
+ } else if (jsonElement instanceof JsonObject) {
+ Map<String, Expression> map = new HashMap<>();
+ for (String key : ((JsonObject) jsonElement).keySet()) {
+ map.put(key, convert(((JsonObject) jsonElement).get(key)));
+ }
+ return new ExpressionMap(map);
+ } else {
+ throw new RuntimeException("Unsupported expression conversion for " + jsonElement.getClass());
+ }
+ }
+
+ /**
* Converts a JsonPrimitive to an expression literal
*
* @param jsonPrimitive the json primitive to convert
@@ -3816,6 +4271,79 @@ public class Expression {
}
/**
+ * Wraps an expression value stored in a Map.
+ */
+ private static class ExpressionMap extends Expression implements ValueExpression {
+ private Map<String, Expression> map;
+
+ ExpressionMap(Map<String, Expression> map) {
+ this.map = map;
+ }
+
+ @Override
+ public Object toValue() {
+ Map<String, Object> unwrappedMap = new HashMap<>();
+ for (String key : map.keySet()) {
+ Expression expression = map.get(key);
+ if (expression instanceof Expression.ExpressionLiteral) {
+ unwrappedMap.put(key, ((ExpressionLiteral) expression).toValue());
+ } else {
+ unwrappedMap.put(key, expression.toArray());
+ }
+ }
+
+ return unwrappedMap;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("{");
+ for (String key : map.keySet()) {
+ builder.append("\"").append(key).append("\": ");
+ builder.append(map.get(key));
+ builder.append(", ");
+ }
+
+ if (map.size() > 0) {
+ builder.delete(builder.length() - 2, builder.length());
+ }
+
+ builder.append("}");
+ return builder.toString();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ if (!super.equals(o)) {
+ return false;
+ }
+ ExpressionMap that = (ExpressionMap) o;
+ return map.equals(that.map);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = super.hashCode();
+ result = 31 * result + (map == null ? 0 : map.hashCode());
+ return result;
+ }
+ }
+
+ /**
+ * Interface used to describe expressions that hold a Java value.
+ */
+ private interface ValueExpression {
+ Object toValue();
+ }
+
+ /**
* Converts an object that is a primitive array to an Object[]
*
* @param object the object to convert to an object array
diff --git a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/style/expressions/ExpressionTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/style/expressions/ExpressionTest.java
index fb74904f96..79bcdd7b5e 100644
--- a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/style/expressions/ExpressionTest.java
+++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/style/expressions/ExpressionTest.java
@@ -1,12 +1,16 @@
package com.mapbox.mapboxsdk.style.expressions;
import android.graphics.Color;
+
import com.mapbox.mapboxsdk.style.layers.PropertyFactory;
+
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Locale;
import static com.mapbox.mapboxsdk.style.expressions.Expression.abs;
import static com.mapbox.mapboxsdk.style.expressions.Expression.acos;
@@ -19,6 +23,7 @@ import static com.mapbox.mapboxsdk.style.expressions.Expression.atan;
import static com.mapbox.mapboxsdk.style.expressions.Expression.bool;
import static com.mapbox.mapboxsdk.style.expressions.Expression.ceil;
import static com.mapbox.mapboxsdk.style.expressions.Expression.coalesce;
+import static com.mapbox.mapboxsdk.style.expressions.Expression.collator;
import static com.mapbox.mapboxsdk.style.expressions.Expression.color;
import static com.mapbox.mapboxsdk.style.expressions.Expression.concat;
import static com.mapbox.mapboxsdk.style.expressions.Expression.cos;
@@ -60,6 +65,7 @@ import static com.mapbox.mapboxsdk.style.expressions.Expression.pow;
import static com.mapbox.mapboxsdk.style.expressions.Expression.product;
import static com.mapbox.mapboxsdk.style.expressions.Expression.properties;
import static com.mapbox.mapboxsdk.style.expressions.Expression.raw;
+import static com.mapbox.mapboxsdk.style.expressions.Expression.resolvedLocale;
import static com.mapbox.mapboxsdk.style.expressions.Expression.rgb;
import static com.mapbox.mapboxsdk.style.expressions.Expression.rgba;
import static com.mapbox.mapboxsdk.style.expressions.Expression.round;
@@ -1290,4 +1296,75 @@ public class ExpressionTest {
String alpha = color.substring(0, color.length() - 1);
assertEquals("alpha value should match", 0.254f, Float.valueOf(alpha), 0.001f);
}
+
+ @Test
+ public void testCollator() {
+ Object[] expected = new Object[] {"collator",
+ new HashMap<String, Object>() {
+ {
+ put("case-sensitive", true);
+ put("diacritic-sensitive", true);
+ put("locale", "it-IT");
+ }
+ }
+ };
+ Object[] actual = collator(true, true, Locale.ITALY).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testStringCollator() {
+ String expected = "[\"collator\", {\"diacritic-sensitive\": true, \"case-sensitive\": true, \"locale\": "
+ + "\"it\"}]";
+ String actual = collator(true, true, Locale.ITALIAN).toString();
+ assertEquals("expression should match", expected, actual);
+ }
+
+ @Test
+ public void testResolvedLocale() {
+ Object[] expected = new Object[] {"resolved-locale",
+ new Object[] {"collator",
+ new HashMap<String, Object>() {
+ {
+ put("case-sensitive", false);
+ put("diacritic-sensitive", false);
+ put("locale", "it");
+ }
+ }
+ }
+ };
+ Object[] actual = resolvedLocale(collator(false, false, Locale.ITALIAN)).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testRawCollator() {
+ Object[] expected = new Object[] {"collator",
+ new HashMap<String, Object>() {
+ {
+ put("case-sensitive", true);
+ put("diacritic-sensitive", true);
+ put("locale", "it-IT");
+ }
+ }
+ };
+ Object[] actual = raw("[\"collator\", {\"diacritic-sensitive\": true, \"case-sensitive\": true, \"locale\": "
+ + "\"it-IT\"}]").toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testRawCollatorDoubleConversion() {
+ Expression expected = collator(false, false, Locale.ITALIAN);
+ Object[] actual = raw(expected.toString()).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected.toArray(), actual));
+ }
+
+ @Test
+ public void testStringNestedCollator() {
+ String expected = "[\"collator\", {\"diacritic-sensitive\": [\"==\", 2.0, 1.0], \"case-sensitive\": false,"
+ + " \"locale\": \"it\"}]";
+ String actual = collator(literal(false), eq(literal(2), literal(1)), literal("it")).toString();
+ assertEquals("expression should match", expected, actual);
+ }
} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/ExpressionTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/ExpressionTest.java
index f1f260c919..4e284cdc14 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/ExpressionTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/ExpressionTest.java
@@ -2,20 +2,30 @@ package com.mapbox.mapboxsdk.testapp.style;
import android.graphics.Color;
import android.support.test.runner.AndroidJUnit4;
+
+import com.mapbox.geojson.Point;
+import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.style.expressions.Expression;
+import com.mapbox.mapboxsdk.style.layers.CircleLayer;
import com.mapbox.mapboxsdk.style.layers.FillLayer;
+import com.mapbox.mapboxsdk.style.layers.Layer;
import com.mapbox.mapboxsdk.style.sources.GeoJsonSource;
import com.mapbox.mapboxsdk.style.sources.Source;
import com.mapbox.mapboxsdk.testapp.R;
import com.mapbox.mapboxsdk.testapp.activity.BaseActivityTest;
import com.mapbox.mapboxsdk.testapp.activity.espresso.EspressoTestActivity;
import com.mapbox.mapboxsdk.testapp.utils.ResourceUtils;
+import com.mapbox.mapboxsdk.utils.ColorUtils;
+
import org.junit.Test;
import org.junit.runner.RunWith;
-import timber.log.Timber;
import java.io.IOException;
+import timber.log.Timber;
+
+import static com.mapbox.mapboxsdk.style.expressions.Expression.collator;
+import static com.mapbox.mapboxsdk.style.expressions.Expression.eq;
import static com.mapbox.mapboxsdk.style.expressions.Expression.exponential;
import static com.mapbox.mapboxsdk.style.expressions.Expression.get;
import static com.mapbox.mapboxsdk.style.expressions.Expression.interpolate;
@@ -26,13 +36,16 @@ import static com.mapbox.mapboxsdk.style.expressions.Expression.rgba;
import static com.mapbox.mapboxsdk.style.expressions.Expression.step;
import static com.mapbox.mapboxsdk.style.expressions.Expression.stop;
import static com.mapbox.mapboxsdk.style.expressions.Expression.string;
+import static com.mapbox.mapboxsdk.style.expressions.Expression.switchCase;
import static com.mapbox.mapboxsdk.style.expressions.Expression.toColor;
import static com.mapbox.mapboxsdk.style.expressions.Expression.zoom;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.circleColor;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.fillAntialias;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.fillColor;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.fillOutlineColor;
import static com.mapbox.mapboxsdk.testapp.action.MapboxMapAction.invoke;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
@RunWith(AndroidJUnit4.class)
public class ExpressionTest extends BaseActivityTest {
@@ -204,6 +217,54 @@ public class ExpressionTest extends BaseActivityTest {
});
}
+ @Test
+ public void testCollatorExpression() {
+ validateTestSetup();
+ setupStyle();
+ invoke(mapboxMap, (uiController, mapboxMap) -> {
+ LatLng latLng = new LatLng(51, 17);
+
+ Expression expression1 = eq(literal("Łukasz"), literal("lukasz"), collator(true, true));
+ Expression expression2 = eq(literal("Łukasz"), literal("lukasz"), collator(literal(false), eq(literal(1),
+ literal(1)), literal("en")));
+ Expression expression3 = eq(literal("Łukasz"), literal("lukasz"), collator(literal(false), eq(literal(2),
+ literal(1))));
+
+ mapboxMap.addSource(new GeoJsonSource("source", Point.fromLngLat(latLng.getLongitude(), latLng.getLatitude())));
+ Layer layer = new CircleLayer("layer", "source")
+ .withProperties(circleColor(
+ switchCase(
+ expression1, literal(ColorUtils.colorToRgbaString(Color.GREEN)),
+ literal(ColorUtils.colorToRgbaString(Color.RED))
+ )
+ ));
+ mapboxMap.addLayer(layer);
+ uiController.loopMainThreadForAtLeast(1000);
+ assertFalse(mapboxMap.queryRenderedFeatures(mapboxMap.getProjection().toScreenLocation(latLng), "layer")
+ .isEmpty());
+
+ layer.setProperties(circleColor(
+ switchCase(
+ expression2, literal(ColorUtils.colorToRgbaString(Color.GREEN)),
+ literal(ColorUtils.colorToRgbaString(Color.RED))
+ )
+ ));
+ uiController.loopMainThreadForAtLeast(1000);
+ assertFalse(mapboxMap.queryRenderedFeatures(mapboxMap.getProjection().toScreenLocation(latLng), "layer")
+ .isEmpty());
+
+ layer.setProperties(circleColor(
+ switchCase(
+ expression3, literal(ColorUtils.colorToRgbaString(Color.GREEN)),
+ literal(ColorUtils.colorToRgbaString(Color.RED))
+ )
+ ));
+ uiController.loopMainThreadForAtLeast(1000);
+ assertFalse(mapboxMap.queryRenderedFeatures(mapboxMap.getProjection().toScreenLocation(latLng), "layer")
+ .isEmpty());
+ });
+ }
+
private void setupStyle() {
invoke(mapboxMap, (uiController, mapboxMap) -> {
// Add a source