Port most Android TestApp utils to kotlin (#668)
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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 {
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Returns the ApiKey set in the app resources.
|
||||
* </p>
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<String, Typeface> 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;
|
||||
}
|
||||
}
|
||||
@@ -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<String, Typeface?>()
|
||||
|
||||
@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
|
||||
}
|
||||
}
|
||||
@@ -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<LatLng> parseGeoJsonCoordinates(String geojsonStr) {
|
||||
List<LatLng> 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();
|
||||
}
|
||||
}
|
||||
@@ -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<LatLng> {
|
||||
val latLngs: MutableList<LatLng> = 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()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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<Attribute<String>> 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<Attribute<Long>> 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<T> {
|
||||
private String name;
|
||||
private T value;
|
||||
|
||||
Attribute(String name, T value) {
|
||||
this.name = name;
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<Attribute<String>> = 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<Attribute<Long>?> = 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<T> internal constructor(private val name: String, private val value: T)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user