diff --git a/MapboxGLAndroidSDK/src/cpp/map/image.cpp b/MapboxGLAndroidSDK/src/cpp/map/image.cpp index 10c32d257..04f5b1a35 100644 --- a/MapboxGLAndroidSDK/src/cpp/map/image.cpp +++ b/MapboxGLAndroidSDK/src/cpp/map/image.cpp @@ -13,6 +13,9 @@ mbgl::style::Image Image::getImage(jni::JNIEnv& env, const jni::Object& i static auto bufferField = javaClass.GetField>(env, "buffer"); static auto nameField = javaClass.GetField(env, "name"); static auto sdfField = javaClass.GetField(env, "sdf"); + static auto contentField = javaClass.GetField>(env, "content"); + static auto stretchXField = javaClass.GetField>(env, "stretchX"); + static auto stretchYField = javaClass.GetField>(env, "stretchY"); auto height = image.Get(env, heightField); auto width = image.Get(env, widthField); @@ -20,7 +23,9 @@ mbgl::style::Image Image::getImage(jni::JNIEnv& env, const jni::Object& i auto pixels = image.Get(env, bufferField); auto name = jni::Make(env, image.Get(env, nameField)); auto sdf = (bool) image.Get(env, sdfField); - + auto content = image.Get(env, contentField); + auto stretchX = image.Get(env, stretchXField); + auto stretchY = image.Get(env, stretchYField); jni::NullCheck(env, pixels.get()); std::size_t size = pixels.Length(env); @@ -29,8 +34,38 @@ mbgl::style::Image Image::getImage(jni::JNIEnv& env, const jni::Object& i throw mbgl::util::StyleImageException("Image pixel count mismatch"); } - jni::GetArrayRegion(env, *pixels, 0, size, reinterpret_cast(premultipliedImage.data.get())); - return mbgl::style::Image {name, std::move(premultipliedImage), pixelRatio, sdf}; + jni::GetArrayRegion(env, *pixels, 0, size, + reinterpret_cast(premultipliedImage.data.get())); + + style::ImageStretches imageStretchesX = {}; + style::ImageStretches imageStretchesY = {}; + if (stretchX.get()) { + std::size_t sizeX = stretchX.Length(env); + for (jni::jsize i = 0; i < sizeX - 1; i += 2) { + imageStretchesX.push_back({stretchX.Get(env, i), stretchX.Get(env, i + 1)}); + } + } + if (stretchY.get()) { + std::size_t sizeY = stretchY.Length(env); + for (jni::jsize i = 0; i < sizeY - 1; i += 2) { + imageStretchesY.push_back({stretchY.Get(env, i), stretchY.Get(env, i + 1)}); + } + } + + if (content) { + const style::ImageContent imageContent = style::ImageContent{content.Get(env, 0), + content.Get(env, 1), + content.Get(env, 2), + content.Get(env, 3)}; + return mbgl::style::Image{name, std::move(premultipliedImage), pixelRatio, sdf, + imageStretchesX, + imageStretchesY, + std::move(imageContent)}; + } + + return mbgl::style::Image{name, std::move(premultipliedImage), pixelRatio, sdf, + imageStretchesX, + imageStretchesY}; } void Image::registerNative(jni::JNIEnv &env) { diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Image.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Image.java index 380f78b07..8a648de31 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Image.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Image.java @@ -10,13 +10,24 @@ public class Image { private final int width; private final int height; private final boolean sdf; + private final float[] content; + private final float[] stretchX; + private final float[] stretchY; public Image(byte[] buffer, float pixelRatio, String name, int width, int height, boolean sdf) { + this(buffer, pixelRatio, name, width, height, sdf, null, null, null); + } + + public Image(byte[] buffer, float pixelRatio, String name, int width, int height, boolean sdf, + float[] stretchX, float[] stretchY, float[] content) { this.buffer = buffer; this.pixelRatio = pixelRatio; this.name = name; this.width = width; this.height = height; this.sdf = sdf; + this.content = content; + this.stretchX = stretchX; + this.stretchY = stretchY; } } diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/ImageContent.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/ImageContent.java new file mode 100644 index 000000000..4b72280c4 --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/ImageContent.java @@ -0,0 +1,66 @@ +package com.mapbox.mapboxsdk.maps; + +/** + * Describes the image content, e.g. where text can be fit into an image. + *

+ * When sizing icons with icon-text-fit, + * the icon size will be adjusted so that the this content box fits exactly around the text. + */ +public final class ImageContent { + + private final float left; + private final float top; + private final float right; + private final float bottom; + + public ImageContent(float left, + float top, + float right, + float bottom) { + this.left = left; + this.top = top; + this.right = right; + this.bottom = bottom; + } + + /** + * Get the array for this content, sorted by left, top, right, bottom. + * + * @return the content array. + */ + public float[] getContentArray() { + float[] array = new float[4]; + array[0] = left; + array[1] = top; + array[2] = right; + array[3] = bottom; + return array; + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof ImageContent)) { + return false; + } + ImageContent other = (ImageContent) obj; + return this.left == other.left + && this.top == other.top + && this.right == other.right + && this.bottom == other.bottom; + } + + @Override + public int hashCode() { + int result = (left != +0.0f ? Float.floatToIntBits(left) : 0); + result = 31 * result + (top != +0.0f ? Float.floatToIntBits(top) : 0); + result = 31 * result + (right != +0.0f ? Float.floatToIntBits(right) : 0); + result = 31 * result + (bottom != +0.0f ? Float.floatToIntBits(bottom) : 0); + return result; + } + + @Override + public String toString() { + return "[ " + "left: " + left + ", " + "top: " + top + ", " + "right: " + right + ", " + "bottom: " + bottom + " ]"; + } + +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/ImageStretches.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/ImageStretches.java new file mode 100644 index 000000000..ec3357167 --- /dev/null +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/ImageStretches.java @@ -0,0 +1,54 @@ +package com.mapbox.mapboxsdk.maps; + + +/** + * Describes the image stretch areas. + */ +public final class ImageStretches { + + private final float first; + private final float second; + + public ImageStretches(float first, + float second) { + this.first = first; + this.second = second; + } + + /** + * The first stretchable part in pixel units. + */ + public float getFirst() { + return first; + } + + /** + * The second stretchable part in pixel units. + */ + public float getSecond() { + return second; + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof ImageStretches)) { + return false; + } + ImageStretches other = (ImageStretches) obj; + return this.first == other.first + && this.second == other.second; + } + + @Override + public int hashCode() { + int result = (first != +0.0f ? Float.floatToIntBits(first) : 0); + result = 31 * result + (second != +0.0f ? Float.floatToIntBits(second) : 0); + return result; + } + + @Override + public String toString() { + return "[ " + "first: " + first + ", " + "second: " + second + " ]"; + } + +} diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Style.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Style.java index fe88e081a..3a9c0cd4f 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Style.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Style.java @@ -3,12 +3,9 @@ package com.mapbox.mapboxsdk.maps; import android.graphics.Bitmap; import android.graphics.drawable.Drawable; import android.os.AsyncTask; -import androidx.annotation.IntRange; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.annotation.StringDef; import android.util.DisplayMetrics; import android.util.Pair; + import com.mapbox.mapboxsdk.constants.MapboxConstants; import com.mapbox.mapboxsdk.style.layers.Layer; import com.mapbox.mapboxsdk.style.layers.TransitionOptions; @@ -26,6 +23,11 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import androidx.annotation.IntRange; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.StringDef; + /** * The proxy object for current map style. *

@@ -317,6 +319,20 @@ public class Style { addImage(name, image, false); } + /** + * Adds an image to be used in the map's style + * + * @param name the name of the image + * @param image the pre-multiplied Bitmap + * @param stretchX image stretch areas for x axix + * @param stretchY image stretch areas for y axix + * @param content image content for text to fit + */ + public void addImage(@NonNull String name, @NonNull Bitmap image, @NonNull List stretchX, + @NonNull List stretchY, @Nullable ImageContent content) { + addImage(name, image, false, stretchX, stretchY, content); + } + /** * Adds an drawable to be converted into a bitmap to be used in the map's style * @@ -331,6 +347,26 @@ public class Style { addImage(name, bitmap, false); } + /** + * Adds an drawable to be converted into a bitmap to be used in the map's style + * + * @param name the name of the image + * @param drawable the drawable instance to convert + * @param stretchX image stretch areas for x axix + * @param stretchY image stretch areas for y axix + * @param content image content for text to fit + */ + public void addImage(@NonNull String name, @NonNull Drawable drawable, + @NonNull List stretchX, + @NonNull List stretchY, + @Nullable ImageContent content) { + Bitmap bitmap = BitmapUtils.getBitmapFromDrawable(drawable); + if (bitmap == null) { + throw new IllegalArgumentException("Provided drawable couldn't be converted to a Bitmap."); + } + addImage(name, bitmap, false, stretchX, stretchY, content); + } + /** * Adds an image to be used in the map's style * @@ -343,6 +379,25 @@ public class Style { nativeMap.addImages(new Image[] {toImage(new Builder.ImageWrapper(name, bitmap, sdf))}); } + /** + * Adds an image to be used in the map's style + * + * @param name the name of the image + * @param bitmap the pre-multiplied Bitmap + * @param sdf the flag indicating image is an SDF or template image + * @param stretchX image stretch areas for x axix + * @param stretchY image stretch areas for y axix + * @param content image content for text to fit + */ + public void addImage(@NonNull final String name, @NonNull Bitmap bitmap, boolean sdf, + @NonNull List stretchX, + @NonNull List stretchY, + @Nullable ImageContent content) { + validateState("addImage"); + nativeMap.addImages(new Image[] { + toImage(new Builder.ImageWrapper(name, bitmap, sdf, stretchX, stretchY, content))}); + } + /** * Adds an image asynchronously, to be used in the map's style. * @@ -353,6 +408,22 @@ public class Style { addImageAsync(name, image, false); } + /** + * Adds an image asynchronously, to be used in the map's style. + * + * @param name the name of the image + * @param image the pre-multiplied Bitmap + * @param stretchX image stretch areas for x axix + * @param stretchY image stretch areas for y axix + * @param content image content for text to fit + */ + public void addImageAsync(@NonNull String name, @NonNull Bitmap image, + @NonNull List stretchX, + @NonNull List stretchY, + @Nullable ImageContent content) { + addImageAsync(name, image, false, stretchX, stretchY, content); + } + /** * Adds an drawable asynchronously, to be converted into a bitmap to be used in the map's style. * @@ -367,6 +438,27 @@ public class Style { addImageAsync(name, bitmap, false); } + + /** + * Adds an drawable asynchronously, to be converted into a bitmap to be used in the map's style. + * + * @param name the name of the image + * @param drawable the drawable instance to convert + * @param stretchX image stretch areas for x axix + * @param stretchY image stretch areas for y axix + * @param content image content for text to fit + */ + public void addImageAsync(@NonNull String name, @NonNull Drawable drawable, + @NonNull List stretchX, + @NonNull List stretchY, + @Nullable ImageContent content) { + Bitmap bitmap = BitmapUtils.getBitmapFromDrawable(drawable); + if (bitmap == null) { + throw new IllegalArgumentException("Provided drawable couldn't be converted to a Bitmap."); + } + addImageAsync(name, bitmap, false, stretchX, stretchY, content); + } + /** * Adds an image asynchronously, to be used in the map's style. * @@ -379,6 +471,25 @@ public class Style { new BitmapImageConversionTask(nativeMap).execute(new Builder.ImageWrapper(name, bitmap, sdf)); } + /** + * Adds an image asynchronously, to be used in the map's style. + * + * @param name the name of the image + * @param bitmap the pre-multiplied Bitmap + * @param sdf the flag indicating image is an SDF or template image + * @param stretchX image stretch areas for x axix + * @param stretchY image stretch areas for y axix + * @param content image content for text to fit + */ + public void addImageAsync(@NonNull final String name, @NonNull Bitmap bitmap, boolean sdf, + @NonNull List stretchX, + @NonNull List stretchY, + @Nullable ImageContent content) { + validateState("addImage"); + new BitmapImageConversionTask(nativeMap) + .execute(new Builder.ImageWrapper(name, bitmap, sdf, stretchX, stretchY, content)); + } + /** * Adds images to be used in the map's style. * @@ -388,6 +499,19 @@ public class Style { addImages(images, false); } + /** + * Adds images to be used in the map's style. + * + * @param images the map of images to add + * @param stretchX image stretch areas for x axix + * @param stretchY image stretch areas for y axix + * @param content image content for text to fit + */ + public void addImages(@NonNull HashMap images, @NonNull List stretchX, + @NonNull List stretchY, @Nullable ImageContent content) { + addImages(images, false, stretchX, stretchY, content); + } + /** * Adds images to be used in the map's style. * @@ -406,6 +530,31 @@ public class Style { nativeMap.addImages(convertedImages); } + /** + * Adds images to be used in the map's style. + * + * @param images the map of images to add + * @param sdf the flag indicating image is an SDF or template image + * @param stretchX image stretch areas for x axix + * @param stretchY image stretch areas for y axix + * @param content image content for text to fit + */ + public void addImages(@NonNull HashMap images, boolean sdf, + @NonNull List stretchX, + @NonNull List stretchY, + @Nullable ImageContent content) { + validateState("addImage"); + Image[] convertedImages = new Image[images.size()]; + int index = 0; + for (Builder.ImageWrapper imageWrapper + : Builder.ImageWrapper.convertToImageArray(images, sdf, stretchX, stretchY, content)) { + convertedImages[index] = toImage(imageWrapper); + index++; + } + + nativeMap.addImages(convertedImages); + } + /** * Adds images asynchronously, to be used in the map's style. * @@ -415,6 +564,19 @@ public class Style { addImagesAsync(images, false); } + /** + * Adds images asynchronously, to be used in the map's style. + * + * @param images the map of images to add + * @param stretchX image stretch areas for x axix + * @param stretchY image stretch areas for y axix + * @param content image content for text to fit + */ + public void addImagesAsync(@NonNull HashMap images, @NonNull List stretchX, + @NonNull List stretchY, @Nullable ImageContent content) { + addImagesAsync(images, false, stretchX, stretchY, content); + } + /** * Adds images asynchronously, to be used in the map's style. * @@ -426,6 +588,24 @@ public class Style { new BitmapImageConversionTask(nativeMap).execute(Builder.ImageWrapper.convertToImageArray(images, sdf)); } + /** + * Adds images asynchronously, to be used in the map's style. + * + * @param images the map of images to add + * @param sdf the flag indicating image is an SDF or template image + * @param stretchX image stretch areas for x axix + * @param stretchY image stretch areas for y axix + * @param content image content for text to fit + */ + public void addImagesAsync(@NonNull HashMap images, boolean sdf, + @NonNull List stretchX, + @NonNull List stretchY, + @Nullable ImageContent content) { + validateState("addImages"); + new BitmapImageConversionTask(nativeMap) + .execute(Builder.ImageWrapper.convertToImageArray(images, sdf, stretchX, stretchY, content)); + } + /** * Removes an image from the map's style. * @@ -830,6 +1010,26 @@ public class Style { return this.withImage(id, bitmap, false); } + /** + * Will add the drawable as image when the map style has loaded. + * + * @param id the id for the image + * @param drawable the drawable to be converted and added + * @param stretchX image stretch areas for x axix + * @param stretchY image stretch areas for y axix + * @param content image content for text to fit + * @return this + */ + @NonNull + public Builder withImage(@NonNull String id, @NonNull Drawable drawable, @NonNull List stretchX, + @NonNull List stretchY, @Nullable ImageContent content) { + Bitmap bitmap = BitmapUtils.getBitmapFromDrawable(drawable); + if (bitmap == null) { + throw new IllegalArgumentException("Provided drawable couldn't be converted to a Bitmap."); + } + return this.withImage(id, bitmap, false, stretchX, stretchY, content); + } + /** * Will add the drawables as images when the map style has loaded. * @@ -853,6 +1053,22 @@ public class Style { return this.withImage(id, image, false); } + /** + * Will add the image when the map style has loaded. + * + * @param id the id for the image + * @param image the image to be added + * @param stretchX image stretch areas for x axix + * @param stretchY image stretch areas for y axix + * @param content image content for text to fit + * @return this + */ + @NonNull + public Builder withImage(@NonNull String id, @NonNull Bitmap image, @NonNull List stretchX, + @NonNull List stretchY, @Nullable ImageContent content) { + return this.withImage(id, image, false, stretchX, stretchY, content); + } + /** * Will add the images when the map style has loaded. * @@ -884,6 +1100,29 @@ public class Style { return this.withImage(id, bitmap, sdf); } + /** + * Will add the drawable as image when the map style has loaded. + * + * @param id the id for the image + * @param drawable the drawable to be converted and added + * @param sdf the flag indicating image is an SDF or template image + * @param stretchX image stretch areas for x axix + * @param stretchY image stretch areas for y axix + * @param content image content for text to fit + * @return this + */ + @NonNull + public Builder withImage(@NonNull String id, @NonNull Drawable drawable, boolean sdf, + @NonNull List stretchX, + @NonNull List stretchY, + @Nullable ImageContent content) { + Bitmap bitmap = BitmapUtils.getBitmapFromDrawable(drawable); + if (bitmap == null) { + throw new IllegalArgumentException("Provided drawable couldn't be converted to a Bitmap."); + } + return this.withImage(id, bitmap, sdf, stretchX, stretchY, content); + } + /** * Will add the drawables as images when the map style has loaded. * @@ -917,6 +1156,25 @@ public class Style { return this; } + /** + * Will add the image when the map style has loaded. + * + * @param id the id for the image + * @param image the image to be added + * @param sdf the flag indicating image is an SDF or template image + * @param stretchX image stretch areas for x axix + * @param stretchY image stretch areas for y axix + * @param content image content for text to fit + * @return this + */ + @NonNull + public Builder withImage(@NonNull String id, @NonNull Bitmap image, boolean sdf, + @NonNull List stretchX, + @NonNull List stretchY, @Nullable ImageContent content) { + images.add(new ImageWrapper(id, image, sdf, stretchX, stretchY, content)); + return this; + } + /** * Will add the images when the map style has loaded. * @@ -967,11 +1225,22 @@ public class Style { Bitmap bitmap; String id; boolean sdf; + List stretchX; + List stretchY; + ImageContent content; public ImageWrapper(String id, Bitmap bitmap, boolean sdf) { + this(id, bitmap, sdf, null, null, null); + } + + public ImageWrapper(String id, Bitmap bitmap, boolean sdf, List stretchX, + List stretchY, ImageContent content) { this.id = id; this.bitmap = bitmap; this.sdf = sdf; + this.stretchX = stretchX; + this.stretchY = stretchY; + this.content = content; } public Bitmap getBitmap() { @@ -986,6 +1255,18 @@ public class Style { return sdf; } + public List getStretchX() { + return stretchX; + } + + public List getStretchY() { + return stretchY; + } + + public ImageContent getContent() { + return content; + } + public static ImageWrapper[] convertToImageArray(HashMap bitmapHashMap, boolean sdf) { ImageWrapper[] images = new ImageWrapper[bitmapHashMap.size()]; List keyList = new ArrayList<>(bitmapHashMap.keySet()); @@ -995,6 +1276,19 @@ public class Style { } return images; } + + public static ImageWrapper[] convertToImageArray(HashMap bitmapHashMap, boolean sdf, + List stretchX, + List stretchY, + ImageContent content) { + ImageWrapper[] images = new ImageWrapper[bitmapHashMap.size()]; + List keyList = new ArrayList<>(bitmapHashMap.keySet()); + for (int i = 0; i < bitmapHashMap.size(); i++) { + String id = keyList.get(i); + images[i] = new ImageWrapper(id, bitmapHashMap.get(id), sdf, stretchX, stretchY, content); + } + return images; + } } public class LayerWrapper { @@ -1059,6 +1353,24 @@ public class Style { bitmap.copyPixelsToBuffer(buffer); float pixelRatio = (float) bitmap.getDensity() / DisplayMetrics.DENSITY_DEFAULT; + if (imageWrapper.getStretchX() != null && imageWrapper.getStretchY() != null) { + float[] arrayX = new float[imageWrapper.getStretchX().size() * 2]; + for (int i = 0; i < imageWrapper.getStretchX().size(); i++) { + arrayX[i * 2] = imageWrapper.getStretchX().get(i).getFirst(); + arrayX[i * 2 + 1] = imageWrapper.getStretchX().get(i).getSecond(); + } + + float[] arrayY = new float[imageWrapper.getStretchY().size() * 2]; + for (int i = 0; i < imageWrapper.getStretchY().size(); i++) { + arrayY[i * 2] = imageWrapper.getStretchY().get(i).getFirst(); + arrayY[i * 2 + 1] = imageWrapper.getStretchY().get(i).getSecond(); + } + return new Image(buffer.array(), pixelRatio, imageWrapper.id, + bitmap.getWidth(), bitmap.getHeight(), imageWrapper.sdf, arrayX, arrayY, + imageWrapper.getContent() == null ? null : imageWrapper.getContent().getContentArray() + ); + } + return new Image(buffer.array(), pixelRatio, imageWrapper.id, bitmap.getWidth(), bitmap.getHeight(), imageWrapper.sdf ); diff --git a/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml b/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml index c5d2cb098..e89902d7e 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml +++ b/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml @@ -1123,6 +1123,18 @@ android:name="android.support.PARENT_ACTIVITY" android:value=".activity.FeatureOverviewActivity" /> + + + + { + Bitmap popup = BitmapUtils.getBitmapFromDrawable(getResources().getDrawable(R.drawable.popup)); + Bitmap popupDebug = BitmapUtils.getBitmapFromDrawable(getResources().getDrawable(R.drawable.popup_debug)); + + // The two (blue) columns of pixels that can be stretched horizontally: + // - the pixels between x: 25 and x: 55 can be stretched + // - the pixels between x: 85 and x: 115 can be stretched. + List stretchX = new ArrayList<>(); + stretchX.add(new ImageStretches(25, 55)); + stretchX.add(new ImageStretches(85, 115)); + + // The one (red) row of pixels that can be stretched vertically: + // - the pixels between y: 25 and y: 100 can be stretched + List stretchY = new ArrayList<>(); + stretchY.add(new ImageStretches(25, 100)); + + // This part of the image that can contain text ([x1, y1, x2, y2]): + ImageContent content = new ImageContent(25, 25, 115, 100); + + style.addImage(NAME_POPUP, popup, stretchX, stretchY, content); + style.addImage(NAME_POPUP_DEBUG, popupDebug, stretchX, stretchY, content); + new LoadFeatureTask(StretchableImageActivity.this).execute(); + }); + } + + private void onFeatureLoaded(String json) { + if (json == null) { + Timber.e("json is null."); + return; + } + + Style style = mapboxMap.getStyle(); + if (style != null) { + FeatureCollection featureCollection = FeatureCollection.fromJson(json); + GeoJsonSource stretchSource = new GeoJsonSource(STRETCH_SOURCE, featureCollection); + SymbolLayer stretchLayer = new SymbolLayer(STRETCH_LAYER, STRETCH_SOURCE) + .withProperties( + textField(get("name")), + iconImage(get("image-name")), + iconAllowOverlap(true), + textAllowOverlap(true), + iconTextFit(ICON_TEXT_FIT_BOTH)); + + // the original, unstretched image for comparison + Point point = Point.fromLngLat(-70, 0); + Feature feature = Feature.fromGeometry(point); + FeatureCollection originalCollection = FeatureCollection.fromFeature(feature); + GeoJsonSource originalSource = new GeoJsonSource(ORIGINAL_SOURCE, originalCollection); + SymbolLayer originalLayer = new SymbolLayer(ORIGINAL_LAYER, ORIGINAL_SOURCE); + + style.addSource(stretchSource); + style.addSource(originalSource); + style.addLayer(stretchLayer); + style.addLayer(originalLayer); + } + } + + private static class LoadFeatureTask extends AsyncTask { + + private WeakReference activity; + + private LoadFeatureTask(StretchableImageActivity activity) { + this.activity = new WeakReference<>(activity); + } + + @Override + protected String doInBackground(Void... params) { + StretchableImageActivity activity = this.activity.get(); + if (activity != null) { + String json = null; + try { + json = GeoParseUtil.loadStringFromAssets(activity.getApplicationContext(), "stretchable_image.geojson"); + } catch (IOException exception) { + Timber.e(exception, "Could not read feature"); + } + + return json; + } + return null; + } + + @Override + protected void onPostExecute(String json) { + super.onPostExecute(json); + StretchableImageActivity activity = this.activity.get(); + if (activity != null) { + activity.onFeatureLoaded(json); + } + } + } + + + @Override + protected void onStart() { + super.onStart(); + mapView.onStart(); + } + + @Override + protected void onResume() { + super.onResume(); + mapView.onResume(); + } + + @Override + protected void onPause() { + super.onPause(); + mapView.onPause(); + } + + @Override + protected void onStop() { + super.onStop(); + mapView.onStop(); + } + + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + mapView.onSaveInstanceState(outState); + } + + @Override + public void onLowMemory() { + super.onLowMemory(); + mapView.onLowMemory(); + } + + @Override + public void onDestroy() { + super.onDestroy(); + mapView.onDestroy(); + } + +} diff --git a/MapboxGLAndroidSDKTestApp/src/main/res/drawable-hdpi/popup.png b/MapboxGLAndroidSDKTestApp/src/main/res/drawable-hdpi/popup.png new file mode 100644 index 000000000..41f38e873 Binary files /dev/null and b/MapboxGLAndroidSDKTestApp/src/main/res/drawable-hdpi/popup.png differ diff --git a/MapboxGLAndroidSDKTestApp/src/main/res/drawable-hdpi/popup_debug.png b/MapboxGLAndroidSDKTestApp/src/main/res/drawable-hdpi/popup_debug.png new file mode 100644 index 000000000..f6667408f Binary files /dev/null and b/MapboxGLAndroidSDKTestApp/src/main/res/drawable-hdpi/popup_debug.png differ diff --git a/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_stretchable_image.xml b/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_stretchable_image.xml new file mode 100644 index 000000000..09b10bf1d --- /dev/null +++ b/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_stretchable_image.xml @@ -0,0 +1,14 @@ + + + + + + diff --git a/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml b/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml index f90653ffe..6f61fb649 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml +++ b/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml @@ -20,6 +20,7 @@ Offline Map example Download an offline region. Usage of the within expression on a buffered geometry + Usage of the stretchable image as a background for text. Update metadata example Delete region example Change resources cache path example diff --git a/MapboxGLAndroidSDKTestApp/src/main/res/values/titles.xml b/MapboxGLAndroidSDKTestApp/src/main/res/values/titles.xml index 637d3b774..23c227f23 100644 --- a/MapboxGLAndroidSDKTestApp/src/main/res/values/titles.xml +++ b/MapboxGLAndroidSDKTestApp/src/main/res/values/titles.xml @@ -90,4 +90,5 @@ Physical Unit Circle Download region Within expression + Stretchable Image \ No newline at end of file