From 7f15ed9c218c326849734d86ff101b73607b3d8b Mon Sep 17 00:00:00 2001 From: AbdElHamid Nasser Date: Wed, 10 Jan 2024 11:56:28 +0200 Subject: [PATCH 1/3] fix(android): Resolve ANR in `showSurvey` This fix addresses the ANR issue in the `showSurvey` function on Android. The resolution ensures smoother execution by defaulting it to the background thread. --- .../instabug/flutter/modules/SurveysApi.java | 29 ++++++++++++++++++- .../com/instabug/flutter/SurveysApiTest.java | 16 +++++++++- .../instabug/flutter/util/GlobalMocks.java | 6 ++++ .../instabug/flutter/util/MockReflected.java | 5 ++++ 4 files changed, 54 insertions(+), 2 deletions(-) diff --git a/android/src/main/java/com/instabug/flutter/modules/SurveysApi.java b/android/src/main/java/com/instabug/flutter/modules/SurveysApi.java index 841c45233..e98f0a903 100644 --- a/android/src/main/java/com/instabug/flutter/modules/SurveysApi.java +++ b/android/src/main/java/com/instabug/flutter/modules/SurveysApi.java @@ -1,21 +1,29 @@ package com.instabug.flutter.modules; +import android.util.Log; + import androidx.annotation.NonNull; +import androidx.annotation.VisibleForTesting; import com.instabug.flutter.generated.SurveysPigeon; +import com.instabug.flutter.util.Reflection; import com.instabug.flutter.util.ThreadManager; import com.instabug.library.Feature; +import com.instabug.library.Platform; import com.instabug.survey.Survey; import com.instabug.survey.Surveys; import com.instabug.survey.callbacks.OnDismissCallback; import com.instabug.survey.callbacks.OnShowCallback; +import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; import io.flutter.plugin.common.BinaryMessenger; public class SurveysApi implements SurveysPigeon.SurveysHostApi { + + private final String TAG = InstabugApi.class.getName(); private final SurveysPigeon.SurveysFlutterApi flutterApi; public static void init(BinaryMessenger messenger) { @@ -42,9 +50,28 @@ public void showSurveyIfAvailable() { Surveys.showSurveyIfAvailable(); } + /** + * Displays a survey using reflection, eliminating the need to call it on a background thread. + * This variant does not return a boolean indicating the existence of the survey. + * Invoked through reflection. + */ + @VisibleForTesting + public void showSurveyCP(@NonNull String surveyToken) { + try { + Method method = Reflection.getMethod(Class.forName("com.instabug.survey.Surveys"), "showSurveyCP", String.class); + if (method != null) { + method.invoke(null, surveyToken); + } else { + Log.e(TAG, "showSurveyCP was not found by reflection"); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + @Override public void showSurvey(@NonNull String surveyToken) { - Surveys.showSurvey(surveyToken); + showSurveyCP(surveyToken); } @Override diff --git a/android/src/test/java/com/instabug/flutter/SurveysApiTest.java b/android/src/test/java/com/instabug/flutter/SurveysApiTest.java index f2176adf4..70ed339c7 100644 --- a/android/src/test/java/com/instabug/flutter/SurveysApiTest.java +++ b/android/src/test/java/com/instabug/flutter/SurveysApiTest.java @@ -1,18 +1,22 @@ package com.instabug.flutter; +import static com.instabug.flutter.util.GlobalMocks.reflected; import static com.instabug.flutter.util.MockResult.makeResult; import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mockStatic; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import com.instabug.flutter.generated.SurveysPigeon; import com.instabug.flutter.modules.SurveysApi; import com.instabug.flutter.util.GlobalMocks; +import com.instabug.flutter.util.MockReflected; import com.instabug.library.Feature; +import com.instabug.library.Platform; import com.instabug.survey.Survey; import com.instabug.survey.Surveys; import com.instabug.survey.callbacks.OnDismissCallback; @@ -82,13 +86,23 @@ public void testShowSurveyIfAvailable() { mSurveys.verify(Surveys::showSurveyIfAvailable); } + @Test + public void testShowSurveyCp() { + String token = "survey-token"; + + api.showSurveyCP(token); + + reflected.verify(() -> MockReflected.showSurveyCP(token)); + } + @Test public void testShowSurvey() { String token = "survey-token"; api.showSurvey(token); - mSurveys.verify(() -> Surveys.showSurvey(token)); + reflected.verify(() -> MockReflected.showSurveyCP(token)); + mSurveys.verify(() -> Surveys.showSurvey(token), never()); } @Test diff --git a/android/src/test/java/com/instabug/flutter/util/GlobalMocks.java b/android/src/test/java/com/instabug/flutter/util/GlobalMocks.java index 8a37d3ba1..98fc044cc 100644 --- a/android/src/test/java/com/instabug/flutter/util/GlobalMocks.java +++ b/android/src/test/java/com/instabug/flutter/util/GlobalMocks.java @@ -77,6 +77,12 @@ public static void setUp() throws NoSuchMethodException { uri = mockStatic(Uri.class); uri.when(() -> Uri.fromFile(any())).thenReturn(mock(Uri.class)); + + Method mShowSurveyCP = MockReflected.class.getDeclaredMethod("showSurveyCP", String.class); + mShowSurveyCP.setAccessible(true); + reflection + .when(() -> Reflection.getMethod(Class.forName("com.instabug.survey.Surveys"), "showSurveyCP", String.class)) + .thenReturn(mShowSurveyCP); } public static void close() { diff --git a/android/src/test/java/com/instabug/flutter/util/MockReflected.java b/android/src/test/java/com/instabug/flutter/util/MockReflected.java index cb81c4f1c..712f55cd3 100644 --- a/android/src/test/java/com/instabug/flutter/util/MockReflected.java +++ b/android/src/test/java/com/instabug/flutter/util/MockReflected.java @@ -36,4 +36,9 @@ public static void apmNetworkLog(long requestStartTime, long requestDuration, St * CrashReporting.reportException */ public static void crashReportException(JSONObject exception, boolean isHandled) {} + + /** + * Surveys.showSurveyCP + */ + public static void showSurveyCP(String surveyToken) {} } From c65d4b79092599cd73f89b1efc9e829814235053 Mon Sep 17 00:00:00 2001 From: AbdElHamid Nasser Date: Wed, 10 Jan 2024 11:56:36 +0200 Subject: [PATCH 2/3] docs: update changelog.md --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index cc7d78ecd..f053537d3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## [Unreleased](https://github.com/Instabug/Instabug-Flutter/compare/v12.5.0...dev) + +### Fixed + +- Fix an Android issue with `showSurvey` causing ANR when invoked from the main thread. The fix ensures its execution on the background thread by default. ([#454]()). + ## [12.7.0](https://github.com/Instabug/Instabug-Flutter/compare/v12.5.0...v12.7.0) (February 15, 2024) ### Added From 664a6005e140d7261e802cf0f6fc5d78a2babedb Mon Sep 17 00:00:00 2001 From: AbdElHamid Nasser Date: Wed, 6 Mar 2024 09:43:22 +0200 Subject: [PATCH 3/3] build(android): integrate fix snapshot --- android/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/build.gradle b/android/build.gradle index 52f1d9b50..8fbd59c87 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -41,7 +41,7 @@ android { } dependencies { - api 'com.instabug.library:instabug:12.7.1' + api 'com.instabug.library:instabug:12.5.1.5573368-SNAPSHOT' testImplementation 'junit:junit:4.13.2' testImplementation "org.mockito:mockito-inline:3.12.1"