[android] updated PerformanceEvent (#13894)
This commit is contained in:
@@ -1,20 +1,55 @@
|
||||
package com.mapbox.mapboxsdk.module.telemetry;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import com.mapbox.android.telemetry.Event;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcel;
|
||||
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* Generic Performance Event that can be used for performance measurements.
|
||||
* Customer measurements can be added to the bundle.
|
||||
*
|
||||
* Bundle is expected to have following properties:
|
||||
* "attributes", "counters", and "metadata" with String values.
|
||||
*
|
||||
* Attributes: a string representing an array of name/string value pair objects.
|
||||
* Counters: a string representing an array of name/number value pair objects.
|
||||
* Metadata is a string representation of a JsonObject with string values.
|
||||
*
|
||||
* Here is an example of a Performance event bundle data:
|
||||
*
|
||||
* "attributes": [{ "name": "style_id", "value": "mapbox://styles/mapbox/streets-v10"}]
|
||||
*
|
||||
* "counters": [{"name": "fps_average", "value": 90.7655486547093},
|
||||
* {"name": "fps_deviation", "value": 29.301809631465574}]
|
||||
* “metadata”: {
|
||||
* “version”: “9”,
|
||||
* “screenSize”: “1080x1794”,
|
||||
* “country”: “US”,
|
||||
* “device”: “Pixel 2”,
|
||||
* “abi”: “arm64-v8a”,
|
||||
* “brand”: “google”,
|
||||
* “ram”: “3834167296”,
|
||||
* “os”: “android”,
|
||||
* “gpu”: “Qualcomm, Adreno (TM) 540, OpenGL ES 3.2 V@313.0 (GIT@7bf2852, Ie32bfa6f6f)“,
|
||||
* “manufacturer”: “Google”
|
||||
* }
|
||||
*/
|
||||
public class PerformanceEvent extends Event {
|
||||
private static final String PERFORMANCE_TRACE = "performance.trace";
|
||||
|
||||
private static final String PERFORMANCE_TRACE = "mobile.performance_trace";
|
||||
|
||||
private final String event;
|
||||
|
||||
@@ -22,23 +57,36 @@ public class PerformanceEvent extends Event {
|
||||
|
||||
private final String sessionId;
|
||||
|
||||
private final Bundle data;
|
||||
private final List<Attribute<String>> attributes;
|
||||
|
||||
private final List<Attribute<Double>> counters;
|
||||
|
||||
private final JsonObject metadata;
|
||||
|
||||
|
||||
private static final SimpleDateFormat DATE_FORMAT =
|
||||
new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ", Locale.US);
|
||||
|
||||
PerformanceEvent(String sessionId, Bundle data) {
|
||||
PerformanceEvent(String sessionId, Bundle bundle) {
|
||||
|
||||
this.event = PERFORMANCE_TRACE;
|
||||
this.created = DATE_FORMAT.format(new Date());
|
||||
this.sessionId = sessionId;
|
||||
this.data = data;
|
||||
this.attributes = initList(bundle.getString("attributes"),
|
||||
new TypeToken<ArrayList<Attribute<String>>>() {});
|
||||
this.counters = initList(bundle.getString("counters"),
|
||||
new TypeToken<ArrayList<Attribute<Double>>>() {});
|
||||
this.metadata = initMetaData(bundle.getString("metadata"));
|
||||
}
|
||||
|
||||
private PerformanceEvent(Parcel in) {
|
||||
this.event = in.readString();
|
||||
this.created = in.readString();
|
||||
this.sessionId = in.readString();
|
||||
this.data = in.readBundle();
|
||||
|
||||
this.attributes = initList(in.readString(), new TypeToken<ArrayList<Attribute<String>>>() {});
|
||||
this.counters = initList(in.readString(), new TypeToken<ArrayList<Attribute<Double>>>() {});
|
||||
this.metadata = initMetaData(in.readString());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -51,7 +99,30 @@ public class PerformanceEvent extends Event {
|
||||
parcel.writeString(event);
|
||||
parcel.writeString(created);
|
||||
parcel.writeString(sessionId);
|
||||
parcel.writeBundle(data);
|
||||
|
||||
Gson gson = new Gson();
|
||||
|
||||
parcel.writeString(gson.toJson(attributes));
|
||||
parcel.writeString(gson.toJson(counters));
|
||||
|
||||
if (metadata != null) {
|
||||
parcel.writeString(metadata.toString());
|
||||
}
|
||||
}
|
||||
|
||||
private <T> ArrayList<Attribute<T>> initList(String fromString, TypeToken typeToken) {
|
||||
if (fromString == null || fromString.isEmpty()) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
return new Gson().fromJson(fromString, typeToken.getType());
|
||||
}
|
||||
|
||||
private JsonObject initMetaData(String fromString) {
|
||||
if (fromString == null) {
|
||||
return new JsonObject();
|
||||
} else {
|
||||
return new Gson().fromJson(fromString, JsonObject.class);
|
||||
}
|
||||
}
|
||||
|
||||
public static final Creator<PerformanceEvent> CREATOR = new Creator<PerformanceEvent>() {
|
||||
@@ -65,4 +136,15 @@ public class PerformanceEvent extends Event {
|
||||
return new PerformanceEvent[size];
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
private class Attribute<T> {
|
||||
private final String name;
|
||||
private final T value;
|
||||
|
||||
Attribute(String name, T value) {
|
||||
this.name = name;
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,8 +111,9 @@ public class TelemetryImpl implements TelemetryDefinition {
|
||||
|
||||
@Override
|
||||
public void onPerformanceEvent(Bundle data) {
|
||||
if (data != null && !data.isEmpty()) {
|
||||
telemetry.push(new PerformanceEvent(UUID.randomUUID().toString(), data));
|
||||
if (data == null) {
|
||||
data = new Bundle();
|
||||
}
|
||||
telemetry.push(new PerformanceEvent(UUID.randomUUID().toString(), data));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,188 @@
|
||||
package com.mapbox.mapboxsdk.module.telemetry;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcel;
|
||||
import android.support.test.runner.AndroidJUnit4;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.view.Display;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.mapbox.mapboxsdk.Mapbox;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class PerformanceEventTest {
|
||||
|
||||
@Test
|
||||
public void checksPerformanceEventWithMetaData() throws Exception {
|
||||
PerformanceEvent event = obtainPerformanceEvent();
|
||||
assertNotNull(event);
|
||||
|
||||
Parcel parcel = Parcel.obtain();
|
||||
|
||||
event.writeToParcel(parcel, 0);
|
||||
parcel.setDataPosition(0);
|
||||
|
||||
PerformanceEvent newPerfEvent = PerformanceEvent.CREATOR.createFromParcel(parcel);
|
||||
assertNotNull(newPerfEvent);
|
||||
|
||||
compare(event, newPerfEvent, "attributes", "style_id");
|
||||
compare(event, newPerfEvent, "counters", "int_value");
|
||||
compare(event, newPerfEvent, "counters", "long_value");
|
||||
compare(event, newPerfEvent, "counters", "double_value");
|
||||
assertEquals(getMetadata(event), getMetadata(newPerfEvent));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checksPerformanceEventOnlyRequiredData() throws Exception {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString("property ignored", "value will be ignored");
|
||||
PerformanceEvent event = new PerformanceEvent(UUID.randomUUID().toString(), bundle);
|
||||
assertNotNull(event);
|
||||
|
||||
Parcel parcel = Parcel.obtain();
|
||||
event.writeToParcel(parcel, 0);
|
||||
parcel.setDataPosition(0);
|
||||
|
||||
PerformanceEvent newPerfEvent = PerformanceEvent.CREATOR.createFromParcel(parcel);
|
||||
assertNotNull(newPerfEvent);
|
||||
|
||||
assertEquals(getAttributes(event).size(), 0);
|
||||
assertEquals(getCounters(event).size(), 0);
|
||||
assertEquals(getAttributes(newPerfEvent).size(), 0);
|
||||
assertEquals(getCounters(newPerfEvent).size(), 0);
|
||||
assertEquals(getMetadata(event), getMetadata(newPerfEvent));
|
||||
}
|
||||
|
||||
|
||||
private PerformanceEvent obtainPerformanceEvent() {
|
||||
String styleStr = "mapbox://styles/mapbox/streets-v11";
|
||||
boolean testPerfEvent = true;
|
||||
Double doubleValue = 40.5;
|
||||
Long longValue = 40L;
|
||||
Integer intValue = 40;
|
||||
|
||||
List<Attribute<String>> attributes = new ArrayList<>();
|
||||
attributes.add(
|
||||
new Attribute<>("style_id", styleStr));
|
||||
attributes.add(
|
||||
new Attribute<>("test_perf_event", String.valueOf(testPerfEvent)));
|
||||
|
||||
List<Attribute<? extends Number>> counters = new ArrayList();
|
||||
counters.add(new Attribute<>("long_value", longValue));
|
||||
counters.add(new Attribute<>("double_value", doubleValue));
|
||||
counters.add(new Attribute<>("int_value", intValue));
|
||||
|
||||
Gson gson = new Gson();
|
||||
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString("attributes", gson.toJson(attributes));
|
||||
bundle.putString("counters", gson.toJson(counters));
|
||||
|
||||
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());
|
||||
bundle.putString("metadata", metaData.toString());
|
||||
|
||||
return new PerformanceEvent(UUID.randomUUID().toString(), bundle);
|
||||
}
|
||||
|
||||
private void compare(PerformanceEvent event1, PerformanceEvent event2, String listFieldName, String name)
|
||||
throws NoSuchFieldException, IllegalAccessException {
|
||||
Object value1 = getValue(event1, listFieldName, name);
|
||||
Object value2 = getValue(event2, listFieldName, name);
|
||||
|
||||
if (value1 instanceof Double && value2 instanceof Double) {
|
||||
assertEquals((Double)value1, (Double)value2, 0.00006);
|
||||
} else {
|
||||
assertEquals(value1, value2);
|
||||
}
|
||||
}
|
||||
|
||||
private Object getPrivateFieldValue(Object object, String fieldName)
|
||||
throws NoSuchFieldException, IllegalAccessException {
|
||||
Field field = object.getClass().getDeclaredField(fieldName);
|
||||
field.setAccessible(true);
|
||||
return field.get(object);
|
||||
}
|
||||
|
||||
private Object getValue(PerformanceEvent event, String listFieldName, String name)
|
||||
throws NoSuchFieldException, IllegalAccessException {
|
||||
ArrayList list = (ArrayList)getPrivateFieldValue(event, listFieldName);
|
||||
for (Object element : list) {
|
||||
Object elementName = getPrivateFieldValue(element, "name");
|
||||
if (elementName != null && elementName.equals((String)name)) {
|
||||
return getPrivateFieldValue(element, "value");
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private JsonObject getMetadata(PerformanceEvent event)
|
||||
throws NoSuchFieldException, IllegalAccessException {
|
||||
return (JsonObject)getPrivateFieldValue(event, "metadata");
|
||||
}
|
||||
|
||||
private ArrayList getAttributes(PerformanceEvent event)
|
||||
throws NoSuchFieldException, IllegalAccessException {
|
||||
return (ArrayList)getPrivateFieldValue(event, "attributes");
|
||||
}
|
||||
|
||||
private ArrayList getCounters(PerformanceEvent event)
|
||||
throws NoSuchFieldException, IllegalAccessException {
|
||||
return (ArrayList)getPrivateFieldValue(event, "counters");
|
||||
}
|
||||
|
||||
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 + "}";
|
||||
}
|
||||
|
||||
private class Attribute<T> {
|
||||
private String name;
|
||||
private T value;
|
||||
|
||||
Attribute(String name, T value) {
|
||||
this.name = name;
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -930,6 +930,17 @@
|
||||
android:name="android.support.PARENT_ACTIVITY"
|
||||
android:value=".activity.FeatureOverviewActivity" />
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".activity.telemetry.PerformanceMeasurementActivity"
|
||||
android:description="@string/description_performance_measurement"
|
||||
android:label="@string/activity_performance_measurement">
|
||||
<meta-data
|
||||
android:name="@string/category"
|
||||
android:value="@string/category_telemetry" />
|
||||
<meta-data
|
||||
android:name="android.support.PARENT_ACTIVITY"
|
||||
android:value=".activity.FeatureOverviewActivity" />
|
||||
</activity>
|
||||
<!-- For Instrumentation tests -->
|
||||
<activity
|
||||
android:name=".activity.style.RuntimeStyleTimingTestActivity"
|
||||
|
||||
@@ -0,0 +1,187 @@
|
||||
package com.mapbox.mapboxsdk.testapp.activity.telemetry;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.view.Display;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.mapbox.mapboxsdk.Mapbox;
|
||||
import com.mapbox.mapboxsdk.maps.MapView;
|
||||
import com.mapbox.mapboxsdk.maps.Style;
|
||||
import com.mapbox.mapboxsdk.module.http.HttpRequestUtil;
|
||||
import com.mapbox.mapboxsdk.testapp.R;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import okhttp3.Call;
|
||||
import okhttp3.EventListener;
|
||||
import okhttp3.OkHttpClient;
|
||||
import timber.log.Timber;
|
||||
|
||||
/**
|
||||
* Test activity showcasing gathering performance measurement data.
|
||||
*/
|
||||
public class PerformanceMeasurementActivity extends AppCompatActivity {
|
||||
|
||||
private MapView mapView;
|
||||
|
||||
private Map<String, Long> startTimes = new HashMap<>();
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_map_simple);
|
||||
mapView = findViewById(R.id.mapView);
|
||||
mapView.onCreate(savedInstanceState);
|
||||
|
||||
|
||||
OkHttpClient.Builder builder = new OkHttpClient.Builder();
|
||||
builder.eventListener(new EventListener() {
|
||||
|
||||
@Override
|
||||
public void callStart(Call call) {
|
||||
String url = call.request().url().toString();
|
||||
startTimes.put(url, System.nanoTime());
|
||||
super.callStart(call);
|
||||
Timber.e("callStart: %s", url);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void callEnd(Call call) {
|
||||
String url = call.request().url().toString();
|
||||
Timber.e("callEnd: %s", url);
|
||||
Long start = startTimes.get(url);
|
||||
if (start != null) {
|
||||
long elapsed = System.nanoTime() - start;
|
||||
triggerPerformanceEvent(url.substring(0, url.indexOf('?')), elapsed);
|
||||
startTimes.remove(start);
|
||||
Timber.e("callEnd: %s took %d", url, elapsed);
|
||||
}
|
||||
super.callEnd(call);
|
||||
}
|
||||
});
|
||||
HttpRequestUtil.setOkHttpClient(builder.build());
|
||||
|
||||
mapView.getMapAsync(mapboxMap -> mapboxMap.setStyle(
|
||||
new Style.Builder().fromUrl(Style.MAPBOX_STREETS)));
|
||||
}
|
||||
|
||||
|
||||
@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 onLowMemory() {
|
||||
super.onLowMemory();
|
||||
mapView.onLowMemory();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
|
||||
startTimes.clear();
|
||||
|
||||
super.onDestroy();
|
||||
mapView.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSaveInstanceState(Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
mapView.onSaveInstanceState(outState);
|
||||
}
|
||||
|
||||
private void triggerPerformanceEvent(String style, long elapsed) {
|
||||
|
||||
List<Attribute<String>> attributes = new ArrayList<>();
|
||||
attributes.add(
|
||||
new Attribute<>("style_id", style));
|
||||
attributes.add(
|
||||
new Attribute<>("test_perf_event", "true"));
|
||||
|
||||
List<Attribute<Long>> counters = new ArrayList();
|
||||
counters.add(new Attribute<>("elapsed", elapsed));
|
||||
|
||||
|
||||
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());
|
||||
|
||||
Gson gson = new Gson();
|
||||
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString("attributes", gson.toJson(attributes));
|
||||
bundle.putString("counters", gson.toJson(counters));
|
||||
bundle.putString("metadata", metaData.toString());
|
||||
|
||||
Mapbox.getTelemetry().onPerformanceEvent(bundle);
|
||||
}
|
||||
|
||||
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 + "}";
|
||||
}
|
||||
|
||||
private class Attribute<T> {
|
||||
private String name;
|
||||
private T value;
|
||||
|
||||
Attribute(String name, T value) {
|
||||
this.name = name;
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,4 +16,5 @@
|
||||
<string name="category_textureview">Texture View</string>
|
||||
<string name="category_location">Location</string>
|
||||
<string name="category_integration">_Integration</string>
|
||||
<string name="category_telemetry">Telemetry</string>
|
||||
</resources>
|
||||
@@ -81,4 +81,5 @@
|
||||
<string name="description_recyclerview_textureview">Show a TextureView MapView as a recyclerView item</string>
|
||||
<string name="description_recyclerview_glsurfaceview">Show a GLSurfaceView MapView as a recyclerView item</string>
|
||||
<string name="description_nested_viewpager">Show a MapView inside a viewpager inside a recyclerView</string>
|
||||
<string name="description_performance_measurement">Show the use PerformanceEvent for performance measurements</string>
|
||||
</resources>
|
||||
|
||||
@@ -81,4 +81,5 @@
|
||||
<string name="activity_recyclerview_textureview">RecyclerView TextureView</string>
|
||||
<string name="activity_recyclerview_glsurfaceview">RecyclerView GLSurfaceView</string>
|
||||
<string name="activity_nested_viewpager">Nested ViewPager</string>
|
||||
<string name="activity_performance_measurement">Performance Measurement</string>
|
||||
</resources>
|
||||
@@ -49,5 +49,6 @@
|
||||
"ChangeResourcesCachePathActivity",
|
||||
"EspressoTestActivity",
|
||||
"FragmentBackStackActivity",
|
||||
"ChildFragmentMapInDialogActivity"
|
||||
"ChildFragmentMapInDialogActivity",
|
||||
"PerformanceMeasurementActivity"
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user