diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/MapLibreApplication.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/MapLibreApplication.kt index 1c501263e..ad3155059 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/MapLibreApplication.kt +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/MapLibreApplication.kt @@ -57,7 +57,9 @@ class MapLibreApplication : MultiDexApplication() { private fun initializeMapbox() { val apiKey = ApiKeyUtils.getApiKey(applicationContext) - validateApiKey(apiKey) + if (apiKey != null) { + validateApiKey(apiKey) + } Mapbox.getInstance(applicationContext, apiKey, TILE_SERVER) TileLoadingMeasurementUtils.setUpTileLoadingMeasurement() MapStrictMode.setStrictModeEnabled(true) diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/LatLngBoundsActivity.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/LatLngBoundsActivity.kt index 60c1cef4c..aa08b72dd 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/LatLngBoundsActivity.kt +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/LatLngBoundsActivity.kt @@ -18,7 +18,7 @@ import com.mapbox.mapboxsdk.style.layers.SymbolLayer import com.mapbox.mapboxsdk.style.sources.GeoJsonSource import com.mapbox.mapboxsdk.testapp.R import com.mapbox.mapboxsdk.testapp.databinding.ActivityLatlngboundsBinding -import com.mapbox.mapboxsdk.testapp.utils.GeoParseUtil.loadStringFromAssets +import com.mapbox.mapboxsdk.testapp.utils.GeoParseUtil import com.mapbox.mapboxsdk.utils.BitmapUtils import java.net.URISyntaxException @@ -52,7 +52,7 @@ class LatLngBoundsActivity : AppCompatActivity() { mapboxMap = map val featureCollection: FeatureCollection = - fromJson(loadStringFromAssets(this, "points-sf.geojson")) + fromJson(GeoParseUtil.loadStringFromAssets(this, "points-sf.geojson")) bounds = createBounds(featureCollection) map.getCameraForLatLngBounds(bounds, createPadding(peekHeight))?.let { diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/OfflineActivity.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/OfflineActivity.kt index e4865d1d8..fd385f133 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/OfflineActivity.kt +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/OfflineActivity.kt @@ -209,21 +209,23 @@ class OfflineActivity : AppCompatActivity(), DownloadRegionDialogListener { val metadata = OfflineUtils.convertRegionName(regionName) // Create region - offlineManager!!.createOfflineRegion( - definition, - metadata, - object : CreateOfflineRegionCallback { - override fun onCreate(offlineRegion: OfflineRegion) { - Timber.d("Offline region created: %s", regionName) - this@OfflineActivity.offlineRegion = offlineRegion - launchDownload() - } + if (metadata != null) { + offlineManager!!.createOfflineRegion( + definition, + metadata, + object : CreateOfflineRegionCallback { + override fun onCreate(offlineRegion: OfflineRegion) { + Timber.d("Offline region created: %s", regionName) + this@OfflineActivity.offlineRegion = offlineRegion + launchDownload() + } - override fun onError(error: String) { - Timber.e("Error: %s", error) + override fun onError(error: String) { + Timber.e("Error: %s", error) + } } - } - ) + ) + } } private fun launchDownload() { @@ -308,7 +310,7 @@ class OfflineActivity : AppCompatActivity(), DownloadRegionDialogListener { companion object { // JSON encoding/decoding - const val JSON_CHARSET = "UTF-8" + val JSON_CHARSET = Charsets.UTF_8 const val JSON_FIELD_REGION_NAME = "FIELD_REGION_NAME" // Style URL diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/UpdateMetadataActivity.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/UpdateMetadataActivity.kt index 8a58424df..18fe60d84 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/UpdateMetadataActivity.kt +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/UpdateMetadataActivity.kt @@ -55,10 +55,12 @@ class UpdateMetadataActivity : builder.setPositiveButton( "OK" ) { dialog: DialogInterface?, which: Int -> - updateMetadata( - region, - OfflineUtils.convertRegionName(input.text.toString()) - ) + OfflineUtils.convertRegionName(input.text.toString())?.let { + updateMetadata( + region, + it + ) + } } builder.setNegativeButton("Cancel") { dialog: DialogInterface, which: Int -> dialog.cancel() } builder.show() diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/ApiKeyUtils.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/ApiKeyUtils.java deleted file mode 100644 index f5ad602c4..000000000 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/ApiKeyUtils.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.mapbox.mapboxsdk.testapp.utils; - - -import android.content.Context; - -import androidx.annotation.NonNull; - -import com.mapbox.mapboxsdk.Mapbox; - -public class ApiKeyUtils { - - /** - *

- * Returns the ApiKey set in the app resources. - *

- * It will first search for a api key in the Mapbox object. If not found it - * will then attempt to load the api key from the - * {@code res/values/dev.xml} development file. - * - * @param context The {@link Context} of the {@link android.app.Activity} or {@link android.app.Fragment}. - * @return The api key or null if not found. - */ - public static String getApiKey(@NonNull Context context) { - try { - // Read out AndroidManifest - String apiKey = Mapbox.getApiKey(); - if (apiKey == null || apiKey.isEmpty()) { - throw new IllegalArgumentException(); - } - return apiKey; - } catch (Exception exception) { - // Use fallback on string resource, used for development - //TODO:PP - int apiKeyResId = context.getResources() - .getIdentifier("api_key", "string", context.getPackageName()); - return apiKeyResId != 0 ? context.getString(apiKeyResId) : null; - } - } -} diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/ApiKeyUtils.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/ApiKeyUtils.kt new file mode 100644 index 000000000..07175f1f8 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/ApiKeyUtils.kt @@ -0,0 +1,34 @@ +package com.mapbox.mapboxsdk.testapp.utils + +import android.content.Context +import com.mapbox.mapboxsdk.Mapbox +import java.lang.Exception + +object ApiKeyUtils { + /** + * + * + * Returns the ApiKey set in the app resources. + * + * It will first search for a api key in the Mapbox object. If not found it + * will then attempt to load the api key from the + * `res/values/dev.xml` development file. + * + * @param context The [Context] of the [android.app.Activity] or [android.app.Fragment]. + * @return The api key or null if not found. + */ + fun getApiKey(context: Context): String? { + return try { + // Read out AndroidManifest + val apiKey = Mapbox.getApiKey() + require(!(apiKey == null || apiKey.isEmpty())) + apiKey + } catch (exception: Exception) { + // Use fallback on string resource, used for development + // TODO:PP + val apiKeyResId = context.resources + .getIdentifier("api_key", "string", context.packageName) + if (apiKeyResId != 0) context.getString(apiKeyResId) else null + } + } +} diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/FontCache.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/FontCache.java deleted file mode 100644 index a4352d0b1..000000000 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/FontCache.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.mapbox.mapboxsdk.testapp.utils; - -import android.content.Context; -import android.graphics.Typeface; - -import java.util.Hashtable; - -import timber.log.Timber; - -public class FontCache { - - private static Hashtable fontCache = new Hashtable<>(); - - public static Typeface get(String name, Context context) { - Typeface tf = fontCache.get(name); - if (tf == null) { - try { - tf = Typeface.createFromAsset(context.getAssets(), name); - fontCache.put(name, tf); - } catch (Exception exception) { - Timber.e("Font not found"); - } - } - return tf; - } -} diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/FontCache.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/FontCache.kt new file mode 100644 index 000000000..5a6d1e9aa --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/FontCache.kt @@ -0,0 +1,25 @@ +package com.mapbox.mapboxsdk.testapp.utils + +import android.content.Context +import android.graphics.Typeface +import timber.log.Timber +import java.lang.Exception +import java.util.* + +object FontCache { + private val fontCache = Hashtable() + + @JvmStatic + operator fun get(name: String, context: Context): Typeface? { + var tf = fontCache[name] + if (tf == null) { + try { + tf = Typeface.createFromAsset(context.assets, name) + fontCache[name] = tf + } catch (exception: Exception) { + Timber.e("Font not found") + } + } + return tf + } +} diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/GeoParseUtil.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/GeoParseUtil.java deleted file mode 100644 index c21e47965..000000000 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/GeoParseUtil.java +++ /dev/null @@ -1,51 +0,0 @@ -package com.mapbox.mapboxsdk.testapp.utils; - -import android.content.Context; -import android.text.TextUtils; - -import com.mapbox.geojson.Feature; -import com.mapbox.geojson.FeatureCollection; -import com.mapbox.geojson.Point; -import com.mapbox.mapboxsdk.geometry.LatLng; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.Reader; -import java.nio.charset.Charset; -import java.util.ArrayList; -import java.util.List; - -public class GeoParseUtil { - - public static String loadStringFromAssets(final Context context, final String fileName) throws IOException { - if (TextUtils.isEmpty(fileName)) { - throw new NullPointerException("No GeoJSON File Name passed in."); - } - InputStream is = context.getAssets().open(fileName); - BufferedReader rd = new BufferedReader(new InputStreamReader(is, Charset.forName("UTF-8"))); - return readAll(rd); - } - - public static List parseGeoJsonCoordinates(String geojsonStr) { - List latLngs = new ArrayList<>(); - FeatureCollection featureCollection = FeatureCollection.fromJson(geojsonStr); - for (Feature feature : featureCollection.features()) { - if (feature.geometry() instanceof Point) { - Point point = (Point) feature.geometry(); - latLngs.add(new LatLng(point.latitude(), point.longitude())); - } - } - return latLngs; - } - - private static String readAll(Reader rd) throws IOException { - StringBuilder sb = new StringBuilder(); - int cp; - while ((cp = rd.read()) != -1) { - sb.append((char) cp); - } - return sb.toString(); - } -} diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/GeoParseUtil.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/GeoParseUtil.kt new file mode 100644 index 000000000..8a1094a36 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/GeoParseUtil.kt @@ -0,0 +1,52 @@ +package com.mapbox.mapboxsdk.testapp.utils + +import android.content.Context +import android.text.TextUtils +import com.mapbox.geojson.FeatureCollection +import com.mapbox.geojson.Point +import com.mapbox.mapboxsdk.geometry.LatLng +import java.io.BufferedReader +import java.io.IOException +import java.io.InputStreamReader +import java.io.Reader +import java.lang.NullPointerException +import java.lang.StringBuilder +import java.util.ArrayList +import kotlin.Throws + +class GeoParseUtil { + + companion object { + @Throws(IOException::class) + fun loadStringFromAssets(context: Context, fileName: String?): String { + if (TextUtils.isEmpty(fileName)) { + throw NullPointerException("No GeoJSON File Name passed in.") + } + val `is` = context.assets.open(fileName!!) + val rd = BufferedReader(InputStreamReader(`is`, Charsets.UTF_8)) + return readAll(rd) + } + + fun parseGeoJsonCoordinates(geojsonStr: String?): List { + val latLngs: MutableList = ArrayList() + val featureCollection = FeatureCollection.fromJson(geojsonStr!!) + for (feature in featureCollection.features()!!) { + if (feature.geometry() is Point) { + val point = feature.geometry() as Point? + latLngs.add(LatLng(point!!.latitude(), point.longitude())) + } + } + return latLngs + } + + @Throws(IOException::class) + private fun readAll(rd: Reader): String { + val sb = StringBuilder() + var cp: Int + while (rd.read().also { cp = it } != -1) { + sb.append(cp.toChar()) + } + return sb.toString() + } + } +} diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/IconUtils.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/IconUtils.java deleted file mode 100644 index c0711d862..000000000 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/IconUtils.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.mapbox.mapboxsdk.testapp.utils; - -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.drawable.Drawable; - -import androidx.annotation.ColorInt; -import androidx.annotation.DrawableRes; -import androidx.annotation.NonNull; -import androidx.core.content.res.ResourcesCompat; -import androidx.core.graphics.drawable.DrawableCompat; - -import com.mapbox.mapboxsdk.annotations.Icon; -import com.mapbox.mapboxsdk.annotations.IconFactory; - -public class IconUtils { - - /** - * Demonstrates converting any Drawable to an Icon, for use as a marker icon. - */ - public static Icon drawableToIcon(@NonNull Context context, @DrawableRes int id, @ColorInt int colorRes) { - Drawable vectorDrawable = ResourcesCompat.getDrawable(context.getResources(), id, context.getTheme()); - Bitmap bitmap = Bitmap.createBitmap(vectorDrawable.getIntrinsicWidth(), - vectorDrawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888); - Canvas canvas = new Canvas(bitmap); - vectorDrawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); - DrawableCompat.setTint(vectorDrawable, colorRes); - vectorDrawable.draw(canvas); - return IconFactory.getInstance(context).fromBitmap(bitmap); - } -} diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/IconUtils.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/IconUtils.kt new file mode 100644 index 000000000..6922ad6c1 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/IconUtils.kt @@ -0,0 +1,31 @@ +package com.mapbox.mapboxsdk.testapp.utils + +import android.content.Context +import android.graphics.Bitmap +import android.graphics.Canvas +import androidx.annotation.ColorInt +import androidx.annotation.DrawableRes +import androidx.core.content.res.ResourcesCompat +import androidx.core.graphics.drawable.DrawableCompat +import com.mapbox.mapboxsdk.annotations.Icon +import com.mapbox.mapboxsdk.annotations.IconFactory + +object IconUtils { + /** + * Demonstrates converting any Drawable to an Icon, for use as a marker icon. + */ + @JvmStatic + fun drawableToIcon(context: Context, @DrawableRes id: Int, @ColorInt colorRes: Int): Icon { + val vectorDrawable = ResourcesCompat.getDrawable(context.resources, id, context.theme) + val bitmap = Bitmap.createBitmap( + vectorDrawable!!.intrinsicWidth, + vectorDrawable.intrinsicHeight, + Bitmap.Config.ARGB_8888 + ) + val canvas = Canvas(bitmap) + vectorDrawable.setBounds(0, 0, canvas.width, canvas.height) + DrawableCompat.setTint(vectorDrawable, colorRes) + vectorDrawable.draw(canvas) + return IconFactory.getInstance(context).fromBitmap(bitmap) + } +} diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/IdleZoomListener.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/IdleZoomListener.java deleted file mode 100644 index 848ed2781..000000000 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/IdleZoomListener.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.mapbox.mapboxsdk.testapp.utils; - -import android.content.Context; -import android.widget.TextView; - -import com.mapbox.mapboxsdk.camera.CameraPosition; -import com.mapbox.mapboxsdk.maps.MapboxMap; -import com.mapbox.mapboxsdk.testapp.R; - -public class IdleZoomListener implements MapboxMap.OnCameraIdleListener { - - private MapboxMap mapboxMap; - private TextView textView; - - public IdleZoomListener(MapboxMap mapboxMap, TextView textView) { - this.mapboxMap = mapboxMap; - this.textView = textView; - } - - @Override - public void onCameraIdle() { - Context context = textView.getContext(); - CameraPosition position = mapboxMap.getCameraPosition(); - textView.setText(String.format(context.getString(R.string.debug_zoom), position.zoom)); - } -} \ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/IdleZoomListener.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/IdleZoomListener.kt new file mode 100644 index 000000000..f045cd9cd --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/IdleZoomListener.kt @@ -0,0 +1,15 @@ +package com.mapbox.mapboxsdk.testapp.utils + +import android.widget.TextView +import com.mapbox.mapboxsdk.maps.MapboxMap +import com.mapbox.mapboxsdk.maps.MapboxMap.OnCameraIdleListener +import com.mapbox.mapboxsdk.testapp.R + +class IdleZoomListener(private val mapboxMap: MapboxMap, private val textView: TextView) : + OnCameraIdleListener { + override fun onCameraIdle() { + val context = textView.context + val position = mapboxMap.cameraPosition + textView.text = String.format(context.getString(R.string.debug_zoom), position.zoom) + } +} diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/OfflineUtils.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/OfflineUtils.java deleted file mode 100644 index 79709f59c..000000000 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/OfflineUtils.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.mapbox.mapboxsdk.testapp.utils; - -import androidx.annotation.NonNull; - -import com.google.gson.Gson; -import com.google.gson.JsonObject; - -import timber.log.Timber; - -import static com.mapbox.mapboxsdk.testapp.activity.offline.OfflineActivity.JSON_CHARSET; -import static com.mapbox.mapboxsdk.testapp.activity.offline.OfflineActivity.JSON_FIELD_REGION_NAME; - -public class OfflineUtils { - - public static String convertRegionName(@NonNull byte[] metadata) { - try { - String json = new String(metadata, JSON_CHARSET); - JsonObject jsonObject = new Gson().fromJson(json, JsonObject.class); - String name = jsonObject.get(JSON_FIELD_REGION_NAME).getAsString(); - return name != null ? name : ""; - } catch (Exception exception) { - return ""; - } - } - - public static byte[] convertRegionName(String regionName) { - try { - JsonObject jsonObject = new JsonObject(); - jsonObject.addProperty(JSON_FIELD_REGION_NAME, regionName); - return jsonObject.toString().getBytes(JSON_CHARSET); - } catch (Exception exception) { - Timber.e(exception, "Failed to encode metadata: "); - } - return null; - } - -} diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/OfflineUtils.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/OfflineUtils.kt new file mode 100644 index 000000000..57f872a68 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/OfflineUtils.kt @@ -0,0 +1,32 @@ +package com.mapbox.mapboxsdk.testapp.utils + +import com.google.gson.Gson +import com.google.gson.JsonObject +import com.mapbox.mapboxsdk.testapp.activity.offline.OfflineActivity +import timber.log.Timber +import java.lang.Exception + +object OfflineUtils { + fun convertRegionName(metadata: ByteArray): String { + return try { + val json = String(metadata, OfflineActivity.JSON_CHARSET) + val jsonObject = Gson().fromJson(json, JsonObject::class.java) + val name = jsonObject[OfflineActivity.JSON_FIELD_REGION_NAME].asString + name ?: "" + } catch (exception: Exception) { + "" + } + } + + @JvmStatic + fun convertRegionName(regionName: String?): ByteArray? { + try { + val jsonObject = JsonObject() + jsonObject.addProperty(OfflineActivity.JSON_FIELD_REGION_NAME, regionName) + return jsonObject.toString().toByteArray(OfflineActivity.JSON_CHARSET) + } catch (exception: Exception) { + Timber.e(exception, "Failed to encode metadata: ") + } + return null + } +} diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/TileLoadingMeasurementUtils.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/TileLoadingMeasurementUtils.java deleted file mode 100644 index 9803b0089..000000000 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/TileLoadingMeasurementUtils.java +++ /dev/null @@ -1,216 +0,0 @@ -package com.mapbox.mapboxsdk.testapp.utils; - -import android.app.ActivityManager; -import android.content.Context; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageManager; -import android.net.ConnectivityManager; -import android.net.NetworkCapabilities; -import android.net.NetworkInfo; -import android.os.Build; -import android.os.Bundle; -import android.util.DisplayMetrics; -import android.view.Display; -import android.view.WindowManager; - -import androidx.annotation.NonNull; -import androidx.annotation.StringDef; - -import com.google.gson.Gson; -import com.google.gson.JsonObject; -import com.mapbox.mapboxsdk.MapStrictMode; -import com.mapbox.mapboxsdk.Mapbox; -import com.mapbox.mapboxsdk.module.http.HttpRequestUtil; - -import java.io.IOException; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; - -import okhttp3.Interceptor; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.Response; -import timber.log.Timber; - -import static com.mapbox.mapboxsdk.constants.MapboxConstants.DEFAULT_MEASURE_TILE_DOWNLOAD_ON; -import static com.mapbox.mapboxsdk.constants.MapboxConstants.KEY_META_DATA_MEASURE_TILE_DOWNLOAD_ON; - -public class TileLoadingMeasurementUtils { - - private static final String ATTRIBUTE_REQUEST_URL = "requestUrl"; - - - public static void setUpTileLoadingMeasurement() { - if (isTileLoadingMeasurementOn()) { - OkHttpClient okHttpClient = new OkHttpClient.Builder() - .addNetworkInterceptor(new TileLoadingInterceptor()) - .build(); - HttpRequestUtil.setOkHttpClient(okHttpClient); - } - } - - private static boolean isTileLoadingMeasurementOn() { - return isBooleanMetaDataValueOn(KEY_META_DATA_MEASURE_TILE_DOWNLOAD_ON, - DEFAULT_MEASURE_TILE_DOWNLOAD_ON); - } - - private static boolean isBooleanMetaDataValueOn(@NonNull String propKey, boolean defaultValue) { - - try { - // Try getting a custom value from the app Manifest - Context context = Mapbox.getApplicationContext(); - ApplicationInfo appInfo = context.getPackageManager().getApplicationInfo(context.getPackageName(), - PackageManager.GET_META_DATA); - if (appInfo.metaData != null) { - return appInfo.metaData.getBoolean(propKey, defaultValue); - } - } catch (PackageManager.NameNotFoundException exception) { - Timber.e("Failed to read the package metadata: " + exception); - MapStrictMode.strictModeViolation(exception); - } catch (Exception exception) { - Timber.e("Failed to read key: " + propKey + " " + exception); - MapStrictMode.strictModeViolation(exception); - } - return defaultValue; - } - - - /** - * This Interceptor allows to measure time spent getting a response object over network. - * The following data will be collected: - * responseCode, elapsedMS - * requestUrl (request string till the question mark), - * and device metadata. - */ - static class TileLoadingInterceptor implements Interceptor { - - private static String metadata = null; - - @StringDef( {CONNECTION_NONE, CONNECTION_CELLULAR, CONNECTION_WIFI}) - @Retention(RetentionPolicy.SOURCE) - @interface ConnectionState { - } - private static final String CONNECTION_NONE = "none"; - private static final String CONNECTION_CELLULAR = "cellular"; - private static final String CONNECTION_WIFI = "wifi"; - - @Override - public Response intercept(Chain chain) throws IOException { - Request request = chain.request(); - long elapsed = System.nanoTime(); - - Response response = chain.proceed(request); - elapsed = System.nanoTime() - elapsed; - - triggerPerformanceEvent(response, elapsed / 1000000); - - return response; - } - - private void triggerPerformanceEvent(Response response, long elapsedMs) { - List> attributes = new ArrayList<>(); - String request = getUrl(response.request()); - attributes.add(new Attribute<>("requestUrl", request)); - attributes.add(new Attribute<>("responseCode", String.valueOf(response.code()))); - attributes.add( - new Attribute<>("connectionState", getConnectionState())); - - List> counters = new ArrayList(); - counters.add(new Attribute<>("elapsedMS", elapsedMs)); - - Bundle bundle = new Bundle(); - Gson gson = new Gson(); - bundle.putString("attributes", gson.toJson(attributes)); - bundle.putString("counters", gson.toJson(counters)); - bundle.putString("metadata", getMetadata()); - } - - private static String getUrl(Request request) { - String url = request.url().toString(); - return url.substring(0, url.indexOf('?')); - } - - private static String getMetadata() { - if (metadata == null) { - JsonObject metaData = new JsonObject(); - metaData.addProperty("os", "android"); - metaData.addProperty("manufacturer", Build.MANUFACTURER); - metaData.addProperty("brand", Build.BRAND); - metaData.addProperty("device", Build.MODEL); - metaData.addProperty("version", Build.VERSION.RELEASE); - metaData.addProperty("abi", Build.CPU_ABI); - metaData.addProperty("country", Locale.getDefault().getISO3Country()); - metaData.addProperty("ram", getRam()); - metaData.addProperty("screenSize", getWindowSize()); - - metadata = metaData.toString(); - } - return metadata; - } - - private static String getRam() { - ActivityManager actManager = - (ActivityManager) Mapbox.getApplicationContext().getSystemService(Context.ACTIVITY_SERVICE); - ActivityManager.MemoryInfo memInfo = new ActivityManager.MemoryInfo(); - actManager.getMemoryInfo(memInfo); - return String.valueOf(memInfo.totalMem); - } - - private static String getWindowSize() { - WindowManager windowManager = - (WindowManager) Mapbox.getApplicationContext().getSystemService(Context.WINDOW_SERVICE); - Display display = windowManager.getDefaultDisplay(); - DisplayMetrics metrics = new DisplayMetrics(); - display.getMetrics(metrics); - int width = metrics.widthPixels; - int height = metrics.heightPixels; - return "{" + width + "," + height + "}"; - } - - @ConnectionState - private static String getConnectionState() { - Context appContext = Mapbox.getApplicationContext(); - ConnectivityManager connectivityManager = - (ConnectivityManager) appContext.getSystemService(Context.CONNECTIVITY_SERVICE); - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - if (connectivityManager != null) { - NetworkCapabilities capabilities = - connectivityManager.getNetworkCapabilities(connectivityManager.getActiveNetwork()); - if (capabilities != null) { - if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) { - return CONNECTION_WIFI; - } else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) { - return CONNECTION_CELLULAR; - } - } - } - } else { - if (connectivityManager != null) { - NetworkInfo activeNetwork = connectivityManager.getActiveNetworkInfo(); - if (activeNetwork != null) { - if (activeNetwork.getType() == ConnectivityManager.TYPE_WIFI) { - return CONNECTION_WIFI; - } else if (activeNetwork.getType() == ConnectivityManager.TYPE_MOBILE) { - return CONNECTION_CELLULAR; - } - } - } - } - return CONNECTION_NONE; - } - } - - private static class Attribute { - private String name; - private T value; - - Attribute(String name, T value) { - this.name = name; - this.value = value; - } - } -} diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/TileLoadingMeasurementUtils.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/TileLoadingMeasurementUtils.kt new file mode 100644 index 000000000..7df2e1c5b --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/TileLoadingMeasurementUtils.kt @@ -0,0 +1,192 @@ +package com.mapbox.mapboxsdk.testapp.utils + +import android.app.ActivityManager +import android.content.Context +import android.content.pm.PackageManager +import android.net.ConnectivityManager +import android.net.NetworkCapabilities +import android.os.Build +import android.os.Bundle +import android.util.DisplayMetrics +import android.view.WindowManager +import androidx.annotation.StringDef +import com.google.gson.Gson +import com.google.gson.JsonObject +import com.mapbox.mapboxsdk.MapStrictMode +import com.mapbox.mapboxsdk.Mapbox +import com.mapbox.mapboxsdk.constants.MapboxConstants +import com.mapbox.mapboxsdk.module.http.HttpRequestUtil +import okhttp3.Interceptor +import okhttp3.Interceptor.Chain +import okhttp3.OkHttpClient +import okhttp3.OkHttpClient.Builder +import okhttp3.Request +import okhttp3.Response +import timber.log.Timber +import java.io.IOException +import java.util.* + +class TileLoadingMeasurementUtils { + + companion object { + + private const val ATTRIBUTE_REQUEST_URL = "requestUrl" + fun setUpTileLoadingMeasurement() { + if (isTileLoadingMeasurementOn) { + val okHttpClient: OkHttpClient = Builder() + .addNetworkInterceptor(TileLoadingInterceptor()) + .build() + HttpRequestUtil.setOkHttpClient(okHttpClient) + } + } + + private val isTileLoadingMeasurementOn: Boolean + private get() = isBooleanMetaDataValueOn( + MapboxConstants.KEY_META_DATA_MEASURE_TILE_DOWNLOAD_ON, + MapboxConstants.DEFAULT_MEASURE_TILE_DOWNLOAD_ON + ) + + private fun isBooleanMetaDataValueOn(propKey: String, defaultValue: Boolean): Boolean { + try { + // Try getting a custom value from the app Manifest + val context = Mapbox.getApplicationContext() + val appInfo = context.packageManager.getApplicationInfo( + context.packageName, + PackageManager.GET_META_DATA + ) + if (appInfo.metaData != null) { + return appInfo.metaData.getBoolean(propKey, defaultValue) + } + } catch (exception: PackageManager.NameNotFoundException) { + Timber.e("Failed to read the package metadata: $exception") + MapStrictMode.strictModeViolation(exception) + } catch (exception: Exception) { + Timber.e("Failed to read key: $propKey $exception") + MapStrictMode.strictModeViolation(exception) + } + return defaultValue + } + + /** + * This Interceptor allows to measure time spent getting a response object over network. + * The following data will be collected: + * responseCode, elapsedMS + * requestUrl (request string till the question mark), + * and device metadata. + */ + internal class TileLoadingInterceptor : Interceptor { + @StringDef(*[CONNECTION_NONE, CONNECTION_CELLULAR, CONNECTION_WIFI]) + @kotlin.annotation.Retention(AnnotationRetention.SOURCE) + internal annotation class ConnectionState + + @Throws(IOException::class) + override fun intercept(chain: Chain): Response { + val request: Request = chain.request() + var elapsed = System.nanoTime() + val response: Response = chain.proceed(request) + elapsed = System.nanoTime() - elapsed + triggerPerformanceEvent(response, elapsed / 1000000) + return response + } + + private fun triggerPerformanceEvent(response: Response, elapsedMs: Long) { + val attributes: MutableList> = ArrayList() + val request = getUrl(response.request) + attributes.add(Attribute("requestUrl", request)) + attributes.add(Attribute("responseCode", response.code.toString())) + attributes.add( + Attribute("connectionState", connectionState) + ) + val counters: MutableList?> = ArrayList() + counters.add(Attribute("elapsedMS", elapsedMs)) + val bundle = Bundle() + val gson = Gson() + bundle.putString("attributes", gson.toJson(attributes)) + bundle.putString("counters", gson.toJson(counters)) + bundle.putString("metadata", metadata) + } + + companion object { + private var metadata: String? = null + private get() { + if (field == null) { + val metaData = JsonObject() + metaData.addProperty("os", "android") + metaData.addProperty("manufacturer", Build.MANUFACTURER) + metaData.addProperty("brand", Build.BRAND) + metaData.addProperty("device", Build.MODEL) + metaData.addProperty("version", Build.VERSION.RELEASE) + metaData.addProperty("abi", Build.CPU_ABI) + metaData.addProperty("country", Locale.getDefault().isO3Country) + metaData.addProperty("ram", ram) + metaData.addProperty("screenSize", windowSize) + field = metaData.toString() + } + return field + } + private const val CONNECTION_NONE = "none" + private const val CONNECTION_CELLULAR = "cellular" + private const val CONNECTION_WIFI = "wifi" + private fun getUrl(request: Request): String { + val url = request.url.toString() + return url.substring(0, url.indexOf('?')) + } + + private val ram: String + private get() { + val actManager = Mapbox.getApplicationContext() + .getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager + val memInfo = ActivityManager.MemoryInfo() + actManager.getMemoryInfo(memInfo) + return memInfo.totalMem.toString() + } + private val windowSize: String + private get() { + val windowManager = Mapbox.getApplicationContext() + .getSystemService(Context.WINDOW_SERVICE) as WindowManager + val display = windowManager.defaultDisplay + val metrics = DisplayMetrics() + display.getMetrics(metrics) + val width = metrics.widthPixels + val height = metrics.heightPixels + return "{$width,$height}" + } + + @get:ConnectionState + private val connectionState: String + private get() { + val appContext = Mapbox.getApplicationContext() + val connectivityManager = + appContext.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + if (connectivityManager != null) { + val capabilities = + connectivityManager.getNetworkCapabilities(connectivityManager.activeNetwork) + if (capabilities != null) { + if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) { + return CONNECTION_WIFI + } else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) { + return CONNECTION_CELLULAR + } + } + } + } else { + if (connectivityManager != null) { + val activeNetwork = connectivityManager.activeNetworkInfo + if (activeNetwork != null) { + if (activeNetwork.type == ConnectivityManager.TYPE_WIFI) { + return CONNECTION_WIFI + } else if (activeNetwork.type == ConnectivityManager.TYPE_MOBILE) { + return CONNECTION_CELLULAR + } + } + } + } + return CONNECTION_NONE + } + } + } + + private class Attribute internal constructor(private val name: String, private val value: T) + } +}