Skip to content

Commit 554c17f

Browse files
AndrewAminInstabugmzelzoghbi
authored andcommitted
feat: add screen loading manual & automatic approaches (#477)
1 parent 66ff626 commit 554c17f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+3077
-91
lines changed

.circleci/config.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -321,4 +321,4 @@ workflows:
321321
- hold_release
322322
filters:
323323
branches:
324-
only: master
324+
only: master

android/src/main/AndroidManifest.xml

+7
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
11
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
22
package="com.instabug.flutter">
3+
4+
<application>
5+
<meta-data
6+
android:name="com.instabug.library.ibg_platform"
7+
android:value="FLUTTER" />
8+
</application>
9+
310
</manifest>

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

+75
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,23 @@
11
package com.instabug.flutter.modules;
22

33
import android.util.Log;
4+
45
import androidx.annotation.NonNull;
56
import androidx.annotation.Nullable;
7+
68
import com.instabug.apm.APM;
9+
import com.instabug.apm.InternalAPM;
10+
import com.instabug.apm.configuration.cp.APMFeature;
11+
import com.instabug.apm.configuration.cp.FeatureAvailabilityCallback;
712
import com.instabug.apm.model.ExecutionTrace;
813
import com.instabug.apm.networking.APMNetworkLogger;
914
import com.instabug.flutter.generated.ApmPigeon;
1015
import com.instabug.flutter.util.Reflection;
1116
import com.instabug.flutter.util.ThreadManager;
17+
1218
import io.flutter.plugin.common.BinaryMessenger;
19+
20+
import org.jetbrains.annotations.NotNull;
1321
import org.json.JSONObject;
1422

1523
import java.lang.reflect.Method;
@@ -213,4 +221,71 @@ public void networkLogAndroid(@NonNull Map<String, Object> data) {
213221
e.printStackTrace();
214222
}
215223
}
224+
225+
226+
@Override
227+
public void startCpUiTrace(@NonNull String screenName, @NonNull Long microTimeStamp, @NonNull Long traceId) {
228+
try {
229+
InternalAPM._startUiTraceCP(screenName, microTimeStamp, traceId);
230+
} catch (Exception e) {
231+
e.printStackTrace();
232+
}
233+
}
234+
235+
@Override
236+
public void reportScreenLoadingCP(@NonNull Long startTimeStampMicro, @NonNull Long durationMicro, @NonNull Long uiTraceId) {
237+
try {
238+
InternalAPM._reportScreenLoadingCP(startTimeStampMicro, durationMicro, uiTraceId);
239+
} catch (Exception e) {
240+
e.printStackTrace();
241+
}
242+
}
243+
244+
@Override
245+
public void endScreenLoadingCP(@NonNull Long timeStampMicro, @NonNull Long uiTraceId) {
246+
try {
247+
InternalAPM._endScreenLoadingCP(timeStampMicro, uiTraceId);
248+
} catch (Exception e) {
249+
e.printStackTrace();
250+
}
251+
}
252+
253+
@Override
254+
public void isEndScreenLoadingEnabled(@NonNull ApmPigeon.Result<Boolean> result) {
255+
isScreenLoadingEnabled(result);
256+
}
257+
258+
@Override
259+
public void isEnabled(@NonNull ApmPigeon.Result<Boolean> result) {
260+
try {
261+
// TODO: replace true with an actual implementation of APM.isEnabled once implemented
262+
// in the Android SDK.
263+
result.success(true);
264+
} catch (Exception e) {
265+
e.printStackTrace();
266+
}
267+
}
268+
269+
@Override
270+
public void isScreenLoadingEnabled(@NonNull ApmPigeon.Result<Boolean> result) {
271+
try {
272+
InternalAPM._isFeatureEnabledCP(APMFeature.SCREEN_LOADING, "InstabugCaptureScreenLoading", new FeatureAvailabilityCallback() {
273+
@Override
274+
public void invoke(boolean isFeatureAvailable) {
275+
result.success(isFeatureAvailable);
276+
}
277+
});
278+
} catch (Exception e) {
279+
e.printStackTrace();
280+
}
281+
}
282+
283+
@Override
284+
public void setScreenLoadingEnabled(@NonNull Boolean isEnabled) {
285+
try {
286+
APM.setScreenLoadingEnabled(isEnabled);
287+
} catch (Exception e) {
288+
e.printStackTrace();
289+
}
290+
}
216291
}

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

+16-15
Original file line numberDiff line numberDiff line change
@@ -6,27 +6,22 @@
66
import android.graphics.BitmapFactory;
77
import android.net.Uri;
88
import android.util.Log;
9-
109
import androidx.annotation.NonNull;
1110
import androidx.annotation.Nullable;
1211
import androidx.annotation.VisibleForTesting;
13-
14-
import com.instabug.flutter.util.ArgsRegistry;
1512
import com.instabug.flutter.generated.InstabugPigeon;
13+
import com.instabug.flutter.util.ArgsRegistry;
1614
import com.instabug.flutter.util.Reflection;
1715
import com.instabug.flutter.util.ThreadManager;
18-
import com.instabug.library.Feature;
19-
import com.instabug.library.Instabug;
20-
import com.instabug.library.InstabugColorTheme;
21-
import com.instabug.library.InstabugCustomTextPlaceHolder;
22-
import com.instabug.library.IssueType;
23-
import com.instabug.library.Platform;
24-
import com.instabug.library.ReproConfigurations;
16+
import com.instabug.library.*;
2517
import com.instabug.library.internal.module.InstabugLocale;
2618
import com.instabug.library.invocation.InstabugInvocationEvent;
2719
import com.instabug.library.model.NetworkLog;
2820
import com.instabug.library.ui.onboarding.WelcomeMessage;
29-
21+
import io.flutter.FlutterInjector;
22+
import io.flutter.embedding.engine.loader.FlutterLoader;
23+
import io.flutter.plugin.common.BinaryMessenger;
24+
import org.jetbrains.annotations.NotNull;
3025
import org.json.JSONObject;
3126

3227
import java.io.File;
@@ -39,10 +34,6 @@
3934
import java.util.Map;
4035
import java.util.concurrent.Callable;
4136

42-
import io.flutter.FlutterInjector;
43-
import io.flutter.plugin.common.BinaryMessenger;
44-
import io.flutter.embedding.engine.loader.FlutterLoader;
45-
4637
public class InstabugApi implements InstabugPigeon.InstabugHostApi {
4738
private final String TAG = InstabugApi.class.getName();
4839
private final Context context;
@@ -85,6 +76,16 @@ public void setEnabled(@NonNull Boolean isEnabled) {
8576
}
8677
}
8778

79+
@NotNull
80+
@Override
81+
public Boolean isEnabled() {
82+
return Instabug.isEnabled();
83+
}
84+
85+
@NotNull
86+
@Override
87+
public Boolean isBuilt() { return Instabug.isBuilt(); }
88+
8889
@Override
8990
public void init(@NonNull String token, @NonNull List<String> invocationEvents, @NonNull String debugLogsLevel) {
9091
setCurrentPlatform();

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

-4
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,8 @@
11
package com.instabug.flutter.modules;
22

33
import androidx.annotation.NonNull;
4-
import androidx.annotation.Nullable;
5-
64
import com.instabug.flutter.generated.SessionReplayPigeon;
7-
import com.instabug.library.OnSessionReplayLinkReady;
85
import com.instabug.library.sessionreplay.SessionReplay;
9-
106
import io.flutter.plugin.common.BinaryMessenger;
117

128
public class SessionReplayApi implements SessionReplayPigeon.SessionReplayHostApi {

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

+119-13
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,18 @@
11
package com.instabug.flutter;
22

3-
import static com.instabug.flutter.util.GlobalMocks.reflected;
4-
import static com.instabug.flutter.util.MockResult.makeResult;
5-
import static org.junit.Assert.assertEquals;
6-
import static org.mockito.ArgumentMatchers.any;
7-
import static org.mockito.ArgumentMatchers.anyInt;
8-
import static org.mockito.ArgumentMatchers.eq;
9-
import static org.mockito.Mockito.mock;
10-
import static org.mockito.Mockito.mockConstruction;
11-
import static org.mockito.Mockito.mockStatic;
12-
import static org.mockito.Mockito.verify;
13-
import static org.mockito.Mockito.when;
14-
153
import com.instabug.apm.APM;
4+
import com.instabug.apm.InternalAPM;
5+
import com.instabug.apm.configuration.cp.APMFeature;
6+
import com.instabug.apm.configuration.cp.FeatureAvailabilityCallback;
167
import com.instabug.apm.model.ExecutionTrace;
178
import com.instabug.apm.networking.APMNetworkLogger;
189
import com.instabug.flutter.generated.ApmPigeon;
1910
import com.instabug.flutter.modules.ApmApi;
2011
import com.instabug.flutter.util.GlobalMocks;
2112
import com.instabug.flutter.util.MockReflected;
2213

14+
import io.flutter.plugin.common.BinaryMessenger;
15+
2316
import org.json.JSONObject;
2417
import org.junit.After;
2518
import org.junit.Assert;
@@ -31,23 +24,32 @@
3124
import java.util.HashMap;
3225
import java.util.Map;
3326

34-
import io.flutter.plugin.common.BinaryMessenger;
27+
import static com.instabug.flutter.util.GlobalMocks.reflected;
28+
import static com.instabug.flutter.util.MockResult.makeResult;
29+
import static org.junit.Assert.assertEquals;
30+
import static org.mockito.ArgumentMatchers.*;
31+
import static org.mockito.Mockito.*;
3532

3633

3734
public class ApmApiTest {
35+
36+
private final BinaryMessenger mMessenger = mock(BinaryMessenger.class);
3837
private final ApmApi api = new ApmApi();
3938
private MockedStatic<APM> mAPM;
39+
private MockedStatic<InternalAPM> mInternalApmStatic;
4040
private MockedStatic<ApmPigeon.ApmHostApi> mHostApi;
4141

4242
@Before
4343
public void setUp() throws NoSuchMethodException {
4444
mAPM = mockStatic(APM.class);
45+
mInternalApmStatic = mockStatic(InternalAPM.class);
4546
mHostApi = mockStatic(ApmPigeon.ApmHostApi.class);
4647
GlobalMocks.setUp();
4748
}
4849

4950
@After
5051
public void cleanUp() {
52+
mInternalApmStatic.close();
5153
mAPM.close();
5254
mHostApi.close();
5355
GlobalMocks.close();
@@ -266,4 +268,108 @@ public void testNetworkLogAndroid() {
266268
mAPMNetworkLogger.close();
267269
mJSONObject.close();
268270
}
271+
272+
@Test
273+
public void testStartUiTraceCP() {
274+
String screenName = "screen-name";
275+
long microTimeStamp = System.currentTimeMillis() / 1000;
276+
long traceId = System.currentTimeMillis();
277+
278+
279+
api.startCpUiTrace(screenName, microTimeStamp, traceId);
280+
281+
mInternalApmStatic.verify(() -> InternalAPM._startUiTraceCP(screenName, microTimeStamp, traceId));
282+
mInternalApmStatic.verifyNoMoreInteractions();
283+
}
284+
285+
@Test
286+
public void testReportScreenLoadingCP() {
287+
long startTimeStampMicro = System.currentTimeMillis() / 1000;
288+
long durationMicro = System.currentTimeMillis() / 1000;
289+
long uiTraceId = System.currentTimeMillis();
290+
291+
api.reportScreenLoadingCP(startTimeStampMicro, durationMicro, uiTraceId);
292+
293+
mInternalApmStatic.verify(() -> InternalAPM._reportScreenLoadingCP(startTimeStampMicro, durationMicro, uiTraceId));
294+
mInternalApmStatic.verifyNoMoreInteractions();
295+
}
296+
297+
@Test
298+
public void testEndScreenLoading() {
299+
long timeStampMicro = System.currentTimeMillis() / 1000;
300+
long uiTraceId = System.currentTimeMillis();
301+
302+
api.endScreenLoadingCP(timeStampMicro, uiTraceId);
303+
304+
mInternalApmStatic.verify(() -> InternalAPM._endScreenLoadingCP(timeStampMicro, uiTraceId));
305+
mInternalApmStatic.verifyNoMoreInteractions();
306+
}
307+
308+
@Test
309+
public void testIsEnabled() {
310+
boolean expected = true;
311+
ApmPigeon.Result<Boolean> result = spy(makeResult((actual) -> assertEquals(expected, actual)));
312+
mInternalApmStatic.when(() -> InternalAPM._isFeatureEnabledCP(eq(APMFeature.SCREEN_LOADING), any(), any(FeatureAvailabilityCallback.class))).thenAnswer(invocation -> {
313+
FeatureAvailabilityCallback callback = invocation.getArgument(1);
314+
callback.invoke(expected);
315+
return null;
316+
});
317+
318+
api.isEnabled(result);
319+
320+
verify(result).success(expected);
321+
}
322+
323+
@Test
324+
public void testIsScreenLoadingEnabled() {
325+
boolean expected = true;
326+
ApmPigeon.Result<Boolean> result = spy(makeResult((actual) -> assertEquals(expected, actual)));
327+
328+
mInternalApmStatic.when(() -> InternalAPM._isFeatureEnabledCP(any(), any(), any())).thenAnswer(
329+
invocation -> {
330+
FeatureAvailabilityCallback callback = (FeatureAvailabilityCallback) invocation.getArguments()[2];
331+
callback.invoke(expected);
332+
return null;
333+
});
334+
335+
336+
api.isScreenLoadingEnabled(result);
337+
338+
mInternalApmStatic.verify(() -> InternalAPM._isFeatureEnabledCP(any(), any(), any()));
339+
mInternalApmStatic.verifyNoMoreInteractions();
340+
341+
verify(result).success(expected);
342+
}
343+
344+
@Test
345+
public void testIsEndScreenLoadingEnabled() {
346+
boolean expected = true;
347+
ApmPigeon.Result<Boolean> result = spy(makeResult((actual) -> assertEquals(expected, actual)));
348+
349+
mInternalApmStatic.when(() -> InternalAPM._isFeatureEnabledCP(any(), any(), any())).thenAnswer(
350+
invocation -> {
351+
FeatureAvailabilityCallback callback = (FeatureAvailabilityCallback) invocation.getArguments()[2];
352+
callback.invoke(expected);
353+
return null;
354+
});
355+
356+
357+
api.isEndScreenLoadingEnabled(result);
358+
359+
mInternalApmStatic.verify(() -> InternalAPM._isFeatureEnabledCP(any(), any(), any()));
360+
mInternalApmStatic.verifyNoMoreInteractions();
361+
362+
verify(result).success(expected);
363+
364+
}
365+
366+
367+
@Test
368+
public void testSetScreenLoadingMonitoringEnabled() {
369+
boolean isEnabled = false;
370+
371+
api.setScreenLoadingEnabled(isEnabled);
372+
373+
mAPM.verify(() -> APM.setScreenLoadingEnabled(isEnabled));
374+
}
269375
}

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

+15
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
import java.util.concurrent.Callable;
5858

5959
import io.flutter.plugin.common.BinaryMessenger;
60+
import org.mockito.verification.VerificationMode;
6061

6162
public class InstabugApiTest {
6263
private final Callable<Bitmap> screenshotProvider = () -> mock(Bitmap.class);
@@ -155,6 +156,20 @@ public void testSetEnabledGivenFalse() {
155156
mInstabug.verify(Instabug::disable);
156157
}
157158

159+
@Test
160+
public void testIsEnabled() {
161+
api.isEnabled();
162+
163+
mInstabug.verify(Instabug::isEnabled);
164+
}
165+
166+
@Test
167+
public void testIsBuilt() {
168+
api.isBuilt();
169+
170+
mInstabug.verify(Instabug::isBuilt);
171+
}
172+
158173
@Test
159174
public void testShow() {
160175
api.show();

0 commit comments

Comments
 (0)