Skip to content

Commit 5c1551b

Browse files
chore: add store API in Android side
1 parent b183a43 commit 5c1551b

File tree

11 files changed

+349
-137
lines changed

11 files changed

+349
-137
lines changed

android/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ android {
5252
}
5353

5454
dependencies {
55-
api 'com.instabug.library:instabug:15.0.0.6897042-SNAPSHOT'
55+
api 'com.instabug.library:instabug:15.0.0.6969715-SNAPSHOT'
5656
testImplementation 'junit:junit:4.13.2'
5757
testImplementation "org.mockito:mockito-inline:3.12.1"
5858
testImplementation "io.mockk:mockk:1.13.13"

android/src/main/java/com/instabug/flutter/modules/ApmApi.java

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,18 @@
1212
import com.instabug.apm.model.ExecutionTrace;
1313
import com.instabug.apm.networking.APMNetworkLogger;
1414
import com.instabug.apm.networkinterception.cp.APMCPNetworkLog;
15+
import com.instabug.apm.screenrendering.models.cp.IBGFrameData;
16+
import com.instabug.apm.screenrendering.models.cp.IBGScreenRenderingData;
1517
import com.instabug.flutter.generated.ApmPigeon;
1618
import com.instabug.flutter.util.Reflection;
1719
import com.instabug.flutter.util.ThreadManager;
1820

1921
import org.json.JSONObject;
2022

2123
import java.lang.reflect.Method;
24+
import java.util.ArrayList;
2225
import java.util.HashMap;
26+
import java.util.List;
2327
import java.util.Map;
2428
import java.util.concurrent.Callable;
2529

@@ -516,12 +520,49 @@ public void deviceRefreshRate(@NonNull ApmPigeon.Result<Double> result) {
516520

517521
@Override
518522
public void endScreenRenderForAutoUiTrace(@NonNull Map<String, Object> data) {
519-
523+
final long traceId = ((Number) data.get("traceId")).longValue();
524+
final long slowFramesTotalDuration = ((Number) data.get("slowFramesTotalDuration")).longValue();
525+
final long frozenFramesTotalDuration = ((Number) data.get("frozenFramesTotalDuration")).longValue();
526+
final long endTime = ((Number) data.get("endTime")).longValue();
527+
528+
// Don't cast directly to ArrayList<ArrayList<Long>> because the inner lists may actually be ArrayList<Integer>
529+
// Instead, cast to List<List<Number>> and convert each value to long explicitly
530+
List<List<Number>> rawFrames = (List<List<Number>>) data.get("frameData");
531+
ArrayList<IBGFrameData> frames = new ArrayList<>();
532+
if (rawFrames != null) {
533+
for (List<Number> frameValues : rawFrames) {
534+
// Defensive: check size and nulls
535+
if (frameValues != null && frameValues.size() >= 2) {
536+
long frameStart = frameValues.get(0).longValue();
537+
long frameDuration = frameValues.get(1).longValue();
538+
frames.add(new IBGFrameData(frameStart, frameDuration));
539+
}
540+
}
541+
}
542+
IBGScreenRenderingData screenRenderingData = new IBGScreenRenderingData(traceId, slowFramesTotalDuration, frozenFramesTotalDuration, frames);
543+
InternalAPM._endAutoUiTraceWithScreenRendering(screenRenderingData, endTime);
520544
}
521545

522546
@Override
523547
public void endScreenRenderForCustomUiTrace(@NonNull Map<String, Object> data) {
524-
548+
final long traceId = ((Number) data.get("traceId")).longValue();
549+
final long slowFramesTotalDuration = ((Number) data.get("slowFramesTotalDuration")).longValue();
550+
final long frozenFramesTotalDuration = ((Number) data.get("frozenFramesTotalDuration")).longValue();
551+
552+
List<List<Number>> rawFrames = (List<List<Number>>) data.get("frameData");
553+
ArrayList<IBGFrameData> frames = new ArrayList<>();
554+
if (rawFrames != null) {
555+
for (List<Number> frameValues : rawFrames) {
556+
// Defensive: check size and nulls
557+
if (frameValues != null && frameValues.size() >= 2) {
558+
long frameStart = frameValues.get(0).longValue();
559+
long frameDuration = frameValues.get(1).longValue();
560+
frames.add(new IBGFrameData(frameStart, frameDuration));
561+
}
562+
}
563+
}
564+
IBGScreenRenderingData screenRenderingData = new IBGScreenRenderingData(traceId, slowFramesTotalDuration, frozenFramesTotalDuration, frames);
565+
InternalAPM._endCustomUiTraceWithScreenRenderingCP(screenRenderingData);
525566
}
526567

527568
}

android/src/test/java/com/instabug/flutter/ApmApiTest.java

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -409,11 +409,129 @@ public void testIsScreenRenderEnabled() {
409409
verify(result).success(expected);
410410
}
411411

412+
@Test
412413
public void testSetScreenRenderEnabled() {
413414
boolean isEnabled = false;
414415

415416
api.setScreenRenderEnabled(isEnabled);
416417

417418
mAPM.verify(() -> APM.setScreenRenderingEnabled(isEnabled));
418419
}
420+
421+
@Test
422+
public void testDeviceRefreshRate() throws Exception {
423+
float expectedRefreshRate = 60.0f;
424+
Double expectedResult = 60.0;
425+
ApmPigeon.Result<Double> result = spy(makeResult((actual) -> assertEquals(expectedResult, actual)));
426+
427+
// Mock the refresh rate provider to return the expected value
428+
Callable<Float> mockRefreshRateProvider = () -> expectedRefreshRate;
429+
ApmApi testApi = new ApmApi(mockRefreshRateProvider);
430+
431+
testApi.deviceRefreshRate(result);
432+
433+
verify(result).success(expectedResult);
434+
}
435+
436+
@Test
437+
public void testDeviceRefreshRateWithException() throws Exception {
438+
ApmPigeon.Result<Double> result = spy(makeResult((actual) -> {}));
439+
440+
// Mock the refresh rate provider to throw an exception
441+
Callable<Float> mockRefreshRateProvider = () -> {
442+
throw new RuntimeException("Test exception");
443+
};
444+
ApmApi testApi = new ApmApi(mockRefreshRateProvider);
445+
446+
testApi.deviceRefreshRate(result);
447+
448+
// Verify that the method doesn't crash when an exception occurs
449+
// The exception is caught and printed, but the result is not called
450+
verify(result, never()).success(any());
451+
}
452+
453+
@Test
454+
public void testEndScreenRenderForAutoUiTrace() {
455+
Map<String, Object> data = new HashMap<>();
456+
data.put("traceId", 123L);
457+
data.put("slowFramesTotalDuration", 1000L);
458+
data.put("frozenFramesTotalDuration", 2000L);
459+
data.put("endTime", 1234567890L);
460+
data.put("frameData", null);
461+
462+
api.endScreenRenderForAutoUiTrace(data);
463+
464+
mInternalApmStatic.verify(() -> InternalAPM._endAutoUiTraceWithScreenRendering(any(), eq(1234567890L)));
465+
mInternalApmStatic.verifyNoMoreInteractions();
466+
}
467+
468+
@Test
469+
public void testEndScreenRenderForAutoUiTraceWithFrameData() {
470+
Map<String, Object> data = new HashMap<>();
471+
data.put("traceId", 123L);
472+
data.put("slowFramesTotalDuration", 1000L);
473+
data.put("frozenFramesTotalDuration", 2000L);
474+
data.put("endTime", 1234567890L);
475+
476+
// Create frame data with ArrayList<ArrayList<Long>>
477+
java.util.ArrayList<java.util.ArrayList<Long>> frameData = new java.util.ArrayList<>();
478+
java.util.ArrayList<Long> frame1 = new java.util.ArrayList<>();
479+
frame1.add(100L);
480+
frame1.add(200L);
481+
frameData.add(frame1);
482+
483+
java.util.ArrayList<Long> frame2 = new java.util.ArrayList<>();
484+
frame2.add(300L);
485+
frame2.add(400L);
486+
frameData.add(frame2);
487+
488+
data.put("frameData", frameData);
489+
490+
api.endScreenRenderForAutoUiTrace(data);
491+
492+
mInternalApmStatic.verify(() -> InternalAPM._endAutoUiTraceWithScreenRendering(any(), eq(1234567890L)));
493+
mInternalApmStatic.verifyNoMoreInteractions();
494+
}
495+
496+
@Test
497+
public void testEndScreenRenderForCustomUiTrace() {
498+
Map<String, Object> data = new HashMap<>();
499+
data.put("traceId", 123L);
500+
data.put("slowFramesTotalDuration", 1000L);
501+
data.put("frozenFramesTotalDuration", 2000L);
502+
data.put("endTime", 1234567890L);
503+
data.put("frameData", null);
504+
505+
api.endScreenRenderForCustomUiTrace(data);
506+
507+
mInternalApmStatic.verify(() -> InternalAPM._endCustomUiTraceWithScreenRenderingCP(any()));
508+
mInternalApmStatic.verifyNoMoreInteractions();
509+
}
510+
511+
@Test
512+
public void testEndScreenRenderForCustomUiTraceWithFrameData() {
513+
Map<String, Object> data = new HashMap<>();
514+
data.put("traceId", 123L);
515+
data.put("slowFramesTotalDuration", 1000L);
516+
data.put("frozenFramesTotalDuration", 2000L);
517+
518+
// Create frame data with ArrayList<ArrayList<Long>>
519+
java.util.ArrayList<java.util.ArrayList<Long>> frameData = new java.util.ArrayList<>();
520+
java.util.ArrayList<Long> frame1 = new java.util.ArrayList<>();
521+
frame1.add(100L);
522+
frame1.add(200L);
523+
frameData.add(frame1);
524+
525+
java.util.ArrayList<Long> frame2 = new java.util.ArrayList<>();
526+
frame2.add(300L);
527+
frame2.add(400L);
528+
frameData.add(frame2);
529+
530+
data.put("frameData", frameData);
531+
532+
api.endScreenRenderForCustomUiTrace(data);
533+
534+
mInternalApmStatic.verify(() -> InternalAPM._endCustomUiTraceWithScreenRenderingCP(any()));
535+
mInternalApmStatic.verifyNoMoreInteractions();
536+
}
419537
}

example/lib/main.dart

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,14 @@ import 'src/widget/instabug_text_field.dart';
1919
import 'src/widget/section_title.dart';
2020

2121
part 'src/components/animated_box.dart';
22+
part 'src/components/apm_switch.dart';
2223
part 'src/components/fatal_crashes_content.dart';
2324
part 'src/components/flows_content.dart';
2425
part 'src/components/network_content.dart';
2526
part 'src/components/non_fatal_crashes_content.dart';
2627
part 'src/components/page.dart';
2728
part 'src/components/screen_render.dart';
29+
part 'src/components/screen_render_switch.dart';
2830
part 'src/components/traces_content.dart';
2931
part 'src/components/ui_traces_content.dart';
3032
part 'src/screens/apm_page.dart';
@@ -34,8 +36,6 @@ part 'src/screens/my_home_page.dart';
3436
part 'src/screens/screen_capture_premature_extension_page.dart';
3537
part 'src/screens/screen_loading_page.dart';
3638
part 'src/screens/screen_render_page.dart';
37-
part 'src/components/apm_switch.dart';
38-
part 'src/components/screen_render_switch.dart';
3939

4040
void main() {
4141
runZonedGuarded(
@@ -46,7 +46,9 @@ void main() {
4646
token: 'ed6f659591566da19b67857e1b9d40ab',
4747
invocationEvents: [InvocationEvent.floatingButton],
4848
debugLogsLevel: LogLevel.verbose,
49-
);
49+
).then((_) {
50+
// APM.setScreenRenderEnabled(false);
51+
});
5052

5153
FlutterError.onError = (FlutterErrorDetails details) {
5254
Zone.current.handleUncaughtError(details.exception, details.stack!);

example/lib/src/screens/screen_render_page.dart

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,9 @@
11
part of '../../main.dart';
22

3-
class ScreenRenderPage extends StatefulWidget {
3+
class ScreenRenderPage extends StatelessWidget {
44
const ScreenRenderPage({Key? key}) : super(key: key);
55
static const String screenName = "/screenRenderPageRoute";
66

7-
@override
8-
State<ScreenRenderPage> createState() => _ScreenRenderPageState();
9-
}
10-
11-
class _ScreenRenderPageState extends State<ScreenRenderPage> {
127
@override
138
Widget build(BuildContext context) {
149
return Page(title: 'Screen Render', children: [

lib/src/models/instabug_screen_render_data.dart

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
11
import 'package:flutter/foundation.dart';
22
import 'package:instabug_flutter/src/models/instabug_frame_data.dart';
3+
import 'package:instabug_flutter/src/utils/ibg_date_time.dart';
34

45
class InstabugScreenRenderData {
56
int traceId;
6-
int slowFramesTotalDuration;
7-
int frozenFramesTotalDuration;
7+
int slowFramesTotalDurationMicro;
8+
int frozenFramesTotalDurationMicro;
9+
int? endTimeMicro;
810
List<InstabugFrameData> frameData;
911

1012
InstabugScreenRenderData({
11-
this.slowFramesTotalDuration = 0,
12-
this.frozenFramesTotalDuration = 0,
13+
this.slowFramesTotalDurationMicro = 0,
14+
this.frozenFramesTotalDurationMicro = 0,
15+
this.endTimeMicro,
1316
required this.frameData,
1417
this.traceId = -1,
1518
});
@@ -22,33 +25,39 @@ class InstabugScreenRenderData {
2225

2326
void clear() {
2427
traceId = -1;
25-
frozenFramesTotalDuration = 0;
26-
slowFramesTotalDuration = 0;
28+
frozenFramesTotalDurationMicro = 0;
29+
slowFramesTotalDurationMicro = 0;
2730
frameData.clear();
2831
}
2932

33+
void saveEndTime() =>
34+
endTimeMicro = IBGDateTime.I.now().microsecondsSinceEpoch;
35+
3036
@override
3137
String toString() => '\nTraceId: $traceId\n'
32-
'SlowFramesTotalDuration: $slowFramesTotalDuration\n'
33-
'FrozenFramesTotalDuration: $frozenFramesTotalDuration\n'
38+
'SlowFramesTotalDuration: $slowFramesTotalDurationMicro\n'
39+
'FrozenFramesTotalDuration: $frozenFramesTotalDurationMicro\n'
40+
'EndTime: $endTimeMicro\n'
3441
'FrameData: [${frameData.map((element) => '$element')}]';
3542

3643
@override
3744
// ignore: hash_and_equals
3845
bool operator ==(covariant InstabugScreenRenderData other) {
3946
if (identical(this, other)) return true;
4047
return traceId == other.traceId &&
41-
slowFramesTotalDuration == other.slowFramesTotalDuration &&
42-
frozenFramesTotalDuration == other.frozenFramesTotalDuration &&
48+
slowFramesTotalDurationMicro == other.slowFramesTotalDurationMicro &&
49+
frozenFramesTotalDurationMicro ==
50+
other.frozenFramesTotalDurationMicro &&
4351
listEquals(frameData, other.frameData);
4452
}
4553

4654
/// Serializes the object to a Map for efficient channel transfer.
4755
Map<String, dynamic> toMap() {
4856
return {
4957
'traceId': traceId,
50-
'slowFramesTotalDuration': slowFramesTotalDuration,
51-
'frozenFramesTotalDuration': frozenFramesTotalDuration,
58+
'slowFramesTotalDuration': slowFramesTotalDurationMicro,
59+
'frozenFramesTotalDuration': frozenFramesTotalDurationMicro,
60+
'endTime': endTimeMicro,
5261
// Convert List<InstabugFrameData> to List<List<int>>
5362
'frameData': frameData.map((frame) => frame.toList()).toList(),
5463
};

0 commit comments

Comments
 (0)