[android] - harden orientation changes (#9128)
This commit is contained in:
@@ -1,15 +1,18 @@
|
||||
package com.mapbox.mapboxsdk.annotations;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.util.DisplayMetrics;
|
||||
|
||||
import com.mapbox.mapboxsdk.maps.MapView;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* Icon is the visual representation of a {@link Marker} on a {@link MapView}.
|
||||
* Icon is the visual representation of a Marker on a MapView.
|
||||
*
|
||||
* @see Marker
|
||||
* @see IconFactory
|
||||
*/
|
||||
public class Icon {
|
||||
|
||||
private Bitmap mBitmap;
|
||||
private String mId;
|
||||
|
||||
@@ -19,29 +22,67 @@ public class Icon {
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link String} identifier for this {@link Icon}.
|
||||
* String identifier for this icon.
|
||||
*
|
||||
* @return {@link String} identifier for this {@link Icon}.
|
||||
* @return String identifier for this icon.
|
||||
*/
|
||||
public String getId() {
|
||||
return mId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the {@link Bitmap} being used for this {@link Icon}.
|
||||
* Get the bitmap being used for this icon.
|
||||
*
|
||||
* @return The {@link Bitmap} being used for the {@link Icon}.
|
||||
* @return The bitmap being used for the icon.
|
||||
*/
|
||||
public Bitmap getBitmap() {
|
||||
if (mBitmap.getConfig() != Bitmap.Config.ARGB_8888) {
|
||||
mBitmap = mBitmap.copy(Bitmap.Config.ARGB_8888, false);
|
||||
}
|
||||
return mBitmap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares this {@link Icon} object with another {@link Icon} and determines if they match.
|
||||
* Get the icon bitmap scale.
|
||||
* <p>
|
||||
* Requires the bitmap to be set before calling this method.
|
||||
* </p>
|
||||
*
|
||||
* @param object Another {@link Icon} to compare with this object.
|
||||
* @return True if the {@link Icon} being passed in matches this {@link Icon} object. Else,
|
||||
* false.
|
||||
* @return the scale of the bitmap
|
||||
*/
|
||||
public float getScale() {
|
||||
if (mBitmap == null) {
|
||||
throw new IllegalStateException("Required to set a Icon before calling getScale");
|
||||
}
|
||||
float density = mBitmap.getDensity();
|
||||
if (density == Bitmap.DENSITY_NONE) {
|
||||
density = DisplayMetrics.DENSITY_DEFAULT;
|
||||
}
|
||||
return density / DisplayMetrics.DENSITY_DEFAULT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the icon bitmap bytes.
|
||||
* <p>
|
||||
* Requires the bitmap to be set before calling this method.
|
||||
* </p>
|
||||
*
|
||||
* @return the bytes of the bitmap
|
||||
*/
|
||||
public byte[] toBytes() {
|
||||
if (mBitmap == null) {
|
||||
throw new IllegalStateException("Required to set a Icon before calling toBytes");
|
||||
}
|
||||
ByteBuffer buffer = ByteBuffer.allocate(mBitmap.getRowBytes() * mBitmap.getHeight());
|
||||
mBitmap.copyPixelsToBuffer(buffer);
|
||||
return buffer.array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares this icon object with another icon and determines if they match.
|
||||
*
|
||||
* @param object Another iconi to compare with this object.
|
||||
* @return True if the icon being passed in matches this icon object. Else, false.
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object object) {
|
||||
@@ -53,11 +94,7 @@ public class Icon {
|
||||
}
|
||||
|
||||
Icon icon = (Icon) object;
|
||||
|
||||
if (!mBitmap.equals(icon.mBitmap)) {
|
||||
return false;
|
||||
}
|
||||
return mId.equals(icon.mId);
|
||||
return mBitmap.equals(icon.mBitmap) && mId.equals(icon.mId);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.mapbox.mapboxsdk.annotations;
|
||||
import android.support.annotation.FloatRange;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import com.mapbox.mapboxsdk.Mapbox;
|
||||
import com.mapbox.mapboxsdk.constants.MapboxConstants;
|
||||
import com.mapbox.mapboxsdk.geometry.LatLng;
|
||||
import com.mapbox.mapboxsdk.maps.MapboxMap;
|
||||
@@ -361,6 +362,9 @@ public class MarkerView extends Marker {
|
||||
*/
|
||||
@Override
|
||||
public Icon getIcon() {
|
||||
if (markerViewIcon == null) {
|
||||
setIcon(IconFactory.getInstance(Mapbox.getApplicationContext()).defaultMarkerView());
|
||||
}
|
||||
return markerViewIcon;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
package com.mapbox.mapboxsdk.maps;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.util.DisplayMetrics;
|
||||
|
||||
import com.mapbox.mapboxsdk.Mapbox;
|
||||
import com.mapbox.mapboxsdk.annotations.Icon;
|
||||
import com.mapbox.mapboxsdk.annotations.IconFactory;
|
||||
import com.mapbox.mapboxsdk.annotations.Marker;
|
||||
import com.mapbox.mapboxsdk.annotations.MarkerView;
|
||||
import com.mapbox.mapboxsdk.exceptions.IconBitmapChangedException;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@@ -41,113 +40,28 @@ class IconManager {
|
||||
|
||||
Icon loadIconForMarker(Marker marker) {
|
||||
Icon icon = marker.getIcon();
|
||||
|
||||
// calculating average before adding
|
||||
int iconSize = icons.size() + 1;
|
||||
|
||||
// TODO replace former if case with anchor implementation,
|
||||
// current workaround for having extra pixels is diving height by 2
|
||||
if (icon == null) {
|
||||
icon = IconFactory.getInstance(nativeMapView.getContext()).defaultMarker();
|
||||
Bitmap bitmap = icon.getBitmap();
|
||||
averageIconHeight = averageIconHeight + (bitmap.getHeight() / 2 - averageIconHeight) / iconSize;
|
||||
averageIconWidth = averageIconWidth + (bitmap.getWidth() - averageIconWidth) / iconSize;
|
||||
marker.setIcon(icon);
|
||||
// TODO replace with anchor implementation, we are faking an anchor by adding extra pixels and diving height by 2
|
||||
// TODO we can move this code afterwards to getIcon as with MarkerView.getIcon
|
||||
icon = loadDefaultIconForMarker(marker);
|
||||
} else {
|
||||
Bitmap bitmap = icon.getBitmap();
|
||||
averageIconHeight = averageIconHeight + (bitmap.getHeight() - averageIconHeight) / iconSize;
|
||||
averageIconWidth = averageIconWidth + (bitmap.getWidth() - averageIconWidth) / iconSize;
|
||||
}
|
||||
|
||||
if (!icons.contains(icon)) {
|
||||
icons.add(icon);
|
||||
loadIcon(icon);
|
||||
} else {
|
||||
Icon oldIcon = icons.get(icons.indexOf(icon));
|
||||
if (!oldIcon.getBitmap().sameAs(icon.getBitmap())) {
|
||||
throw new IconBitmapChangedException();
|
||||
}
|
||||
updateAverageIconSize(icon);
|
||||
}
|
||||
addIcon(icon);
|
||||
return icon;
|
||||
}
|
||||
|
||||
Icon loadIconForMarkerView(MarkerView marker) {
|
||||
void loadIconForMarkerView(MarkerView marker) {
|
||||
Icon icon = marker.getIcon();
|
||||
int iconSize = icons.size() + 1;
|
||||
if (icon == null) {
|
||||
icon = IconFactory.getInstance(nativeMapView.getContext()).defaultMarkerView();
|
||||
marker.setIcon(icon);
|
||||
}
|
||||
Bitmap bitmap = icon.getBitmap();
|
||||
averageIconHeight = averageIconHeight + (bitmap.getHeight() - averageIconHeight) / iconSize;
|
||||
averageIconWidth = averageIconWidth + (bitmap.getWidth() - averageIconWidth) / iconSize;
|
||||
if (!icons.contains(icon)) {
|
||||
icons.add(icon);
|
||||
} else {
|
||||
Icon oldIcon = icons.get(icons.indexOf(icon));
|
||||
if (!oldIcon.getBitmap().sameAs(icon.getBitmap())) {
|
||||
throw new IconBitmapChangedException();
|
||||
}
|
||||
}
|
||||
return icon;
|
||||
updateAverageIconSize(bitmap);
|
||||
addIcon(icon, false);
|
||||
}
|
||||
|
||||
int getTopOffsetPixelsForIcon(Icon icon) {
|
||||
return (int) (nativeMapView.getTopOffsetPixelsForAnnotationSymbol(icon.getId()) * nativeMapView.getPixelRatio());
|
||||
}
|
||||
|
||||
void loadIcon(Icon icon) {
|
||||
Bitmap bitmap = icon.getBitmap();
|
||||
String id = icon.getId();
|
||||
if (bitmap.getConfig() != Bitmap.Config.ARGB_8888) {
|
||||
bitmap = bitmap.copy(Bitmap.Config.ARGB_8888, false);
|
||||
}
|
||||
ByteBuffer buffer = ByteBuffer.allocate(bitmap.getRowBytes() * bitmap.getHeight());
|
||||
bitmap.copyPixelsToBuffer(buffer);
|
||||
|
||||
float density = bitmap.getDensity();
|
||||
if (density == Bitmap.DENSITY_NONE) {
|
||||
density = DisplayMetrics.DENSITY_DEFAULT;
|
||||
}
|
||||
float scale = density / DisplayMetrics.DENSITY_DEFAULT;
|
||||
nativeMapView.addAnnotationIcon(
|
||||
id,
|
||||
bitmap.getWidth(),
|
||||
bitmap.getHeight(),
|
||||
scale, buffer.array());
|
||||
}
|
||||
|
||||
void reloadIcons() {
|
||||
int count = icons.size();
|
||||
for (int i = 0; i < count; i++) {
|
||||
Icon icon = icons.get(i);
|
||||
loadIcon(icon);
|
||||
}
|
||||
}
|
||||
|
||||
void ensureIconLoaded(Marker marker, MapboxMap mapboxMap) {
|
||||
Icon icon = marker.getIcon();
|
||||
if (icon == null) {
|
||||
icon = IconFactory.getInstance(nativeMapView.getContext()).defaultMarker();
|
||||
marker.setIcon(icon);
|
||||
}
|
||||
if (!icons.contains(icon)) {
|
||||
icons.add(icon);
|
||||
loadIcon(icon);
|
||||
} else {
|
||||
Icon oldIcon = icons.get(icons.indexOf(icon));
|
||||
if (!oldIcon.getBitmap().sameAs(icon.getBitmap())) {
|
||||
throw new IconBitmapChangedException();
|
||||
}
|
||||
}
|
||||
|
||||
// this seems to be a costly operation according to the profiler so I'm trying to save some calls
|
||||
Marker previousMarker = marker.getId() != -1 ? (Marker) mapboxMap.getAnnotation(marker.getId()) : null;
|
||||
if (previousMarker == null || previousMarker.getIcon() == null || previousMarker.getIcon() != marker.getIcon()) {
|
||||
marker.setTopOffsetPixels(getTopOffsetPixelsForIcon(icon));
|
||||
}
|
||||
}
|
||||
|
||||
int getAverageIconHeight() {
|
||||
return averageIconHeight;
|
||||
}
|
||||
@@ -155,4 +69,80 @@ class IconManager {
|
||||
int getAverageIconWidth() {
|
||||
return averageIconWidth;
|
||||
}
|
||||
|
||||
private Icon loadDefaultIconForMarker(Marker marker) {
|
||||
Icon icon = IconFactory.getInstance(Mapbox.getApplicationContext()).defaultMarker();
|
||||
Bitmap bitmap = icon.getBitmap();
|
||||
updateAverageIconSize(bitmap.getWidth(), bitmap.getHeight() / 2);
|
||||
marker.setIcon(icon);
|
||||
return icon;
|
||||
}
|
||||
|
||||
private void addIcon(Icon icon) {
|
||||
addIcon(icon, true);
|
||||
}
|
||||
|
||||
private void addIcon(Icon icon, boolean addIconToMap) {
|
||||
if (!icons.contains(icon)) {
|
||||
icons.add(icon);
|
||||
if (addIconToMap) {
|
||||
loadIcon(icon);
|
||||
}
|
||||
} else {
|
||||
validateIconChanged(icon);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateAverageIconSize(Icon icon) {
|
||||
updateAverageIconSize(icon.getBitmap());
|
||||
}
|
||||
|
||||
private void updateAverageIconSize(Bitmap bitmap) {
|
||||
updateAverageIconSize(bitmap.getWidth(), bitmap.getHeight());
|
||||
}
|
||||
|
||||
private void updateAverageIconSize(int width, int height) {
|
||||
int iconSize = icons.size() + 1;
|
||||
averageIconHeight = averageIconHeight + (height - averageIconHeight) / iconSize;
|
||||
averageIconWidth = averageIconWidth + (width - averageIconWidth) / iconSize;
|
||||
}
|
||||
|
||||
private void loadIcon(Icon icon) {
|
||||
Bitmap bitmap = icon.getBitmap();
|
||||
nativeMapView.addAnnotationIcon(icon.getId(),
|
||||
bitmap.getWidth(),
|
||||
bitmap.getHeight(),
|
||||
icon.getScale(),
|
||||
icon.toBytes());
|
||||
}
|
||||
|
||||
void reloadIcons() {
|
||||
for (Icon icon : icons) {
|
||||
loadIcon(icon);
|
||||
}
|
||||
}
|
||||
|
||||
private void validateIconChanged(Icon icon) {
|
||||
Icon oldIcon = icons.get(icons.indexOf(icon));
|
||||
if (!oldIcon.getBitmap().sameAs(icon.getBitmap())) {
|
||||
throw new IconBitmapChangedException();
|
||||
}
|
||||
}
|
||||
|
||||
void ensureIconLoaded(Marker marker, MapboxMap mapboxMap) {
|
||||
Icon icon = marker.getIcon();
|
||||
if (icon == null) {
|
||||
icon = loadDefaultIconForMarker(marker);
|
||||
}
|
||||
addIcon(icon);
|
||||
setTopOffsetPixels(marker, mapboxMap, icon);
|
||||
}
|
||||
|
||||
private void setTopOffsetPixels(Marker marker, MapboxMap mapboxMap, Icon icon) {
|
||||
// this seems to be a costly operation according to the profiler so I'm trying to save some calls
|
||||
Marker previousMarker = marker.getId() != -1 ? (Marker) mapboxMap.getAnnotation(marker.getId()) : null;
|
||||
if (previousMarker == null || previousMarker.getIcon() == null || previousMarker.getIcon() != marker.getIcon()) {
|
||||
marker.setTopOffsetPixels(getTopOffsetPixelsForIcon(icon));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -897,10 +897,6 @@ final class NativeMapView {
|
||||
return pixelRatio;
|
||||
}
|
||||
|
||||
public Context getContext() {
|
||||
return mapView.getContext();
|
||||
}
|
||||
|
||||
//
|
||||
// Callbacks
|
||||
//
|
||||
|
||||
Reference in New Issue
Block a user