From c5111cfd9c09c1803cee0f9baab8171d4e914222 Mon Sep 17 00:00:00 2001 From: Andrew Amin Date: Fri, 6 Jun 2025 23:04:44 +0300 Subject: [PATCH 01/84] feat: add instabug_screen_render_manager which control screen render , add instabug_widget_binding_observer which manage app life cycle, refactor ui trace related apis --- .../gradle/wrapper/gradle-wrapper.properties | 1 - .../com/instabug/flutter/modules/ApmApi.java | 17 +- example/ios/Podfile.lock | 2 +- example/ios/Runner/AppDelegate.swift | 2 +- example/lib/main.dart | 6 + example/lib/src/components/animated_box.dart | 80 +++++ example/lib/src/components/screen_render.dart | 31 ++ example/lib/src/screens/apm_page.dart | 1 + .../lib/src/screens/screen_render_page.dart | 44 +++ example/pubspec.lock | 34 +- ios/Classes/Modules/ApmApi.m | 10 + lib/instabug_flutter.dart | 2 +- lib/src/models/InstabugFrameData.dart | 9 + lib/src/models/InstabugScreenRenderData.dart | 32 ++ lib/src/modules/apm.dart | 19 ++ lib/src/modules/instabug.dart | 5 + .../utils/instabug_navigator_observer.dart | 11 +- .../screen_loading_manager.dart | 12 +- .../instabug_frame_tracking.dart | 43 +++ .../instabug_screen_render_manager.dart | 313 ++++++++++++++++++ .../instabug_widget_binding_observer.dart | 55 +++ .../flags_config.dart | 3 + .../route_matcher.dart | 0 .../ui_trace.dart | 2 +- pigeons/apm.api.dart | 6 + test/route_matcher_test.dart | 2 +- .../screen_loading_manager_test.dart | 5 +- test/utils/screen_loading/ui_trace_test.dart | 2 +- 28 files changed, 716 insertions(+), 33 deletions(-) create mode 100644 example/lib/src/components/animated_box.dart create mode 100644 example/lib/src/components/screen_render.dart create mode 100644 example/lib/src/screens/screen_render_page.dart create mode 100644 lib/src/models/InstabugFrameData.dart create mode 100644 lib/src/models/InstabugScreenRenderData.dart create mode 100644 lib/src/utils/screen_rendering/instabug_frame_tracking.dart create mode 100644 lib/src/utils/screen_rendering/instabug_screen_render_manager.dart create mode 100644 lib/src/utils/screen_rendering/instabug_widget_binding_observer.dart rename lib/src/utils/{screen_loading => ui_trace}/flags_config.dart (83%) rename lib/src/utils/{screen_loading => ui_trace}/route_matcher.dart (100%) rename lib/src/utils/{screen_loading => ui_trace}/ui_trace.dart (94%) diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index ca8c529fc..5ca64aa4c 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -2,4 +2,3 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.8-bin.zip diff --git a/android/src/main/java/com/instabug/flutter/modules/ApmApi.java b/android/src/main/java/com/instabug/flutter/modules/ApmApi.java index 496b90eaf..c32a243bb 100644 --- a/android/src/main/java/com/instabug/flutter/modules/ApmApi.java +++ b/android/src/main/java/com/instabug/flutter/modules/ApmApi.java @@ -345,7 +345,6 @@ public void isEndScreenLoadingEnabled(@NonNull ApmPigeon.Result result) isScreenLoadingEnabled(result); } - @Override public void isEnabled(@NonNull ApmPigeon.Result result) { try { @@ -385,4 +384,20 @@ public void setScreenLoadingEnabled(@NonNull Boolean isEnabled) { e.printStackTrace(); } } + + + @Override + public void isScreenRenderEnabled(@NonNull ApmPigeon.Result result) { + try { + result.success(true); + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Override + public void deviceRefreshRate(@NonNull ApmPigeon.Result result) { + result.success(60.0); + } + } diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index 484d0ae99..aee5aad67 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -30,4 +30,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: 8f7552fd115ace1988c3db54a69e4a123c448f84 -COCOAPODS: 1.16.2 +COCOAPODS: 1.15.2 diff --git a/example/ios/Runner/AppDelegate.swift b/example/ios/Runner/AppDelegate.swift index 11f416a26..b8991863b 100644 --- a/example/ios/Runner/AppDelegate.swift +++ b/example/ios/Runner/AppDelegate.swift @@ -1,7 +1,7 @@ import UIKit import Flutter -@UIApplicationMain +@main @objc class AppDelegate: FlutterAppDelegate { override func application( _ application: UIApplication, diff --git a/example/lib/main.dart b/example/lib/main.dart index 91b0a67e7..40fc4f4e1 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -30,6 +30,8 @@ part 'src/screens/screen_loading_page.dart'; part 'src/screens/my_home_page.dart'; +part 'src/screens/screen_render_page.dart'; + part 'src/components/fatal_crashes_content.dart'; part 'src/components/non_fatal_crashes_content.dart'; @@ -42,6 +44,10 @@ part 'src/components/traces_content.dart'; part 'src/components/flows_content.dart'; +part 'src/components/screen_render.dart'; + +part 'src/components/animated_box.dart'; + void main() { runZonedGuarded( () { diff --git a/example/lib/src/components/animated_box.dart b/example/lib/src/components/animated_box.dart new file mode 100644 index 000000000..4eec36bcd --- /dev/null +++ b/example/lib/src/components/animated_box.dart @@ -0,0 +1,80 @@ +part of '../../main.dart'; + +class AnimatedBox extends StatefulWidget { + const AnimatedBox({Key? key}) : super(key: key); + + @override + _AnimatedBoxState createState() => _AnimatedBoxState(); +} + +class _AnimatedBoxState extends State + with SingleTickerProviderStateMixin { + late AnimationController _controller; + late Animation _animation; + + @override + void initState() { + super.initState(); + _controller = AnimationController( + duration: const Duration(minutes: 1 , seconds: 40), + vsync: this, + ); + _animation = Tween(begin: 0, end: 100).animate(_controller) + ..addListener(() { + setState(() { + // The state that has changed here is the animation value + }); + }); + } + + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } + + void _startAnimation() { + _controller.forward(); + } + + void _stopAnimation() { + _controller.stop(); + } + + void _resetAnimation() { + _controller.reset(); + } + + @override + Widget build(BuildContext context) { + return Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + RotationTransition( + turns: _animation, + child: const FlutterLogo(size: 100), + ), + const SizedBox(height: 20), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + ElevatedButton( + onPressed: () => _startAnimation(), + child: const Text('Start'), + ), + const SizedBox(width: 20), + ElevatedButton( + onPressed: () => _stopAnimation(), + child: const Text('Stop'), + ), + const SizedBox(width: 20), + ElevatedButton( + onPressed: () => _resetAnimation(), + child: const Text('reset'), + ), + ], + ), + ], + ); + } +} diff --git a/example/lib/src/components/screen_render.dart b/example/lib/src/components/screen_render.dart new file mode 100644 index 000000000..2ab70282f --- /dev/null +++ b/example/lib/src/components/screen_render.dart @@ -0,0 +1,31 @@ +part of '../../main.dart'; + +class ScreenRender extends StatelessWidget { + const ScreenRender({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Column( + children: [ + const SectionTitle('Screen Render'), + InstabugButton( + text: 'Screen Render', + onPressed: () => _navigateToScreenRender(context), + ), + ], + ); + } + + _navigateToScreenRender(BuildContext context) { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => const InstabugCaptureScreenLoading( + screenName: ScreenRenderPage.screenName, + child: ScreenRenderPage(), + ), + settings: const RouteSettings(name: ScreenRenderPage.screenName), + ), + ); + } +} diff --git a/example/lib/src/screens/apm_page.dart b/example/lib/src/screens/apm_page.dart index 798e906fa..153b23b5c 100644 --- a/example/lib/src/screens/apm_page.dart +++ b/example/lib/src/screens/apm_page.dart @@ -51,6 +51,7 @@ class _ApmPageState extends State { SizedBox.fromSize( size: const Size.fromHeight(12), ), + ScreenRender(), ], ); } diff --git a/example/lib/src/screens/screen_render_page.dart b/example/lib/src/screens/screen_render_page.dart new file mode 100644 index 000000000..924eefab2 --- /dev/null +++ b/example/lib/src/screens/screen_render_page.dart @@ -0,0 +1,44 @@ +part of '../../main.dart'; + +class ScreenRenderPage extends StatelessWidget { + const ScreenRenderPage({Key? key}) : super(key: key); + static const String screenName = "/screenRenderPageRoute"; + + @override + Widget build(BuildContext context) { + return Page(title: 'Screen Render', children: [ + + const AnimatedBox(), + SizedBox.fromSize(size: const Size.fromHeight(50),), + InstabugButton( + text: 'Perform Frozen Frame', + onPressed: () => _simulateHeavyComputation(), + ), + InstabugButton( + text: 'Monitored Complex Page', + onPressed: () => _navigateToComplexPage(context), + ), + ]); + } + + void _navigateToComplexPage(BuildContext context) { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => const ComplexPage.monitored(), + settings: const RouteSettings( + name: ComplexPage.screenName, + ), + ), + ); + } + + // Simulates a computationally expensive task + void _simulateHeavyComputation() { + final startTime = DateTime.now(); + // Block the UI thread for ~500ms + while (DateTime.now().difference(startTime).inMilliseconds <= 1000) { + // Busy waiting (not recommended in real apps) + } + } +} diff --git a/example/pubspec.lock b/example/pubspec.lock index 93971dc8b..ba4cc0a6d 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -37,10 +37,10 @@ packages: dependency: transitive description: name: collection - sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf url: "https://pub.dev" source: hosted - version: "1.18.0" + version: "1.19.0" fake_async: dependency: transitive description: @@ -120,18 +120,18 @@ packages: dependency: transitive description: name: leak_tracker - sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05" + sha256: "7bb2830ebd849694d1ec25bf1f44582d6ac531a57a365a803a6034ff751d2d06" url: "https://pub.dev" source: hosted - version: "10.0.5" + version: "10.0.7" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806" + sha256: "9491a714cca3667b60b5c420da8217e6de0d1ba7a5ec322fab01758f6998f379" url: "https://pub.dev" source: hosted - version: "3.0.5" + version: "3.0.8" leak_tracker_testing: dependency: transitive description: @@ -200,7 +200,7 @@ packages: dependency: transitive description: flutter source: sdk - version: "0.0.99" + version: "0.0.0" source_span: dependency: transitive description: @@ -213,10 +213,10 @@ packages: dependency: transitive description: name: stack_trace - sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" + sha256: "9f47fd3630d76be3ab26f0ee06d213679aa425996925ff3feffdec504931c377" url: "https://pub.dev" source: hosted - version: "1.11.1" + version: "1.12.0" stream_channel: dependency: transitive description: @@ -229,10 +229,10 @@ packages: dependency: transitive description: name: string_scanner - sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + sha256: "688af5ed3402a4bde5b3a6c15fd768dbf2621a614950b17f04626c431ab3c4c3" url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.3.0" sync_http: dependency: transitive description: @@ -253,10 +253,10 @@ packages: dependency: transitive description: name: test_api - sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb" + sha256: "664d3a9a64782fcdeb83ce9c6b39e78fd2971d4e37827b9b06c3aa1edc5e760c" url: "https://pub.dev" source: hosted - version: "0.7.2" + version: "0.7.3" typed_data: dependency: transitive description: @@ -277,18 +277,18 @@ packages: dependency: transitive description: name: vm_service - sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d" + sha256: f6be3ed8bd01289b34d679c2b62226f63c0e69f9fd2e50a6b3c1c729a961041b url: "https://pub.dev" source: hosted - version: "14.2.5" + version: "14.3.0" webdriver: dependency: transitive description: name: webdriver - sha256: "003d7da9519e1e5f329422b36c4dcdf18d7d2978d1ba099ea4e45ba490ed845e" + sha256: "3d773670966f02a646319410766d3b5e1037efb7f07cc68f844d5e06cd4d61c8" url: "https://pub.dev" source: hosted - version: "3.0.3" + version: "3.0.4" sdks: dart: ">=3.5.0 <4.0.0" flutter: ">=3.18.0-18.0.pre.54" diff --git a/ios/Classes/Modules/ApmApi.m b/ios/Classes/Modules/ApmApi.m index 782765ad7..c27f953b2 100644 --- a/ios/Classes/Modules/ApmApi.m +++ b/ios/Classes/Modules/ApmApi.m @@ -197,5 +197,15 @@ - (void)isEndScreenLoadingEnabledWithCompletion:(nonnull void (^)(NSNumber * _Nu completion(isEnabledNumber, nil); } +- (void)isScreenRenderEnabledWithCompletion:(void (^)(NSNumber * _Nullable, FlutterError * _Nullable))completion{ + BOOL isScreenRenderEnabled = YES; + NSNumber *isEnabledNumber = @(isScreenRenderEnabled); + completion(isEnabledNumber, nil); +} + +- (void)deviceRefreshRateWithCompletion:(void (^)(NSNumber * _Nullable, FlutterError * _Nullable))completion{ + completion(@60 , nil); +} + @end diff --git a/lib/instabug_flutter.dart b/lib/instabug_flutter.dart index e38545897..edf703ba3 100644 --- a/lib/instabug_flutter.dart +++ b/lib/instabug_flutter.dart @@ -20,5 +20,5 @@ export 'src/modules/surveys.dart'; // Utils export 'src/utils/instabug_navigator_observer.dart'; export 'src/utils/screen_loading/instabug_capture_screen_loading.dart'; -export 'src/utils/screen_loading/route_matcher.dart'; +export 'src/utils/ui_trace/route_matcher.dart'; export 'src/utils/screen_name_masker.dart' show ScreenNameMaskingCallback; diff --git a/lib/src/models/InstabugFrameData.dart b/lib/src/models/InstabugFrameData.dart new file mode 100644 index 000000000..d7db5a01d --- /dev/null +++ b/lib/src/models/InstabugFrameData.dart @@ -0,0 +1,9 @@ +class InstabugFrameData{ + int startTimeTimestamp; + int duration; + + InstabugFrameData(this.startTimeTimestamp, this.duration); + + @override + String toString() => "startTime: $startTimeTimestamp, duration: $duration"; +} \ No newline at end of file diff --git a/lib/src/models/InstabugScreenRenderData.dart b/lib/src/models/InstabugScreenRenderData.dart new file mode 100644 index 000000000..b55f464f1 --- /dev/null +++ b/lib/src/models/InstabugScreenRenderData.dart @@ -0,0 +1,32 @@ +import 'package:instabug_flutter/src/models/InstabugFrameData.dart'; + +class InstabugScreenRenderData { + int traceId; + int totalSlowFramesDurations; + int totalFrozenFramesDurations; + List frameData; + + InstabugScreenRenderData({ + this.totalSlowFramesDurations = 0, + this.totalFrozenFramesDurations = 0, + required this.frameData , + this.traceId = -1, + }); + + bool get isEmpty => traceId == -1; + + bool get isNotEmpty => !isEmpty; + + void clear() { + traceId = -1; + totalFrozenFramesDurations = 0; + totalSlowFramesDurations = 0; + frameData.clear(); + } + + @override + String toString() => '\nTraceId $traceId\n' + 'TotalSlowFramesDurations: $totalSlowFramesDurations\n' + 'TotalFrozenFramesDurations $totalFrozenFramesDurations\n' + 'FrameData[\n${frameData.map((element) => '\t\n$element')}\n]'; +} diff --git a/lib/src/modules/apm.dart b/lib/src/modules/apm.dart index a9f6e0a7c..a37d8c118 100644 --- a/lib/src/modules/apm.dart +++ b/lib/src/modules/apm.dart @@ -346,4 +346,23 @@ class APM { }) { return ScreenLoadingManager.wrapRoutes(routes, exclude: exclude); } + + /// Returns a Future indicating whether the screen + /// render is enabled. + /// + /// Returns: + /// A Future is being returned. + @internal + static Future isScreenRenderEnabled() async{ + return _host.isScreenRenderEnabled(); + } + + /// Retrieve the device refresh rate from native side . + /// + /// Returns: + /// A Future that represent the refresh rate. + @internal + static Future getDeviceRefreshRate(){ + return _host.deviceRefreshRate(); + } } diff --git a/lib/src/modules/instabug.dart b/lib/src/modules/instabug.dart index 6bba8ed1f..96b40876d 100644 --- a/lib/src/modules/instabug.dart +++ b/lib/src/modules/instabug.dart @@ -21,6 +21,8 @@ import 'package:instabug_flutter/src/utils/feature_flags_manager.dart'; import 'package:instabug_flutter/src/utils/ibg_build_info.dart'; import 'package:instabug_flutter/src/utils/instabug_logger.dart'; import 'package:instabug_flutter/src/utils/screen_name_masker.dart'; +import 'package:instabug_flutter/src/utils/screen_rendering/instabug_screen_render_manager.dart'; +import 'package:instabug_flutter/src/utils/screen_rendering/instabug_widget_binding_observer.dart'; import 'package:meta/meta.dart'; enum InvocationEvent { @@ -191,6 +193,9 @@ class Instabug { invocationEvents.mapToString(), debugLogsLevel.toString(), ); + + await InstabugScreenRenderManager.I.init(); + return FeatureFlagsManager().registerW3CFlagsListener(); } diff --git a/lib/src/utils/instabug_navigator_observer.dart b/lib/src/utils/instabug_navigator_observer.dart index d9d6b02db..e185347ad 100644 --- a/lib/src/utils/instabug_navigator_observer.dart +++ b/lib/src/utils/instabug_navigator_observer.dart @@ -6,6 +6,7 @@ import 'package:instabug_flutter/src/utils/instabug_logger.dart'; import 'package:instabug_flutter/src/utils/repro_steps_constants.dart'; import 'package:instabug_flutter/src/utils/screen_loading/screen_loading_manager.dart'; import 'package:instabug_flutter/src/utils/screen_name_masker.dart'; +import 'package:instabug_flutter/src/utils/screen_rendering/instabug_screen_render_manager.dart'; class InstabugNavigatorObserver extends NavigatorObserver { final List _steps = []; @@ -24,7 +25,15 @@ class InstabugNavigatorObserver extends NavigatorObserver { ); // Starts a the new UI trace which is exclusive to screen loading - ScreenLoadingManager.I.startUiTrace(maskedScreenName, screenName); + ScreenLoadingManager.I + .startUiTrace(maskedScreenName, screenName) + .then((uiTraceId) { + if (uiTraceId != null) { + InstabugScreenRenderManager.I + .startScreenRenderCollectorForTraceId(uiTraceId); + } + }); + // If there is a step that hasn't been pushed yet if (_steps.isNotEmpty) { // Report the last step and remove it from the list diff --git a/lib/src/utils/screen_loading/screen_loading_manager.dart b/lib/src/utils/screen_loading/screen_loading_manager.dart index b01b77627..ce73a3e30 100644 --- a/lib/src/utils/screen_loading/screen_loading_manager.dart +++ b/lib/src/utils/screen_loading/screen_loading_manager.dart @@ -4,9 +4,9 @@ import 'package:instabug_flutter/src/utils/ibg_build_info.dart'; import 'package:instabug_flutter/src/utils/ibg_date_time.dart'; import 'package:instabug_flutter/src/utils/instabug_logger.dart'; import 'package:instabug_flutter/src/utils/instabug_montonic_clock.dart'; -import 'package:instabug_flutter/src/utils/screen_loading/flags_config.dart'; +import 'package:instabug_flutter/src/utils/ui_trace/flags_config.dart'; import 'package:instabug_flutter/src/utils/screen_loading/screen_loading_trace.dart'; -import 'package:instabug_flutter/src/utils/screen_loading/ui_trace.dart'; +import 'package:instabug_flutter/src/utils/ui_trace/ui_trace.dart'; import 'package:meta/meta.dart'; /// Manages screen loading traces and UI traces for performance monitoring. @@ -139,7 +139,7 @@ class ScreenLoadingManager { /// [matchingScreenName] as the screen name used for matching the UI trace /// with a Screen Loading trace. @internal - Future startUiTrace( + Future startUiTrace( String screenName, [ String? matchingScreenName, ]) async { @@ -150,7 +150,7 @@ class ScreenLoadingManager { final isSDKBuilt = await _checkInstabugSDKBuilt("APM.InstabugCaptureScreenLoading"); - if (!isSDKBuilt) return; + if (!isSDKBuilt) return null; // TODO: On Android, FlagsConfig.apm.isEnabled isn't implemented correctly // so we skip the isApmEnabled check on Android and only check on iOS. @@ -164,7 +164,7 @@ class ScreenLoadingManager { 'https://docs.instabug.com/docs/react-native-apm-disabling-enabling', tag: APM.tag, ); - return; + return null; } final sanitizedScreenName = sanitizeScreenName(screenName); @@ -181,8 +181,10 @@ class ScreenLoadingManager { matchingScreenName: sanitizedMatchingScreenName, traceId: uiTraceId, ); + return uiTraceId; } catch (error, stackTrace) { _logExceptionErrorAndStackTrace(error, stackTrace); + return null; } } diff --git a/lib/src/utils/screen_rendering/instabug_frame_tracking.dart b/lib/src/utils/screen_rendering/instabug_frame_tracking.dart new file mode 100644 index 000000000..486abdb51 --- /dev/null +++ b/lib/src/utils/screen_rendering/instabug_frame_tracking.dart @@ -0,0 +1,43 @@ +// import 'dart:async'; +// import 'dart:developer'; +// import 'dart:ui'; +// import 'package:flutter/foundation.dart'; +// import 'package:flutter/widgets.dart'; +// import 'package:instabug_flutter/src/modules/apm.dart'; +// import 'package:meta/meta.dart'; +// +// @internal +// class InstabugFrameTracker { +// late Duration buildTime; +// late Duration rasterTime; +// late Duration totalTime; +// +// int _JANKFrames = 0; +// double _deviceRefreshRate = 60; +// double _threshold = 16; +// +// // final stackChain = Chain.current(); +// +// InstabugFrameTracker() { +// log("Andrew InstabugFrameTracker has been attached"); +// _checkForWidgetBinding(); +// +// WidgetsBinding.instance.addTimingsCallback((timings) { +// for (final frameTiming in timings) { +// _analyzeFrameTiming(frameTiming); +// } +// }); +// } +// +// // Simulates a computationally expensive task +// void simulateHeavyComputation() { +// final startTime = DateTime.now(); +// // Block the UI thread for ~500ms +// while (DateTime.now().difference(startTime).inMilliseconds <= 1000) { +// // Busy waiting (not recommended in real apps) +// } +// } +// +// +// +// } diff --git a/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart b/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart new file mode 100644 index 000000000..092c62169 --- /dev/null +++ b/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart @@ -0,0 +1,313 @@ +import 'dart:developer'; +import 'dart:ui'; + +import 'package:flutter/widgets.dart'; +import 'package:instabug_flutter/src/models/InstabugFrameData.dart'; +import 'package:instabug_flutter/src/models/InstabugScreenRenderData.dart'; +import 'package:instabug_flutter/src/modules/apm.dart'; +import 'package:instabug_flutter/src/modules/instabug.dart'; +import 'package:instabug_flutter/src/utils/instabug_logger.dart'; +import 'package:instabug_flutter/src/utils/screen_rendering/instabug_widget_binding_observer.dart'; +import 'package:instabug_flutter/src/utils/ui_trace/flags_config.dart'; +import 'package:meta/meta.dart'; + +@internal +enum UiTraceType { + auto, + custom, +} + +@internal +class InstabugScreenRenderManager { + late int _buildTime; + late int _rasterTime; + late int _totalTime; + late TimingsCallback _timingsCallback; + late InstabugScreenRenderData _screenRenderForAutoUiTrace; + late InstabugScreenRenderData _screenRenderForCustomUiTrace; + + final List _delayedFrames = []; + + double _deviceRefreshRate = 60; + double _slowFrameThresholdMs = 16.67; + final _frozenFrameThresholdMs = 700; + int _slowFramesTotalDuration = 0; + int _frozenFramesTotalDuration = 0; + + bool _isTimingsListenerAttached = false; + + InstabugScreenRenderManager._(); + + static final InstabugScreenRenderManager _instance = + InstabugScreenRenderManager._(); + + /// Returns the singleton instance of [InstabugScreenRenderManager]. + static InstabugScreenRenderManager get instance => _instance; + + /// Shorthand for [instance] + static InstabugScreenRenderManager get I => instance; + + /// Logging tag for debugging purposes. + static const tag = "ScreenRenderManager"; + + /// A named constructor used for testing purposes + + @visibleForTesting + InstabugScreenRenderManager.init(); + + /// setup function for [InstabugScreenRenderManager] + Future init() async { + if (await FlagsConfig.screenRendering.isEnabled() && + (!_isTimingsListenerAttached)) { + log("Andrew InstabugScreenRenderManager has been attached"); + _checkForWidgetBinding(); + WidgetsBinding.instance.addObserver(InstabugWidgetsBindingObserver()); + _initStaticValues(); + _initFrameTimings(); + } + } + + /// analyze frame data in order to detect slow/frozen frame. + void _analyzeFrameTiming(FrameTiming frameTiming) { + _buildTime = frameTiming.buildDuration.inMilliseconds; + _rasterTime = frameTiming.rasterDuration.inMilliseconds; + _totalTime = frameTiming.totalSpan.inMilliseconds; + + _displayFrameTimingDetails(frameTiming); + if (_isUiSlow) { + _slowFramesTotalDuration += + _buildTime.inMicro; //convert from milliseconds to microseconds + } else if (_isRasterSlow) { + _slowFramesTotalDuration += + _rasterTime.inMicro; //convert from milliseconds to microseconds + } + + if (_isUiFrozen) { + _frozenFramesTotalDuration += _buildTime.inMicro; + } else if (_isRasterFrozen) { + _frozenFramesTotalDuration += _rasterTime.inMicro; + } else if (_isFrozen) { + _frozenFramesTotalDuration += _totalTime.inMicro; + } + + if (_isUiDelayed) { + _onDelayedFrameDetected( + frameTiming.timestampInMicroseconds(FramePhase.buildStart), + frameTiming.buildDuration.inMicroseconds, + ); + } else if (_isRasterDelayed) { + _onDelayedFrameDetected( + frameTiming.timestampInMicroseconds(FramePhase.rasterStart), + frameTiming.rasterDuration.inMicroseconds, + ); + } else if (_isTotalTimeLarge) { + // todo what to do? + _onDelayedFrameDetected( + frameTiming.timestampInMicroseconds(FramePhase.vsyncStart), + frameTiming.totalSpan.inMicroseconds, + ); + } + } + + bool get _isSlow => _isUiSlow || _isRasterSlow; + + bool get _isUiDelayed => _isUiSlow || _isUiFrozen; + + bool get _isRasterDelayed => _isRasterSlow || _isRasterFrozen; + + bool get _isUiSlow => + _buildTime > _slowFrameThresholdMs && + _buildTime < _frozenFrameThresholdMs; + + bool get _isRasterSlow => + _rasterTime > _slowFrameThresholdMs && + _buildTime < _frozenFrameThresholdMs; + + bool get _isFrozen => _isUiFrozen || _isRasterFrozen || _isTotalTimeLarge; + + bool get _isTotalTimeLarge => _totalTime >= _frozenFrameThresholdMs; + + bool get _isUiFrozen => _buildTime >= _frozenFrameThresholdMs; + + bool get _isRasterFrozen => _rasterTime >= _frozenFrameThresholdMs; + + double _targetMsPerFrame(double displayRefreshRate) => + 1 / displayRefreshRate * 1000; + + /// Safe garde check for [WidgetsBinding.instance] initialization + void _checkForWidgetBinding() { + try { + WidgetsBinding.instance; + } catch (_) { + WidgetsFlutterBinding.ensureInitialized(); + } + } + + /// Checks if the Instabug SDK is built before calling API methods. + Future _checkInstabugSDKBuilt(String apiName) async { + final isInstabugSDKBuilt = await Instabug.isBuilt(); + if (!isInstabugSDKBuilt) { + InstabugLogger.I.e( + 'Instabug API {$apiName} was called before the SDK is built. To build it, first by following the instructions at this link:\n' + 'https://docs.instabug.com/reference#showing-and-manipulating-the-invocation', + tag: APM.tag, + ); + } + return isInstabugSDKBuilt; + } + + /// check if getting from native would return different value. + /// Platforms may limit what information is available to the application with regard to secondary displays and/or displays that do not have an active application window. + /// Presently, on Android and Web this collection will only contain the display that the current window is on. + /// On iOS, it will only contains the main display on the phone or tablet. + /// On Desktop, it will contain only a main display with a valid refresh rate but invalid size and device pixel ratio values. + double get _getDeviceRefreshRate => + WidgetsBinding.instance.platformDispatcher.displays.last.refreshRate; + + /// get device refresh rate from native side. + Future get _getDeviceRefreshRateFromNative => + APM.getDeviceRefreshRate(); + + /// initialize the static variables + void _initStaticValues() { + _timingsCallback = (timings) { + for (final frameTiming in timings) { + _analyzeFrameTiming(frameTiming); + } + }; + _deviceRefreshRate = _getDeviceRefreshRate; + _slowFrameThresholdMs = _targetMsPerFrame(_getDeviceRefreshRate); + _screenRenderForAutoUiTrace = InstabugScreenRenderData(frameData: []); + _screenRenderForCustomUiTrace = InstabugScreenRenderData(frameData: []); + } + + /// add a frame observer by calling [WidgetsBinding.instance.addTimingsCallback] + void _initFrameTimings() { + WidgetsBinding.instance.addTimingsCallback(_timingsCallback); + _isTimingsListenerAttached = true; + } + + /// remove the running frame observer by calling [WidgetsBinding.instance.removeTimingsCallback] + void _removeFrameTimings() { + WidgetsBinding.instance.removeTimingsCallback(_timingsCallback); + _isTimingsListenerAttached = false; + } + + void startScreenRenderCollectorForTraceId( + int traceId, [ + UiTraceType type = UiTraceType.auto, + ]) { + if (!_isTimingsListenerAttached) { + _initFrameTimings(); + } + + if (_delayedFrames.isNotEmpty) { + _saveCollectedData(); + _resetCachedFrameData(); + } + if (type == UiTraceType.custom) { + if (_screenRenderForCustomUiTrace.isNotEmpty) { + _reportScreenRenderForCustomUiTrace(_screenRenderForCustomUiTrace); + _screenRenderForCustomUiTrace.clear(); + } + _screenRenderForCustomUiTrace.traceId = traceId; + } + if (type == UiTraceType.auto) { + if (_screenRenderForAutoUiTrace.isNotEmpty) { + _reportScreenRenderForAutoUiTrace(_screenRenderForAutoUiTrace); + _screenRenderForAutoUiTrace.clear(); + } + _screenRenderForAutoUiTrace.traceId = traceId; + } + } + + void stopScreenRenderCollector([UiTraceType? type]) { + _saveCollectedData(); + if (_screenRenderForCustomUiTrace.isNotEmpty) { + _reportScreenRenderForCustomUiTrace(_screenRenderForCustomUiTrace); + } + if (_screenRenderForAutoUiTrace.isNotEmpty) { + _reportScreenRenderForAutoUiTrace(_screenRenderForAutoUiTrace); + } + + _removeFrameTimings(); + _resetCachedFrameData(); + } + + void _resetCachedFrameData() { + _slowFramesTotalDuration = 0; + _frozenFramesTotalDuration = 0; + _delayedFrames.clear(); + } + + /// Save Slow/Frozen Frames data + void _onDelayedFrameDetected(int startTime, int duration) { + _delayedFrames.add(InstabugFrameData(startTime, duration)); + } + + //todo: to be removed + void _displayFrameTimingDetails(FrameTiming frameTiming) { + if (_isSlow) { + debugPrint( + '========================= Slow frame detected ⚠️ =========================', + ); + } + if (_isFrozen) { + debugPrint( + '========================= Frozen frame detected 🚨 =========================', + ); + } + + if (_isFrozen || _isSlow) { + debugPrint("{\n\t$frameTiming\n\t" + "Timestamps(${frameTiming.timestampInMicroseconds( + FramePhase.buildStart, + )}, ${frameTiming.timestampInMicroseconds( + FramePhase.buildFinish, + )}, ${frameTiming.timestampInMicroseconds( + FramePhase.rasterStart, + )}, ${frameTiming.timestampInMicroseconds( + FramePhase.rasterFinish, + )}, ${frameTiming.timestampInMicroseconds( + FramePhase.vsyncStart, + )}, ${frameTiming.timestampInMicroseconds( + FramePhase.rasterFinishWallTime, + )}" + ")\n}\n"); + debugPrint("Device refresh rate: $_deviceRefreshRate FPS"); + debugPrint("Threshold: $_slowFrameThresholdMs ms\n" + "==============================================================================="); + } + } + + Future _reportScreenRenderForCustomUiTrace( + InstabugScreenRenderData screenRenderData) async { + log("ReportedData: $screenRenderData", name: tag); + } + + Future _reportScreenRenderForAutoUiTrace( + InstabugScreenRenderData screenRenderData) async { + log("ReportedData: $screenRenderData", name: tag); + } + + void _saveCollectedData() { + if (_screenRenderForAutoUiTrace.isNotEmpty) { + _screenRenderForAutoUiTrace.totalSlowFramesDurations += + _slowFramesTotalDuration; + _screenRenderForAutoUiTrace.totalFrozenFramesDurations += + _frozenFramesTotalDuration; + _screenRenderForAutoUiTrace.frameData.addAll(_delayedFrames); + } + if (_screenRenderForCustomUiTrace.isNotEmpty) { + _screenRenderForCustomUiTrace.totalSlowFramesDurations += + _slowFramesTotalDuration; + _screenRenderForCustomUiTrace.totalFrozenFramesDurations += + _frozenFramesTotalDuration; + _screenRenderForCustomUiTrace.frameData.addAll(_delayedFrames); + } + } +} + +extension on int { + int get inMicro => this * 1000; +} diff --git a/lib/src/utils/screen_rendering/instabug_widget_binding_observer.dart b/lib/src/utils/screen_rendering/instabug_widget_binding_observer.dart new file mode 100644 index 000000000..89119f088 --- /dev/null +++ b/lib/src/utils/screen_rendering/instabug_widget_binding_observer.dart @@ -0,0 +1,55 @@ +import 'dart:async'; +import 'dart:developer'; +import 'dart:ui'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/widgets.dart'; +import 'package:instabug_flutter/src/models/InstabugScreenRenderData.dart'; +import 'package:instabug_flutter/src/utils/screen_loading/screen_loading_manager.dart'; +import 'package:instabug_flutter/src/utils/screen_name_masker.dart'; +import 'package:instabug_flutter/src/utils/screen_rendering/instabug_screen_render_manager.dart'; + +class InstabugWidgetsBindingObserver extends WidgetsBindingObserver { + void _handleResumedState() { + log('Performing resume actions...'); + final lastUiTrace = ScreenLoadingManager.I.currentUiTrace; + if (lastUiTrace != null) { + final maskedScreenName = ScreenNameMasker.I.mask(lastUiTrace.screenName); + ScreenLoadingManager.I + .startUiTrace(maskedScreenName, lastUiTrace.screenName); + } + // ... complex logic for resumed state + } + + void _handlePausedState() { + // ... complex logic for paused state + log('Performing pause actions...'); + InstabugScreenRenderManager.I.stopScreenRenderCollector(); + } + + void _handleDetachedState() { + log('Performing detached actions...'); + InstabugScreenRenderManager.I.stopScreenRenderCollector(); + // ... complex logic for paused state + } + + @override + void didChangeAppLifecycleState(AppLifecycleState state) { + switch (state) { + case AppLifecycleState.resumed: + _handleResumedState(); + break; + case AppLifecycleState.paused: + _handlePausedState(); + break; + case AppLifecycleState.detached: + _handleDetachedState(); + break; + case AppLifecycleState.inactive: + // TODO: Handle this case. + break; + case AppLifecycleState.hidden: + // TODO: Handle this case. + break; + } + } +} diff --git a/lib/src/utils/screen_loading/flags_config.dart b/lib/src/utils/ui_trace/flags_config.dart similarity index 83% rename from lib/src/utils/screen_loading/flags_config.dart rename to lib/src/utils/ui_trace/flags_config.dart index f18eb1ccb..92a899b15 100644 --- a/lib/src/utils/screen_loading/flags_config.dart +++ b/lib/src/utils/ui_trace/flags_config.dart @@ -5,6 +5,7 @@ enum FlagsConfig { uiTrace, screenLoading, endScreenLoading, + screenRendering, } extension FeatureExtensions on FlagsConfig { @@ -16,6 +17,8 @@ extension FeatureExtensions on FlagsConfig { return APM.isScreenLoadingEnabled(); case FlagsConfig.endScreenLoading: return APM.isEndScreenLoadingEnabled(); + case FlagsConfig.screenRendering: + return APM.isScreenRenderEnabled(); default: return false; } diff --git a/lib/src/utils/screen_loading/route_matcher.dart b/lib/src/utils/ui_trace/route_matcher.dart similarity index 100% rename from lib/src/utils/screen_loading/route_matcher.dart rename to lib/src/utils/ui_trace/route_matcher.dart diff --git a/lib/src/utils/screen_loading/ui_trace.dart b/lib/src/utils/ui_trace/ui_trace.dart similarity index 94% rename from lib/src/utils/screen_loading/ui_trace.dart rename to lib/src/utils/ui_trace/ui_trace.dart index 17ef41046..34c88cbc0 100644 --- a/lib/src/utils/screen_loading/ui_trace.dart +++ b/lib/src/utils/ui_trace/ui_trace.dart @@ -1,4 +1,4 @@ -import 'package:instabug_flutter/src/utils/screen_loading/route_matcher.dart'; +import 'package:instabug_flutter/src/utils/ui_trace/route_matcher.dart'; class UiTrace { final String screenName; diff --git a/pigeons/apm.api.dart b/pigeons/apm.api.dart index 84fe9eb8e..d4a159631 100644 --- a/pigeons/apm.api.dart +++ b/pigeons/apm.api.dart @@ -40,4 +40,10 @@ abstract class ApmHostApi { @async bool isEndScreenLoadingEnabled(); + + @async + bool isScreenRenderEnabled(); + + @async + double deviceRefreshRate(); } diff --git a/test/route_matcher_test.dart b/test/route_matcher_test.dart index 977c61d88..5d8b234c4 100644 --- a/test/route_matcher_test.dart +++ b/test/route_matcher_test.dart @@ -1,6 +1,6 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:instabug_flutter/src/utils/screen_loading/route_matcher.dart'; +import 'package:instabug_flutter/src/utils/ui_trace/route_matcher.dart'; void main() { TestWidgetsFlutterBinding.ensureInitialized(); diff --git a/test/utils/screen_loading/screen_loading_manager_test.dart b/test/utils/screen_loading/screen_loading_manager_test.dart index c008b8bcc..f452c4cda 100644 --- a/test/utils/screen_loading/screen_loading_manager_test.dart +++ b/test/utils/screen_loading/screen_loading_manager_test.dart @@ -7,12 +7,13 @@ import 'package:instabug_flutter/src/utils/ibg_build_info.dart'; import 'package:instabug_flutter/src/utils/ibg_date_time.dart'; import 'package:instabug_flutter/src/utils/instabug_logger.dart'; import 'package:instabug_flutter/src/utils/instabug_montonic_clock.dart'; -import 'package:instabug_flutter/src/utils/screen_loading/flags_config.dart'; import 'package:instabug_flutter/src/utils/screen_loading/screen_loading_manager.dart'; import 'package:instabug_flutter/src/utils/screen_loading/screen_loading_trace.dart'; -import 'package:instabug_flutter/src/utils/screen_loading/ui_trace.dart'; +import 'package:instabug_flutter/src/utils/ui_trace/ui_trace.dart'; +import 'package:instabug_flutter/src/utils/ui_trace/flags_config.dart'; import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; + import 'screen_loading_manager_test.mocks.dart'; class ScreenLoadingManagerNoResets extends ScreenLoadingManager { diff --git a/test/utils/screen_loading/ui_trace_test.dart b/test/utils/screen_loading/ui_trace_test.dart index 11ed57c66..68a0f06cf 100644 --- a/test/utils/screen_loading/ui_trace_test.dart +++ b/test/utils/screen_loading/ui_trace_test.dart @@ -1,6 +1,6 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:instabug_flutter/instabug_flutter.dart'; -import 'package:instabug_flutter/src/utils/screen_loading/ui_trace.dart'; +import 'package:instabug_flutter/src/utils/ui_trace/ui_trace.dart'; import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; From 7064e0e6c878b5250357918379fd3236366f9490 Mon Sep 17 00:00:00 2001 From: Andrew Amin Date: Wed, 18 Jun 2025 12:14:07 +0300 Subject: [PATCH 02/84] chore: attach screen render collector to the app lifecycle and ui traces , add unit tests. --- example/lib/main.dart | 2 + .../lib/src/components/ui_traces_content.dart | 75 ++++ example/lib/src/screens/apm_page.dart | 2 + lib/src/models/InstabugFrameData.dart | 13 +- lib/src/models/InstabugScreenRenderData.dart | 34 +- lib/src/modules/apm.dart | 19 +- lib/src/modules/instabug.dart | 7 +- .../instabug_frame_tracking.dart | 43 --- .../instabug_screen_render_manager.dart | 170 +++++--- .../instabug_widget_binding_observer.dart | 39 +- .../instabug_screen_render_manager_test.dart | 364 ++++++++++++++++++ 11 files changed, 638 insertions(+), 130 deletions(-) create mode 100644 example/lib/src/components/ui_traces_content.dart delete mode 100644 lib/src/utils/screen_rendering/instabug_frame_tracking.dart create mode 100644 test/utils/screen_render/instabug_screen_render_manager_test.dart diff --git a/example/lib/main.dart b/example/lib/main.dart index 40fc4f4e1..8895bd084 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -48,6 +48,8 @@ part 'src/components/screen_render.dart'; part 'src/components/animated_box.dart'; +part 'src/components/ui_traces_content.dart'; + void main() { runZonedGuarded( () { diff --git a/example/lib/src/components/ui_traces_content.dart b/example/lib/src/components/ui_traces_content.dart new file mode 100644 index 000000000..19e9ec0dd --- /dev/null +++ b/example/lib/src/components/ui_traces_content.dart @@ -0,0 +1,75 @@ +part of '../../main.dart'; + +class UITracesContent extends StatefulWidget { + const UITracesContent({Key? key}) : super(key: key); + + @override + State createState() => _UITracesContentState(); +} + +class _UITracesContentState extends State { + final traceNameController = TextEditingController(); + + @override + Widget build(BuildContext context) { + final textTheme = Theme.of(context).textTheme; + return Column( + children: [ + InstabugTextField( + label: 'UI Trace name', + labelStyle: textTheme.labelMedium, + controller: traceNameController, + ), + SizedBox.fromSize( + size: const Size.fromHeight(10.0), + ), + Row( + children: [ + Flexible( + flex: 5, + child: InstabugButton.smallFontSize( + text: 'Start UI Trace', + onPressed: () => _startTrace(traceNameController.text), + margin: const EdgeInsetsDirectional.only( + start: 20.0, + end: 10.0, + ), + ), + ), + Flexible( + flex: 5, + child: InstabugButton.smallFontSize( + text: 'End UI Trace', + onPressed: () => _endTrace(), + margin: const EdgeInsetsDirectional.only( + start: 10.0, + end: 20.0, + ), + ), + ), + ], + ), + + ], + ); + } + + void _startTrace( + String traceName, { + int delayInMilliseconds = 0, + }) { + if (traceName.trim().isNotEmpty) { + log('_startTrace — traceName: $traceName, delay in Milliseconds: $delayInMilliseconds'); + log('traceName: $traceName'); + Future.delayed(Duration(milliseconds: delayInMilliseconds), + () => APM.startUITrace(traceName)); + } else { + log('startUITrace - Please enter a trace name'); + } + } + + void _endTrace() { + log('endUITrace - '); + APM.endUITrace(); + } +} diff --git a/example/lib/src/screens/apm_page.dart b/example/lib/src/screens/apm_page.dart index 153b23b5c..0dcf90a2c 100644 --- a/example/lib/src/screens/apm_page.dart +++ b/example/lib/src/screens/apm_page.dart @@ -40,6 +40,8 @@ class _ApmPageState extends State { const TracesContent(), const SectionTitle('Flows'), const FlowsContent(), + const SectionTitle('Custom UI Traces'), + const UITracesContent(), const SectionTitle('Screen Loading'), SizedBox.fromSize( size: const Size.fromHeight(12), diff --git a/lib/src/models/InstabugFrameData.dart b/lib/src/models/InstabugFrameData.dart index d7db5a01d..d62368c3a 100644 --- a/lib/src/models/InstabugFrameData.dart +++ b/lib/src/models/InstabugFrameData.dart @@ -1,9 +1,16 @@ -class InstabugFrameData{ +class InstabugFrameData { int startTimeTimestamp; int duration; InstabugFrameData(this.startTimeTimestamp, this.duration); @override - String toString() => "startTime: $startTimeTimestamp, duration: $duration"; -} \ No newline at end of file + String toString() => "start time: $startTimeTimestamp, duration: $duration"; + + @override + bool operator == (covariant InstabugFrameData other) { + if (identical(this, other)) return true; + return startTimeTimestamp == other.startTimeTimestamp && + duration == other.duration; + } +} diff --git a/lib/src/models/InstabugScreenRenderData.dart b/lib/src/models/InstabugScreenRenderData.dart index b55f464f1..ed5f4a2f3 100644 --- a/lib/src/models/InstabugScreenRenderData.dart +++ b/lib/src/models/InstabugScreenRenderData.dart @@ -1,15 +1,16 @@ +import 'package:flutter/foundation.dart'; import 'package:instabug_flutter/src/models/InstabugFrameData.dart'; class InstabugScreenRenderData { int traceId; - int totalSlowFramesDurations; - int totalFrozenFramesDurations; + int slowFramesTotalDuration; + int frozenFramesTotalDuration; List frameData; InstabugScreenRenderData({ - this.totalSlowFramesDurations = 0, - this.totalFrozenFramesDurations = 0, - required this.frameData , + this.slowFramesTotalDuration = 0, + this.frozenFramesTotalDuration = 0, + required this.frameData, this.traceId = -1, }); @@ -19,14 +20,25 @@ class InstabugScreenRenderData { void clear() { traceId = -1; - totalFrozenFramesDurations = 0; - totalSlowFramesDurations = 0; + frozenFramesTotalDuration = 0; + slowFramesTotalDuration = 0; frameData.clear(); } @override - String toString() => '\nTraceId $traceId\n' - 'TotalSlowFramesDurations: $totalSlowFramesDurations\n' - 'TotalFrozenFramesDurations $totalFrozenFramesDurations\n' - 'FrameData[\n${frameData.map((element) => '\t\n$element')}\n]'; + String toString() => '\nTrace Id $traceId\n' + 'Slow Frames Total Duration: $slowFramesTotalDuration\n' + 'Frozen Frames Total Duration $frozenFramesTotalDuration\n' + 'Frame Data[\n${frameData.map((element) => '\t\n$element')}\n]'; + + @override + bool operator ==(covariant InstabugScreenRenderData other) { + if (identical(this, other)) return true; + return traceId == other.traceId && + slowFramesTotalDuration == other.slowFramesTotalDuration && + frozenFramesTotalDuration == other.frozenFramesTotalDuration && + listEquals(frameData, other.frameData); + } + + } diff --git a/lib/src/modules/apm.dart b/lib/src/modules/apm.dart index a37d8c118..43af7b7d7 100644 --- a/lib/src/modules/apm.dart +++ b/lib/src/modules/apm.dart @@ -10,6 +10,8 @@ import 'package:instabug_flutter/src/utils/ibg_build_info.dart'; import 'package:instabug_flutter/src/utils/ibg_date_time.dart'; import 'package:instabug_flutter/src/utils/instabug_logger.dart'; import 'package:instabug_flutter/src/utils/screen_loading/screen_loading_manager.dart'; +import 'package:instabug_flutter/src/utils/screen_rendering/instabug_screen_render_manager.dart'; +import 'package:instabug_flutter/src/utils/ui_trace/flags_config.dart'; import 'package:meta/meta.dart'; class APM { @@ -189,7 +191,14 @@ class APM { /// Returns: /// The method is returning a `Future`. static Future startUITrace(String name) async { - return _host.startUITrace(name); + return _host.startUITrace(name).then( + (_) async { + // Start screen render collector for custom ui trace if enabled. + if (await FlagsConfig.screenRendering.isEnabled()) { + InstabugScreenRenderManager.I.startScreenRenderCollectorForTraceId(0 ,UiTraceType.custom); + } + }, + ); } /// The [endUITrace] function ends a UI trace. @@ -197,6 +206,12 @@ class APM { /// Returns: /// The method is returning a `Future`. static Future endUITrace() async { + // End screen render collector for custom ui trace if enabled. + if (await FlagsConfig.screenRendering.isEnabled()) { + return InstabugScreenRenderManager.I + .endScreenRenderCollectorForCustomUiTrace(); + } + return _host.endUITrace(); } @@ -353,7 +368,7 @@ class APM { /// Returns: /// A Future is being returned. @internal - static Future isScreenRenderEnabled() async{ + static Future isScreenRenderEnabled() async { return _host.isScreenRenderEnabled(); } diff --git a/lib/src/modules/instabug.dart b/lib/src/modules/instabug.dart index 96b40876d..0a832526b 100644 --- a/lib/src/modules/instabug.dart +++ b/lib/src/modules/instabug.dart @@ -11,6 +11,7 @@ import 'dart:typed_data'; import 'dart:ui'; import 'package:flutter/material.dart'; + // to maintain supported versions prior to Flutter 3.3 // ignore: unused_import import 'package:flutter/services.dart'; @@ -23,6 +24,7 @@ import 'package:instabug_flutter/src/utils/instabug_logger.dart'; import 'package:instabug_flutter/src/utils/screen_name_masker.dart'; import 'package:instabug_flutter/src/utils/screen_rendering/instabug_screen_render_manager.dart'; import 'package:instabug_flutter/src/utils/screen_rendering/instabug_widget_binding_observer.dart'; +import 'package:instabug_flutter/src/utils/ui_trace/flags_config.dart'; import 'package:meta/meta.dart'; enum InvocationEvent { @@ -194,7 +196,10 @@ class Instabug { debugLogsLevel.toString(), ); - await InstabugScreenRenderManager.I.init(); + if (await FlagsConfig.screenRendering.isEnabled()) { + checkForWidgetBinding(); + await InstabugScreenRenderManager.I.init(WidgetsBinding.instance); + } return FeatureFlagsManager().registerW3CFlagsListener(); } diff --git a/lib/src/utils/screen_rendering/instabug_frame_tracking.dart b/lib/src/utils/screen_rendering/instabug_frame_tracking.dart deleted file mode 100644 index 486abdb51..000000000 --- a/lib/src/utils/screen_rendering/instabug_frame_tracking.dart +++ /dev/null @@ -1,43 +0,0 @@ -// import 'dart:async'; -// import 'dart:developer'; -// import 'dart:ui'; -// import 'package:flutter/foundation.dart'; -// import 'package:flutter/widgets.dart'; -// import 'package:instabug_flutter/src/modules/apm.dart'; -// import 'package:meta/meta.dart'; -// -// @internal -// class InstabugFrameTracker { -// late Duration buildTime; -// late Duration rasterTime; -// late Duration totalTime; -// -// int _JANKFrames = 0; -// double _deviceRefreshRate = 60; -// double _threshold = 16; -// -// // final stackChain = Chain.current(); -// -// InstabugFrameTracker() { -// log("Andrew InstabugFrameTracker has been attached"); -// _checkForWidgetBinding(); -// -// WidgetsBinding.instance.addTimingsCallback((timings) { -// for (final frameTiming in timings) { -// _analyzeFrameTiming(frameTiming); -// } -// }); -// } -// -// // Simulates a computationally expensive task -// void simulateHeavyComputation() { -// final startTime = DateTime.now(); -// // Block the UI thread for ~500ms -// while (DateTime.now().difference(startTime).inMilliseconds <= 1000) { -// // Busy waiting (not recommended in real apps) -// } -// } -// -// -// -// } diff --git a/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart b/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart index 092c62169..55baed043 100644 --- a/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart +++ b/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart @@ -5,12 +5,13 @@ import 'package:flutter/widgets.dart'; import 'package:instabug_flutter/src/models/InstabugFrameData.dart'; import 'package:instabug_flutter/src/models/InstabugScreenRenderData.dart'; import 'package:instabug_flutter/src/modules/apm.dart'; -import 'package:instabug_flutter/src/modules/instabug.dart'; -import 'package:instabug_flutter/src/utils/instabug_logger.dart'; import 'package:instabug_flutter/src/utils/screen_rendering/instabug_widget_binding_observer.dart'; -import 'package:instabug_flutter/src/utils/ui_trace/flags_config.dart'; import 'package:meta/meta.dart'; +extension on int { + int get inMicro => this * 1000; +} + @internal enum UiTraceType { auto, @@ -19,6 +20,7 @@ enum UiTraceType { @internal class InstabugScreenRenderManager { + late final WidgetsBinding _widgetsBinding; late int _buildTime; late int _rasterTime; late int _totalTime; @@ -56,19 +58,24 @@ class InstabugScreenRenderManager { InstabugScreenRenderManager.init(); /// setup function for [InstabugScreenRenderManager] - Future init() async { - if (await FlagsConfig.screenRendering.isEnabled() && - (!_isTimingsListenerAttached)) { - log("Andrew InstabugScreenRenderManager has been attached"); - _checkForWidgetBinding(); - WidgetsBinding.instance.addObserver(InstabugWidgetsBindingObserver()); - _initStaticValues(); + @internal + Future init(WidgetsBinding widgetBinding) async { + if (!_isTimingsListenerAttached) { + _widgetsBinding = widgetBinding; + _addWidgetBindingObserver(); + await _initStaticValues(); _initFrameTimings(); } } + /// nodoc + + void _addWidgetBindingObserver() => + _widgetsBinding.addObserver(InstabugWidgetsBindingObserver.instance); + /// analyze frame data in order to detect slow/frozen frame. - void _analyzeFrameTiming(FrameTiming frameTiming) { + @visibleForTesting + void analyzeFrameTiming(FrameTiming frameTiming) { _buildTime = frameTiming.buildDuration.inMilliseconds; _rasterTime = frameTiming.rasterDuration.inMilliseconds; _totalTime = frameTiming.totalSpan.inMilliseconds; @@ -121,7 +128,7 @@ class InstabugScreenRenderManager { bool get _isRasterSlow => _rasterTime > _slowFrameThresholdMs && - _buildTime < _frozenFrameThresholdMs; + _rasterTime < _frozenFrameThresholdMs; bool get _isFrozen => _isUiFrozen || _isRasterFrozen || _isTotalTimeLarge; @@ -131,109 +138,121 @@ class InstabugScreenRenderManager { bool get _isRasterFrozen => _rasterTime >= _frozenFrameThresholdMs; + /// Calculate the target time for the frame to be drawn in milliseconds based on the device refresh rate. double _targetMsPerFrame(double displayRefreshRate) => 1 / displayRefreshRate * 1000; - /// Safe garde check for [WidgetsBinding.instance] initialization - void _checkForWidgetBinding() { - try { - WidgetsBinding.instance; - } catch (_) { - WidgetsFlutterBinding.ensureInitialized(); - } - } - - /// Checks if the Instabug SDK is built before calling API methods. - Future _checkInstabugSDKBuilt(String apiName) async { - final isInstabugSDKBuilt = await Instabug.isBuilt(); - if (!isInstabugSDKBuilt) { - InstabugLogger.I.e( - 'Instabug API {$apiName} was called before the SDK is built. To build it, first by following the instructions at this link:\n' - 'https://docs.instabug.com/reference#showing-and-manipulating-the-invocation', - tag: APM.tag, - ); - } - return isInstabugSDKBuilt; - } - - /// check if getting from native would return different value. + /// Check if getting from native would return different value. /// Platforms may limit what information is available to the application with regard to secondary displays and/or displays that do not have an active application window. /// Presently, on Android and Web this collection will only contain the display that the current window is on. /// On iOS, it will only contains the main display on the phone or tablet. /// On Desktop, it will contain only a main display with a valid refresh rate but invalid size and device pixel ratio values. + //todo: will be removed after getting the actual value from native side. double get _getDeviceRefreshRate => - WidgetsBinding.instance.platformDispatcher.displays.last.refreshRate; + _widgetsBinding.platformDispatcher.displays.last.refreshRate; - /// get device refresh rate from native side. + /// Get device refresh rate from native side. Future get _getDeviceRefreshRateFromNative => APM.getDeviceRefreshRate(); - /// initialize the static variables - void _initStaticValues() { + /// Initialize the static variables + Future _initStaticValues() async { _timingsCallback = (timings) { for (final frameTiming in timings) { - _analyzeFrameTiming(frameTiming); + analyzeFrameTiming(frameTiming); } }; - _deviceRefreshRate = _getDeviceRefreshRate; - _slowFrameThresholdMs = _targetMsPerFrame(_getDeviceRefreshRate); + _deviceRefreshRate = await _getDeviceRefreshRateFromNative; + _slowFrameThresholdMs = _targetMsPerFrame(_deviceRefreshRate); _screenRenderForAutoUiTrace = InstabugScreenRenderData(frameData: []); _screenRenderForCustomUiTrace = InstabugScreenRenderData(frameData: []); } - /// add a frame observer by calling [WidgetsBinding.instance.addTimingsCallback] + /// Add a frame observer by calling [WidgetsBinding.instance.addTimingsCallback] + void _initFrameTimings() { - WidgetsBinding.instance.addTimingsCallback(_timingsCallback); + _widgetsBinding.addTimingsCallback(_timingsCallback); _isTimingsListenerAttached = true; } - /// remove the running frame observer by calling [WidgetsBinding.instance.removeTimingsCallback] + /// Remove the running frame observer by calling [_widgetsBinding.removeTimingsCallback] void _removeFrameTimings() { - WidgetsBinding.instance.removeTimingsCallback(_timingsCallback); + _widgetsBinding.removeTimingsCallback(_timingsCallback); _isTimingsListenerAttached = false; } + /// Start collecting screen render data for the running [UITrace]. + /// It ends the running collector when starting a new one of the same type [UiTraceType]. + @internal void startScreenRenderCollectorForTraceId( int traceId, [ UiTraceType type = UiTraceType.auto, ]) { + // Attach frameTimingListener if not attached if (!_isTimingsListenerAttached) { _initFrameTimings(); } + //Save the memory cached data to be sent to native side if (_delayedFrames.isNotEmpty) { _saveCollectedData(); _resetCachedFrameData(); } + + //Sync the captured screen render data of the Custom UI trace when starting new one if (type == UiTraceType.custom) { if (_screenRenderForCustomUiTrace.isNotEmpty) { - _reportScreenRenderForCustomUiTrace(_screenRenderForCustomUiTrace); + reportScreenRending(_screenRenderForCustomUiTrace, UiTraceType.custom); _screenRenderForCustomUiTrace.clear(); } _screenRenderForCustomUiTrace.traceId = traceId; } + + //Sync the captured screen render data of the Auto UI trace when starting new one if (type == UiTraceType.auto) { if (_screenRenderForAutoUiTrace.isNotEmpty) { - _reportScreenRenderForAutoUiTrace(_screenRenderForAutoUiTrace); + reportScreenRending(_screenRenderForAutoUiTrace); _screenRenderForAutoUiTrace.clear(); } _screenRenderForAutoUiTrace.traceId = traceId; } } - void stopScreenRenderCollector([UiTraceType? type]) { + /// Stop screen render collector and sync the captured data. + @internal + void stopScreenRenderCollector() { _saveCollectedData(); + if (_screenRenderForCustomUiTrace.isNotEmpty) { - _reportScreenRenderForCustomUiTrace(_screenRenderForCustomUiTrace); + reportScreenRending(_screenRenderForCustomUiTrace, UiTraceType.custom); } if (_screenRenderForAutoUiTrace.isNotEmpty) { - _reportScreenRenderForAutoUiTrace(_screenRenderForAutoUiTrace); + reportScreenRending(_screenRenderForAutoUiTrace); } _removeFrameTimings(); + _resetCachedFrameData(); } + /// Sync the capture screen render data of the custom UI trace without stopping the collector. + @internal + void endScreenRenderCollectorForCustomUiTrace() { + if (_screenRenderForCustomUiTrace.isNotEmpty) { + // Save the captured screen rendering data to be synced + _screenRenderForCustomUiTrace.slowFramesTotalDuration += + _slowFramesTotalDuration; + _screenRenderForCustomUiTrace.frozenFramesTotalDuration += + _frozenFramesTotalDuration; + _screenRenderForCustomUiTrace.frameData.addAll(_delayedFrames); + + // Sync the saved screen rendering data + reportScreenRending(_screenRenderForCustomUiTrace, UiTraceType.custom); + _screenRenderForCustomUiTrace.clear(); + } + } + + /// Reset the memory cashed data void _resetCachedFrameData() { _slowFramesTotalDuration = 0; _frozenFramesTotalDuration = 0; @@ -280,34 +299,61 @@ class InstabugScreenRenderManager { } } + @visibleForTesting + Future reportScreenRending(InstabugScreenRenderData screenRenderData, + [UiTraceType type = UiTraceType.auto]) async { + if (type == UiTraceType.auto) { + _reportScreenRenderForAutoUiTrace(screenRenderData); + } else { + _reportScreenRenderForCustomUiTrace(screenRenderData); + } + log("Reported Data (${type == UiTraceType.auto ? 'auto' : 'custom'}): $screenRenderData", + name: tag); + } + Future _reportScreenRenderForCustomUiTrace( - InstabugScreenRenderData screenRenderData) async { - log("ReportedData: $screenRenderData", name: tag); + InstabugScreenRenderData screenRenderData, + ) async { + //todo: Will be implemented in next sprint } Future _reportScreenRenderForAutoUiTrace( - InstabugScreenRenderData screenRenderData) async { - log("ReportedData: $screenRenderData", name: tag); + InstabugScreenRenderData screenRenderData, + ) async { + //todo: Will be implemented in next sprint } + /// Add the memory cashed data to the objects that will be synced asynchronously to the native side. void _saveCollectedData() { if (_screenRenderForAutoUiTrace.isNotEmpty) { - _screenRenderForAutoUiTrace.totalSlowFramesDurations += + _screenRenderForAutoUiTrace.slowFramesTotalDuration += _slowFramesTotalDuration; - _screenRenderForAutoUiTrace.totalFrozenFramesDurations += + _screenRenderForAutoUiTrace.frozenFramesTotalDuration += _frozenFramesTotalDuration; _screenRenderForAutoUiTrace.frameData.addAll(_delayedFrames); } if (_screenRenderForCustomUiTrace.isNotEmpty) { - _screenRenderForCustomUiTrace.totalSlowFramesDurations += + _screenRenderForCustomUiTrace.slowFramesTotalDuration += _slowFramesTotalDuration; - _screenRenderForCustomUiTrace.totalFrozenFramesDurations += + _screenRenderForCustomUiTrace.frozenFramesTotalDuration += _frozenFramesTotalDuration; _screenRenderForCustomUiTrace.frameData.addAll(_delayedFrames); } } -} -extension on int { - int get inMicro => this * 1000; + /// --------------------------- testing helper functions --------------------- + @visibleForTesting + InstabugScreenRenderData get screenRenderForAutoUiTrace => + _screenRenderForAutoUiTrace; + + @visibleForTesting + InstabugScreenRenderData get screenRenderForCustomUiTrace => + _screenRenderForCustomUiTrace; + + @visibleForTesting + void setFrameData(InstabugScreenRenderData data) { + _delayedFrames.addAll(data.frameData); + _frozenFramesTotalDuration = data.frozenFramesTotalDuration; + _slowFramesTotalDuration = data.slowFramesTotalDuration; + } } diff --git a/lib/src/utils/screen_rendering/instabug_widget_binding_observer.dart b/lib/src/utils/screen_rendering/instabug_widget_binding_observer.dart index 89119f088..053beaed8 100644 --- a/lib/src/utils/screen_rendering/instabug_widget_binding_observer.dart +++ b/lib/src/utils/screen_rendering/instabug_widget_binding_observer.dart @@ -1,27 +1,42 @@ -import 'dart:async'; import 'dart:developer'; -import 'dart:ui'; -import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; -import 'package:instabug_flutter/src/models/InstabugScreenRenderData.dart'; import 'package:instabug_flutter/src/utils/screen_loading/screen_loading_manager.dart'; import 'package:instabug_flutter/src/utils/screen_name_masker.dart'; import 'package:instabug_flutter/src/utils/screen_rendering/instabug_screen_render_manager.dart'; +import 'package:meta/meta.dart'; class InstabugWidgetsBindingObserver extends WidgetsBindingObserver { + InstabugWidgetsBindingObserver._(); + + static final InstabugWidgetsBindingObserver _instance = + InstabugWidgetsBindingObserver._(); + + /// Returns the singleton instance of [InstabugWidgetsBindingObserver]. + static InstabugWidgetsBindingObserver get instance => _instance; + + /// Shorthand for [instance] + static InstabugWidgetsBindingObserver get I => instance; + + /// Logging tag for debugging purposes. + static const tag = "InstabugWidgetsBindingObserver"; + void _handleResumedState() { log('Performing resume actions...'); final lastUiTrace = ScreenLoadingManager.I.currentUiTrace; if (lastUiTrace != null) { final maskedScreenName = ScreenNameMasker.I.mask(lastUiTrace.screenName); ScreenLoadingManager.I - .startUiTrace(maskedScreenName, lastUiTrace.screenName); + .startUiTrace(maskedScreenName, lastUiTrace.screenName) + .then((uiTraceId) { + if (uiTraceId != null) { + InstabugScreenRenderManager.I + .startScreenRenderCollectorForTraceId(uiTraceId); + } + }); } - // ... complex logic for resumed state } void _handlePausedState() { - // ... complex logic for paused state log('Performing pause actions...'); InstabugScreenRenderManager.I.stopScreenRenderCollector(); } @@ -29,7 +44,6 @@ class InstabugWidgetsBindingObserver extends WidgetsBindingObserver { void _handleDetachedState() { log('Performing detached actions...'); InstabugScreenRenderManager.I.stopScreenRenderCollector(); - // ... complex logic for paused state } @override @@ -53,3 +67,12 @@ class InstabugWidgetsBindingObserver extends WidgetsBindingObserver { } } } + +@internal +void checkForWidgetBinding() { + try { + WidgetsBinding.instance; + } catch (_) { + WidgetsFlutterBinding.ensureInitialized(); + } +} diff --git a/test/utils/screen_render/instabug_screen_render_manager_test.dart b/test/utils/screen_render/instabug_screen_render_manager_test.dart new file mode 100644 index 000000000..1f0f404b0 --- /dev/null +++ b/test/utils/screen_render/instabug_screen_render_manager_test.dart @@ -0,0 +1,364 @@ +import 'dart:ui'; + +import 'package:flutter/widgets.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:instabug_flutter/instabug_flutter.dart'; +import 'package:instabug_flutter/src/generated/apm.api.g.dart'; +import 'package:instabug_flutter/src/models/InstabugFrameData.dart'; +import 'package:instabug_flutter/src/models/InstabugScreenRenderData.dart'; +import 'package:instabug_flutter/src/utils/screen_rendering/instabug_screen_render_manager.dart'; +import 'package:mockito/annotations.dart'; +import 'package:mockito/mockito.dart'; + +import 'instabug_screen_render_manager_test.mocks.dart'; + +@GenerateMocks([FrameTiming, ApmHostApi, WidgetsBinding]) +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + late InstabugScreenRenderManager manager; + late MockApmHostApi mApmHost; + late MockWidgetsBinding mWidgetBinding; + + setUp(() async { + mApmHost = MockApmHostApi(); + mWidgetBinding = MockWidgetsBinding(); + manager = InstabugScreenRenderManager.init(); // test-only constructor + APM.$setHostApi(mApmHost); + + when(mApmHost.deviceRefreshRate()).thenAnswer((_) async => 60); + await manager.init(mWidgetBinding); + await untilCalled(mApmHost.deviceRefreshRate()); + }); + + tearDown(() { + // Clean up state after each test + }); + + group('InstabugScreenRenderManager.init()', () { + test('should initialize timings callback and add observer', () async { + expect(manager, isA()); + + verify(mWidgetBinding.addObserver(any)).called(1); + + verify(mWidgetBinding.addTimingsCallback(any)).called(1); + }); + + test('calling init more that one time should do nothing', () async { + await manager.init(mWidgetBinding); + await manager.init(mWidgetBinding); // second call should be ignored + + + verify(mWidgetBinding.addObserver(any)).called(1); + + verify(mWidgetBinding.addTimingsCallback(any)).called(1); + + expect(true, isTrue); // no crash + }); + }); + + group('startScreenRenderCollectorForTraceId()', () { + test('should not attach timing listener if it is attached', () async { + manager.startScreenRenderCollectorForTraceId(1); + manager.startScreenRenderCollectorForTraceId(2); + manager.startScreenRenderCollectorForTraceId(3); + + verify(mWidgetBinding.addTimingsCallback(any)).called( + 1, + ); // the one form init() + }); + + test( + 'should report data to native when starting new trace from the same type', + () async { + ///todo: will be implemented in next sprint + }); + + test('should attach timing listener if it is not attached', () async { + manager.stopScreenRenderCollector(); // this should detach listener safely + + manager.startScreenRenderCollectorForTraceId(1); + + verify(mWidgetBinding.addTimingsCallback(any)).called( + 2, + ); // one form init() and one form startScreenRenderCollectorForTraceId() + }); + + test('should update the data for same trace type', () { + const firstTraceId = 123; + const secondTraceId = 456; + + expect(manager.screenRenderForAutoUiTrace.isNotEmpty, false); + + manager.startScreenRenderCollectorForTraceId( + firstTraceId, UiTraceType.auto); + expect(manager.screenRenderForAutoUiTrace.isNotEmpty, true); + expect(manager.screenRenderForAutoUiTrace.traceId, firstTraceId); + + manager.startScreenRenderCollectorForTraceId( + secondTraceId, UiTraceType.auto); + expect(manager.screenRenderForAutoUiTrace.isNotEmpty, true); + expect(manager.screenRenderForAutoUiTrace.traceId, secondTraceId); + }); + + test('should not update the data for same trace type', () { + const firstTraceId = 123; + const secondTraceId = 456; + + expect(manager.screenRenderForAutoUiTrace.isNotEmpty, false); + expect(manager.screenRenderForCustomUiTrace.isNotEmpty, false); + + manager.startScreenRenderCollectorForTraceId( + firstTraceId, UiTraceType.auto); + expect(manager.screenRenderForAutoUiTrace.isNotEmpty, true); + expect(manager.screenRenderForAutoUiTrace.traceId, firstTraceId); + + manager.startScreenRenderCollectorForTraceId( + secondTraceId, UiTraceType.custom); + expect(manager.screenRenderForAutoUiTrace.traceId, firstTraceId); + expect(manager.screenRenderForCustomUiTrace.traceId, secondTraceId); + }); + }); + + group('stopScreenRenderCollector()', () { + test('should not save data if no UI trace is started', () { + final frameTestdata = InstabugScreenRenderData( + traceId: 123, + frameData: [ + InstabugFrameData(10000, 200), + InstabugFrameData(20000, 1000), + ], + frozenFramesTotalDuration: 1000, + slowFramesTotalDuration: 200, + ); + + manager.setFrameData(frameTestdata); + + manager.stopScreenRenderCollector(); + + expect(manager.screenRenderForAutoUiTrace.isEmpty, true); + expect(manager.screenRenderForAutoUiTrace == frameTestdata, false); + + expect(manager.screenRenderForCustomUiTrace.isEmpty, true); + expect(manager.screenRenderForCustomUiTrace == frameTestdata, false); + }); + + test( + 'should save and data to screenRenderForAutoUiTrace when for autoUITrace', + () { + final frameTestdata = InstabugScreenRenderData( + traceId: 123, + frameData: [ + InstabugFrameData(10000, 200), + InstabugFrameData(20000, 1000), + ], + frozenFramesTotalDuration: 1000, + slowFramesTotalDuration: 200, + ); + + manager.startScreenRenderCollectorForTraceId( + frameTestdata.traceId, + UiTraceType.auto, + ); + + manager.setFrameData(frameTestdata); + + manager.stopScreenRenderCollector(); + + expect(manager.screenRenderForAutoUiTrace.isNotEmpty, true); + + expect(manager.screenRenderForAutoUiTrace == frameTestdata, true); + + expect(manager.screenRenderForCustomUiTrace.isEmpty, true); + }); + + test( + 'should save and data to screenRenderForCustomUiTrace when for customUITrace', + () { + final frameTestdata = InstabugScreenRenderData( + traceId: 123, + frameData: [ + InstabugFrameData(10000, 200), + InstabugFrameData(20000, 1000), + ], + frozenFramesTotalDuration: 1000, + slowFramesTotalDuration: 200, + ); + + manager.startScreenRenderCollectorForTraceId( + frameTestdata.traceId, + UiTraceType.custom, + ); + + manager.setFrameData(frameTestdata); + + manager.stopScreenRenderCollector(); + + expect(manager.screenRenderForCustomUiTrace.isNotEmpty, true); + + expect(manager.screenRenderForCustomUiTrace == frameTestdata, true); + + expect(manager.screenRenderForAutoUiTrace.isEmpty, true); + }); + + test('should remove timing callback listener', () { + manager.stopScreenRenderCollector(); + + verify(mWidgetBinding.removeTimingsCallback(any)).called(1); + }); + + test( + 'should report data to native when starting new trace from the same type', + () async { + ///todo: will be implemented in next sprint + }); + }); + + group('endScreenRenderCollectorForCustomUiTrace()', () { + setUp(() { + manager.screenRenderForAutoUiTrace.clear(); + manager.screenRenderForCustomUiTrace.clear(); + }); + + test('should not save data if no custom UI trace is started', () { + final frameTestdata = InstabugScreenRenderData( + traceId: 123, + frameData: [ + InstabugFrameData(10000, 200), + InstabugFrameData(20000, 1000), + ], + frozenFramesTotalDuration: 1000, + slowFramesTotalDuration: 200, + ); + + manager.setFrameData(frameTestdata); + + manager.endScreenRenderCollectorForCustomUiTrace(); + + expect(manager.screenRenderForCustomUiTrace.isEmpty, true); + expect(manager.screenRenderForCustomUiTrace == frameTestdata, false); + }); + + test( + 'should save data to screenRenderForCustomUiTrace if custom UI trace is started', + () { + final frameTestdata = InstabugScreenRenderData( + traceId: 123, + frameData: [ + InstabugFrameData(10000, 200), + InstabugFrameData(20000, 1000), + ], + frozenFramesTotalDuration: 1000, + slowFramesTotalDuration: 200, + ); + + manager.startScreenRenderCollectorForTraceId( + frameTestdata.traceId, + UiTraceType.custom, + ); + + manager.setFrameData(frameTestdata); + + manager.endScreenRenderCollectorForCustomUiTrace(); + }); + + test('should not remove timing callback listener', () { + manager.endScreenRenderCollectorForCustomUiTrace(); + + verifyNever(mWidgetBinding.removeTimingsCallback(any)); + }); + + test( + 'should report data to native when starting new trace from the same type', + () async { + ///todo: will be implemented in next sprint + }); + }); + + group('analyzeFrameTiming()', () { + late MockFrameTiming mockFrameTiming; + + setUp(() { + mockFrameTiming = MockFrameTiming(); + when(mockFrameTiming.buildDuration) + .thenReturn(const Duration(milliseconds: 1)); + when(mockFrameTiming.rasterDuration) + .thenReturn(const Duration(milliseconds: 1)); + when(mockFrameTiming.totalSpan) + .thenReturn(const Duration(milliseconds: 2)); + when(mockFrameTiming.timestampInMicroseconds(any)).thenReturn(1000); + }); + + test('should detect slow frame on ui thread and record duration', () { + const buildDuration = 20; + when(mockFrameTiming.buildDuration) + .thenReturn(const Duration(milliseconds: buildDuration)); + + manager.startScreenRenderCollectorForTraceId(1); // start new collector + manager.analyzeFrameTiming(mockFrameTiming); // mock frame timing + manager.stopScreenRenderCollector(); // should save data + + expect(manager.screenRenderForAutoUiTrace.frameData.length, 1); + expect(manager.screenRenderForAutoUiTrace.slowFramesTotalDuration, buildDuration *1000); // * 1000 to convert from milli to micro + expect(manager.screenRenderForAutoUiTrace.frozenFramesTotalDuration, 0); + + }); + + test('should detect slow frame on raster thread and record duration', () { + const rasterDuration = 20; + when(mockFrameTiming.rasterDuration) + .thenReturn(const Duration(milliseconds: rasterDuration)); + + manager.startScreenRenderCollectorForTraceId(1); // start new collector + manager.analyzeFrameTiming(mockFrameTiming); // mock frame timing + manager.stopScreenRenderCollector(); // should save data + + expect(manager.screenRenderForAutoUiTrace.frameData.length, 1); + expect(manager.screenRenderForAutoUiTrace.slowFramesTotalDuration, rasterDuration *1000); // * 1000 to convert from milli to micro + expect(manager.screenRenderForAutoUiTrace.frozenFramesTotalDuration, 0); + + }); + + test('should detect frozen frame on build thread when durations are greater than or equal 700 ms', () { + const buildDuration = 700; + when(mockFrameTiming.buildDuration) + .thenReturn(const Duration(milliseconds: buildDuration)); + manager.startScreenRenderCollectorForTraceId(1); // start new collector + manager.analyzeFrameTiming(mockFrameTiming); // mock frame timing + manager.stopScreenRenderCollector(); // should save data + + expect(manager.screenRenderForAutoUiTrace.frameData.length, 1); + expect(manager.screenRenderForAutoUiTrace.frozenFramesTotalDuration, buildDuration *1000); // * 1000 to convert from milli to micro + expect(manager.screenRenderForAutoUiTrace.slowFramesTotalDuration, 0); + + }); + + test('should detect frozen frame on raster thread when durations are greater than or equal 700 ms', () { + const rasterBuild = 700; + when(mockFrameTiming.buildDuration) + .thenReturn(const Duration(milliseconds: rasterBuild)); + manager.startScreenRenderCollectorForTraceId(1); // start new collector + manager.analyzeFrameTiming(mockFrameTiming); // mock frame timing + manager.stopScreenRenderCollector(); // should save data + + expect(manager.screenRenderForAutoUiTrace.frameData.length, 1); + expect(manager.screenRenderForAutoUiTrace.frozenFramesTotalDuration, rasterBuild *1000); // * 1000 to convert from milli to micro + expect(manager.screenRenderForAutoUiTrace.slowFramesTotalDuration, 0); + + }); + + test('should detect no slow or frozen frame under thresholds', () { + when(mockFrameTiming.buildDuration) + .thenReturn(const Duration(milliseconds: 5)); + when(mockFrameTiming.rasterDuration) + .thenReturn(const Duration(milliseconds: 5)); + when(mockFrameTiming.totalSpan) + .thenReturn(const Duration(milliseconds: 10)); + manager.analyzeFrameTiming(mockFrameTiming); + expect(manager.screenRenderForAutoUiTrace.frameData.isEmpty, true); + expect(manager.screenRenderForAutoUiTrace.frozenFramesTotalDuration, 0); // * 1000 to convert from milli to micro + expect(manager.screenRenderForAutoUiTrace.slowFramesTotalDuration, 0); + + }); + }); +} From 2faf643042e20554f05c6e12b77207af5b9cd1b8 Mon Sep 17 00:00:00 2001 From: Andrew Amin Date: Wed, 18 Jun 2025 13:54:50 +0300 Subject: [PATCH 03/84] chore: add unit tests for app lifecycle --- .../instabug_screen_render_manager.dart | 10 +- ...instabug_widget_binding_observer_test.dart | 103 ++++++++++++++++++ 2 files changed, 111 insertions(+), 2 deletions(-) create mode 100644 test/utils/screen_render/instabug_widget_binding_observer_test.dart diff --git a/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart b/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart index 55baed043..e5f1cd775 100644 --- a/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart +++ b/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart @@ -40,7 +40,7 @@ class InstabugScreenRenderManager { InstabugScreenRenderManager._(); - static final InstabugScreenRenderManager _instance = + static InstabugScreenRenderManager _instance = InstabugScreenRenderManager._(); /// Returns the singleton instance of [InstabugScreenRenderManager]. @@ -53,10 +53,16 @@ class InstabugScreenRenderManager { static const tag = "ScreenRenderManager"; /// A named constructor used for testing purposes - + @internal @visibleForTesting InstabugScreenRenderManager.init(); + /// Allows setting a custom instance for testing. + @visibleForTesting + // ignore: use_setters_to_change_properties + static void setInstance(InstabugScreenRenderManager instance) { + _instance = instance; + } /// setup function for [InstabugScreenRenderManager] @internal Future init(WidgetsBinding widgetBinding) async { diff --git a/test/utils/screen_render/instabug_widget_binding_observer_test.dart b/test/utils/screen_render/instabug_widget_binding_observer_test.dart new file mode 100644 index 000000000..8c5d952c5 --- /dev/null +++ b/test/utils/screen_render/instabug_widget_binding_observer_test.dart @@ -0,0 +1,103 @@ +import 'package:flutter/widgets.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:instabug_flutter/src/utils/screen_loading/screen_loading_manager.dart'; +import 'package:instabug_flutter/src/utils/screen_name_masker.dart'; +import 'package:instabug_flutter/src/utils/screen_rendering/instabug_screen_render_manager.dart'; +import 'package:instabug_flutter/src/utils/screen_rendering/instabug_widget_binding_observer.dart'; +import 'package:instabug_flutter/src/utils/ui_trace/ui_trace.dart'; +import 'package:mockito/annotations.dart'; +import 'package:mockito/mockito.dart'; + +import 'instabug_widget_binding_observer_test.mocks.dart'; + +@GenerateMocks([ + InstabugScreenRenderManager, + ScreenLoadingManager, + ScreenNameMasker, + UiTrace, +]) +void main() { + late MockInstabugScreenRenderManager mockRenderManager; + late MockScreenLoadingManager mockLoadingManager; + late MockScreenNameMasker mockNameMasker; + late MockUiTrace mockUiTrace; + + setUp(() { + mockRenderManager = MockInstabugScreenRenderManager(); + mockLoadingManager = MockScreenLoadingManager(); + mockNameMasker = MockScreenNameMasker(); + mockUiTrace = MockUiTrace(); + + // Inject singleton mocks + InstabugScreenRenderManager.setInstance(mockRenderManager); + ScreenLoadingManager.setInstance(mockLoadingManager); + ScreenNameMasker.setInstance(mockNameMasker); + }); + + group('InstabugWidgetsBindingObserver', () { + test('returns the singleton instance', () { + final instance = InstabugWidgetsBindingObserver.instance; + final shorthand = InstabugWidgetsBindingObserver.I; + expect(instance, isA()); + expect(shorthand, same(instance)); + }); + + test('handles AppLifecycleState.resumed and starts UiTrace', () async { + when(mockLoadingManager.currentUiTrace).thenReturn(mockUiTrace); + when(mockUiTrace.screenName).thenReturn("HomeScreen"); + when(mockNameMasker.mask("HomeScreen")).thenReturn("MaskedHome"); + when(mockLoadingManager.startUiTrace("MaskedHome", "HomeScreen")) + .thenAnswer((_) async => 123); + + InstabugWidgetsBindingObserver.I + .didChangeAppLifecycleState(AppLifecycleState.resumed); + + // wait for async call to complete + await untilCalled( + mockRenderManager.startScreenRenderCollectorForTraceId(123)); + + verify(mockRenderManager.startScreenRenderCollectorForTraceId(123)) + .called(1); + }); + + test('handles AppLifecycleState.paused and stops render collector', () { + InstabugWidgetsBindingObserver.I + .didChangeAppLifecycleState(AppLifecycleState.paused); + verify(mockRenderManager.stopScreenRenderCollector()).called(1); + }); + + test('handles AppLifecycleState.detached and stops render collector', () { + InstabugWidgetsBindingObserver.I + .didChangeAppLifecycleState(AppLifecycleState.detached); + verify(mockRenderManager.stopScreenRenderCollector()).called(1); + }); + + test('handles AppLifecycleState.inactive with no action', () { + // Just ensure it doesn't crash + expect(() { + InstabugWidgetsBindingObserver.I + .didChangeAppLifecycleState(AppLifecycleState.inactive); + }, returnsNormally); + }); + + test('handles AppLifecycleState.hidden with no action', () { + expect(() { + InstabugWidgetsBindingObserver.I + .didChangeAppLifecycleState(AppLifecycleState.hidden); + }, returnsNormally); + }); + + test('_handleResumedState does nothing if no currentUiTrace', () { + when(mockLoadingManager.currentUiTrace).thenReturn(null); + + InstabugWidgetsBindingObserver.I + .didChangeAppLifecycleState(AppLifecycleState.resumed); + + verifyNever(mockRenderManager.startScreenRenderCollectorForTraceId(any)); + }); + + test('checkForWidgetBinding ensures initialization', () { + expect(() => checkForWidgetBinding(), returnsNormally); + }); + }); +} From 21cc57baa8d9eb6a57fc20d51293744cf50934ca Mon Sep 17 00:00:00 2001 From: Andrew Amin Date: Thu, 19 Jun 2025 21:42:07 +0300 Subject: [PATCH 04/84] chore: fix related uint testing files , fix implementation logic. --- .../lib/src/screens/screen_render_page.dart | 31 +++++-- lib/src/modules/instabug.dart | 2 +- .../utils/instabug_navigator_observer.dart | 3 +- .../instabug_screen_render_manager.dart | 55 +++++++------ .../instabug_widget_binding_observer.dart | 6 +- test/apm_test.dart | 6 +- test/instabug_test.dart | 8 ++ .../instabug_navigator_observer_test.dart | 9 +-- .../instabug_screen_render_manager_test.dart | 81 ++++++++++++------- ...instabug_widget_binding_observer_test.dart | 26 +++--- 10 files changed, 144 insertions(+), 83 deletions(-) diff --git a/example/lib/src/screens/screen_render_page.dart b/example/lib/src/screens/screen_render_page.dart index 924eefab2..a6c97cb23 100644 --- a/example/lib/src/screens/screen_render_page.dart +++ b/example/lib/src/screens/screen_render_page.dart @@ -1,17 +1,32 @@ part of '../../main.dart'; -class ScreenRenderPage extends StatelessWidget { +class ScreenRenderPage extends StatefulWidget { const ScreenRenderPage({Key? key}) : super(key: key); static const String screenName = "/screenRenderPageRoute"; + @override + State createState() => _ScreenRenderPageState(); +} + +class _ScreenRenderPageState extends State { + final durationController = TextEditingController(); + @override Widget build(BuildContext context) { return Page(title: 'Screen Render', children: [ - + SizedBox.fromSize(size: const Size.fromHeight(16.0)), const AnimatedBox(), - SizedBox.fromSize(size: const Size.fromHeight(50),), + SizedBox.fromSize( + size: const Size.fromHeight(50), + ), + InstabugTextField( + label: 'Frame duration in milliseconds', + labelStyle: Theme.of(context).textTheme.labelMedium, + controller: durationController, + ), + SizedBox.fromSize(size: const Size.fromHeight(16.0)), InstabugButton( - text: 'Perform Frozen Frame', + text: 'Perform Heavy Computation', onPressed: () => _simulateHeavyComputation(), ), InstabugButton( @@ -36,9 +51,13 @@ class ScreenRenderPage extends StatelessWidget { // Simulates a computationally expensive task void _simulateHeavyComputation() { final startTime = DateTime.now(); + final pauseTime = double.tryParse(durationController.text.trim()); // Block the UI thread for ~500ms - while (DateTime.now().difference(startTime).inMilliseconds <= 1000) { - // Busy waiting (not recommended in real apps) + if (pauseTime == null) { + return log("enter a valid number"); + } + while (DateTime.now().difference(startTime).inMilliseconds <= pauseTime) { + // Busy waiting } } } diff --git a/lib/src/modules/instabug.dart b/lib/src/modules/instabug.dart index 0a832526b..4b079ab99 100644 --- a/lib/src/modules/instabug.dart +++ b/lib/src/modules/instabug.dart @@ -198,7 +198,7 @@ class Instabug { if (await FlagsConfig.screenRendering.isEnabled()) { checkForWidgetBinding(); - await InstabugScreenRenderManager.I.init(WidgetsBinding.instance); + InstabugScreenRenderManager.I.init(WidgetsBinding.instance); } return FeatureFlagsManager().registerW3CFlagsListener(); diff --git a/lib/src/utils/instabug_navigator_observer.dart b/lib/src/utils/instabug_navigator_observer.dart index e185347ad..775236f2b 100644 --- a/lib/src/utils/instabug_navigator_observer.dart +++ b/lib/src/utils/instabug_navigator_observer.dart @@ -28,7 +28,8 @@ class InstabugNavigatorObserver extends NavigatorObserver { ScreenLoadingManager.I .startUiTrace(maskedScreenName, screenName) .then((uiTraceId) { - if (uiTraceId != null) { + if (uiTraceId != null && + InstabugScreenRenderManager.I.screenRenderEnabled) { InstabugScreenRenderManager.I .startScreenRenderCollectorForTraceId(uiTraceId); } diff --git a/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart b/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart index e5f1cd775..bc5c7fc71 100644 --- a/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart +++ b/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart @@ -8,6 +8,7 @@ import 'package:instabug_flutter/src/modules/apm.dart'; import 'package:instabug_flutter/src/utils/screen_rendering/instabug_widget_binding_observer.dart'; import 'package:meta/meta.dart'; +//todo: remove logs extension on int { int get inMicro => this * 1000; } @@ -37,10 +38,10 @@ class InstabugScreenRenderManager { int _frozenFramesTotalDuration = 0; bool _isTimingsListenerAttached = false; - + bool screenRenderEnabled = false; InstabugScreenRenderManager._(); - static InstabugScreenRenderManager _instance = + static InstabugScreenRenderManager _instance = InstabugScreenRenderManager._(); /// Returns the singleton instance of [InstabugScreenRenderManager]. @@ -52,25 +53,15 @@ class InstabugScreenRenderManager { /// Logging tag for debugging purposes. static const tag = "ScreenRenderManager"; - /// A named constructor used for testing purposes - @internal - @visibleForTesting - InstabugScreenRenderManager.init(); - - /// Allows setting a custom instance for testing. - @visibleForTesting - // ignore: use_setters_to_change_properties - static void setInstance(InstabugScreenRenderManager instance) { - _instance = instance; - } /// setup function for [InstabugScreenRenderManager] @internal - Future init(WidgetsBinding widgetBinding) async { + void init(WidgetsBinding widgetBinding, [double? refreshRate]) { if (!_isTimingsListenerAttached) { _widgetsBinding = widgetBinding; _addWidgetBindingObserver(); - await _initStaticValues(); + _initStaticValues(refreshRate); _initFrameTimings(); + screenRenderEnabled = true; } } @@ -153,22 +144,24 @@ class InstabugScreenRenderManager { /// Presently, on Android and Web this collection will only contain the display that the current window is on. /// On iOS, it will only contains the main display on the phone or tablet. /// On Desktop, it will contain only a main display with a valid refresh rate but invalid size and device pixel ratio values. - //todo: will be removed after getting the actual value from native side. + //todo: will be compared with value from native side after it's implemented. double get _getDeviceRefreshRate => - _widgetsBinding.platformDispatcher.displays.last.refreshRate; + _widgetsBinding.platformDispatcher.displays.first.refreshRate; /// Get device refresh rate from native side. + //todo: will be compared with value from native side after it's implemented. + // ignore: unused_element Future get _getDeviceRefreshRateFromNative => APM.getDeviceRefreshRate(); /// Initialize the static variables - Future _initStaticValues() async { + void _initStaticValues(double? refreshRate) { _timingsCallback = (timings) { for (final frameTiming in timings) { analyzeFrameTiming(frameTiming); } }; - _deviceRefreshRate = await _getDeviceRefreshRateFromNative; + _deviceRefreshRate = refreshRate ?? _getDeviceRefreshRate; _slowFrameThresholdMs = _targetMsPerFrame(_deviceRefreshRate); _screenRenderForAutoUiTrace = InstabugScreenRenderData(frameData: []); _screenRenderForCustomUiTrace = InstabugScreenRenderData(frameData: []); @@ -270,7 +263,7 @@ class InstabugScreenRenderManager { _delayedFrames.add(InstabugFrameData(startTime, duration)); } - //todo: to be removed + //todo: will be removed void _displayFrameTimingDetails(FrameTiming frameTiming) { if (_isSlow) { debugPrint( @@ -306,15 +299,19 @@ class InstabugScreenRenderManager { } @visibleForTesting - Future reportScreenRending(InstabugScreenRenderData screenRenderData, - [UiTraceType type = UiTraceType.auto]) async { + Future reportScreenRending( + InstabugScreenRenderData screenRenderData, [ + UiTraceType type = UiTraceType.auto, + ]) async { if (type == UiTraceType.auto) { _reportScreenRenderForAutoUiTrace(screenRenderData); } else { _reportScreenRenderForCustomUiTrace(screenRenderData); } - log("Reported Data (${type == UiTraceType.auto ? 'auto' : 'custom'}): $screenRenderData", - name: tag); + log( + "Reported Data (${type == UiTraceType.auto ? 'auto' : 'custom'}): $screenRenderData", + name: tag, + ); } Future _reportScreenRenderForCustomUiTrace( @@ -348,6 +345,16 @@ class InstabugScreenRenderManager { } /// --------------------------- testing helper functions --------------------- + + @visibleForTesting + InstabugScreenRenderManager.init(); + + @visibleForTesting + // ignore: use_setters_to_change_properties + static void setInstance(InstabugScreenRenderManager instance) { + _instance = instance; + } + @visibleForTesting InstabugScreenRenderData get screenRenderForAutoUiTrace => _screenRenderForAutoUiTrace; diff --git a/lib/src/utils/screen_rendering/instabug_widget_binding_observer.dart b/lib/src/utils/screen_rendering/instabug_widget_binding_observer.dart index 053beaed8..caf768be3 100644 --- a/lib/src/utils/screen_rendering/instabug_widget_binding_observer.dart +++ b/lib/src/utils/screen_rendering/instabug_widget_binding_observer.dart @@ -5,11 +5,12 @@ import 'package:instabug_flutter/src/utils/screen_name_masker.dart'; import 'package:instabug_flutter/src/utils/screen_rendering/instabug_screen_render_manager.dart'; import 'package:meta/meta.dart'; +//todo: remove logs class InstabugWidgetsBindingObserver extends WidgetsBindingObserver { InstabugWidgetsBindingObserver._(); static final InstabugWidgetsBindingObserver _instance = - InstabugWidgetsBindingObserver._(); + InstabugWidgetsBindingObserver._(); /// Returns the singleton instance of [InstabugWidgetsBindingObserver]. static InstabugWidgetsBindingObserver get instance => _instance; @@ -28,7 +29,8 @@ class InstabugWidgetsBindingObserver extends WidgetsBindingObserver { ScreenLoadingManager.I .startUiTrace(maskedScreenName, lastUiTrace.screenName) .then((uiTraceId) { - if (uiTraceId != null) { + if (uiTraceId != null && + InstabugScreenRenderManager.I.screenRenderEnabled) { InstabugScreenRenderManager.I .startScreenRenderCollectorForTraceId(uiTraceId); } diff --git a/test/apm_test.dart b/test/apm_test.dart index c801926f3..4e8ec87a6 100644 --- a/test/apm_test.dart +++ b/test/apm_test.dart @@ -165,6 +165,9 @@ void main() { test('[startUITrace] should call host method', () async { const name = 'UI-trace'; + //disable the feature flag for screen render feature in order to skip its checking. + when(mHost.isScreenRenderEnabled()).thenAnswer((_) async => false); + await APM.startUITrace(name); verify( @@ -214,7 +217,6 @@ void main() { verify( mHost.startCpUiTrace(screenName, microTimeStamp, traceId), ).called(1); - verifyNoMoreInteractions(mHost); }); test('[reportScreenLoading] should call host method', () async { @@ -235,7 +237,6 @@ void main() { uiTraceId, ), ).called(1); - verifyNoMoreInteractions(mHost); }); test('[endScreenLoading] should call host method', () async { @@ -247,7 +248,6 @@ void main() { verify( mHost.endScreenLoadingCP(timeStampMicro, uiTraceId), ).called(1); - verifyNoMoreInteractions(mHost); }); test('[isSEndScreenLoadingEnabled] should call host method', () async { diff --git a/test/instabug_test.dart b/test/instabug_test.dart index e2fd7d298..3afb6648c 100644 --- a/test/instabug_test.dart +++ b/test/instabug_test.dart @@ -3,6 +3,7 @@ import 'dart:typed_data'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:instabug_flutter/instabug_flutter.dart'; +import 'package:instabug_flutter/src/generated/apm.api.g.dart'; import 'package:instabug_flutter/src/generated/instabug.api.g.dart'; import 'package:instabug_flutter/src/utils/enum_converter.dart'; import 'package:instabug_flutter/src/utils/feature_flags_manager.dart'; @@ -17,6 +18,7 @@ import 'instabug_test.mocks.dart'; InstabugHostApi, IBGBuildInfo, ScreenNameMasker, + ApmHostApi, ]) void main() { TestWidgetsFlutterBinding.ensureInitialized(); @@ -25,12 +27,14 @@ void main() { final mHost = MockInstabugHostApi(); final mBuildInfo = MockIBGBuildInfo(); final mScreenNameMasker = MockScreenNameMasker(); + final mApmHost = MockApmHostApi(); setUpAll(() { Instabug.$setHostApi(mHost); FeatureFlagsManager().$setHostApi(mHost); IBGBuildInfo.setInstance(mBuildInfo); ScreenNameMasker.setInstance(mScreenNameMasker); + APM.$setHostApi(mApmHost); }); test('[setEnabled] should call host method', () async { @@ -78,6 +82,10 @@ void main() { "isW3cCaughtHeaderEnabled": true, }), ); + + //disable the feature flag for screen render feature in order to skip its checking. + when(mApmHost.isScreenRenderEnabled()).thenAnswer((_) async => false); + await Instabug.init( token: token, invocationEvents: events, diff --git a/test/utils/instabug_navigator_observer_test.dart b/test/utils/instabug_navigator_observer_test.dart index ebf541137..81a9f174e 100644 --- a/test/utils/instabug_navigator_observer_test.dart +++ b/test/utils/instabug_navigator_observer_test.dart @@ -10,13 +10,10 @@ import 'package:mockito/mockito.dart'; import 'instabug_navigator_observer_test.mocks.dart'; -@GenerateMocks([ - InstabugHostApi, - ScreenLoadingManager, -]) +@GenerateMocks([InstabugHostApi]) +@GenerateNiceMocks([MockSpec()]) void main() { TestWidgetsFlutterBinding.ensureInitialized(); - WidgetsFlutterBinding.ensureInitialized(); final mHost = MockInstabugHostApi(); final mScreenLoadingManager = MockScreenLoadingManager(); @@ -41,7 +38,7 @@ void main() { }); test('should report screen change when a route is pushed', () { - fakeAsync((async) { + fakeAsync((async) async { observer.didPush(route, previousRoute); async.elapse(const Duration(milliseconds: 1000)); diff --git a/test/utils/screen_render/instabug_screen_render_manager_test.dart b/test/utils/screen_render/instabug_screen_render_manager_test.dart index 1f0f404b0..37879753a 100644 --- a/test/utils/screen_render/instabug_screen_render_manager_test.dart +++ b/test/utils/screen_render/instabug_screen_render_manager_test.dart @@ -19,6 +19,7 @@ void main() { late InstabugScreenRenderManager manager; late MockApmHostApi mApmHost; late MockWidgetsBinding mWidgetBinding; + const mRefreshRate = 60.0; setUp(() async { mApmHost = MockApmHostApi(); @@ -26,9 +27,7 @@ void main() { manager = InstabugScreenRenderManager.init(); // test-only constructor APM.$setHostApi(mApmHost); - when(mApmHost.deviceRefreshRate()).thenAnswer((_) async => 60); - await manager.init(mWidgetBinding); - await untilCalled(mApmHost.deviceRefreshRate()); + manager.init(mWidgetBinding, mRefreshRate); }); tearDown(() { @@ -45,9 +44,11 @@ void main() { }); test('calling init more that one time should do nothing', () async { - await manager.init(mWidgetBinding); - await manager.init(mWidgetBinding); // second call should be ignored - + manager.init(mWidgetBinding, mRefreshRate); + manager.init( + mWidgetBinding, + mRefreshRate, + ); // second call should be ignored verify(mWidgetBinding.addObserver(any)).called(1); @@ -65,7 +66,7 @@ void main() { verify(mWidgetBinding.addTimingsCallback(any)).called( 1, - ); // the one form init() + ); // the one form initForTesting() }); test( @@ -81,7 +82,7 @@ void main() { verify(mWidgetBinding.addTimingsCallback(any)).called( 2, - ); // one form init() and one form startScreenRenderCollectorForTraceId() + ); // one form initForTesting() and one form startScreenRenderCollectorForTraceId() }); test('should update the data for same trace type', () { @@ -91,12 +92,14 @@ void main() { expect(manager.screenRenderForAutoUiTrace.isNotEmpty, false); manager.startScreenRenderCollectorForTraceId( - firstTraceId, UiTraceType.auto); + firstTraceId, + ); expect(manager.screenRenderForAutoUiTrace.isNotEmpty, true); expect(manager.screenRenderForAutoUiTrace.traceId, firstTraceId); manager.startScreenRenderCollectorForTraceId( - secondTraceId, UiTraceType.auto); + secondTraceId, + ); expect(manager.screenRenderForAutoUiTrace.isNotEmpty, true); expect(manager.screenRenderForAutoUiTrace.traceId, secondTraceId); }); @@ -109,12 +112,15 @@ void main() { expect(manager.screenRenderForCustomUiTrace.isNotEmpty, false); manager.startScreenRenderCollectorForTraceId( - firstTraceId, UiTraceType.auto); + firstTraceId, + ); expect(manager.screenRenderForAutoUiTrace.isNotEmpty, true); expect(manager.screenRenderForAutoUiTrace.traceId, firstTraceId); manager.startScreenRenderCollectorForTraceId( - secondTraceId, UiTraceType.custom); + secondTraceId, + UiTraceType.custom, + ); expect(manager.screenRenderForAutoUiTrace.traceId, firstTraceId); expect(manager.screenRenderForCustomUiTrace.traceId, secondTraceId); }); @@ -158,7 +164,6 @@ void main() { manager.startScreenRenderCollectorForTraceId( frameTestdata.traceId, - UiTraceType.auto, ); manager.setFrameData(frameTestdata); @@ -209,9 +214,9 @@ void main() { test( 'should report data to native when starting new trace from the same type', - () async { - ///todo: will be implemented in next sprint - }); + () async { + ///todo: will be implemented in next sprint + }); }); group('endScreenRenderCollectorForCustomUiTrace()', () { @@ -270,9 +275,9 @@ void main() { test( 'should report data to native when starting new trace from the same type', - () async { - ///todo: will be implemented in next sprint - }); + () async { + ///todo: will be implemented in next sprint + }); }); group('analyzeFrameTiming()', () { @@ -299,9 +304,11 @@ void main() { manager.stopScreenRenderCollector(); // should save data expect(manager.screenRenderForAutoUiTrace.frameData.length, 1); - expect(manager.screenRenderForAutoUiTrace.slowFramesTotalDuration, buildDuration *1000); // * 1000 to convert from milli to micro + expect( + manager.screenRenderForAutoUiTrace.slowFramesTotalDuration, + buildDuration * 1000, + ); // * 1000 to convert from milli to micro expect(manager.screenRenderForAutoUiTrace.frozenFramesTotalDuration, 0); - }); test('should detect slow frame on raster thread and record duration', () { @@ -314,12 +321,16 @@ void main() { manager.stopScreenRenderCollector(); // should save data expect(manager.screenRenderForAutoUiTrace.frameData.length, 1); - expect(manager.screenRenderForAutoUiTrace.slowFramesTotalDuration, rasterDuration *1000); // * 1000 to convert from milli to micro + expect( + manager.screenRenderForAutoUiTrace.slowFramesTotalDuration, + rasterDuration * 1000, + ); // * 1000 to convert from milli to micro expect(manager.screenRenderForAutoUiTrace.frozenFramesTotalDuration, 0); - }); - test('should detect frozen frame on build thread when durations are greater than or equal 700 ms', () { + test( + 'should detect frozen frame on build thread when durations are greater than or equal 700 ms', + () { const buildDuration = 700; when(mockFrameTiming.buildDuration) .thenReturn(const Duration(milliseconds: buildDuration)); @@ -328,12 +339,16 @@ void main() { manager.stopScreenRenderCollector(); // should save data expect(manager.screenRenderForAutoUiTrace.frameData.length, 1); - expect(manager.screenRenderForAutoUiTrace.frozenFramesTotalDuration, buildDuration *1000); // * 1000 to convert from milli to micro + expect( + manager.screenRenderForAutoUiTrace.frozenFramesTotalDuration, + buildDuration * 1000, + ); // * 1000 to convert from milli to micro expect(manager.screenRenderForAutoUiTrace.slowFramesTotalDuration, 0); - }); - test('should detect frozen frame on raster thread when durations are greater than or equal 700 ms', () { + test( + 'should detect frozen frame on raster thread when durations are greater than or equal 700 ms', + () { const rasterBuild = 700; when(mockFrameTiming.buildDuration) .thenReturn(const Duration(milliseconds: rasterBuild)); @@ -342,9 +357,11 @@ void main() { manager.stopScreenRenderCollector(); // should save data expect(manager.screenRenderForAutoUiTrace.frameData.length, 1); - expect(manager.screenRenderForAutoUiTrace.frozenFramesTotalDuration, rasterBuild *1000); // * 1000 to convert from milli to micro + expect( + manager.screenRenderForAutoUiTrace.frozenFramesTotalDuration, + rasterBuild * 1000, + ); // * 1000 to convert from milli to micro expect(manager.screenRenderForAutoUiTrace.slowFramesTotalDuration, 0); - }); test('should detect no slow or frozen frame under thresholds', () { @@ -356,9 +373,11 @@ void main() { .thenReturn(const Duration(milliseconds: 10)); manager.analyzeFrameTiming(mockFrameTiming); expect(manager.screenRenderForAutoUiTrace.frameData.isEmpty, true); - expect(manager.screenRenderForAutoUiTrace.frozenFramesTotalDuration, 0); // * 1000 to convert from milli to micro + expect( + manager.screenRenderForAutoUiTrace.frozenFramesTotalDuration, + 0, + ); // * 1000 to convert from milli to micro expect(manager.screenRenderForAutoUiTrace.slowFramesTotalDuration, 0); - }); }); } diff --git a/test/utils/screen_render/instabug_widget_binding_observer_test.dart b/test/utils/screen_render/instabug_widget_binding_observer_test.dart index 8c5d952c5..58bbe92d8 100644 --- a/test/utils/screen_render/instabug_widget_binding_observer_test.dart +++ b/test/utils/screen_render/instabug_widget_binding_observer_test.dart @@ -48,13 +48,15 @@ void main() { when(mockNameMasker.mask("HomeScreen")).thenReturn("MaskedHome"); when(mockLoadingManager.startUiTrace("MaskedHome", "HomeScreen")) .thenAnswer((_) async => 123); + when(mockRenderManager.screenRenderEnabled).thenReturn(true); InstabugWidgetsBindingObserver.I .didChangeAppLifecycleState(AppLifecycleState.resumed); // wait for async call to complete await untilCalled( - mockRenderManager.startScreenRenderCollectorForTraceId(123)); + mockRenderManager.startScreenRenderCollectorForTraceId(123), + ); verify(mockRenderManager.startScreenRenderCollectorForTraceId(123)) .called(1); @@ -74,17 +76,23 @@ void main() { test('handles AppLifecycleState.inactive with no action', () { // Just ensure it doesn't crash - expect(() { - InstabugWidgetsBindingObserver.I - .didChangeAppLifecycleState(AppLifecycleState.inactive); - }, returnsNormally); + expect( + () { + InstabugWidgetsBindingObserver.I + .didChangeAppLifecycleState(AppLifecycleState.inactive); + }, + returnsNormally, + ); }); test('handles AppLifecycleState.hidden with no action', () { - expect(() { - InstabugWidgetsBindingObserver.I - .didChangeAppLifecycleState(AppLifecycleState.hidden); - }, returnsNormally); + expect( + () { + InstabugWidgetsBindingObserver.I + .didChangeAppLifecycleState(AppLifecycleState.hidden); + }, + returnsNormally, + ); }); test('_handleResumedState does nothing if no currentUiTrace', () { From 35a0c5aabbb187a8224b43e16e216ece08864f95 Mon Sep 17 00:00:00 2001 From: Andrew Amin Date: Sat, 21 Jun 2025 18:42:06 +0300 Subject: [PATCH 05/84] chore: fix ci failed jobs --- example/lib/src/components/animated_box.dart | 2 +- example/lib/src/components/ui_traces_content.dart | 1 - lib/src/models/InstabugFrameData.dart | 2 +- lib/src/models/InstabugScreenRenderData.dart | 2 -- lib/src/modules/apm.dart | 5 +++-- .../instabug_screen_render_manager.dart | 12 ++++++------ .../instabug_widget_binding_observer.dart | 13 +++++++------ .../instabug_screen_render_manager_test.dart | 8 +++----- 8 files changed, 21 insertions(+), 24 deletions(-) diff --git a/example/lib/src/components/animated_box.dart b/example/lib/src/components/animated_box.dart index 4eec36bcd..fc0a8e362 100644 --- a/example/lib/src/components/animated_box.dart +++ b/example/lib/src/components/animated_box.dart @@ -16,7 +16,7 @@ class _AnimatedBoxState extends State void initState() { super.initState(); _controller = AnimationController( - duration: const Duration(minutes: 1 , seconds: 40), + duration: const Duration(minutes: 1, seconds: 40), vsync: this, ); _animation = Tween(begin: 0, end: 100).animate(_controller) diff --git a/example/lib/src/components/ui_traces_content.dart b/example/lib/src/components/ui_traces_content.dart index 19e9ec0dd..b05144408 100644 --- a/example/lib/src/components/ui_traces_content.dart +++ b/example/lib/src/components/ui_traces_content.dart @@ -49,7 +49,6 @@ class _UITracesContentState extends State { ), ], ), - ], ); } diff --git a/lib/src/models/InstabugFrameData.dart b/lib/src/models/InstabugFrameData.dart index d62368c3a..6c9c1ae8a 100644 --- a/lib/src/models/InstabugFrameData.dart +++ b/lib/src/models/InstabugFrameData.dart @@ -8,7 +8,7 @@ class InstabugFrameData { String toString() => "start time: $startTimeTimestamp, duration: $duration"; @override - bool operator == (covariant InstabugFrameData other) { + bool operator ==(covariant InstabugFrameData other) { if (identical(this, other)) return true; return startTimeTimestamp == other.startTimeTimestamp && duration == other.duration; diff --git a/lib/src/models/InstabugScreenRenderData.dart b/lib/src/models/InstabugScreenRenderData.dart index ed5f4a2f3..1e093de98 100644 --- a/lib/src/models/InstabugScreenRenderData.dart +++ b/lib/src/models/InstabugScreenRenderData.dart @@ -39,6 +39,4 @@ class InstabugScreenRenderData { frozenFramesTotalDuration == other.frozenFramesTotalDuration && listEquals(frameData, other.frameData); } - - } diff --git a/lib/src/modules/apm.dart b/lib/src/modules/apm.dart index 43af7b7d7..efd9dc609 100644 --- a/lib/src/modules/apm.dart +++ b/lib/src/modules/apm.dart @@ -195,7 +195,8 @@ class APM { (_) async { // Start screen render collector for custom ui trace if enabled. if (await FlagsConfig.screenRendering.isEnabled()) { - InstabugScreenRenderManager.I.startScreenRenderCollectorForTraceId(0 ,UiTraceType.custom); + InstabugScreenRenderManager.I + .startScreenRenderCollectorForTraceId(0, UiTraceType.custom); } }, ); @@ -377,7 +378,7 @@ class APM { /// Returns: /// A Future that represent the refresh rate. @internal - static Future getDeviceRefreshRate(){ + static Future getDeviceRefreshRate() { return _host.deviceRefreshRate(); } } diff --git a/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart b/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart index bc5c7fc71..34f17f60c 100644 --- a/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart +++ b/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart @@ -55,11 +55,11 @@ class InstabugScreenRenderManager { /// setup function for [InstabugScreenRenderManager] @internal - void init(WidgetsBinding widgetBinding, [double? refreshRate]) { + Future init(WidgetsBinding widgetBinding) async { if (!_isTimingsListenerAttached) { _widgetsBinding = widgetBinding; _addWidgetBindingObserver(); - _initStaticValues(refreshRate); + await _initStaticValues(); _initFrameTimings(); screenRenderEnabled = true; } @@ -145,8 +145,8 @@ class InstabugScreenRenderManager { /// On iOS, it will only contains the main display on the phone or tablet. /// On Desktop, it will contain only a main display with a valid refresh rate but invalid size and device pixel ratio values. //todo: will be compared with value from native side after it's implemented. - double get _getDeviceRefreshRate => - _widgetsBinding.platformDispatcher.displays.first.refreshRate; + // double get _getDeviceRefreshRate => + // _widgetsBinding.platformDispatcher.displays.first.refreshRate; /// Get device refresh rate from native side. //todo: will be compared with value from native side after it's implemented. @@ -155,13 +155,13 @@ class InstabugScreenRenderManager { APM.getDeviceRefreshRate(); /// Initialize the static variables - void _initStaticValues(double? refreshRate) { + Future _initStaticValues() async { _timingsCallback = (timings) { for (final frameTiming in timings) { analyzeFrameTiming(frameTiming); } }; - _deviceRefreshRate = refreshRate ?? _getDeviceRefreshRate; + _deviceRefreshRate = await _getDeviceRefreshRateFromNative; _slowFrameThresholdMs = _targetMsPerFrame(_deviceRefreshRate); _screenRenderForAutoUiTrace = InstabugScreenRenderData(frameData: []); _screenRenderForCustomUiTrace = InstabugScreenRenderData(frameData: []); diff --git a/lib/src/utils/screen_rendering/instabug_widget_binding_observer.dart b/lib/src/utils/screen_rendering/instabug_widget_binding_observer.dart index caf768be3..89ba6886a 100644 --- a/lib/src/utils/screen_rendering/instabug_widget_binding_observer.dart +++ b/lib/src/utils/screen_rendering/instabug_widget_binding_observer.dart @@ -60,14 +60,15 @@ class InstabugWidgetsBindingObserver extends WidgetsBindingObserver { case AppLifecycleState.detached: _handleDetachedState(); break; - case AppLifecycleState.inactive: - // TODO: Handle this case. - break; - case AppLifecycleState.hidden: - // TODO: Handle this case. - break; + default: + _handleDefaultState(); } } + + void _handleDefaultState() { + //todo: will be removed + debugPrint("default"); + } } @internal diff --git a/test/utils/screen_render/instabug_screen_render_manager_test.dart b/test/utils/screen_render/instabug_screen_render_manager_test.dart index 37879753a..563703018 100644 --- a/test/utils/screen_render/instabug_screen_render_manager_test.dart +++ b/test/utils/screen_render/instabug_screen_render_manager_test.dart @@ -19,15 +19,14 @@ void main() { late InstabugScreenRenderManager manager; late MockApmHostApi mApmHost; late MockWidgetsBinding mWidgetBinding; - const mRefreshRate = 60.0; setUp(() async { mApmHost = MockApmHostApi(); mWidgetBinding = MockWidgetsBinding(); manager = InstabugScreenRenderManager.init(); // test-only constructor APM.$setHostApi(mApmHost); - - manager.init(mWidgetBinding, mRefreshRate); + when(mApmHost.deviceRefreshRate()).thenAnswer((_) async => 60); + manager.init(mWidgetBinding); }); tearDown(() { @@ -44,10 +43,9 @@ void main() { }); test('calling init more that one time should do nothing', () async { - manager.init(mWidgetBinding, mRefreshRate); + manager.init(mWidgetBinding); manager.init( mWidgetBinding, - mRefreshRate, ); // second call should be ignored verify(mWidgetBinding.addObserver(any)).called(1); From 953cb536e727a0f468dd348a1387c50e01101e8a Mon Sep 17 00:00:00 2001 From: Andrew Amin Date: Sun, 22 Jun 2025 11:18:21 +0300 Subject: [PATCH 06/84] chore: fix ci failed jobs --- lib/instabug_flutter.dart | 3 +-- ...rameData.dart => instabug_frame_data.dart} | 1 + ....dart => instabug_screen_render_data.dart} | 3 ++- lib/src/modules/instabug.dart | 1 + .../screen_loading_manager.dart | 2 +- .../instabug_screen_render_manager.dart | 22 ++++++------------- .../instabug_widget_binding_observer.dart | 2 +- test/instabug_test.dart | 1 + .../screen_loading_manager_test.dart | 2 +- .../instabug_screen_render_manager_test.dart | 5 +++-- ...instabug_widget_binding_observer_test.dart | 10 --------- 11 files changed, 19 insertions(+), 33 deletions(-) rename lib/src/models/{InstabugFrameData.dart => instabug_frame_data.dart} (93%) rename lib/src/models/{InstabugScreenRenderData.dart => instabug_screen_render_data.dart} (92%) diff --git a/lib/instabug_flutter.dart b/lib/instabug_flutter.dart index edf703ba3..d2df80429 100644 --- a/lib/instabug_flutter.dart +++ b/lib/instabug_flutter.dart @@ -5,7 +5,6 @@ export 'src/models/feature_flag.dart'; export 'src/models/network_data.dart'; export 'src/models/trace.dart'; export 'src/models/w3c_header.dart'; - // Modules export 'src/modules/apm.dart'; export 'src/modules/bug_reporting.dart'; @@ -20,5 +19,5 @@ export 'src/modules/surveys.dart'; // Utils export 'src/utils/instabug_navigator_observer.dart'; export 'src/utils/screen_loading/instabug_capture_screen_loading.dart'; -export 'src/utils/ui_trace/route_matcher.dart'; export 'src/utils/screen_name_masker.dart' show ScreenNameMaskingCallback; +export 'src/utils/ui_trace/route_matcher.dart'; diff --git a/lib/src/models/InstabugFrameData.dart b/lib/src/models/instabug_frame_data.dart similarity index 93% rename from lib/src/models/InstabugFrameData.dart rename to lib/src/models/instabug_frame_data.dart index 6c9c1ae8a..60bda2550 100644 --- a/lib/src/models/InstabugFrameData.dart +++ b/lib/src/models/instabug_frame_data.dart @@ -8,6 +8,7 @@ class InstabugFrameData { String toString() => "start time: $startTimeTimestamp, duration: $duration"; @override + // ignore: hash_and_equals bool operator ==(covariant InstabugFrameData other) { if (identical(this, other)) return true; return startTimeTimestamp == other.startTimeTimestamp && diff --git a/lib/src/models/InstabugScreenRenderData.dart b/lib/src/models/instabug_screen_render_data.dart similarity index 92% rename from lib/src/models/InstabugScreenRenderData.dart rename to lib/src/models/instabug_screen_render_data.dart index 1e093de98..11a002345 100644 --- a/lib/src/models/InstabugScreenRenderData.dart +++ b/lib/src/models/instabug_screen_render_data.dart @@ -1,5 +1,5 @@ import 'package:flutter/foundation.dart'; -import 'package:instabug_flutter/src/models/InstabugFrameData.dart'; +import 'package:instabug_flutter/src/models/instabug_frame_data.dart'; class InstabugScreenRenderData { int traceId; @@ -32,6 +32,7 @@ class InstabugScreenRenderData { 'Frame Data[\n${frameData.map((element) => '\t\n$element')}\n]'; @override + // ignore: hash_and_equals bool operator ==(covariant InstabugScreenRenderData other) { if (identical(this, other)) return true; return traceId == other.traceId && diff --git a/lib/src/modules/instabug.dart b/lib/src/modules/instabug.dart index 4b079ab99..9ef4930b0 100644 --- a/lib/src/modules/instabug.dart +++ b/lib/src/modules/instabug.dart @@ -1,4 +1,5 @@ // ignore_for_file: avoid_classes_with_only_static_members +// ignore_for_file: deprecated_member_use import 'dart:async'; diff --git a/lib/src/utils/screen_loading/screen_loading_manager.dart b/lib/src/utils/screen_loading/screen_loading_manager.dart index ce73a3e30..9b48d6441 100644 --- a/lib/src/utils/screen_loading/screen_loading_manager.dart +++ b/lib/src/utils/screen_loading/screen_loading_manager.dart @@ -4,8 +4,8 @@ import 'package:instabug_flutter/src/utils/ibg_build_info.dart'; import 'package:instabug_flutter/src/utils/ibg_date_time.dart'; import 'package:instabug_flutter/src/utils/instabug_logger.dart'; import 'package:instabug_flutter/src/utils/instabug_montonic_clock.dart'; -import 'package:instabug_flutter/src/utils/ui_trace/flags_config.dart'; import 'package:instabug_flutter/src/utils/screen_loading/screen_loading_trace.dart'; +import 'package:instabug_flutter/src/utils/ui_trace/flags_config.dart'; import 'package:instabug_flutter/src/utils/ui_trace/ui_trace.dart'; import 'package:meta/meta.dart'; diff --git a/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart b/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart index 34f17f60c..143032215 100644 --- a/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart +++ b/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart @@ -2,8 +2,8 @@ import 'dart:developer'; import 'dart:ui'; import 'package:flutter/widgets.dart'; -import 'package:instabug_flutter/src/models/InstabugFrameData.dart'; -import 'package:instabug_flutter/src/models/InstabugScreenRenderData.dart'; +import 'package:instabug_flutter/src/models/instabug_frame_data.dart'; +import 'package:instabug_flutter/src/models/instabug_screen_render_data.dart'; import 'package:instabug_flutter/src/modules/apm.dart'; import 'package:instabug_flutter/src/utils/screen_rendering/instabug_widget_binding_observer.dart'; import 'package:meta/meta.dart'; @@ -39,6 +39,7 @@ class InstabugScreenRenderManager { bool _isTimingsListenerAttached = false; bool screenRenderEnabled = false; + InstabugScreenRenderManager._(); static InstabugScreenRenderManager _instance = @@ -55,8 +56,9 @@ class InstabugScreenRenderManager { /// setup function for [InstabugScreenRenderManager] @internal - Future init(WidgetsBinding widgetBinding) async { - if (!_isTimingsListenerAttached) { + Future init(WidgetsBinding? widgetBinding) async { + // passing WidgetsBinding? (nullable) for flutter versions prior than 3.x + if (!_isTimingsListenerAttached && widgetBinding != null) { _widgetsBinding = widgetBinding; _addWidgetBindingObserver(); await _initStaticValues(); @@ -139,18 +141,8 @@ class InstabugScreenRenderManager { double _targetMsPerFrame(double displayRefreshRate) => 1 / displayRefreshRate * 1000; - /// Check if getting from native would return different value. - /// Platforms may limit what information is available to the application with regard to secondary displays and/or displays that do not have an active application window. - /// Presently, on Android and Web this collection will only contain the display that the current window is on. - /// On iOS, it will only contains the main display on the phone or tablet. - /// On Desktop, it will contain only a main display with a valid refresh rate but invalid size and device pixel ratio values. - //todo: will be compared with value from native side after it's implemented. - // double get _getDeviceRefreshRate => - // _widgetsBinding.platformDispatcher.displays.first.refreshRate; - /// Get device refresh rate from native side. //todo: will be compared with value from native side after it's implemented. - // ignore: unused_element Future get _getDeviceRefreshRateFromNative => APM.getDeviceRefreshRate(); @@ -263,7 +255,7 @@ class InstabugScreenRenderManager { _delayedFrames.add(InstabugFrameData(startTime, duration)); } - //todo: will be removed + //todo: will be removed (is used for debugging) void _displayFrameTimingDetails(FrameTiming frameTiming) { if (_isSlow) { debugPrint( diff --git a/lib/src/utils/screen_rendering/instabug_widget_binding_observer.dart b/lib/src/utils/screen_rendering/instabug_widget_binding_observer.dart index 89ba6886a..6a92b51ce 100644 --- a/lib/src/utils/screen_rendering/instabug_widget_binding_observer.dart +++ b/lib/src/utils/screen_rendering/instabug_widget_binding_observer.dart @@ -66,7 +66,7 @@ class InstabugWidgetsBindingObserver extends WidgetsBindingObserver { } void _handleDefaultState() { - //todo: will be removed + //todo: will be implemented in next story debugPrint("default"); } } diff --git a/test/instabug_test.dart b/test/instabug_test.dart index 3afb6648c..06f3a3ef2 100644 --- a/test/instabug_test.dart +++ b/test/instabug_test.dart @@ -1,3 +1,4 @@ +// ignore_for_file: deprecated_member_use import 'dart:typed_data'; import 'package:flutter/widgets.dart'; diff --git a/test/utils/screen_loading/screen_loading_manager_test.dart b/test/utils/screen_loading/screen_loading_manager_test.dart index f452c4cda..341bc7368 100644 --- a/test/utils/screen_loading/screen_loading_manager_test.dart +++ b/test/utils/screen_loading/screen_loading_manager_test.dart @@ -9,8 +9,8 @@ import 'package:instabug_flutter/src/utils/instabug_logger.dart'; import 'package:instabug_flutter/src/utils/instabug_montonic_clock.dart'; import 'package:instabug_flutter/src/utils/screen_loading/screen_loading_manager.dart'; import 'package:instabug_flutter/src/utils/screen_loading/screen_loading_trace.dart'; -import 'package:instabug_flutter/src/utils/ui_trace/ui_trace.dart'; import 'package:instabug_flutter/src/utils/ui_trace/flags_config.dart'; +import 'package:instabug_flutter/src/utils/ui_trace/ui_trace.dart'; import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; diff --git a/test/utils/screen_render/instabug_screen_render_manager_test.dart b/test/utils/screen_render/instabug_screen_render_manager_test.dart index 563703018..f84a9fad4 100644 --- a/test/utils/screen_render/instabug_screen_render_manager_test.dart +++ b/test/utils/screen_render/instabug_screen_render_manager_test.dart @@ -4,8 +4,9 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:instabug_flutter/instabug_flutter.dart'; import 'package:instabug_flutter/src/generated/apm.api.g.dart'; -import 'package:instabug_flutter/src/models/InstabugFrameData.dart'; -import 'package:instabug_flutter/src/models/InstabugScreenRenderData.dart'; +import 'package:instabug_flutter/src/models/instabug_frame_data.dart'; +import 'package:instabug_flutter/src/models/instabug_screen_render_data.dart'; + import 'package:instabug_flutter/src/utils/screen_rendering/instabug_screen_render_manager.dart'; import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; diff --git a/test/utils/screen_render/instabug_widget_binding_observer_test.dart b/test/utils/screen_render/instabug_widget_binding_observer_test.dart index 58bbe92d8..54415fdb7 100644 --- a/test/utils/screen_render/instabug_widget_binding_observer_test.dart +++ b/test/utils/screen_render/instabug_widget_binding_observer_test.dart @@ -85,16 +85,6 @@ void main() { ); }); - test('handles AppLifecycleState.hidden with no action', () { - expect( - () { - InstabugWidgetsBindingObserver.I - .didChangeAppLifecycleState(AppLifecycleState.hidden); - }, - returnsNormally, - ); - }); - test('_handleResumedState does nothing if no currentUiTrace', () { when(mockLoadingManager.currentUiTrace).thenReturn(null); From e576a89d3283aa78351f46644d4cb0d1781b0a3a Mon Sep 17 00:00:00 2001 From: Andrew Amin Date: Sun, 22 Jun 2025 15:36:08 +0300 Subject: [PATCH 07/84] chore: add unit test cases for instabug_navigator_observer --- .../utils/instabug_navigator_observer.dart | 11 +-- .../instabug_screen_render_manager.dart | 38 +++++----- .../instabug_navigator_observer_test.dart | 75 ++++++++++++++++++- 3 files changed, 95 insertions(+), 29 deletions(-) diff --git a/lib/src/utils/instabug_navigator_observer.dart b/lib/src/utils/instabug_navigator_observer.dart index 775236f2b..4f3e814ff 100644 --- a/lib/src/utils/instabug_navigator_observer.dart +++ b/lib/src/utils/instabug_navigator_observer.dart @@ -6,7 +6,6 @@ import 'package:instabug_flutter/src/utils/instabug_logger.dart'; import 'package:instabug_flutter/src/utils/repro_steps_constants.dart'; import 'package:instabug_flutter/src/utils/screen_loading/screen_loading_manager.dart'; import 'package:instabug_flutter/src/utils/screen_name_masker.dart'; -import 'package:instabug_flutter/src/utils/screen_rendering/instabug_screen_render_manager.dart'; class InstabugNavigatorObserver extends NavigatorObserver { final List _steps = []; @@ -25,15 +24,7 @@ class InstabugNavigatorObserver extends NavigatorObserver { ); // Starts a the new UI trace which is exclusive to screen loading - ScreenLoadingManager.I - .startUiTrace(maskedScreenName, screenName) - .then((uiTraceId) { - if (uiTraceId != null && - InstabugScreenRenderManager.I.screenRenderEnabled) { - InstabugScreenRenderManager.I - .startScreenRenderCollectorForTraceId(uiTraceId); - } - }); + ScreenLoadingManager.I.startUiTrace(maskedScreenName, screenName); // If there is a step that hasn't been pushed yet if (_steps.isNotEmpty) { diff --git a/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart b/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart index 143032215..bde2008c3 100644 --- a/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart +++ b/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart @@ -269,24 +269,28 @@ class InstabugScreenRenderManager { } if (_isFrozen || _isSlow) { - debugPrint("{\n\t$frameTiming\n\t" - "Timestamps(${frameTiming.timestampInMicroseconds( - FramePhase.buildStart, - )}, ${frameTiming.timestampInMicroseconds( - FramePhase.buildFinish, - )}, ${frameTiming.timestampInMicroseconds( - FramePhase.rasterStart, - )}, ${frameTiming.timestampInMicroseconds( - FramePhase.rasterFinish, - )}, ${frameTiming.timestampInMicroseconds( - FramePhase.vsyncStart, - )}, ${frameTiming.timestampInMicroseconds( - FramePhase.rasterFinishWallTime, - )}" - ")\n}\n"); + debugPrint( + "{\n\t$frameTiming\n\t" + "Timestamps(${frameTiming.timestampInMicroseconds( + FramePhase.buildStart, + )}, ${frameTiming.timestampInMicroseconds( + FramePhase.buildFinish, + )}, ${frameTiming.timestampInMicroseconds( + FramePhase.rasterStart, + )}, ${frameTiming.timestampInMicroseconds( + FramePhase.rasterFinish, + )}, ${frameTiming.timestampInMicroseconds( + FramePhase.vsyncStart, + )}, ${frameTiming.timestampInMicroseconds( + FramePhase.rasterFinishWallTime, + )}" + ")\n}\n", + ); debugPrint("Device refresh rate: $_deviceRefreshRate FPS"); - debugPrint("Threshold: $_slowFrameThresholdMs ms\n" - "==============================================================================="); + debugPrint( + "Threshold: $_slowFrameThresholdMs ms\n" + "===============================================================================", + ); } } diff --git a/test/utils/instabug_navigator_observer_test.dart b/test/utils/instabug_navigator_observer_test.dart index 81a9f174e..76ae1840e 100644 --- a/test/utils/instabug_navigator_observer_test.dart +++ b/test/utils/instabug_navigator_observer_test.dart @@ -5,18 +5,23 @@ import 'package:instabug_flutter/instabug_flutter.dart'; import 'package:instabug_flutter/src/generated/instabug.api.g.dart'; import 'package:instabug_flutter/src/utils/screen_loading/screen_loading_manager.dart'; import 'package:instabug_flutter/src/utils/screen_name_masker.dart'; +import 'package:instabug_flutter/src/utils/screen_rendering/instabug_screen_render_manager.dart'; import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; import 'instabug_navigator_observer_test.mocks.dart'; -@GenerateMocks([InstabugHostApi]) -@GenerateNiceMocks([MockSpec()]) +@GenerateMocks([ + InstabugHostApi, + ScreenLoadingManager, + InstabugScreenRenderManager, +]) void main() { TestWidgetsFlutterBinding.ensureInitialized(); final mHost = MockInstabugHostApi(); final mScreenLoadingManager = MockScreenLoadingManager(); + final mScreenRenderManager = MockInstabugScreenRenderManager(); late InstabugNavigatorObserver observer; const screen = '/screen'; @@ -35,6 +40,7 @@ void main() { previousRoute = createRoute(previousScreen); ScreenNameMasker.I.setMaskingCallback(null); + when(mScreenRenderManager.screenRenderEnabled).thenReturn(false); }); test('should report screen change when a route is pushed', () { @@ -57,6 +63,9 @@ void main() { 'should report screen change when a route is popped and previous is known', () { fakeAsync((async) { + when(mScreenLoadingManager.startUiTrace(previousScreen, previousScreen)) + .thenAnswer((realInvocation) async => null); + observer.didPop(route, previousRoute); async.elapse(const Duration(milliseconds: 1000)); @@ -94,6 +103,9 @@ void main() { final route = createRoute(''); const fallback = 'N/A'; + when(mScreenLoadingManager.startUiTrace(fallback, fallback)) + .thenAnswer((realInvocation) async => null); + observer.didPush(route, previousRoute); async.elapse(const Duration(milliseconds: 1000)); @@ -111,6 +123,9 @@ void main() { test('should mask screen name when masking callback is set', () { const maskedScreen = 'maskedScreen'; + when(mScreenLoadingManager.startUiTrace(maskedScreen, screen)) + .thenAnswer((realInvocation) async => null); + ScreenNameMasker.I.setMaskingCallback((_) => maskedScreen); fakeAsync((async) { @@ -127,6 +142,62 @@ void main() { ).called(1); }); }); + + test('should start new screen render collector when a route is pushed', () { + fakeAsync((async) async { + const traceID = 123; + + when(mScreenLoadingManager.startUiTrace(screen, screen)) + .thenAnswer((_) async => traceID); + when(mScreenRenderManager.screenRenderEnabled).thenReturn(true); + + observer.didPush(route, previousRoute); + + async.elapse(const Duration(milliseconds: 1000)); + + verify( + mScreenRenderManager.startScreenRenderCollectorForTraceId(traceID), + ).called(1); + }); + }); + + test( + 'should not start new screen render collector when a route is pushed and [traceID] is null', + () { + fakeAsync((async) async { + when(mScreenLoadingManager.startUiTrace(screen, screen)) + .thenAnswer((_) async => null); + + when(mScreenRenderManager.screenRenderEnabled).thenReturn(true); + + observer.didPush(route, previousRoute); + + async.elapse(const Duration(milliseconds: 1000)); + + verifyNever( + mScreenRenderManager.startScreenRenderCollectorForTraceId(any), + ); + }); + }); + + test( + 'should not start new screen render collector when a route is pushed and [mScreenRenderManager.screenRenderEnabled] is false', + () { + fakeAsync((async) async { + when(mScreenLoadingManager.startUiTrace(screen, screen)) + .thenAnswer((_) async => 123); + + when(mScreenRenderManager.screenRenderEnabled).thenReturn(false); + + observer.didPush(route, previousRoute); + + async.elapse(const Duration(milliseconds: 1000)); + + verifyNever( + mScreenRenderManager.startScreenRenderCollectorForTraceId(any), + ); + }); + }); } Route createRoute(String? name) { From ec2b04bb913d5b8d9fbcb5e5b4831e88d198d11a Mon Sep 17 00:00:00 2001 From: Andrew Amin Date: Sun, 22 Jun 2025 17:18:03 +0300 Subject: [PATCH 08/84] chore: add instabug_screen_render_manager_test_manual_mocks.dart --- .../instabug_screen_render_manager_test.dart | 7 +- ...reen_render_manager_test_manual_mocks.dart | 879 ++++++++++++++++++ 2 files changed, 880 insertions(+), 6 deletions(-) create mode 100644 test/utils/screen_render/instabug_screen_render_manager_test_manual_mocks.dart diff --git a/test/utils/screen_render/instabug_screen_render_manager_test.dart b/test/utils/screen_render/instabug_screen_render_manager_test.dart index f84a9fad4..54b16301d 100644 --- a/test/utils/screen_render/instabug_screen_render_manager_test.dart +++ b/test/utils/screen_render/instabug_screen_render_manager_test.dart @@ -1,19 +1,14 @@ -import 'dart:ui'; -import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:instabug_flutter/instabug_flutter.dart'; -import 'package:instabug_flutter/src/generated/apm.api.g.dart'; import 'package:instabug_flutter/src/models/instabug_frame_data.dart'; import 'package:instabug_flutter/src/models/instabug_screen_render_data.dart'; import 'package:instabug_flutter/src/utils/screen_rendering/instabug_screen_render_manager.dart'; -import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; -import 'instabug_screen_render_manager_test.mocks.dart'; +import 'instabug_screen_render_manager_test_manual_mocks.dart'; -@GenerateMocks([FrameTiming, ApmHostApi, WidgetsBinding]) void main() { TestWidgetsFlutterBinding.ensureInitialized(); diff --git a/test/utils/screen_render/instabug_screen_render_manager_test_manual_mocks.dart b/test/utils/screen_render/instabug_screen_render_manager_test_manual_mocks.dart new file mode 100644 index 000000000..0560e4bcc --- /dev/null +++ b/test/utils/screen_render/instabug_screen_render_manager_test_manual_mocks.dart @@ -0,0 +1,879 @@ +// Mocks generated by Mockito 5.2.0 from annotations +// in instabug_flutter/example/ios/.symlinks/plugins/instabug_flutter/test/utils/screen_render/instabug_screen_render_manager_test.dart. +// Do not manually edit this file. + +import 'dart:async' as _i9; +import 'dart:developer' as _i13; +import 'dart:ui' as _i4; + +import 'package:flutter/foundation.dart' as _i3; +import 'package:flutter/gestures.dart' as _i6; +import 'package:flutter/rendering.dart' as _i7; +import 'package:flutter/scheduler.dart' as _i11; +import 'package:flutter/services.dart' as _i5; +import 'package:flutter/src/widgets/binding.dart' as _i10; +import 'package:flutter/src/widgets/focus_manager.dart' as _i2; +import 'package:flutter/src/widgets/framework.dart' as _i12; +import 'package:instabug_flutter/src/generated/apm.api.g.dart' as _i8; +import 'package:mockito/mockito.dart' as _i1; + +// ignore_for_file: type=lint +// ignore_for_file: avoid_redundant_argument_values +// ignore_for_file: avoid_setters_without_getters +// ignore_for_file: comment_references +// ignore_for_file: implementation_imports +// ignore_for_file: invalid_use_of_visible_for_testing_member +// ignore_for_file: prefer_const_constructors +// ignore_for_file: unnecessary_parenthesis +// ignore_for_file: camel_case_types + +// This file has been manually changed due to a mockito inconsistency with flutter v 2.10.5 + +class _FakeDuration_0 extends _i1.Fake implements Duration {} + +class _FakeFocusManager_1 extends _i1.Fake implements _i2.FocusManager { + @override + String toString({_i3.DiagnosticLevel? minLevel = _i3.DiagnosticLevel.info}) => + super.toString(); +} + +class _FakeSingletonFlutterWindow_2 extends _i1.Fake + implements _i4.SingletonFlutterWindow {} + +class _FakePlatformDispatcher_3 extends _i1.Fake + implements _i4.PlatformDispatcher {} + +class _FakeHardwareKeyboard_4 extends _i1.Fake implements _i5.HardwareKeyboard { +} + +class _FakeKeyEventManager_5 extends _i1.Fake implements _i5.KeyEventManager {} + +class _FakeBinaryMessenger_6 extends _i1.Fake implements _i5.BinaryMessenger {} + +class _FakeChannelBuffers_7 extends _i1.Fake implements _i4.ChannelBuffers {} + +class _FakeRestorationManager_8 extends _i1.Fake + implements _i5.RestorationManager {} + +class _FakePointerRouter_9 extends _i1.Fake implements _i6.PointerRouter {} + +class _FakeGestureArenaManager_10 extends _i1.Fake + implements _i6.GestureArenaManager {} + +class _FakePointerSignalResolver_11 extends _i1.Fake + implements _i6.PointerSignalResolver {} + +class _FakeMouseTracker_12 extends _i1.Fake implements _i7.MouseTracker {} + +class _FakePipelineOwner_13 extends _i1.Fake implements _i7.PipelineOwner {} + +class _FakeRenderView_14 extends _i1.Fake implements _i7.RenderView { + @override + String toString({_i3.DiagnosticLevel? minLevel = _i3.DiagnosticLevel.info}) => + super.toString(); +} + +class _FakeAccessibilityFeatures_15 extends _i1.Fake + implements _i4.AccessibilityFeatures {} + +class _FakeViewConfiguration_16 extends _i1.Fake + implements _i7.ViewConfiguration {} + +class _FakeSemanticsUpdateBuilder_17 extends _i1.Fake + implements _i4.SemanticsUpdateBuilder {} + +/// A class which mocks [FrameTiming]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockFrameTiming extends _i1.Mock implements _i4.FrameTiming { + MockFrameTiming() { + _i1.throwOnMissingStub(this); + } + + @override + Duration get buildDuration => + (super.noSuchMethod(Invocation.getter(#buildDuration), + returnValue: _FakeDuration_0()) as Duration); + + @override + Duration get rasterDuration => + (super.noSuchMethod(Invocation.getter(#rasterDuration), + returnValue: _FakeDuration_0()) as Duration); + + @override + Duration get vsyncOverhead => + (super.noSuchMethod(Invocation.getter(#vsyncOverhead), + returnValue: _FakeDuration_0()) as Duration); + + @override + Duration get totalSpan => (super.noSuchMethod(Invocation.getter(#totalSpan), + returnValue: _FakeDuration_0()) as Duration); + + @override + int get layerCacheCount => + (super.noSuchMethod(Invocation.getter(#layerCacheCount), returnValue: 0) + as int); + + @override + int get layerCacheBytes => + (super.noSuchMethod(Invocation.getter(#layerCacheBytes), returnValue: 0) + as int); + + @override + double get layerCacheMegabytes => + (super.noSuchMethod(Invocation.getter(#layerCacheMegabytes), + returnValue: 0.0) as double); + + @override + int get pictureCacheCount => + (super.noSuchMethod(Invocation.getter(#pictureCacheCount), returnValue: 0) + as int); + + @override + int get pictureCacheBytes => + (super.noSuchMethod(Invocation.getter(#pictureCacheBytes), returnValue: 0) + as int); + + @override + double get pictureCacheMegabytes => + (super.noSuchMethod(Invocation.getter(#pictureCacheMegabytes), + returnValue: 0.0) as double); + + @override + int get frameNumber => + (super.noSuchMethod(Invocation.getter(#frameNumber), returnValue: 0) + as int); + + @override + int timestampInMicroseconds(_i4.FramePhase? phase) => + (super.noSuchMethod(Invocation.method(#timestampInMicroseconds, [phase]), + returnValue: 0) as int); +} + +/// A class which mocks [ApmHostApi]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockApmHostApi extends _i1.Mock implements _i8.ApmHostApi { + MockApmHostApi() { + _i1.throwOnMissingStub(this); + } + + @override + _i9.Future setEnabled(bool? arg_isEnabled) => + (super.noSuchMethod(Invocation.method(#setEnabled, [arg_isEnabled]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + + @override + _i9.Future isEnabled() => + (super.noSuchMethod(Invocation.method(#isEnabled, []), + returnValue: Future.value(false)) as _i9.Future); + + @override + _i9.Future setScreenLoadingEnabled(bool? arg_isEnabled) => + (super.noSuchMethod( + Invocation.method(#setScreenLoadingEnabled, [arg_isEnabled]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + + @override + _i9.Future isScreenLoadingEnabled() => + (super.noSuchMethod(Invocation.method(#isScreenLoadingEnabled, []), + returnValue: Future.value(false)) as _i9.Future); + + @override + _i9.Future setColdAppLaunchEnabled(bool? arg_isEnabled) => + (super.noSuchMethod( + Invocation.method(#setColdAppLaunchEnabled, [arg_isEnabled]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + + @override + _i9.Future setAutoUITraceEnabled(bool? arg_isEnabled) => (super + .noSuchMethod(Invocation.method(#setAutoUITraceEnabled, [arg_isEnabled]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + + @override + _i9.Future startExecutionTrace(String? arg_id, String? arg_name) => + (super.noSuchMethod( + Invocation.method(#startExecutionTrace, [arg_id, arg_name]), + returnValue: Future.value()) as _i9.Future); + + @override + _i9.Future startFlow(String? arg_name) => + (super.noSuchMethod(Invocation.method(#startFlow, [arg_name]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + + @override + _i9.Future setFlowAttribute( + String? arg_name, String? arg_key, String? arg_value) => + (super.noSuchMethod( + Invocation.method(#setFlowAttribute, [arg_name, arg_key, arg_value]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + + @override + _i9.Future endFlow(String? arg_name) => + (super.noSuchMethod(Invocation.method(#endFlow, [arg_name]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + + @override + _i9.Future setExecutionTraceAttribute( + String? arg_id, String? arg_key, String? arg_value) => + (super.noSuchMethod( + Invocation.method( + #setExecutionTraceAttribute, [arg_id, arg_key, arg_value]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + + @override + _i9.Future endExecutionTrace(String? arg_id) => + (super.noSuchMethod(Invocation.method(#endExecutionTrace, [arg_id]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + + @override + _i9.Future startUITrace(String? arg_name) => + (super.noSuchMethod(Invocation.method(#startUITrace, [arg_name]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + + @override + _i9.Future endUITrace() => + (super.noSuchMethod(Invocation.method(#endUITrace, []), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + + @override + _i9.Future endAppLaunch() => + (super.noSuchMethod(Invocation.method(#endAppLaunch, []), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + + @override + _i9.Future networkLogAndroid(Map? arg_data) => + (super.noSuchMethod(Invocation.method(#networkLogAndroid, [arg_data]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + + @override + _i9.Future startCpUiTrace( + String? arg_screenName, int? arg_microTimeStamp, int? arg_traceId) => + (super.noSuchMethod( + Invocation.method(#startCpUiTrace, + [arg_screenName, arg_microTimeStamp, arg_traceId]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + + @override + _i9.Future reportScreenLoadingCP(int? arg_startTimeStampMicro, + int? arg_durationMicro, int? arg_uiTraceId) => + (super.noSuchMethod( + Invocation.method(#reportScreenLoadingCP, + [arg_startTimeStampMicro, arg_durationMicro, arg_uiTraceId]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + + @override + _i9.Future endScreenLoadingCP( + int? arg_timeStampMicro, int? arg_uiTraceId) => + (super.noSuchMethod( + Invocation.method( + #endScreenLoadingCP, [arg_timeStampMicro, arg_uiTraceId]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + + @override + _i9.Future isEndScreenLoadingEnabled() => + (super.noSuchMethod(Invocation.method(#isEndScreenLoadingEnabled, []), + returnValue: Future.value(false)) as _i9.Future); + + @override + _i9.Future isScreenRenderEnabled() => + (super.noSuchMethod(Invocation.method(#isScreenRenderEnabled, []), + returnValue: Future.value(false)) as _i9.Future); + + @override + _i9.Future deviceRefreshRate() => + (super.noSuchMethod(Invocation.method(#deviceRefreshRate, []), + returnValue: Future.value(0.0)) as _i9.Future); +} + +/// A class which mocks [WidgetsBinding]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockWidgetsBinding extends _i1.Mock implements _i10.WidgetsBinding { + MockWidgetsBinding() { + _i1.throwOnMissingStub(this); + } + + @override + bool get debugBuildingDirtyElements => + (super.noSuchMethod(Invocation.getter(#debugBuildingDirtyElements), + returnValue: false) as bool); + + @override + set debugBuildingDirtyElements(bool? _debugBuildingDirtyElements) => + super.noSuchMethod( + Invocation.setter( + #debugBuildingDirtyElements, _debugBuildingDirtyElements), + returnValueForMissingStub: null); + + @override + _i2.FocusManager get focusManager => + (super.noSuchMethod(Invocation.getter(#focusManager), + returnValue: _FakeFocusManager_1()) as _i2.FocusManager); + + @override + bool get firstFrameRasterized => + (super.noSuchMethod(Invocation.getter(#firstFrameRasterized), + returnValue: false) as bool); + + @override + _i9.Future get waitUntilFirstFrameRasterized => + (super.noSuchMethod(Invocation.getter(#waitUntilFirstFrameRasterized), + returnValue: Future.value()) as _i9.Future); + + @override + bool get debugDidSendFirstFrameEvent => + (super.noSuchMethod(Invocation.getter(#debugDidSendFirstFrameEvent), + returnValue: false) as bool); + + @override + bool get framesEnabled => + (super.noSuchMethod(Invocation.getter(#framesEnabled), returnValue: false) + as bool); + + @override + bool get isRootWidgetAttached => + (super.noSuchMethod(Invocation.getter(#isRootWidgetAttached), + returnValue: false) as bool); + + @override + _i4.SingletonFlutterWindow get window => + (super.noSuchMethod(Invocation.getter(#window), + returnValue: _FakeSingletonFlutterWindow_2()) + as _i4.SingletonFlutterWindow); + + @override + _i4.PlatformDispatcher get platformDispatcher => + (super.noSuchMethod(Invocation.getter(#platformDispatcher), + returnValue: _FakePlatformDispatcher_3()) as _i4.PlatformDispatcher); + + @override + bool get locked => + (super.noSuchMethod(Invocation.getter(#locked), returnValue: false) + as bool); + + @override + _i5.HardwareKeyboard get keyboard => + (super.noSuchMethod(Invocation.getter(#keyboard), + returnValue: _FakeHardwareKeyboard_4()) as _i5.HardwareKeyboard); + + @override + _i5.KeyEventManager get keyEventManager => + (super.noSuchMethod(Invocation.getter(#keyEventManager), + returnValue: _FakeKeyEventManager_5()) as _i5.KeyEventManager); + + @override + _i5.BinaryMessenger get defaultBinaryMessenger => + (super.noSuchMethod(Invocation.getter(#defaultBinaryMessenger), + returnValue: _FakeBinaryMessenger_6()) as _i5.BinaryMessenger); + + @override + _i4.ChannelBuffers get channelBuffers => + (super.noSuchMethod(Invocation.getter(#channelBuffers), + returnValue: _FakeChannelBuffers_7()) as _i4.ChannelBuffers); + + @override + _i5.RestorationManager get restorationManager => + (super.noSuchMethod(Invocation.getter(#restorationManager), + returnValue: _FakeRestorationManager_8()) as _i5.RestorationManager); + + // Parameters {int? priority, _i11.SchedulerBinding? scheduler} have been changed from {int priority, _i11.SchedulerBinding scheduler}. + @override + _i11.SchedulingStrategy get schedulingStrategy => + (super.noSuchMethod(Invocation.getter(#schedulingStrategy), + returnValue: ({int? priority, _i11.SchedulerBinding? scheduler}) => + false) as _i11.SchedulingStrategy); + + @override + set schedulingStrategy(_i11.SchedulingStrategy? _schedulingStrategy) => super + .noSuchMethod(Invocation.setter(#schedulingStrategy, _schedulingStrategy), + returnValueForMissingStub: null); + + @override + int get transientCallbackCount => + (super.noSuchMethod(Invocation.getter(#transientCallbackCount), + returnValue: 0) as int); + + @override + _i9.Future get endOfFrame => + (super.noSuchMethod(Invocation.getter(#endOfFrame), + returnValue: Future.value()) as _i9.Future); + + @override + bool get hasScheduledFrame => + (super.noSuchMethod(Invocation.getter(#hasScheduledFrame), + returnValue: false) as bool); + + @override + _i11.SchedulerPhase get schedulerPhase => + (super.noSuchMethod(Invocation.getter(#schedulerPhase), + returnValue: _i11.SchedulerPhase.idle) as _i11.SchedulerPhase); + + @override + Duration get currentFrameTimeStamp => + (super.noSuchMethod(Invocation.getter(#currentFrameTimeStamp), + returnValue: _FakeDuration_0()) as Duration); + + @override + Duration get currentSystemFrameTimeStamp => + (super.noSuchMethod(Invocation.getter(#currentSystemFrameTimeStamp), + returnValue: _FakeDuration_0()) as Duration); + + @override + _i6.PointerRouter get pointerRouter => + (super.noSuchMethod(Invocation.getter(#pointerRouter), + returnValue: _FakePointerRouter_9()) as _i6.PointerRouter); + + @override + _i6.GestureArenaManager get gestureArena => (super.noSuchMethod( + Invocation.getter(#gestureArena), + returnValue: _FakeGestureArenaManager_10()) as _i6.GestureArenaManager); + + @override + _i6.PointerSignalResolver get pointerSignalResolver => + (super.noSuchMethod(Invocation.getter(#pointerSignalResolver), + returnValue: _FakePointerSignalResolver_11()) + as _i6.PointerSignalResolver); + + @override + bool get resamplingEnabled => + (super.noSuchMethod(Invocation.getter(#resamplingEnabled), + returnValue: false) as bool); + + @override + set resamplingEnabled(bool? _resamplingEnabled) => super.noSuchMethod( + Invocation.setter(#resamplingEnabled, _resamplingEnabled), + returnValueForMissingStub: null); + + @override + Duration get samplingOffset => + (super.noSuchMethod(Invocation.getter(#samplingOffset), + returnValue: _FakeDuration_0()) as Duration); + + @override + set samplingOffset(Duration? _samplingOffset) => + super.noSuchMethod(Invocation.setter(#samplingOffset, _samplingOffset), + returnValueForMissingStub: null); + + @override + _i7.MouseTracker get mouseTracker => + (super.noSuchMethod(Invocation.getter(#mouseTracker), + returnValue: _FakeMouseTracker_12()) as _i7.MouseTracker); + + @override + _i7.PipelineOwner get pipelineOwner => + (super.noSuchMethod(Invocation.getter(#pipelineOwner), + returnValue: _FakePipelineOwner_13()) as _i7.PipelineOwner); + + @override + _i7.RenderView get renderView => + (super.noSuchMethod(Invocation.getter(#renderView), + returnValue: _FakeRenderView_14()) as _i7.RenderView); + + @override + set renderView(_i7.RenderView? value) => + super.noSuchMethod(Invocation.setter(#renderView, value), + returnValueForMissingStub: null); + + @override + bool get sendFramesToEngine => + (super.noSuchMethod(Invocation.getter(#sendFramesToEngine), + returnValue: false) as bool); + + @override + _i4.AccessibilityFeatures get accessibilityFeatures => + (super.noSuchMethod(Invocation.getter(#accessibilityFeatures), + returnValue: _FakeAccessibilityFeatures_15()) + as _i4.AccessibilityFeatures); + + @override + bool get disableAnimations => + (super.noSuchMethod(Invocation.getter(#disableAnimations), + returnValue: false) as bool); + + @override + void initInstances() => + super.noSuchMethod(Invocation.method(#initInstances, []), + returnValueForMissingStub: null); + + @override + void initServiceExtensions() => + super.noSuchMethod(Invocation.method(#initServiceExtensions, []), + returnValueForMissingStub: null); + + @override + void addObserver(_i10.WidgetsBindingObserver? observer) => + super.noSuchMethod(Invocation.method(#addObserver, [observer]), + returnValueForMissingStub: null); + + @override + bool removeObserver(_i10.WidgetsBindingObserver? observer) => + (super.noSuchMethod(Invocation.method(#removeObserver, [observer]), + returnValue: false) as bool); + + @override + void handleMetricsChanged() => + super.noSuchMethod(Invocation.method(#handleMetricsChanged, []), + returnValueForMissingStub: null); + + @override + void handleTextScaleFactorChanged() => + super.noSuchMethod(Invocation.method(#handleTextScaleFactorChanged, []), + returnValueForMissingStub: null); + + @override + void handlePlatformBrightnessChanged() => super.noSuchMethod( + Invocation.method(#handlePlatformBrightnessChanged, []), + returnValueForMissingStub: null); + + @override + void handleAccessibilityFeaturesChanged() => super.noSuchMethod( + Invocation.method(#handleAccessibilityFeaturesChanged, []), + returnValueForMissingStub: null); + + @override + void handleLocaleChanged() => + super.noSuchMethod(Invocation.method(#handleLocaleChanged, []), + returnValueForMissingStub: null); + + @override + void dispatchLocalesChanged(List<_i4.Locale>? locales) => + super.noSuchMethod(Invocation.method(#dispatchLocalesChanged, [locales]), + returnValueForMissingStub: null); + + @override + void dispatchAccessibilityFeaturesChanged() => super.noSuchMethod( + Invocation.method(#dispatchAccessibilityFeaturesChanged, []), + returnValueForMissingStub: null); + + @override + _i9.Future handlePopRoute() => + (super.noSuchMethod(Invocation.method(#handlePopRoute, []), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + + @override + _i9.Future handlePushRoute(String? route) => + (super.noSuchMethod(Invocation.method(#handlePushRoute, [route]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + + @override + void handleAppLifecycleStateChanged(_i4.AppLifecycleState? state) => super + .noSuchMethod(Invocation.method(#handleAppLifecycleStateChanged, [state]), + returnValueForMissingStub: null); + + @override + void handleMemoryPressure() => + super.noSuchMethod(Invocation.method(#handleMemoryPressure, []), + returnValueForMissingStub: null); + + @override + void drawFrame() => super.noSuchMethod(Invocation.method(#drawFrame, []), + returnValueForMissingStub: null); + + @override + void scheduleAttachRootWidget(_i12.Widget? rootWidget) => super.noSuchMethod( + Invocation.method(#scheduleAttachRootWidget, [rootWidget]), + returnValueForMissingStub: null); + + @override + void attachRootWidget(_i12.Widget? rootWidget) => + super.noSuchMethod(Invocation.method(#attachRootWidget, [rootWidget]), + returnValueForMissingStub: null); + + @override + _i9.Future performReassemble() => + (super.noSuchMethod(Invocation.method(#performReassemble, []), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + + @override + _i4.Locale? computePlatformResolvedLocale( + List<_i4.Locale>? supportedLocales) => + (super.noSuchMethod(Invocation.method( + #computePlatformResolvedLocale, [supportedLocales])) as _i4.Locale?); + + @override + _i9.Future lockEvents(_i9.Future Function()? callback) => + (super.noSuchMethod(Invocation.method(#lockEvents, [callback]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + + @override + void unlocked() => super.noSuchMethod(Invocation.method(#unlocked, []), + returnValueForMissingStub: null); + + @override + _i9.Future reassembleApplication() => + (super.noSuchMethod(Invocation.method(#reassembleApplication, []), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + + @override + void registerSignalServiceExtension( + {String? name, _i3.AsyncCallback? callback}) => + super.noSuchMethod( + Invocation.method(#registerSignalServiceExtension, [], + {#name: name, #callback: callback}), + returnValueForMissingStub: null); + + @override + void registerBoolServiceExtension( + {String? name, + _i3.AsyncValueGetter? getter, + _i3.AsyncValueSetter? setter}) => + super.noSuchMethod( + Invocation.method(#registerBoolServiceExtension, [], + {#name: name, #getter: getter, #setter: setter}), + returnValueForMissingStub: null); + + @override + void registerNumericServiceExtension( + {String? name, + _i3.AsyncValueGetter? getter, + _i3.AsyncValueSetter? setter}) => + super.noSuchMethod( + Invocation.method(#registerNumericServiceExtension, [], + {#name: name, #getter: getter, #setter: setter}), + returnValueForMissingStub: null); + + @override + void postEvent(String? eventKind, Map? eventData) => + super.noSuchMethod(Invocation.method(#postEvent, [eventKind, eventData]), + returnValueForMissingStub: null); + + @override + void registerStringServiceExtension( + {String? name, + _i3.AsyncValueGetter? getter, + _i3.AsyncValueSetter? setter}) => + super.noSuchMethod( + Invocation.method(#registerStringServiceExtension, [], + {#name: name, #getter: getter, #setter: setter}), + returnValueForMissingStub: null); + + @override + void registerServiceExtension( + {String? name, _i3.ServiceExtensionCallback? callback}) => + super.noSuchMethod( + Invocation.method(#registerServiceExtension, [], + {#name: name, #callback: callback}), + returnValueForMissingStub: null); + + @override + _i5.BinaryMessenger createBinaryMessenger() => + (super.noSuchMethod(Invocation.method(#createBinaryMessenger, []), + returnValue: _FakeBinaryMessenger_6()) as _i5.BinaryMessenger); + + @override + _i9.Future handleSystemMessage(Object? systemMessage) => (super + .noSuchMethod(Invocation.method(#handleSystemMessage, [systemMessage]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + + @override + void initLicenses() => + super.noSuchMethod(Invocation.method(#initLicenses, []), + returnValueForMissingStub: null); + + @override + void evict(String? asset) => + super.noSuchMethod(Invocation.method(#evict, [asset]), + returnValueForMissingStub: null); + + @override + void readInitialLifecycleStateFromNativeWindow() => super.noSuchMethod( + Invocation.method(#readInitialLifecycleStateFromNativeWindow, []), + returnValueForMissingStub: null); + + @override + _i5.RestorationManager createRestorationManager() => + (super.noSuchMethod(Invocation.method(#createRestorationManager, []), + returnValue: _FakeRestorationManager_8()) as _i5.RestorationManager); + + @override + void setSystemUiChangeCallback(_i5.SystemUiChangeCallback? callback) => super + .noSuchMethod(Invocation.method(#setSystemUiChangeCallback, [callback]), + returnValueForMissingStub: null); + + @override + void addTimingsCallback(_i4.TimingsCallback? callback) => + super.noSuchMethod(Invocation.method(#addTimingsCallback, [callback]), + returnValueForMissingStub: null); + + @override + void removeTimingsCallback(_i4.TimingsCallback? callback) => + super.noSuchMethod(Invocation.method(#removeTimingsCallback, [callback]), + returnValueForMissingStub: null); + + @override + _i9.Future scheduleTask( + _i11.TaskCallback? task, _i11.Priority? priority, + {String? debugLabel, _i13.Flow? flow}) => + (super.noSuchMethod( + Invocation.method(#scheduleTask, [task, priority], + {#debugLabel: debugLabel, #flow: flow}), + returnValue: Future.value(null)) as _i9.Future); + + @override + bool handleEventLoopCallback() => + (super.noSuchMethod(Invocation.method(#handleEventLoopCallback, []), + returnValue: false) as bool); + + @override + int scheduleFrameCallback(_i11.FrameCallback? callback, + {bool? rescheduling = false}) => + (super.noSuchMethod( + Invocation.method(#scheduleFrameCallback, [callback], + {#rescheduling: rescheduling}), + returnValue: 0) as int); + + @override + void cancelFrameCallbackWithId(int? id) => + super.noSuchMethod(Invocation.method(#cancelFrameCallbackWithId, [id]), + returnValueForMissingStub: null); + + @override + bool debugAssertNoTransientCallbacks(String? reason) => (super.noSuchMethod( + Invocation.method(#debugAssertNoTransientCallbacks, [reason]), + returnValue: false) as bool); + + @override + void addPersistentFrameCallback(_i11.FrameCallback? callback) => super + .noSuchMethod(Invocation.method(#addPersistentFrameCallback, [callback]), + returnValueForMissingStub: null); + + @override + void addPostFrameCallback(_i11.FrameCallback? callback) => + super.noSuchMethod(Invocation.method(#addPostFrameCallback, [callback]), + returnValueForMissingStub: null); + + @override + void ensureFrameCallbacksRegistered() => + super.noSuchMethod(Invocation.method(#ensureFrameCallbacksRegistered, []), + returnValueForMissingStub: null); + + @override + void ensureVisualUpdate() => + super.noSuchMethod(Invocation.method(#ensureVisualUpdate, []), + returnValueForMissingStub: null); + + @override + void scheduleFrame() => + super.noSuchMethod(Invocation.method(#scheduleFrame, []), + returnValueForMissingStub: null); + + @override + void scheduleForcedFrame() => + super.noSuchMethod(Invocation.method(#scheduleForcedFrame, []), + returnValueForMissingStub: null); + + @override + void scheduleWarmUpFrame() => + super.noSuchMethod(Invocation.method(#scheduleWarmUpFrame, []), + returnValueForMissingStub: null); + + @override + void resetEpoch() => super.noSuchMethod(Invocation.method(#resetEpoch, []), + returnValueForMissingStub: null); + + @override + void handleBeginFrame(Duration? rawTimeStamp) => + super.noSuchMethod(Invocation.method(#handleBeginFrame, [rawTimeStamp]), + returnValueForMissingStub: null); + + @override + void handleDrawFrame() => + super.noSuchMethod(Invocation.method(#handleDrawFrame, []), + returnValueForMissingStub: null); + + @override + void cancelPointer(int? pointer) => + super.noSuchMethod(Invocation.method(#cancelPointer, [pointer]), + returnValueForMissingStub: null); + + @override + void handlePointerEvent(_i7.PointerEvent? event) => + super.noSuchMethod(Invocation.method(#handlePointerEvent, [event]), + returnValueForMissingStub: null); + + @override + void hitTest(_i7.HitTestResult? result, _i4.Offset? position) => + super.noSuchMethod(Invocation.method(#hitTest, [result, position]), + returnValueForMissingStub: null); + + @override + void dispatchEvent( + _i7.PointerEvent? event, _i7.HitTestResult? hitTestResult) => + super.noSuchMethod( + Invocation.method(#dispatchEvent, [event, hitTestResult]), + returnValueForMissingStub: null); + + @override + void handleEvent(_i7.PointerEvent? event, _i7.HitTestEntry? entry) => + super.noSuchMethod(Invocation.method(#handleEvent, [event, entry]), + returnValueForMissingStub: null); + + @override + void resetGestureBinding() => + super.noSuchMethod(Invocation.method(#resetGestureBinding, []), + returnValueForMissingStub: null); + + @override + void initRenderView() => + super.noSuchMethod(Invocation.method(#initRenderView, []), + returnValueForMissingStub: null); + + @override + _i7.ViewConfiguration createViewConfiguration() => + (super.noSuchMethod(Invocation.method(#createViewConfiguration, []), + returnValue: _FakeViewConfiguration_16()) as _i7.ViewConfiguration); + + @override + void initMouseTracker([_i7.MouseTracker? tracker]) => + super.noSuchMethod(Invocation.method(#initMouseTracker, [tracker]), + returnValueForMissingStub: null); + + @override + void setSemanticsEnabled(bool? enabled) => + super.noSuchMethod(Invocation.method(#setSemanticsEnabled, [enabled]), + returnValueForMissingStub: null); + + @override + void deferFirstFrame() => + super.noSuchMethod(Invocation.method(#deferFirstFrame, []), + returnValueForMissingStub: null); + + @override + void allowFirstFrame() => + super.noSuchMethod(Invocation.method(#allowFirstFrame, []), + returnValueForMissingStub: null); + + @override + void resetFirstFrameSent() => + super.noSuchMethod(Invocation.method(#resetFirstFrameSent, []), + returnValueForMissingStub: null); + + @override + _i4.SemanticsUpdateBuilder createSemanticsUpdateBuilder() => + (super.noSuchMethod(Invocation.method(#createSemanticsUpdateBuilder, []), + returnValue: _FakeSemanticsUpdateBuilder_17()) + as _i4.SemanticsUpdateBuilder); +} From 608f5e50b2b495e8b3e53641421d1d53fc76628a Mon Sep 17 00:00:00 2001 From: Andrew Amin Date: Sun, 22 Jun 2025 17:49:01 +0300 Subject: [PATCH 09/84] chore: run dart format . --- .../utils/screen_render/instabug_screen_render_manager_test.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/test/utils/screen_render/instabug_screen_render_manager_test.dart b/test/utils/screen_render/instabug_screen_render_manager_test.dart index 54b16301d..f77d8b234 100644 --- a/test/utils/screen_render/instabug_screen_render_manager_test.dart +++ b/test/utils/screen_render/instabug_screen_render_manager_test.dart @@ -1,4 +1,3 @@ - import 'package:flutter_test/flutter_test.dart'; import 'package:instabug_flutter/instabug_flutter.dart'; import 'package:instabug_flutter/src/models/instabug_frame_data.dart'; From dce7286e16d06be84a3efdb912cf35e4019067bf Mon Sep 17 00:00:00 2001 From: Andrew Amin Date: Sun, 22 Jun 2025 18:05:18 +0300 Subject: [PATCH 10/84] chore: run dart format . --- .../instabug_screen_render_manager_test_manual_mocks.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/utils/screen_render/instabug_screen_render_manager_test_manual_mocks.dart b/test/utils/screen_render/instabug_screen_render_manager_test_manual_mocks.dart index 0560e4bcc..b35602da3 100644 --- a/test/utils/screen_render/instabug_screen_render_manager_test_manual_mocks.dart +++ b/test/utils/screen_render/instabug_screen_render_manager_test_manual_mocks.dart @@ -393,7 +393,8 @@ class MockWidgetsBinding extends _i1.Mock implements _i10.WidgetsBinding { (super.noSuchMethod(Invocation.getter(#restorationManager), returnValue: _FakeRestorationManager_8()) as _i5.RestorationManager); - // Parameters {int? priority, _i11.SchedulerBinding? scheduler} have been changed from {int priority, _i11.SchedulerBinding scheduler}. + // Parameters {int? priority, _i11.SchedulerBinding? scheduler} have been + // changed from {int priority, _i11.SchedulerBinding scheduler}. @override _i11.SchedulingStrategy get schedulingStrategy => (super.noSuchMethod(Invocation.getter(#schedulingStrategy), From 83cbbbac105e01fe8989d78f2daf417560693055 Mon Sep 17 00:00:00 2001 From: Andrew Amin Date: Sat, 28 Jun 2025 23:52:39 +0300 Subject: [PATCH 11/84] chore: add native feature apis --- android/build.gradle | 11 +- .../flutter/InstabugFlutterPlugin.java | 27 +- .../com/instabug/flutter/modules/ApmApi.java | 32 +- .../java/com/instabug/flutter/ApmApiTest.java | 42 +- example/ios/Podfile | 3 +- example/ios/Podfile.lock | 16 +- example/ios/Runner.xcodeproj/project.pbxproj | 2 +- .../xcshareddata/xcschemes/Runner.xcscheme | 5 +- example/lib/main.dart | 46 +- example/pubspec.lock | 189 ++-- ios/Classes/Modules/ApmApi.m | 57 +- ios/Classes/Util/IBGAPM+PrivateAPIs.h | 2 + ios/instabug_flutter.podspec | 2 +- lib/src/modules/apm.dart | 13 + lib/src/modules/instabug.dart | 2 +- .../utils/instabug_navigator_observer.dart | 19 +- .../instabug_screen_render_manager.dart | 38 +- pigeons/apm.api.dart | 2 + scripts/pigeon.sh | 0 .../instabug_screen_render_manager_test.dart | 31 +- ...reen_render_manager_test_manual_mocks.dart | 880 ------------------ 21 files changed, 345 insertions(+), 1074 deletions(-) mode change 100644 => 100755 scripts/pigeon.sh delete mode 100644 test/utils/screen_render/instabug_screen_render_manager_test_manual_mocks.dart diff --git a/android/build.gradle b/android/build.gradle index a6c41ffd0..0a1bab7ea 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -1,3 +1,5 @@ +package android + group 'com.instabug.flutter' version '14.3.0' @@ -16,9 +18,17 @@ rootProject.allprojects { repositories { google() mavenCentral() + maven { + url "https://mvn.instabug.com/nexus/repository/instabug-internal/" + credentials { + username "instabug" + password System.getenv("INSTABUG_REPOSITORY_PASSWORD") + } + } } } + apply plugin: 'com.android.library' android { @@ -48,7 +58,6 @@ dependencies { testImplementation 'junit:junit:4.13.2' testImplementation "org.mockito:mockito-inline:3.12.1" testImplementation "io.mockk:mockk:1.13.13" - } // add upload_symbols task diff --git a/android/src/main/java/com/instabug/flutter/InstabugFlutterPlugin.java b/android/src/main/java/com/instabug/flutter/InstabugFlutterPlugin.java index bb3b043fa..3a51a4051 100644 --- a/android/src/main/java/com/instabug/flutter/InstabugFlutterPlugin.java +++ b/android/src/main/java/com/instabug/flutter/InstabugFlutterPlugin.java @@ -4,7 +4,9 @@ import android.app.Activity; import android.content.Context; import android.graphics.Bitmap; +import android.os.Build; import android.util.Log; +import android.view.Display; import android.view.View; import androidx.annotation.NonNull; @@ -73,7 +75,14 @@ public Bitmap call() { } }; - ApmApi.init(messenger); + Callable refreshRateProvider = new Callable() { + @Override + public Float call(){ + return getRefreshRate(); + } + }; + + ApmApi.init(messenger, refreshRateProvider); BugReportingApi.init(messenger); CrashReportingApi.init(messenger); FeatureRequestsApi.init(messenger); @@ -99,4 +108,20 @@ private static Bitmap takeScreenshot(FlutterRenderer renderer) { return null; } } + + private static float getRefreshRate() { + float refreshRate = 60f; + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + final Display display = activity.getDisplay(); + if (display != null) { + refreshRate = display.getRefreshRate(); + } + } else { + refreshRate = activity.getWindowManager().getDefaultDisplay().getRefreshRate(); + } + + return refreshRate; + } + } diff --git a/android/src/main/java/com/instabug/flutter/modules/ApmApi.java b/android/src/main/java/com/instabug/flutter/modules/ApmApi.java index ee93d7614..3b16e93fb 100644 --- a/android/src/main/java/com/instabug/flutter/modules/ApmApi.java +++ b/android/src/main/java/com/instabug/flutter/modules/ApmApi.java @@ -23,13 +23,20 @@ import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; +import java.util.concurrent.Callable; public class ApmApi implements ApmPigeon.ApmHostApi { private final String TAG = ApmApi.class.getName(); private final HashMap traces = new HashMap<>(); + private final Callable refreshRate; - public static void init(BinaryMessenger messenger) { - final ApmApi api = new ApmApi(); + public ApmApi(Callable refreshRate) { + this.refreshRate = refreshRate; + } + + public static void init(BinaryMessenger messenger, Callable refreshRateProvider) { + + final ApmApi api = new ApmApi(refreshRateProvider); ApmPigeon.ApmHostApi.setup(messenger, api); } @@ -475,11 +482,24 @@ public void setScreenLoadingEnabled(@NonNull Boolean isEnabled) { } } + @Override + public void setScreenRenderEnabled(@NonNull Boolean isEnabled) { + try { + APM.setScreenRenderingEnabled(isEnabled); + } catch (Exception e) { + e.printStackTrace(); + } + } @Override public void isScreenRenderEnabled(@NonNull ApmPigeon.Result result) { try { - result.success(true); + InternalAPM._isFeatureEnabledCP(APMFeature.SCREEN_RENDERING, "InstabugCaptureScreenRender", new FeatureAvailabilityCallback() { + @Override + public void invoke(boolean isEnabled) { + result.success(isEnabled); + } + }); } catch (Exception e) { e.printStackTrace(); } @@ -487,7 +507,11 @@ public void isScreenRenderEnabled(@NonNull ApmPigeon.Result result) { @Override public void deviceRefreshRate(@NonNull ApmPigeon.Result result) { - result.success(60.0); + try { + result.success(refreshRate.call().doubleValue()); + } catch (Exception e) { + e.printStackTrace(); + } } } diff --git a/android/src/test/java/com/instabug/flutter/ApmApiTest.java b/android/src/test/java/com/instabug/flutter/ApmApiTest.java index 725d3bd98..4ef118cec 100644 --- a/android/src/test/java/com/instabug/flutter/ApmApiTest.java +++ b/android/src/test/java/com/instabug/flutter/ApmApiTest.java @@ -8,10 +8,9 @@ import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.mockConstruction; import static org.mockito.Mockito.mockStatic; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; import com.instabug.apm.APM; import com.instabug.apm.InternalAPM; @@ -24,8 +23,6 @@ import com.instabug.flutter.util.GlobalMocks; import com.instabug.flutter.util.MockReflected; -import io.flutter.plugin.common.BinaryMessenger; - import org.json.JSONObject; import org.junit.After; import org.junit.Assert; @@ -36,18 +33,21 @@ import java.util.HashMap; import java.util.Map; +import java.util.concurrent.Callable; 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.*; import static org.mockito.Mockito.*; +import io.flutter.plugin.common.BinaryMessenger; public class ApmApiTest { private final BinaryMessenger mMessenger = mock(BinaryMessenger.class); - private final ApmApi api = new ApmApi(); + private final Callable refreshRateProvider = () -> mock(Float.class); + private final ApmApi api = new ApmApi(refreshRateProvider); private MockedStatic mAPM; private MockedStatic mInternalApmStatic; private MockedStatic mHostApi; @@ -83,7 +83,7 @@ private ExecutionTrace mockTrace(String id) { public void testInit() { BinaryMessenger messenger = mock(BinaryMessenger.class); - ApmApi.init(messenger); + ApmApi.init(messenger, refreshRateProvider); mHostApi.verify(() -> ApmPigeon.ApmHostApi.setup(eq(messenger), any(ApmApi.class))); } @@ -386,4 +386,34 @@ public void testSetScreenLoadingMonitoringEnabled() { mAPM.verify(() -> APM.setScreenLoadingEnabled(isEnabled)); } + + @Test + public void testIsScreenRenderEnabled() { + + boolean expected = true; + ApmPigeon.Result result = spy(makeResult((actual) -> assertEquals(expected, actual))); + + mInternalApmStatic.when(() -> InternalAPM._isFeatureEnabledCP(any(), any(), any())).thenAnswer( + invocation -> { + FeatureAvailabilityCallback callback = (FeatureAvailabilityCallback) invocation.getArguments()[2]; + callback.invoke(expected); + return null; + }); + + + api.isScreenRenderEnabled(result); + + mInternalApmStatic.verify(() -> InternalAPM._isFeatureEnabledCP(any(), any(), any())); + mInternalApmStatic.verifyNoMoreInteractions(); + + verify(result).success(expected); + } + + public void testSetScreenRenderEnabled() { + boolean isEnabled = false; + + api.setScreenRenderEnabled(isEnabled); + + mAPM.verify(() -> APM.setScreenRenderingEnabled(isEnabled)); + } } diff --git a/example/ios/Podfile b/example/ios/Podfile index 6020d7a4b..f72ca45fe 100644 --- a/example/ios/Podfile +++ b/example/ios/Podfile @@ -30,7 +30,8 @@ target 'Runner' do use_frameworks! use_modular_headers! - pod 'Instabug', :podspec => 'https://ios-releases.instabug.com/custom/fix-main-thread-warning/15.0.0/Instabug.podspec' +# pod 'Instabug', :podspec => 'https://ios-releases.instabug.com/custom/fix-main-thread-warning/15.0.0/Instabug.podspec' + pod 'Instabug', :podspec => 'https://ios-releases.instabug.com/custom/faeture-screen_rendering-release/15.1.0/Instabug.podspec' flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) end diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index fdf33bc82..7fcc59514 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -1,14 +1,14 @@ PODS: - Flutter (1.0.0) - - Instabug (15.0.0) + - Instabug (15.1.0) - instabug_flutter (14.3.0): - Flutter - - Instabug (= 15.0.0) + - Instabug (= 15.1.0) - OCMock (3.6) DEPENDENCIES: - Flutter (from `Flutter`) - - Instabug (from `https://ios-releases.instabug.com/custom/fix-main-thread-warning/15.0.0/Instabug.podspec`) + - Instabug (from `https://ios-releases.instabug.com/custom/faeture-screen_rendering-release/15.1.0/Instabug.podspec`) - instabug_flutter (from `.symlinks/plugins/instabug_flutter/ios`) - OCMock (= 3.6) @@ -20,16 +20,16 @@ EXTERNAL SOURCES: Flutter: :path: Flutter Instabug: - :podspec: https://ios-releases.instabug.com/custom/fix-main-thread-warning/15.0.0/Instabug.podspec + :podspec: https://ios-releases.instabug.com/custom/faeture-screen_rendering-release/15.1.0/Instabug.podspec instabug_flutter: :path: ".symlinks/plugins/instabug_flutter/ios" SPEC CHECKSUMS: - Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 - Instabug: 3b1db5a683e85ec5a02946aa2b3314036f9022be - instabug_flutter: e59da7a0cae82ce00b2773625ee544c275442000 + Flutter: 50d75fe2f02b26cc09d224853bb45737f8b3214a + Instabug: a2b8c384cd4af7a01ab43b2ce2957a880f8862d7 + instabug_flutter: 6ee721f30066123a769da64b687eded6eb4ff125 OCMock: 5ea90566be239f179ba766fd9fbae5885040b992 -PODFILE CHECKSUM: c16418947581b888c337ed7ff120a59b4b5f3f3f +PODFILE CHECKSUM: e6e180d6b55e3a12f55f266c3f4d8654480877ef COCOAPODS: 1.15.2 diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj index d32f983fc..2d4497cb9 100644 --- a/example/ios/Runner.xcodeproj/project.pbxproj +++ b/example/ios/Runner.xcodeproj/project.pbxproj @@ -271,7 +271,7 @@ 97C146E61CF9000F007C117D /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1510; + LastUpgradeCheck = 1300; ORGANIZATIONNAME = ""; TargetAttributes = { 97C146ED1CF9000F007C117D = { diff --git a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index 0b15932d1..b7206827b 100644 --- a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ diff --git a/example/lib/main.dart b/example/lib/main.dart index 8895bd084..020c05b59 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -1,54 +1,38 @@ import 'dart:async'; +import 'dart:convert'; import 'dart:developer'; import 'dart:io'; -import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:instabug_flutter/instabug_flutter.dart'; -import 'package:instabug_flutter_example/src/components/apm_switch.dart'; -import 'package:instabug_http_client/instabug_http_client.dart'; +import 'package:instabug_flutter/src/utils/screen_loading/screen_loading_manager.dart'; import 'package:instabug_flutter_example/src/app_routes.dart'; +import 'package:instabug_flutter_example/src/components/apm_switch.dart'; import 'package:instabug_flutter_example/src/widget/nested_view.dart'; +import 'package:instabug_http_client/instabug_http_client.dart'; import 'src/native/instabug_flutter_example_method_channel.dart'; import 'src/widget/instabug_button.dart'; import 'src/widget/instabug_clipboard_input.dart'; import 'src/widget/instabug_text_field.dart'; -import 'package:instabug_flutter/src/utils/screen_loading/screen_loading_manager.dart'; - import 'src/widget/section_title.dart'; -part 'src/screens/crashes_page.dart'; - -part 'src/screens/complex_page.dart'; - -part 'src/screens/apm_page.dart'; - -part 'src/screens/screen_capture_premature_extension_page.dart'; - -part 'src/screens/screen_loading_page.dart'; - -part 'src/screens/my_home_page.dart'; - -part 'src/screens/screen_render_page.dart'; - +part 'src/components/animated_box.dart'; part 'src/components/fatal_crashes_content.dart'; - -part 'src/components/non_fatal_crashes_content.dart'; - +part 'src/components/flows_content.dart'; part 'src/components/network_content.dart'; - +part 'src/components/non_fatal_crashes_content.dart'; part 'src/components/page.dart'; - -part 'src/components/traces_content.dart'; - -part 'src/components/flows_content.dart'; - part 'src/components/screen_render.dart'; - -part 'src/components/animated_box.dart'; - +part 'src/components/traces_content.dart'; part 'src/components/ui_traces_content.dart'; +part 'src/screens/apm_page.dart'; +part 'src/screens/complex_page.dart'; +part 'src/screens/crashes_page.dart'; +part 'src/screens/my_home_page.dart'; +part 'src/screens/screen_capture_premature_extension_page.dart'; +part 'src/screens/screen_loading_page.dart'; +part 'src/screens/screen_render_page.dart'; void main() { runZonedGuarded( diff --git a/example/pubspec.lock b/example/pubspec.lock index ba4cc0a6d..db618bb81 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -1,62 +1,76 @@ # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: + archive: + dependency: transitive + description: + name: archive + url: "https://pub.dartlang.org" + source: hosted + version: "3.1.6" async: dependency: transitive description: name: async - sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "2.11.0" + version: "2.8.2" boolean_selector: dependency: transitive description: name: boolean_selector - sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "2.1.1" + version: "2.1.0" characters: dependency: transitive description: name: characters - sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "1.3.0" + version: "1.2.0" + charcode: + dependency: transitive + description: + name: charcode + url: "https://pub.dartlang.org" + source: hosted + version: "1.3.1" clock: dependency: transitive description: name: clock - sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "1.1.1" + version: "1.1.0" collection: dependency: transitive description: name: collection - sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "1.19.0" + version: "1.15.0" + crypto: + dependency: transitive + description: + name: crypto + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.1" fake_async: dependency: transitive description: name: fake_async - sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "1.3.1" + version: "1.2.0" file: dependency: transitive description: name: file - sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c" - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "7.0.0" + version: "6.1.2" flutter: dependency: "direct main" description: flutter @@ -71,8 +85,7 @@ packages: dependency: "direct dev" description: name: flutter_lints - sha256: b543301ad291598523947dc534aaddc5aaad597b709d2426d3a0e0d44c5cb493 - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted version: "1.0.4" flutter_test: @@ -89,16 +102,14 @@ packages: dependency: "direct main" description: name: http - sha256: "5895291c13fa8a3bd82e76d5627f69e0d85ca6a30dcac95c4ea19a5d555879c2" - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "0.13.6" + version: "0.13.5" http_parser: dependency: transitive description: name: http_parser - sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted version: "4.0.2" instabug_flutter: @@ -112,183 +123,139 @@ packages: dependency: "direct main" description: name: instabug_http_client - sha256: "7d52803c0dd639f6dddbe07333418eb251ae02f3f9f4d30402517533ca692784" - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "2.4.0" - leak_tracker: - dependency: transitive - description: - name: leak_tracker - sha256: "7bb2830ebd849694d1ec25bf1f44582d6ac531a57a365a803a6034ff751d2d06" - url: "https://pub.dev" - source: hosted - version: "10.0.7" - leak_tracker_flutter_testing: - dependency: transitive - description: - name: leak_tracker_flutter_testing - sha256: "9491a714cca3667b60b5c420da8217e6de0d1ba7a5ec322fab01758f6998f379" - url: "https://pub.dev" - source: hosted - version: "3.0.8" - leak_tracker_testing: - dependency: transitive - description: - name: leak_tracker_testing - sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" - url: "https://pub.dev" - source: hosted - version: "3.0.1" + version: "2.5.1" lints: dependency: transitive description: name: lints - sha256: a2c3d198cb5ea2e179926622d433331d8b58374ab8f29cdda6e863bd62fd369c - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted version: "1.0.1" matcher: dependency: transitive description: name: matcher - sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "0.12.16+1" + version: "0.12.11" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "0.11.1" + version: "0.1.3" meta: dependency: transitive description: name: meta - sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "1.15.0" + version: "1.7.0" path: dependency: transitive description: name: path - sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "1.9.0" + version: "1.8.0" platform: dependency: transitive description: name: platform - sha256: "9b71283fc13df574056616011fb138fd3b793ea47cc509c189a6c3fa5f8a1a65" - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "3.1.5" + version: "3.1.0" process: dependency: transitive description: name: process - sha256: "21e54fd2faf1b5bdd5102afd25012184a6793927648ea81eea80552ac9405b32" - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "5.0.2" + version: "4.2.4" sky_engine: dependency: transitive description: flutter source: sdk - version: "0.0.0" + version: "0.0.99" source_span: dependency: transitive description: name: source_span - sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "1.10.0" + version: "1.8.1" stack_trace: dependency: transitive description: name: stack_trace - sha256: "9f47fd3630d76be3ab26f0ee06d213679aa425996925ff3feffdec504931c377" - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "1.12.0" + version: "1.10.0" stream_channel: dependency: transitive description: name: stream_channel - sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "2.1.2" + version: "2.1.0" string_scanner: dependency: transitive description: name: string_scanner - sha256: "688af5ed3402a4bde5b3a6c15fd768dbf2621a614950b17f04626c431ab3c4c3" - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "1.3.0" + version: "1.1.0" sync_http: dependency: transitive description: name: sync_http - sha256: "7f0cd72eca000d2e026bcd6f990b81d0ca06022ef4e32fb257b30d3d1014a961" - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "0.3.1" + version: "0.3.0" term_glyph: dependency: transitive description: name: term_glyph - sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "1.2.1" + version: "1.2.0" test_api: dependency: transitive description: name: test_api - sha256: "664d3a9a64782fcdeb83ce9c6b39e78fd2971d4e37827b9b06c3aa1edc5e760c" - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "0.7.3" + version: "0.4.8" typed_data: dependency: transitive description: name: typed_data - sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "1.4.0" + version: "1.3.0" vector_math: dependency: transitive description: name: vector_math - sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "2.1.4" + version: "2.1.1" vm_service: dependency: transitive description: name: vm_service - sha256: f6be3ed8bd01289b34d679c2b62226f63c0e69f9fd2e50a6b3c1c729a961041b - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "14.3.0" + version: "7.5.0" webdriver: dependency: transitive description: name: webdriver - sha256: "3d773670966f02a646319410766d3b5e1037efb7f07cc68f844d5e06cd4d61c8" - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "3.0.4" + version: "3.0.0" sdks: - dart: ">=3.5.0 <4.0.0" - flutter: ">=3.18.0-18.0.pre.54" + dart: ">=2.14.0 <3.0.0" diff --git a/ios/Classes/Modules/ApmApi.m b/ios/Classes/Modules/ApmApi.m index 01d4952b3..385936702 100644 --- a/ios/Classes/Modules/ApmApi.m +++ b/ios/Classes/Modules/ApmApi.m @@ -91,7 +91,7 @@ - (void)startExecutionTraceId:(NSString *)id name:(NSString *)name completion:(v // Deprecated - see [startFlowName, setFlowAttributeName & endFlowName]. - (void)setExecutionTraceAttributeId:(NSString *)id key:(NSString *)key value:(NSString *)value error:(FlutterError *_Nullable *_Nonnull)error { IBGExecutionTrace *trace = [traces objectForKey:id]; - + if (trace != nil) { [trace setAttributeWithKey:key value:value]; } @@ -103,7 +103,7 @@ - (void)setExecutionTraceAttributeId:(NSString *)id key:(NSString *)key value:(N // Deprecated - see [startFlowName, setFlowAttributeName & endFlowName]. - (void)endExecutionTraceId:(NSString *)id error:(FlutterError *_Nullable *_Nonnull)error { IBGExecutionTrace *trace = [traces objectForKey:id]; - + if (trace != nil) { [trace end]; } @@ -130,13 +130,13 @@ - (void)endFlowName:(nonnull NSString *)name error:(FlutterError * _Nullable __a [IBGAPM endFlowWithName:name]; } -// This method is responsible for starting a UI trace with the given `name`. +// This method is responsible for starting a UI trace with the given `name`. // Which initiates the tracking of user interface interactions for monitoring the performance of the application. - (void)startUITraceName:(NSString *)name error:(FlutterError *_Nullable *_Nonnull)error { [IBGAPM startUITraceWithName:name]; } -// The method is responsible for ending the currently active UI trace. +// The method is responsible for ending the currently active UI trace. // Which signifies the completion of tracking user interface interactions. - (void)endUITraceWithError:(FlutterError *_Nullable *_Nonnull)error { [IBGAPM endUITrace]; @@ -198,13 +198,58 @@ - (void)isEndScreenLoadingEnabledWithCompletion:(nonnull void (^)(NSNumber * _Nu } - (void)isScreenRenderEnabledWithCompletion:(void (^)(NSNumber * _Nullable, FlutterError * _Nullable))completion{ - BOOL isScreenRenderEnabled = YES; + BOOL isScreenRenderEnabled = IBGAPM.isScreenRenderingOperational; NSNumber *isEnabledNumber = @(isScreenRenderEnabled); completion(isEnabledNumber, nil); } +- (void)setScreenRenderEnabledIsEnabled:(nonnull NSNumber *)isEnabled error:(FlutterError * _Nullable __autoreleasing * _Nonnull)error { + [IBGAPM setScreenRenderingEnabled:[isEnabled boolValue]]; + +} + - (void)deviceRefreshRateWithCompletion:(void (^)(NSNumber * _Nullable, FlutterError * _Nullable))completion{ - completion(@60 , nil); + // First, try using CADisplayLink to get the preferred frame rate. + // This is a more modern approach, especially for ProMotion displays. + CADisplayLink *displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(onDisplayLink:)]; + displayLink.paused = YES; + [displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes]; + + NSInteger preferredFPS = displayLink.preferredFramesPerSecond; + + [displayLink invalidate]; + + if (preferredFPS != 0) { + completion(@(preferredFPS) , nil); + return; + } + + // If CADisplayLink fails, fall back to other methods. + // For iOS 13+, use the windowScene for better accuracy in multi-window environments. + if (@available(iOS 13.0, *)) { + UIWindowScene *windowScene = nil; + // Find the first active window scene + for (UIScene *scene in [UIApplication sharedApplication].connectedScenes) { + if (scene.activationState == UISceneActivationStateForegroundActive && [scene isKindOfClass:[UIWindowScene class]]) { + windowScene = (UIWindowScene *)scene; + break; + } + } + + if (windowScene) { + completion(@(windowScene.screen.maximumFramesPerSecond) , nil); + return; + } + } + + // As a final fallback (and for iOS versions < 13), use the main screen. + if (@available(iOS 10.3, *)) { + double refreshRate = [UIScreen mainScreen].maximumFramesPerSecond; + completion(@(refreshRate) ,nil); + } else { + // Fallback for very old iOS versions. + completion(@(60.0) , nil); + } } diff --git a/ios/Classes/Util/IBGAPM+PrivateAPIs.h b/ios/Classes/Util/IBGAPM+PrivateAPIs.h index 22207d45b..dba847b13 100644 --- a/ios/Classes/Util/IBGAPM+PrivateAPIs.h +++ b/ios/Classes/Util/IBGAPM+PrivateAPIs.h @@ -22,4 +22,6 @@ + (void)endScreenLoadingCPWithEndTimestampMUS:(IBGMicroSecondsTimeInterval)endTimestampMUS; ++ (BOOL)isScreenRenderingOperational; + @end diff --git a/ios/instabug_flutter.podspec b/ios/instabug_flutter.podspec index 22c684ec7..cf6703fda 100644 --- a/ios/instabug_flutter.podspec +++ b/ios/instabug_flutter.podspec @@ -17,6 +17,6 @@ Pod::Spec.new do |s| s.pod_target_xcconfig = { 'OTHER_LDFLAGS' => '-framework "Flutter" -framework "InstabugSDK"'} s.dependency 'Flutter' - s.dependency 'Instabug', '15.0.0' + s.dependency 'Instabug', '15.1.0' end diff --git a/lib/src/modules/apm.dart b/lib/src/modules/apm.dart index efd9dc609..4077d65f2 100644 --- a/lib/src/modules/apm.dart +++ b/lib/src/modules/apm.dart @@ -381,4 +381,17 @@ class APM { static Future getDeviceRefreshRate() { return _host.deviceRefreshRate(); } + + /// Sets the screen Render state based on the provided boolean value. + /// + /// Args: + /// isEnabled (bool): The [isEnabled] parameter is a boolean value that determines whether screen + /// Render is enabled or disabled. If [isEnabled] is `true`, screen render will be enabled; if + /// [isEnabled] is `false`, screen render will be disabled. + /// + /// Returns: + /// A Future is being returned. + static Future setScreenRenderEnabled(bool isEnabled) { + return _host.setScreenRenderEnabled(isEnabled); + } } diff --git a/lib/src/modules/instabug.dart b/lib/src/modules/instabug.dart index 9ef4930b0..3d7b52f1b 100644 --- a/lib/src/modules/instabug.dart +++ b/lib/src/modules/instabug.dart @@ -191,6 +191,7 @@ class Instabug { }) async { $setup(); InstabugLogger.I.logLevel = debugLogsLevel; + checkForWidgetBinding(); await _host.init( token, invocationEvents.mapToString(), @@ -198,7 +199,6 @@ class Instabug { ); if (await FlagsConfig.screenRendering.isEnabled()) { - checkForWidgetBinding(); InstabugScreenRenderManager.I.init(WidgetsBinding.instance); } diff --git a/lib/src/utils/instabug_navigator_observer.dart b/lib/src/utils/instabug_navigator_observer.dart index 4f3e814ff..80b4cb13d 100644 --- a/lib/src/utils/instabug_navigator_observer.dart +++ b/lib/src/utils/instabug_navigator_observer.dart @@ -1,3 +1,6 @@ +import 'dart:async'; +import 'dart:developer'; + import 'package:flutter/material.dart'; import 'package:instabug_flutter/instabug_flutter.dart'; import 'package:instabug_flutter/src/models/instabug_route.dart'; @@ -6,6 +9,8 @@ import 'package:instabug_flutter/src/utils/instabug_logger.dart'; import 'package:instabug_flutter/src/utils/repro_steps_constants.dart'; import 'package:instabug_flutter/src/utils/screen_loading/screen_loading_manager.dart'; import 'package:instabug_flutter/src/utils/screen_name_masker.dart'; +import 'package:instabug_flutter/src/utils/screen_rendering/instabug_screen_render_manager.dart'; +import 'package:instabug_flutter/src/utils/ui_trace/flags_config.dart'; class InstabugNavigatorObserver extends NavigatorObserver { final List _steps = []; @@ -23,8 +28,9 @@ class InstabugNavigatorObserver extends NavigatorObserver { name: maskedScreenName, ); - // Starts a the new UI trace which is exclusive to screen loading - ScreenLoadingManager.I.startUiTrace(maskedScreenName, screenName); + ScreenLoadingManager.I + .startUiTrace(maskedScreenName, screenName) + .then(_startScreenRenderCollector); // If there is a step that hasn't been pushed yet if (_steps.isNotEmpty) { @@ -48,6 +54,15 @@ class InstabugNavigatorObserver extends NavigatorObserver { } } + FutureOr _startScreenRenderCollector(int? uiTraceId) async { + final isScreenRender = await FlagsConfig.screenRendering.isEnabled(); + log("isScreenRender: $isScreenRender", name: 'Andrew'); + if (uiTraceId != null && isScreenRender) { + InstabugScreenRenderManager.I + .startScreenRenderCollectorForTraceId(uiTraceId); + } + } + @override void didPop(Route route, Route? previousRoute) { if (previousRoute != null) { diff --git a/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart b/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart index bde2008c3..50e16fbc5 100644 --- a/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart +++ b/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart @@ -142,9 +142,11 @@ class InstabugScreenRenderManager { 1 / displayRefreshRate * 1000; /// Get device refresh rate from native side. - //todo: will be compared with value from native side after it's implemented. - Future get _getDeviceRefreshRateFromNative => - APM.getDeviceRefreshRate(); + Future get _getDeviceRefreshRateFromNative { + final rr = APM.getDeviceRefreshRate(); + log("refreshRateFromNative: $rr", name: "Andrew"); + return rr; + } /// Initialize the static variables Future _initStaticValues() async { @@ -162,12 +164,16 @@ class InstabugScreenRenderManager { /// Add a frame observer by calling [WidgetsBinding.instance.addTimingsCallback] void _initFrameTimings() { + if (_isTimingsListenerAttached) { + return; // A timings callback is already attached + } _widgetsBinding.addTimingsCallback(_timingsCallback); _isTimingsListenerAttached = true; } /// Remove the running frame observer by calling [_widgetsBinding.removeTimingsCallback] void _removeFrameTimings() { + if (!_isTimingsListenerAttached) return; // No timings callback attached. _widgetsBinding.removeTimingsCallback(_timingsCallback); _isTimingsListenerAttached = false; } @@ -212,6 +218,8 @@ class InstabugScreenRenderManager { /// Stop screen render collector and sync the captured data. @internal void stopScreenRenderCollector() { + if (_delayedFrames.isEmpty) return; // No delayed framed to be synced. + _saveCollectedData(); if (_screenRenderForCustomUiTrace.isNotEmpty) { @@ -229,18 +237,18 @@ class InstabugScreenRenderManager { /// Sync the capture screen render data of the custom UI trace without stopping the collector. @internal void endScreenRenderCollectorForCustomUiTrace() { - if (_screenRenderForCustomUiTrace.isNotEmpty) { - // Save the captured screen rendering data to be synced - _screenRenderForCustomUiTrace.slowFramesTotalDuration += - _slowFramesTotalDuration; - _screenRenderForCustomUiTrace.frozenFramesTotalDuration += - _frozenFramesTotalDuration; - _screenRenderForCustomUiTrace.frameData.addAll(_delayedFrames); - - // Sync the saved screen rendering data - reportScreenRending(_screenRenderForCustomUiTrace, UiTraceType.custom); - _screenRenderForCustomUiTrace.clear(); - } + if (_screenRenderForCustomUiTrace.isEmpty) return; + + // Save the captured screen rendering data to be synced + _screenRenderForCustomUiTrace.slowFramesTotalDuration += + _slowFramesTotalDuration; + _screenRenderForCustomUiTrace.frozenFramesTotalDuration += + _frozenFramesTotalDuration; + _screenRenderForCustomUiTrace.frameData.addAll(_delayedFrames); + + // Sync the saved screen rendering data + reportScreenRending(_screenRenderForCustomUiTrace, UiTraceType.custom); + _screenRenderForCustomUiTrace.clear(); } /// Reset the memory cashed data diff --git a/pigeons/apm.api.dart b/pigeons/apm.api.dart index d4a159631..255e35de4 100644 --- a/pigeons/apm.api.dart +++ b/pigeons/apm.api.dart @@ -46,4 +46,6 @@ abstract class ApmHostApi { @async double deviceRefreshRate(); + + void setScreenRenderEnabled(bool isEnabled); } diff --git a/scripts/pigeon.sh b/scripts/pigeon.sh old mode 100644 new mode 100755 diff --git a/test/utils/screen_render/instabug_screen_render_manager_test.dart b/test/utils/screen_render/instabug_screen_render_manager_test.dart index f77d8b234..73fea5561 100644 --- a/test/utils/screen_render/instabug_screen_render_manager_test.dart +++ b/test/utils/screen_render/instabug_screen_render_manager_test.dart @@ -1,13 +1,19 @@ +import 'dart:ui'; + +import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:instabug_flutter/instabug_flutter.dart'; +import 'package:instabug_flutter/src/generated/apm.api.g.dart'; import 'package:instabug_flutter/src/models/instabug_frame_data.dart'; import 'package:instabug_flutter/src/models/instabug_screen_render_data.dart'; import 'package:instabug_flutter/src/utils/screen_rendering/instabug_screen_render_manager.dart'; +import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; +import 'instabug_screen_render_manager_test.mocks.dart'; +// import 'instabug_screen_render_manager_test_manual_mocks.dart'; -import 'instabug_screen_render_manager_test_manual_mocks.dart'; - +@GenerateMocks([FrameTiming, ApmHostApi, WidgetsBinding]) void main() { TestWidgetsFlutterBinding.ensureInitialized(); @@ -74,8 +80,8 @@ void main() { manager.startScreenRenderCollectorForTraceId(1); verify(mWidgetBinding.addTimingsCallback(any)).called( - 2, - ); // one form initForTesting() and one form startScreenRenderCollectorForTraceId() + 1, + ); }); test('should update the data for same trace type', () { @@ -199,7 +205,24 @@ void main() { expect(manager.screenRenderForAutoUiTrace.isEmpty, true); }); + test('should do nothing if there is no cached data', () { + manager.stopScreenRenderCollector(); + + verifyNever(mWidgetBinding.removeTimingsCallback(any)); + }); + test('should remove timing callback listener', () { + final frameTestdata = InstabugScreenRenderData( + traceId: 123, + frameData: [ + InstabugFrameData(10000, 200), + InstabugFrameData(20000, 1000), + ], + frozenFramesTotalDuration: 1000, + slowFramesTotalDuration: 200, + ); + + manager.setFrameData(frameTestdata); manager.stopScreenRenderCollector(); verify(mWidgetBinding.removeTimingsCallback(any)).called(1); diff --git a/test/utils/screen_render/instabug_screen_render_manager_test_manual_mocks.dart b/test/utils/screen_render/instabug_screen_render_manager_test_manual_mocks.dart deleted file mode 100644 index b35602da3..000000000 --- a/test/utils/screen_render/instabug_screen_render_manager_test_manual_mocks.dart +++ /dev/null @@ -1,880 +0,0 @@ -// Mocks generated by Mockito 5.2.0 from annotations -// in instabug_flutter/example/ios/.symlinks/plugins/instabug_flutter/test/utils/screen_render/instabug_screen_render_manager_test.dart. -// Do not manually edit this file. - -import 'dart:async' as _i9; -import 'dart:developer' as _i13; -import 'dart:ui' as _i4; - -import 'package:flutter/foundation.dart' as _i3; -import 'package:flutter/gestures.dart' as _i6; -import 'package:flutter/rendering.dart' as _i7; -import 'package:flutter/scheduler.dart' as _i11; -import 'package:flutter/services.dart' as _i5; -import 'package:flutter/src/widgets/binding.dart' as _i10; -import 'package:flutter/src/widgets/focus_manager.dart' as _i2; -import 'package:flutter/src/widgets/framework.dart' as _i12; -import 'package:instabug_flutter/src/generated/apm.api.g.dart' as _i8; -import 'package:mockito/mockito.dart' as _i1; - -// ignore_for_file: type=lint -// ignore_for_file: avoid_redundant_argument_values -// ignore_for_file: avoid_setters_without_getters -// ignore_for_file: comment_references -// ignore_for_file: implementation_imports -// ignore_for_file: invalid_use_of_visible_for_testing_member -// ignore_for_file: prefer_const_constructors -// ignore_for_file: unnecessary_parenthesis -// ignore_for_file: camel_case_types - -// This file has been manually changed due to a mockito inconsistency with flutter v 2.10.5 - -class _FakeDuration_0 extends _i1.Fake implements Duration {} - -class _FakeFocusManager_1 extends _i1.Fake implements _i2.FocusManager { - @override - String toString({_i3.DiagnosticLevel? minLevel = _i3.DiagnosticLevel.info}) => - super.toString(); -} - -class _FakeSingletonFlutterWindow_2 extends _i1.Fake - implements _i4.SingletonFlutterWindow {} - -class _FakePlatformDispatcher_3 extends _i1.Fake - implements _i4.PlatformDispatcher {} - -class _FakeHardwareKeyboard_4 extends _i1.Fake implements _i5.HardwareKeyboard { -} - -class _FakeKeyEventManager_5 extends _i1.Fake implements _i5.KeyEventManager {} - -class _FakeBinaryMessenger_6 extends _i1.Fake implements _i5.BinaryMessenger {} - -class _FakeChannelBuffers_7 extends _i1.Fake implements _i4.ChannelBuffers {} - -class _FakeRestorationManager_8 extends _i1.Fake - implements _i5.RestorationManager {} - -class _FakePointerRouter_9 extends _i1.Fake implements _i6.PointerRouter {} - -class _FakeGestureArenaManager_10 extends _i1.Fake - implements _i6.GestureArenaManager {} - -class _FakePointerSignalResolver_11 extends _i1.Fake - implements _i6.PointerSignalResolver {} - -class _FakeMouseTracker_12 extends _i1.Fake implements _i7.MouseTracker {} - -class _FakePipelineOwner_13 extends _i1.Fake implements _i7.PipelineOwner {} - -class _FakeRenderView_14 extends _i1.Fake implements _i7.RenderView { - @override - String toString({_i3.DiagnosticLevel? minLevel = _i3.DiagnosticLevel.info}) => - super.toString(); -} - -class _FakeAccessibilityFeatures_15 extends _i1.Fake - implements _i4.AccessibilityFeatures {} - -class _FakeViewConfiguration_16 extends _i1.Fake - implements _i7.ViewConfiguration {} - -class _FakeSemanticsUpdateBuilder_17 extends _i1.Fake - implements _i4.SemanticsUpdateBuilder {} - -/// A class which mocks [FrameTiming]. -/// -/// See the documentation for Mockito's code generation for more information. -class MockFrameTiming extends _i1.Mock implements _i4.FrameTiming { - MockFrameTiming() { - _i1.throwOnMissingStub(this); - } - - @override - Duration get buildDuration => - (super.noSuchMethod(Invocation.getter(#buildDuration), - returnValue: _FakeDuration_0()) as Duration); - - @override - Duration get rasterDuration => - (super.noSuchMethod(Invocation.getter(#rasterDuration), - returnValue: _FakeDuration_0()) as Duration); - - @override - Duration get vsyncOverhead => - (super.noSuchMethod(Invocation.getter(#vsyncOverhead), - returnValue: _FakeDuration_0()) as Duration); - - @override - Duration get totalSpan => (super.noSuchMethod(Invocation.getter(#totalSpan), - returnValue: _FakeDuration_0()) as Duration); - - @override - int get layerCacheCount => - (super.noSuchMethod(Invocation.getter(#layerCacheCount), returnValue: 0) - as int); - - @override - int get layerCacheBytes => - (super.noSuchMethod(Invocation.getter(#layerCacheBytes), returnValue: 0) - as int); - - @override - double get layerCacheMegabytes => - (super.noSuchMethod(Invocation.getter(#layerCacheMegabytes), - returnValue: 0.0) as double); - - @override - int get pictureCacheCount => - (super.noSuchMethod(Invocation.getter(#pictureCacheCount), returnValue: 0) - as int); - - @override - int get pictureCacheBytes => - (super.noSuchMethod(Invocation.getter(#pictureCacheBytes), returnValue: 0) - as int); - - @override - double get pictureCacheMegabytes => - (super.noSuchMethod(Invocation.getter(#pictureCacheMegabytes), - returnValue: 0.0) as double); - - @override - int get frameNumber => - (super.noSuchMethod(Invocation.getter(#frameNumber), returnValue: 0) - as int); - - @override - int timestampInMicroseconds(_i4.FramePhase? phase) => - (super.noSuchMethod(Invocation.method(#timestampInMicroseconds, [phase]), - returnValue: 0) as int); -} - -/// A class which mocks [ApmHostApi]. -/// -/// See the documentation for Mockito's code generation for more information. -class MockApmHostApi extends _i1.Mock implements _i8.ApmHostApi { - MockApmHostApi() { - _i1.throwOnMissingStub(this); - } - - @override - _i9.Future setEnabled(bool? arg_isEnabled) => - (super.noSuchMethod(Invocation.method(#setEnabled, [arg_isEnabled]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - - @override - _i9.Future isEnabled() => - (super.noSuchMethod(Invocation.method(#isEnabled, []), - returnValue: Future.value(false)) as _i9.Future); - - @override - _i9.Future setScreenLoadingEnabled(bool? arg_isEnabled) => - (super.noSuchMethod( - Invocation.method(#setScreenLoadingEnabled, [arg_isEnabled]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - - @override - _i9.Future isScreenLoadingEnabled() => - (super.noSuchMethod(Invocation.method(#isScreenLoadingEnabled, []), - returnValue: Future.value(false)) as _i9.Future); - - @override - _i9.Future setColdAppLaunchEnabled(bool? arg_isEnabled) => - (super.noSuchMethod( - Invocation.method(#setColdAppLaunchEnabled, [arg_isEnabled]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - - @override - _i9.Future setAutoUITraceEnabled(bool? arg_isEnabled) => (super - .noSuchMethod(Invocation.method(#setAutoUITraceEnabled, [arg_isEnabled]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - - @override - _i9.Future startExecutionTrace(String? arg_id, String? arg_name) => - (super.noSuchMethod( - Invocation.method(#startExecutionTrace, [arg_id, arg_name]), - returnValue: Future.value()) as _i9.Future); - - @override - _i9.Future startFlow(String? arg_name) => - (super.noSuchMethod(Invocation.method(#startFlow, [arg_name]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - - @override - _i9.Future setFlowAttribute( - String? arg_name, String? arg_key, String? arg_value) => - (super.noSuchMethod( - Invocation.method(#setFlowAttribute, [arg_name, arg_key, arg_value]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - - @override - _i9.Future endFlow(String? arg_name) => - (super.noSuchMethod(Invocation.method(#endFlow, [arg_name]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - - @override - _i9.Future setExecutionTraceAttribute( - String? arg_id, String? arg_key, String? arg_value) => - (super.noSuchMethod( - Invocation.method( - #setExecutionTraceAttribute, [arg_id, arg_key, arg_value]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - - @override - _i9.Future endExecutionTrace(String? arg_id) => - (super.noSuchMethod(Invocation.method(#endExecutionTrace, [arg_id]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - - @override - _i9.Future startUITrace(String? arg_name) => - (super.noSuchMethod(Invocation.method(#startUITrace, [arg_name]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - - @override - _i9.Future endUITrace() => - (super.noSuchMethod(Invocation.method(#endUITrace, []), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - - @override - _i9.Future endAppLaunch() => - (super.noSuchMethod(Invocation.method(#endAppLaunch, []), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - - @override - _i9.Future networkLogAndroid(Map? arg_data) => - (super.noSuchMethod(Invocation.method(#networkLogAndroid, [arg_data]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - - @override - _i9.Future startCpUiTrace( - String? arg_screenName, int? arg_microTimeStamp, int? arg_traceId) => - (super.noSuchMethod( - Invocation.method(#startCpUiTrace, - [arg_screenName, arg_microTimeStamp, arg_traceId]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - - @override - _i9.Future reportScreenLoadingCP(int? arg_startTimeStampMicro, - int? arg_durationMicro, int? arg_uiTraceId) => - (super.noSuchMethod( - Invocation.method(#reportScreenLoadingCP, - [arg_startTimeStampMicro, arg_durationMicro, arg_uiTraceId]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - - @override - _i9.Future endScreenLoadingCP( - int? arg_timeStampMicro, int? arg_uiTraceId) => - (super.noSuchMethod( - Invocation.method( - #endScreenLoadingCP, [arg_timeStampMicro, arg_uiTraceId]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - - @override - _i9.Future isEndScreenLoadingEnabled() => - (super.noSuchMethod(Invocation.method(#isEndScreenLoadingEnabled, []), - returnValue: Future.value(false)) as _i9.Future); - - @override - _i9.Future isScreenRenderEnabled() => - (super.noSuchMethod(Invocation.method(#isScreenRenderEnabled, []), - returnValue: Future.value(false)) as _i9.Future); - - @override - _i9.Future deviceRefreshRate() => - (super.noSuchMethod(Invocation.method(#deviceRefreshRate, []), - returnValue: Future.value(0.0)) as _i9.Future); -} - -/// A class which mocks [WidgetsBinding]. -/// -/// See the documentation for Mockito's code generation for more information. -class MockWidgetsBinding extends _i1.Mock implements _i10.WidgetsBinding { - MockWidgetsBinding() { - _i1.throwOnMissingStub(this); - } - - @override - bool get debugBuildingDirtyElements => - (super.noSuchMethod(Invocation.getter(#debugBuildingDirtyElements), - returnValue: false) as bool); - - @override - set debugBuildingDirtyElements(bool? _debugBuildingDirtyElements) => - super.noSuchMethod( - Invocation.setter( - #debugBuildingDirtyElements, _debugBuildingDirtyElements), - returnValueForMissingStub: null); - - @override - _i2.FocusManager get focusManager => - (super.noSuchMethod(Invocation.getter(#focusManager), - returnValue: _FakeFocusManager_1()) as _i2.FocusManager); - - @override - bool get firstFrameRasterized => - (super.noSuchMethod(Invocation.getter(#firstFrameRasterized), - returnValue: false) as bool); - - @override - _i9.Future get waitUntilFirstFrameRasterized => - (super.noSuchMethod(Invocation.getter(#waitUntilFirstFrameRasterized), - returnValue: Future.value()) as _i9.Future); - - @override - bool get debugDidSendFirstFrameEvent => - (super.noSuchMethod(Invocation.getter(#debugDidSendFirstFrameEvent), - returnValue: false) as bool); - - @override - bool get framesEnabled => - (super.noSuchMethod(Invocation.getter(#framesEnabled), returnValue: false) - as bool); - - @override - bool get isRootWidgetAttached => - (super.noSuchMethod(Invocation.getter(#isRootWidgetAttached), - returnValue: false) as bool); - - @override - _i4.SingletonFlutterWindow get window => - (super.noSuchMethod(Invocation.getter(#window), - returnValue: _FakeSingletonFlutterWindow_2()) - as _i4.SingletonFlutterWindow); - - @override - _i4.PlatformDispatcher get platformDispatcher => - (super.noSuchMethod(Invocation.getter(#platformDispatcher), - returnValue: _FakePlatformDispatcher_3()) as _i4.PlatformDispatcher); - - @override - bool get locked => - (super.noSuchMethod(Invocation.getter(#locked), returnValue: false) - as bool); - - @override - _i5.HardwareKeyboard get keyboard => - (super.noSuchMethod(Invocation.getter(#keyboard), - returnValue: _FakeHardwareKeyboard_4()) as _i5.HardwareKeyboard); - - @override - _i5.KeyEventManager get keyEventManager => - (super.noSuchMethod(Invocation.getter(#keyEventManager), - returnValue: _FakeKeyEventManager_5()) as _i5.KeyEventManager); - - @override - _i5.BinaryMessenger get defaultBinaryMessenger => - (super.noSuchMethod(Invocation.getter(#defaultBinaryMessenger), - returnValue: _FakeBinaryMessenger_6()) as _i5.BinaryMessenger); - - @override - _i4.ChannelBuffers get channelBuffers => - (super.noSuchMethod(Invocation.getter(#channelBuffers), - returnValue: _FakeChannelBuffers_7()) as _i4.ChannelBuffers); - - @override - _i5.RestorationManager get restorationManager => - (super.noSuchMethod(Invocation.getter(#restorationManager), - returnValue: _FakeRestorationManager_8()) as _i5.RestorationManager); - - // Parameters {int? priority, _i11.SchedulerBinding? scheduler} have been - // changed from {int priority, _i11.SchedulerBinding scheduler}. - @override - _i11.SchedulingStrategy get schedulingStrategy => - (super.noSuchMethod(Invocation.getter(#schedulingStrategy), - returnValue: ({int? priority, _i11.SchedulerBinding? scheduler}) => - false) as _i11.SchedulingStrategy); - - @override - set schedulingStrategy(_i11.SchedulingStrategy? _schedulingStrategy) => super - .noSuchMethod(Invocation.setter(#schedulingStrategy, _schedulingStrategy), - returnValueForMissingStub: null); - - @override - int get transientCallbackCount => - (super.noSuchMethod(Invocation.getter(#transientCallbackCount), - returnValue: 0) as int); - - @override - _i9.Future get endOfFrame => - (super.noSuchMethod(Invocation.getter(#endOfFrame), - returnValue: Future.value()) as _i9.Future); - - @override - bool get hasScheduledFrame => - (super.noSuchMethod(Invocation.getter(#hasScheduledFrame), - returnValue: false) as bool); - - @override - _i11.SchedulerPhase get schedulerPhase => - (super.noSuchMethod(Invocation.getter(#schedulerPhase), - returnValue: _i11.SchedulerPhase.idle) as _i11.SchedulerPhase); - - @override - Duration get currentFrameTimeStamp => - (super.noSuchMethod(Invocation.getter(#currentFrameTimeStamp), - returnValue: _FakeDuration_0()) as Duration); - - @override - Duration get currentSystemFrameTimeStamp => - (super.noSuchMethod(Invocation.getter(#currentSystemFrameTimeStamp), - returnValue: _FakeDuration_0()) as Duration); - - @override - _i6.PointerRouter get pointerRouter => - (super.noSuchMethod(Invocation.getter(#pointerRouter), - returnValue: _FakePointerRouter_9()) as _i6.PointerRouter); - - @override - _i6.GestureArenaManager get gestureArena => (super.noSuchMethod( - Invocation.getter(#gestureArena), - returnValue: _FakeGestureArenaManager_10()) as _i6.GestureArenaManager); - - @override - _i6.PointerSignalResolver get pointerSignalResolver => - (super.noSuchMethod(Invocation.getter(#pointerSignalResolver), - returnValue: _FakePointerSignalResolver_11()) - as _i6.PointerSignalResolver); - - @override - bool get resamplingEnabled => - (super.noSuchMethod(Invocation.getter(#resamplingEnabled), - returnValue: false) as bool); - - @override - set resamplingEnabled(bool? _resamplingEnabled) => super.noSuchMethod( - Invocation.setter(#resamplingEnabled, _resamplingEnabled), - returnValueForMissingStub: null); - - @override - Duration get samplingOffset => - (super.noSuchMethod(Invocation.getter(#samplingOffset), - returnValue: _FakeDuration_0()) as Duration); - - @override - set samplingOffset(Duration? _samplingOffset) => - super.noSuchMethod(Invocation.setter(#samplingOffset, _samplingOffset), - returnValueForMissingStub: null); - - @override - _i7.MouseTracker get mouseTracker => - (super.noSuchMethod(Invocation.getter(#mouseTracker), - returnValue: _FakeMouseTracker_12()) as _i7.MouseTracker); - - @override - _i7.PipelineOwner get pipelineOwner => - (super.noSuchMethod(Invocation.getter(#pipelineOwner), - returnValue: _FakePipelineOwner_13()) as _i7.PipelineOwner); - - @override - _i7.RenderView get renderView => - (super.noSuchMethod(Invocation.getter(#renderView), - returnValue: _FakeRenderView_14()) as _i7.RenderView); - - @override - set renderView(_i7.RenderView? value) => - super.noSuchMethod(Invocation.setter(#renderView, value), - returnValueForMissingStub: null); - - @override - bool get sendFramesToEngine => - (super.noSuchMethod(Invocation.getter(#sendFramesToEngine), - returnValue: false) as bool); - - @override - _i4.AccessibilityFeatures get accessibilityFeatures => - (super.noSuchMethod(Invocation.getter(#accessibilityFeatures), - returnValue: _FakeAccessibilityFeatures_15()) - as _i4.AccessibilityFeatures); - - @override - bool get disableAnimations => - (super.noSuchMethod(Invocation.getter(#disableAnimations), - returnValue: false) as bool); - - @override - void initInstances() => - super.noSuchMethod(Invocation.method(#initInstances, []), - returnValueForMissingStub: null); - - @override - void initServiceExtensions() => - super.noSuchMethod(Invocation.method(#initServiceExtensions, []), - returnValueForMissingStub: null); - - @override - void addObserver(_i10.WidgetsBindingObserver? observer) => - super.noSuchMethod(Invocation.method(#addObserver, [observer]), - returnValueForMissingStub: null); - - @override - bool removeObserver(_i10.WidgetsBindingObserver? observer) => - (super.noSuchMethod(Invocation.method(#removeObserver, [observer]), - returnValue: false) as bool); - - @override - void handleMetricsChanged() => - super.noSuchMethod(Invocation.method(#handleMetricsChanged, []), - returnValueForMissingStub: null); - - @override - void handleTextScaleFactorChanged() => - super.noSuchMethod(Invocation.method(#handleTextScaleFactorChanged, []), - returnValueForMissingStub: null); - - @override - void handlePlatformBrightnessChanged() => super.noSuchMethod( - Invocation.method(#handlePlatformBrightnessChanged, []), - returnValueForMissingStub: null); - - @override - void handleAccessibilityFeaturesChanged() => super.noSuchMethod( - Invocation.method(#handleAccessibilityFeaturesChanged, []), - returnValueForMissingStub: null); - - @override - void handleLocaleChanged() => - super.noSuchMethod(Invocation.method(#handleLocaleChanged, []), - returnValueForMissingStub: null); - - @override - void dispatchLocalesChanged(List<_i4.Locale>? locales) => - super.noSuchMethod(Invocation.method(#dispatchLocalesChanged, [locales]), - returnValueForMissingStub: null); - - @override - void dispatchAccessibilityFeaturesChanged() => super.noSuchMethod( - Invocation.method(#dispatchAccessibilityFeaturesChanged, []), - returnValueForMissingStub: null); - - @override - _i9.Future handlePopRoute() => - (super.noSuchMethod(Invocation.method(#handlePopRoute, []), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - - @override - _i9.Future handlePushRoute(String? route) => - (super.noSuchMethod(Invocation.method(#handlePushRoute, [route]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - - @override - void handleAppLifecycleStateChanged(_i4.AppLifecycleState? state) => super - .noSuchMethod(Invocation.method(#handleAppLifecycleStateChanged, [state]), - returnValueForMissingStub: null); - - @override - void handleMemoryPressure() => - super.noSuchMethod(Invocation.method(#handleMemoryPressure, []), - returnValueForMissingStub: null); - - @override - void drawFrame() => super.noSuchMethod(Invocation.method(#drawFrame, []), - returnValueForMissingStub: null); - - @override - void scheduleAttachRootWidget(_i12.Widget? rootWidget) => super.noSuchMethod( - Invocation.method(#scheduleAttachRootWidget, [rootWidget]), - returnValueForMissingStub: null); - - @override - void attachRootWidget(_i12.Widget? rootWidget) => - super.noSuchMethod(Invocation.method(#attachRootWidget, [rootWidget]), - returnValueForMissingStub: null); - - @override - _i9.Future performReassemble() => - (super.noSuchMethod(Invocation.method(#performReassemble, []), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - - @override - _i4.Locale? computePlatformResolvedLocale( - List<_i4.Locale>? supportedLocales) => - (super.noSuchMethod(Invocation.method( - #computePlatformResolvedLocale, [supportedLocales])) as _i4.Locale?); - - @override - _i9.Future lockEvents(_i9.Future Function()? callback) => - (super.noSuchMethod(Invocation.method(#lockEvents, [callback]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - - @override - void unlocked() => super.noSuchMethod(Invocation.method(#unlocked, []), - returnValueForMissingStub: null); - - @override - _i9.Future reassembleApplication() => - (super.noSuchMethod(Invocation.method(#reassembleApplication, []), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - - @override - void registerSignalServiceExtension( - {String? name, _i3.AsyncCallback? callback}) => - super.noSuchMethod( - Invocation.method(#registerSignalServiceExtension, [], - {#name: name, #callback: callback}), - returnValueForMissingStub: null); - - @override - void registerBoolServiceExtension( - {String? name, - _i3.AsyncValueGetter? getter, - _i3.AsyncValueSetter? setter}) => - super.noSuchMethod( - Invocation.method(#registerBoolServiceExtension, [], - {#name: name, #getter: getter, #setter: setter}), - returnValueForMissingStub: null); - - @override - void registerNumericServiceExtension( - {String? name, - _i3.AsyncValueGetter? getter, - _i3.AsyncValueSetter? setter}) => - super.noSuchMethod( - Invocation.method(#registerNumericServiceExtension, [], - {#name: name, #getter: getter, #setter: setter}), - returnValueForMissingStub: null); - - @override - void postEvent(String? eventKind, Map? eventData) => - super.noSuchMethod(Invocation.method(#postEvent, [eventKind, eventData]), - returnValueForMissingStub: null); - - @override - void registerStringServiceExtension( - {String? name, - _i3.AsyncValueGetter? getter, - _i3.AsyncValueSetter? setter}) => - super.noSuchMethod( - Invocation.method(#registerStringServiceExtension, [], - {#name: name, #getter: getter, #setter: setter}), - returnValueForMissingStub: null); - - @override - void registerServiceExtension( - {String? name, _i3.ServiceExtensionCallback? callback}) => - super.noSuchMethod( - Invocation.method(#registerServiceExtension, [], - {#name: name, #callback: callback}), - returnValueForMissingStub: null); - - @override - _i5.BinaryMessenger createBinaryMessenger() => - (super.noSuchMethod(Invocation.method(#createBinaryMessenger, []), - returnValue: _FakeBinaryMessenger_6()) as _i5.BinaryMessenger); - - @override - _i9.Future handleSystemMessage(Object? systemMessage) => (super - .noSuchMethod(Invocation.method(#handleSystemMessage, [systemMessage]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - - @override - void initLicenses() => - super.noSuchMethod(Invocation.method(#initLicenses, []), - returnValueForMissingStub: null); - - @override - void evict(String? asset) => - super.noSuchMethod(Invocation.method(#evict, [asset]), - returnValueForMissingStub: null); - - @override - void readInitialLifecycleStateFromNativeWindow() => super.noSuchMethod( - Invocation.method(#readInitialLifecycleStateFromNativeWindow, []), - returnValueForMissingStub: null); - - @override - _i5.RestorationManager createRestorationManager() => - (super.noSuchMethod(Invocation.method(#createRestorationManager, []), - returnValue: _FakeRestorationManager_8()) as _i5.RestorationManager); - - @override - void setSystemUiChangeCallback(_i5.SystemUiChangeCallback? callback) => super - .noSuchMethod(Invocation.method(#setSystemUiChangeCallback, [callback]), - returnValueForMissingStub: null); - - @override - void addTimingsCallback(_i4.TimingsCallback? callback) => - super.noSuchMethod(Invocation.method(#addTimingsCallback, [callback]), - returnValueForMissingStub: null); - - @override - void removeTimingsCallback(_i4.TimingsCallback? callback) => - super.noSuchMethod(Invocation.method(#removeTimingsCallback, [callback]), - returnValueForMissingStub: null); - - @override - _i9.Future scheduleTask( - _i11.TaskCallback? task, _i11.Priority? priority, - {String? debugLabel, _i13.Flow? flow}) => - (super.noSuchMethod( - Invocation.method(#scheduleTask, [task, priority], - {#debugLabel: debugLabel, #flow: flow}), - returnValue: Future.value(null)) as _i9.Future); - - @override - bool handleEventLoopCallback() => - (super.noSuchMethod(Invocation.method(#handleEventLoopCallback, []), - returnValue: false) as bool); - - @override - int scheduleFrameCallback(_i11.FrameCallback? callback, - {bool? rescheduling = false}) => - (super.noSuchMethod( - Invocation.method(#scheduleFrameCallback, [callback], - {#rescheduling: rescheduling}), - returnValue: 0) as int); - - @override - void cancelFrameCallbackWithId(int? id) => - super.noSuchMethod(Invocation.method(#cancelFrameCallbackWithId, [id]), - returnValueForMissingStub: null); - - @override - bool debugAssertNoTransientCallbacks(String? reason) => (super.noSuchMethod( - Invocation.method(#debugAssertNoTransientCallbacks, [reason]), - returnValue: false) as bool); - - @override - void addPersistentFrameCallback(_i11.FrameCallback? callback) => super - .noSuchMethod(Invocation.method(#addPersistentFrameCallback, [callback]), - returnValueForMissingStub: null); - - @override - void addPostFrameCallback(_i11.FrameCallback? callback) => - super.noSuchMethod(Invocation.method(#addPostFrameCallback, [callback]), - returnValueForMissingStub: null); - - @override - void ensureFrameCallbacksRegistered() => - super.noSuchMethod(Invocation.method(#ensureFrameCallbacksRegistered, []), - returnValueForMissingStub: null); - - @override - void ensureVisualUpdate() => - super.noSuchMethod(Invocation.method(#ensureVisualUpdate, []), - returnValueForMissingStub: null); - - @override - void scheduleFrame() => - super.noSuchMethod(Invocation.method(#scheduleFrame, []), - returnValueForMissingStub: null); - - @override - void scheduleForcedFrame() => - super.noSuchMethod(Invocation.method(#scheduleForcedFrame, []), - returnValueForMissingStub: null); - - @override - void scheduleWarmUpFrame() => - super.noSuchMethod(Invocation.method(#scheduleWarmUpFrame, []), - returnValueForMissingStub: null); - - @override - void resetEpoch() => super.noSuchMethod(Invocation.method(#resetEpoch, []), - returnValueForMissingStub: null); - - @override - void handleBeginFrame(Duration? rawTimeStamp) => - super.noSuchMethod(Invocation.method(#handleBeginFrame, [rawTimeStamp]), - returnValueForMissingStub: null); - - @override - void handleDrawFrame() => - super.noSuchMethod(Invocation.method(#handleDrawFrame, []), - returnValueForMissingStub: null); - - @override - void cancelPointer(int? pointer) => - super.noSuchMethod(Invocation.method(#cancelPointer, [pointer]), - returnValueForMissingStub: null); - - @override - void handlePointerEvent(_i7.PointerEvent? event) => - super.noSuchMethod(Invocation.method(#handlePointerEvent, [event]), - returnValueForMissingStub: null); - - @override - void hitTest(_i7.HitTestResult? result, _i4.Offset? position) => - super.noSuchMethod(Invocation.method(#hitTest, [result, position]), - returnValueForMissingStub: null); - - @override - void dispatchEvent( - _i7.PointerEvent? event, _i7.HitTestResult? hitTestResult) => - super.noSuchMethod( - Invocation.method(#dispatchEvent, [event, hitTestResult]), - returnValueForMissingStub: null); - - @override - void handleEvent(_i7.PointerEvent? event, _i7.HitTestEntry? entry) => - super.noSuchMethod(Invocation.method(#handleEvent, [event, entry]), - returnValueForMissingStub: null); - - @override - void resetGestureBinding() => - super.noSuchMethod(Invocation.method(#resetGestureBinding, []), - returnValueForMissingStub: null); - - @override - void initRenderView() => - super.noSuchMethod(Invocation.method(#initRenderView, []), - returnValueForMissingStub: null); - - @override - _i7.ViewConfiguration createViewConfiguration() => - (super.noSuchMethod(Invocation.method(#createViewConfiguration, []), - returnValue: _FakeViewConfiguration_16()) as _i7.ViewConfiguration); - - @override - void initMouseTracker([_i7.MouseTracker? tracker]) => - super.noSuchMethod(Invocation.method(#initMouseTracker, [tracker]), - returnValueForMissingStub: null); - - @override - void setSemanticsEnabled(bool? enabled) => - super.noSuchMethod(Invocation.method(#setSemanticsEnabled, [enabled]), - returnValueForMissingStub: null); - - @override - void deferFirstFrame() => - super.noSuchMethod(Invocation.method(#deferFirstFrame, []), - returnValueForMissingStub: null); - - @override - void allowFirstFrame() => - super.noSuchMethod(Invocation.method(#allowFirstFrame, []), - returnValueForMissingStub: null); - - @override - void resetFirstFrameSent() => - super.noSuchMethod(Invocation.method(#resetFirstFrameSent, []), - returnValueForMissingStub: null); - - @override - _i4.SemanticsUpdateBuilder createSemanticsUpdateBuilder() => - (super.noSuchMethod(Invocation.method(#createSemanticsUpdateBuilder, []), - returnValue: _FakeSemanticsUpdateBuilder_17()) - as _i4.SemanticsUpdateBuilder); -} From 7a2ca1112031571e51737f5de194856810b56de0 Mon Sep 17 00:00:00 2001 From: Andrew Amin Date: Mon, 30 Jun 2025 18:02:31 +0300 Subject: [PATCH 12/84] chore: fix some capture logic, add unit test cases. --- android/build.gradle | 4 +- example/ios/Podfile.lock | 2 +- example/ios/Runner.xcodeproj/project.pbxproj | 2 +- .../xcshareddata/xcschemes/Runner.xcscheme | 2 +- example/lib/main.dart | 4 +- example/lib/src/components/apm_switch.dart | 26 +- .../src/components/screen_render_switch.dart | 35 +++ example/lib/src/screens/apm_page.dart | 2 +- .../lib/src/screens/screen_render_page.dart | 7 + example/pubspec.lock | 189 +++++++------ ios/Classes/Modules/ApmApi.m | 5 +- lib/src/modules/apm.dart | 10 +- .../utils/instabug_navigator_observer.dart | 3 + .../instabug_screen_render_manager.dart | 263 ++++++++++-------- .../instabug_widget_binding_observer.dart | 39 +-- test/apm_test.dart | 115 ++++++++ 16 files changed, 478 insertions(+), 230 deletions(-) create mode 100644 example/lib/src/components/screen_render_switch.dart diff --git a/android/build.gradle b/android/build.gradle index 0a1bab7ea..8767af259 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -1,5 +1,3 @@ -package android - group 'com.instabug.flutter' version '14.3.0' @@ -54,7 +52,7 @@ android { } dependencies { - api 'com.instabug.library:instabug:14.3.0' + api 'com.instabug.library:instabug:15.0.0.6897042-SNAPSHOT' testImplementation 'junit:junit:4.13.2' testImplementation "org.mockito:mockito-inline:3.12.1" testImplementation "io.mockk:mockk:1.13.13" diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index 7fcc59514..8dad08077 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -25,7 +25,7 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/instabug_flutter/ios" SPEC CHECKSUMS: - Flutter: 50d75fe2f02b26cc09d224853bb45737f8b3214a + Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 Instabug: a2b8c384cd4af7a01ab43b2ce2957a880f8862d7 instabug_flutter: 6ee721f30066123a769da64b687eded6eb4ff125 OCMock: 5ea90566be239f179ba766fd9fbae5885040b992 diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj index 2d4497cb9..d32f983fc 100644 --- a/example/ios/Runner.xcodeproj/project.pbxproj +++ b/example/ios/Runner.xcodeproj/project.pbxproj @@ -271,7 +271,7 @@ 97C146E61CF9000F007C117D /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1300; + LastUpgradeCheck = 1510; ORGANIZATIONNAME = ""; TargetAttributes = { 97C146ED1CF9000F007C117D = { diff --git a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index b7206827b..3264af370 100644 --- a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ { @override Widget build(BuildContext context) { - return Column( - children: [ - SwitchListTile.adaptive( - title: const Text('APM Enabled'), - value: isEnabled, - onChanged: (value) => onAPMChanged(context, value), - ), - ], - ); + return FutureBuilder( + future: APM.isEnabled(), + builder: (context, snapshot) { + if (snapshot.hasData) { + isEnabled = snapshot.data ?? false; + return SwitchListTile.adaptive( + title: const Text('APM Enabled'), + value: isEnabled, + onChanged: (value) => onAPMChanged(context, value), + ); + } + return const SizedBox.shrink(); + }); } void onAPMChanged(BuildContext context, bool value) { diff --git a/example/lib/src/components/screen_render_switch.dart b/example/lib/src/components/screen_render_switch.dart new file mode 100644 index 000000000..d5c6d9e18 --- /dev/null +++ b/example/lib/src/components/screen_render_switch.dart @@ -0,0 +1,35 @@ +part of '../../main.dart'; + +class ScreenRenderSwitch extends StatefulWidget { + const ScreenRenderSwitch({Key? key}) : super(key: key); + + @override + State createState() => _ScreenRenderSwitchState(); +} + +class _ScreenRenderSwitchState extends State { + bool isEnabled = false; + + @override + Widget build(BuildContext context) { + return FutureBuilder( + future: APM.isScreenRenderEnabled(), + builder: (context, snapshot) { + if (snapshot.hasData) { + isEnabled = snapshot.data ?? false; + return SwitchListTile.adaptive( + title: const Text('Screen Render Enabled'), + value: isEnabled, + onChanged: (value) => onScreenRenderChanged(context, value), + ); + } + return const SizedBox.shrink(); + }); + } + + void onScreenRenderChanged(BuildContext context, bool value) { + APM.setScreenRenderEnabled(value); + showSnackBar(context, "Screen Render is ${value ? "enabled" : "disabled"}"); + setState(() => isEnabled = value); + } +} diff --git a/example/lib/src/screens/apm_page.dart b/example/lib/src/screens/apm_page.dart index 0dcf90a2c..b5de7a228 100644 --- a/example/lib/src/screens/apm_page.dart +++ b/example/lib/src/screens/apm_page.dart @@ -53,7 +53,7 @@ class _ApmPageState extends State { SizedBox.fromSize( size: const Size.fromHeight(12), ), - ScreenRender(), + const ScreenRender(), ], ); } diff --git a/example/lib/src/screens/screen_render_page.dart b/example/lib/src/screens/screen_render_page.dart index a6c97cb23..872435f99 100644 --- a/example/lib/src/screens/screen_render_page.dart +++ b/example/lib/src/screens/screen_render_page.dart @@ -11,9 +11,16 @@ class ScreenRenderPage extends StatefulWidget { class _ScreenRenderPageState extends State { final durationController = TextEditingController(); + @override + void dispose() { + durationController.dispose(); + super.dispose(); + } + @override Widget build(BuildContext context) { return Page(title: 'Screen Render', children: [ + const ScreenRenderSwitch(), SizedBox.fromSize(size: const Size.fromHeight(16.0)), const AnimatedBox(), SizedBox.fromSize( diff --git a/example/pubspec.lock b/example/pubspec.lock index db618bb81..74b4b6b46 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -1,76 +1,62 @@ # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: - archive: - dependency: transitive - description: - name: archive - url: "https://pub.dartlang.org" - source: hosted - version: "3.1.6" async: dependency: transitive description: name: async - url: "https://pub.dartlang.org" + sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb" + url: "https://pub.dev" source: hosted - version: "2.8.2" + version: "2.13.0" boolean_selector: dependency: transitive description: name: boolean_selector - url: "https://pub.dartlang.org" + sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.2" characters: dependency: transitive description: name: characters - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.0" - charcode: - dependency: transitive - description: - name: charcode - url: "https://pub.dartlang.org" + sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 + url: "https://pub.dev" source: hosted - version: "1.3.1" + version: "1.4.0" clock: dependency: transitive description: name: clock - url: "https://pub.dartlang.org" + sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b + url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.1.2" collection: dependency: transitive description: name: collection - url: "https://pub.dartlang.org" + sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" + url: "https://pub.dev" source: hosted - version: "1.15.0" - crypto: - dependency: transitive - description: - name: crypto - url: "https://pub.dartlang.org" - source: hosted - version: "3.0.1" + version: "1.19.1" fake_async: dependency: transitive description: name: fake_async - url: "https://pub.dartlang.org" + sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" + url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.3.3" file: dependency: transitive description: name: file - url: "https://pub.dartlang.org" + sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 + url: "https://pub.dev" source: hosted - version: "6.1.2" + version: "7.0.1" flutter: dependency: "direct main" description: flutter @@ -85,7 +71,8 @@ packages: dependency: "direct dev" description: name: flutter_lints - url: "https://pub.dartlang.org" + sha256: b543301ad291598523947dc534aaddc5aaad597b709d2426d3a0e0d44c5cb493 + url: "https://pub.dev" source: hosted version: "1.0.4" flutter_test: @@ -102,16 +89,18 @@ packages: dependency: "direct main" description: name: http - url: "https://pub.dartlang.org" + sha256: "5895291c13fa8a3bd82e76d5627f69e0d85ca6a30dcac95c4ea19a5d555879c2" + url: "https://pub.dev" source: hosted - version: "0.13.5" + version: "0.13.6" http_parser: dependency: transitive description: name: http_parser - url: "https://pub.dartlang.org" + sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571" + url: "https://pub.dev" source: hosted - version: "4.0.2" + version: "4.1.2" instabug_flutter: dependency: "direct main" description: @@ -123,139 +112,183 @@ packages: dependency: "direct main" description: name: instabug_http_client - url: "https://pub.dartlang.org" + sha256: "97a6ab88491eff87e42437564b528d6986a65eb3f3262f73373009f949cb4560" + url: "https://pub.dev" source: hosted version: "2.5.1" + leak_tracker: + dependency: transitive + description: + name: leak_tracker + sha256: "6bb818ecbdffe216e81182c2f0714a2e62b593f4a4f13098713ff1685dfb6ab0" + url: "https://pub.dev" + source: hosted + version: "10.0.9" + leak_tracker_flutter_testing: + dependency: transitive + description: + name: leak_tracker_flutter_testing + sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573 + url: "https://pub.dev" + source: hosted + version: "3.0.9" + leak_tracker_testing: + dependency: transitive + description: + name: leak_tracker_testing + sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" + url: "https://pub.dev" + source: hosted + version: "3.0.1" lints: dependency: transitive description: name: lints - url: "https://pub.dartlang.org" + sha256: a2c3d198cb5ea2e179926622d433331d8b58374ab8f29cdda6e863bd62fd369c + url: "https://pub.dev" source: hosted version: "1.0.1" matcher: dependency: transitive description: name: matcher - url: "https://pub.dartlang.org" + sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 + url: "https://pub.dev" source: hosted - version: "0.12.11" + version: "0.12.17" material_color_utilities: dependency: transitive description: name: material_color_utilities - url: "https://pub.dartlang.org" + sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec + url: "https://pub.dev" source: hosted - version: "0.1.3" + version: "0.11.1" meta: dependency: transitive description: name: meta - url: "https://pub.dartlang.org" + sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c + url: "https://pub.dev" source: hosted - version: "1.7.0" + version: "1.16.0" path: dependency: transitive description: name: path - url: "https://pub.dartlang.org" + sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" + url: "https://pub.dev" source: hosted - version: "1.8.0" + version: "1.9.1" platform: dependency: transitive description: name: platform - url: "https://pub.dartlang.org" + sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984" + url: "https://pub.dev" source: hosted - version: "3.1.0" + version: "3.1.6" process: dependency: transitive description: name: process - url: "https://pub.dartlang.org" + sha256: "107d8be718f120bbba9dcd1e95e3bd325b1b4a4f07db64154635ba03f2567a0d" + url: "https://pub.dev" source: hosted - version: "4.2.4" + version: "5.0.3" sky_engine: dependency: transitive description: flutter source: sdk - version: "0.0.99" + version: "0.0.0" source_span: dependency: transitive description: name: source_span - url: "https://pub.dartlang.org" + sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c" + url: "https://pub.dev" source: hosted - version: "1.8.1" + version: "1.10.1" stack_trace: dependency: transitive description: name: stack_trace - url: "https://pub.dartlang.org" + sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" + url: "https://pub.dev" source: hosted - version: "1.10.0" + version: "1.12.1" stream_channel: dependency: transitive description: name: stream_channel - url: "https://pub.dartlang.org" + sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.4" string_scanner: dependency: transitive description: name: string_scanner - url: "https://pub.dartlang.org" + sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" + url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.4.1" sync_http: dependency: transitive description: name: sync_http - url: "https://pub.dartlang.org" + sha256: "7f0cd72eca000d2e026bcd6f990b81d0ca06022ef4e32fb257b30d3d1014a961" + url: "https://pub.dev" source: hosted - version: "0.3.0" + version: "0.3.1" term_glyph: dependency: transitive description: name: term_glyph - url: "https://pub.dartlang.org" + sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" + url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.2.2" test_api: dependency: transitive description: name: test_api - url: "https://pub.dartlang.org" + sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd + url: "https://pub.dev" source: hosted - version: "0.4.8" + version: "0.7.4" typed_data: dependency: transitive description: name: typed_data - url: "https://pub.dartlang.org" + sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 + url: "https://pub.dev" source: hosted - version: "1.3.0" + version: "1.4.0" vector_math: dependency: transitive description: name: vector_math - url: "https://pub.dartlang.org" + sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.4" vm_service: dependency: transitive description: name: vm_service - url: "https://pub.dartlang.org" + sha256: ddfa8d30d89985b96407efce8acbdd124701f96741f2d981ca860662f1c0dc02 + url: "https://pub.dev" source: hosted - version: "7.5.0" + version: "15.0.0" webdriver: dependency: transitive description: name: webdriver - url: "https://pub.dartlang.org" + sha256: "2f3a14ca026957870cfd9c635b83507e0e51d8091568e90129fbf805aba7cade" + url: "https://pub.dev" source: hosted - version: "3.0.0" + version: "3.1.0" sdks: - dart: ">=2.14.0 <3.0.0" + dart: ">=3.7.0-0 <4.0.0" + flutter: ">=3.18.0-18.0.pre.54" diff --git a/ios/Classes/Modules/ApmApi.m b/ios/Classes/Modules/ApmApi.m index 385936702..f82219770 100644 --- a/ios/Classes/Modules/ApmApi.m +++ b/ios/Classes/Modules/ApmApi.m @@ -215,7 +215,7 @@ - (void)deviceRefreshRateWithCompletion:(void (^)(NSNumber * _Nullable, FlutterE displayLink.paused = YES; [displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes]; - NSInteger preferredFPS = displayLink.preferredFramesPerSecond; + double preferredFPS = displayLink.preferredFramesPerSecond; [displayLink invalidate]; @@ -237,7 +237,8 @@ - (void)deviceRefreshRateWithCompletion:(void (^)(NSNumber * _Nullable, FlutterE } if (windowScene) { - completion(@(windowScene.screen.maximumFramesPerSecond) , nil); + double preferredFPS = windowScene.screen.maximumFramesPerSecond; + completion(@(preferredFPS) , nil); return; } } diff --git a/lib/src/modules/apm.dart b/lib/src/modules/apm.dart index 4077d65f2..7d4ef9804 100644 --- a/lib/src/modules/apm.dart +++ b/lib/src/modules/apm.dart @@ -2,7 +2,7 @@ import 'dart:async'; -import 'package:flutter/widgets.dart' show WidgetBuilder; +import 'package:flutter/widgets.dart' show WidgetBuilder, WidgetsBinding; import 'package:instabug_flutter/src/generated/apm.api.g.dart'; import 'package:instabug_flutter/src/models/network_data.dart'; import 'package:instabug_flutter/src/models/trace.dart'; @@ -392,6 +392,12 @@ class APM { /// Returns: /// A Future is being returned. static Future setScreenRenderEnabled(bool isEnabled) { - return _host.setScreenRenderEnabled(isEnabled); + return _host.setScreenRenderEnabled(isEnabled).then((_) { + if (isEnabled) { + InstabugScreenRenderManager.I.init(WidgetsBinding.instance); + } else { + InstabugScreenRenderManager.I.remove(); + } + }); } } diff --git a/lib/src/utils/instabug_navigator_observer.dart b/lib/src/utils/instabug_navigator_observer.dart index 80b4cb13d..63dc31dad 100644 --- a/lib/src/utils/instabug_navigator_observer.dart +++ b/lib/src/utils/instabug_navigator_observer.dart @@ -61,6 +61,9 @@ class InstabugNavigatorObserver extends NavigatorObserver { InstabugScreenRenderManager.I .startScreenRenderCollectorForTraceId(uiTraceId); } + // if(isScreenRender && InstabugScreenRenderManager.I.screenRenderEnabled){ + // InstabugScreenRenderManager.I.remove(); + // } } @override diff --git a/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart b/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart index 50e16fbc5..526c2ddc3 100644 --- a/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart +++ b/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart @@ -1,3 +1,4 @@ +import 'dart:async'; import 'dart:developer'; import 'dart:ui'; @@ -5,6 +6,7 @@ import 'package:flutter/widgets.dart'; import 'package:instabug_flutter/src/models/instabug_frame_data.dart'; import 'package:instabug_flutter/src/models/instabug_screen_render_data.dart'; import 'package:instabug_flutter/src/modules/apm.dart'; +import 'package:instabug_flutter/src/utils/instabug_logger.dart'; import 'package:instabug_flutter/src/utils/screen_rendering/instabug_widget_binding_observer.dart'; import 'package:meta/meta.dart'; @@ -57,21 +59,21 @@ class InstabugScreenRenderManager { /// setup function for [InstabugScreenRenderManager] @internal Future init(WidgetsBinding? widgetBinding) async { - // passing WidgetsBinding? (nullable) for flutter versions prior than 3.x - if (!_isTimingsListenerAttached && widgetBinding != null) { - _widgetsBinding = widgetBinding; - _addWidgetBindingObserver(); - await _initStaticValues(); - _initFrameTimings(); - screenRenderEnabled = true; + try { + // passing WidgetsBinding? (nullable) for flutter versions prior than 3.x + if (!_isTimingsListenerAttached && widgetBinding != null) { + _widgetsBinding = widgetBinding; + _addWidgetBindingObserver(); + await _initStaticValues(); + _initFrameTimings(); + screenRenderEnabled = true; + } + log("$tag: init", name: 'andrew'); + } catch (error, stackTrace) { + _logExceptionErrorAndStackTrace(error, stackTrace); } } - /// nodoc - - void _addWidgetBindingObserver() => - _widgetsBinding.addObserver(InstabugWidgetsBindingObserver.instance); - /// analyze frame data in order to detect slow/frozen frame. @visibleForTesting void analyzeFrameTiming(FrameTiming frameTiming) { @@ -115,6 +117,128 @@ class InstabugScreenRenderManager { } } + /// Start collecting screen render data for the running [UITrace]. + /// It ends the running collector when starting a new one of the same type [UiTraceType]. + @internal + void startScreenRenderCollectorForTraceId( + int traceId, [ + UiTraceType type = UiTraceType.auto, + ]) { + try { + // Return if frameTimingListener not attached + if (!screenRenderEnabled || !_isTimingsListenerAttached) { + log("$tag: start returned", name: 'andrew'); + + return; + } + + //Save the memory cached data to be sent to native side + if (_delayedFrames.isNotEmpty) { + _saveCollectedData(); + _resetCachedFrameData(); + } + + //Sync the captured screen render data of the Custom UI trace when starting new one + if (type == UiTraceType.custom) { + if (_screenRenderForCustomUiTrace.isNotEmpty) { + reportScreenRending( + _screenRenderForCustomUiTrace, + UiTraceType.custom, + ); + _screenRenderForCustomUiTrace.clear(); + } + _screenRenderForCustomUiTrace.traceId = traceId; + } + + //Sync the captured screen render data of the Auto UI trace when starting new one + if (type == UiTraceType.auto) { + if (_screenRenderForAutoUiTrace.isNotEmpty) { + reportScreenRending(_screenRenderForAutoUiTrace); + _screenRenderForAutoUiTrace.clear(); + } + _screenRenderForAutoUiTrace.traceId = traceId; + } + log("$tag: start normally", name: 'andrew'); + } catch (error, stackTrace) { + _logExceptionErrorAndStackTrace(error, stackTrace); + } + } + + /// Stop screen render collector and sync the captured data. + @internal + void stopScreenRenderCollector() { + try { + if (_delayedFrames.isEmpty) { + return; + } // No delayed framed to be synced. + + _saveCollectedData(); + + if (_screenRenderForCustomUiTrace.isNotEmpty) { + reportScreenRending(_screenRenderForCustomUiTrace, UiTraceType.custom); + } + if (_screenRenderForAutoUiTrace.isNotEmpty) { + reportScreenRending(_screenRenderForAutoUiTrace); + } + + _removeFrameTimings(); + + _resetCachedFrameData(); + log("$tag: stop", name: 'andrew'); + } catch (error, stackTrace) { + _logExceptionErrorAndStackTrace(error, stackTrace); + } + } + + /// Sync the capture screen render data of the custom UI trace without stopping the collector. + @internal + void endScreenRenderCollectorForCustomUiTrace() { + try { + if (_screenRenderForCustomUiTrace.isEmpty) { + return; + } + + // Save the captured screen rendering data to be synced + _screenRenderForCustomUiTrace.slowFramesTotalDuration += + _slowFramesTotalDuration; + _screenRenderForCustomUiTrace.frozenFramesTotalDuration += + _frozenFramesTotalDuration; + _screenRenderForCustomUiTrace.frameData.addAll(_delayedFrames); + + // Sync the saved screen rendering data + reportScreenRending(_screenRenderForCustomUiTrace, UiTraceType.custom); + _screenRenderForCustomUiTrace.clear(); + log("$tag: endCustom", name: 'andrew'); + } catch (error, stackTrace) { + _logExceptionErrorAndStackTrace(error, stackTrace); + } + } + + @visibleForTesting + Future reportScreenRending( + InstabugScreenRenderData screenRenderData, [ + UiTraceType type = UiTraceType.auto, + ]) async { + if (type == UiTraceType.auto) { + _reportScreenRenderForAutoUiTrace(screenRenderData); + } else { + _reportScreenRenderForCustomUiTrace(screenRenderData); + } + log( + "$tag: Report ${type == UiTraceType.auto ? 'auto' : 'custom'} Data: $screenRenderData", + name: 'andrew', + ); + } + + void remove() { + _resetCachedFrameData(); + _removeFrameTimings(); + screenRenderEnabled = false; + log("$tag: remove", name: 'andrew'); + } + + /// --------------------------- private methods --------------------- + bool get _isSlow => _isUiSlow || _isRasterSlow; bool get _isUiDelayed => _isUiSlow || _isUiFrozen; @@ -142,11 +266,12 @@ class InstabugScreenRenderManager { 1 / displayRefreshRate * 1000; /// Get device refresh rate from native side. - Future get _getDeviceRefreshRateFromNative { - final rr = APM.getDeviceRefreshRate(); - log("refreshRateFromNative: $rr", name: "Andrew"); - return rr; - } + Future get _getDeviceRefreshRateFromNative => + APM.getDeviceRefreshRate(); + + /// add new [WidgetsBindingObserver] to track app lifecycle. + void _addWidgetBindingObserver() => + _widgetsBinding.addObserver(InstabugWidgetsBindingObserver.instance); /// Initialize the static variables Future _initStaticValues() async { @@ -178,79 +303,6 @@ class InstabugScreenRenderManager { _isTimingsListenerAttached = false; } - /// Start collecting screen render data for the running [UITrace]. - /// It ends the running collector when starting a new one of the same type [UiTraceType]. - @internal - void startScreenRenderCollectorForTraceId( - int traceId, [ - UiTraceType type = UiTraceType.auto, - ]) { - // Attach frameTimingListener if not attached - if (!_isTimingsListenerAttached) { - _initFrameTimings(); - } - - //Save the memory cached data to be sent to native side - if (_delayedFrames.isNotEmpty) { - _saveCollectedData(); - _resetCachedFrameData(); - } - - //Sync the captured screen render data of the Custom UI trace when starting new one - if (type == UiTraceType.custom) { - if (_screenRenderForCustomUiTrace.isNotEmpty) { - reportScreenRending(_screenRenderForCustomUiTrace, UiTraceType.custom); - _screenRenderForCustomUiTrace.clear(); - } - _screenRenderForCustomUiTrace.traceId = traceId; - } - - //Sync the captured screen render data of the Auto UI trace when starting new one - if (type == UiTraceType.auto) { - if (_screenRenderForAutoUiTrace.isNotEmpty) { - reportScreenRending(_screenRenderForAutoUiTrace); - _screenRenderForAutoUiTrace.clear(); - } - _screenRenderForAutoUiTrace.traceId = traceId; - } - } - - /// Stop screen render collector and sync the captured data. - @internal - void stopScreenRenderCollector() { - if (_delayedFrames.isEmpty) return; // No delayed framed to be synced. - - _saveCollectedData(); - - if (_screenRenderForCustomUiTrace.isNotEmpty) { - reportScreenRending(_screenRenderForCustomUiTrace, UiTraceType.custom); - } - if (_screenRenderForAutoUiTrace.isNotEmpty) { - reportScreenRending(_screenRenderForAutoUiTrace); - } - - _removeFrameTimings(); - - _resetCachedFrameData(); - } - - /// Sync the capture screen render data of the custom UI trace without stopping the collector. - @internal - void endScreenRenderCollectorForCustomUiTrace() { - if (_screenRenderForCustomUiTrace.isEmpty) return; - - // Save the captured screen rendering data to be synced - _screenRenderForCustomUiTrace.slowFramesTotalDuration += - _slowFramesTotalDuration; - _screenRenderForCustomUiTrace.frozenFramesTotalDuration += - _frozenFramesTotalDuration; - _screenRenderForCustomUiTrace.frameData.addAll(_delayedFrames); - - // Sync the saved screen rendering data - reportScreenRending(_screenRenderForCustomUiTrace, UiTraceType.custom); - _screenRenderForCustomUiTrace.clear(); - } - /// Reset the memory cashed data void _resetCachedFrameData() { _slowFramesTotalDuration = 0; @@ -302,32 +354,16 @@ class InstabugScreenRenderManager { } } - @visibleForTesting - Future reportScreenRending( - InstabugScreenRenderData screenRenderData, [ - UiTraceType type = UiTraceType.auto, - ]) async { - if (type == UiTraceType.auto) { - _reportScreenRenderForAutoUiTrace(screenRenderData); - } else { - _reportScreenRenderForCustomUiTrace(screenRenderData); - } - log( - "Reported Data (${type == UiTraceType.auto ? 'auto' : 'custom'}): $screenRenderData", - name: tag, - ); - } - Future _reportScreenRenderForCustomUiTrace( InstabugScreenRenderData screenRenderData, ) async { - //todo: Will be implemented in next sprint + //todo: Will be implemented in the next PR } Future _reportScreenRenderForAutoUiTrace( InstabugScreenRenderData screenRenderData, ) async { - //todo: Will be implemented in next sprint + //todo: Will be implemented in the next PR } /// Add the memory cashed data to the objects that will be synced asynchronously to the native side. @@ -348,7 +384,16 @@ class InstabugScreenRenderManager { } } - /// --------------------------- testing helper functions --------------------- + /// @nodoc + void _logExceptionErrorAndStackTrace(Object error, StackTrace stackTrace) { + InstabugLogger.I.e( + '[Error]:$error \n' + '[StackTrace]: $stackTrace', + tag: tag, + ); + } + + /// --------------------------- testing helper methods --------------------- @visibleForTesting InstabugScreenRenderManager.init(); diff --git a/lib/src/utils/screen_rendering/instabug_widget_binding_observer.dart b/lib/src/utils/screen_rendering/instabug_widget_binding_observer.dart index 6a92b51ce..f7e16f054 100644 --- a/lib/src/utils/screen_rendering/instabug_widget_binding_observer.dart +++ b/lib/src/utils/screen_rendering/instabug_widget_binding_observer.dart @@ -1,4 +1,5 @@ import 'dart:developer'; + import 'package:flutter/widgets.dart'; import 'package:instabug_flutter/src/utils/screen_loading/screen_loading_manager.dart'; import 'package:instabug_flutter/src/utils/screen_name_masker.dart'; @@ -22,32 +23,37 @@ class InstabugWidgetsBindingObserver extends WidgetsBindingObserver { static const tag = "InstabugWidgetsBindingObserver"; void _handleResumedState() { - log('Performing resume actions...'); + log('Performing resume actions...', name: 'andrew'); final lastUiTrace = ScreenLoadingManager.I.currentUiTrace; - if (lastUiTrace != null) { - final maskedScreenName = ScreenNameMasker.I.mask(lastUiTrace.screenName); - ScreenLoadingManager.I - .startUiTrace(maskedScreenName, lastUiTrace.screenName) - .then((uiTraceId) { - if (uiTraceId != null && - InstabugScreenRenderManager.I.screenRenderEnabled) { - InstabugScreenRenderManager.I - .startScreenRenderCollectorForTraceId(uiTraceId); - } - }); + if (lastUiTrace == null) { + return; } + final maskedScreenName = ScreenNameMasker.I.mask(lastUiTrace.screenName); + ScreenLoadingManager.I + .startUiTrace(maskedScreenName, lastUiTrace.screenName) + .then((uiTraceId) { + if (uiTraceId != null && + InstabugScreenRenderManager.I.screenRenderEnabled) { + InstabugScreenRenderManager.I + .startScreenRenderCollectorForTraceId(uiTraceId); + } + }); } void _handlePausedState() { - log('Performing pause actions...'); + log('Performing pause actions...', name: 'andrew'); InstabugScreenRenderManager.I.stopScreenRenderCollector(); } void _handleDetachedState() { - log('Performing detached actions...'); + log('Performing detached actions...', name: 'andrew'); InstabugScreenRenderManager.I.stopScreenRenderCollector(); } + void _handleDefaultState() { + log("handle default state", name: 'andrew'); + } + @override void didChangeAppLifecycleState(AppLifecycleState state) { switch (state) { @@ -64,11 +70,6 @@ class InstabugWidgetsBindingObserver extends WidgetsBindingObserver { _handleDefaultState(); } } - - void _handleDefaultState() { - //todo: will be implemented in next story - debugPrint("default"); - } } @internal diff --git a/test/apm_test.dart b/test/apm_test.dart index 4e8ec87a6..9f095f15d 100644 --- a/test/apm_test.dart +++ b/test/apm_test.dart @@ -4,6 +4,7 @@ import 'package:instabug_flutter/instabug_flutter.dart'; import 'package:instabug_flutter/src/generated/apm.api.g.dart'; import 'package:instabug_flutter/src/utils/ibg_build_info.dart'; import 'package:instabug_flutter/src/utils/ibg_date_time.dart'; +import 'package:instabug_flutter/src/utils/screen_rendering/instabug_screen_render_manager.dart'; import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; @@ -13,6 +14,7 @@ import 'apm_test.mocks.dart'; ApmHostApi, IBGDateTime, IBGBuildInfo, + InstabugScreenRenderManager, ]) void main() { TestWidgetsFlutterBinding.ensureInitialized(); @@ -21,6 +23,7 @@ void main() { final mHost = MockApmHostApi(); final mDateTime = MockIBGDateTime(); final mBuildInfo = MockIBGBuildInfo(); + final mScreenRenderManager = MockInstabugScreenRenderManager(); setUpAll(() { APM.$setHostApi(mHost); @@ -258,4 +261,116 @@ void main() { mHost.isEndScreenLoadingEnabled(), ).called(1); }); + + group("ScreenRender", () { + setUp(() { + InstabugScreenRenderManager.setInstance(mScreenRenderManager); + }); + tearDown((){ + reset(mScreenRenderManager); + }); + test("[isScreenRenderEnabled] should call host method", () async { + when(mHost.isScreenRenderEnabled()).thenAnswer((_) async => true); + await APM.isScreenRenderEnabled(); + verify(mHost.isScreenRenderEnabled()); + }); + + test("[getDeviceRefreshRate] should call host method", () async { + when(mHost.deviceRefreshRate()).thenAnswer((_) async => 60.0); + await APM.getDeviceRefreshRate(); + verify(mHost.deviceRefreshRate()).called(1); + }); + + test("[setScreenRenderEnabled] should call host method", () async { + const isEnabled = false; + await APM.setScreenRenderEnabled(isEnabled); + verify(mHost.setScreenRenderEnabled(isEnabled)).called(1); + }); + + test("[setScreenRenderEnabled] should call [init()] screen render collector, is the feature is enabled", () async { + const isEnabled = true; + await APM.setScreenRenderEnabled(isEnabled); + verify(mScreenRenderManager.init(any)).called(1); + verifyNoMoreInteractions(mScreenRenderManager); + }); + + test("[setScreenRenderEnabled] should call [remove()] screen render collector, is the feature is enabled", () async { + const isEnabled = false; + await APM.setScreenRenderEnabled(isEnabled); + verify(mScreenRenderManager.remove()).called(1); + verifyNoMoreInteractions(mScreenRenderManager); + }); + + + + test( + "[startUITrace] should start screen render collector with right params, if screen render feature is enabled", + () async { + when(mHost.isScreenRenderEnabled()).thenAnswer((_) async => true); + + const traceName = "traceNameTest"; + await APM.startUITrace(traceName); + + verify(mHost.startUITrace(traceName)).called(1); + verify(mHost.isScreenRenderEnabled()).called(1); + verify( + mScreenRenderManager.startScreenRenderCollectorForTraceId( + 0, + UiTraceType.custom, + ), + ).called(1); + }); + + test( + "[startUITrace] should not start screen render collector, if screen render feature is disabled", + () async { + when(mHost.isScreenRenderEnabled()).thenAnswer((_) async => false); + + const traceName = "traceNameTest"; + await APM.startUITrace(traceName); + + verify(mHost.startUITrace(traceName)).called(1); + verify(mHost.isScreenRenderEnabled()).called(1); + verifyNever( + mScreenRenderManager.startScreenRenderCollectorForTraceId( + any, + any, + ), + ); + }); + + test( + "[endUITrace] should stop screen render collector with, if screen render feature is enabled", + () async { + when(mHost.isScreenRenderEnabled()).thenAnswer((_) async => true); + + const traceName = "traceNameTest"; + await APM.startUITrace(traceName); + await APM.endUITrace(); + + verify(mHost.startUITrace(traceName)).called(1); + verify( + mScreenRenderManager.endScreenRenderCollectorForCustomUiTrace(), + ).called(1); + verifyNever(mHost.endUITrace()); + }); + + test( + "[endUITrace] should acts as normal and do nothing related to screen render, if screen render feature is disabled", + () async { + when(mHost.isScreenRenderEnabled()).thenAnswer((_) async => false); + + const traceName = "traceNameTest"; + await APM.startUITrace(traceName); + await APM.endUITrace(); + + verify(mHost.startUITrace(traceName)).called(1); + verify( + mHost.endUITrace(), + ).called(1); + verifyNever( + mScreenRenderManager.endScreenRenderCollectorForCustomUiTrace(), + ); + }); + }); } From b804d45df3a222824762a02ef136b53623f08451 Mon Sep 17 00:00:00 2001 From: Andrew Amin Date: Mon, 30 Jun 2025 23:33:03 +0300 Subject: [PATCH 13/84] chore: merge screen_render_native_apis branch --- test/apm_test.dart | 12 +- .../instabug_screen_render_manager_test.dart | 9 +- ...reen_render_manager_test_manual_mocks.dart | 2140 +++++++++++++++++ 3 files changed, 2148 insertions(+), 13 deletions(-) create mode 100644 test/utils/screen_render/instabug_screen_render_manager_test_manual_mocks.dart diff --git a/test/apm_test.dart b/test/apm_test.dart index 9f095f15d..0e02cd48e 100644 --- a/test/apm_test.dart +++ b/test/apm_test.dart @@ -266,7 +266,7 @@ void main() { setUp(() { InstabugScreenRenderManager.setInstance(mScreenRenderManager); }); - tearDown((){ + tearDown(() { reset(mScreenRenderManager); }); test("[isScreenRenderEnabled] should call host method", () async { @@ -287,22 +287,24 @@ void main() { verify(mHost.setScreenRenderEnabled(isEnabled)).called(1); }); - test("[setScreenRenderEnabled] should call [init()] screen render collector, is the feature is enabled", () async { + test( + "[setScreenRenderEnabled] should call [init()] screen render collector, is the feature is enabled", + () async { const isEnabled = true; await APM.setScreenRenderEnabled(isEnabled); verify(mScreenRenderManager.init(any)).called(1); verifyNoMoreInteractions(mScreenRenderManager); }); - test("[setScreenRenderEnabled] should call [remove()] screen render collector, is the feature is enabled", () async { + test( + "[setScreenRenderEnabled] should call [remove()] screen render collector, is the feature is enabled", + () async { const isEnabled = false; await APM.setScreenRenderEnabled(isEnabled); verify(mScreenRenderManager.remove()).called(1); verifyNoMoreInteractions(mScreenRenderManager); }); - - test( "[startUITrace] should start screen render collector with right params, if screen render feature is enabled", () async { diff --git a/test/utils/screen_render/instabug_screen_render_manager_test.dart b/test/utils/screen_render/instabug_screen_render_manager_test.dart index 73fea5561..deb227462 100644 --- a/test/utils/screen_render/instabug_screen_render_manager_test.dart +++ b/test/utils/screen_render/instabug_screen_render_manager_test.dart @@ -1,19 +1,12 @@ -import 'dart:ui'; - -import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:instabug_flutter/instabug_flutter.dart'; -import 'package:instabug_flutter/src/generated/apm.api.g.dart'; import 'package:instabug_flutter/src/models/instabug_frame_data.dart'; import 'package:instabug_flutter/src/models/instabug_screen_render_data.dart'; import 'package:instabug_flutter/src/utils/screen_rendering/instabug_screen_render_manager.dart'; -import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; -import 'instabug_screen_render_manager_test.mocks.dart'; -// import 'instabug_screen_render_manager_test_manual_mocks.dart'; +import 'instabug_screen_render_manager_test_manual_mocks.dart'; -@GenerateMocks([FrameTiming, ApmHostApi, WidgetsBinding]) void main() { TestWidgetsFlutterBinding.ensureInitialized(); diff --git a/test/utils/screen_render/instabug_screen_render_manager_test_manual_mocks.dart b/test/utils/screen_render/instabug_screen_render_manager_test_manual_mocks.dart new file mode 100644 index 000000000..f34570489 --- /dev/null +++ b/test/utils/screen_render/instabug_screen_render_manager_test_manual_mocks.dart @@ -0,0 +1,2140 @@ +// Mocks generated by Mockito 5.4.4 from annotations +// in instabug_flutter/test/utils/screen_render/instabug_screen_render_manager_test.dart. +// Do not manually edit this file. + +// ignore_for_file: no_leading_underscores_for_library_prefixes +import 'dart:async' as _i10; +import 'dart:developer' as _i15; +import 'dart:ui' as _i5; + +import 'package:flutter/foundation.dart' as _i3; +import 'package:flutter/gestures.dart' as _i7; +import 'package:flutter/rendering.dart' as _i8; +import 'package:flutter/scheduler.dart' as _i13; +import 'package:flutter/services.dart' as _i6; +import 'package:flutter/src/widgets/binding.dart' as _i12; +import 'package:flutter/src/widgets/focus_manager.dart' as _i4; +import 'package:flutter/src/widgets/framework.dart' as _i9; +import 'package:flutter/src/widgets/platform_menu_bar.dart' as _i2; +import 'package:instabug_flutter/src/generated/apm.api.g.dart' as _i11; +import 'package:mockito/mockito.dart' as _i1; +import 'package:mockito/src/dummies.dart' as _i14; + +// ignore_for_file: type=lint +// ignore_for_file: avoid_redundant_argument_values +// ignore_for_file: avoid_setters_without_getters +// ignore_for_file: comment_references +// ignore_for_file: deprecated_member_use +// ignore_for_file: deprecated_member_use_from_same_package +// ignore_for_file: implementation_imports +// ignore_for_file: invalid_use_of_visible_for_testing_member +// ignore_for_file: prefer_const_constructors +// ignore_for_file: unnecessary_parenthesis +// ignore_for_file: camel_case_types +// ignore_for_file: subtype_of_sealed_class + +class _FakeDuration_0 extends _i1.SmartFake implements Duration { + _FakeDuration_0( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} + +class _FakePlatformMenuDelegate_1 extends _i1.SmartFake + implements _i2.PlatformMenuDelegate { + _FakePlatformMenuDelegate_1( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} + +class _FakeValueNotifier_2 extends _i1.SmartFake + implements _i3.ValueNotifier { + _FakeValueNotifier_2( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} + +class _FakeFocusManager_3 extends _i1.SmartFake implements _i4.FocusManager { + _FakeFocusManager_3( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); + + @override + String toString({_i3.DiagnosticLevel? minLevel = _i3.DiagnosticLevel.info}) => + super.toString(); +} + +class _FakeSingletonFlutterWindow_4 extends _i1.SmartFake + implements _i5.SingletonFlutterWindow { + _FakeSingletonFlutterWindow_4( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} + +class _FakePlatformDispatcher_5 extends _i1.SmartFake + implements _i5.PlatformDispatcher { + _FakePlatformDispatcher_5( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} + +class _FakeHardwareKeyboard_6 extends _i1.SmartFake + implements _i6.HardwareKeyboard { + _FakeHardwareKeyboard_6( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} + +class _FakeKeyEventManager_7 extends _i1.SmartFake + implements _i6.KeyEventManager { + _FakeKeyEventManager_7( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} + +class _FakeBinaryMessenger_8 extends _i1.SmartFake + implements _i6.BinaryMessenger { + _FakeBinaryMessenger_8( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} + +class _FakeChannelBuffers_9 extends _i1.SmartFake + implements _i5.ChannelBuffers { + _FakeChannelBuffers_9( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} + +class _FakeRestorationManager_10 extends _i1.SmartFake + implements _i6.RestorationManager { + _FakeRestorationManager_10( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} + +class _FakePointerRouter_11 extends _i1.SmartFake implements _i7.PointerRouter { + _FakePointerRouter_11( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} + +class _FakeGestureArenaManager_12 extends _i1.SmartFake + implements _i7.GestureArenaManager { + _FakeGestureArenaManager_12( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} + +class _FakePointerSignalResolver_13 extends _i1.SmartFake + implements _i7.PointerSignalResolver { + _FakePointerSignalResolver_13( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} + +class _FakeSamplingClock_14 extends _i1.SmartFake implements _i7.SamplingClock { + _FakeSamplingClock_14( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} + +class _FakeRenderView_15 extends _i1.SmartFake implements _i8.RenderView { + _FakeRenderView_15( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); + + @override + String toString({_i3.DiagnosticLevel? minLevel = _i3.DiagnosticLevel.info}) => + super.toString(); +} + +class _FakeMouseTracker_16 extends _i1.SmartFake implements _i8.MouseTracker { + _FakeMouseTracker_16( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} + +class _FakeAccessibilityFeatures_17 extends _i1.SmartFake + implements _i5.AccessibilityFeatures { + _FakeAccessibilityFeatures_17( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} + +class _FakeWidget_18 extends _i1.SmartFake implements _i9.Widget { + _FakeWidget_18( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); + + @override + String toString({_i3.DiagnosticLevel? minLevel = _i3.DiagnosticLevel.info}) => + super.toString(); +} + +class _FakeFuture_19 extends _i1.SmartFake implements _i10.Future { + _FakeFuture_19( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} + +class _FakeViewConfiguration_20 extends _i1.SmartFake + implements _i8.ViewConfiguration { + _FakeViewConfiguration_20( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} + +class _FakeSceneBuilder_21 extends _i1.SmartFake implements _i5.SceneBuilder { + _FakeSceneBuilder_21( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} + +class _FakePictureRecorder_22 extends _i1.SmartFake + implements _i5.PictureRecorder { + _FakePictureRecorder_22( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} + +class _FakeCanvas_23 extends _i1.SmartFake implements _i5.Canvas { + _FakeCanvas_23( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} + +class _FakeSemanticsHandle_24 extends _i1.SmartFake + implements _i8.SemanticsHandle { + _FakeSemanticsHandle_24( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} + +class _FakeSemanticsUpdateBuilder_25 extends _i1.SmartFake + implements _i5.SemanticsUpdateBuilder { + _FakeSemanticsUpdateBuilder_25( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} + +/// A class which mocks [FrameTiming]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockFrameTiming extends _i1.Mock implements _i5.FrameTiming { + MockFrameTiming() { + _i1.throwOnMissingStub(this); + } + + @override + Duration get buildDuration => (super.noSuchMethod( + Invocation.getter(#buildDuration), + returnValue: _FakeDuration_0( + this, + Invocation.getter(#buildDuration), + ), + ) as Duration); + + @override + Duration get rasterDuration => (super.noSuchMethod( + Invocation.getter(#rasterDuration), + returnValue: _FakeDuration_0( + this, + Invocation.getter(#rasterDuration), + ), + ) as Duration); + + @override + Duration get vsyncOverhead => (super.noSuchMethod( + Invocation.getter(#vsyncOverhead), + returnValue: _FakeDuration_0( + this, + Invocation.getter(#vsyncOverhead), + ), + ) as Duration); + + @override + Duration get totalSpan => (super.noSuchMethod( + Invocation.getter(#totalSpan), + returnValue: _FakeDuration_0( + this, + Invocation.getter(#totalSpan), + ), + ) as Duration); + + @override + int get layerCacheCount => (super.noSuchMethod( + Invocation.getter(#layerCacheCount), + returnValue: 0, + ) as int); + + @override + int get layerCacheBytes => (super.noSuchMethod( + Invocation.getter(#layerCacheBytes), + returnValue: 0, + ) as int); + + @override + double get layerCacheMegabytes => (super.noSuchMethod( + Invocation.getter(#layerCacheMegabytes), + returnValue: 0.0, + ) as double); + + @override + int get pictureCacheCount => (super.noSuchMethod( + Invocation.getter(#pictureCacheCount), + returnValue: 0, + ) as int); + + @override + int get pictureCacheBytes => (super.noSuchMethod( + Invocation.getter(#pictureCacheBytes), + returnValue: 0, + ) as int); + + @override + double get pictureCacheMegabytes => (super.noSuchMethod( + Invocation.getter(#pictureCacheMegabytes), + returnValue: 0.0, + ) as double); + + @override + int get frameNumber => (super.noSuchMethod( + Invocation.getter(#frameNumber), + returnValue: 0, + ) as int); + + @override + int timestampInMicroseconds(_i5.FramePhase? phase) => (super.noSuchMethod( + Invocation.method( + #timestampInMicroseconds, + [phase], + ), + returnValue: 0, + ) as int); +} + +/// A class which mocks [ApmHostApi]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockApmHostApi extends _i1.Mock implements _i11.ApmHostApi { + MockApmHostApi() { + _i1.throwOnMissingStub(this); + } + + @override + _i10.Future setEnabled(bool? arg_isEnabled) => (super.noSuchMethod( + Invocation.method( + #setEnabled, + [arg_isEnabled], + ), + returnValue: _i10.Future.value(), + returnValueForMissingStub: _i10.Future.value(), + ) as _i10.Future); + + @override + _i10.Future isEnabled() => (super.noSuchMethod( + Invocation.method( + #isEnabled, + [], + ), + returnValue: _i10.Future.value(false), + ) as _i10.Future); + + @override + _i10.Future setScreenLoadingEnabled(bool? arg_isEnabled) => + (super.noSuchMethod( + Invocation.method( + #setScreenLoadingEnabled, + [arg_isEnabled], + ), + returnValue: _i10.Future.value(), + returnValueForMissingStub: _i10.Future.value(), + ) as _i10.Future); + + @override + _i10.Future isScreenLoadingEnabled() => (super.noSuchMethod( + Invocation.method( + #isScreenLoadingEnabled, + [], + ), + returnValue: _i10.Future.value(false), + ) as _i10.Future); + + @override + _i10.Future setColdAppLaunchEnabled(bool? arg_isEnabled) => + (super.noSuchMethod( + Invocation.method( + #setColdAppLaunchEnabled, + [arg_isEnabled], + ), + returnValue: _i10.Future.value(), + returnValueForMissingStub: _i10.Future.value(), + ) as _i10.Future); + + @override + _i10.Future setAutoUITraceEnabled(bool? arg_isEnabled) => + (super.noSuchMethod( + Invocation.method( + #setAutoUITraceEnabled, + [arg_isEnabled], + ), + returnValue: _i10.Future.value(), + returnValueForMissingStub: _i10.Future.value(), + ) as _i10.Future); + + @override + _i10.Future startExecutionTrace( + String? arg_id, + String? arg_name, + ) => + (super.noSuchMethod( + Invocation.method( + #startExecutionTrace, + [ + arg_id, + arg_name, + ], + ), + returnValue: _i10.Future.value(), + ) as _i10.Future); + + @override + _i10.Future startFlow(String? arg_name) => (super.noSuchMethod( + Invocation.method( + #startFlow, + [arg_name], + ), + returnValue: _i10.Future.value(), + returnValueForMissingStub: _i10.Future.value(), + ) as _i10.Future); + + @override + _i10.Future setFlowAttribute( + String? arg_name, + String? arg_key, + String? arg_value, + ) => + (super.noSuchMethod( + Invocation.method( + #setFlowAttribute, + [ + arg_name, + arg_key, + arg_value, + ], + ), + returnValue: _i10.Future.value(), + returnValueForMissingStub: _i10.Future.value(), + ) as _i10.Future); + + @override + _i10.Future endFlow(String? arg_name) => (super.noSuchMethod( + Invocation.method( + #endFlow, + [arg_name], + ), + returnValue: _i10.Future.value(), + returnValueForMissingStub: _i10.Future.value(), + ) as _i10.Future); + + @override + _i10.Future setExecutionTraceAttribute( + String? arg_id, + String? arg_key, + String? arg_value, + ) => + (super.noSuchMethod( + Invocation.method( + #setExecutionTraceAttribute, + [ + arg_id, + arg_key, + arg_value, + ], + ), + returnValue: _i10.Future.value(), + returnValueForMissingStub: _i10.Future.value(), + ) as _i10.Future); + + @override + _i10.Future endExecutionTrace(String? arg_id) => (super.noSuchMethod( + Invocation.method( + #endExecutionTrace, + [arg_id], + ), + returnValue: _i10.Future.value(), + returnValueForMissingStub: _i10.Future.value(), + ) as _i10.Future); + + @override + _i10.Future startUITrace(String? arg_name) => (super.noSuchMethod( + Invocation.method( + #startUITrace, + [arg_name], + ), + returnValue: _i10.Future.value(), + returnValueForMissingStub: _i10.Future.value(), + ) as _i10.Future); + + @override + _i10.Future endUITrace() => (super.noSuchMethod( + Invocation.method( + #endUITrace, + [], + ), + returnValue: _i10.Future.value(), + returnValueForMissingStub: _i10.Future.value(), + ) as _i10.Future); + + @override + _i10.Future endAppLaunch() => (super.noSuchMethod( + Invocation.method( + #endAppLaunch, + [], + ), + returnValue: _i10.Future.value(), + returnValueForMissingStub: _i10.Future.value(), + ) as _i10.Future); + + @override + _i10.Future networkLogAndroid(Map? arg_data) => + (super.noSuchMethod( + Invocation.method( + #networkLogAndroid, + [arg_data], + ), + returnValue: _i10.Future.value(), + returnValueForMissingStub: _i10.Future.value(), + ) as _i10.Future); + + @override + _i10.Future startCpUiTrace( + String? arg_screenName, + int? arg_microTimeStamp, + int? arg_traceId, + ) => + (super.noSuchMethod( + Invocation.method( + #startCpUiTrace, + [ + arg_screenName, + arg_microTimeStamp, + arg_traceId, + ], + ), + returnValue: _i10.Future.value(), + returnValueForMissingStub: _i10.Future.value(), + ) as _i10.Future); + + @override + _i10.Future reportScreenLoadingCP( + int? arg_startTimeStampMicro, + int? arg_durationMicro, + int? arg_uiTraceId, + ) => + (super.noSuchMethod( + Invocation.method( + #reportScreenLoadingCP, + [ + arg_startTimeStampMicro, + arg_durationMicro, + arg_uiTraceId, + ], + ), + returnValue: _i10.Future.value(), + returnValueForMissingStub: _i10.Future.value(), + ) as _i10.Future); + + @override + _i10.Future endScreenLoadingCP( + int? arg_timeStampMicro, + int? arg_uiTraceId, + ) => + (super.noSuchMethod( + Invocation.method( + #endScreenLoadingCP, + [ + arg_timeStampMicro, + arg_uiTraceId, + ], + ), + returnValue: _i10.Future.value(), + returnValueForMissingStub: _i10.Future.value(), + ) as _i10.Future); + + @override + _i10.Future isEndScreenLoadingEnabled() => (super.noSuchMethod( + Invocation.method( + #isEndScreenLoadingEnabled, + [], + ), + returnValue: _i10.Future.value(false), + ) as _i10.Future); + + @override + _i10.Future isScreenRenderEnabled() => (super.noSuchMethod( + Invocation.method( + #isScreenRenderEnabled, + [], + ), + returnValue: _i10.Future.value(false), + ) as _i10.Future); + + @override + _i10.Future deviceRefreshRate() => (super.noSuchMethod( + Invocation.method( + #deviceRefreshRate, + [], + ), + returnValue: _i10.Future.value(0.0), + ) as _i10.Future); + + @override + _i10.Future setScreenRenderEnabled(bool? arg_isEnabled) => + (super.noSuchMethod( + Invocation.method( + #setScreenRenderEnabled, + [arg_isEnabled], + ), + returnValue: _i10.Future.value(), + returnValueForMissingStub: _i10.Future.value(), + ) as _i10.Future); +} + +/// A class which mocks [WidgetsBinding]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockWidgetsBinding extends _i1.Mock implements _i12.WidgetsBinding { + MockWidgetsBinding() { + _i1.throwOnMissingStub(this); + } + + @override + _i2.PlatformMenuDelegate get platformMenuDelegate => (super.noSuchMethod( + Invocation.getter(#platformMenuDelegate), + returnValue: _FakePlatformMenuDelegate_1( + this, + Invocation.getter(#platformMenuDelegate), + ), + ) as _i2.PlatformMenuDelegate); + + @override + set platformMenuDelegate(_i2.PlatformMenuDelegate? _platformMenuDelegate) => + super.noSuchMethod( + Invocation.setter( + #platformMenuDelegate, + _platformMenuDelegate, + ), + returnValueForMissingStub: null, + ); + + @override + bool get debugBuildingDirtyElements => (super.noSuchMethod( + Invocation.getter(#debugBuildingDirtyElements), + returnValue: false, + ) as bool); + + @override + set debugBuildingDirtyElements(bool? _debugBuildingDirtyElements) => + super.noSuchMethod( + Invocation.setter( + #debugBuildingDirtyElements, + _debugBuildingDirtyElements, + ), + returnValueForMissingStub: null, + ); + + @override + bool get debugShowWidgetInspectorOverride => (super.noSuchMethod( + Invocation.getter(#debugShowWidgetInspectorOverride), + returnValue: false, + ) as bool); + + @override + set debugShowWidgetInspectorOverride(bool? value) => super.noSuchMethod( + Invocation.setter( + #debugShowWidgetInspectorOverride, + value, + ), + returnValueForMissingStub: null, + ); + + @override + _i3.ValueNotifier get debugShowWidgetInspectorOverrideNotifier => + (super.noSuchMethod( + Invocation.getter(#debugShowWidgetInspectorOverrideNotifier), + returnValue: _FakeValueNotifier_2( + this, + Invocation.getter(#debugShowWidgetInspectorOverrideNotifier), + ), + ) as _i3.ValueNotifier); + + @override + _i3.ValueNotifier get debugWidgetInspectorSelectionOnTapEnabled => + (super.noSuchMethod( + Invocation.getter(#debugWidgetInspectorSelectionOnTapEnabled), + returnValue: _FakeValueNotifier_2( + this, + Invocation.getter(#debugWidgetInspectorSelectionOnTapEnabled), + ), + ) as _i3.ValueNotifier); + + @override + _i4.FocusManager get focusManager => (super.noSuchMethod( + Invocation.getter(#focusManager), + returnValue: _FakeFocusManager_3( + this, + Invocation.getter(#focusManager), + ), + ) as _i4.FocusManager); + + @override + bool get firstFrameRasterized => (super.noSuchMethod( + Invocation.getter(#firstFrameRasterized), + returnValue: false, + ) as bool); + + @override + _i10.Future get waitUntilFirstFrameRasterized => (super.noSuchMethod( + Invocation.getter(#waitUntilFirstFrameRasterized), + returnValue: _i10.Future.value(), + ) as _i10.Future); + + @override + bool get debugDidSendFirstFrameEvent => (super.noSuchMethod( + Invocation.getter(#debugDidSendFirstFrameEvent), + returnValue: false, + ) as bool); + + @override + bool get framesEnabled => (super.noSuchMethod( + Invocation.getter(#framesEnabled), + returnValue: false, + ) as bool); + + @override + bool get isRootWidgetAttached => (super.noSuchMethod( + Invocation.getter(#isRootWidgetAttached), + returnValue: false, + ) as bool); + + @override + _i5.SingletonFlutterWindow get window => (super.noSuchMethod( + Invocation.getter(#window), + returnValue: _FakeSingletonFlutterWindow_4( + this, + Invocation.getter(#window), + ), + ) as _i5.SingletonFlutterWindow); + + @override + _i5.PlatformDispatcher get platformDispatcher => (super.noSuchMethod( + Invocation.getter(#platformDispatcher), + returnValue: _FakePlatformDispatcher_5( + this, + Invocation.getter(#platformDispatcher), + ), + ) as _i5.PlatformDispatcher); + + @override + bool get locked => (super.noSuchMethod( + Invocation.getter(#locked), + returnValue: false, + ) as bool); + + @override + _i3.ValueNotifier get accessibilityFocus => (super.noSuchMethod( + Invocation.getter(#accessibilityFocus), + returnValue: _FakeValueNotifier_2( + this, + Invocation.getter(#accessibilityFocus), + ), + ) as _i3.ValueNotifier); + + @override + _i6.HardwareKeyboard get keyboard => (super.noSuchMethod( + Invocation.getter(#keyboard), + returnValue: _FakeHardwareKeyboard_6( + this, + Invocation.getter(#keyboard), + ), + ) as _i6.HardwareKeyboard); + + @override + _i6.KeyEventManager get keyEventManager => (super.noSuchMethod( + Invocation.getter(#keyEventManager), + returnValue: _FakeKeyEventManager_7( + this, + Invocation.getter(#keyEventManager), + ), + ) as _i6.KeyEventManager); + + @override + _i6.BinaryMessenger get defaultBinaryMessenger => (super.noSuchMethod( + Invocation.getter(#defaultBinaryMessenger), + returnValue: _FakeBinaryMessenger_8( + this, + Invocation.getter(#defaultBinaryMessenger), + ), + ) as _i6.BinaryMessenger); + + @override + _i5.ChannelBuffers get channelBuffers => (super.noSuchMethod( + Invocation.getter(#channelBuffers), + returnValue: _FakeChannelBuffers_9( + this, + Invocation.getter(#channelBuffers), + ), + ) as _i5.ChannelBuffers); + + @override + _i6.RestorationManager get restorationManager => (super.noSuchMethod( + Invocation.getter(#restorationManager), + returnValue: _FakeRestorationManager_10( + this, + Invocation.getter(#restorationManager), + ), + ) as _i6.RestorationManager); + + @override + _i13.SchedulingStrategy get schedulingStrategy => (super.noSuchMethod( + Invocation.getter(#schedulingStrategy), + returnValue: ({ + required int priority, + required _i13.SchedulerBinding scheduler, + }) => + false, + ) as _i13.SchedulingStrategy); + + @override + set schedulingStrategy(_i13.SchedulingStrategy? _schedulingStrategy) => + super.noSuchMethod( + Invocation.setter( + #schedulingStrategy, + _schedulingStrategy, + ), + returnValueForMissingStub: null, + ); + + @override + int get transientCallbackCount => (super.noSuchMethod( + Invocation.getter(#transientCallbackCount), + returnValue: 0, + ) as int); + + @override + _i10.Future get endOfFrame => (super.noSuchMethod( + Invocation.getter(#endOfFrame), + returnValue: _i10.Future.value(), + ) as _i10.Future); + + @override + bool get hasScheduledFrame => (super.noSuchMethod( + Invocation.getter(#hasScheduledFrame), + returnValue: false, + ) as bool); + + @override + _i13.SchedulerPhase get schedulerPhase => (super.noSuchMethod( + Invocation.getter(#schedulerPhase), + returnValue: _i13.SchedulerPhase.idle, + ) as _i13.SchedulerPhase); + + @override + Duration get currentFrameTimeStamp => (super.noSuchMethod( + Invocation.getter(#currentFrameTimeStamp), + returnValue: _FakeDuration_0( + this, + Invocation.getter(#currentFrameTimeStamp), + ), + ) as Duration); + + @override + Duration get currentSystemFrameTimeStamp => (super.noSuchMethod( + Invocation.getter(#currentSystemFrameTimeStamp), + returnValue: _FakeDuration_0( + this, + Invocation.getter(#currentSystemFrameTimeStamp), + ), + ) as Duration); + + @override + _i7.PointerRouter get pointerRouter => (super.noSuchMethod( + Invocation.getter(#pointerRouter), + returnValue: _FakePointerRouter_11( + this, + Invocation.getter(#pointerRouter), + ), + ) as _i7.PointerRouter); + + @override + _i7.GestureArenaManager get gestureArena => (super.noSuchMethod( + Invocation.getter(#gestureArena), + returnValue: _FakeGestureArenaManager_12( + this, + Invocation.getter(#gestureArena), + ), + ) as _i7.GestureArenaManager); + + @override + _i7.PointerSignalResolver get pointerSignalResolver => (super.noSuchMethod( + Invocation.getter(#pointerSignalResolver), + returnValue: _FakePointerSignalResolver_13( + this, + Invocation.getter(#pointerSignalResolver), + ), + ) as _i7.PointerSignalResolver); + + @override + bool get resamplingEnabled => (super.noSuchMethod( + Invocation.getter(#resamplingEnabled), + returnValue: false, + ) as bool); + + @override + set resamplingEnabled(bool? _resamplingEnabled) => super.noSuchMethod( + Invocation.setter( + #resamplingEnabled, + _resamplingEnabled, + ), + returnValueForMissingStub: null, + ); + + @override + Duration get samplingOffset => (super.noSuchMethod( + Invocation.getter(#samplingOffset), + returnValue: _FakeDuration_0( + this, + Invocation.getter(#samplingOffset), + ), + ) as Duration); + + @override + set samplingOffset(Duration? _samplingOffset) => super.noSuchMethod( + Invocation.setter( + #samplingOffset, + _samplingOffset, + ), + returnValueForMissingStub: null, + ); + + @override + _i7.SamplingClock get samplingClock => (super.noSuchMethod( + Invocation.getter(#samplingClock), + returnValue: _FakeSamplingClock_14( + this, + Invocation.getter(#samplingClock), + ), + ) as _i7.SamplingClock); + + @override + _i8.PipelineOwner get pipelineOwner => (super.noSuchMethod( + Invocation.getter(#pipelineOwner), + returnValue: _i14.dummyValue<_i8.PipelineOwner>( + this, + Invocation.getter(#pipelineOwner), + ), + ) as _i8.PipelineOwner); + + @override + _i8.RenderView get renderView => (super.noSuchMethod( + Invocation.getter(#renderView), + returnValue: _FakeRenderView_15( + this, + Invocation.getter(#renderView), + ), + ) as _i8.RenderView); + + @override + _i8.MouseTracker get mouseTracker => (super.noSuchMethod( + Invocation.getter(#mouseTracker), + returnValue: _FakeMouseTracker_16( + this, + Invocation.getter(#mouseTracker), + ), + ) as _i8.MouseTracker); + + @override + _i8.PipelineOwner get rootPipelineOwner => (super.noSuchMethod( + Invocation.getter(#rootPipelineOwner), + returnValue: _i14.dummyValue<_i8.PipelineOwner>( + this, + Invocation.getter(#rootPipelineOwner), + ), + ) as _i8.PipelineOwner); + + @override + Iterable<_i8.RenderView> get renderViews => (super.noSuchMethod( + Invocation.getter(#renderViews), + returnValue: <_i8.RenderView>[], + ) as Iterable<_i8.RenderView>); + + @override + bool get sendFramesToEngine => (super.noSuchMethod( + Invocation.getter(#sendFramesToEngine), + returnValue: false, + ) as bool); + + @override + bool get semanticsEnabled => (super.noSuchMethod( + Invocation.getter(#semanticsEnabled), + returnValue: false, + ) as bool); + + @override + int get debugOutstandingSemanticsHandles => (super.noSuchMethod( + Invocation.getter(#debugOutstandingSemanticsHandles), + returnValue: 0, + ) as int); + + @override + _i5.AccessibilityFeatures get accessibilityFeatures => (super.noSuchMethod( + Invocation.getter(#accessibilityFeatures), + returnValue: _FakeAccessibilityFeatures_17( + this, + Invocation.getter(#accessibilityFeatures), + ), + ) as _i5.AccessibilityFeatures); + + @override + bool get disableAnimations => (super.noSuchMethod( + Invocation.getter(#disableAnimations), + returnValue: false, + ) as bool); + + @override + void initInstances() => super.noSuchMethod( + Invocation.method( + #initInstances, + [], + ), + returnValueForMissingStub: null, + ); + + @override + void resetInternalState() => super.noSuchMethod( + Invocation.method( + #resetInternalState, + [], + ), + returnValueForMissingStub: null, + ); + + @override + void initServiceExtensions() => super.noSuchMethod( + Invocation.method( + #initServiceExtensions, + [], + ), + returnValueForMissingStub: null, + ); + + @override + void addObserver(_i12.WidgetsBindingObserver? observer) => super.noSuchMethod( + Invocation.method( + #addObserver, + [observer], + ), + returnValueForMissingStub: null, + ); + + @override + bool removeObserver(_i12.WidgetsBindingObserver? observer) => + (super.noSuchMethod( + Invocation.method( + #removeObserver, + [observer], + ), + returnValue: false, + ) as bool); + + @override + _i10.Future<_i5.AppExitResponse> handleRequestAppExit() => + (super.noSuchMethod( + Invocation.method( + #handleRequestAppExit, + [], + ), + returnValue: + _i10.Future<_i5.AppExitResponse>.value(_i5.AppExitResponse.exit), + ) as _i10.Future<_i5.AppExitResponse>); + + @override + void handleMetricsChanged() => super.noSuchMethod( + Invocation.method( + #handleMetricsChanged, + [], + ), + returnValueForMissingStub: null, + ); + + @override + void handleTextScaleFactorChanged() => super.noSuchMethod( + Invocation.method( + #handleTextScaleFactorChanged, + [], + ), + returnValueForMissingStub: null, + ); + + @override + void handlePlatformBrightnessChanged() => super.noSuchMethod( + Invocation.method( + #handlePlatformBrightnessChanged, + [], + ), + returnValueForMissingStub: null, + ); + + @override + void handleAccessibilityFeaturesChanged() => super.noSuchMethod( + Invocation.method( + #handleAccessibilityFeaturesChanged, + [], + ), + returnValueForMissingStub: null, + ); + + @override + void handleLocaleChanged() => super.noSuchMethod( + Invocation.method( + #handleLocaleChanged, + [], + ), + returnValueForMissingStub: null, + ); + + @override + void dispatchLocalesChanged(List<_i5.Locale>? locales) => super.noSuchMethod( + Invocation.method( + #dispatchLocalesChanged, + [locales], + ), + returnValueForMissingStub: null, + ); + + @override + void dispatchAccessibilityFeaturesChanged() => super.noSuchMethod( + Invocation.method( + #dispatchAccessibilityFeaturesChanged, + [], + ), + returnValueForMissingStub: null, + ); + + @override + _i10.Future handlePopRoute() => (super.noSuchMethod( + Invocation.method( + #handlePopRoute, + [], + ), + returnValue: _i10.Future.value(false), + ) as _i10.Future); + + @override + _i10.Future handlePushRoute(String? route) => (super.noSuchMethod( + Invocation.method( + #handlePushRoute, + [route], + ), + returnValue: _i10.Future.value(false), + ) as _i10.Future); + + @override + void handleAppLifecycleStateChanged(_i5.AppLifecycleState? state) => + super.noSuchMethod( + Invocation.method( + #handleAppLifecycleStateChanged, + [state], + ), + returnValueForMissingStub: null, + ); + + @override + void handleViewFocusChanged(_i5.ViewFocusEvent? event) => super.noSuchMethod( + Invocation.method( + #handleViewFocusChanged, + [event], + ), + returnValueForMissingStub: null, + ); + + @override + void handleMemoryPressure() => super.noSuchMethod( + Invocation.method( + #handleMemoryPressure, + [], + ), + returnValueForMissingStub: null, + ); + + @override + void drawFrame() => super.noSuchMethod( + Invocation.method( + #drawFrame, + [], + ), + returnValueForMissingStub: null, + ); + + @override + _i9.Widget wrapWithDefaultView(_i9.Widget? rootWidget) => (super.noSuchMethod( + Invocation.method( + #wrapWithDefaultView, + [rootWidget], + ), + returnValue: _FakeWidget_18( + this, + Invocation.method( + #wrapWithDefaultView, + [rootWidget], + ), + ), + ) as _i9.Widget); + + @override + void scheduleAttachRootWidget(_i9.Widget? rootWidget) => super.noSuchMethod( + Invocation.method( + #scheduleAttachRootWidget, + [rootWidget], + ), + returnValueForMissingStub: null, + ); + + @override + void attachRootWidget(_i9.Widget? rootWidget) => super.noSuchMethod( + Invocation.method( + #attachRootWidget, + [rootWidget], + ), + returnValueForMissingStub: null, + ); + + @override + void attachToBuildOwner(_i12.RootWidget? widget) => super.noSuchMethod( + Invocation.method( + #attachToBuildOwner, + [widget], + ), + returnValueForMissingStub: null, + ); + + @override + _i10.Future performReassemble() => (super.noSuchMethod( + Invocation.method( + #performReassemble, + [], + ), + returnValue: _i10.Future.value(), + returnValueForMissingStub: _i10.Future.value(), + ) as _i10.Future); + + @override + _i5.Locale? computePlatformResolvedLocale( + List<_i5.Locale>? supportedLocales) => + (super.noSuchMethod(Invocation.method( + #computePlatformResolvedLocale, + [supportedLocales], + )) as _i5.Locale?); + + @override + bool debugCheckZone(String? entryPoint) => (super.noSuchMethod( + Invocation.method( + #debugCheckZone, + [entryPoint], + ), + returnValue: false, + ) as bool); + + @override + _i10.Future lockEvents(_i10.Future Function()? callback) => + (super.noSuchMethod( + Invocation.method( + #lockEvents, + [callback], + ), + returnValue: _i10.Future.value(), + returnValueForMissingStub: _i10.Future.value(), + ) as _i10.Future); + + @override + void unlocked() => super.noSuchMethod( + Invocation.method( + #unlocked, + [], + ), + returnValueForMissingStub: null, + ); + + @override + _i10.Future reassembleApplication() => (super.noSuchMethod( + Invocation.method( + #reassembleApplication, + [], + ), + returnValue: _i10.Future.value(), + returnValueForMissingStub: _i10.Future.value(), + ) as _i10.Future); + + @override + void registerSignalServiceExtension({ + required String? name, + required _i3.AsyncCallback? callback, + }) => + super.noSuchMethod( + Invocation.method( + #registerSignalServiceExtension, + [], + { + #name: name, + #callback: callback, + }, + ), + returnValueForMissingStub: null, + ); + + @override + void registerBoolServiceExtension({ + required String? name, + required _i3.AsyncValueGetter? getter, + required _i3.AsyncValueSetter? setter, + }) => + super.noSuchMethod( + Invocation.method( + #registerBoolServiceExtension, + [], + { + #name: name, + #getter: getter, + #setter: setter, + }, + ), + returnValueForMissingStub: null, + ); + + @override + void registerNumericServiceExtension({ + required String? name, + required _i3.AsyncValueGetter? getter, + required _i3.AsyncValueSetter? setter, + }) => + super.noSuchMethod( + Invocation.method( + #registerNumericServiceExtension, + [], + { + #name: name, + #getter: getter, + #setter: setter, + }, + ), + returnValueForMissingStub: null, + ); + + @override + void postEvent( + String? eventKind, + Map? eventData, + ) => + super.noSuchMethod( + Invocation.method( + #postEvent, + [ + eventKind, + eventData, + ], + ), + returnValueForMissingStub: null, + ); + + @override + void registerStringServiceExtension({ + required String? name, + required _i3.AsyncValueGetter? getter, + required _i3.AsyncValueSetter? setter, + }) => + super.noSuchMethod( + Invocation.method( + #registerStringServiceExtension, + [], + { + #name: name, + #getter: getter, + #setter: setter, + }, + ), + returnValueForMissingStub: null, + ); + + @override + void registerServiceExtension({ + required String? name, + required _i3.ServiceExtensionCallback? callback, + }) => + super.noSuchMethod( + Invocation.method( + #registerServiceExtension, + [], + { + #name: name, + #callback: callback, + }, + ), + returnValueForMissingStub: null, + ); + + @override + _i6.BinaryMessenger createBinaryMessenger() => (super.noSuchMethod( + Invocation.method( + #createBinaryMessenger, + [], + ), + returnValue: _FakeBinaryMessenger_8( + this, + Invocation.method( + #createBinaryMessenger, + [], + ), + ), + ) as _i6.BinaryMessenger); + + @override + _i10.Future handleSystemMessage(Object? systemMessage) => + (super.noSuchMethod( + Invocation.method( + #handleSystemMessage, + [systemMessage], + ), + returnValue: _i10.Future.value(), + returnValueForMissingStub: _i10.Future.value(), + ) as _i10.Future); + + @override + void initLicenses() => super.noSuchMethod( + Invocation.method( + #initLicenses, + [], + ), + returnValueForMissingStub: null, + ); + + @override + void evict(String? asset) => super.noSuchMethod( + Invocation.method( + #evict, + [asset], + ), + returnValueForMissingStub: null, + ); + + @override + void readInitialLifecycleStateFromNativeWindow() => super.noSuchMethod( + Invocation.method( + #readInitialLifecycleStateFromNativeWindow, + [], + ), + returnValueForMissingStub: null, + ); + + @override + _i10.Future<_i5.AppExitResponse> exitApplication( + _i5.AppExitType? exitType, [ + int? exitCode = 0, + ]) => + (super.noSuchMethod( + Invocation.method( + #exitApplication, + [ + exitType, + exitCode, + ], + ), + returnValue: + _i10.Future<_i5.AppExitResponse>.value(_i5.AppExitResponse.exit), + ) as _i10.Future<_i5.AppExitResponse>); + + @override + _i6.RestorationManager createRestorationManager() => (super.noSuchMethod( + Invocation.method( + #createRestorationManager, + [], + ), + returnValue: _FakeRestorationManager_10( + this, + Invocation.method( + #createRestorationManager, + [], + ), + ), + ) as _i6.RestorationManager); + + @override + void setSystemUiChangeCallback(_i6.SystemUiChangeCallback? callback) => + super.noSuchMethod( + Invocation.method( + #setSystemUiChangeCallback, + [callback], + ), + returnValueForMissingStub: null, + ); + + @override + _i10.Future initializationComplete() => (super.noSuchMethod( + Invocation.method( + #initializationComplete, + [], + ), + returnValue: _i10.Future.value(), + returnValueForMissingStub: _i10.Future.value(), + ) as _i10.Future); + + @override + void addTimingsCallback(_i5.TimingsCallback? callback) => super.noSuchMethod( + Invocation.method( + #addTimingsCallback, + [callback], + ), + returnValueForMissingStub: null, + ); + + @override + void removeTimingsCallback(_i5.TimingsCallback? callback) => + super.noSuchMethod( + Invocation.method( + #removeTimingsCallback, + [callback], + ), + returnValueForMissingStub: null, + ); + + @override + _i10.Future scheduleTask( + _i13.TaskCallback? task, + _i13.Priority? priority, { + String? debugLabel, + _i15.Flow? flow, + }) => + (super.noSuchMethod( + Invocation.method( + #scheduleTask, + [ + task, + priority, + ], + { + #debugLabel: debugLabel, + #flow: flow, + }, + ), + returnValue: _i14.ifNotNull( + _i14.dummyValueOrNull( + this, + Invocation.method( + #scheduleTask, + [ + task, + priority, + ], + { + #debugLabel: debugLabel, + #flow: flow, + }, + ), + ), + (T v) => _i10.Future.value(v), + ) ?? + _FakeFuture_19( + this, + Invocation.method( + #scheduleTask, + [ + task, + priority, + ], + { + #debugLabel: debugLabel, + #flow: flow, + }, + ), + ), + ) as _i10.Future); + + @override + bool handleEventLoopCallback() => (super.noSuchMethod( + Invocation.method( + #handleEventLoopCallback, + [], + ), + returnValue: false, + ) as bool); + + @override + int scheduleFrameCallback( + _i13.FrameCallback? callback, { + bool? rescheduling = false, + bool? scheduleNewFrame = true, + }) => + (super.noSuchMethod( + Invocation.method( + #scheduleFrameCallback, + [callback], + { + #rescheduling: rescheduling, + #scheduleNewFrame: scheduleNewFrame, + }, + ), + returnValue: 0, + ) as int); + + @override + void cancelFrameCallbackWithId(int? id) => super.noSuchMethod( + Invocation.method( + #cancelFrameCallbackWithId, + [id], + ), + returnValueForMissingStub: null, + ); + + @override + bool debugAssertNoTransientCallbacks(String? reason) => (super.noSuchMethod( + Invocation.method( + #debugAssertNoTransientCallbacks, + [reason], + ), + returnValue: false, + ) as bool); + + @override + bool debugAssertNoPendingPerformanceModeRequests(String? reason) => + (super.noSuchMethod( + Invocation.method( + #debugAssertNoPendingPerformanceModeRequests, + [reason], + ), + returnValue: false, + ) as bool); + + @override + bool debugAssertNoTimeDilation(String? reason) => (super.noSuchMethod( + Invocation.method( + #debugAssertNoTimeDilation, + [reason], + ), + returnValue: false, + ) as bool); + + @override + void addPersistentFrameCallback(_i13.FrameCallback? callback) => + super.noSuchMethod( + Invocation.method( + #addPersistentFrameCallback, + [callback], + ), + returnValueForMissingStub: null, + ); + + @override + void addPostFrameCallback( + _i13.FrameCallback? callback, { + String? debugLabel = r'callback', + }) => + super.noSuchMethod( + Invocation.method( + #addPostFrameCallback, + [callback], + {#debugLabel: debugLabel}, + ), + returnValueForMissingStub: null, + ); + + @override + void ensureFrameCallbacksRegistered() => super.noSuchMethod( + Invocation.method( + #ensureFrameCallbacksRegistered, + [], + ), + returnValueForMissingStub: null, + ); + + @override + void ensureVisualUpdate() => super.noSuchMethod( + Invocation.method( + #ensureVisualUpdate, + [], + ), + returnValueForMissingStub: null, + ); + + @override + void scheduleFrame() => super.noSuchMethod( + Invocation.method( + #scheduleFrame, + [], + ), + returnValueForMissingStub: null, + ); + + @override + void scheduleForcedFrame() => super.noSuchMethod( + Invocation.method( + #scheduleForcedFrame, + [], + ), + returnValueForMissingStub: null, + ); + + @override + void scheduleWarmUpFrame() => super.noSuchMethod( + Invocation.method( + #scheduleWarmUpFrame, + [], + ), + returnValueForMissingStub: null, + ); + + @override + void resetEpoch() => super.noSuchMethod( + Invocation.method( + #resetEpoch, + [], + ), + returnValueForMissingStub: null, + ); + + @override + void handleBeginFrame(Duration? rawTimeStamp) => super.noSuchMethod( + Invocation.method( + #handleBeginFrame, + [rawTimeStamp], + ), + returnValueForMissingStub: null, + ); + + @override + _i13.PerformanceModeRequestHandle? requestPerformanceMode( + _i5.DartPerformanceMode? mode) => + (super.noSuchMethod(Invocation.method( + #requestPerformanceMode, + [mode], + )) as _i13.PerformanceModeRequestHandle?); + + @override + void handleDrawFrame() => super.noSuchMethod( + Invocation.method( + #handleDrawFrame, + [], + ), + returnValueForMissingStub: null, + ); + + @override + void cancelPointer(int? pointer) => super.noSuchMethod( + Invocation.method( + #cancelPointer, + [pointer], + ), + returnValueForMissingStub: null, + ); + + @override + void handlePointerEvent(_i6.PointerEvent? event) => super.noSuchMethod( + Invocation.method( + #handlePointerEvent, + [event], + ), + returnValueForMissingStub: null, + ); + + @override + void hitTestInView( + _i7.HitTestResult? result, + _i5.Offset? position, + int? viewId, + ) => + super.noSuchMethod( + Invocation.method( + #hitTestInView, + [ + result, + position, + viewId, + ], + ), + returnValueForMissingStub: null, + ); + + @override + void hitTest( + _i7.HitTestResult? result, + _i5.Offset? position, + ) => + super.noSuchMethod( + Invocation.method( + #hitTest, + [ + result, + position, + ], + ), + returnValueForMissingStub: null, + ); + + @override + void dispatchEvent( + _i6.PointerEvent? event, + _i7.HitTestResult? hitTestResult, + ) => + super.noSuchMethod( + Invocation.method( + #dispatchEvent, + [ + event, + hitTestResult, + ], + ), + returnValueForMissingStub: null, + ); + + @override + void handleEvent( + _i6.PointerEvent? event, + _i7.HitTestEntry<_i7.HitTestTarget>? entry, + ) => + super.noSuchMethod( + Invocation.method( + #handleEvent, + [ + event, + entry, + ], + ), + returnValueForMissingStub: null, + ); + + @override + void resetGestureBinding() => super.noSuchMethod( + Invocation.method( + #resetGestureBinding, + [], + ), + returnValueForMissingStub: null, + ); + + @override + _i8.PipelineOwner createRootPipelineOwner() => (super.noSuchMethod( + Invocation.method( + #createRootPipelineOwner, + [], + ), + returnValue: _i14.dummyValue<_i8.PipelineOwner>( + this, + Invocation.method( + #createRootPipelineOwner, + [], + ), + ), + ) as _i8.PipelineOwner); + + @override + void addRenderView(_i8.RenderView? view) => super.noSuchMethod( + Invocation.method( + #addRenderView, + [view], + ), + returnValueForMissingStub: null, + ); + + @override + void removeRenderView(_i8.RenderView? view) => super.noSuchMethod( + Invocation.method( + #removeRenderView, + [view], + ), + returnValueForMissingStub: null, + ); + + @override + _i8.ViewConfiguration createViewConfigurationFor( + _i8.RenderView? renderView) => + (super.noSuchMethod( + Invocation.method( + #createViewConfigurationFor, + [renderView], + ), + returnValue: _FakeViewConfiguration_20( + this, + Invocation.method( + #createViewConfigurationFor, + [renderView], + ), + ), + ) as _i8.ViewConfiguration); + + @override + _i5.SceneBuilder createSceneBuilder() => (super.noSuchMethod( + Invocation.method( + #createSceneBuilder, + [], + ), + returnValue: _FakeSceneBuilder_21( + this, + Invocation.method( + #createSceneBuilder, + [], + ), + ), + ) as _i5.SceneBuilder); + + @override + _i5.PictureRecorder createPictureRecorder() => (super.noSuchMethod( + Invocation.method( + #createPictureRecorder, + [], + ), + returnValue: _FakePictureRecorder_22( + this, + Invocation.method( + #createPictureRecorder, + [], + ), + ), + ) as _i5.PictureRecorder); + + @override + _i5.Canvas createCanvas(_i5.PictureRecorder? recorder) => (super.noSuchMethod( + Invocation.method( + #createCanvas, + [recorder], + ), + returnValue: _FakeCanvas_23( + this, + Invocation.method( + #createCanvas, + [recorder], + ), + ), + ) as _i5.Canvas); + + @override + void initMouseTracker([_i8.MouseTracker? tracker]) => super.noSuchMethod( + Invocation.method( + #initMouseTracker, + [tracker], + ), + returnValueForMissingStub: null, + ); + + @override + void performSemanticsAction(_i5.SemanticsActionEvent? action) => + super.noSuchMethod( + Invocation.method( + #performSemanticsAction, + [action], + ), + returnValueForMissingStub: null, + ); + + @override + void deferFirstFrame() => super.noSuchMethod( + Invocation.method( + #deferFirstFrame, + [], + ), + returnValueForMissingStub: null, + ); + + @override + void allowFirstFrame() => super.noSuchMethod( + Invocation.method( + #allowFirstFrame, + [], + ), + returnValueForMissingStub: null, + ); + + @override + void resetFirstFrameSent() => super.noSuchMethod( + Invocation.method( + #resetFirstFrameSent, + [], + ), + returnValueForMissingStub: null, + ); + + @override + void addSemanticsEnabledListener(_i5.VoidCallback? listener) => + super.noSuchMethod( + Invocation.method( + #addSemanticsEnabledListener, + [listener], + ), + returnValueForMissingStub: null, + ); + + @override + void removeSemanticsEnabledListener(_i5.VoidCallback? listener) => + super.noSuchMethod( + Invocation.method( + #removeSemanticsEnabledListener, + [listener], + ), + returnValueForMissingStub: null, + ); + + @override + void addSemanticsActionListener( + _i3.ValueSetter<_i5.SemanticsActionEvent>? listener) => + super.noSuchMethod( + Invocation.method( + #addSemanticsActionListener, + [listener], + ), + returnValueForMissingStub: null, + ); + + @override + void removeSemanticsActionListener( + _i3.ValueSetter<_i5.SemanticsActionEvent>? listener) => + super.noSuchMethod( + Invocation.method( + #removeSemanticsActionListener, + [listener], + ), + returnValueForMissingStub: null, + ); + + @override + _i8.SemanticsHandle ensureSemantics() => (super.noSuchMethod( + Invocation.method( + #ensureSemantics, + [], + ), + returnValue: _FakeSemanticsHandle_24( + this, + Invocation.method( + #ensureSemantics, + [], + ), + ), + ) as _i8.SemanticsHandle); + + @override + _i5.SemanticsUpdateBuilder createSemanticsUpdateBuilder() => + (super.noSuchMethod( + Invocation.method( + #createSemanticsUpdateBuilder, + [], + ), + returnValue: _FakeSemanticsUpdateBuilder_25( + this, + Invocation.method( + #createSemanticsUpdateBuilder, + [], + ), + ), + ) as _i5.SemanticsUpdateBuilder); +} From 39bdd7254a6e30689ad56472614afdb8054246a5 Mon Sep 17 00:00:00 2001 From: Andrew Amin Date: Tue, 1 Jul 2025 14:08:07 +0300 Subject: [PATCH 14/84] chore: apply flutter 2.10.5 --- example/pubspec.lock | 189 +- .../instabug_screen_render_manager_test.dart | 13 +- ...reen_render_manager_test_manual_mocks.dart | 2484 ++++------------- 3 files changed, 698 insertions(+), 1988 deletions(-) diff --git a/example/pubspec.lock b/example/pubspec.lock index 74b4b6b46..db618bb81 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -1,62 +1,76 @@ # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: + archive: + dependency: transitive + description: + name: archive + url: "https://pub.dartlang.org" + source: hosted + version: "3.1.6" async: dependency: transitive description: name: async - sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb" - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "2.13.0" + version: "2.8.2" boolean_selector: dependency: transitive description: name: boolean_selector - sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "2.1.2" + version: "2.1.0" characters: dependency: transitive description: name: characters - sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 - url: "https://pub.dev" + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.0" + charcode: + dependency: transitive + description: + name: charcode + url: "https://pub.dartlang.org" source: hosted - version: "1.4.0" + version: "1.3.1" clock: dependency: transitive description: name: clock - sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "1.1.2" + version: "1.1.0" collection: dependency: transitive description: name: collection - sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "1.19.1" + version: "1.15.0" + crypto: + dependency: transitive + description: + name: crypto + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.1" fake_async: dependency: transitive description: name: fake_async - sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "1.3.3" + version: "1.2.0" file: dependency: transitive description: name: file - sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "7.0.1" + version: "6.1.2" flutter: dependency: "direct main" description: flutter @@ -71,8 +85,7 @@ packages: dependency: "direct dev" description: name: flutter_lints - sha256: b543301ad291598523947dc534aaddc5aaad597b709d2426d3a0e0d44c5cb493 - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted version: "1.0.4" flutter_test: @@ -89,18 +102,16 @@ packages: dependency: "direct main" description: name: http - sha256: "5895291c13fa8a3bd82e76d5627f69e0d85ca6a30dcac95c4ea19a5d555879c2" - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "0.13.6" + version: "0.13.5" http_parser: dependency: transitive description: name: http_parser - sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571" - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "4.1.2" + version: "4.0.2" instabug_flutter: dependency: "direct main" description: @@ -112,183 +123,139 @@ packages: dependency: "direct main" description: name: instabug_http_client - sha256: "97a6ab88491eff87e42437564b528d6986a65eb3f3262f73373009f949cb4560" - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted version: "2.5.1" - leak_tracker: - dependency: transitive - description: - name: leak_tracker - sha256: "6bb818ecbdffe216e81182c2f0714a2e62b593f4a4f13098713ff1685dfb6ab0" - url: "https://pub.dev" - source: hosted - version: "10.0.9" - leak_tracker_flutter_testing: - dependency: transitive - description: - name: leak_tracker_flutter_testing - sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573 - url: "https://pub.dev" - source: hosted - version: "3.0.9" - leak_tracker_testing: - dependency: transitive - description: - name: leak_tracker_testing - sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" - url: "https://pub.dev" - source: hosted - version: "3.0.1" lints: dependency: transitive description: name: lints - sha256: a2c3d198cb5ea2e179926622d433331d8b58374ab8f29cdda6e863bd62fd369c - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted version: "1.0.1" matcher: dependency: transitive description: name: matcher - sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "0.12.17" + version: "0.12.11" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "0.11.1" + version: "0.1.3" meta: dependency: transitive description: name: meta - sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "1.16.0" + version: "1.7.0" path: dependency: transitive description: name: path - sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "1.9.1" + version: "1.8.0" platform: dependency: transitive description: name: platform - sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984" - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "3.1.6" + version: "3.1.0" process: dependency: transitive description: name: process - sha256: "107d8be718f120bbba9dcd1e95e3bd325b1b4a4f07db64154635ba03f2567a0d" - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "5.0.3" + version: "4.2.4" sky_engine: dependency: transitive description: flutter source: sdk - version: "0.0.0" + version: "0.0.99" source_span: dependency: transitive description: name: source_span - sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c" - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "1.10.1" + version: "1.8.1" stack_trace: dependency: transitive description: name: stack_trace - sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "1.12.1" + version: "1.10.0" stream_channel: dependency: transitive description: name: stream_channel - sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "2.1.4" + version: "2.1.0" string_scanner: dependency: transitive description: name: string_scanner - sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "1.4.1" + version: "1.1.0" sync_http: dependency: transitive description: name: sync_http - sha256: "7f0cd72eca000d2e026bcd6f990b81d0ca06022ef4e32fb257b30d3d1014a961" - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "0.3.1" + version: "0.3.0" term_glyph: dependency: transitive description: name: term_glyph - sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "1.2.2" + version: "1.2.0" test_api: dependency: transitive description: name: test_api - sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "0.7.4" + version: "0.4.8" typed_data: dependency: transitive description: name: typed_data - sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "1.4.0" + version: "1.3.0" vector_math: dependency: transitive description: name: vector_math - sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "2.1.4" + version: "2.1.1" vm_service: dependency: transitive description: name: vm_service - sha256: ddfa8d30d89985b96407efce8acbdd124701f96741f2d981ca860662f1c0dc02 - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "15.0.0" + version: "7.5.0" webdriver: dependency: transitive description: name: webdriver - sha256: "2f3a14ca026957870cfd9c635b83507e0e51d8091568e90129fbf805aba7cade" - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "3.1.0" + version: "3.0.0" sdks: - dart: ">=3.7.0-0 <4.0.0" - flutter: ">=3.18.0-18.0.pre.54" + dart: ">=2.14.0 <3.0.0" diff --git a/test/utils/screen_render/instabug_screen_render_manager_test.dart b/test/utils/screen_render/instabug_screen_render_manager_test.dart index deb227462..c261fc879 100644 --- a/test/utils/screen_render/instabug_screen_render_manager_test.dart +++ b/test/utils/screen_render/instabug_screen_render_manager_test.dart @@ -1,12 +1,19 @@ +import 'dart:ui'; + +import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:instabug_flutter/instabug_flutter.dart'; +import 'package:instabug_flutter/src/generated/apm.api.g.dart'; import 'package:instabug_flutter/src/models/instabug_frame_data.dart'; import 'package:instabug_flutter/src/models/instabug_screen_render_data.dart'; import 'package:instabug_flutter/src/utils/screen_rendering/instabug_screen_render_manager.dart'; +import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; + import 'instabug_screen_render_manager_test_manual_mocks.dart'; +@GenerateMocks([ApmHostApi, WidgetsBinding, FrameTiming]) void main() { TestWidgetsFlutterBinding.ensureInitialized(); @@ -23,10 +30,6 @@ void main() { manager.init(mWidgetBinding); }); - tearDown(() { - // Clean up state after each test - }); - group('InstabugScreenRenderManager.init()', () { test('should initialize timings callback and add observer', () async { expect(manager, isA()); @@ -45,8 +48,6 @@ void main() { verify(mWidgetBinding.addObserver(any)).called(1); verify(mWidgetBinding.addTimingsCallback(any)).called(1); - - expect(true, isTrue); // no crash }); }); diff --git a/test/utils/screen_render/instabug_screen_render_manager_test_manual_mocks.dart b/test/utils/screen_render/instabug_screen_render_manager_test_manual_mocks.dart index f34570489..dcc87eaab 100644 --- a/test/utils/screen_render/instabug_screen_render_manager_test_manual_mocks.dart +++ b/test/utils/screen_render/instabug_screen_render_manager_test_manual_mocks.dart @@ -1,2140 +1,882 @@ -// Mocks generated by Mockito 5.4.4 from annotations -// in instabug_flutter/test/utils/screen_render/instabug_screen_render_manager_test.dart. +// Mocks generated by Mockito 5.2.0 from annotations +// in instabug_flutter/example/ios/.symlinks/plugins/instabug_flutter/test/utils/screen_render/instabug_screen_render_manager_test.dart. // Do not manually edit this file. -// ignore_for_file: no_leading_underscores_for_library_prefixes -import 'dart:async' as _i10; -import 'dart:developer' as _i15; -import 'dart:ui' as _i5; +import 'dart:async' as _i9; +import 'dart:developer' as _i13; +import 'dart:ui' as _i4; import 'package:flutter/foundation.dart' as _i3; -import 'package:flutter/gestures.dart' as _i7; -import 'package:flutter/rendering.dart' as _i8; -import 'package:flutter/scheduler.dart' as _i13; -import 'package:flutter/services.dart' as _i6; -import 'package:flutter/src/widgets/binding.dart' as _i12; -import 'package:flutter/src/widgets/focus_manager.dart' as _i4; -import 'package:flutter/src/widgets/framework.dart' as _i9; -import 'package:flutter/src/widgets/platform_menu_bar.dart' as _i2; -import 'package:instabug_flutter/src/generated/apm.api.g.dart' as _i11; +import 'package:flutter/gestures.dart' as _i6; +import 'package:flutter/rendering.dart' as _i7; +import 'package:flutter/scheduler.dart' as _i11; +import 'package:flutter/services.dart' as _i5; +import 'package:flutter/src/widgets/binding.dart' as _i10; +import 'package:flutter/src/widgets/focus_manager.dart' as _i2; +import 'package:flutter/src/widgets/framework.dart' as _i12; +import 'package:instabug_flutter/src/generated/apm.api.g.dart' as _i8; import 'package:mockito/mockito.dart' as _i1; -import 'package:mockito/src/dummies.dart' as _i14; // ignore_for_file: type=lint // ignore_for_file: avoid_redundant_argument_values // ignore_for_file: avoid_setters_without_getters // ignore_for_file: comment_references -// ignore_for_file: deprecated_member_use -// ignore_for_file: deprecated_member_use_from_same_package // ignore_for_file: implementation_imports // ignore_for_file: invalid_use_of_visible_for_testing_member // ignore_for_file: prefer_const_constructors // ignore_for_file: unnecessary_parenthesis // ignore_for_file: camel_case_types -// ignore_for_file: subtype_of_sealed_class - -class _FakeDuration_0 extends _i1.SmartFake implements Duration { - _FakeDuration_0( - Object parent, - Invocation parentInvocation, - ) : super( - parent, - parentInvocation, - ); -} - -class _FakePlatformMenuDelegate_1 extends _i1.SmartFake - implements _i2.PlatformMenuDelegate { - _FakePlatformMenuDelegate_1( - Object parent, - Invocation parentInvocation, - ) : super( - parent, - parentInvocation, - ); -} - -class _FakeValueNotifier_2 extends _i1.SmartFake - implements _i3.ValueNotifier { - _FakeValueNotifier_2( - Object parent, - Invocation parentInvocation, - ) : super( - parent, - parentInvocation, - ); -} - -class _FakeFocusManager_3 extends _i1.SmartFake implements _i4.FocusManager { - _FakeFocusManager_3( - Object parent, - Invocation parentInvocation, - ) : super( - parent, - parentInvocation, - ); +class _FakeFocusManager_0 extends _i1.Fake implements _i2.FocusManager { @override String toString({_i3.DiagnosticLevel? minLevel = _i3.DiagnosticLevel.info}) => super.toString(); } -class _FakeSingletonFlutterWindow_4 extends _i1.SmartFake - implements _i5.SingletonFlutterWindow { - _FakeSingletonFlutterWindow_4( - Object parent, - Invocation parentInvocation, - ) : super( - parent, - parentInvocation, - ); -} - -class _FakePlatformDispatcher_5 extends _i1.SmartFake - implements _i5.PlatformDispatcher { - _FakePlatformDispatcher_5( - Object parent, - Invocation parentInvocation, - ) : super( - parent, - parentInvocation, - ); -} - -class _FakeHardwareKeyboard_6 extends _i1.SmartFake - implements _i6.HardwareKeyboard { - _FakeHardwareKeyboard_6( - Object parent, - Invocation parentInvocation, - ) : super( - parent, - parentInvocation, - ); -} - -class _FakeKeyEventManager_7 extends _i1.SmartFake - implements _i6.KeyEventManager { - _FakeKeyEventManager_7( - Object parent, - Invocation parentInvocation, - ) : super( - parent, - parentInvocation, - ); -} +class _FakeSingletonFlutterWindow_1 extends _i1.Fake + implements _i4.SingletonFlutterWindow {} -class _FakeBinaryMessenger_8 extends _i1.SmartFake - implements _i6.BinaryMessenger { - _FakeBinaryMessenger_8( - Object parent, - Invocation parentInvocation, - ) : super( - parent, - parentInvocation, - ); -} +class _FakePlatformDispatcher_2 extends _i1.Fake + implements _i4.PlatformDispatcher {} -class _FakeChannelBuffers_9 extends _i1.SmartFake - implements _i5.ChannelBuffers { - _FakeChannelBuffers_9( - Object parent, - Invocation parentInvocation, - ) : super( - parent, - parentInvocation, - ); +class _FakeHardwareKeyboard_3 extends _i1.Fake implements _i5.HardwareKeyboard { } -class _FakeRestorationManager_10 extends _i1.SmartFake - implements _i6.RestorationManager { - _FakeRestorationManager_10( - Object parent, - Invocation parentInvocation, - ) : super( - parent, - parentInvocation, - ); -} +class _FakeKeyEventManager_4 extends _i1.Fake implements _i5.KeyEventManager {} -class _FakePointerRouter_11 extends _i1.SmartFake implements _i7.PointerRouter { - _FakePointerRouter_11( - Object parent, - Invocation parentInvocation, - ) : super( - parent, - parentInvocation, - ); -} +class _FakeBinaryMessenger_5 extends _i1.Fake implements _i5.BinaryMessenger {} -class _FakeGestureArenaManager_12 extends _i1.SmartFake - implements _i7.GestureArenaManager { - _FakeGestureArenaManager_12( - Object parent, - Invocation parentInvocation, - ) : super( - parent, - parentInvocation, - ); -} +class _FakeChannelBuffers_6 extends _i1.Fake implements _i4.ChannelBuffers {} -class _FakePointerSignalResolver_13 extends _i1.SmartFake - implements _i7.PointerSignalResolver { - _FakePointerSignalResolver_13( - Object parent, - Invocation parentInvocation, - ) : super( - parent, - parentInvocation, - ); -} +class _FakeRestorationManager_7 extends _i1.Fake + implements _i5.RestorationManager {} -class _FakeSamplingClock_14 extends _i1.SmartFake implements _i7.SamplingClock { - _FakeSamplingClock_14( - Object parent, - Invocation parentInvocation, - ) : super( - parent, - parentInvocation, - ); -} +class _FakeDuration_8 extends _i1.Fake implements Duration {} -class _FakeRenderView_15 extends _i1.SmartFake implements _i8.RenderView { - _FakeRenderView_15( - Object parent, - Invocation parentInvocation, - ) : super( - parent, - parentInvocation, - ); +class _FakePointerRouter_9 extends _i1.Fake implements _i6.PointerRouter {} - @override - String toString({_i3.DiagnosticLevel? minLevel = _i3.DiagnosticLevel.info}) => - super.toString(); -} +class _FakeGestureArenaManager_10 extends _i1.Fake + implements _i6.GestureArenaManager {} -class _FakeMouseTracker_16 extends _i1.SmartFake implements _i8.MouseTracker { - _FakeMouseTracker_16( - Object parent, - Invocation parentInvocation, - ) : super( - parent, - parentInvocation, - ); -} +class _FakePointerSignalResolver_11 extends _i1.Fake + implements _i6.PointerSignalResolver {} -class _FakeAccessibilityFeatures_17 extends _i1.SmartFake - implements _i5.AccessibilityFeatures { - _FakeAccessibilityFeatures_17( - Object parent, - Invocation parentInvocation, - ) : super( - parent, - parentInvocation, - ); -} +class _FakeMouseTracker_12 extends _i1.Fake implements _i7.MouseTracker {} -class _FakeWidget_18 extends _i1.SmartFake implements _i9.Widget { - _FakeWidget_18( - Object parent, - Invocation parentInvocation, - ) : super( - parent, - parentInvocation, - ); +class _FakePipelineOwner_13 extends _i1.Fake implements _i7.PipelineOwner {} +class _FakeRenderView_14 extends _i1.Fake implements _i7.RenderView { @override String toString({_i3.DiagnosticLevel? minLevel = _i3.DiagnosticLevel.info}) => super.toString(); } -class _FakeFuture_19 extends _i1.SmartFake implements _i10.Future { - _FakeFuture_19( - Object parent, - Invocation parentInvocation, - ) : super( - parent, - parentInvocation, - ); -} +class _FakeAccessibilityFeatures_15 extends _i1.Fake + implements _i4.AccessibilityFeatures {} -class _FakeViewConfiguration_20 extends _i1.SmartFake - implements _i8.ViewConfiguration { - _FakeViewConfiguration_20( - Object parent, - Invocation parentInvocation, - ) : super( - parent, - parentInvocation, - ); -} - -class _FakeSceneBuilder_21 extends _i1.SmartFake implements _i5.SceneBuilder { - _FakeSceneBuilder_21( - Object parent, - Invocation parentInvocation, - ) : super( - parent, - parentInvocation, - ); -} +class _FakeViewConfiguration_16 extends _i1.Fake + implements _i7.ViewConfiguration {} -class _FakePictureRecorder_22 extends _i1.SmartFake - implements _i5.PictureRecorder { - _FakePictureRecorder_22( - Object parent, - Invocation parentInvocation, - ) : super( - parent, - parentInvocation, - ); -} +class _FakeSemanticsUpdateBuilder_17 extends _i1.Fake + implements _i4.SemanticsUpdateBuilder {} -class _FakeCanvas_23 extends _i1.SmartFake implements _i5.Canvas { - _FakeCanvas_23( - Object parent, - Invocation parentInvocation, - ) : super( - parent, - parentInvocation, - ); -} - -class _FakeSemanticsHandle_24 extends _i1.SmartFake - implements _i8.SemanticsHandle { - _FakeSemanticsHandle_24( - Object parent, - Invocation parentInvocation, - ) : super( - parent, - parentInvocation, - ); -} - -class _FakeSemanticsUpdateBuilder_25 extends _i1.SmartFake - implements _i5.SemanticsUpdateBuilder { - _FakeSemanticsUpdateBuilder_25( - Object parent, - Invocation parentInvocation, - ) : super( - parent, - parentInvocation, - ); -} - -/// A class which mocks [FrameTiming]. +/// A class which mocks [ApmHostApi]. /// /// See the documentation for Mockito's code generation for more information. -class MockFrameTiming extends _i1.Mock implements _i5.FrameTiming { - MockFrameTiming() { +class MockApmHostApi extends _i1.Mock implements _i8.ApmHostApi { + MockApmHostApi() { _i1.throwOnMissingStub(this); } @override - Duration get buildDuration => (super.noSuchMethod( - Invocation.getter(#buildDuration), - returnValue: _FakeDuration_0( - this, - Invocation.getter(#buildDuration), - ), - ) as Duration); + _i9.Future setEnabled(bool? arg_isEnabled) => + (super.noSuchMethod(Invocation.method(#setEnabled, [arg_isEnabled]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); @override - Duration get rasterDuration => (super.noSuchMethod( - Invocation.getter(#rasterDuration), - returnValue: _FakeDuration_0( - this, - Invocation.getter(#rasterDuration), - ), - ) as Duration); + _i9.Future isEnabled() => + (super.noSuchMethod(Invocation.method(#isEnabled, []), + returnValue: Future.value(false)) as _i9.Future); @override - Duration get vsyncOverhead => (super.noSuchMethod( - Invocation.getter(#vsyncOverhead), - returnValue: _FakeDuration_0( - this, - Invocation.getter(#vsyncOverhead), - ), - ) as Duration); + _i9.Future setScreenLoadingEnabled(bool? arg_isEnabled) => + (super.noSuchMethod( + Invocation.method(#setScreenLoadingEnabled, [arg_isEnabled]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); @override - Duration get totalSpan => (super.noSuchMethod( - Invocation.getter(#totalSpan), - returnValue: _FakeDuration_0( - this, - Invocation.getter(#totalSpan), - ), - ) as Duration); + _i9.Future isScreenLoadingEnabled() => + (super.noSuchMethod(Invocation.method(#isScreenLoadingEnabled, []), + returnValue: Future.value(false)) as _i9.Future); @override - int get layerCacheCount => (super.noSuchMethod( - Invocation.getter(#layerCacheCount), - returnValue: 0, - ) as int); + _i9.Future setColdAppLaunchEnabled(bool? arg_isEnabled) => + (super.noSuchMethod( + Invocation.method(#setColdAppLaunchEnabled, [arg_isEnabled]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); @override - int get layerCacheBytes => (super.noSuchMethod( - Invocation.getter(#layerCacheBytes), - returnValue: 0, - ) as int); + _i9.Future setAutoUITraceEnabled(bool? arg_isEnabled) => (super + .noSuchMethod(Invocation.method(#setAutoUITraceEnabled, [arg_isEnabled]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); @override - double get layerCacheMegabytes => (super.noSuchMethod( - Invocation.getter(#layerCacheMegabytes), - returnValue: 0.0, - ) as double); + _i9.Future startExecutionTrace(String? arg_id, String? arg_name) => + (super.noSuchMethod( + Invocation.method(#startExecutionTrace, [arg_id, arg_name]), + returnValue: Future.value()) as _i9.Future); @override - int get pictureCacheCount => (super.noSuchMethod( - Invocation.getter(#pictureCacheCount), - returnValue: 0, - ) as int); + _i9.Future startFlow(String? arg_name) => + (super.noSuchMethod(Invocation.method(#startFlow, [arg_name]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); @override - int get pictureCacheBytes => (super.noSuchMethod( - Invocation.getter(#pictureCacheBytes), - returnValue: 0, - ) as int); + _i9.Future setFlowAttribute( + String? arg_name, String? arg_key, String? arg_value) => + (super.noSuchMethod( + Invocation.method(#setFlowAttribute, [arg_name, arg_key, arg_value]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); @override - double get pictureCacheMegabytes => (super.noSuchMethod( - Invocation.getter(#pictureCacheMegabytes), - returnValue: 0.0, - ) as double); + _i9.Future endFlow(String? arg_name) => + (super.noSuchMethod(Invocation.method(#endFlow, [arg_name]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); @override - int get frameNumber => (super.noSuchMethod( - Invocation.getter(#frameNumber), - returnValue: 0, - ) as int); + _i9.Future setExecutionTraceAttribute( + String? arg_id, String? arg_key, String? arg_value) => + (super.noSuchMethod( + Invocation.method( + #setExecutionTraceAttribute, [arg_id, arg_key, arg_value]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); @override - int timestampInMicroseconds(_i5.FramePhase? phase) => (super.noSuchMethod( - Invocation.method( - #timestampInMicroseconds, - [phase], - ), - returnValue: 0, - ) as int); -} - -/// A class which mocks [ApmHostApi]. -/// -/// See the documentation for Mockito's code generation for more information. -class MockApmHostApi extends _i1.Mock implements _i11.ApmHostApi { - MockApmHostApi() { - _i1.throwOnMissingStub(this); - } + _i9.Future endExecutionTrace(String? arg_id) => + (super.noSuchMethod(Invocation.method(#endExecutionTrace, [arg_id]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); @override - _i10.Future setEnabled(bool? arg_isEnabled) => (super.noSuchMethod( - Invocation.method( - #setEnabled, - [arg_isEnabled], - ), - returnValue: _i10.Future.value(), - returnValueForMissingStub: _i10.Future.value(), - ) as _i10.Future); + _i9.Future startUITrace(String? arg_name) => + (super.noSuchMethod(Invocation.method(#startUITrace, [arg_name]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); @override - _i10.Future isEnabled() => (super.noSuchMethod( - Invocation.method( - #isEnabled, - [], - ), - returnValue: _i10.Future.value(false), - ) as _i10.Future); + _i9.Future endUITrace() => + (super.noSuchMethod(Invocation.method(#endUITrace, []), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); @override - _i10.Future setScreenLoadingEnabled(bool? arg_isEnabled) => - (super.noSuchMethod( - Invocation.method( - #setScreenLoadingEnabled, - [arg_isEnabled], - ), - returnValue: _i10.Future.value(), - returnValueForMissingStub: _i10.Future.value(), - ) as _i10.Future); + _i9.Future endAppLaunch() => + (super.noSuchMethod(Invocation.method(#endAppLaunch, []), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); @override - _i10.Future isScreenLoadingEnabled() => (super.noSuchMethod( - Invocation.method( - #isScreenLoadingEnabled, - [], - ), - returnValue: _i10.Future.value(false), - ) as _i10.Future); + _i9.Future networkLogAndroid(Map? arg_data) => + (super.noSuchMethod(Invocation.method(#networkLogAndroid, [arg_data]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); @override - _i10.Future setColdAppLaunchEnabled(bool? arg_isEnabled) => + _i9.Future startCpUiTrace( + String? arg_screenName, int? arg_microTimeStamp, int? arg_traceId) => (super.noSuchMethod( - Invocation.method( - #setColdAppLaunchEnabled, - [arg_isEnabled], - ), - returnValue: _i10.Future.value(), - returnValueForMissingStub: _i10.Future.value(), - ) as _i10.Future); + Invocation.method(#startCpUiTrace, + [arg_screenName, arg_microTimeStamp, arg_traceId]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); @override - _i10.Future setAutoUITraceEnabled(bool? arg_isEnabled) => - (super.noSuchMethod( - Invocation.method( - #setAutoUITraceEnabled, - [arg_isEnabled], - ), - returnValue: _i10.Future.value(), - returnValueForMissingStub: _i10.Future.value(), - ) as _i10.Future); - - @override - _i10.Future startExecutionTrace( - String? arg_id, - String? arg_name, - ) => - (super.noSuchMethod( - Invocation.method( - #startExecutionTrace, - [ - arg_id, - arg_name, - ], - ), - returnValue: _i10.Future.value(), - ) as _i10.Future); - - @override - _i10.Future startFlow(String? arg_name) => (super.noSuchMethod( - Invocation.method( - #startFlow, - [arg_name], - ), - returnValue: _i10.Future.value(), - returnValueForMissingStub: _i10.Future.value(), - ) as _i10.Future); - - @override - _i10.Future setFlowAttribute( - String? arg_name, - String? arg_key, - String? arg_value, - ) => - (super.noSuchMethod( - Invocation.method( - #setFlowAttribute, - [ - arg_name, - arg_key, - arg_value, - ], - ), - returnValue: _i10.Future.value(), - returnValueForMissingStub: _i10.Future.value(), - ) as _i10.Future); - - @override - _i10.Future endFlow(String? arg_name) => (super.noSuchMethod( - Invocation.method( - #endFlow, - [arg_name], - ), - returnValue: _i10.Future.value(), - returnValueForMissingStub: _i10.Future.value(), - ) as _i10.Future); - - @override - _i10.Future setExecutionTraceAttribute( - String? arg_id, - String? arg_key, - String? arg_value, - ) => + _i9.Future reportScreenLoadingCP(int? arg_startTimeStampMicro, + int? arg_durationMicro, int? arg_uiTraceId) => (super.noSuchMethod( - Invocation.method( - #setExecutionTraceAttribute, - [ - arg_id, - arg_key, - arg_value, - ], - ), - returnValue: _i10.Future.value(), - returnValueForMissingStub: _i10.Future.value(), - ) as _i10.Future); - - @override - _i10.Future endExecutionTrace(String? arg_id) => (super.noSuchMethod( - Invocation.method( - #endExecutionTrace, - [arg_id], - ), - returnValue: _i10.Future.value(), - returnValueForMissingStub: _i10.Future.value(), - ) as _i10.Future); - - @override - _i10.Future startUITrace(String? arg_name) => (super.noSuchMethod( - Invocation.method( - #startUITrace, - [arg_name], - ), - returnValue: _i10.Future.value(), - returnValueForMissingStub: _i10.Future.value(), - ) as _i10.Future); - - @override - _i10.Future endUITrace() => (super.noSuchMethod( - Invocation.method( - #endUITrace, - [], - ), - returnValue: _i10.Future.value(), - returnValueForMissingStub: _i10.Future.value(), - ) as _i10.Future); - - @override - _i10.Future endAppLaunch() => (super.noSuchMethod( - Invocation.method( - #endAppLaunch, - [], - ), - returnValue: _i10.Future.value(), - returnValueForMissingStub: _i10.Future.value(), - ) as _i10.Future); - - @override - _i10.Future networkLogAndroid(Map? arg_data) => - (super.noSuchMethod( - Invocation.method( - #networkLogAndroid, - [arg_data], - ), - returnValue: _i10.Future.value(), - returnValueForMissingStub: _i10.Future.value(), - ) as _i10.Future); - - @override - _i10.Future startCpUiTrace( - String? arg_screenName, - int? arg_microTimeStamp, - int? arg_traceId, - ) => - (super.noSuchMethod( - Invocation.method( - #startCpUiTrace, - [ - arg_screenName, - arg_microTimeStamp, - arg_traceId, - ], - ), - returnValue: _i10.Future.value(), - returnValueForMissingStub: _i10.Future.value(), - ) as _i10.Future); - - @override - _i10.Future reportScreenLoadingCP( - int? arg_startTimeStampMicro, - int? arg_durationMicro, - int? arg_uiTraceId, - ) => - (super.noSuchMethod( - Invocation.method( - #reportScreenLoadingCP, - [ - arg_startTimeStampMicro, - arg_durationMicro, - arg_uiTraceId, - ], - ), - returnValue: _i10.Future.value(), - returnValueForMissingStub: _i10.Future.value(), - ) as _i10.Future); - - @override - _i10.Future endScreenLoadingCP( - int? arg_timeStampMicro, - int? arg_uiTraceId, - ) => - (super.noSuchMethod( - Invocation.method( - #endScreenLoadingCP, - [ - arg_timeStampMicro, - arg_uiTraceId, - ], - ), - returnValue: _i10.Future.value(), - returnValueForMissingStub: _i10.Future.value(), - ) as _i10.Future); - - @override - _i10.Future isEndScreenLoadingEnabled() => (super.noSuchMethod( - Invocation.method( - #isEndScreenLoadingEnabled, - [], - ), - returnValue: _i10.Future.value(false), - ) as _i10.Future); - - @override - _i10.Future isScreenRenderEnabled() => (super.noSuchMethod( - Invocation.method( - #isScreenRenderEnabled, - [], - ), - returnValue: _i10.Future.value(false), - ) as _i10.Future); - - @override - _i10.Future deviceRefreshRate() => (super.noSuchMethod( - Invocation.method( - #deviceRefreshRate, - [], - ), - returnValue: _i10.Future.value(0.0), - ) as _i10.Future); - - @override - _i10.Future setScreenRenderEnabled(bool? arg_isEnabled) => + Invocation.method(#reportScreenLoadingCP, + [arg_startTimeStampMicro, arg_durationMicro, arg_uiTraceId]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + + @override + _i9.Future endScreenLoadingCP( + int? arg_timeStampMicro, int? arg_uiTraceId) => (super.noSuchMethod( - Invocation.method( - #setScreenRenderEnabled, - [arg_isEnabled], - ), - returnValue: _i10.Future.value(), - returnValueForMissingStub: _i10.Future.value(), - ) as _i10.Future); + Invocation.method( + #endScreenLoadingCP, [arg_timeStampMicro, arg_uiTraceId]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + + @override + _i9.Future isEndScreenLoadingEnabled() => + (super.noSuchMethod(Invocation.method(#isEndScreenLoadingEnabled, []), + returnValue: Future.value(false)) as _i9.Future); + + @override + _i9.Future isScreenRenderEnabled() => + (super.noSuchMethod(Invocation.method(#isScreenRenderEnabled, []), + returnValue: Future.value(false)) as _i9.Future); + + @override + _i9.Future deviceRefreshRate() => + (super.noSuchMethod(Invocation.method(#deviceRefreshRate, []), + returnValue: Future.value(0.0)) as _i9.Future); + + @override + _i9.Future setScreenRenderEnabled(bool? arg_isEnabled) => (super + .noSuchMethod(Invocation.method(#setScreenRenderEnabled, [arg_isEnabled]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); } /// A class which mocks [WidgetsBinding]. /// /// See the documentation for Mockito's code generation for more information. -class MockWidgetsBinding extends _i1.Mock implements _i12.WidgetsBinding { +class MockWidgetsBinding extends _i1.Mock implements _i10.WidgetsBinding { MockWidgetsBinding() { _i1.throwOnMissingStub(this); } @override - _i2.PlatformMenuDelegate get platformMenuDelegate => (super.noSuchMethod( - Invocation.getter(#platformMenuDelegate), - returnValue: _FakePlatformMenuDelegate_1( - this, - Invocation.getter(#platformMenuDelegate), - ), - ) as _i2.PlatformMenuDelegate); + bool get debugBuildingDirtyElements => + (super.noSuchMethod(Invocation.getter(#debugBuildingDirtyElements), + returnValue: false) as bool); @override - set platformMenuDelegate(_i2.PlatformMenuDelegate? _platformMenuDelegate) => + set debugBuildingDirtyElements(bool? _debugBuildingDirtyElements) => super.noSuchMethod( - Invocation.setter( - #platformMenuDelegate, - _platformMenuDelegate, - ), - returnValueForMissingStub: null, - ); + Invocation.setter( + #debugBuildingDirtyElements, _debugBuildingDirtyElements), + returnValueForMissingStub: null); @override - bool get debugBuildingDirtyElements => (super.noSuchMethod( - Invocation.getter(#debugBuildingDirtyElements), - returnValue: false, - ) as bool); + _i2.FocusManager get focusManager => + (super.noSuchMethod(Invocation.getter(#focusManager), + returnValue: _FakeFocusManager_0()) as _i2.FocusManager); @override - set debugBuildingDirtyElements(bool? _debugBuildingDirtyElements) => - super.noSuchMethod( - Invocation.setter( - #debugBuildingDirtyElements, - _debugBuildingDirtyElements, - ), - returnValueForMissingStub: null, - ); + bool get firstFrameRasterized => + (super.noSuchMethod(Invocation.getter(#firstFrameRasterized), + returnValue: false) as bool); @override - bool get debugShowWidgetInspectorOverride => (super.noSuchMethod( - Invocation.getter(#debugShowWidgetInspectorOverride), - returnValue: false, - ) as bool); + _i9.Future get waitUntilFirstFrameRasterized => + (super.noSuchMethod(Invocation.getter(#waitUntilFirstFrameRasterized), + returnValue: Future.value()) as _i9.Future); @override - set debugShowWidgetInspectorOverride(bool? value) => super.noSuchMethod( - Invocation.setter( - #debugShowWidgetInspectorOverride, - value, - ), - returnValueForMissingStub: null, - ); + bool get debugDidSendFirstFrameEvent => + (super.noSuchMethod(Invocation.getter(#debugDidSendFirstFrameEvent), + returnValue: false) as bool); @override - _i3.ValueNotifier get debugShowWidgetInspectorOverrideNotifier => - (super.noSuchMethod( - Invocation.getter(#debugShowWidgetInspectorOverrideNotifier), - returnValue: _FakeValueNotifier_2( - this, - Invocation.getter(#debugShowWidgetInspectorOverrideNotifier), - ), - ) as _i3.ValueNotifier); + bool get framesEnabled => + (super.noSuchMethod(Invocation.getter(#framesEnabled), returnValue: false) + as bool); @override - _i3.ValueNotifier get debugWidgetInspectorSelectionOnTapEnabled => - (super.noSuchMethod( - Invocation.getter(#debugWidgetInspectorSelectionOnTapEnabled), - returnValue: _FakeValueNotifier_2( - this, - Invocation.getter(#debugWidgetInspectorSelectionOnTapEnabled), - ), - ) as _i3.ValueNotifier); + bool get isRootWidgetAttached => + (super.noSuchMethod(Invocation.getter(#isRootWidgetAttached), + returnValue: false) as bool); @override - _i4.FocusManager get focusManager => (super.noSuchMethod( - Invocation.getter(#focusManager), - returnValue: _FakeFocusManager_3( - this, - Invocation.getter(#focusManager), - ), - ) as _i4.FocusManager); + _i4.SingletonFlutterWindow get window => + (super.noSuchMethod(Invocation.getter(#window), + returnValue: _FakeSingletonFlutterWindow_1()) + as _i4.SingletonFlutterWindow); @override - bool get firstFrameRasterized => (super.noSuchMethod( - Invocation.getter(#firstFrameRasterized), - returnValue: false, - ) as bool); + _i4.PlatformDispatcher get platformDispatcher => + (super.noSuchMethod(Invocation.getter(#platformDispatcher), + returnValue: _FakePlatformDispatcher_2()) as _i4.PlatformDispatcher); @override - _i10.Future get waitUntilFirstFrameRasterized => (super.noSuchMethod( - Invocation.getter(#waitUntilFirstFrameRasterized), - returnValue: _i10.Future.value(), - ) as _i10.Future); + bool get locked => + (super.noSuchMethod(Invocation.getter(#locked), returnValue: false) + as bool); @override - bool get debugDidSendFirstFrameEvent => (super.noSuchMethod( - Invocation.getter(#debugDidSendFirstFrameEvent), - returnValue: false, - ) as bool); + _i5.HardwareKeyboard get keyboard => + (super.noSuchMethod(Invocation.getter(#keyboard), + returnValue: _FakeHardwareKeyboard_3()) as _i5.HardwareKeyboard); @override - bool get framesEnabled => (super.noSuchMethod( - Invocation.getter(#framesEnabled), - returnValue: false, - ) as bool); + _i5.KeyEventManager get keyEventManager => + (super.noSuchMethod(Invocation.getter(#keyEventManager), + returnValue: _FakeKeyEventManager_4()) as _i5.KeyEventManager); @override - bool get isRootWidgetAttached => (super.noSuchMethod( - Invocation.getter(#isRootWidgetAttached), - returnValue: false, - ) as bool); + _i5.BinaryMessenger get defaultBinaryMessenger => + (super.noSuchMethod(Invocation.getter(#defaultBinaryMessenger), + returnValue: _FakeBinaryMessenger_5()) as _i5.BinaryMessenger); @override - _i5.SingletonFlutterWindow get window => (super.noSuchMethod( - Invocation.getter(#window), - returnValue: _FakeSingletonFlutterWindow_4( - this, - Invocation.getter(#window), - ), - ) as _i5.SingletonFlutterWindow); + _i4.ChannelBuffers get channelBuffers => + (super.noSuchMethod(Invocation.getter(#channelBuffers), + returnValue: _FakeChannelBuffers_6()) as _i4.ChannelBuffers); @override - _i5.PlatformDispatcher get platformDispatcher => (super.noSuchMethod( - Invocation.getter(#platformDispatcher), - returnValue: _FakePlatformDispatcher_5( - this, - Invocation.getter(#platformDispatcher), - ), - ) as _i5.PlatformDispatcher); + _i5.RestorationManager get restorationManager => + (super.noSuchMethod(Invocation.getter(#restorationManager), + returnValue: _FakeRestorationManager_7()) as _i5.RestorationManager); @override - bool get locked => (super.noSuchMethod( - Invocation.getter(#locked), - returnValue: false, - ) as bool); + _i11.SchedulingStrategy get schedulingStrategy => + (super.noSuchMethod(Invocation.getter(#schedulingStrategy), + returnValue: ({int? priority, _i11.SchedulerBinding? scheduler}) => + false) as _i11.SchedulingStrategy); @override - _i3.ValueNotifier get accessibilityFocus => (super.noSuchMethod( - Invocation.getter(#accessibilityFocus), - returnValue: _FakeValueNotifier_2( - this, - Invocation.getter(#accessibilityFocus), - ), - ) as _i3.ValueNotifier); + set schedulingStrategy(_i11.SchedulingStrategy? _schedulingStrategy) => super + .noSuchMethod(Invocation.setter(#schedulingStrategy, _schedulingStrategy), + returnValueForMissingStub: null); @override - _i6.HardwareKeyboard get keyboard => (super.noSuchMethod( - Invocation.getter(#keyboard), - returnValue: _FakeHardwareKeyboard_6( - this, - Invocation.getter(#keyboard), - ), - ) as _i6.HardwareKeyboard); + int get transientCallbackCount => + (super.noSuchMethod(Invocation.getter(#transientCallbackCount), + returnValue: 0) as int); @override - _i6.KeyEventManager get keyEventManager => (super.noSuchMethod( - Invocation.getter(#keyEventManager), - returnValue: _FakeKeyEventManager_7( - this, - Invocation.getter(#keyEventManager), - ), - ) as _i6.KeyEventManager); + _i9.Future get endOfFrame => + (super.noSuchMethod(Invocation.getter(#endOfFrame), + returnValue: Future.value()) as _i9.Future); @override - _i6.BinaryMessenger get defaultBinaryMessenger => (super.noSuchMethod( - Invocation.getter(#defaultBinaryMessenger), - returnValue: _FakeBinaryMessenger_8( - this, - Invocation.getter(#defaultBinaryMessenger), - ), - ) as _i6.BinaryMessenger); + bool get hasScheduledFrame => + (super.noSuchMethod(Invocation.getter(#hasScheduledFrame), + returnValue: false) as bool); @override - _i5.ChannelBuffers get channelBuffers => (super.noSuchMethod( - Invocation.getter(#channelBuffers), - returnValue: _FakeChannelBuffers_9( - this, - Invocation.getter(#channelBuffers), - ), - ) as _i5.ChannelBuffers); + _i11.SchedulerPhase get schedulerPhase => + (super.noSuchMethod(Invocation.getter(#schedulerPhase), + returnValue: _i11.SchedulerPhase.idle) as _i11.SchedulerPhase); @override - _i6.RestorationManager get restorationManager => (super.noSuchMethod( - Invocation.getter(#restorationManager), - returnValue: _FakeRestorationManager_10( - this, - Invocation.getter(#restorationManager), - ), - ) as _i6.RestorationManager); + Duration get currentFrameTimeStamp => + (super.noSuchMethod(Invocation.getter(#currentFrameTimeStamp), + returnValue: _FakeDuration_8()) as Duration); @override - _i13.SchedulingStrategy get schedulingStrategy => (super.noSuchMethod( - Invocation.getter(#schedulingStrategy), - returnValue: ({ - required int priority, - required _i13.SchedulerBinding scheduler, - }) => - false, - ) as _i13.SchedulingStrategy); + Duration get currentSystemFrameTimeStamp => + (super.noSuchMethod(Invocation.getter(#currentSystemFrameTimeStamp), + returnValue: _FakeDuration_8()) as Duration); @override - set schedulingStrategy(_i13.SchedulingStrategy? _schedulingStrategy) => - super.noSuchMethod( - Invocation.setter( - #schedulingStrategy, - _schedulingStrategy, - ), - returnValueForMissingStub: null, - ); + _i6.PointerRouter get pointerRouter => + (super.noSuchMethod(Invocation.getter(#pointerRouter), + returnValue: _FakePointerRouter_9()) as _i6.PointerRouter); @override - int get transientCallbackCount => (super.noSuchMethod( - Invocation.getter(#transientCallbackCount), - returnValue: 0, - ) as int); + _i6.GestureArenaManager get gestureArena => (super.noSuchMethod( + Invocation.getter(#gestureArena), + returnValue: _FakeGestureArenaManager_10()) as _i6.GestureArenaManager); @override - _i10.Future get endOfFrame => (super.noSuchMethod( - Invocation.getter(#endOfFrame), - returnValue: _i10.Future.value(), - ) as _i10.Future); + _i6.PointerSignalResolver get pointerSignalResolver => + (super.noSuchMethod(Invocation.getter(#pointerSignalResolver), + returnValue: _FakePointerSignalResolver_11()) + as _i6.PointerSignalResolver); @override - bool get hasScheduledFrame => (super.noSuchMethod( - Invocation.getter(#hasScheduledFrame), - returnValue: false, - ) as bool); + bool get resamplingEnabled => + (super.noSuchMethod(Invocation.getter(#resamplingEnabled), + returnValue: false) as bool); @override - _i13.SchedulerPhase get schedulerPhase => (super.noSuchMethod( - Invocation.getter(#schedulerPhase), - returnValue: _i13.SchedulerPhase.idle, - ) as _i13.SchedulerPhase); + set resamplingEnabled(bool? _resamplingEnabled) => super.noSuchMethod( + Invocation.setter(#resamplingEnabled, _resamplingEnabled), + returnValueForMissingStub: null); @override - Duration get currentFrameTimeStamp => (super.noSuchMethod( - Invocation.getter(#currentFrameTimeStamp), - returnValue: _FakeDuration_0( - this, - Invocation.getter(#currentFrameTimeStamp), - ), - ) as Duration); + Duration get samplingOffset => + (super.noSuchMethod(Invocation.getter(#samplingOffset), + returnValue: _FakeDuration_8()) as Duration); @override - Duration get currentSystemFrameTimeStamp => (super.noSuchMethod( - Invocation.getter(#currentSystemFrameTimeStamp), - returnValue: _FakeDuration_0( - this, - Invocation.getter(#currentSystemFrameTimeStamp), - ), - ) as Duration); + set samplingOffset(Duration? _samplingOffset) => + super.noSuchMethod(Invocation.setter(#samplingOffset, _samplingOffset), + returnValueForMissingStub: null); @override - _i7.PointerRouter get pointerRouter => (super.noSuchMethod( - Invocation.getter(#pointerRouter), - returnValue: _FakePointerRouter_11( - this, - Invocation.getter(#pointerRouter), - ), - ) as _i7.PointerRouter); + _i7.MouseTracker get mouseTracker => + (super.noSuchMethod(Invocation.getter(#mouseTracker), + returnValue: _FakeMouseTracker_12()) as _i7.MouseTracker); @override - _i7.GestureArenaManager get gestureArena => (super.noSuchMethod( - Invocation.getter(#gestureArena), - returnValue: _FakeGestureArenaManager_12( - this, - Invocation.getter(#gestureArena), - ), - ) as _i7.GestureArenaManager); + _i7.PipelineOwner get pipelineOwner => + (super.noSuchMethod(Invocation.getter(#pipelineOwner), + returnValue: _FakePipelineOwner_13()) as _i7.PipelineOwner); @override - _i7.PointerSignalResolver get pointerSignalResolver => (super.noSuchMethod( - Invocation.getter(#pointerSignalResolver), - returnValue: _FakePointerSignalResolver_13( - this, - Invocation.getter(#pointerSignalResolver), - ), - ) as _i7.PointerSignalResolver); + _i7.RenderView get renderView => + (super.noSuchMethod(Invocation.getter(#renderView), + returnValue: _FakeRenderView_14()) as _i7.RenderView); @override - bool get resamplingEnabled => (super.noSuchMethod( - Invocation.getter(#resamplingEnabled), - returnValue: false, - ) as bool); + set renderView(_i7.RenderView? value) => + super.noSuchMethod(Invocation.setter(#renderView, value), + returnValueForMissingStub: null); @override - set resamplingEnabled(bool? _resamplingEnabled) => super.noSuchMethod( - Invocation.setter( - #resamplingEnabled, - _resamplingEnabled, - ), - returnValueForMissingStub: null, - ); - - @override - Duration get samplingOffset => (super.noSuchMethod( - Invocation.getter(#samplingOffset), - returnValue: _FakeDuration_0( - this, - Invocation.getter(#samplingOffset), - ), - ) as Duration); - - @override - set samplingOffset(Duration? _samplingOffset) => super.noSuchMethod( - Invocation.setter( - #samplingOffset, - _samplingOffset, - ), - returnValueForMissingStub: null, - ); - - @override - _i7.SamplingClock get samplingClock => (super.noSuchMethod( - Invocation.getter(#samplingClock), - returnValue: _FakeSamplingClock_14( - this, - Invocation.getter(#samplingClock), - ), - ) as _i7.SamplingClock); - - @override - _i8.PipelineOwner get pipelineOwner => (super.noSuchMethod( - Invocation.getter(#pipelineOwner), - returnValue: _i14.dummyValue<_i8.PipelineOwner>( - this, - Invocation.getter(#pipelineOwner), - ), - ) as _i8.PipelineOwner); - - @override - _i8.RenderView get renderView => (super.noSuchMethod( - Invocation.getter(#renderView), - returnValue: _FakeRenderView_15( - this, - Invocation.getter(#renderView), - ), - ) as _i8.RenderView); + bool get sendFramesToEngine => + (super.noSuchMethod(Invocation.getter(#sendFramesToEngine), + returnValue: false) as bool); @override - _i8.MouseTracker get mouseTracker => (super.noSuchMethod( - Invocation.getter(#mouseTracker), - returnValue: _FakeMouseTracker_16( - this, - Invocation.getter(#mouseTracker), - ), - ) as _i8.MouseTracker); + _i4.AccessibilityFeatures get accessibilityFeatures => + (super.noSuchMethod(Invocation.getter(#accessibilityFeatures), + returnValue: _FakeAccessibilityFeatures_15()) + as _i4.AccessibilityFeatures); @override - _i8.PipelineOwner get rootPipelineOwner => (super.noSuchMethod( - Invocation.getter(#rootPipelineOwner), - returnValue: _i14.dummyValue<_i8.PipelineOwner>( - this, - Invocation.getter(#rootPipelineOwner), - ), - ) as _i8.PipelineOwner); + bool get disableAnimations => + (super.noSuchMethod(Invocation.getter(#disableAnimations), + returnValue: false) as bool); @override - Iterable<_i8.RenderView> get renderViews => (super.noSuchMethod( - Invocation.getter(#renderViews), - returnValue: <_i8.RenderView>[], - ) as Iterable<_i8.RenderView>); + void initInstances() => + super.noSuchMethod(Invocation.method(#initInstances, []), + returnValueForMissingStub: null); @override - bool get sendFramesToEngine => (super.noSuchMethod( - Invocation.getter(#sendFramesToEngine), - returnValue: false, - ) as bool); + void initServiceExtensions() => + super.noSuchMethod(Invocation.method(#initServiceExtensions, []), + returnValueForMissingStub: null); @override - bool get semanticsEnabled => (super.noSuchMethod( - Invocation.getter(#semanticsEnabled), - returnValue: false, - ) as bool); + void addObserver(_i10.WidgetsBindingObserver? observer) => + super.noSuchMethod(Invocation.method(#addObserver, [observer]), + returnValueForMissingStub: null); @override - int get debugOutstandingSemanticsHandles => (super.noSuchMethod( - Invocation.getter(#debugOutstandingSemanticsHandles), - returnValue: 0, - ) as int); + bool removeObserver(_i10.WidgetsBindingObserver? observer) => + (super.noSuchMethod(Invocation.method(#removeObserver, [observer]), + returnValue: false) as bool); @override - _i5.AccessibilityFeatures get accessibilityFeatures => (super.noSuchMethod( - Invocation.getter(#accessibilityFeatures), - returnValue: _FakeAccessibilityFeatures_17( - this, - Invocation.getter(#accessibilityFeatures), - ), - ) as _i5.AccessibilityFeatures); + void handleMetricsChanged() => + super.noSuchMethod(Invocation.method(#handleMetricsChanged, []), + returnValueForMissingStub: null); @override - bool get disableAnimations => (super.noSuchMethod( - Invocation.getter(#disableAnimations), - returnValue: false, - ) as bool); + void handleTextScaleFactorChanged() => + super.noSuchMethod(Invocation.method(#handleTextScaleFactorChanged, []), + returnValueForMissingStub: null); @override - void initInstances() => super.noSuchMethod( - Invocation.method( - #initInstances, - [], - ), - returnValueForMissingStub: null, - ); + void handlePlatformBrightnessChanged() => super.noSuchMethod( + Invocation.method(#handlePlatformBrightnessChanged, []), + returnValueForMissingStub: null); @override - void resetInternalState() => super.noSuchMethod( - Invocation.method( - #resetInternalState, - [], - ), - returnValueForMissingStub: null, - ); + void handleAccessibilityFeaturesChanged() => super.noSuchMethod( + Invocation.method(#handleAccessibilityFeaturesChanged, []), + returnValueForMissingStub: null); @override - void initServiceExtensions() => super.noSuchMethod( - Invocation.method( - #initServiceExtensions, - [], - ), - returnValueForMissingStub: null, - ); + void handleLocaleChanged() => + super.noSuchMethod(Invocation.method(#handleLocaleChanged, []), + returnValueForMissingStub: null); @override - void addObserver(_i12.WidgetsBindingObserver? observer) => super.noSuchMethod( - Invocation.method( - #addObserver, - [observer], - ), - returnValueForMissingStub: null, - ); + void dispatchLocalesChanged(List<_i4.Locale>? locales) => + super.noSuchMethod(Invocation.method(#dispatchLocalesChanged, [locales]), + returnValueForMissingStub: null); @override - bool removeObserver(_i12.WidgetsBindingObserver? observer) => - (super.noSuchMethod( - Invocation.method( - #removeObserver, - [observer], - ), - returnValue: false, - ) as bool); + void dispatchAccessibilityFeaturesChanged() => super.noSuchMethod( + Invocation.method(#dispatchAccessibilityFeaturesChanged, []), + returnValueForMissingStub: null); @override - _i10.Future<_i5.AppExitResponse> handleRequestAppExit() => - (super.noSuchMethod( - Invocation.method( - #handleRequestAppExit, - [], - ), - returnValue: - _i10.Future<_i5.AppExitResponse>.value(_i5.AppExitResponse.exit), - ) as _i10.Future<_i5.AppExitResponse>); + _i9.Future handlePopRoute() => + (super.noSuchMethod(Invocation.method(#handlePopRoute, []), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); @override - void handleMetricsChanged() => super.noSuchMethod( - Invocation.method( - #handleMetricsChanged, - [], - ), - returnValueForMissingStub: null, - ); + _i9.Future handlePushRoute(String? route) => + (super.noSuchMethod(Invocation.method(#handlePushRoute, [route]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); @override - void handleTextScaleFactorChanged() => super.noSuchMethod( - Invocation.method( - #handleTextScaleFactorChanged, - [], - ), - returnValueForMissingStub: null, - ); + void handleAppLifecycleStateChanged(_i4.AppLifecycleState? state) => super + .noSuchMethod(Invocation.method(#handleAppLifecycleStateChanged, [state]), + returnValueForMissingStub: null); @override - void handlePlatformBrightnessChanged() => super.noSuchMethod( - Invocation.method( - #handlePlatformBrightnessChanged, - [], - ), - returnValueForMissingStub: null, - ); + void handleMemoryPressure() => + super.noSuchMethod(Invocation.method(#handleMemoryPressure, []), + returnValueForMissingStub: null); @override - void handleAccessibilityFeaturesChanged() => super.noSuchMethod( - Invocation.method( - #handleAccessibilityFeaturesChanged, - [], - ), - returnValueForMissingStub: null, - ); + void drawFrame() => super.noSuchMethod(Invocation.method(#drawFrame, []), + returnValueForMissingStub: null); @override - void handleLocaleChanged() => super.noSuchMethod( - Invocation.method( - #handleLocaleChanged, - [], - ), - returnValueForMissingStub: null, - ); + void scheduleAttachRootWidget(_i12.Widget? rootWidget) => super.noSuchMethod( + Invocation.method(#scheduleAttachRootWidget, [rootWidget]), + returnValueForMissingStub: null); @override - void dispatchLocalesChanged(List<_i5.Locale>? locales) => super.noSuchMethod( - Invocation.method( - #dispatchLocalesChanged, - [locales], - ), - returnValueForMissingStub: null, - ); + void attachRootWidget(_i12.Widget? rootWidget) => + super.noSuchMethod(Invocation.method(#attachRootWidget, [rootWidget]), + returnValueForMissingStub: null); @override - void dispatchAccessibilityFeaturesChanged() => super.noSuchMethod( - Invocation.method( - #dispatchAccessibilityFeaturesChanged, - [], - ), - returnValueForMissingStub: null, - ); + _i9.Future performReassemble() => + (super.noSuchMethod(Invocation.method(#performReassemble, []), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); @override - _i10.Future handlePopRoute() => (super.noSuchMethod( - Invocation.method( - #handlePopRoute, - [], - ), - returnValue: _i10.Future.value(false), - ) as _i10.Future); + _i4.Locale? computePlatformResolvedLocale( + List<_i4.Locale>? supportedLocales) => + (super.noSuchMethod(Invocation.method( + #computePlatformResolvedLocale, [supportedLocales])) as _i4.Locale?); @override - _i10.Future handlePushRoute(String? route) => (super.noSuchMethod( - Invocation.method( - #handlePushRoute, - [route], - ), - returnValue: _i10.Future.value(false), - ) as _i10.Future); + _i9.Future lockEvents(_i9.Future Function()? callback) => + (super.noSuchMethod(Invocation.method(#lockEvents, [callback]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); @override - void handleAppLifecycleStateChanged(_i5.AppLifecycleState? state) => - super.noSuchMethod( - Invocation.method( - #handleAppLifecycleStateChanged, - [state], - ), - returnValueForMissingStub: null, - ); - - @override - void handleViewFocusChanged(_i5.ViewFocusEvent? event) => super.noSuchMethod( - Invocation.method( - #handleViewFocusChanged, - [event], - ), - returnValueForMissingStub: null, - ); - - @override - void handleMemoryPressure() => super.noSuchMethod( - Invocation.method( - #handleMemoryPressure, - [], - ), - returnValueForMissingStub: null, - ); - - @override - void drawFrame() => super.noSuchMethod( - Invocation.method( - #drawFrame, - [], - ), - returnValueForMissingStub: null, - ); - - @override - _i9.Widget wrapWithDefaultView(_i9.Widget? rootWidget) => (super.noSuchMethod( - Invocation.method( - #wrapWithDefaultView, - [rootWidget], - ), - returnValue: _FakeWidget_18( - this, - Invocation.method( - #wrapWithDefaultView, - [rootWidget], - ), - ), - ) as _i9.Widget); - - @override - void scheduleAttachRootWidget(_i9.Widget? rootWidget) => super.noSuchMethod( - Invocation.method( - #scheduleAttachRootWidget, - [rootWidget], - ), - returnValueForMissingStub: null, - ); - - @override - void attachRootWidget(_i9.Widget? rootWidget) => super.noSuchMethod( - Invocation.method( - #attachRootWidget, - [rootWidget], - ), - returnValueForMissingStub: null, - ); - - @override - void attachToBuildOwner(_i12.RootWidget? widget) => super.noSuchMethod( - Invocation.method( - #attachToBuildOwner, - [widget], - ), - returnValueForMissingStub: null, - ); - - @override - _i10.Future performReassemble() => (super.noSuchMethod( - Invocation.method( - #performReassemble, - [], - ), - returnValue: _i10.Future.value(), - returnValueForMissingStub: _i10.Future.value(), - ) as _i10.Future); - - @override - _i5.Locale? computePlatformResolvedLocale( - List<_i5.Locale>? supportedLocales) => - (super.noSuchMethod(Invocation.method( - #computePlatformResolvedLocale, - [supportedLocales], - )) as _i5.Locale?); + void unlocked() => super.noSuchMethod(Invocation.method(#unlocked, []), + returnValueForMissingStub: null); @override - bool debugCheckZone(String? entryPoint) => (super.noSuchMethod( - Invocation.method( - #debugCheckZone, - [entryPoint], - ), - returnValue: false, - ) as bool); + _i9.Future reassembleApplication() => + (super.noSuchMethod(Invocation.method(#reassembleApplication, []), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); @override - _i10.Future lockEvents(_i10.Future Function()? callback) => - (super.noSuchMethod( - Invocation.method( - #lockEvents, - [callback], - ), - returnValue: _i10.Future.value(), - returnValueForMissingStub: _i10.Future.value(), - ) as _i10.Future); - - @override - void unlocked() => super.noSuchMethod( - Invocation.method( - #unlocked, - [], - ), - returnValueForMissingStub: null, - ); - - @override - _i10.Future reassembleApplication() => (super.noSuchMethod( - Invocation.method( - #reassembleApplication, - [], - ), - returnValue: _i10.Future.value(), - returnValueForMissingStub: _i10.Future.value(), - ) as _i10.Future); - - @override - void registerSignalServiceExtension({ - required String? name, - required _i3.AsyncCallback? callback, - }) => - super.noSuchMethod( - Invocation.method( - #registerSignalServiceExtension, - [], - { - #name: name, - #callback: callback, - }, - ), - returnValueForMissingStub: null, - ); - - @override - void registerBoolServiceExtension({ - required String? name, - required _i3.AsyncValueGetter? getter, - required _i3.AsyncValueSetter? setter, - }) => + void registerSignalServiceExtension( + {String? name, _i3.AsyncCallback? callback}) => super.noSuchMethod( - Invocation.method( - #registerBoolServiceExtension, - [], - { - #name: name, - #getter: getter, - #setter: setter, - }, - ), - returnValueForMissingStub: null, - ); - - @override - void registerNumericServiceExtension({ - required String? name, - required _i3.AsyncValueGetter? getter, - required _i3.AsyncValueSetter? setter, - }) => + Invocation.method(#registerSignalServiceExtension, [], + {#name: name, #callback: callback}), + returnValueForMissingStub: null); + + @override + void registerBoolServiceExtension( + {String? name, + _i3.AsyncValueGetter? getter, + _i3.AsyncValueSetter? setter}) => super.noSuchMethod( - Invocation.method( - #registerNumericServiceExtension, - [], - { - #name: name, - #getter: getter, - #setter: setter, - }, - ), - returnValueForMissingStub: null, - ); - - @override - void postEvent( - String? eventKind, - Map? eventData, - ) => + Invocation.method(#registerBoolServiceExtension, [], + {#name: name, #getter: getter, #setter: setter}), + returnValueForMissingStub: null); + + @override + void registerNumericServiceExtension( + {String? name, + _i3.AsyncValueGetter? getter, + _i3.AsyncValueSetter? setter}) => super.noSuchMethod( - Invocation.method( - #postEvent, - [ - eventKind, - eventData, - ], - ), - returnValueForMissingStub: null, - ); - - @override - void registerStringServiceExtension({ - required String? name, - required _i3.AsyncValueGetter? getter, - required _i3.AsyncValueSetter? setter, - }) => + Invocation.method(#registerNumericServiceExtension, [], + {#name: name, #getter: getter, #setter: setter}), + returnValueForMissingStub: null); + + @override + void postEvent(String? eventKind, Map? eventData) => + super.noSuchMethod(Invocation.method(#postEvent, [eventKind, eventData]), + returnValueForMissingStub: null); + + @override + void registerStringServiceExtension( + {String? name, + _i3.AsyncValueGetter? getter, + _i3.AsyncValueSetter? setter}) => super.noSuchMethod( - Invocation.method( - #registerStringServiceExtension, - [], - { - #name: name, - #getter: getter, - #setter: setter, - }, - ), - returnValueForMissingStub: null, - ); - - @override - void registerServiceExtension({ - required String? name, - required _i3.ServiceExtensionCallback? callback, - }) => + Invocation.method(#registerStringServiceExtension, [], + {#name: name, #getter: getter, #setter: setter}), + returnValueForMissingStub: null); + + @override + void registerServiceExtension( + {String? name, _i3.ServiceExtensionCallback? callback}) => super.noSuchMethod( - Invocation.method( - #registerServiceExtension, - [], - { - #name: name, - #callback: callback, - }, - ), - returnValueForMissingStub: null, - ); - - @override - _i6.BinaryMessenger createBinaryMessenger() => (super.noSuchMethod( - Invocation.method( - #createBinaryMessenger, - [], - ), - returnValue: _FakeBinaryMessenger_8( - this, - Invocation.method( - #createBinaryMessenger, - [], - ), - ), - ) as _i6.BinaryMessenger); + Invocation.method(#registerServiceExtension, [], + {#name: name, #callback: callback}), + returnValueForMissingStub: null); @override - _i10.Future handleSystemMessage(Object? systemMessage) => - (super.noSuchMethod( - Invocation.method( - #handleSystemMessage, - [systemMessage], - ), - returnValue: _i10.Future.value(), - returnValueForMissingStub: _i10.Future.value(), - ) as _i10.Future); + _i5.BinaryMessenger createBinaryMessenger() => + (super.noSuchMethod(Invocation.method(#createBinaryMessenger, []), + returnValue: _FakeBinaryMessenger_5()) as _i5.BinaryMessenger); @override - void initLicenses() => super.noSuchMethod( - Invocation.method( - #initLicenses, - [], - ), - returnValueForMissingStub: null, - ); + _i9.Future handleSystemMessage(Object? systemMessage) => (super + .noSuchMethod(Invocation.method(#handleSystemMessage, [systemMessage]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); @override - void evict(String? asset) => super.noSuchMethod( - Invocation.method( - #evict, - [asset], - ), - returnValueForMissingStub: null, - ); + void initLicenses() => + super.noSuchMethod(Invocation.method(#initLicenses, []), + returnValueForMissingStub: null); + + @override + void evict(String? asset) => + super.noSuchMethod(Invocation.method(#evict, [asset]), + returnValueForMissingStub: null); @override void readInitialLifecycleStateFromNativeWindow() => super.noSuchMethod( - Invocation.method( - #readInitialLifecycleStateFromNativeWindow, - [], - ), - returnValueForMissingStub: null, - ); - - @override - _i10.Future<_i5.AppExitResponse> exitApplication( - _i5.AppExitType? exitType, [ - int? exitCode = 0, - ]) => - (super.noSuchMethod( - Invocation.method( - #exitApplication, - [ - exitType, - exitCode, - ], - ), - returnValue: - _i10.Future<_i5.AppExitResponse>.value(_i5.AppExitResponse.exit), - ) as _i10.Future<_i5.AppExitResponse>); - - @override - _i6.RestorationManager createRestorationManager() => (super.noSuchMethod( - Invocation.method( - #createRestorationManager, - [], - ), - returnValue: _FakeRestorationManager_10( - this, - Invocation.method( - #createRestorationManager, - [], - ), - ), - ) as _i6.RestorationManager); + Invocation.method(#readInitialLifecycleStateFromNativeWindow, []), + returnValueForMissingStub: null); @override - void setSystemUiChangeCallback(_i6.SystemUiChangeCallback? callback) => - super.noSuchMethod( - Invocation.method( - #setSystemUiChangeCallback, - [callback], - ), - returnValueForMissingStub: null, - ); - - @override - _i10.Future initializationComplete() => (super.noSuchMethod( - Invocation.method( - #initializationComplete, - [], - ), - returnValue: _i10.Future.value(), - returnValueForMissingStub: _i10.Future.value(), - ) as _i10.Future); - - @override - void addTimingsCallback(_i5.TimingsCallback? callback) => super.noSuchMethod( - Invocation.method( - #addTimingsCallback, - [callback], - ), - returnValueForMissingStub: null, - ); - - @override - void removeTimingsCallback(_i5.TimingsCallback? callback) => - super.noSuchMethod( - Invocation.method( - #removeTimingsCallback, - [callback], - ), - returnValueForMissingStub: null, - ); - - @override - _i10.Future scheduleTask( - _i13.TaskCallback? task, - _i13.Priority? priority, { - String? debugLabel, - _i15.Flow? flow, - }) => + _i5.RestorationManager createRestorationManager() => + (super.noSuchMethod(Invocation.method(#createRestorationManager, []), + returnValue: _FakeRestorationManager_7()) as _i5.RestorationManager); + + @override + void setSystemUiChangeCallback(_i5.SystemUiChangeCallback? callback) => super + .noSuchMethod(Invocation.method(#setSystemUiChangeCallback, [callback]), + returnValueForMissingStub: null); + + @override + void addTimingsCallback(_i4.TimingsCallback? callback) => + super.noSuchMethod(Invocation.method(#addTimingsCallback, [callback]), + returnValueForMissingStub: null); + + @override + void removeTimingsCallback(_i4.TimingsCallback? callback) => + super.noSuchMethod(Invocation.method(#removeTimingsCallback, [callback]), + returnValueForMissingStub: null); + + @override + _i9.Future scheduleTask( + _i11.TaskCallback? task, _i11.Priority? priority, + {String? debugLabel, _i13.Flow? flow}) => (super.noSuchMethod( - Invocation.method( - #scheduleTask, - [ - task, - priority, - ], - { - #debugLabel: debugLabel, - #flow: flow, - }, - ), - returnValue: _i14.ifNotNull( - _i14.dummyValueOrNull( - this, - Invocation.method( - #scheduleTask, - [ - task, - priority, - ], - { - #debugLabel: debugLabel, - #flow: flow, - }, - ), - ), - (T v) => _i10.Future.value(v), - ) ?? - _FakeFuture_19( - this, - Invocation.method( - #scheduleTask, - [ - task, - priority, - ], - { - #debugLabel: debugLabel, - #flow: flow, - }, - ), - ), - ) as _i10.Future); - - @override - bool handleEventLoopCallback() => (super.noSuchMethod( - Invocation.method( - #handleEventLoopCallback, - [], - ), - returnValue: false, - ) as bool); - - @override - int scheduleFrameCallback( - _i13.FrameCallback? callback, { - bool? rescheduling = false, - bool? scheduleNewFrame = true, - }) => + Invocation.method(#scheduleTask, [task, priority], + {#debugLabel: debugLabel, #flow: flow}), + returnValue: Future.value(null)) as _i9.Future); + + @override + bool handleEventLoopCallback() => + (super.noSuchMethod(Invocation.method(#handleEventLoopCallback, []), + returnValue: false) as bool); + + @override + int scheduleFrameCallback(_i11.FrameCallback? callback, + {bool? rescheduling = false}) => (super.noSuchMethod( - Invocation.method( - #scheduleFrameCallback, - [callback], - { - #rescheduling: rescheduling, - #scheduleNewFrame: scheduleNewFrame, - }, - ), - returnValue: 0, - ) as int); - - @override - void cancelFrameCallbackWithId(int? id) => super.noSuchMethod( - Invocation.method( - #cancelFrameCallbackWithId, - [id], - ), - returnValueForMissingStub: null, - ); + Invocation.method(#scheduleFrameCallback, [callback], + {#rescheduling: rescheduling}), + returnValue: 0) as int); + + @override + void cancelFrameCallbackWithId(int? id) => + super.noSuchMethod(Invocation.method(#cancelFrameCallbackWithId, [id]), + returnValueForMissingStub: null); @override bool debugAssertNoTransientCallbacks(String? reason) => (super.noSuchMethod( - Invocation.method( - #debugAssertNoTransientCallbacks, - [reason], - ), - returnValue: false, - ) as bool); + Invocation.method(#debugAssertNoTransientCallbacks, [reason]), + returnValue: false) as bool); @override - bool debugAssertNoPendingPerformanceModeRequests(String? reason) => - (super.noSuchMethod( - Invocation.method( - #debugAssertNoPendingPerformanceModeRequests, - [reason], - ), - returnValue: false, - ) as bool); + void addPersistentFrameCallback(_i11.FrameCallback? callback) => super + .noSuchMethod(Invocation.method(#addPersistentFrameCallback, [callback]), + returnValueForMissingStub: null); @override - bool debugAssertNoTimeDilation(String? reason) => (super.noSuchMethod( - Invocation.method( - #debugAssertNoTimeDilation, - [reason], - ), - returnValue: false, - ) as bool); + void addPostFrameCallback(_i11.FrameCallback? callback) => + super.noSuchMethod(Invocation.method(#addPostFrameCallback, [callback]), + returnValueForMissingStub: null); @override - void addPersistentFrameCallback(_i13.FrameCallback? callback) => - super.noSuchMethod( - Invocation.method( - #addPersistentFrameCallback, - [callback], - ), - returnValueForMissingStub: null, - ); - - @override - void addPostFrameCallback( - _i13.FrameCallback? callback, { - String? debugLabel = r'callback', - }) => - super.noSuchMethod( - Invocation.method( - #addPostFrameCallback, - [callback], - {#debugLabel: debugLabel}, - ), - returnValueForMissingStub: null, - ); - - @override - void ensureFrameCallbacksRegistered() => super.noSuchMethod( - Invocation.method( - #ensureFrameCallbacksRegistered, - [], - ), - returnValueForMissingStub: null, - ); - - @override - void ensureVisualUpdate() => super.noSuchMethod( - Invocation.method( - #ensureVisualUpdate, - [], - ), - returnValueForMissingStub: null, - ); - - @override - void scheduleFrame() => super.noSuchMethod( - Invocation.method( - #scheduleFrame, - [], - ), - returnValueForMissingStub: null, - ); - - @override - void scheduleForcedFrame() => super.noSuchMethod( - Invocation.method( - #scheduleForcedFrame, - [], - ), - returnValueForMissingStub: null, - ); - - @override - void scheduleWarmUpFrame() => super.noSuchMethod( - Invocation.method( - #scheduleWarmUpFrame, - [], - ), - returnValueForMissingStub: null, - ); - - @override - void resetEpoch() => super.noSuchMethod( - Invocation.method( - #resetEpoch, - [], - ), - returnValueForMissingStub: null, - ); - - @override - void handleBeginFrame(Duration? rawTimeStamp) => super.noSuchMethod( - Invocation.method( - #handleBeginFrame, - [rawTimeStamp], - ), - returnValueForMissingStub: null, - ); - - @override - _i13.PerformanceModeRequestHandle? requestPerformanceMode( - _i5.DartPerformanceMode? mode) => - (super.noSuchMethod(Invocation.method( - #requestPerformanceMode, - [mode], - )) as _i13.PerformanceModeRequestHandle?); - - @override - void handleDrawFrame() => super.noSuchMethod( - Invocation.method( - #handleDrawFrame, - [], - ), - returnValueForMissingStub: null, - ); - - @override - void cancelPointer(int? pointer) => super.noSuchMethod( - Invocation.method( - #cancelPointer, - [pointer], - ), - returnValueForMissingStub: null, - ); - - @override - void handlePointerEvent(_i6.PointerEvent? event) => super.noSuchMethod( - Invocation.method( - #handlePointerEvent, - [event], - ), - returnValueForMissingStub: null, - ); - - @override - void hitTestInView( - _i7.HitTestResult? result, - _i5.Offset? position, - int? viewId, - ) => - super.noSuchMethod( - Invocation.method( - #hitTestInView, - [ - result, - position, - viewId, - ], - ), - returnValueForMissingStub: null, - ); - - @override - void hitTest( - _i7.HitTestResult? result, - _i5.Offset? position, - ) => - super.noSuchMethod( - Invocation.method( - #hitTest, - [ - result, - position, - ], - ), - returnValueForMissingStub: null, - ); + void ensureFrameCallbacksRegistered() => + super.noSuchMethod(Invocation.method(#ensureFrameCallbacksRegistered, []), + returnValueForMissingStub: null); + + @override + void ensureVisualUpdate() => + super.noSuchMethod(Invocation.method(#ensureVisualUpdate, []), + returnValueForMissingStub: null); + + @override + void scheduleFrame() => + super.noSuchMethod(Invocation.method(#scheduleFrame, []), + returnValueForMissingStub: null); + + @override + void scheduleForcedFrame() => + super.noSuchMethod(Invocation.method(#scheduleForcedFrame, []), + returnValueForMissingStub: null); + + @override + void scheduleWarmUpFrame() => + super.noSuchMethod(Invocation.method(#scheduleWarmUpFrame, []), + returnValueForMissingStub: null); + + @override + void resetEpoch() => super.noSuchMethod(Invocation.method(#resetEpoch, []), + returnValueForMissingStub: null); + + @override + void handleBeginFrame(Duration? rawTimeStamp) => + super.noSuchMethod(Invocation.method(#handleBeginFrame, [rawTimeStamp]), + returnValueForMissingStub: null); + + @override + void handleDrawFrame() => + super.noSuchMethod(Invocation.method(#handleDrawFrame, []), + returnValueForMissingStub: null); + + @override + void cancelPointer(int? pointer) => + super.noSuchMethod(Invocation.method(#cancelPointer, [pointer]), + returnValueForMissingStub: null); + + @override + void handlePointerEvent(_i6.PointerEvent? event) => + super.noSuchMethod(Invocation.method(#handlePointerEvent, [event]), + returnValueForMissingStub: null); + + @override + void hitTest(_i6.HitTestResult? result, _i4.Offset? position) => + super.noSuchMethod(Invocation.method(#hitTest, [result, position]), + returnValueForMissingStub: null); @override void dispatchEvent( - _i6.PointerEvent? event, - _i7.HitTestResult? hitTestResult, - ) => - super.noSuchMethod( - Invocation.method( - #dispatchEvent, - [ - event, - hitTestResult, - ], - ), - returnValueForMissingStub: null, - ); - - @override - void handleEvent( - _i6.PointerEvent? event, - _i7.HitTestEntry<_i7.HitTestTarget>? entry, - ) => + _i6.PointerEvent? event, _i6.HitTestResult? hitTestResult) => super.noSuchMethod( - Invocation.method( - #handleEvent, - [ - event, - entry, - ], - ), - returnValueForMissingStub: null, - ); - - @override - void resetGestureBinding() => super.noSuchMethod( - Invocation.method( - #resetGestureBinding, - [], - ), - returnValueForMissingStub: null, - ); - - @override - _i8.PipelineOwner createRootPipelineOwner() => (super.noSuchMethod( - Invocation.method( - #createRootPipelineOwner, - [], - ), - returnValue: _i14.dummyValue<_i8.PipelineOwner>( - this, - Invocation.method( - #createRootPipelineOwner, - [], - ), - ), - ) as _i8.PipelineOwner); + Invocation.method(#dispatchEvent, [event, hitTestResult]), + returnValueForMissingStub: null); @override - void addRenderView(_i8.RenderView? view) => super.noSuchMethod( - Invocation.method( - #addRenderView, - [view], - ), - returnValueForMissingStub: null, - ); + void handleEvent(_i6.PointerEvent? event, _i6.HitTestEntry? entry) => + super.noSuchMethod(Invocation.method(#handleEvent, [event, entry]), + returnValueForMissingStub: null); @override - void removeRenderView(_i8.RenderView? view) => super.noSuchMethod( - Invocation.method( - #removeRenderView, - [view], - ), - returnValueForMissingStub: null, - ); + void resetGestureBinding() => + super.noSuchMethod(Invocation.method(#resetGestureBinding, []), + returnValueForMissingStub: null); @override - _i8.ViewConfiguration createViewConfigurationFor( - _i8.RenderView? renderView) => - (super.noSuchMethod( - Invocation.method( - #createViewConfigurationFor, - [renderView], - ), - returnValue: _FakeViewConfiguration_20( - this, - Invocation.method( - #createViewConfigurationFor, - [renderView], - ), - ), - ) as _i8.ViewConfiguration); - - @override - _i5.SceneBuilder createSceneBuilder() => (super.noSuchMethod( - Invocation.method( - #createSceneBuilder, - [], - ), - returnValue: _FakeSceneBuilder_21( - this, - Invocation.method( - #createSceneBuilder, - [], - ), - ), - ) as _i5.SceneBuilder); - - @override - _i5.PictureRecorder createPictureRecorder() => (super.noSuchMethod( - Invocation.method( - #createPictureRecorder, - [], - ), - returnValue: _FakePictureRecorder_22( - this, - Invocation.method( - #createPictureRecorder, - [], - ), - ), - ) as _i5.PictureRecorder); - - @override - _i5.Canvas createCanvas(_i5.PictureRecorder? recorder) => (super.noSuchMethod( - Invocation.method( - #createCanvas, - [recorder], - ), - returnValue: _FakeCanvas_23( - this, - Invocation.method( - #createCanvas, - [recorder], - ), - ), - ) as _i5.Canvas); + void initRenderView() => + super.noSuchMethod(Invocation.method(#initRenderView, []), + returnValueForMissingStub: null); @override - void initMouseTracker([_i8.MouseTracker? tracker]) => super.noSuchMethod( - Invocation.method( - #initMouseTracker, - [tracker], - ), - returnValueForMissingStub: null, - ); + _i7.ViewConfiguration createViewConfiguration() => + (super.noSuchMethod(Invocation.method(#createViewConfiguration, []), + returnValue: _FakeViewConfiguration_16()) as _i7.ViewConfiguration); @override - void performSemanticsAction(_i5.SemanticsActionEvent? action) => - super.noSuchMethod( - Invocation.method( - #performSemanticsAction, - [action], - ), - returnValueForMissingStub: null, - ); - - @override - void deferFirstFrame() => super.noSuchMethod( - Invocation.method( - #deferFirstFrame, - [], - ), - returnValueForMissingStub: null, - ); - - @override - void allowFirstFrame() => super.noSuchMethod( - Invocation.method( - #allowFirstFrame, - [], - ), - returnValueForMissingStub: null, - ); - - @override - void resetFirstFrameSent() => super.noSuchMethod( - Invocation.method( - #resetFirstFrameSent, - [], - ), - returnValueForMissingStub: null, - ); - - @override - void addSemanticsEnabledListener(_i5.VoidCallback? listener) => - super.noSuchMethod( - Invocation.method( - #addSemanticsEnabledListener, - [listener], - ), - returnValueForMissingStub: null, - ); + void initMouseTracker([_i7.MouseTracker? tracker]) => + super.noSuchMethod(Invocation.method(#initMouseTracker, [tracker]), + returnValueForMissingStub: null); @override - void removeSemanticsEnabledListener(_i5.VoidCallback? listener) => - super.noSuchMethod( - Invocation.method( - #removeSemanticsEnabledListener, - [listener], - ), - returnValueForMissingStub: null, - ); + void setSemanticsEnabled(bool? enabled) => + super.noSuchMethod(Invocation.method(#setSemanticsEnabled, [enabled]), + returnValueForMissingStub: null); @override - void addSemanticsActionListener( - _i3.ValueSetter<_i5.SemanticsActionEvent>? listener) => - super.noSuchMethod( - Invocation.method( - #addSemanticsActionListener, - [listener], - ), - returnValueForMissingStub: null, - ); + void deferFirstFrame() => + super.noSuchMethod(Invocation.method(#deferFirstFrame, []), + returnValueForMissingStub: null); @override - void removeSemanticsActionListener( - _i3.ValueSetter<_i5.SemanticsActionEvent>? listener) => - super.noSuchMethod( - Invocation.method( - #removeSemanticsActionListener, - [listener], - ), - returnValueForMissingStub: null, - ); - - @override - _i8.SemanticsHandle ensureSemantics() => (super.noSuchMethod( - Invocation.method( - #ensureSemantics, - [], - ), - returnValue: _FakeSemanticsHandle_24( - this, - Invocation.method( - #ensureSemantics, - [], - ), - ), - ) as _i8.SemanticsHandle); + void allowFirstFrame() => + super.noSuchMethod(Invocation.method(#allowFirstFrame, []), + returnValueForMissingStub: null); @override - _i5.SemanticsUpdateBuilder createSemanticsUpdateBuilder() => - (super.noSuchMethod( - Invocation.method( - #createSemanticsUpdateBuilder, - [], - ), - returnValue: _FakeSemanticsUpdateBuilder_25( - this, - Invocation.method( - #createSemanticsUpdateBuilder, - [], - ), - ), - ) as _i5.SemanticsUpdateBuilder); + void resetFirstFrameSent() => + super.noSuchMethod(Invocation.method(#resetFirstFrameSent, []), + returnValueForMissingStub: null); + + @override + _i4.SemanticsUpdateBuilder createSemanticsUpdateBuilder() => + (super.noSuchMethod(Invocation.method(#createSemanticsUpdateBuilder, []), + returnValue: _FakeSemanticsUpdateBuilder_17()) + as _i4.SemanticsUpdateBuilder); +} + +/// A class which mocks [FrameTiming]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockFrameTiming extends _i1.Mock implements _i4.FrameTiming { + MockFrameTiming() { + _i1.throwOnMissingStub(this); + } + + @override + Duration get buildDuration => + (super.noSuchMethod(Invocation.getter(#buildDuration), + returnValue: _FakeDuration_8()) as Duration); + + @override + Duration get rasterDuration => + (super.noSuchMethod(Invocation.getter(#rasterDuration), + returnValue: _FakeDuration_8()) as Duration); + + @override + Duration get vsyncOverhead => + (super.noSuchMethod(Invocation.getter(#vsyncOverhead), + returnValue: _FakeDuration_8()) as Duration); + + @override + Duration get totalSpan => (super.noSuchMethod(Invocation.getter(#totalSpan), + returnValue: _FakeDuration_8()) as Duration); + + @override + int get layerCacheCount => + (super.noSuchMethod(Invocation.getter(#layerCacheCount), returnValue: 0) + as int); + + @override + int get layerCacheBytes => + (super.noSuchMethod(Invocation.getter(#layerCacheBytes), returnValue: 0) + as int); + + @override + double get layerCacheMegabytes => + (super.noSuchMethod(Invocation.getter(#layerCacheMegabytes), + returnValue: 0.0) as double); + + @override + int get pictureCacheCount => + (super.noSuchMethod(Invocation.getter(#pictureCacheCount), returnValue: 0) + as int); + + @override + int get pictureCacheBytes => + (super.noSuchMethod(Invocation.getter(#pictureCacheBytes), returnValue: 0) + as int); + + @override + double get pictureCacheMegabytes => + (super.noSuchMethod(Invocation.getter(#pictureCacheMegabytes), + returnValue: 0.0) as double); + + @override + int get frameNumber => + (super.noSuchMethod(Invocation.getter(#frameNumber), returnValue: 0) + as int); + + @override + int timestampInMicroseconds(_i4.FramePhase? phase) => + (super.noSuchMethod(Invocation.method(#timestampInMicroseconds, [phase]), + returnValue: 0) as int); } From 2ae2acccdaf2634cd27e487424b0100a7db870eb Mon Sep 17 00:00:00 2001 From: Ahmed alaa Date: Tue, 1 Jul 2025 14:18:22 +0300 Subject: [PATCH 15/84] fix: dart format --- .../instabug_screen_render_manager_test_manual_mocks.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/utils/screen_render/instabug_screen_render_manager_test_manual_mocks.dart b/test/utils/screen_render/instabug_screen_render_manager_test_manual_mocks.dart index dcc87eaab..35f21c850 100644 --- a/test/utils/screen_render/instabug_screen_render_manager_test_manual_mocks.dart +++ b/test/utils/screen_render/instabug_screen_render_manager_test_manual_mocks.dart @@ -39,8 +39,8 @@ class _FakeSingletonFlutterWindow_1 extends _i1.Fake class _FakePlatformDispatcher_2 extends _i1.Fake implements _i4.PlatformDispatcher {} -class _FakeHardwareKeyboard_3 extends _i1.Fake implements _i5.HardwareKeyboard { -} +class _FakeHardwareKeyboard_3 extends _i1.Fake + implements _i5.HardwareKeyboard {} class _FakeKeyEventManager_4 extends _i1.Fake implements _i5.KeyEventManager {} From 86cb8bed994f242ddb7ee86ab54a8451b44a9eb0 Mon Sep 17 00:00:00 2001 From: Andrew Amin Date: Wed, 2 Jul 2025 14:33:05 +0300 Subject: [PATCH 16/84] chore: add ios store pod --- example/ios/Podfile | 4 +- example/ios/Podfile.lock | 14 +- example/pubspec.lock | 189 ++-- ios/Classes/Modules/ApmApi.m | 55 +- ios/Classes/Util/IBGAPM+PrivateAPIs.h | 5 + ios/instabug_flutter.podspec | 2 +- lib/src/models/instabug_frame_data.dart | 3 + .../models/instabug_screen_render_data.dart | 11 + lib/src/modules/apm.dart | 29 + pigeons/apm.api.dart | 17 + .../instabug_screen_render_manager_test.dart | 5 +- ...reen_render_manager_test_manual_mocks.dart | 882 ------------------ 12 files changed, 207 insertions(+), 1009 deletions(-) delete mode 100644 test/utils/screen_render/instabug_screen_render_manager_test_manual_mocks.dart diff --git a/example/ios/Podfile b/example/ios/Podfile index f72ca45fe..85792c734 100644 --- a/example/ios/Podfile +++ b/example/ios/Podfile @@ -30,9 +30,7 @@ target 'Runner' do use_frameworks! use_modular_headers! -# pod 'Instabug', :podspec => 'https://ios-releases.instabug.com/custom/fix-main-thread-warning/15.0.0/Instabug.podspec' - pod 'Instabug', :podspec => 'https://ios-releases.instabug.com/custom/faeture-screen_rendering-release/15.1.0/Instabug.podspec' - + pod 'Instabug', :podspec => 'https://ios-releases.instabug.com/custom/faeture-screen_rendering-release/15.1.6/Instabug.podspec' flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) end diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index 8dad08077..62bbff217 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -1,14 +1,14 @@ PODS: - Flutter (1.0.0) - - Instabug (15.1.0) + - Instabug (15.1.6) - instabug_flutter (14.3.0): - Flutter - - Instabug (= 15.1.0) + - Instabug (= 15.1.6) - OCMock (3.6) DEPENDENCIES: - Flutter (from `Flutter`) - - Instabug (from `https://ios-releases.instabug.com/custom/faeture-screen_rendering-release/15.1.0/Instabug.podspec`) + - Instabug (from `https://ios-releases.instabug.com/custom/faeture-screen_rendering-release/15.1.6/Instabug.podspec`) - instabug_flutter (from `.symlinks/plugins/instabug_flutter/ios`) - OCMock (= 3.6) @@ -20,16 +20,16 @@ EXTERNAL SOURCES: Flutter: :path: Flutter Instabug: - :podspec: https://ios-releases.instabug.com/custom/faeture-screen_rendering-release/15.1.0/Instabug.podspec + :podspec: https://ios-releases.instabug.com/custom/faeture-screen_rendering-release/15.1.6/Instabug.podspec instabug_flutter: :path: ".symlinks/plugins/instabug_flutter/ios" SPEC CHECKSUMS: Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 - Instabug: a2b8c384cd4af7a01ab43b2ce2957a880f8862d7 - instabug_flutter: 6ee721f30066123a769da64b687eded6eb4ff125 + Instabug: 160e6c775d933adcb577bb6b0246392d4e2c7796 + instabug_flutter: 8dd37e80d4f4883723b7f7b211e3f1907d85e5d3 OCMock: 5ea90566be239f179ba766fd9fbae5885040b992 -PODFILE CHECKSUM: e6e180d6b55e3a12f55f266c3f4d8654480877ef +PODFILE CHECKSUM: 96100ba35e9247b6dd1f0e51d13d3880f140fb35 COCOAPODS: 1.15.2 diff --git a/example/pubspec.lock b/example/pubspec.lock index db618bb81..74b4b6b46 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -1,76 +1,62 @@ # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: - archive: - dependency: transitive - description: - name: archive - url: "https://pub.dartlang.org" - source: hosted - version: "3.1.6" async: dependency: transitive description: name: async - url: "https://pub.dartlang.org" + sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb" + url: "https://pub.dev" source: hosted - version: "2.8.2" + version: "2.13.0" boolean_selector: dependency: transitive description: name: boolean_selector - url: "https://pub.dartlang.org" + sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.2" characters: dependency: transitive description: name: characters - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.0" - charcode: - dependency: transitive - description: - name: charcode - url: "https://pub.dartlang.org" + sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 + url: "https://pub.dev" source: hosted - version: "1.3.1" + version: "1.4.0" clock: dependency: transitive description: name: clock - url: "https://pub.dartlang.org" + sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b + url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.1.2" collection: dependency: transitive description: name: collection - url: "https://pub.dartlang.org" + sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" + url: "https://pub.dev" source: hosted - version: "1.15.0" - crypto: - dependency: transitive - description: - name: crypto - url: "https://pub.dartlang.org" - source: hosted - version: "3.0.1" + version: "1.19.1" fake_async: dependency: transitive description: name: fake_async - url: "https://pub.dartlang.org" + sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" + url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.3.3" file: dependency: transitive description: name: file - url: "https://pub.dartlang.org" + sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 + url: "https://pub.dev" source: hosted - version: "6.1.2" + version: "7.0.1" flutter: dependency: "direct main" description: flutter @@ -85,7 +71,8 @@ packages: dependency: "direct dev" description: name: flutter_lints - url: "https://pub.dartlang.org" + sha256: b543301ad291598523947dc534aaddc5aaad597b709d2426d3a0e0d44c5cb493 + url: "https://pub.dev" source: hosted version: "1.0.4" flutter_test: @@ -102,16 +89,18 @@ packages: dependency: "direct main" description: name: http - url: "https://pub.dartlang.org" + sha256: "5895291c13fa8a3bd82e76d5627f69e0d85ca6a30dcac95c4ea19a5d555879c2" + url: "https://pub.dev" source: hosted - version: "0.13.5" + version: "0.13.6" http_parser: dependency: transitive description: name: http_parser - url: "https://pub.dartlang.org" + sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571" + url: "https://pub.dev" source: hosted - version: "4.0.2" + version: "4.1.2" instabug_flutter: dependency: "direct main" description: @@ -123,139 +112,183 @@ packages: dependency: "direct main" description: name: instabug_http_client - url: "https://pub.dartlang.org" + sha256: "97a6ab88491eff87e42437564b528d6986a65eb3f3262f73373009f949cb4560" + url: "https://pub.dev" source: hosted version: "2.5.1" + leak_tracker: + dependency: transitive + description: + name: leak_tracker + sha256: "6bb818ecbdffe216e81182c2f0714a2e62b593f4a4f13098713ff1685dfb6ab0" + url: "https://pub.dev" + source: hosted + version: "10.0.9" + leak_tracker_flutter_testing: + dependency: transitive + description: + name: leak_tracker_flutter_testing + sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573 + url: "https://pub.dev" + source: hosted + version: "3.0.9" + leak_tracker_testing: + dependency: transitive + description: + name: leak_tracker_testing + sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" + url: "https://pub.dev" + source: hosted + version: "3.0.1" lints: dependency: transitive description: name: lints - url: "https://pub.dartlang.org" + sha256: a2c3d198cb5ea2e179926622d433331d8b58374ab8f29cdda6e863bd62fd369c + url: "https://pub.dev" source: hosted version: "1.0.1" matcher: dependency: transitive description: name: matcher - url: "https://pub.dartlang.org" + sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 + url: "https://pub.dev" source: hosted - version: "0.12.11" + version: "0.12.17" material_color_utilities: dependency: transitive description: name: material_color_utilities - url: "https://pub.dartlang.org" + sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec + url: "https://pub.dev" source: hosted - version: "0.1.3" + version: "0.11.1" meta: dependency: transitive description: name: meta - url: "https://pub.dartlang.org" + sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c + url: "https://pub.dev" source: hosted - version: "1.7.0" + version: "1.16.0" path: dependency: transitive description: name: path - url: "https://pub.dartlang.org" + sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" + url: "https://pub.dev" source: hosted - version: "1.8.0" + version: "1.9.1" platform: dependency: transitive description: name: platform - url: "https://pub.dartlang.org" + sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984" + url: "https://pub.dev" source: hosted - version: "3.1.0" + version: "3.1.6" process: dependency: transitive description: name: process - url: "https://pub.dartlang.org" + sha256: "107d8be718f120bbba9dcd1e95e3bd325b1b4a4f07db64154635ba03f2567a0d" + url: "https://pub.dev" source: hosted - version: "4.2.4" + version: "5.0.3" sky_engine: dependency: transitive description: flutter source: sdk - version: "0.0.99" + version: "0.0.0" source_span: dependency: transitive description: name: source_span - url: "https://pub.dartlang.org" + sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c" + url: "https://pub.dev" source: hosted - version: "1.8.1" + version: "1.10.1" stack_trace: dependency: transitive description: name: stack_trace - url: "https://pub.dartlang.org" + sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" + url: "https://pub.dev" source: hosted - version: "1.10.0" + version: "1.12.1" stream_channel: dependency: transitive description: name: stream_channel - url: "https://pub.dartlang.org" + sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.4" string_scanner: dependency: transitive description: name: string_scanner - url: "https://pub.dartlang.org" + sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" + url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.4.1" sync_http: dependency: transitive description: name: sync_http - url: "https://pub.dartlang.org" + sha256: "7f0cd72eca000d2e026bcd6f990b81d0ca06022ef4e32fb257b30d3d1014a961" + url: "https://pub.dev" source: hosted - version: "0.3.0" + version: "0.3.1" term_glyph: dependency: transitive description: name: term_glyph - url: "https://pub.dartlang.org" + sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" + url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.2.2" test_api: dependency: transitive description: name: test_api - url: "https://pub.dartlang.org" + sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd + url: "https://pub.dev" source: hosted - version: "0.4.8" + version: "0.7.4" typed_data: dependency: transitive description: name: typed_data - url: "https://pub.dartlang.org" + sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 + url: "https://pub.dev" source: hosted - version: "1.3.0" + version: "1.4.0" vector_math: dependency: transitive description: name: vector_math - url: "https://pub.dartlang.org" + sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.4" vm_service: dependency: transitive description: name: vm_service - url: "https://pub.dartlang.org" + sha256: ddfa8d30d89985b96407efce8acbdd124701f96741f2d981ca860662f1c0dc02 + url: "https://pub.dev" source: hosted - version: "7.5.0" + version: "15.0.0" webdriver: dependency: transitive description: name: webdriver - url: "https://pub.dartlang.org" + sha256: "2f3a14ca026957870cfd9c635b83507e0e51d8091568e90129fbf805aba7cade" + url: "https://pub.dev" source: hosted - version: "3.0.0" + version: "3.1.0" sdks: - dart: ">=2.14.0 <3.0.0" + dart: ">=3.7.0-0 <4.0.0" + flutter: ">=3.18.0-18.0.pre.54" diff --git a/ios/Classes/Modules/ApmApi.m b/ios/Classes/Modules/ApmApi.m index f82219770..699f07b40 100644 --- a/ios/Classes/Modules/ApmApi.m +++ b/ios/Classes/Modules/ApmApi.m @@ -3,6 +3,7 @@ #import "ArgsRegistry.h" #import "IBGAPM+PrivateAPIs.h" #import "IBGTimeIntervalUnits.h" +#import "IBGFrameInfo.h" void InitApmApi(id messenger) { ApmApi *api = [[ApmApi alloc] init]; @@ -209,41 +210,6 @@ - (void)setScreenRenderEnabledIsEnabled:(nonnull NSNumber *)isEnabled error:(Flu } - (void)deviceRefreshRateWithCompletion:(void (^)(NSNumber * _Nullable, FlutterError * _Nullable))completion{ - // First, try using CADisplayLink to get the preferred frame rate. - // This is a more modern approach, especially for ProMotion displays. - CADisplayLink *displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(onDisplayLink:)]; - displayLink.paused = YES; - [displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes]; - - double preferredFPS = displayLink.preferredFramesPerSecond; - - [displayLink invalidate]; - - if (preferredFPS != 0) { - completion(@(preferredFPS) , nil); - return; - } - - // If CADisplayLink fails, fall back to other methods. - // For iOS 13+, use the windowScene for better accuracy in multi-window environments. - if (@available(iOS 13.0, *)) { - UIWindowScene *windowScene = nil; - // Find the first active window scene - for (UIScene *scene in [UIApplication sharedApplication].connectedScenes) { - if (scene.activationState == UISceneActivationStateForegroundActive && [scene isKindOfClass:[UIWindowScene class]]) { - windowScene = (UIWindowScene *)scene; - break; - } - } - - if (windowScene) { - double preferredFPS = windowScene.screen.maximumFramesPerSecond; - completion(@(preferredFPS) , nil); - return; - } - } - - // As a final fallback (and for iOS versions < 13), use the main screen. if (@available(iOS 10.3, *)) { double refreshRate = [UIScreen mainScreen].maximumFramesPerSecond; completion(@(refreshRate) ,nil); @@ -253,5 +219,24 @@ - (void)deviceRefreshRateWithCompletion:(void (^)(NSNumber * _Nullable, FlutterE } } +- (void)endScreenRenderForAutoUiTraceData:(nonnull NSDictionary *)data error:(FlutterError * _Nullable __autoreleasing * _Nonnull)error { + int traceId = [data[@"traceId"] intValue]; + int slowFrames = [data[@"slowFramesTotalDuration"] intValue]; + int frozenFrames = [data[@"frozenFramesTotalDuration"] intValue]; + + NSArray *> *rawFrames = data[@"frameData"]; + + //complete from here + + +// [IBGAPM endAutoUITraceCPWithFrames:/*<#(nullable NSArray *)#>*/] +} + + +- (void)endScreenRenderForCustomUiTraceData:(nonnull NSDictionary *)data error:(FlutterError * _Nullable __autoreleasing * _Nonnull)error { + //code +} + + @end diff --git a/ios/Classes/Util/IBGAPM+PrivateAPIs.h b/ios/Classes/Util/IBGAPM+PrivateAPIs.h index dba847b13..27524fc88 100644 --- a/ios/Classes/Util/IBGAPM+PrivateAPIs.h +++ b/ios/Classes/Util/IBGAPM+PrivateAPIs.h @@ -8,6 +8,7 @@ #import #import "IBGTimeIntervalUnits.h" +#import "IBGFrameInfo.h" @interface IBGAPM (PrivateAPIs) @@ -24,4 +25,8 @@ + (BOOL)isScreenRenderingOperational; ++ (void)endAutoUITraceCPWithFrames:(nullable NSArray *)frames; + ++ (void)endCustomUITraceCPWithFrames:(nullable NSArray *)frames; + @end diff --git a/ios/instabug_flutter.podspec b/ios/instabug_flutter.podspec index cf6703fda..3d9c4bdca 100644 --- a/ios/instabug_flutter.podspec +++ b/ios/instabug_flutter.podspec @@ -17,6 +17,6 @@ Pod::Spec.new do |s| s.pod_target_xcconfig = { 'OTHER_LDFLAGS' => '-framework "Flutter" -framework "InstabugSDK"'} s.dependency 'Flutter' - s.dependency 'Instabug', '15.1.0' + s.dependency 'Instabug', '15.1.6' end diff --git a/lib/src/models/instabug_frame_data.dart b/lib/src/models/instabug_frame_data.dart index 60bda2550..d4d31c709 100644 --- a/lib/src/models/instabug_frame_data.dart +++ b/lib/src/models/instabug_frame_data.dart @@ -14,4 +14,7 @@ class InstabugFrameData { return startTimeTimestamp == other.startTimeTimestamp && duration == other.duration; } + + /// Serializes the object to a List for efficient channel transfer. + List toList() => [startTimeTimestamp, duration]; } diff --git a/lib/src/models/instabug_screen_render_data.dart b/lib/src/models/instabug_screen_render_data.dart index 11a002345..82ea4bcbc 100644 --- a/lib/src/models/instabug_screen_render_data.dart +++ b/lib/src/models/instabug_screen_render_data.dart @@ -40,4 +40,15 @@ class InstabugScreenRenderData { frozenFramesTotalDuration == other.frozenFramesTotalDuration && listEquals(frameData, other.frameData); } + + /// Serializes the object to a Map for efficient channel transfer. + Map toMap() { + return { + 'traceId': traceId, + 'slowFramesTotalDuration': slowFramesTotalDuration, + 'frozenFramesTotalDuration': frozenFramesTotalDuration, + // Convert List to List> + 'frameData': frameData.map((frame) => frame.toList()).toList(), + }; + } } diff --git a/lib/src/modules/apm.dart b/lib/src/modules/apm.dart index 7d4ef9804..6c389ee7f 100644 --- a/lib/src/modules/apm.dart +++ b/lib/src/modules/apm.dart @@ -4,6 +4,7 @@ import 'dart:async'; import 'package:flutter/widgets.dart' show WidgetBuilder, WidgetsBinding; import 'package:instabug_flutter/src/generated/apm.api.g.dart'; +import 'package:instabug_flutter/src/models/instabug_screen_render_data.dart'; import 'package:instabug_flutter/src/models/network_data.dart'; import 'package:instabug_flutter/src/models/trace.dart'; import 'package:instabug_flutter/src/utils/ibg_build_info.dart'; @@ -400,4 +401,32 @@ class APM { } }); } + + /// The function `endScreenRenderForAutoUiTrace` end screen rendering for + /// automatic UI tracing using data provided in `InstabugScreenRenderData` object. + /// + /// Args: + /// data (InstabugScreenRenderData): The `data` parameter in the `endScreenRenderForAutoUiTrace` + /// function is of type `InstabugScreenRenderData`. It contains information related to screen + /// rendering. + /// + /// Returns: + /// A `Future` is being returned. + Future endScreenRenderForAutoUiTrace(InstabugScreenRenderData data) { + return _host.endScreenRenderForAutoUiTrace(data.toMap()); + } + + /// The function `endScreenRenderForCustomUiTrace` ends the screen render for a custom + /// UI trace using data provided in `InstabugScreenRenderData`. + /// + /// Args: + /// data (InstabugScreenRenderData): The `data` parameter in the `endScreenRenderForCustomUiTrace` + /// function is of type `InstabugScreenRenderData`, which contains information related to the + /// rendering of a screen in the Instabug custom UI. + /// + /// Returns: + /// A `Future` is being returned. + Future endScreenRenderForCustomUiTrace(InstabugScreenRenderData data) { + return _host.endScreenRenderForCustomUiTrace(data.toMap()); + } } diff --git a/pigeons/apm.api.dart b/pigeons/apm.api.dart index 255e35de4..3711d53fc 100644 --- a/pigeons/apm.api.dart +++ b/pigeons/apm.api.dart @@ -3,29 +3,42 @@ import 'package:pigeon/pigeon.dart'; @HostApi() abstract class ApmHostApi { void setEnabled(bool isEnabled); + @async bool isEnabled(); + void setScreenLoadingEnabled(bool isEnabled); + @async bool isScreenLoadingEnabled(); + void setColdAppLaunchEnabled(bool isEnabled); + void setAutoUITraceEnabled(bool isEnabled); @async String? startExecutionTrace(String id, String name); void startFlow(String name); + void setFlowAttribute(String name, String key, String? value); + void endFlow(String name); + void setExecutionTraceAttribute( String id, String key, String value, ); + void endExecutionTrace(String id); + void startUITrace(String name); + void endUITrace(); + void endAppLaunch(); + void networkLogAndroid(Map data); void startCpUiTrace(String screenName, int microTimeStamp, int traceId); @@ -48,4 +61,8 @@ abstract class ApmHostApi { double deviceRefreshRate(); void setScreenRenderEnabled(bool isEnabled); + + void endScreenRenderForAutoUiTrace(Map data); + + void endScreenRenderForCustomUiTrace(Map data); } diff --git a/test/utils/screen_render/instabug_screen_render_manager_test.dart b/test/utils/screen_render/instabug_screen_render_manager_test.dart index c261fc879..15ebf3c9e 100644 --- a/test/utils/screen_render/instabug_screen_render_manager_test.dart +++ b/test/utils/screen_render/instabug_screen_render_manager_test.dart @@ -1,4 +1,4 @@ -import 'dart:ui'; +import 'dart:ui' show FrameTiming; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -6,12 +6,11 @@ import 'package:instabug_flutter/instabug_flutter.dart'; import 'package:instabug_flutter/src/generated/apm.api.g.dart'; import 'package:instabug_flutter/src/models/instabug_frame_data.dart'; import 'package:instabug_flutter/src/models/instabug_screen_render_data.dart'; - import 'package:instabug_flutter/src/utils/screen_rendering/instabug_screen_render_manager.dart'; import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; -import 'instabug_screen_render_manager_test_manual_mocks.dart'; +import 'instabug_screen_render_manager_test.mocks.dart'; @GenerateMocks([ApmHostApi, WidgetsBinding, FrameTiming]) void main() { diff --git a/test/utils/screen_render/instabug_screen_render_manager_test_manual_mocks.dart b/test/utils/screen_render/instabug_screen_render_manager_test_manual_mocks.dart deleted file mode 100644 index 35f21c850..000000000 --- a/test/utils/screen_render/instabug_screen_render_manager_test_manual_mocks.dart +++ /dev/null @@ -1,882 +0,0 @@ -// Mocks generated by Mockito 5.2.0 from annotations -// in instabug_flutter/example/ios/.symlinks/plugins/instabug_flutter/test/utils/screen_render/instabug_screen_render_manager_test.dart. -// Do not manually edit this file. - -import 'dart:async' as _i9; -import 'dart:developer' as _i13; -import 'dart:ui' as _i4; - -import 'package:flutter/foundation.dart' as _i3; -import 'package:flutter/gestures.dart' as _i6; -import 'package:flutter/rendering.dart' as _i7; -import 'package:flutter/scheduler.dart' as _i11; -import 'package:flutter/services.dart' as _i5; -import 'package:flutter/src/widgets/binding.dart' as _i10; -import 'package:flutter/src/widgets/focus_manager.dart' as _i2; -import 'package:flutter/src/widgets/framework.dart' as _i12; -import 'package:instabug_flutter/src/generated/apm.api.g.dart' as _i8; -import 'package:mockito/mockito.dart' as _i1; - -// ignore_for_file: type=lint -// ignore_for_file: avoid_redundant_argument_values -// ignore_for_file: avoid_setters_without_getters -// ignore_for_file: comment_references -// ignore_for_file: implementation_imports -// ignore_for_file: invalid_use_of_visible_for_testing_member -// ignore_for_file: prefer_const_constructors -// ignore_for_file: unnecessary_parenthesis -// ignore_for_file: camel_case_types - -class _FakeFocusManager_0 extends _i1.Fake implements _i2.FocusManager { - @override - String toString({_i3.DiagnosticLevel? minLevel = _i3.DiagnosticLevel.info}) => - super.toString(); -} - -class _FakeSingletonFlutterWindow_1 extends _i1.Fake - implements _i4.SingletonFlutterWindow {} - -class _FakePlatformDispatcher_2 extends _i1.Fake - implements _i4.PlatformDispatcher {} - -class _FakeHardwareKeyboard_3 extends _i1.Fake - implements _i5.HardwareKeyboard {} - -class _FakeKeyEventManager_4 extends _i1.Fake implements _i5.KeyEventManager {} - -class _FakeBinaryMessenger_5 extends _i1.Fake implements _i5.BinaryMessenger {} - -class _FakeChannelBuffers_6 extends _i1.Fake implements _i4.ChannelBuffers {} - -class _FakeRestorationManager_7 extends _i1.Fake - implements _i5.RestorationManager {} - -class _FakeDuration_8 extends _i1.Fake implements Duration {} - -class _FakePointerRouter_9 extends _i1.Fake implements _i6.PointerRouter {} - -class _FakeGestureArenaManager_10 extends _i1.Fake - implements _i6.GestureArenaManager {} - -class _FakePointerSignalResolver_11 extends _i1.Fake - implements _i6.PointerSignalResolver {} - -class _FakeMouseTracker_12 extends _i1.Fake implements _i7.MouseTracker {} - -class _FakePipelineOwner_13 extends _i1.Fake implements _i7.PipelineOwner {} - -class _FakeRenderView_14 extends _i1.Fake implements _i7.RenderView { - @override - String toString({_i3.DiagnosticLevel? minLevel = _i3.DiagnosticLevel.info}) => - super.toString(); -} - -class _FakeAccessibilityFeatures_15 extends _i1.Fake - implements _i4.AccessibilityFeatures {} - -class _FakeViewConfiguration_16 extends _i1.Fake - implements _i7.ViewConfiguration {} - -class _FakeSemanticsUpdateBuilder_17 extends _i1.Fake - implements _i4.SemanticsUpdateBuilder {} - -/// A class which mocks [ApmHostApi]. -/// -/// See the documentation for Mockito's code generation for more information. -class MockApmHostApi extends _i1.Mock implements _i8.ApmHostApi { - MockApmHostApi() { - _i1.throwOnMissingStub(this); - } - - @override - _i9.Future setEnabled(bool? arg_isEnabled) => - (super.noSuchMethod(Invocation.method(#setEnabled, [arg_isEnabled]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - - @override - _i9.Future isEnabled() => - (super.noSuchMethod(Invocation.method(#isEnabled, []), - returnValue: Future.value(false)) as _i9.Future); - - @override - _i9.Future setScreenLoadingEnabled(bool? arg_isEnabled) => - (super.noSuchMethod( - Invocation.method(#setScreenLoadingEnabled, [arg_isEnabled]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - - @override - _i9.Future isScreenLoadingEnabled() => - (super.noSuchMethod(Invocation.method(#isScreenLoadingEnabled, []), - returnValue: Future.value(false)) as _i9.Future); - - @override - _i9.Future setColdAppLaunchEnabled(bool? arg_isEnabled) => - (super.noSuchMethod( - Invocation.method(#setColdAppLaunchEnabled, [arg_isEnabled]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - - @override - _i9.Future setAutoUITraceEnabled(bool? arg_isEnabled) => (super - .noSuchMethod(Invocation.method(#setAutoUITraceEnabled, [arg_isEnabled]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - - @override - _i9.Future startExecutionTrace(String? arg_id, String? arg_name) => - (super.noSuchMethod( - Invocation.method(#startExecutionTrace, [arg_id, arg_name]), - returnValue: Future.value()) as _i9.Future); - - @override - _i9.Future startFlow(String? arg_name) => - (super.noSuchMethod(Invocation.method(#startFlow, [arg_name]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - - @override - _i9.Future setFlowAttribute( - String? arg_name, String? arg_key, String? arg_value) => - (super.noSuchMethod( - Invocation.method(#setFlowAttribute, [arg_name, arg_key, arg_value]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - - @override - _i9.Future endFlow(String? arg_name) => - (super.noSuchMethod(Invocation.method(#endFlow, [arg_name]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - - @override - _i9.Future setExecutionTraceAttribute( - String? arg_id, String? arg_key, String? arg_value) => - (super.noSuchMethod( - Invocation.method( - #setExecutionTraceAttribute, [arg_id, arg_key, arg_value]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - - @override - _i9.Future endExecutionTrace(String? arg_id) => - (super.noSuchMethod(Invocation.method(#endExecutionTrace, [arg_id]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - - @override - _i9.Future startUITrace(String? arg_name) => - (super.noSuchMethod(Invocation.method(#startUITrace, [arg_name]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - - @override - _i9.Future endUITrace() => - (super.noSuchMethod(Invocation.method(#endUITrace, []), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - - @override - _i9.Future endAppLaunch() => - (super.noSuchMethod(Invocation.method(#endAppLaunch, []), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - - @override - _i9.Future networkLogAndroid(Map? arg_data) => - (super.noSuchMethod(Invocation.method(#networkLogAndroid, [arg_data]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - - @override - _i9.Future startCpUiTrace( - String? arg_screenName, int? arg_microTimeStamp, int? arg_traceId) => - (super.noSuchMethod( - Invocation.method(#startCpUiTrace, - [arg_screenName, arg_microTimeStamp, arg_traceId]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - - @override - _i9.Future reportScreenLoadingCP(int? arg_startTimeStampMicro, - int? arg_durationMicro, int? arg_uiTraceId) => - (super.noSuchMethod( - Invocation.method(#reportScreenLoadingCP, - [arg_startTimeStampMicro, arg_durationMicro, arg_uiTraceId]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - - @override - _i9.Future endScreenLoadingCP( - int? arg_timeStampMicro, int? arg_uiTraceId) => - (super.noSuchMethod( - Invocation.method( - #endScreenLoadingCP, [arg_timeStampMicro, arg_uiTraceId]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - - @override - _i9.Future isEndScreenLoadingEnabled() => - (super.noSuchMethod(Invocation.method(#isEndScreenLoadingEnabled, []), - returnValue: Future.value(false)) as _i9.Future); - - @override - _i9.Future isScreenRenderEnabled() => - (super.noSuchMethod(Invocation.method(#isScreenRenderEnabled, []), - returnValue: Future.value(false)) as _i9.Future); - - @override - _i9.Future deviceRefreshRate() => - (super.noSuchMethod(Invocation.method(#deviceRefreshRate, []), - returnValue: Future.value(0.0)) as _i9.Future); - - @override - _i9.Future setScreenRenderEnabled(bool? arg_isEnabled) => (super - .noSuchMethod(Invocation.method(#setScreenRenderEnabled, [arg_isEnabled]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); -} - -/// A class which mocks [WidgetsBinding]. -/// -/// See the documentation for Mockito's code generation for more information. -class MockWidgetsBinding extends _i1.Mock implements _i10.WidgetsBinding { - MockWidgetsBinding() { - _i1.throwOnMissingStub(this); - } - - @override - bool get debugBuildingDirtyElements => - (super.noSuchMethod(Invocation.getter(#debugBuildingDirtyElements), - returnValue: false) as bool); - - @override - set debugBuildingDirtyElements(bool? _debugBuildingDirtyElements) => - super.noSuchMethod( - Invocation.setter( - #debugBuildingDirtyElements, _debugBuildingDirtyElements), - returnValueForMissingStub: null); - - @override - _i2.FocusManager get focusManager => - (super.noSuchMethod(Invocation.getter(#focusManager), - returnValue: _FakeFocusManager_0()) as _i2.FocusManager); - - @override - bool get firstFrameRasterized => - (super.noSuchMethod(Invocation.getter(#firstFrameRasterized), - returnValue: false) as bool); - - @override - _i9.Future get waitUntilFirstFrameRasterized => - (super.noSuchMethod(Invocation.getter(#waitUntilFirstFrameRasterized), - returnValue: Future.value()) as _i9.Future); - - @override - bool get debugDidSendFirstFrameEvent => - (super.noSuchMethod(Invocation.getter(#debugDidSendFirstFrameEvent), - returnValue: false) as bool); - - @override - bool get framesEnabled => - (super.noSuchMethod(Invocation.getter(#framesEnabled), returnValue: false) - as bool); - - @override - bool get isRootWidgetAttached => - (super.noSuchMethod(Invocation.getter(#isRootWidgetAttached), - returnValue: false) as bool); - - @override - _i4.SingletonFlutterWindow get window => - (super.noSuchMethod(Invocation.getter(#window), - returnValue: _FakeSingletonFlutterWindow_1()) - as _i4.SingletonFlutterWindow); - - @override - _i4.PlatformDispatcher get platformDispatcher => - (super.noSuchMethod(Invocation.getter(#platformDispatcher), - returnValue: _FakePlatformDispatcher_2()) as _i4.PlatformDispatcher); - - @override - bool get locked => - (super.noSuchMethod(Invocation.getter(#locked), returnValue: false) - as bool); - - @override - _i5.HardwareKeyboard get keyboard => - (super.noSuchMethod(Invocation.getter(#keyboard), - returnValue: _FakeHardwareKeyboard_3()) as _i5.HardwareKeyboard); - - @override - _i5.KeyEventManager get keyEventManager => - (super.noSuchMethod(Invocation.getter(#keyEventManager), - returnValue: _FakeKeyEventManager_4()) as _i5.KeyEventManager); - - @override - _i5.BinaryMessenger get defaultBinaryMessenger => - (super.noSuchMethod(Invocation.getter(#defaultBinaryMessenger), - returnValue: _FakeBinaryMessenger_5()) as _i5.BinaryMessenger); - - @override - _i4.ChannelBuffers get channelBuffers => - (super.noSuchMethod(Invocation.getter(#channelBuffers), - returnValue: _FakeChannelBuffers_6()) as _i4.ChannelBuffers); - - @override - _i5.RestorationManager get restorationManager => - (super.noSuchMethod(Invocation.getter(#restorationManager), - returnValue: _FakeRestorationManager_7()) as _i5.RestorationManager); - - @override - _i11.SchedulingStrategy get schedulingStrategy => - (super.noSuchMethod(Invocation.getter(#schedulingStrategy), - returnValue: ({int? priority, _i11.SchedulerBinding? scheduler}) => - false) as _i11.SchedulingStrategy); - - @override - set schedulingStrategy(_i11.SchedulingStrategy? _schedulingStrategy) => super - .noSuchMethod(Invocation.setter(#schedulingStrategy, _schedulingStrategy), - returnValueForMissingStub: null); - - @override - int get transientCallbackCount => - (super.noSuchMethod(Invocation.getter(#transientCallbackCount), - returnValue: 0) as int); - - @override - _i9.Future get endOfFrame => - (super.noSuchMethod(Invocation.getter(#endOfFrame), - returnValue: Future.value()) as _i9.Future); - - @override - bool get hasScheduledFrame => - (super.noSuchMethod(Invocation.getter(#hasScheduledFrame), - returnValue: false) as bool); - - @override - _i11.SchedulerPhase get schedulerPhase => - (super.noSuchMethod(Invocation.getter(#schedulerPhase), - returnValue: _i11.SchedulerPhase.idle) as _i11.SchedulerPhase); - - @override - Duration get currentFrameTimeStamp => - (super.noSuchMethod(Invocation.getter(#currentFrameTimeStamp), - returnValue: _FakeDuration_8()) as Duration); - - @override - Duration get currentSystemFrameTimeStamp => - (super.noSuchMethod(Invocation.getter(#currentSystemFrameTimeStamp), - returnValue: _FakeDuration_8()) as Duration); - - @override - _i6.PointerRouter get pointerRouter => - (super.noSuchMethod(Invocation.getter(#pointerRouter), - returnValue: _FakePointerRouter_9()) as _i6.PointerRouter); - - @override - _i6.GestureArenaManager get gestureArena => (super.noSuchMethod( - Invocation.getter(#gestureArena), - returnValue: _FakeGestureArenaManager_10()) as _i6.GestureArenaManager); - - @override - _i6.PointerSignalResolver get pointerSignalResolver => - (super.noSuchMethod(Invocation.getter(#pointerSignalResolver), - returnValue: _FakePointerSignalResolver_11()) - as _i6.PointerSignalResolver); - - @override - bool get resamplingEnabled => - (super.noSuchMethod(Invocation.getter(#resamplingEnabled), - returnValue: false) as bool); - - @override - set resamplingEnabled(bool? _resamplingEnabled) => super.noSuchMethod( - Invocation.setter(#resamplingEnabled, _resamplingEnabled), - returnValueForMissingStub: null); - - @override - Duration get samplingOffset => - (super.noSuchMethod(Invocation.getter(#samplingOffset), - returnValue: _FakeDuration_8()) as Duration); - - @override - set samplingOffset(Duration? _samplingOffset) => - super.noSuchMethod(Invocation.setter(#samplingOffset, _samplingOffset), - returnValueForMissingStub: null); - - @override - _i7.MouseTracker get mouseTracker => - (super.noSuchMethod(Invocation.getter(#mouseTracker), - returnValue: _FakeMouseTracker_12()) as _i7.MouseTracker); - - @override - _i7.PipelineOwner get pipelineOwner => - (super.noSuchMethod(Invocation.getter(#pipelineOwner), - returnValue: _FakePipelineOwner_13()) as _i7.PipelineOwner); - - @override - _i7.RenderView get renderView => - (super.noSuchMethod(Invocation.getter(#renderView), - returnValue: _FakeRenderView_14()) as _i7.RenderView); - - @override - set renderView(_i7.RenderView? value) => - super.noSuchMethod(Invocation.setter(#renderView, value), - returnValueForMissingStub: null); - - @override - bool get sendFramesToEngine => - (super.noSuchMethod(Invocation.getter(#sendFramesToEngine), - returnValue: false) as bool); - - @override - _i4.AccessibilityFeatures get accessibilityFeatures => - (super.noSuchMethod(Invocation.getter(#accessibilityFeatures), - returnValue: _FakeAccessibilityFeatures_15()) - as _i4.AccessibilityFeatures); - - @override - bool get disableAnimations => - (super.noSuchMethod(Invocation.getter(#disableAnimations), - returnValue: false) as bool); - - @override - void initInstances() => - super.noSuchMethod(Invocation.method(#initInstances, []), - returnValueForMissingStub: null); - - @override - void initServiceExtensions() => - super.noSuchMethod(Invocation.method(#initServiceExtensions, []), - returnValueForMissingStub: null); - - @override - void addObserver(_i10.WidgetsBindingObserver? observer) => - super.noSuchMethod(Invocation.method(#addObserver, [observer]), - returnValueForMissingStub: null); - - @override - bool removeObserver(_i10.WidgetsBindingObserver? observer) => - (super.noSuchMethod(Invocation.method(#removeObserver, [observer]), - returnValue: false) as bool); - - @override - void handleMetricsChanged() => - super.noSuchMethod(Invocation.method(#handleMetricsChanged, []), - returnValueForMissingStub: null); - - @override - void handleTextScaleFactorChanged() => - super.noSuchMethod(Invocation.method(#handleTextScaleFactorChanged, []), - returnValueForMissingStub: null); - - @override - void handlePlatformBrightnessChanged() => super.noSuchMethod( - Invocation.method(#handlePlatformBrightnessChanged, []), - returnValueForMissingStub: null); - - @override - void handleAccessibilityFeaturesChanged() => super.noSuchMethod( - Invocation.method(#handleAccessibilityFeaturesChanged, []), - returnValueForMissingStub: null); - - @override - void handleLocaleChanged() => - super.noSuchMethod(Invocation.method(#handleLocaleChanged, []), - returnValueForMissingStub: null); - - @override - void dispatchLocalesChanged(List<_i4.Locale>? locales) => - super.noSuchMethod(Invocation.method(#dispatchLocalesChanged, [locales]), - returnValueForMissingStub: null); - - @override - void dispatchAccessibilityFeaturesChanged() => super.noSuchMethod( - Invocation.method(#dispatchAccessibilityFeaturesChanged, []), - returnValueForMissingStub: null); - - @override - _i9.Future handlePopRoute() => - (super.noSuchMethod(Invocation.method(#handlePopRoute, []), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - - @override - _i9.Future handlePushRoute(String? route) => - (super.noSuchMethod(Invocation.method(#handlePushRoute, [route]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - - @override - void handleAppLifecycleStateChanged(_i4.AppLifecycleState? state) => super - .noSuchMethod(Invocation.method(#handleAppLifecycleStateChanged, [state]), - returnValueForMissingStub: null); - - @override - void handleMemoryPressure() => - super.noSuchMethod(Invocation.method(#handleMemoryPressure, []), - returnValueForMissingStub: null); - - @override - void drawFrame() => super.noSuchMethod(Invocation.method(#drawFrame, []), - returnValueForMissingStub: null); - - @override - void scheduleAttachRootWidget(_i12.Widget? rootWidget) => super.noSuchMethod( - Invocation.method(#scheduleAttachRootWidget, [rootWidget]), - returnValueForMissingStub: null); - - @override - void attachRootWidget(_i12.Widget? rootWidget) => - super.noSuchMethod(Invocation.method(#attachRootWidget, [rootWidget]), - returnValueForMissingStub: null); - - @override - _i9.Future performReassemble() => - (super.noSuchMethod(Invocation.method(#performReassemble, []), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - - @override - _i4.Locale? computePlatformResolvedLocale( - List<_i4.Locale>? supportedLocales) => - (super.noSuchMethod(Invocation.method( - #computePlatformResolvedLocale, [supportedLocales])) as _i4.Locale?); - - @override - _i9.Future lockEvents(_i9.Future Function()? callback) => - (super.noSuchMethod(Invocation.method(#lockEvents, [callback]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - - @override - void unlocked() => super.noSuchMethod(Invocation.method(#unlocked, []), - returnValueForMissingStub: null); - - @override - _i9.Future reassembleApplication() => - (super.noSuchMethod(Invocation.method(#reassembleApplication, []), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - - @override - void registerSignalServiceExtension( - {String? name, _i3.AsyncCallback? callback}) => - super.noSuchMethod( - Invocation.method(#registerSignalServiceExtension, [], - {#name: name, #callback: callback}), - returnValueForMissingStub: null); - - @override - void registerBoolServiceExtension( - {String? name, - _i3.AsyncValueGetter? getter, - _i3.AsyncValueSetter? setter}) => - super.noSuchMethod( - Invocation.method(#registerBoolServiceExtension, [], - {#name: name, #getter: getter, #setter: setter}), - returnValueForMissingStub: null); - - @override - void registerNumericServiceExtension( - {String? name, - _i3.AsyncValueGetter? getter, - _i3.AsyncValueSetter? setter}) => - super.noSuchMethod( - Invocation.method(#registerNumericServiceExtension, [], - {#name: name, #getter: getter, #setter: setter}), - returnValueForMissingStub: null); - - @override - void postEvent(String? eventKind, Map? eventData) => - super.noSuchMethod(Invocation.method(#postEvent, [eventKind, eventData]), - returnValueForMissingStub: null); - - @override - void registerStringServiceExtension( - {String? name, - _i3.AsyncValueGetter? getter, - _i3.AsyncValueSetter? setter}) => - super.noSuchMethod( - Invocation.method(#registerStringServiceExtension, [], - {#name: name, #getter: getter, #setter: setter}), - returnValueForMissingStub: null); - - @override - void registerServiceExtension( - {String? name, _i3.ServiceExtensionCallback? callback}) => - super.noSuchMethod( - Invocation.method(#registerServiceExtension, [], - {#name: name, #callback: callback}), - returnValueForMissingStub: null); - - @override - _i5.BinaryMessenger createBinaryMessenger() => - (super.noSuchMethod(Invocation.method(#createBinaryMessenger, []), - returnValue: _FakeBinaryMessenger_5()) as _i5.BinaryMessenger); - - @override - _i9.Future handleSystemMessage(Object? systemMessage) => (super - .noSuchMethod(Invocation.method(#handleSystemMessage, [systemMessage]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - - @override - void initLicenses() => - super.noSuchMethod(Invocation.method(#initLicenses, []), - returnValueForMissingStub: null); - - @override - void evict(String? asset) => - super.noSuchMethod(Invocation.method(#evict, [asset]), - returnValueForMissingStub: null); - - @override - void readInitialLifecycleStateFromNativeWindow() => super.noSuchMethod( - Invocation.method(#readInitialLifecycleStateFromNativeWindow, []), - returnValueForMissingStub: null); - - @override - _i5.RestorationManager createRestorationManager() => - (super.noSuchMethod(Invocation.method(#createRestorationManager, []), - returnValue: _FakeRestorationManager_7()) as _i5.RestorationManager); - - @override - void setSystemUiChangeCallback(_i5.SystemUiChangeCallback? callback) => super - .noSuchMethod(Invocation.method(#setSystemUiChangeCallback, [callback]), - returnValueForMissingStub: null); - - @override - void addTimingsCallback(_i4.TimingsCallback? callback) => - super.noSuchMethod(Invocation.method(#addTimingsCallback, [callback]), - returnValueForMissingStub: null); - - @override - void removeTimingsCallback(_i4.TimingsCallback? callback) => - super.noSuchMethod(Invocation.method(#removeTimingsCallback, [callback]), - returnValueForMissingStub: null); - - @override - _i9.Future scheduleTask( - _i11.TaskCallback? task, _i11.Priority? priority, - {String? debugLabel, _i13.Flow? flow}) => - (super.noSuchMethod( - Invocation.method(#scheduleTask, [task, priority], - {#debugLabel: debugLabel, #flow: flow}), - returnValue: Future.value(null)) as _i9.Future); - - @override - bool handleEventLoopCallback() => - (super.noSuchMethod(Invocation.method(#handleEventLoopCallback, []), - returnValue: false) as bool); - - @override - int scheduleFrameCallback(_i11.FrameCallback? callback, - {bool? rescheduling = false}) => - (super.noSuchMethod( - Invocation.method(#scheduleFrameCallback, [callback], - {#rescheduling: rescheduling}), - returnValue: 0) as int); - - @override - void cancelFrameCallbackWithId(int? id) => - super.noSuchMethod(Invocation.method(#cancelFrameCallbackWithId, [id]), - returnValueForMissingStub: null); - - @override - bool debugAssertNoTransientCallbacks(String? reason) => (super.noSuchMethod( - Invocation.method(#debugAssertNoTransientCallbacks, [reason]), - returnValue: false) as bool); - - @override - void addPersistentFrameCallback(_i11.FrameCallback? callback) => super - .noSuchMethod(Invocation.method(#addPersistentFrameCallback, [callback]), - returnValueForMissingStub: null); - - @override - void addPostFrameCallback(_i11.FrameCallback? callback) => - super.noSuchMethod(Invocation.method(#addPostFrameCallback, [callback]), - returnValueForMissingStub: null); - - @override - void ensureFrameCallbacksRegistered() => - super.noSuchMethod(Invocation.method(#ensureFrameCallbacksRegistered, []), - returnValueForMissingStub: null); - - @override - void ensureVisualUpdate() => - super.noSuchMethod(Invocation.method(#ensureVisualUpdate, []), - returnValueForMissingStub: null); - - @override - void scheduleFrame() => - super.noSuchMethod(Invocation.method(#scheduleFrame, []), - returnValueForMissingStub: null); - - @override - void scheduleForcedFrame() => - super.noSuchMethod(Invocation.method(#scheduleForcedFrame, []), - returnValueForMissingStub: null); - - @override - void scheduleWarmUpFrame() => - super.noSuchMethod(Invocation.method(#scheduleWarmUpFrame, []), - returnValueForMissingStub: null); - - @override - void resetEpoch() => super.noSuchMethod(Invocation.method(#resetEpoch, []), - returnValueForMissingStub: null); - - @override - void handleBeginFrame(Duration? rawTimeStamp) => - super.noSuchMethod(Invocation.method(#handleBeginFrame, [rawTimeStamp]), - returnValueForMissingStub: null); - - @override - void handleDrawFrame() => - super.noSuchMethod(Invocation.method(#handleDrawFrame, []), - returnValueForMissingStub: null); - - @override - void cancelPointer(int? pointer) => - super.noSuchMethod(Invocation.method(#cancelPointer, [pointer]), - returnValueForMissingStub: null); - - @override - void handlePointerEvent(_i6.PointerEvent? event) => - super.noSuchMethod(Invocation.method(#handlePointerEvent, [event]), - returnValueForMissingStub: null); - - @override - void hitTest(_i6.HitTestResult? result, _i4.Offset? position) => - super.noSuchMethod(Invocation.method(#hitTest, [result, position]), - returnValueForMissingStub: null); - - @override - void dispatchEvent( - _i6.PointerEvent? event, _i6.HitTestResult? hitTestResult) => - super.noSuchMethod( - Invocation.method(#dispatchEvent, [event, hitTestResult]), - returnValueForMissingStub: null); - - @override - void handleEvent(_i6.PointerEvent? event, _i6.HitTestEntry? entry) => - super.noSuchMethod(Invocation.method(#handleEvent, [event, entry]), - returnValueForMissingStub: null); - - @override - void resetGestureBinding() => - super.noSuchMethod(Invocation.method(#resetGestureBinding, []), - returnValueForMissingStub: null); - - @override - void initRenderView() => - super.noSuchMethod(Invocation.method(#initRenderView, []), - returnValueForMissingStub: null); - - @override - _i7.ViewConfiguration createViewConfiguration() => - (super.noSuchMethod(Invocation.method(#createViewConfiguration, []), - returnValue: _FakeViewConfiguration_16()) as _i7.ViewConfiguration); - - @override - void initMouseTracker([_i7.MouseTracker? tracker]) => - super.noSuchMethod(Invocation.method(#initMouseTracker, [tracker]), - returnValueForMissingStub: null); - - @override - void setSemanticsEnabled(bool? enabled) => - super.noSuchMethod(Invocation.method(#setSemanticsEnabled, [enabled]), - returnValueForMissingStub: null); - - @override - void deferFirstFrame() => - super.noSuchMethod(Invocation.method(#deferFirstFrame, []), - returnValueForMissingStub: null); - - @override - void allowFirstFrame() => - super.noSuchMethod(Invocation.method(#allowFirstFrame, []), - returnValueForMissingStub: null); - - @override - void resetFirstFrameSent() => - super.noSuchMethod(Invocation.method(#resetFirstFrameSent, []), - returnValueForMissingStub: null); - - @override - _i4.SemanticsUpdateBuilder createSemanticsUpdateBuilder() => - (super.noSuchMethod(Invocation.method(#createSemanticsUpdateBuilder, []), - returnValue: _FakeSemanticsUpdateBuilder_17()) - as _i4.SemanticsUpdateBuilder); -} - -/// A class which mocks [FrameTiming]. -/// -/// See the documentation for Mockito's code generation for more information. -class MockFrameTiming extends _i1.Mock implements _i4.FrameTiming { - MockFrameTiming() { - _i1.throwOnMissingStub(this); - } - - @override - Duration get buildDuration => - (super.noSuchMethod(Invocation.getter(#buildDuration), - returnValue: _FakeDuration_8()) as Duration); - - @override - Duration get rasterDuration => - (super.noSuchMethod(Invocation.getter(#rasterDuration), - returnValue: _FakeDuration_8()) as Duration); - - @override - Duration get vsyncOverhead => - (super.noSuchMethod(Invocation.getter(#vsyncOverhead), - returnValue: _FakeDuration_8()) as Duration); - - @override - Duration get totalSpan => (super.noSuchMethod(Invocation.getter(#totalSpan), - returnValue: _FakeDuration_8()) as Duration); - - @override - int get layerCacheCount => - (super.noSuchMethod(Invocation.getter(#layerCacheCount), returnValue: 0) - as int); - - @override - int get layerCacheBytes => - (super.noSuchMethod(Invocation.getter(#layerCacheBytes), returnValue: 0) - as int); - - @override - double get layerCacheMegabytes => - (super.noSuchMethod(Invocation.getter(#layerCacheMegabytes), - returnValue: 0.0) as double); - - @override - int get pictureCacheCount => - (super.noSuchMethod(Invocation.getter(#pictureCacheCount), returnValue: 0) - as int); - - @override - int get pictureCacheBytes => - (super.noSuchMethod(Invocation.getter(#pictureCacheBytes), returnValue: 0) - as int); - - @override - double get pictureCacheMegabytes => - (super.noSuchMethod(Invocation.getter(#pictureCacheMegabytes), - returnValue: 0.0) as double); - - @override - int get frameNumber => - (super.noSuchMethod(Invocation.getter(#frameNumber), returnValue: 0) - as int); - - @override - int timestampInMicroseconds(_i4.FramePhase? phase) => - (super.noSuchMethod(Invocation.method(#timestampInMicroseconds, [phase]), - returnValue: 0) as int); -} From d9acd3aec612a4077d76d008712639e05bae5251 Mon Sep 17 00:00:00 2001 From: Andrew Amin Date: Wed, 2 Jul 2025 19:23:07 +0300 Subject: [PATCH 17/84] chore: add store API in Flutter side --- .../com/instabug/flutter/modules/ApmApi.java | 198 +++++++++--------- ios/Classes/Modules/ApmApi.m | 25 ++- ios/Classes/Util/IBGAPM+PrivateAPIs.h | 8 +- .../models/instabug_screen_render_data.dart | 14 +- lib/src/modules/apm.dart | 6 +- .../instabug_screen_render_manager.dart | 80 ++++--- test/apm_test.dart | 2 +- .../instabug_screen_render_manager_test.dart | 32 ++- 8 files changed, 204 insertions(+), 161 deletions(-) diff --git a/android/src/main/java/com/instabug/flutter/modules/ApmApi.java b/android/src/main/java/com/instabug/flutter/modules/ApmApi.java index 3b16e93fb..d2c85e240 100644 --- a/android/src/main/java/com/instabug/flutter/modules/ApmApi.java +++ b/android/src/main/java/com/instabug/flutter/modules/ApmApi.java @@ -16,8 +16,6 @@ import com.instabug.flutter.util.Reflection; import com.instabug.flutter.util.ThreadManager; -import io.flutter.plugin.common.BinaryMessenger; - import org.json.JSONObject; import java.lang.reflect.Method; @@ -25,6 +23,8 @@ import java.util.Map; import java.util.concurrent.Callable; +import io.flutter.plugin.common.BinaryMessenger; + public class ApmApi implements ApmPigeon.ApmHostApi { private final String TAG = ApmApi.class.getName(); private final HashMap traces = new HashMap<>(); @@ -40,14 +40,14 @@ public static void init(BinaryMessenger messenger, Callable refreshRatePr ApmPigeon.ApmHostApi.setup(messenger, api); } - /** - * The function sets the enabled status of APM. - * - * @param isEnabled The `setEnabled` method in the code snippet is used to enable or disable a - * feature, and it takes a `Boolean` parameter named `isEnabled`. When this method is called with - * `true`, it enables the feature, and when called with `false`, it disables the feature. The method - * internally calls - */ + /** + * The function sets the enabled status of APM. + * + * @param isEnabled The `setEnabled` method in the code snippet is used to enable or disable a + * feature, and it takes a `Boolean` parameter named `isEnabled`. When this method is called with + * `true`, it enables the feature, and when called with `false`, it disables the feature. The method + * internally calls + */ @Override public void setEnabled(@NonNull Boolean isEnabled) { try { @@ -58,12 +58,12 @@ public void setEnabled(@NonNull Boolean isEnabled) { } /** - * Sets the cold app launch enabled status using the APM library. - * - * @param isEnabled The `isEnabled` parameter is a Boolean value that indicates whether cold app launch - * is enabled or not. When `isEnabled` is set to `true`, cold app launch is enabled, and when it is set - * to `false`, cold app launch is disabled. - */ + * Sets the cold app launch enabled status using the APM library. + * + * @param isEnabled The `isEnabled` parameter is a Boolean value that indicates whether cold app launch + * is enabled or not. When `isEnabled` is set to `true`, cold app launch is enabled, and when it is set + * to `false`, cold app launch is disabled. + */ @Override public void setColdAppLaunchEnabled(@NonNull Boolean isEnabled) { try { @@ -73,14 +73,14 @@ public void setColdAppLaunchEnabled(@NonNull Boolean isEnabled) { } } - /** - * The function sets the auto UI trace enabled status in an APM system, handling any exceptions that - * may occur. - * - * @param isEnabled The `isEnabled` parameter is a Boolean value that indicates whether the Auto UI - * trace feature should be enabled or disabled. When `isEnabled` is set to `true`, the Auto UI trace - * feature is enabled, and when it is set to `false`, the feature is disabled. - */ + /** + * The function sets the auto UI trace enabled status in an APM system, handling any exceptions that + * may occur. + * + * @param isEnabled The `isEnabled` parameter is a Boolean value that indicates whether the Auto UI + * trace feature should be enabled or disabled. When `isEnabled` is set to `true`, the Auto UI trace + * feature is enabled, and when it is set to `false`, the feature is disabled. + */ @Override public void setAutoUITraceEnabled(@NonNull Boolean isEnabled) { try { @@ -90,21 +90,20 @@ public void setAutoUITraceEnabled(@NonNull Boolean isEnabled) { } } - /** - * Starts an execution trace and handles the result - * using callbacks. - * - * @param id The `id` parameter is a non-null String that represents the identifier of the execution - * trace. - * @param name The `name` parameter in the `startExecutionTrace` method represents the name of the - * execution trace that will be started. It is used as a reference to identify the trace during - * execution monitoring. - * @param result The `result` parameter in the `startExecutionTrace` method is an instance of - * `ApmPigeon.Result`. This parameter is used to provide the result of the execution trace - * operation back to the caller. The `success` method of the `result` object is called with the - * - * @deprecated see {@link #startFlow} - */ + /** + * Starts an execution trace and handles the result + * using callbacks. + * + * @param id The `id` parameter is a non-null String that represents the identifier of the execution + * trace. + * @param name The `name` parameter in the `startExecutionTrace` method represents the name of the + * execution trace that will be started. It is used as a reference to identify the trace during + * execution monitoring. + * @param result The `result` parameter in the `startExecutionTrace` method is an instance of + * `ApmPigeon.Result`. This parameter is used to provide the result of the execution trace + * operation back to the caller. The `success` method of the `result` object is called with the + * @deprecated see {@link #startFlow} + */ @Override public void startExecutionTrace(@NonNull String id, @NonNull String name, ApmPigeon.Result result) { ThreadManager.runOnBackground( @@ -165,7 +164,7 @@ public void startFlow(@NonNull String name) { } } - /** + /** * Sets custom attributes for AppFlow with a given name. *
* Setting an attribute value to null will remove its corresponding key if it already exists. @@ -194,7 +193,7 @@ public void setFlowAttribute(@NonNull String name, @NonNull String key, @Nullabl } } - /** + /** * Ends AppFlow with a given name. * * @param name AppFlow name to be ended. It can not be empty string or null @@ -208,13 +207,12 @@ public void endFlow(@NonNull String name) { } } - /** + /** * Adds a new attribute to trace * * @param id String id of the trace. * @param key attribute key * @param value attribute value. Null to remove attribute - * * @deprecated see {@link #setFlowAttribute} */ @Override @@ -230,7 +228,6 @@ public void setExecutionTraceAttribute(@NonNull String id, @NonNull String key, * Ends a trace * * @param id string id of the trace. - * * @deprecated see {@link #endFlow} */ @Override @@ -283,7 +280,7 @@ public void endAppLaunch() { /** * logs network-related information - * + * * @param data Map of network data object. */ @Override @@ -349,43 +346,44 @@ public void networkLogAndroid(@NonNull Map data) { } - if (data.containsKey("w3CCaughtHeader")) { - w3CCaughtHeader = (String) data.get("w3CCaughtHeader"); - - } + if (data.containsKey("w3CCaughtHeader")) { + w3CCaughtHeader = (String) data.get("w3CCaughtHeader"); + } - APMCPNetworkLog.W3CExternalTraceAttributes w3cExternalTraceAttributes = - null; - if (isW3cHeaderFound != null) { - w3cExternalTraceAttributes = new APMCPNetworkLog.W3CExternalTraceAttributes( - isW3cHeaderFound, partialId == null ? null : partialId.longValue(), - networkStartTimeInSeconds == null ? null : networkStartTimeInSeconds.longValue(), - w3CGeneratedHeader, w3CCaughtHeader - ); - } + APMCPNetworkLog.W3CExternalTraceAttributes w3cExternalTraceAttributes = + null; + if (isW3cHeaderFound != null) { + w3cExternalTraceAttributes = new APMCPNetworkLog.W3CExternalTraceAttributes( + isW3cHeaderFound, partialId == null ? null : partialId.longValue(), + networkStartTimeInSeconds == null ? null : networkStartTimeInSeconds.longValue(), + w3CGeneratedHeader, w3CCaughtHeader - Method method = Reflection.getMethod(Class.forName("com.instabug.apm.networking.APMNetworkLogger"), "log", long.class, long.class, String.class, String.class, long.class, String.class, String.class, String.class, String.class, String.class, long.class, int.class, String.class, String.class, String.class, String.class, APMCPNetworkLog.W3CExternalTraceAttributes.class); - if (method != null) { - method.invoke(apmNetworkLogger, requestStartTime, requestDuration, requestHeaders, requestBody, requestBodySize, requestMethod, requestUrl, requestContentType, responseHeaders, responseBody, responseBodySize, statusCode, responseContentType, errorMessage, gqlQueryName, serverErrorMessage, w3cExternalTraceAttributes); - } else { - Log.e(TAG, "APMNetworkLogger.log was not found by reflection"); - } + ); + } - } catch(Exception e){ - e.printStackTrace(); + Method method = Reflection.getMethod(Class.forName("com.instabug.apm.networking.APMNetworkLogger"), "log", long.class, long.class, String.class, String.class, long.class, String.class, String.class, String.class, String.class, String.class, long.class, int.class, String.class, String.class, String.class, String.class, APMCPNetworkLog.W3CExternalTraceAttributes.class); + if (method != null) { + method.invoke(apmNetworkLogger, requestStartTime, requestDuration, requestHeaders, requestBody, requestBodySize, requestMethod, requestUrl, requestContentType, responseHeaders, responseBody, responseBodySize, statusCode, responseContentType, errorMessage, gqlQueryName, serverErrorMessage, w3cExternalTraceAttributes); + } else { + Log.e(TAG, "APMNetworkLogger.log was not found by reflection"); } + + } catch (Exception e) { + e.printStackTrace(); } + } - /** - * This method is responsible for initiating a custom performance UI trace - * in the APM module. It takes three parameters: - * @param screenName: A string representing the name of the screen or UI element being traced. - * @param microTimeStamp: A number representing the timestamp in microseconds when the trace is started. - * @param traceId: A number representing the unique identifier for the trace. - */ + /** + * This method is responsible for initiating a custom performance UI trace + * in the APM module. It takes three parameters: + * + * @param screenName: A string representing the name of the screen or UI element being traced. + * @param microTimeStamp: A number representing the timestamp in microseconds when the trace is started. + * @param traceId: A number representing the unique identifier for the trace. + */ @Override public void startCpUiTrace(@NonNull String screenName, @NonNull Long microTimeStamp, @NonNull Long traceId) { try { @@ -396,16 +394,17 @@ public void startCpUiTrace(@NonNull String screenName, @NonNull Long microTimeSt } - /** - * This method is responsible for reporting the screen - * loading data from Dart side to Android side. It takes three parameters: - * @param startTimeStampMicro: A number representing the start timestamp in microseconds of the screen - * loading custom performance data. - * @param durationMicro: A number representing the duration in microseconds of the screen loading custom - * performance data. - * @param uiTraceId: A number representing the unique identifier for the UI trace associated with the - * screen loading. - */ + /** + * This method is responsible for reporting the screen + * loading data from Dart side to Android side. It takes three parameters: + * + * @param startTimeStampMicro: A number representing the start timestamp in microseconds of the screen + * loading custom performance data. + * @param durationMicro: A number representing the duration in microseconds of the screen loading custom + * performance data. + * @param uiTraceId: A number representing the unique identifier for the UI trace associated with the + * screen loading. + */ @Override public void reportScreenLoadingCP(@NonNull Long startTimeStampMicro, @NonNull Long durationMicro, @NonNull Long uiTraceId) { try { @@ -417,13 +416,14 @@ public void reportScreenLoadingCP(@NonNull Long startTimeStampMicro, @NonNull Lo /** - * This method is responsible for extend the end time if the screen loading custom - * trace. It takes two parameters: - * @param timeStampMicro: A number representing the timestamp in microseconds when the screen loading - * custom trace is ending. - * @param uiTraceId: A number representing the unique identifier for the UI trace associated with the - * screen loading. - */ + * This method is responsible for extend the end time if the screen loading custom + * trace. It takes two parameters: + * + * @param timeStampMicro: A number representing the timestamp in microseconds when the screen loading + * custom trace is ending. + * @param uiTraceId: A number representing the unique identifier for the UI trace associated with the + * screen loading. + */ @Override public void endScreenLoadingCP(@NonNull Long timeStampMicro, @NonNull Long uiTraceId) { try { @@ -435,7 +435,7 @@ public void endScreenLoadingCP(@NonNull Long timeStampMicro, @NonNull Long uiTra /** - * This method is used to check whether the end screen loading feature is enabled or not. + * This method is used to check whether the end screen loading feature is enabled or not. */ @Override public void isEndScreenLoadingEnabled(@NonNull ApmPigeon.Result result) { @@ -453,9 +453,9 @@ public void isEnabled(@NonNull ApmPigeon.Result result) { } } - /** - * checks whether the screen loading feature is enabled. - * */ + /** + * checks whether the screen loading feature is enabled. + */ @Override public void isScreenLoadingEnabled(@NonNull ApmPigeon.Result result) { try { @@ -514,4 +514,14 @@ public void deviceRefreshRate(@NonNull ApmPigeon.Result result) { } } + @Override + public void endScreenRenderForAutoUiTrace(@NonNull Map data) { + + } + + @Override + public void endScreenRenderForCustomUiTrace(@NonNull Map data) { + + } + } diff --git a/ios/Classes/Modules/ApmApi.m b/ios/Classes/Modules/ApmApi.m index 699f07b40..867391730 100644 --- a/ios/Classes/Modules/ApmApi.m +++ b/ios/Classes/Modules/ApmApi.m @@ -3,7 +3,6 @@ #import "ArgsRegistry.h" #import "IBGAPM+PrivateAPIs.h" #import "IBGTimeIntervalUnits.h" -#import "IBGFrameInfo.h" void InitApmApi(id messenger) { ApmApi *api = [[ApmApi alloc] init]; @@ -219,17 +218,23 @@ - (void)deviceRefreshRateWithCompletion:(void (^)(NSNumber * _Nullable, FlutterE } } -- (void)endScreenRenderForAutoUiTraceData:(nonnull NSDictionary *)data error:(FlutterError * _Nullable __autoreleasing * _Nonnull)error { +- (void)endScreenRenderForAutoUiTraceData:(nonnull NSDictionary *)data error:(FlutterError * _Nullable __autoreleasing * _Nonnull)error { int traceId = [data[@"traceId"] intValue]; - int slowFrames = [data[@"slowFramesTotalDuration"] intValue]; - int frozenFrames = [data[@"frozenFramesTotalDuration"] intValue]; - - NSArray *> *rawFrames = data[@"frameData"]; - - //complete from here + int slowFrames = [data[@"slowFramesTotalDuration"] intValue]; + int frozenFrames = [data[@"frozenFramesTotalDuration"] intValue]; - -// [IBGAPM endAutoUITraceCPWithFrames:/*<#(nullable NSArray *)#>*/] + NSArray *> *rawFrames = data[@"frameData"]; + NSLog(@"traceID%d" , traceId); + NSLog(@"slowFrames%d" , slowFrames); + NSLog(@"frozenFrames%d" , frozenFrames); + if (rawFrames && [rawFrames isKindOfClass:[NSArray class]]) { + for (NSArray *frameValues in rawFrames) { + if ([frameValues count] == 2) { + NSLog(@"startTime%lld" , [frameValues[0] longLongValue]); + NSLog(@"duration%lld" , [frameValues[1] longLongValue]); + } + } + } } diff --git a/ios/Classes/Util/IBGAPM+PrivateAPIs.h b/ios/Classes/Util/IBGAPM+PrivateAPIs.h index 27524fc88..423237943 100644 --- a/ios/Classes/Util/IBGAPM+PrivateAPIs.h +++ b/ios/Classes/Util/IBGAPM+PrivateAPIs.h @@ -8,7 +8,7 @@ #import #import "IBGTimeIntervalUnits.h" -#import "IBGFrameInfo.h" +//#import "IBGFrameInfo.h" @interface IBGAPM (PrivateAPIs) @@ -25,8 +25,8 @@ + (BOOL)isScreenRenderingOperational; -+ (void)endAutoUITraceCPWithFrames:(nullable NSArray *)frames; - -+ (void)endCustomUITraceCPWithFrames:(nullable NSArray *)frames; +//+ (void)endAutoUITraceCPWithFrames:(nullable NSArray *)frames; +// +//+ (void)endCustomUITraceCPWithFrames:(nullable NSArray *)frames; @end diff --git a/lib/src/models/instabug_screen_render_data.dart b/lib/src/models/instabug_screen_render_data.dart index 82ea4bcbc..570f57115 100644 --- a/lib/src/models/instabug_screen_render_data.dart +++ b/lib/src/models/instabug_screen_render_data.dart @@ -14,9 +14,11 @@ class InstabugScreenRenderData { this.traceId = -1, }); - bool get isEmpty => traceId == -1; + bool get isEmpty => frameData.isEmpty; - bool get isNotEmpty => !isEmpty; + bool get isNotEmpty => frameData.isNotEmpty; + + bool get isActive => traceId != -1; void clear() { traceId = -1; @@ -26,10 +28,10 @@ class InstabugScreenRenderData { } @override - String toString() => '\nTrace Id $traceId\n' - 'Slow Frames Total Duration: $slowFramesTotalDuration\n' - 'Frozen Frames Total Duration $frozenFramesTotalDuration\n' - 'Frame Data[\n${frameData.map((element) => '\t\n$element')}\n]'; + String toString() => '\nTraceId: $traceId\n' + 'SlowFramesTotalDuration: $slowFramesTotalDuration\n' + 'FrozenFramesTotalDuration: $frozenFramesTotalDuration\n' + 'FrameData: [${frameData.map((element) => '$element')}]'; @override // ignore: hash_and_equals diff --git a/lib/src/modules/apm.dart b/lib/src/modules/apm.dart index 6c389ee7f..124d49e1f 100644 --- a/lib/src/modules/apm.dart +++ b/lib/src/modules/apm.dart @@ -397,7 +397,7 @@ class APM { if (isEnabled) { InstabugScreenRenderManager.I.init(WidgetsBinding.instance); } else { - InstabugScreenRenderManager.I.remove(); + InstabugScreenRenderManager.I.dispose(); } }); } @@ -412,7 +412,7 @@ class APM { /// /// Returns: /// A `Future` is being returned. - Future endScreenRenderForAutoUiTrace(InstabugScreenRenderData data) { + static Future endScreenRenderForAutoUiTrace(InstabugScreenRenderData data) { return _host.endScreenRenderForAutoUiTrace(data.toMap()); } @@ -426,7 +426,7 @@ class APM { /// /// Returns: /// A `Future` is being returned. - Future endScreenRenderForCustomUiTrace(InstabugScreenRenderData data) { + static Future endScreenRenderForCustomUiTrace(InstabugScreenRenderData data) { return _host.endScreenRenderForCustomUiTrace(data.toMap()); } } diff --git a/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart b/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart index 526c2ddc3..f9820ae3f 100644 --- a/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart +++ b/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart @@ -62,13 +62,13 @@ class InstabugScreenRenderManager { try { // passing WidgetsBinding? (nullable) for flutter versions prior than 3.x if (!_isTimingsListenerAttached && widgetBinding != null) { + log("$tag: init", name: 'andrew'); _widgetsBinding = widgetBinding; _addWidgetBindingObserver(); await _initStaticValues(); _initFrameTimings(); screenRenderEnabled = true; } - log("$tag: init", name: 'andrew'); } catch (error, stackTrace) { _logExceptionErrorAndStackTrace(error, stackTrace); } @@ -128,9 +128,9 @@ class InstabugScreenRenderManager { // Return if frameTimingListener not attached if (!screenRenderEnabled || !_isTimingsListenerAttached) { log("$tag: start returned", name: 'andrew'); - return; } + log("$tag: start normally", name: 'andrew'); //Save the memory cached data to be sent to native side if (_delayedFrames.isNotEmpty) { @@ -140,7 +140,9 @@ class InstabugScreenRenderManager { //Sync the captured screen render data of the Custom UI trace when starting new one if (type == UiTraceType.custom) { - if (_screenRenderForCustomUiTrace.isNotEmpty) { + // Report only if the collector was active and has captured data + if (_screenRenderForCustomUiTrace.isActive && + _screenRenderForCustomUiTrace.isNotEmpty) { reportScreenRending( _screenRenderForCustomUiTrace, UiTraceType.custom, @@ -148,17 +150,22 @@ class InstabugScreenRenderManager { _screenRenderForCustomUiTrace.clear(); } _screenRenderForCustomUiTrace.traceId = traceId; + log("$tag: start collecting for auto custom trace $traceId", + name: 'andrew'); } //Sync the captured screen render data of the Auto UI trace when starting new one if (type == UiTraceType.auto) { - if (_screenRenderForAutoUiTrace.isNotEmpty) { + // Report only if the collector was active and has captured data + if (_screenRenderForAutoUiTrace.isActive && + _screenRenderForAutoUiTrace.isNotEmpty) { reportScreenRending(_screenRenderForAutoUiTrace); _screenRenderForAutoUiTrace.clear(); } _screenRenderForAutoUiTrace.traceId = traceId; + log("$tag: start collecting for auto ui trace $traceId", + name: 'andrew'); } - log("$tag: start normally", name: 'andrew'); } catch (error, stackTrace) { _logExceptionErrorAndStackTrace(error, stackTrace); } @@ -168,22 +175,20 @@ class InstabugScreenRenderManager { @internal void stopScreenRenderCollector() { try { - if (_delayedFrames.isEmpty) { - return; - } // No delayed framed to be synced. - - _saveCollectedData(); + if (_delayedFrames.isNotEmpty) { + _saveCollectedData(); + } - if (_screenRenderForCustomUiTrace.isNotEmpty) { + if (_screenRenderForCustomUiTrace.isActive && + _screenRenderForCustomUiTrace.isNotEmpty) { reportScreenRending(_screenRenderForCustomUiTrace, UiTraceType.custom); } - if (_screenRenderForAutoUiTrace.isNotEmpty) { + if (_screenRenderForAutoUiTrace.isActive && + _screenRenderForAutoUiTrace.isNotEmpty) { reportScreenRending(_screenRenderForAutoUiTrace); } - _removeFrameTimings(); - - _resetCachedFrameData(); + dispose(); log("$tag: stop", name: 'andrew'); } catch (error, stackTrace) { _logExceptionErrorAndStackTrace(error, stackTrace); @@ -194,7 +199,7 @@ class InstabugScreenRenderManager { @internal void endScreenRenderCollectorForCustomUiTrace() { try { - if (_screenRenderForCustomUiTrace.isEmpty) { + if (!_screenRenderForCustomUiTrace.isActive) { return; } @@ -224,13 +229,14 @@ class InstabugScreenRenderManager { } else { _reportScreenRenderForCustomUiTrace(screenRenderData); } + log( "$tag: Report ${type == UiTraceType.auto ? 'auto' : 'custom'} Data: $screenRenderData", name: 'andrew', ); } - void remove() { + void dispose() { _resetCachedFrameData(); _removeFrameTimings(); screenRenderEnabled = false; @@ -287,13 +293,13 @@ class InstabugScreenRenderManager { } /// Add a frame observer by calling [WidgetsBinding.instance.addTimingsCallback] - void _initFrameTimings() { if (_isTimingsListenerAttached) { return; // A timings callback is already attached } _widgetsBinding.addTimingsCallback(_timingsCallback); _isTimingsListenerAttached = true; + log("start frame timing", name: 'andrew'); } /// Remove the running frame observer by calling [_widgetsBinding.removeTimingsCallback] @@ -308,6 +314,10 @@ class InstabugScreenRenderManager { _slowFramesTotalDuration = 0; _frozenFramesTotalDuration = 0; _delayedFrames.clear(); + log( + "$tag: Captured data is cleared ", + name: 'andrew', + ); } /// Save Slow/Frozen Frames data @@ -354,34 +364,56 @@ class InstabugScreenRenderManager { } } - Future _reportScreenRenderForCustomUiTrace( + /// Ends custom ui trace with the screen render data that has been collected for it. + /// params: + /// [InstabugScreenRenderData] screenRenderData. + Future _reportScreenRenderForCustomUiTrace( InstabugScreenRenderData screenRenderData, ) async { - //todo: Will be implemented in the next PR + try { + await APM.endScreenRenderForCustomUiTrace(screenRenderData); + return true; + } catch (error, stackTrace) { + _logExceptionErrorAndStackTrace(error, stackTrace); + return false; + } } - Future _reportScreenRenderForAutoUiTrace( + /// Ends auto ui trace with the screen render data that has been collected for it. + /// params: + /// [InstabugScreenRenderData] screenRenderData. + Future _reportScreenRenderForAutoUiTrace( InstabugScreenRenderData screenRenderData, ) async { - //todo: Will be implemented in the next PR + try { + await APM.endScreenRenderForAutoUiTrace(screenRenderData); + return true; + } catch (error, stackTrace) { + _logExceptionErrorAndStackTrace(error, stackTrace); + return false; + } } /// Add the memory cashed data to the objects that will be synced asynchronously to the native side. void _saveCollectedData() { - if (_screenRenderForAutoUiTrace.isNotEmpty) { + if (_screenRenderForAutoUiTrace.isActive) { _screenRenderForAutoUiTrace.slowFramesTotalDuration += _slowFramesTotalDuration; _screenRenderForAutoUiTrace.frozenFramesTotalDuration += _frozenFramesTotalDuration; _screenRenderForAutoUiTrace.frameData.addAll(_delayedFrames); } - if (_screenRenderForCustomUiTrace.isNotEmpty) { + if (_screenRenderForCustomUiTrace.isActive) { _screenRenderForCustomUiTrace.slowFramesTotalDuration += _slowFramesTotalDuration; _screenRenderForCustomUiTrace.frozenFramesTotalDuration += _frozenFramesTotalDuration; _screenRenderForCustomUiTrace.frameData.addAll(_delayedFrames); } + log( + "$tag: Captured data is saved ", + name: 'andrew', + ); } /// @nodoc diff --git a/test/apm_test.dart b/test/apm_test.dart index 0e02cd48e..128b4d860 100644 --- a/test/apm_test.dart +++ b/test/apm_test.dart @@ -301,7 +301,7 @@ void main() { () async { const isEnabled = false; await APM.setScreenRenderEnabled(isEnabled); - verify(mScreenRenderManager.remove()).called(1); + verify(mScreenRenderManager.dispose()).called(1); verifyNoMoreInteractions(mScreenRenderManager); }); diff --git a/test/utils/screen_render/instabug_screen_render_manager_test.dart b/test/utils/screen_render/instabug_screen_render_manager_test.dart index 15ebf3c9e..7759d62c3 100644 --- a/test/utils/screen_render/instabug_screen_render_manager_test.dart +++ b/test/utils/screen_render/instabug_screen_render_manager_test.dart @@ -81,18 +81,18 @@ void main() { const firstTraceId = 123; const secondTraceId = 456; - expect(manager.screenRenderForAutoUiTrace.isNotEmpty, false); + expect(manager.screenRenderForAutoUiTrace.isActive, false); manager.startScreenRenderCollectorForTraceId( firstTraceId, ); - expect(manager.screenRenderForAutoUiTrace.isNotEmpty, true); + expect(manager.screenRenderForAutoUiTrace.isActive, true); expect(manager.screenRenderForAutoUiTrace.traceId, firstTraceId); manager.startScreenRenderCollectorForTraceId( secondTraceId, ); - expect(manager.screenRenderForAutoUiTrace.isNotEmpty, true); + expect(manager.screenRenderForAutoUiTrace.isActive, true); expect(manager.screenRenderForAutoUiTrace.traceId, secondTraceId); }); @@ -100,13 +100,13 @@ void main() { const firstTraceId = 123; const secondTraceId = 456; - expect(manager.screenRenderForAutoUiTrace.isNotEmpty, false); - expect(manager.screenRenderForCustomUiTrace.isNotEmpty, false); + expect(manager.screenRenderForAutoUiTrace.isActive, false); + expect(manager.screenRenderForCustomUiTrace.isActive, false); manager.startScreenRenderCollectorForTraceId( firstTraceId, ); - expect(manager.screenRenderForAutoUiTrace.isNotEmpty, true); + expect(manager.screenRenderForAutoUiTrace.isActive, true); expect(manager.screenRenderForAutoUiTrace.traceId, firstTraceId); manager.startScreenRenderCollectorForTraceId( @@ -134,10 +134,10 @@ void main() { manager.stopScreenRenderCollector(); - expect(manager.screenRenderForAutoUiTrace.isEmpty, true); + expect(manager.screenRenderForAutoUiTrace.isActive, false); expect(manager.screenRenderForAutoUiTrace == frameTestdata, false); - expect(manager.screenRenderForCustomUiTrace.isEmpty, true); + expect(manager.screenRenderForCustomUiTrace.isActive, false); expect(manager.screenRenderForCustomUiTrace == frameTestdata, false); }); @@ -162,11 +162,11 @@ void main() { manager.stopScreenRenderCollector(); - expect(manager.screenRenderForAutoUiTrace.isNotEmpty, true); + expect(manager.screenRenderForAutoUiTrace.isActive, true); expect(manager.screenRenderForAutoUiTrace == frameTestdata, true); - expect(manager.screenRenderForCustomUiTrace.isEmpty, true); + expect(manager.screenRenderForCustomUiTrace.isActive, false); }); test( @@ -191,17 +191,11 @@ void main() { manager.stopScreenRenderCollector(); - expect(manager.screenRenderForCustomUiTrace.isNotEmpty, true); + expect(manager.screenRenderForCustomUiTrace.isActive, true); expect(manager.screenRenderForCustomUiTrace == frameTestdata, true); - expect(manager.screenRenderForAutoUiTrace.isEmpty, true); - }); - - test('should do nothing if there is no cached data', () { - manager.stopScreenRenderCollector(); - - verifyNever(mWidgetBinding.removeTimingsCallback(any)); + expect(manager.screenRenderForAutoUiTrace.isActive, false); }); test('should remove timing callback listener', () { @@ -249,7 +243,7 @@ void main() { manager.endScreenRenderCollectorForCustomUiTrace(); - expect(manager.screenRenderForCustomUiTrace.isEmpty, true); + expect(manager.screenRenderForCustomUiTrace.isActive, false); expect(manager.screenRenderForCustomUiTrace == frameTestdata, false); }); From 49652b77145651316aa4dcd34c504b13a83aa715 Mon Sep 17 00:00:00 2001 From: ahmed alaa <154802748+ahmedAlaaInstabug@users.noreply.github.com> Date: Mon, 7 Jul 2025 13:34:59 +0300 Subject: [PATCH 18/84] bump: android SDK to 15.0.2 (#594) * bump: android SDK to 15.0.2 * bump: android SDK to 15.0.2 --- CHANGELOG.md | 4 +- android/build.gradle | 2 +- example/pubspec.lock | 88 ++++++++++++++++++++++---------------------- pubspec.yaml | 2 +- 4 files changed, 48 insertions(+), 48 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 039ad6ae1..86c0b6245 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Changelog -## [15.0.1](https://github.com/Instabug/Instabug-Flutter/compare/v14.3.0...15.0.1) +## [15.0.2](https://github.com/Instabug/Instabug-Flutter/compare/v14.3.0...15.0.1) (Jul 7, 2025) ### Added @@ -12,7 +12,7 @@ - Bump Instabug iOS SDK to v15.1.1 ([#581](https://github.com/Instabug/Instabug-Flutter/pull/581)). [See release notes](https://github.com/Instabug/Instabug-iOS/releases/tag/15.1.1). -- Bump Instabug Android SDK to v15.0.1 ([#581](https://github.com/Instabug/Instabug-Flutter/pull/581)). [See release notes](https://github.com/Instabug/Instabug-Android/releases/tag/v15.0.1). +- Bump Instabug Android SDK to v15.0.2 ([#581](https://github.com/Instabug/Instabug-Flutter/pull/581)). [See release notes](https://github.com/Instabug/Instabug-Android/releases/tag/v15.0.2). ## [14.3.1](https://github.com/Instabug/Instabug-Flutter/compare/v14.3.0...14.3.1) (May 20, 2025) diff --git a/android/build.gradle b/android/build.gradle index be7f0c4dc..e6d2bb3ed 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -47,7 +47,7 @@ android { } dependencies { - api 'com.instabug.library:instabug:15.0.1' + api 'com.instabug.library:instabug:15.0.2' testImplementation 'junit:junit:4.13.2' testImplementation "org.mockito:mockito-inline:3.12.1" testImplementation "io.mockk:mockk:1.13.13" diff --git a/example/pubspec.lock b/example/pubspec.lock index b6bf3b61e..99e8f9d56 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -5,58 +5,58 @@ packages: dependency: transitive description: name: async - sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63 + sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" url: "https://pub.dev" source: hosted - version: "2.12.0" + version: "2.11.0" boolean_selector: dependency: transitive description: name: boolean_selector - sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" + sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.1" characters: dependency: transitive description: name: characters - sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 + sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" url: "https://pub.dev" source: hosted - version: "1.4.0" + version: "1.3.0" clock: dependency: transitive description: name: clock - sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b + sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf url: "https://pub.dev" source: hosted - version: "1.1.2" + version: "1.1.1" collection: dependency: transitive description: name: collection - sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" + sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf url: "https://pub.dev" source: hosted - version: "1.19.1" + version: "1.19.0" fake_async: dependency: transitive description: name: fake_async - sha256: "6a95e56b2449df2273fd8c45a662d6947ce1ebb7aafe80e550a3f68297f3cacc" + sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" url: "https://pub.dev" source: hosted - version: "1.3.2" + version: "1.3.1" file: dependency: transitive description: name: file - sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 + sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c" url: "https://pub.dev" source: hosted - version: "7.0.1" + version: "7.0.0" flutter: dependency: "direct main" description: flutter @@ -107,7 +107,7 @@ packages: path: ".." relative: true source: path - version: "15.0.1" + version: "15.0.2" instabug_http_client: dependency: "direct main" description: @@ -120,18 +120,18 @@ packages: dependency: transitive description: name: leak_tracker - sha256: c35baad643ba394b40aac41080300150a4f08fd0fd6a10378f8f7c6bc161acec + sha256: "7bb2830ebd849694d1ec25bf1f44582d6ac531a57a365a803a6034ff751d2d06" url: "https://pub.dev" source: hosted - version: "10.0.8" + version: "10.0.7" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573 + sha256: "9491a714cca3667b60b5c420da8217e6de0d1ba7a5ec322fab01758f6998f379" url: "https://pub.dev" source: hosted - version: "3.0.9" + version: "3.0.8" leak_tracker_testing: dependency: transitive description: @@ -152,10 +152,10 @@ packages: dependency: transitive description: name: matcher - sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 + sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb url: "https://pub.dev" source: hosted - version: "0.12.17" + version: "0.12.16+1" material_color_utilities: dependency: transitive description: @@ -168,34 +168,34 @@ packages: dependency: transitive description: name: meta - sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c + sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 url: "https://pub.dev" source: hosted - version: "1.16.0" + version: "1.15.0" path: dependency: transitive description: name: path - sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" + sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" url: "https://pub.dev" source: hosted - version: "1.9.1" + version: "1.9.0" platform: dependency: transitive description: name: platform - sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984" + sha256: "9b71283fc13df574056616011fb138fd3b793ea47cc509c189a6c3fa5f8a1a65" url: "https://pub.dev" source: hosted - version: "3.1.6" + version: "3.1.5" process: dependency: transitive description: name: process - sha256: "107d8be718f120bbba9dcd1e95e3bd325b1b4a4f07db64154635ba03f2567a0d" + sha256: "21e54fd2faf1b5bdd5102afd25012184a6793927648ea81eea80552ac9405b32" url: "https://pub.dev" source: hosted - version: "5.0.3" + version: "5.0.2" sky_engine: dependency: transitive description: flutter @@ -205,34 +205,34 @@ packages: dependency: transitive description: name: source_span - sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c" + sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" url: "https://pub.dev" source: hosted - version: "1.10.1" + version: "1.10.0" stack_trace: dependency: transitive description: name: stack_trace - sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" + sha256: "9f47fd3630d76be3ab26f0ee06d213679aa425996925ff3feffdec504931c377" url: "https://pub.dev" source: hosted - version: "1.12.1" + version: "1.12.0" stream_channel: dependency: transitive description: name: stream_channel - sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" + sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 url: "https://pub.dev" source: hosted - version: "2.1.4" + version: "2.1.2" string_scanner: dependency: transitive description: name: string_scanner - sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" + sha256: "688af5ed3402a4bde5b3a6c15fd768dbf2621a614950b17f04626c431ab3c4c3" url: "https://pub.dev" source: hosted - version: "1.4.1" + version: "1.3.0" sync_http: dependency: transitive description: @@ -245,18 +245,18 @@ packages: dependency: transitive description: name: term_glyph - sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 url: "https://pub.dev" source: hosted - version: "1.2.2" + version: "1.2.1" test_api: dependency: transitive description: name: test_api - sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd + sha256: "664d3a9a64782fcdeb83ce9c6b39e78fd2971d4e37827b9b06c3aa1edc5e760c" url: "https://pub.dev" source: hosted - version: "0.7.4" + version: "0.7.3" typed_data: dependency: transitive description: @@ -277,10 +277,10 @@ packages: dependency: transitive description: name: vm_service - sha256: "0968250880a6c5fe7edc067ed0a13d4bae1577fe2771dcf3010d52c4a9d3ca14" + sha256: f6be3ed8bd01289b34d679c2b62226f63c0e69f9fd2e50a6b3c1c729a961041b url: "https://pub.dev" source: hosted - version: "14.3.1" + version: "14.3.0" webdriver: dependency: transitive description: @@ -290,5 +290,5 @@ packages: source: hosted version: "3.0.4" sdks: - dart: ">=3.7.0-0 <4.0.0" + dart: ">=3.5.0 <4.0.0" flutter: ">=3.18.0-18.0.pre.54" diff --git a/pubspec.yaml b/pubspec.yaml index b6957c5b8..86884fb71 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: instabug_flutter -version: 15.0.1 +version: 15.0.2 description: >- Instabug empowers mobile teams to monitor, prioritize, and debug performance and stability issues throughout the app development lifecycle. From dd69dcc73eae72e2bb8bd91cb3e3d74c32ba1fa4 Mon Sep 17 00:00:00 2001 From: ahmed alaa <154802748+ahmedAlaaInstabug@users.noreply.github.com> Date: Wed, 9 Jul 2025 13:37:00 +0300 Subject: [PATCH 19/84] Merge pull request #597 from Instabug/release/androidv15.0.2 Release: v15.0.2 --- CHANGELOG.md | 2 +- android/build.gradle | 2 +- example/ios/Podfile.lock | 4 ++-- ios/instabug_flutter.podspec | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 86c0b6245..9cb867f5c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Changelog -## [15.0.2](https://github.com/Instabug/Instabug-Flutter/compare/v14.3.0...15.0.1) (Jul 7, 2025) +## [15.0.2](https://github.com/Instabug/Instabug-Flutter/compare/v14.3.0...15.0.2) (Jul 7, 2025) ### Added diff --git a/android/build.gradle b/android/build.gradle index e6d2bb3ed..0f1d8b852 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -1,5 +1,5 @@ group 'com.instabug.flutter' -version '15.0.1' +version '15.0.2' buildscript { repositories { diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index 619d1436c..505c29865 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -1,7 +1,7 @@ PODS: - Flutter (1.0.0) - Instabug (15.1.1) - - instabug_flutter (15.0.1): + - instabug_flutter (15.0.2): - Flutter - Instabug (= 15.1.1) - OCMock (3.6) @@ -25,7 +25,7 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 Instabug: 3e7af445c14d7823fcdecba223f09b5f7c0c6ce1 - instabug_flutter: e4e366434313bab3a2db123c1501ca6247dc950b + instabug_flutter: c5a8cb73d6c50dd193fc267b0b283087dc05c37a OCMock: 5ea90566be239f179ba766fd9fbae5885040b992 PODFILE CHECKSUM: 4d0aaaf6a444f68024f992999ff2c2ee26baa6ec diff --git a/ios/instabug_flutter.podspec b/ios/instabug_flutter.podspec index 2d898f9c6..785f1c07b 100644 --- a/ios/instabug_flutter.podspec +++ b/ios/instabug_flutter.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'instabug_flutter' - s.version = '15.0.1' + s.version = '15.0.2' s.summary = 'Flutter plugin for integrating the Instabug SDK.' s.author = 'Instabug' s.homepage = 'https://www.instabug.com/platforms/flutter' From b183a4330265d3b0acfc55ac80d6509a1b66064f Mon Sep 17 00:00:00 2001 From: Andrew Amin Date: Wed, 9 Jul 2025 17:20:19 +0300 Subject: [PATCH 20/84] chore: add store API in iOS side --- example/ios/InstabugTests/ApmApiTests.m | 320 ++++++++++++++++++ example/ios/Podfile | 2 +- example/ios/Podfile.lock | 14 +- example/lib/main.dart | 1 + .../lib/src/screens/screen_render_page.dart | 37 +- ios/Classes/Modules/ApmApi.m | 36 +- ios/Classes/Util/IBGAPM+PrivateAPIs.h | 10 +- ios/instabug_flutter.podspec | 2 +- lib/src/modules/apm.dart | 14 +- .../utils/instabug_navigator_observer.dart | 34 +- .../instabug_screen_render_manager.dart | 68 ++-- .../instabug_widget_binding_observer.dart | 3 + .../instabug_screen_render_manager_test.dart | 82 +++-- 13 files changed, 512 insertions(+), 111 deletions(-) diff --git a/example/ios/InstabugTests/ApmApiTests.m b/example/ios/InstabugTests/ApmApiTests.m index bdb710ac7..ae634487d 100644 --- a/example/ios/InstabugTests/ApmApiTests.m +++ b/example/ios/InstabugTests/ApmApiTests.m @@ -266,5 +266,325 @@ - (void)testEndScreenLoading { OCMVerify([self.mAPM endScreenLoadingCPWithEndTimestampMUS:endScreenLoadingCPWithEndTimestampMUS]); } +- (void)testIsScreenRenderEnabled { + XCTestExpectation *expectation = [self expectationWithDescription:@"Call completion handler"]; + + BOOL isScreenRenderEnabled = YES; + OCMStub([self.mAPM isScreenRenderingOperational]).andReturn(isScreenRenderEnabled); + + [self.api isScreenRenderEnabledWithCompletion:^(NSNumber *isEnabledNumber, FlutterError *error) { + [expectation fulfill]; + + XCTAssertEqualObjects(isEnabledNumber, @(isScreenRenderEnabled)); + XCTAssertNil(error); + }]; + + [self waitForExpectations:@[expectation] timeout:5.0]; +} + +- (void)testIsScreenRenderEnabledWhenDisabled { + XCTestExpectation *expectation = [self expectationWithDescription:@"Call completion handler"]; + + BOOL isScreenRenderEnabled = NO; + OCMStub([self.mAPM isScreenRenderingOperational]).andReturn(isScreenRenderEnabled); + + [self.api isScreenRenderEnabledWithCompletion:^(NSNumber *isEnabledNumber, FlutterError *error) { + [expectation fulfill]; + + XCTAssertEqualObjects(isEnabledNumber, @(isScreenRenderEnabled)); + XCTAssertNil(error); + }]; + + [self waitForExpectations:@[expectation] timeout:5.0]; +} + +- (void)testSetScreenRenderEnabled { + NSNumber *isEnabled = @1; + FlutterError *error; + + [self.api setScreenRenderEnabledIsEnabled:isEnabled error:&error]; + + OCMVerify([self.mAPM setScreenRenderingEnabled:YES]); +} + +- (void)testSetScreenRenderDisabled { + NSNumber *isEnabled = @0; + FlutterError *error; + + [self.api setScreenRenderEnabledIsEnabled:isEnabled error:&error]; + + OCMVerify([self.mAPM setScreenRenderingEnabled:NO]); +} + +- (void)testDeviceRefreshRate { + XCTestExpectation *expectation = [self expectationWithDescription:@"Call completion handler"]; + + // Mock UIScreen for iOS 10.3+ + id mockScreen = OCMClassMock([UIScreen class]); + OCMStub([mockScreen mainScreen]).andReturn(mockScreen); + OCMStub([mockScreen maximumFramesPerSecond]).andReturn(120.0); + + [self.api deviceRefreshRateWithCompletion:^(NSNumber *refreshRate, FlutterError *error) { + [expectation fulfill]; + + XCTAssertEqualObjects(refreshRate, @(120.0)); + XCTAssertNil(error); + }]; + + [self waitForExpectations:@[expectation] timeout:5.0]; + + [mockScreen stopMocking]; +} + +- (void)testDeviceRefreshRateFallback { + XCTestExpectation *expectation = [self expectationWithDescription:@"Call completion handler"]; + + // Note: Testing the fallback behavior for iOS < 10.3 is challenging in unit tests + // since we can't easily mock the iOS version check. In a real scenario, this would + // return 60.0 for older iOS versions. For now, we'll test the normal case. + + // Mock UIScreen to return 60.0 (typical fallback value) + id mockScreen = OCMClassMock([UIScreen class]); + OCMStub([mockScreen mainScreen]).andReturn(mockScreen); + OCMStub([mockScreen maximumFramesPerSecond]).andReturn(60.0); + + [self.api deviceRefreshRateWithCompletion:^(NSNumber *refreshRate, FlutterError *error) { + [expectation fulfill]; + + XCTAssertEqualObjects(refreshRate, @(60.0)); + XCTAssertNil(error); + }]; + + [self waitForExpectations:@[expectation] timeout:5.0]; + + [mockScreen stopMocking]; +} + +- (void)testEndScreenRenderForAutoUiTrace { + FlutterError *error; + + // Create mock frame data + NSDictionary *frameData = @{ + @"frameData": @[ + @[@(1000.0), @(16.67)], // Frame 1: start time 1000.0µs, duration 16.67µs + @[@(1016.67), @(33.33)], // Frame 2: start time 1016.67µs, duration 33.33µs + @[@(1050.0), @(50.0)] // Frame 3: start time 1050.0µs, duration 50.0µs + ] + }; + + [self.api endScreenRenderForAutoUiTraceData:frameData error:&error]; + + // Verify that endAutoUITraceCPWithFrames was called + OCMVerify([self.mAPM endAutoUITraceCPWithFrames:[OCMArg checkWithBlock:^BOOL(NSArray *frames) { + // Verify that we have the correct number of frames + XCTAssertEqual(frames.count, 3); + + // Verify the first frame + IBGFrameInfo *firstFrame = frames[0]; + XCTAssertEqual(firstFrame.startTimestampInMicroseconds, 1000.0); + XCTAssertEqual(firstFrame.durationInMicroseconds, 16.67); + + // Verify the second frame + IBGFrameInfo *secondFrame = frames[1]; + XCTAssertEqual(secondFrame.startTimestampInMicroseconds, 1016.67); + XCTAssertEqual(secondFrame.durationInMicroseconds, 33.33); + + // Verify the third frame + IBGFrameInfo *thirdFrame = frames[2]; + XCTAssertEqual(thirdFrame.startTimestampInMicroseconds, 1050.0); + XCTAssertEqual(thirdFrame.durationInMicroseconds, 50.0); + + return YES; + }]]); +} + +- (void)testEndScreenRenderForCustomUiTrace { + FlutterError *error; + + // Create mock frame data + NSDictionary *frameData = @{ + @"frameData": @[ + @[@(2000.0), @(20.0)], // Frame 1: start time 2000.0µs, duration 20.0µs + @[@(2020.0), @(25.0)] // Frame 2: start time 2020.0µs, duration 25.0µs + ] + }; + + [self.api endScreenRenderForCustomUiTraceData:frameData error:&error]; + + // Verify that endCustomUITraceCPWithFrames was called + OCMVerify([self.mAPM endCustomUITraceCPWithFrames:[OCMArg checkWithBlock:^BOOL(NSArray *frames) { + // Verify that we have the correct number of frames + XCTAssertEqual(frames.count, 2); + + // Verify the first frame + IBGFrameInfo *firstFrame = frames[0]; + XCTAssertEqual(firstFrame.startTimestampInMicroseconds, 2000.0); + XCTAssertEqual(firstFrame.durationInMicroseconds, 20.0); + + // Verify the second frame + IBGFrameInfo *secondFrame = frames[1]; + XCTAssertEqual(secondFrame.startTimestampInMicroseconds, 2020.0); + XCTAssertEqual(secondFrame.durationInMicroseconds, 25.0); + + return YES; + }]]); +} + +- (void)testEndScreenRenderForAutoUiTraceWithEmptyFrameData { + FlutterError *error; + + // Create empty frame data + NSDictionary *frameData = @{ + @"frameData": @[] + }; + + [self.api endScreenRenderForAutoUiTraceData:frameData error:&error]; + + // Verify that endAutoUITraceCPWithFrames was called with empty array + OCMVerify([self.mAPM endAutoUITraceCPWithFrames:[OCMArg checkWithBlock:^BOOL(NSArray *frames) { + XCTAssertEqual(frames.count, 0); + return YES; + }]]); +} + +- (void)testEndScreenRenderForCustomUiTraceWithEmptyFrameData { + FlutterError *error; + + // Create empty frame data + NSDictionary *frameData = @{ + @"frameData": @[] + }; + + [self.api endScreenRenderForCustomUiTraceData:frameData error:&error]; + + // Verify that endCustomUITraceCPWithFrames was called with empty array + OCMVerify([self.mAPM endCustomUITraceCPWithFrames:[OCMArg checkWithBlock:^BOOL(NSArray *frames) { + XCTAssertEqual(frames.count, 0); + return YES; + }]]); +} + +- (void)testEndScreenRenderForAutoUiTraceWithMalformedFrameData { + FlutterError *error; + + // Create malformed frame data (missing values or extra values) + NSDictionary *frameData = @{ + @"frameData": @[ + @[@(1000.0)], // Frame with only one value (should be ignored) + @[@(1016.67), @(33.33)], // Valid frame + @[@(1050.0), @(50.0), @(100.0)] // Frame with extra values (should be ignored) + ] + }; + + [self.api endScreenRenderForAutoUiTraceData:frameData error:&error]; + + // Verify that endAutoUITraceCPWithFrames was called with only valid frames + OCMVerify([self.mAPM endAutoUITraceCPWithFrames:[OCMArg checkWithBlock:^BOOL(NSArray *frames) { + // Should only have 1 valid frame (first and third frames are ignored due to wrong count) + XCTAssertEqual(frames.count, 1); + + // Verify the valid frame + IBGFrameInfo *frame = frames[0]; + XCTAssertEqual(frame.startTimestampInMicroseconds, 1016.67); + XCTAssertEqual(frame.durationInMicroseconds, 33.33); + + return YES; + }]]); +} + +- (void)testEndScreenRenderForCustomUiTraceWithMalformedFrameData { + FlutterError *error; + + // Create malformed frame data (missing values) + NSDictionary *frameData = @{ + @"frameData": @[ + @[@(2000.0)], // Frame with only one value (should be ignored) + @[@(2020.0), @(25.0)] // Valid frame + ] + }; + + [self.api endScreenRenderForCustomUiTraceData:frameData error:&error]; + + // Verify that endCustomUITraceCPWithFrames was called with only valid frames + OCMVerify([self.mAPM endCustomUITraceCPWithFrames:[OCMArg checkWithBlock:^BOOL(NSArray *frames) { + // Should only have 1 valid frame + XCTAssertEqual(frames.count, 1); + + // Verify the valid frame + IBGFrameInfo *frame = frames[0]; + XCTAssertEqual(frame.startTimestampInMicroseconds, 2020.0); + XCTAssertEqual(frame.durationInMicroseconds, 25.0); + + return YES; + }]]); +} + +- (void)testEndScreenRenderForAutoUiTraceWithNilFrameData { + FlutterError *error; + + // Create frame data with nil frameData + NSDictionary *frameData = @{ + @"frameData": [NSNull null] + }; + + [self.api endScreenRenderForAutoUiTraceData:frameData error:&error]; + + // Verify that endAutoUITraceCPWithFrames was called with empty array + OCMVerify([self.mAPM endAutoUITraceCPWithFrames:[OCMArg checkWithBlock:^BOOL(NSArray *frames) { + XCTAssertEqual(frames.count, 0); + return YES; + }]]); +} + +- (void)testEndScreenRenderForCustomUiTraceWithNilFrameData { + FlutterError *error; + + // Create frame data with nil frameData + NSDictionary *frameData = @{ + @"frameData": [NSNull null] + }; + + [self.api endScreenRenderForCustomUiTraceData:frameData error:&error]; + + // Verify that endCustomUITraceCPWithFrames was called with empty array + OCMVerify([self.mAPM endCustomUITraceCPWithFrames:[OCMArg checkWithBlock:^BOOL(NSArray *frames) { + XCTAssertEqual(frames.count, 0); + return YES; + }]]); +} + +- (void)testEndScreenRenderForAutoUiTraceWithMissingFrameDataKey { + FlutterError *error; + + // Create frame data without frameData key + NSDictionary *frameData = @{ + @"otherKey": @"someValue" + }; + + [self.api endScreenRenderForAutoUiTraceData:frameData error:&error]; + + // Verify that endAutoUITraceCPWithFrames was called with empty array + OCMVerify([self.mAPM endAutoUITraceCPWithFrames:[OCMArg checkWithBlock:^BOOL(NSArray *frames) { + XCTAssertEqual(frames.count, 0); + return YES; + }]]); +} + +- (void)testEndScreenRenderForCustomUiTraceWithMissingFrameDataKey { + FlutterError *error; + + // Create frame data without frameData key + NSDictionary *frameData = @{ + @"otherKey": @"someValue" + }; + + [self.api endScreenRenderForCustomUiTraceData:frameData error:&error]; + + // Verify that endCustomUITraceCPWithFrames was called with empty array + OCMVerify([self.mAPM endCustomUITraceCPWithFrames:[OCMArg checkWithBlock:^BOOL(NSArray *frames) { + XCTAssertEqual(frames.count, 0); + return YES; + }]]); +} @end diff --git a/example/ios/Podfile b/example/ios/Podfile index 85792c734..f74d6afed 100644 --- a/example/ios/Podfile +++ b/example/ios/Podfile @@ -30,7 +30,7 @@ target 'Runner' do use_frameworks! use_modular_headers! - pod 'Instabug', :podspec => 'https://ios-releases.instabug.com/custom/faeture-screen_rendering-release/15.1.6/Instabug.podspec' + pod 'Instabug', :podspec => 'https://ios-releases.instabug.com/custom/faeture-screen_rendering-release/15.1.13/Instabug.podspec' flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) end diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index 62bbff217..f691b0f5f 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -1,14 +1,14 @@ PODS: - Flutter (1.0.0) - - Instabug (15.1.6) + - Instabug (15.1.13) - instabug_flutter (14.3.0): - Flutter - - Instabug (= 15.1.6) + - Instabug (= 15.1.13) - OCMock (3.6) DEPENDENCIES: - Flutter (from `Flutter`) - - Instabug (from `https://ios-releases.instabug.com/custom/faeture-screen_rendering-release/15.1.6/Instabug.podspec`) + - Instabug (from `https://ios-releases.instabug.com/custom/faeture-screen_rendering-release/15.1.13/Instabug.podspec`) - instabug_flutter (from `.symlinks/plugins/instabug_flutter/ios`) - OCMock (= 3.6) @@ -20,16 +20,16 @@ EXTERNAL SOURCES: Flutter: :path: Flutter Instabug: - :podspec: https://ios-releases.instabug.com/custom/faeture-screen_rendering-release/15.1.6/Instabug.podspec + :podspec: https://ios-releases.instabug.com/custom/faeture-screen_rendering-release/15.1.13/Instabug.podspec instabug_flutter: :path: ".symlinks/plugins/instabug_flutter/ios" SPEC CHECKSUMS: Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 - Instabug: 160e6c775d933adcb577bb6b0246392d4e2c7796 - instabug_flutter: 8dd37e80d4f4883723b7f7b211e3f1907d85e5d3 + Instabug: 697dc090bbdb9b99a9a91758558f8a2014ee5725 + instabug_flutter: 1093324eaca70f9d310a4bc7f1f3537c746c1d6c OCMock: 5ea90566be239f179ba766fd9fbae5885040b992 -PODFILE CHECKSUM: 96100ba35e9247b6dd1f0e51d13d3880f140fb35 +PODFILE CHECKSUM: 509cc3728286920762d8cbecfac090a3af93635d COCOAPODS: 1.15.2 diff --git a/example/lib/main.dart b/example/lib/main.dart index 1c95863e0..d3a16aa52 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'dart:convert'; import 'dart:developer'; import 'dart:io'; +import 'dart:math' show Random; import 'package:flutter/material.dart'; import 'package:instabug_flutter/instabug_flutter.dart'; diff --git a/example/lib/src/screens/screen_render_page.dart b/example/lib/src/screens/screen_render_page.dart index 872435f99..f8dddf96b 100644 --- a/example/lib/src/screens/screen_render_page.dart +++ b/example/lib/src/screens/screen_render_page.dart @@ -9,14 +9,6 @@ class ScreenRenderPage extends StatefulWidget { } class _ScreenRenderPageState extends State { - final durationController = TextEditingController(); - - @override - void dispose() { - durationController.dispose(); - super.dispose(); - } - @override Widget build(BuildContext context) { return Page(title: 'Screen Render', children: [ @@ -26,15 +18,14 @@ class _ScreenRenderPageState extends State { SizedBox.fromSize( size: const Size.fromHeight(50), ), - InstabugTextField( - label: 'Frame duration in milliseconds', - labelStyle: Theme.of(context).textTheme.labelMedium, - controller: durationController, - ), SizedBox.fromSize(size: const Size.fromHeight(16.0)), InstabugButton( - text: 'Perform Heavy Computation', - onPressed: () => _simulateHeavyComputation(), + text: 'Trigger Slow Frame', + onPressed: () => _simulateHeavyComputationForSlowFrames(), + ), + InstabugButton( + text: 'Trigger Frozen Frame', + onPressed: () => _simulateHeavyComputationForFrozenFrames(), ), InstabugButton( text: 'Monitored Complex Page', @@ -56,13 +47,17 @@ class _ScreenRenderPageState extends State { } // Simulates a computationally expensive task - void _simulateHeavyComputation() { - final startTime = DateTime.now(); - final pauseTime = double.tryParse(durationController.text.trim()); - // Block the UI thread for ~500ms - if (pauseTime == null) { - return log("enter a valid number"); + void _simulateHeavyComputationForSlowFrames() { + Random random = Random(); + for (int i = 0; i < 1000000; i++) { + random.nextInt(100) * random.nextInt(100); } + } + + _simulateHeavyComputationForFrozenFrames() { + final startTime = DateTime.now(); + const pauseTime = 1000; + // Block the UI thread for ~1000ms while (DateTime.now().difference(startTime).inMilliseconds <= pauseTime) { // Busy waiting } diff --git a/ios/Classes/Modules/ApmApi.m b/ios/Classes/Modules/ApmApi.m index 867391730..4787a9b22 100644 --- a/ios/Classes/Modules/ApmApi.m +++ b/ios/Classes/Modules/ApmApi.m @@ -76,7 +76,7 @@ - (void)setAutoUITraceEnabledIsEnabled:(NSNumber *)isEnabled error:(FlutterError // Deprecated - see [startFlowName, setFlowAttributeName & endFlowName]. - (void)startExecutionTraceId:(NSString *)id name:(NSString *)name completion:(void(^)(NSString *_Nullable, FlutterError *_Nullable))completion { IBGExecutionTrace *trace = [IBGAPM startExecutionTraceWithName:name]; - + if (trace != nil) { [traces setObject:trace forKey:id]; return completion(id, nil); @@ -219,27 +219,39 @@ - (void)deviceRefreshRateWithCompletion:(void (^)(NSNumber * _Nullable, FlutterE } - (void)endScreenRenderForAutoUiTraceData:(nonnull NSDictionary *)data error:(FlutterError * _Nullable __autoreleasing * _Nonnull)error { - int traceId = [data[@"traceId"] intValue]; - int slowFrames = [data[@"slowFramesTotalDuration"] intValue]; - int frozenFrames = [data[@"frozenFramesTotalDuration"] intValue]; - NSArray *> *rawFrames = data[@"frameData"]; - NSLog(@"traceID%d" , traceId); - NSLog(@"slowFrames%d" , slowFrames); - NSLog(@"frozenFrames%d" , frozenFrames); + NSMutableArray *frameInfos = [[NSMutableArray alloc] init]; + if (rawFrames && [rawFrames isKindOfClass:[NSArray class]]) { for (NSArray *frameValues in rawFrames) { if ([frameValues count] == 2) { - NSLog(@"startTime%lld" , [frameValues[0] longLongValue]); - NSLog(@"duration%lld" , [frameValues[1] longLongValue]); + IBGFrameInfo *frameInfo = [[IBGFrameInfo alloc] init]; + frameInfo.startTimestampInMicroseconds = [frameValues[0] doubleValue]; + frameInfo.durationInMicroseconds = [frameValues[1] doubleValue]; + [frameInfos addObject:frameInfo]; } } } + [IBGAPM endAutoUITraceCPWithFrames:frameInfos]; } -- (void)endScreenRenderForCustomUiTraceData:(nonnull NSDictionary *)data error:(FlutterError * _Nullable __autoreleasing * _Nonnull)error { - //code +- (void)endScreenRenderForCustomUiTraceData:(nonnull NSDictionary *)data error:(FlutterError * _Nullable __autoreleasing * _Nonnull)error { + NSArray *> *rawFrames = data[@"frameData"]; + NSMutableArray *frameInfos = [[NSMutableArray alloc] init]; + + if (rawFrames && [rawFrames isKindOfClass:[NSArray class]]) { + for (NSArray *frameValues in rawFrames) { + if ([frameValues count] == 2) { + IBGFrameInfo *frameInfo = [[IBGFrameInfo alloc] init]; + frameInfo.startTimestampInMicroseconds = [frameValues[0] doubleValue]; + frameInfo.durationInMicroseconds = [frameValues[1] doubleValue]; + [frameInfos addObject:frameInfo]; + } + } + } + + [IBGAPM endCustomUITraceCPWithFrames:frameInfos]; } diff --git a/ios/Classes/Util/IBGAPM+PrivateAPIs.h b/ios/Classes/Util/IBGAPM+PrivateAPIs.h index 423237943..c562e629e 100644 --- a/ios/Classes/Util/IBGAPM+PrivateAPIs.h +++ b/ios/Classes/Util/IBGAPM+PrivateAPIs.h @@ -8,7 +8,7 @@ #import #import "IBGTimeIntervalUnits.h" -//#import "IBGFrameInfo.h" +#import @interface IBGAPM (PrivateAPIs) @@ -16,6 +16,8 @@ /// `endScreenLoadingEnabled` will be only true if APM, screenLoadingFeature.enabled and autoUITracesUserPreference are true @property (class, atomic, assign) BOOL endScreenLoadingEnabled; ++ (void)setScreenRenderingEnabled:(BOOL)enabled; + + (void)startUITraceCPWithName:(NSString *)name startTimestampMUS:(IBGMicroSecondsTimeInterval)startTimestampMUS; + (void)reportScreenLoadingCPWithStartTimestampMUS:(IBGMicroSecondsTimeInterval)startTimestampMUS @@ -25,8 +27,8 @@ + (BOOL)isScreenRenderingOperational; -//+ (void)endAutoUITraceCPWithFrames:(nullable NSArray *)frames; -// -//+ (void)endCustomUITraceCPWithFrames:(nullable NSArray *)frames; ++ (void)endAutoUITraceCPWithFrames:(nullable NSArray *)frames; + ++ (void)endCustomUITraceCPWithFrames:(nullable NSArray *)frames; @end diff --git a/ios/instabug_flutter.podspec b/ios/instabug_flutter.podspec index 3d9c4bdca..002c8d443 100644 --- a/ios/instabug_flutter.podspec +++ b/ios/instabug_flutter.podspec @@ -17,6 +17,6 @@ Pod::Spec.new do |s| s.pod_target_xcconfig = { 'OTHER_LDFLAGS' => '-framework "Flutter" -framework "InstabugSDK"'} s.dependency 'Flutter' - s.dependency 'Instabug', '15.1.6' + s.dependency 'Instabug', '15.1.13' end diff --git a/lib/src/modules/apm.dart b/lib/src/modules/apm.dart index 124d49e1f..3c9d9532f 100644 --- a/lib/src/modules/apm.dart +++ b/lib/src/modules/apm.dart @@ -209,7 +209,7 @@ class APM { /// The method is returning a `Future`. static Future endUITrace() async { // End screen render collector for custom ui trace if enabled. - if (await FlagsConfig.screenRendering.isEnabled()) { + if (InstabugScreenRenderManager.I.screenRenderEnabled) { return InstabugScreenRenderManager.I .endScreenRenderCollectorForCustomUiTrace(); } @@ -402,7 +402,7 @@ class APM { }); } - /// The function `endScreenRenderForAutoUiTrace` end screen rendering for + /// Ends screen rendering for /// automatic UI tracing using data provided in `InstabugScreenRenderData` object. /// /// Args: @@ -412,11 +412,13 @@ class APM { /// /// Returns: /// A `Future` is being returned. - static Future endScreenRenderForAutoUiTrace(InstabugScreenRenderData data) { + static Future endScreenRenderForAutoUiTrace( + InstabugScreenRenderData data, + ) { return _host.endScreenRenderForAutoUiTrace(data.toMap()); } - /// The function `endScreenRenderForCustomUiTrace` ends the screen render for a custom + /// Ends the screen render for a custom /// UI trace using data provided in `InstabugScreenRenderData`. /// /// Args: @@ -426,7 +428,9 @@ class APM { /// /// Returns: /// A `Future` is being returned. - static Future endScreenRenderForCustomUiTrace(InstabugScreenRenderData data) { + static Future endScreenRenderForCustomUiTrace( + InstabugScreenRenderData data, + ) { return _host.endScreenRenderForCustomUiTrace(data.toMap()); } } diff --git a/lib/src/utils/instabug_navigator_observer.dart b/lib/src/utils/instabug_navigator_observer.dart index 63dc31dad..7f83eb279 100644 --- a/lib/src/utils/instabug_navigator_observer.dart +++ b/lib/src/utils/instabug_navigator_observer.dart @@ -54,18 +54,6 @@ class InstabugNavigatorObserver extends NavigatorObserver { } } - FutureOr _startScreenRenderCollector(int? uiTraceId) async { - final isScreenRender = await FlagsConfig.screenRendering.isEnabled(); - log("isScreenRender: $isScreenRender", name: 'Andrew'); - if (uiTraceId != null && isScreenRender) { - InstabugScreenRenderManager.I - .startScreenRenderCollectorForTraceId(uiTraceId); - } - // if(isScreenRender && InstabugScreenRenderManager.I.screenRenderEnabled){ - // InstabugScreenRenderManager.I.remove(); - // } - } - @override void didPop(Route route, Route? previousRoute) { if (previousRoute != null) { @@ -77,4 +65,26 @@ class InstabugNavigatorObserver extends NavigatorObserver { void didPush(Route route, Route? previousRoute) { screenChanged(route); } + + FutureOr _startScreenRenderCollector(int? uiTraceId) async { + final isScreenRender = await FlagsConfig.screenRendering.isEnabled(); + log("isScreenRender: $isScreenRender", name: 'Andrew'); + _checkForScreenRenderInitialization(isScreenRender); + if (uiTraceId != null && isScreenRender) { + InstabugScreenRenderManager.I + .startScreenRenderCollectorForTraceId(uiTraceId); + } + } + + void _checkForScreenRenderInitialization(bool isScreenRender) { + if (isScreenRender) { + if (!InstabugScreenRenderManager.I.screenRenderEnabled) { + InstabugScreenRenderManager.I.init(WidgetsBinding.instance); + } + } else { + if (InstabugScreenRenderManager.I.screenRenderEnabled) { + InstabugScreenRenderManager.I.dispose(); + } + } + } } diff --git a/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart b/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart index f9820ae3f..090be0a7b 100644 --- a/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart +++ b/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart @@ -11,9 +11,6 @@ import 'package:instabug_flutter/src/utils/screen_rendering/instabug_widget_bind import 'package:meta/meta.dart'; //todo: remove logs -extension on int { - int get inMicro => this * 1000; -} @internal enum UiTraceType { @@ -23,7 +20,7 @@ enum UiTraceType { @internal class InstabugScreenRenderManager { - late final WidgetsBinding _widgetsBinding; + WidgetsBinding? _widgetsBinding; late int _buildTime; late int _rasterTime; late int _totalTime; @@ -34,10 +31,17 @@ class InstabugScreenRenderManager { final List _delayedFrames = []; double _deviceRefreshRate = 60; + + /// Default refresh rate for 60 FPS displays double _slowFrameThresholdMs = 16.67; + + /// 1/DeviceRefreshRate * 1000 final _frozenFrameThresholdMs = 700; + + /// Default frozen frame threshold in milliseconds (700ms) int _slowFramesTotalDuration = 0; int _frozenFramesTotalDuration = 0; + final int _microsecondsPerMillisecond = 1000; bool _isTimingsListenerAttached = false; bool screenRenderEnabled = false; @@ -61,7 +65,7 @@ class InstabugScreenRenderManager { Future init(WidgetsBinding? widgetBinding) async { try { // passing WidgetsBinding? (nullable) for flutter versions prior than 3.x - if (!_isTimingsListenerAttached && widgetBinding != null) { + if (!screenRenderEnabled && widgetBinding != null) { log("$tag: init", name: 'andrew'); _widgetsBinding = widgetBinding; _addWidgetBindingObserver(); @@ -83,19 +87,19 @@ class InstabugScreenRenderManager { _displayFrameTimingDetails(frameTiming); if (_isUiSlow) { - _slowFramesTotalDuration += - _buildTime.inMicro; //convert from milliseconds to microseconds + _slowFramesTotalDuration += _buildTime * + _microsecondsPerMillisecond; //convert from milliseconds to microseconds } else if (_isRasterSlow) { - _slowFramesTotalDuration += - _rasterTime.inMicro; //convert from milliseconds to microseconds + _slowFramesTotalDuration += _rasterTime * + _microsecondsPerMillisecond; //convert from milliseconds to microseconds } if (_isUiFrozen) { - _frozenFramesTotalDuration += _buildTime.inMicro; + _frozenFramesTotalDuration += _buildTime * _microsecondsPerMillisecond; } else if (_isRasterFrozen) { - _frozenFramesTotalDuration += _rasterTime.inMicro; + _frozenFramesTotalDuration += _rasterTime * _microsecondsPerMillisecond; } else if (_isFrozen) { - _frozenFramesTotalDuration += _totalTime.inMicro; + _frozenFramesTotalDuration += _totalTime * _microsecondsPerMillisecond; } if (_isUiDelayed) { @@ -127,10 +131,16 @@ class InstabugScreenRenderManager { try { // Return if frameTimingListener not attached if (!screenRenderEnabled || !_isTimingsListenerAttached) { - log("$tag: start returned", name: 'andrew'); + log( + "$tag: startScreenRenderCollectorForTraceId returned", + name: 'andrew', + ); return; } - log("$tag: start normally", name: 'andrew'); + log( + "$tag: startScreenRenderCollectorForTraceId $traceId (${type.name})", + name: 'andrew', + ); //Save the memory cached data to be sent to native side if (_delayedFrames.isNotEmpty) { @@ -150,8 +160,6 @@ class InstabugScreenRenderManager { _screenRenderForCustomUiTrace.clear(); } _screenRenderForCustomUiTrace.traceId = traceId; - log("$tag: start collecting for auto custom trace $traceId", - name: 'andrew'); } //Sync the captured screen render data of the Auto UI trace when starting new one @@ -163,8 +171,6 @@ class InstabugScreenRenderManager { _screenRenderForAutoUiTrace.clear(); } _screenRenderForAutoUiTrace.traceId = traceId; - log("$tag: start collecting for auto ui trace $traceId", - name: 'andrew'); } } catch (error, stackTrace) { _logExceptionErrorAndStackTrace(error, stackTrace); @@ -179,17 +185,21 @@ class InstabugScreenRenderManager { _saveCollectedData(); } + // Sync Screen Render data for custom ui trace if exists if (_screenRenderForCustomUiTrace.isActive && _screenRenderForCustomUiTrace.isNotEmpty) { reportScreenRending(_screenRenderForCustomUiTrace, UiTraceType.custom); } + + // Sync Screen Render data for auto ui trace if exists if (_screenRenderForAutoUiTrace.isActive && _screenRenderForAutoUiTrace.isNotEmpty) { reportScreenRending(_screenRenderForAutoUiTrace); } + // Dispose Screen Render Manager dispose(); - log("$tag: stop", name: 'andrew'); + log("$tag: stopScreenRenderCollector", name: 'andrew'); } catch (error, stackTrace) { _logExceptionErrorAndStackTrace(error, stackTrace); } @@ -219,6 +229,7 @@ class InstabugScreenRenderManager { } } + /// Sync captures screen render data based on their type. @visibleForTesting Future reportScreenRending( InstabugScreenRenderData screenRenderData, [ @@ -236,11 +247,13 @@ class InstabugScreenRenderManager { ); } + /// Dispose InstabugScreenRenderManager by removing timings callback and cashed data. void dispose() { _resetCachedFrameData(); _removeFrameTimings(); + _widgetsBinding = null; screenRenderEnabled = false; - log("$tag: remove", name: 'andrew'); + log("$tag: dispose", name: 'andrew'); } /// --------------------------- private methods --------------------- @@ -277,7 +290,7 @@ class InstabugScreenRenderManager { /// add new [WidgetsBindingObserver] to track app lifecycle. void _addWidgetBindingObserver() => - _widgetsBinding.addObserver(InstabugWidgetsBindingObserver.instance); + _widgetsBinding?.addObserver(InstabugWidgetsBindingObserver.instance); /// Initialize the static variables Future _initStaticValues() async { @@ -290,6 +303,7 @@ class InstabugScreenRenderManager { _slowFrameThresholdMs = _targetMsPerFrame(_deviceRefreshRate); _screenRenderForAutoUiTrace = InstabugScreenRenderData(frameData: []); _screenRenderForCustomUiTrace = InstabugScreenRenderData(frameData: []); + log("$tag: _initStaticValues ", name: 'andrew'); } /// Add a frame observer by calling [WidgetsBinding.instance.addTimingsCallback] @@ -297,16 +311,20 @@ class InstabugScreenRenderManager { if (_isTimingsListenerAttached) { return; // A timings callback is already attached } - _widgetsBinding.addTimingsCallback(_timingsCallback); + _widgetsBinding?.addTimingsCallback(_timingsCallback); _isTimingsListenerAttached = true; - log("start frame timing", name: 'andrew'); + log("$tag: _initFrameTimings ", name: 'andrew'); } /// Remove the running frame observer by calling [_widgetsBinding.removeTimingsCallback] void _removeFrameTimings() { if (!_isTimingsListenerAttached) return; // No timings callback attached. - _widgetsBinding.removeTimingsCallback(_timingsCallback); + _widgetsBinding?.removeTimingsCallback(_timingsCallback); _isTimingsListenerAttached = false; + log( + "$tag: _removeFrameTimings ", + name: 'andrew', + ); } /// Reset the memory cashed data @@ -315,7 +333,7 @@ class InstabugScreenRenderManager { _frozenFramesTotalDuration = 0; _delayedFrames.clear(); log( - "$tag: Captured data is cleared ", + "$tag: _resetCachedFrameData ", name: 'andrew', ); } diff --git a/lib/src/utils/screen_rendering/instabug_widget_binding_observer.dart b/lib/src/utils/screen_rendering/instabug_widget_binding_observer.dart index f7e16f054..61cb7b013 100644 --- a/lib/src/utils/screen_rendering/instabug_widget_binding_observer.dart +++ b/lib/src/utils/screen_rendering/instabug_widget_binding_observer.dart @@ -22,6 +22,8 @@ class InstabugWidgetsBindingObserver extends WidgetsBindingObserver { /// Logging tag for debugging purposes. static const tag = "InstabugWidgetsBindingObserver"; + static void dispose() => WidgetsBinding.instance.removeObserver(_instance); + void _handleResumedState() { log('Performing resume actions...', name: 'andrew'); final lastUiTrace = ScreenLoadingManager.I.currentUiTrace; @@ -48,6 +50,7 @@ class InstabugWidgetsBindingObserver extends WidgetsBindingObserver { void _handleDetachedState() { log('Performing detached actions...', name: 'andrew'); InstabugScreenRenderManager.I.stopScreenRenderCollector(); + dispose(); } void _handleDefaultState() { diff --git a/test/utils/screen_render/instabug_screen_render_manager_test.dart b/test/utils/screen_render/instabug_screen_render_manager_test.dart index 7759d62c3..fc8705362 100644 --- a/test/utils/screen_render/instabug_screen_render_manager_test.dart +++ b/test/utils/screen_render/instabug_screen_render_manager_test.dart @@ -64,7 +64,20 @@ void main() { test( 'should report data to native when starting new trace from the same type', () async { - ///todo: will be implemented in next sprint + final frameTestData = InstabugScreenRenderData( + traceId: 123, + frameData: [ + InstabugFrameData(10000, 200), + InstabugFrameData(20000, 1000), + ], + frozenFramesTotalDuration: 1000, + slowFramesTotalDuration: 200, + ); + + manager.startScreenRenderCollectorForTraceId(frameTestData.traceId); + manager.setFrameData(frameTestData); + manager.startScreenRenderCollectorForTraceId(2); + verify(mApmHost.endScreenRenderForAutoUiTrace(any)).called(1); }); test('should attach timing listener if it is not attached', () async { @@ -120,7 +133,7 @@ void main() { group('stopScreenRenderCollector()', () { test('should not save data if no UI trace is started', () { - final frameTestdata = InstabugScreenRenderData( + final frameTestData = InstabugScreenRenderData( traceId: 123, frameData: [ InstabugFrameData(10000, 200), @@ -130,21 +143,21 @@ void main() { slowFramesTotalDuration: 200, ); - manager.setFrameData(frameTestdata); + manager.setFrameData(frameTestData); manager.stopScreenRenderCollector(); expect(manager.screenRenderForAutoUiTrace.isActive, false); - expect(manager.screenRenderForAutoUiTrace == frameTestdata, false); + expect(manager.screenRenderForAutoUiTrace == frameTestData, false); expect(manager.screenRenderForCustomUiTrace.isActive, false); - expect(manager.screenRenderForCustomUiTrace == frameTestdata, false); + expect(manager.screenRenderForCustomUiTrace == frameTestData, false); }); test( 'should save and data to screenRenderForAutoUiTrace when for autoUITrace', () { - final frameTestdata = InstabugScreenRenderData( + final frameTestData = InstabugScreenRenderData( traceId: 123, frameData: [ InstabugFrameData(10000, 200), @@ -155,16 +168,16 @@ void main() { ); manager.startScreenRenderCollectorForTraceId( - frameTestdata.traceId, + frameTestData.traceId, ); - manager.setFrameData(frameTestdata); + manager.setFrameData(frameTestData); manager.stopScreenRenderCollector(); expect(manager.screenRenderForAutoUiTrace.isActive, true); - expect(manager.screenRenderForAutoUiTrace == frameTestdata, true); + expect(manager.screenRenderForAutoUiTrace == frameTestData, true); expect(manager.screenRenderForCustomUiTrace.isActive, false); }); @@ -172,7 +185,7 @@ void main() { test( 'should save and data to screenRenderForCustomUiTrace when for customUITrace', () { - final frameTestdata = InstabugScreenRenderData( + final frameTestData = InstabugScreenRenderData( traceId: 123, frameData: [ InstabugFrameData(10000, 200), @@ -183,23 +196,23 @@ void main() { ); manager.startScreenRenderCollectorForTraceId( - frameTestdata.traceId, + frameTestData.traceId, UiTraceType.custom, ); - manager.setFrameData(frameTestdata); + manager.setFrameData(frameTestData); manager.stopScreenRenderCollector(); expect(manager.screenRenderForCustomUiTrace.isActive, true); - expect(manager.screenRenderForCustomUiTrace == frameTestdata, true); + expect(manager.screenRenderForCustomUiTrace == frameTestData, true); expect(manager.screenRenderForAutoUiTrace.isActive, false); }); test('should remove timing callback listener', () { - final frameTestdata = InstabugScreenRenderData( + final frameTestData = InstabugScreenRenderData( traceId: 123, frameData: [ InstabugFrameData(10000, 200), @@ -209,16 +222,28 @@ void main() { slowFramesTotalDuration: 200, ); - manager.setFrameData(frameTestdata); + manager.setFrameData(frameTestData); manager.stopScreenRenderCollector(); verify(mWidgetBinding.removeTimingsCallback(any)).called(1); }); - test( - 'should report data to native when starting new trace from the same type', - () async { - ///todo: will be implemented in next sprint + test('should report data to native side with the correct type', () async { + final frameTestData = InstabugScreenRenderData( + traceId: 123, + frameData: [ + InstabugFrameData(10000, 200), + InstabugFrameData(20000, 1000), + ], + frozenFramesTotalDuration: 1000, + slowFramesTotalDuration: 200, + ); + + manager.startScreenRenderCollectorForTraceId(0, UiTraceType.custom); + manager.setFrameData(frameTestData); + manager.stopScreenRenderCollector(); + verify(mApmHost.endScreenRenderForCustomUiTrace(any)).called(1); + verifyNever(mApmHost.endScreenRenderForAutoUiTrace(any)); }); }); @@ -276,10 +301,21 @@ void main() { verifyNever(mWidgetBinding.removeTimingsCallback(any)); }); - test( - 'should report data to native when starting new trace from the same type', - () async { - ///todo: will be implemented in next sprint + test('should report data to native side', () async { + final frameTestData = InstabugScreenRenderData( + traceId: 123, + frameData: [ + InstabugFrameData(10000, 200), + InstabugFrameData(20000, 1000), + ], + frozenFramesTotalDuration: 1000, + slowFramesTotalDuration: 200, + ); + + manager.startScreenRenderCollectorForTraceId(0, UiTraceType.custom); + manager.setFrameData(frameTestData); + manager.endScreenRenderCollectorForCustomUiTrace(); + verify(mApmHost.endScreenRenderForCustomUiTrace(any)).called(1); }); }); From 3ea64843b56120ece479b468ed6f938fc51649e1 Mon Sep 17 00:00:00 2001 From: AyaMahmoud148 Date: Thu, 10 Jul 2025 11:40:06 +0300 Subject: [PATCH 21/84] feat: support advanced UI customization --- .../instabug/flutter/modules/InstabugApi.java | 162 ++++++++++++++++++ .../com/instabug/flutter/InstabugApiTest.java | 73 ++++++++ .../InstabugExampleMethodCallHandler.kt | 28 +++ example/ios/InstabugTests/InstabugApiTests.m | 28 +++ ...stabug_flutter_example_method_channel.dart | 17 ++ example/pubspec.yaml | 5 + ios/Classes/Modules/InstabugApi.m | 127 +++++++++++++- lib/instabug_flutter.dart | 1 + lib/src/models/theme_config.dart | 121 +++++++++++++ lib/src/modules/instabug.dart | 39 +++++ pigeons/instabug.api.dart | 2 + 11 files changed, 602 insertions(+), 1 deletion(-) create mode 100644 lib/src/models/theme_config.dart diff --git a/android/src/main/java/com/instabug/flutter/modules/InstabugApi.java b/android/src/main/java/com/instabug/flutter/modules/InstabugApi.java index edfde055a..27331152a 100644 --- a/android/src/main/java/com/instabug/flutter/modules/InstabugApi.java +++ b/android/src/main/java/com/instabug/flutter/modules/InstabugApi.java @@ -5,6 +5,7 @@ import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.net.Uri; +import android.graphics.Typeface; import android.util.Log; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -509,4 +510,165 @@ public void setNetworkLogBodyEnabled(@NonNull Boolean isEnabled) { e.printStackTrace(); } } + + @Override + public void setTheme(@NonNull Map themeConfig) { + try { + Log.d(TAG, "setTheme called with config: " + themeConfig.toString()); + + com.instabug.library.model.IBGTheme.Builder builder = new com.instabug.library.model.IBGTheme.Builder(); + + if (themeConfig.containsKey("primaryColor")) { + builder.setPrimaryColor(getColor(themeConfig, "primaryColor")); + } + if (themeConfig.containsKey("secondaryTextColor")) { + builder.setSecondaryTextColor(getColor(themeConfig, "secondaryTextColor")); + } + if (themeConfig.containsKey("primaryTextColor")) { + builder.setPrimaryTextColor(getColor(themeConfig, "primaryTextColor")); + } + if (themeConfig.containsKey("titleTextColor")) { + builder.setTitleTextColor(getColor(themeConfig, "titleTextColor")); + } + if (themeConfig.containsKey("backgroundColor")) { + builder.setBackgroundColor(getColor(themeConfig, "backgroundColor")); + } + + if (themeConfig.containsKey("primaryTextStyle")) { + builder.setPrimaryTextStyle(getTextStyle(themeConfig, "primaryTextStyle")); + } + if (themeConfig.containsKey("secondaryTextStyle")) { + builder.setSecondaryTextStyle(getTextStyle(themeConfig, "secondaryTextStyle")); + } + if (themeConfig.containsKey("ctaTextStyle")) { + builder.setCtaTextStyle(getTextStyle(themeConfig, "ctaTextStyle")); + } + + setFontIfPresent(themeConfig, builder, "primaryFontPath", "primaryFontAsset", "primary"); + setFontIfPresent(themeConfig, builder, "secondaryFontPath", "secondaryFontAsset", "secondary"); + setFontIfPresent(themeConfig, builder, "ctaFontPath", "ctaFontAsset", "CTA"); + + com.instabug.library.model.IBGTheme theme = builder.build(); + Instabug.setTheme(theme); + Log.d(TAG, "Theme applied successfully"); + + } catch (Exception e) { + Log.e(TAG, "Error in setTheme: " + e.getMessage()); + e.printStackTrace(); + } + } + + public void setFullscreen(@NonNull Boolean isEnabled) { + try { + Instabug.setFullscreen(isEnabled); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * Retrieves a color value from the Map. + * + * @param map The Map object. + * @param key The key to look for. + * @return The parsed color as an integer, or black if missing or invalid. + */ + private int getColor(Map map, String key) { + try { + if (map != null && map.containsKey(key) && map.get(key) != null) { + String colorString = (String) map.get(key); + return android.graphics.Color.parseColor(colorString); + } + } catch (Exception e) { + e.printStackTrace(); + } + return android.graphics.Color.BLACK; + } + + /** + * Retrieves a text style from the Map. + * + * @param map The Map object. + * @param key The key to look for. + * @return The corresponding Typeface style, or Typeface.NORMAL if missing or invalid. + */ + private int getTextStyle(Map map, String key) { + try { + if (map != null && map.containsKey(key) && map.get(key) != null) { + String style = (String) map.get(key); + switch (style.toLowerCase()) { + case "bold": + return Typeface.BOLD; + case "italic": + return Typeface.ITALIC; + case "bold_italic": + return Typeface.BOLD_ITALIC; + case "normal": + default: + return Typeface.NORMAL; + } + } + } catch (Exception e) { + e.printStackTrace(); + } + return Typeface.NORMAL; + } + + /** + * Sets a font on the theme builder if the font configuration is present in the theme config. + * + * @param themeConfig The theme configuration map + * @param builder The theme builder + * @param fileKey The key for font file path + * @param assetKey The key for font asset path + * @param fontType The type of font (for logging purposes) + */ + private void setFontIfPresent(Map themeConfig, com.instabug.library.model.IBGTheme.Builder builder, + String fileKey, String assetKey, String fontType) { + if (themeConfig.containsKey(fileKey) || themeConfig.containsKey(assetKey)) { + Typeface typeface = getTypeface(themeConfig, fileKey, assetKey); + if (typeface != null) { + switch (fontType) { + case "primary": + builder.setPrimaryTextFont(typeface); + break; + case "secondary": + builder.setSecondaryTextFont(typeface); + break; + case "CTA": + builder.setCtaTextFont(typeface); + break; + } + } + } + } + + private Typeface getTypeface(Map map, String fileKey, String assetKey) { + try { + String fontName = null; + + if (assetKey != null && map.containsKey(assetKey) && map.get(assetKey) != null) { + fontName = (String) map.get(assetKey); + } else if (fileKey != null && map.containsKey(fileKey) && map.get(fileKey) != null) { + fontName = (String) map.get(fileKey); + } + + if (fontName == null) { + return Typeface.DEFAULT; + } + + + try { + String assetPath = "fonts/" + fontName; + return Typeface.createFromAsset(context.getAssets(), assetPath); + } catch (Exception e) { + return Typeface.create(fontName, Typeface.NORMAL); + } + + } catch (Exception e) { + return Typeface.DEFAULT; + } + } + + } diff --git a/android/src/test/java/com/instabug/flutter/InstabugApiTest.java b/android/src/test/java/com/instabug/flutter/InstabugApiTest.java index 97b9cdf7b..478570c9a 100644 --- a/android/src/test/java/com/instabug/flutter/InstabugApiTest.java +++ b/android/src/test/java/com/instabug/flutter/InstabugApiTest.java @@ -80,6 +80,8 @@ import org.mockito.verification.VerificationMode; import org.mockito.verification.VerificationMode; +import android.graphics.Typeface; + public class InstabugApiTest { private final Callable screenshotProvider = () -> mock(Bitmap.class); private final Application mContext = mock(Application.class); @@ -658,4 +660,75 @@ public void testSetNetworkLogBodyDisabled() { mInstabug.verify(() -> Instabug.setNetworkLogBodyEnabled(false)); } + + @Test + public void testSetThemeWithAllProperties() { + Map themeConfig = new HashMap<>(); + themeConfig.put("primaryColor", "#FF6B6B"); + themeConfig.put("backgroundColor", "#FFFFFF"); + themeConfig.put("titleTextColor", "#000000"); + themeConfig.put("primaryTextColor", "#333333"); + themeConfig.put("secondaryTextColor", "#666666"); + themeConfig.put("primaryTextStyle", "bold"); + themeConfig.put("secondaryTextStyle", "italic"); + themeConfig.put("ctaTextStyle", "bold_italic"); + themeConfig.put("primaryFontAsset", "assets/fonts/CustomFont-Regular.ttf"); + themeConfig.put("secondaryFontAsset", "assets/fonts/CustomFont-Bold.ttf"); + themeConfig.put("ctaFontAsset", "assets/fonts/CustomFont-Italic.ttf"); + + MockedConstruction mThemeBuilder = + mockConstruction(com.instabug.library.model.IBGTheme.Builder.class, (mock, context) -> { + when(mock.setPrimaryColor(anyInt())).thenReturn(mock); + when(mock.setBackgroundColor(anyInt())).thenReturn(mock); + when(mock.setTitleTextColor(anyInt())).thenReturn(mock); + when(mock.setPrimaryTextColor(anyInt())).thenReturn(mock); + when(mock.setSecondaryTextColor(anyInt())).thenReturn(mock); + when(mock.setPrimaryTextStyle(anyInt())).thenReturn(mock); + when(mock.setSecondaryTextStyle(anyInt())).thenReturn(mock); + when(mock.setCtaTextStyle(anyInt())).thenReturn(mock); + when(mock.setPrimaryTextFont(any(Typeface.class))).thenReturn(mock); + when(mock.setSecondaryTextFont(any(Typeface.class))).thenReturn(mock); + when(mock.setCtaTextFont(any(Typeface.class))).thenReturn(mock); + when(mock.build()).thenReturn(mock(com.instabug.library.model.IBGTheme.class)); + }); + + api.setTheme(themeConfig); + + com.instabug.library.model.IBGTheme.Builder builder = mThemeBuilder.constructed().get(0); + + // Verify color setters were called + verify(builder).setPrimaryColor(android.graphics.Color.parseColor("#FF6B6B")); + verify(builder).setBackgroundColor(android.graphics.Color.parseColor("#FFFFFF")); + verify(builder).setTitleTextColor(android.graphics.Color.parseColor("#000000")); + verify(builder).setPrimaryTextColor(android.graphics.Color.parseColor("#333333")); + verify(builder).setSecondaryTextColor(android.graphics.Color.parseColor("#666666")); + + // Verify text style setters were called + verify(builder).setPrimaryTextStyle(Typeface.BOLD); + verify(builder).setSecondaryTextStyle(Typeface.ITALIC); + verify(builder).setCtaTextStyle(Typeface.BOLD_ITALIC); + + // Verify theme was set on Instabug + mInstabug.verify(() -> Instabug.setTheme(any(com.instabug.library.model.IBGTheme.class))); + + } + + + @Test + public void testSetFullscreenEnabled() { + boolean isEnabled = true; + + api.setFullscreen(isEnabled); + + mInstabug.verify(() -> Instabug.setFullscreen(true)); + } + + @Test + public void testSetFullscreenDisabled() { + boolean isEnabled = false; + + api.setFullscreen(isEnabled); + + mInstabug.verify(() -> Instabug.setFullscreen(false)); + } } diff --git a/example/android/app/src/main/kotlin/com/example/InstabugSample/InstabugExampleMethodCallHandler.kt b/example/android/app/src/main/kotlin/com/example/InstabugSample/InstabugExampleMethodCallHandler.kt index 17a7d35c6..f6fb0fc03 100644 --- a/example/android/app/src/main/kotlin/com/example/InstabugSample/InstabugExampleMethodCallHandler.kt +++ b/example/android/app/src/main/kotlin/com/example/InstabugSample/InstabugExampleMethodCallHandler.kt @@ -37,6 +37,12 @@ class InstabugExampleMethodCallHandler : MethodChannel.MethodCallHandler { sendOOM() result.success(null) } + SET_FULLSCREEN -> { + val isEnabled = call.arguments as? Map<*, *> + val enabled = isEnabled?.get("isEnabled") as? Boolean ?: false + setFullscreen(enabled) + result.success(null) + } else -> { Log.e(TAG, "onMethodCall for ${call.method} is not implemented") result.notImplemented() @@ -55,6 +61,7 @@ class InstabugExampleMethodCallHandler : MethodChannel.MethodCallHandler { const val SEND_NATIVE_FATAL_HANG = "sendNativeFatalHang" const val SEND_ANR = "sendAnr" const val SEND_OOM = "sendOom" + const val SET_FULLSCREEN = "setFullscreen" } private fun sendNativeNonFatal(exceptionObject: String?) { @@ -125,4 +132,25 @@ class InstabugExampleMethodCallHandler : MethodChannel.MethodCallHandler { return randomString.toString() } + private fun setFullscreen(enabled: Boolean) { + try { + + try { + val instabugClass = Class.forName("com.instabug.library.Instabug") + val setFullscreenMethod = instabugClass.getMethod("setFullscreen", Boolean::class.java) + setFullscreenMethod.invoke(null, enabled) + } catch (e: ClassNotFoundException) { + throw e + } catch (e: NoSuchMethodException) { + throw e + } catch (e: Exception) { + throw e + } + + } catch (e: Exception) { + e.printStackTrace() + + } + } + } diff --git a/example/ios/InstabugTests/InstabugApiTests.m b/example/ios/InstabugTests/InstabugApiTests.m index 9f2c04373..d778f830e 100644 --- a/example/ios/InstabugTests/InstabugApiTests.m +++ b/example/ios/InstabugTests/InstabugApiTests.m @@ -611,4 +611,32 @@ - (void)testisW3CFeatureFlagsEnabled { } +- (void)testSetThemeWithAllProperties { + NSDictionary *themeConfig = @{ + @"primaryColor": @"#FF6B6B", + @"backgroundColor": @"#FFFFFF", + @"titleTextColor": @"#000000", + @"primaryTextColor": @"#333333", + @"secondaryTextColor": @"#666666", + @"callToActionTextColor": @"#FF6B6B", + @"primaryFontPath": @"assets/fonts/CustomFont-Regular.ttf", + @"secondaryFontPath": @"assets/fonts/CustomFont-Bold.ttf", + @"ctaFontPath": @"assets/fonts/CustomFont-Italic.ttf" + }; + + id mockTheme = OCMClassMock([IBGTheme class]); + OCMStub([mockTheme primaryColor]).andReturn([UIColor redColor]); + OCMStub([mockTheme backgroundColor]).andReturn([UIColor whiteColor]); + OCMStub([mockTheme titleTextColor]).andReturn([UIColor blackColor]); + OCMStub([mockTheme primaryTextColor]).andReturn([UIColor darkGrayColor]); + OCMStub([mockTheme secondaryTextColor]).andReturn([UIColor grayColor]); + OCMStub([mockTheme callToActionTextColor]).andReturn([UIColor redColor]); + + FlutterError *error; + + [self.api setThemeThemeConfig:themeConfig error:&error]; + + OCMVerify([self.mInstabug setTheme:OCMArg.any]); +} + @end diff --git a/example/lib/src/native/instabug_flutter_example_method_channel.dart b/example/lib/src/native/instabug_flutter_example_method_channel.dart index 9507cc403..118097dc3 100644 --- a/example/lib/src/native/instabug_flutter_example_method_channel.dart +++ b/example/lib/src/native/instabug_flutter_example_method_channel.dart @@ -54,6 +54,22 @@ class InstabugFlutterExampleMethodChannel { log("Failed to send out of memory: '${e.message}'.", name: _tag); } } + + static Future setFullscreen(bool isEnabled) async { + if (!Platform.isAndroid) { + return; + } + + try { + await _channel.invokeMethod(Constants.setFullscreenMethodName, { + 'isEnabled': isEnabled, + }); + } on PlatformException catch (e) { + log("Failed to set fullscreen: '${e.message}'.", name: _tag); + } catch (e) { + log("Unexpected error setting fullscreen: '$e'.", name: _tag); + } + } } class Constants { @@ -65,4 +81,5 @@ class Constants { static const sendNativeFatalHangMethodName = "sendNativeFatalHang"; static const sendAnrMethodName = "sendAnr"; static const sendOomMethodName = "sendOom"; + static const setFullscreenMethodName = "setFullscreen"; } diff --git a/example/pubspec.yaml b/example/pubspec.yaml index fe72aaa2d..4e2cd44b0 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -51,6 +51,8 @@ flutter: # To add assets to your application, add an assets section, like this: # assets: + # - assets/fonts/ + # assets: # - images/a_dot_burr.jpeg # - images/a_dot_ham.jpeg @@ -66,6 +68,9 @@ flutter: # list giving the asset and other descriptors for the font. For # example: # fonts: + # - family: ManufacturingConsent + # fonts: + # - asset: assets/fonts/ManufacturingConsent-Regular.ttf # - family: Schyler # fonts: # - asset: fonts/Schyler-Regular.ttf diff --git a/ios/Classes/Modules/InstabugApi.m b/ios/Classes/Modules/InstabugApi.m index 3bdc465f0..fce1dbc2b 100644 --- a/ios/Classes/Modules/InstabugApi.m +++ b/ios/Classes/Modules/InstabugApi.m @@ -14,7 +14,9 @@ extern void InitInstabugApi(id messenger) { InstabugHostApiSetup(messenger, api); } -@implementation InstabugApi +@implementation InstabugApi { + NSMutableSet *_registeredFonts; +} - (void)setEnabledIsEnabled:(NSNumber *)isEnabled error:(FlutterError *_Nullable *_Nonnull)error { Instabug.enabled = [isEnabled boolValue]; @@ -396,4 +398,127 @@ - (void)setNetworkLogBodyEnabledIsEnabled:(NSNumber *)isEnabled IBGNetworkLogger.logBodyEnabled = [isEnabled boolValue]; } + + +- (void)setThemeThemeConfig:(NSDictionary *)themeConfig error:(FlutterError *_Nullable *_Nonnull)error { + IBGTheme *theme = [[IBGTheme alloc] init]; + + NSDictionary *colorMapping = @{ + @"primaryColor": ^(UIColor *color) { theme.primaryColor = color; }, + @"backgroundColor": ^(UIColor *color) { theme.backgroundColor = color; }, + @"titleTextColor": ^(UIColor *color) { theme.titleTextColor = color; }, + @"subtitleTextColor": ^(UIColor *color) { theme.subtitleTextColor = color; }, + @"primaryTextColor": ^(UIColor *color) { theme.primaryTextColor = color; }, + @"secondaryTextColor": ^(UIColor *color) { theme.secondaryTextColor = color; }, + @"callToActionTextColor": ^(UIColor *color) { theme.callToActionTextColor = color; }, + @"headerBackgroundColor": ^(UIColor *color) { theme.headerBackgroundColor = color; }, + @"footerBackgroundColor": ^(UIColor *color) { theme.footerBackgroundColor = color; }, + @"rowBackgroundColor": ^(UIColor *color) { theme.rowBackgroundColor = color; }, + @"selectedRowBackgroundColor": ^(UIColor *color) { theme.selectedRowBackgroundColor = color; }, + @"rowSeparatorColor": ^(UIColor *color) { theme.rowSeparatorColor = color; } + }; + + for (NSString *key in colorMapping) { + if (themeConfig[key]) { + NSString *colorString = themeConfig[key]; + UIColor *color = [self colorFromHexString:colorString]; + if (color) { + void (^setter)(UIColor *) = colorMapping[key]; + setter(color); + } + } + } + + [self setFontIfPresent:themeConfig[@"primaryFontPath"] ?: themeConfig[@"primaryFontAsset"] forTheme:theme type:@"primary"]; + [self setFontIfPresent:themeConfig[@"secondaryFontPath"] ?: themeConfig[@"secondaryFontAsset"] forTheme:theme type:@"secondary"]; + [self setFontIfPresent:themeConfig[@"ctaFontPath"] ?: themeConfig[@"ctaFontAsset"] forTheme:theme type:@"cta"]; + + Instabug.theme = theme; +} + +- (void)setFontIfPresent:(NSString *)fontPath forTheme:(IBGTheme *)theme type:(NSString *)type { + if (!fontPath || fontPath.length == 0 || !theme || !type) return; + + if (!_registeredFonts) { + _registeredFonts = [NSMutableSet set]; + } + + UIFont *font = [UIFont fontWithName:fontPath size:UIFont.systemFontSize]; + + if (!font && ![_registeredFonts containsObject:fontPath]) { + NSString *fontFileName = [fontPath stringByDeletingPathExtension]; + NSArray *fontExtensions = @[@"ttf", @"otf", @"woff", @"woff2"]; + NSString *fontFilePath = nil; + + for (NSString *extension in fontExtensions) { + fontFilePath = [[NSBundle mainBundle] pathForResource:fontFileName ofType:extension]; + if (fontFilePath) break; + } + + if (fontFilePath) { + NSData *fontData = [NSData dataWithContentsOfFile:fontFilePath]; + if (fontData) { + CGDataProviderRef provider = CGDataProviderCreateWithCFData((__bridge CFDataRef)fontData); + if (provider) { + CGFontRef cgFont = CGFontCreateWithDataProvider(provider); + if (cgFont) { + CFErrorRef error = NULL; + if (CTFontManagerRegisterGraphicsFont(cgFont, &error)) { + NSString *postScriptName = (__bridge_transfer NSString *)CGFontCopyPostScriptName(cgFont); + if (postScriptName) { + font = [UIFont fontWithName:postScriptName size:UIFont.systemFontSize]; + [_registeredFonts addObject:fontPath]; + } + } else if (error) { + CFStringRef desc = CFErrorCopyDescription(error); + CFRelease(desc); + CFRelease(error); + } + CGFontRelease(cgFont); + } + CGDataProviderRelease(provider); + } + } + } + } else if (!font && [_registeredFonts containsObject:fontPath]) { + font = [UIFont fontWithName:fontPath size:UIFont.systemFontSize]; + } + + if (font) { + if ([type isEqualToString:@"primary"]) { + theme.primaryTextFont = font; + } else if ([type isEqualToString:@"secondary"]) { + theme.secondaryTextFont = font; + } else if ([type isEqualToString:@"cta"]) { + theme.callToActionTextFont = font; + } + } +} + +- (UIColor *)colorFromHexString:(NSString *)hexString { + NSString *cleanString = [hexString stringByReplacingOccurrencesOfString:@"#" withString:@""]; + + if (cleanString.length == 6) { + unsigned int rgbValue = 0; + NSScanner *scanner = [NSScanner scannerWithString:cleanString]; + [scanner scanHexInt:&rgbValue]; + + return [UIColor colorWithRed:((rgbValue & 0xFF0000) >> 16) / 255.0 + green:((rgbValue & 0xFF00) >> 8) / 255.0 + blue:(rgbValue & 0xFF) / 255.0 + alpha:1.0]; + } else if (cleanString.length == 8) { + unsigned int rgbaValue = 0; + NSScanner *scanner = [NSScanner scannerWithString:cleanString]; + [scanner scanHexInt:&rgbaValue]; + + return [UIColor colorWithRed:((rgbaValue & 0xFF000000) >> 24) / 255.0 + green:((rgbaValue & 0xFF0000) >> 16) / 255.0 + blue:((rgbaValue & 0xFF00) >> 8) / 255.0 + alpha:(rgbaValue & 0xFF) / 255.0]; + } + + return [UIColor blackColor]; +} + @end diff --git a/lib/instabug_flutter.dart b/lib/instabug_flutter.dart index e38545897..66f74c2fb 100644 --- a/lib/instabug_flutter.dart +++ b/lib/instabug_flutter.dart @@ -3,6 +3,7 @@ export 'src/models/crash_data.dart'; export 'src/models/exception_data.dart'; export 'src/models/feature_flag.dart'; export 'src/models/network_data.dart'; +export 'src/models/theme_config.dart'; export 'src/models/trace.dart'; export 'src/models/w3c_header.dart'; diff --git a/lib/src/models/theme_config.dart b/lib/src/models/theme_config.dart new file mode 100644 index 000000000..ea3a6754e --- /dev/null +++ b/lib/src/models/theme_config.dart @@ -0,0 +1,121 @@ +class ThemeConfig { + /// Primary color for UI elements indicating interactivity or call to action. + final String? primaryColor; + + /// Background color for the main UI. + final String? backgroundColor; + + /// Color for title text elements. + final String? titleTextColor; + + /// Color for subtitle text elements. + final String? subtitleTextColor; + + /// Color for primary text elements. + final String? primaryTextColor; + + /// Color for secondary text elements. + final String? secondaryTextColor; + + /// Color for call-to-action text elements. + final String? callToActionTextColor; + + /// Background color for header elements. + final String? headerBackgroundColor; + + /// Background color for footer elements. + final String? footerBackgroundColor; + + /// Background color for row elements. + final String? rowBackgroundColor; + + /// Background color for selected row elements. + final String? selectedRowBackgroundColor; + + /// Color for row separator lines. + final String? rowSeparatorColor; + + /// Text style for primary text (Android only). + final String? primaryTextStyle; + + /// Text style for secondary text (Android only). + final String? secondaryTextStyle; + + /// Text style for title text (Android only). + final String? titleTextStyle; + + /// Text style for call-to-action text (Android only). + final String? ctaTextStyle; + + /// Path to primary font file. + final String? primaryFontPath; + + /// Asset path to primary font file. + final String? primaryFontAsset; + + /// Path to secondary font file. + final String? secondaryFontPath; + + /// Asset path to secondary font file. + final String? secondaryFontAsset; + + /// Path to call-to-action font file. + final String? ctaFontPath; + + /// Asset path to call-to-action font file. + final String? ctaFontAsset; + + const ThemeConfig({ + this.primaryColor, + this.backgroundColor, + this.titleTextColor, + this.subtitleTextColor, + this.primaryTextColor, + this.secondaryTextColor, + this.callToActionTextColor, + this.headerBackgroundColor, + this.footerBackgroundColor, + this.rowBackgroundColor, + this.selectedRowBackgroundColor, + this.rowSeparatorColor, + this.primaryTextStyle, + this.secondaryTextStyle, + this.titleTextStyle, + this.ctaTextStyle, + this.primaryFontPath, + this.primaryFontAsset, + this.secondaryFontPath, + this.secondaryFontAsset, + this.ctaFontPath, + this.ctaFontAsset, + }); + + Map toMap() { + return Map.fromEntries( + [ + MapEntry('primaryColor', primaryColor), + MapEntry('backgroundColor', backgroundColor), + MapEntry('titleTextColor', titleTextColor), + MapEntry('subtitleTextColor', subtitleTextColor), + MapEntry('primaryTextColor', primaryTextColor), + MapEntry('secondaryTextColor', secondaryTextColor), + MapEntry('callToActionTextColor', callToActionTextColor), + MapEntry('headerBackgroundColor', headerBackgroundColor), + MapEntry('footerBackgroundColor', footerBackgroundColor), + MapEntry('rowBackgroundColor', rowBackgroundColor), + MapEntry('selectedRowBackgroundColor', selectedRowBackgroundColor), + MapEntry('rowSeparatorColor', rowSeparatorColor), + MapEntry('primaryTextStyle', primaryTextStyle), + MapEntry('secondaryTextStyle', secondaryTextStyle), + MapEntry('titleTextStyle', titleTextStyle), + MapEntry('ctaTextStyle', ctaTextStyle), + MapEntry('primaryFontPath', primaryFontPath), + MapEntry('primaryFontAsset', primaryFontAsset), + MapEntry('secondaryFontPath', secondaryFontPath), + MapEntry('secondaryFontAsset', secondaryFontAsset), + MapEntry('ctaFontPath', ctaFontPath), + MapEntry('ctaFontAsset', ctaFontAsset), + ].where((entry) => entry.value != null), + ); + } +} diff --git a/lib/src/modules/instabug.dart b/lib/src/modules/instabug.dart index 6bba8ed1f..81f2baa4d 100644 --- a/lib/src/modules/instabug.dart +++ b/lib/src/modules/instabug.dart @@ -1,6 +1,7 @@ // ignore_for_file: avoid_classes_with_only_static_members import 'dart:async'; +import 'dart:io'; // to maintain supported versions prior to Flutter 3.3 // ignore: unnecessary_import @@ -482,4 +483,42 @@ class Instabug { static Future willRedirectToStore() async { return _host.willRedirectToStore(); } + + /// Sets a custom theme for Instabug UI elements. + /// + /// @param theme - Configuration object containing theme properties + /// + /// Example: + /// ```dart + /// + /// Instabug.setTheme(ThemeConfig( + /// primaryColor: '#FF6B6B', + /// secondaryTextColor: '#666666', + /// primaryTextColor: '#333333', + /// titleTextColor: '#000000', + /// backgroundColor: '#FFFFFF', + /// primaryTextStyle: 'bold', + /// secondaryTextStyle: 'normal', + /// titleTextStyle: 'bold', + /// ctaTextStyle: 'bold', + /// primaryFontPath: '/data/user/0/com.yourapp/files/fonts/YourFont.ttf', + /// secondaryFontPath: '/data/user/0/com.yourapp/files/fonts/YourFont.ttf', + /// ctaFontPath: '/data/user/0/com.yourapp/files/fonts/YourFont.ttf', + /// primaryFontAsset: 'fonts/YourFont.ttf', + /// secondaryFontAsset: 'fonts/YourFont.ttf' + /// )); + /// ``` + static Future setTheme(ThemeConfig themeConfig) async { + return _host.setTheme(themeConfig.toMap()); + } + + /// Enables or disables displaying in full-screen mode, hiding the status and navigation bars. + /// This method is only available on Android platform. + /// @param isEnabled A boolean to enable/disable setFullscreen. + static Future setFullscreen(bool isEnabled) async { + if (Platform.isAndroid) { + const MethodChannel channel = MethodChannel('instabug_flutter'); + await channel.invokeMethod('setFullscreen', {'isEnabled': isEnabled}); + } + } } diff --git a/pigeons/instabug.api.dart b/pigeons/instabug.api.dart index 275306987..898199824 100644 --- a/pigeons/instabug.api.dart +++ b/pigeons/instabug.api.dart @@ -76,4 +76,6 @@ abstract class InstabugHostApi { void willRedirectToStore(); void setNetworkLogBodyEnabled(bool isEnabled); + + void setTheme(Map themeConfig); } From 4081f5bff6b2662bf401dc521156f66c1d2037e6 Mon Sep 17 00:00:00 2001 From: AyaMahmoud148 Date: Thu, 10 Jul 2025 11:42:17 +0300 Subject: [PATCH 22/84] chore: add change log --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9cb867f5c..c7824fef1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [Unreleased](https://github.com/Instabug/Instabug-Flutter/compare/v15.0.2...dev) + +### Added + +- Add support for Advanced UI customization with comprehensive theming capabilities ([#599](https://github.com/Instabug/Instabug-Flutter/pull/599)) + + ## [15.0.2](https://github.com/Instabug/Instabug-Flutter/compare/v14.3.0...15.0.2) (Jul 7, 2025) ### Added From 8798555d6f23c63e2bdd925351dea81038b12465 Mon Sep 17 00:00:00 2001 From: AyaMahmoud148 Date: Thu, 10 Jul 2025 11:48:47 +0300 Subject: [PATCH 23/84] fix: delete setFullScreen --- .../instabug/flutter/modules/InstabugApi.java | 8 +------- .../com/instabug/flutter/InstabugApiTest.java | 17 ----------------- lib/src/modules/instabug.dart | 10 ---------- 3 files changed, 1 insertion(+), 34 deletions(-) diff --git a/android/src/main/java/com/instabug/flutter/modules/InstabugApi.java b/android/src/main/java/com/instabug/flutter/modules/InstabugApi.java index 27331152a..12286decb 100644 --- a/android/src/main/java/com/instabug/flutter/modules/InstabugApi.java +++ b/android/src/main/java/com/instabug/flutter/modules/InstabugApi.java @@ -558,13 +558,7 @@ public void setTheme(@NonNull Map themeConfig) { } } - public void setFullscreen(@NonNull Boolean isEnabled) { - try { - Instabug.setFullscreen(isEnabled); - } catch (Exception e) { - e.printStackTrace(); - } - } + /** * Retrieves a color value from the Map. diff --git a/android/src/test/java/com/instabug/flutter/InstabugApiTest.java b/android/src/test/java/com/instabug/flutter/InstabugApiTest.java index 478570c9a..65b36d959 100644 --- a/android/src/test/java/com/instabug/flutter/InstabugApiTest.java +++ b/android/src/test/java/com/instabug/flutter/InstabugApiTest.java @@ -713,22 +713,5 @@ public void testSetThemeWithAllProperties() { } - - @Test - public void testSetFullscreenEnabled() { - boolean isEnabled = true; - - api.setFullscreen(isEnabled); - - mInstabug.verify(() -> Instabug.setFullscreen(true)); - } - @Test - public void testSetFullscreenDisabled() { - boolean isEnabled = false; - - api.setFullscreen(isEnabled); - - mInstabug.verify(() -> Instabug.setFullscreen(false)); - } } diff --git a/lib/src/modules/instabug.dart b/lib/src/modules/instabug.dart index 81f2baa4d..a074a7f6d 100644 --- a/lib/src/modules/instabug.dart +++ b/lib/src/modules/instabug.dart @@ -511,14 +511,4 @@ class Instabug { static Future setTheme(ThemeConfig themeConfig) async { return _host.setTheme(themeConfig.toMap()); } - - /// Enables or disables displaying in full-screen mode, hiding the status and navigation bars. - /// This method is only available on Android platform. - /// @param isEnabled A boolean to enable/disable setFullscreen. - static Future setFullscreen(bool isEnabled) async { - if (Platform.isAndroid) { - const MethodChannel channel = MethodChannel('instabug_flutter'); - await channel.invokeMethod('setFullscreen', {'isEnabled': isEnabled}); - } - } } From d46e04dc64a9b7c53e07e9ae12e7862ea15d24fe Mon Sep 17 00:00:00 2001 From: AyaMahmoud148 Date: Thu, 10 Jul 2025 11:55:44 +0300 Subject: [PATCH 24/84] fix: linting --- lib/src/modules/instabug.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/src/modules/instabug.dart b/lib/src/modules/instabug.dart index a074a7f6d..41b66bc97 100644 --- a/lib/src/modules/instabug.dart +++ b/lib/src/modules/instabug.dart @@ -1,7 +1,6 @@ // ignore_for_file: avoid_classes_with_only_static_members import 'dart:async'; -import 'dart:io'; // to maintain supported versions prior to Flutter 3.3 // ignore: unnecessary_import From 98a2f8cb9429c2f70aac6dad744ab272f766c72e Mon Sep 17 00:00:00 2001 From: AyaMahmoud148 Date: Thu, 10 Jul 2025 12:25:15 +0300 Subject: [PATCH 25/84] fix: unit test --- .../com/instabug/flutter/InstabugApiTest.java | 34 ++++++++----------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/android/src/test/java/com/instabug/flutter/InstabugApiTest.java b/android/src/test/java/com/instabug/flutter/InstabugApiTest.java index 65b36d959..30512a2e4 100644 --- a/android/src/test/java/com/instabug/flutter/InstabugApiTest.java +++ b/android/src/test/java/com/instabug/flutter/InstabugApiTest.java @@ -692,25 +692,21 @@ public void testSetThemeWithAllProperties() { when(mock.build()).thenReturn(mock(com.instabug.library.model.IBGTheme.class)); }); - api.setTheme(themeConfig); - - com.instabug.library.model.IBGTheme.Builder builder = mThemeBuilder.constructed().get(0); - - // Verify color setters were called - verify(builder).setPrimaryColor(android.graphics.Color.parseColor("#FF6B6B")); - verify(builder).setBackgroundColor(android.graphics.Color.parseColor("#FFFFFF")); - verify(builder).setTitleTextColor(android.graphics.Color.parseColor("#000000")); - verify(builder).setPrimaryTextColor(android.graphics.Color.parseColor("#333333")); - verify(builder).setSecondaryTextColor(android.graphics.Color.parseColor("#666666")); - - // Verify text style setters were called - verify(builder).setPrimaryTextStyle(Typeface.BOLD); - verify(builder).setSecondaryTextStyle(Typeface.ITALIC); - verify(builder).setCtaTextStyle(Typeface.BOLD_ITALIC); - - // Verify theme was set on Instabug - mInstabug.verify(() -> Instabug.setTheme(any(com.instabug.library.model.IBGTheme.class))); - + api.setTheme(themeConfig); + + com.instabug.library.model.IBGTheme.Builder builder = mThemeBuilder.constructed().get(0); + + verify(builder).setPrimaryColor(anyInt()); + verify(builder).setBackgroundColor(anyInt()); + verify(builder).setTitleTextColor(anyInt()); + verify(builder).setPrimaryTextColor(anyInt()); + verify(builder).setSecondaryTextColor(anyInt()); + + verify(builder).setPrimaryTextStyle(Typeface.BOLD); + verify(builder).setSecondaryTextStyle(Typeface.ITALIC); + verify(builder).setCtaTextStyle(Typeface.BOLD_ITALIC); + + mInstabug.verify(() -> Instabug.setTheme(any(com.instabug.library.model.IBGTheme.class))) } From 20add374041542de55fbe0d419797c22390d94ad Mon Sep 17 00:00:00 2001 From: AyaMahmoud148 Date: Thu, 10 Jul 2025 12:33:07 +0300 Subject: [PATCH 26/84] fix: linting --- android/src/test/java/com/instabug/flutter/InstabugApiTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/src/test/java/com/instabug/flutter/InstabugApiTest.java b/android/src/test/java/com/instabug/flutter/InstabugApiTest.java index 30512a2e4..755a9d068 100644 --- a/android/src/test/java/com/instabug/flutter/InstabugApiTest.java +++ b/android/src/test/java/com/instabug/flutter/InstabugApiTest.java @@ -706,7 +706,7 @@ public void testSetThemeWithAllProperties() { verify(builder).setSecondaryTextStyle(Typeface.ITALIC); verify(builder).setCtaTextStyle(Typeface.BOLD_ITALIC); - mInstabug.verify(() -> Instabug.setTheme(any(com.instabug.library.model.IBGTheme.class))) + mInstabug.verify(() -> Instabug.setTheme(any(com.instabug.library.model.IBGTheme.class))); } From 5c1551b8ff56a8e53d6d73604be9c849897f265b Mon Sep 17 00:00:00 2001 From: Andrew Amin Date: Sun, 13 Jul 2025 17:59:14 +0300 Subject: [PATCH 27/84] chore: add store API in Android side --- android/build.gradle | 2 +- .../com/instabug/flutter/modules/ApmApi.java | 45 +++++- .../java/com/instabug/flutter/ApmApiTest.java | 118 ++++++++++++++ example/lib/main.dart | 8 +- .../lib/src/screens/screen_render_page.dart | 7 +- .../models/instabug_screen_render_data.dart | 33 ++-- .../instabug_screen_render_manager.dart | 150 +++++++++--------- .../instabug_widget_binding_observer.dart | 16 +- test/apm_test.dart | 4 +- .../instabug_screen_render_manager_test.dart | 95 +++++++---- ...instabug_widget_binding_observer_test.dart | 8 + 11 files changed, 349 insertions(+), 137 deletions(-) diff --git a/android/build.gradle b/android/build.gradle index 8767af259..59335cf53 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -52,7 +52,7 @@ android { } dependencies { - api 'com.instabug.library:instabug:15.0.0.6897042-SNAPSHOT' + api 'com.instabug.library:instabug:15.0.0.6969715-SNAPSHOT' testImplementation 'junit:junit:4.13.2' testImplementation "org.mockito:mockito-inline:3.12.1" testImplementation "io.mockk:mockk:1.13.13" diff --git a/android/src/main/java/com/instabug/flutter/modules/ApmApi.java b/android/src/main/java/com/instabug/flutter/modules/ApmApi.java index d2c85e240..7e4b58bd5 100644 --- a/android/src/main/java/com/instabug/flutter/modules/ApmApi.java +++ b/android/src/main/java/com/instabug/flutter/modules/ApmApi.java @@ -12,6 +12,8 @@ import com.instabug.apm.model.ExecutionTrace; import com.instabug.apm.networking.APMNetworkLogger; import com.instabug.apm.networkinterception.cp.APMCPNetworkLog; +import com.instabug.apm.screenrendering.models.cp.IBGFrameData; +import com.instabug.apm.screenrendering.models.cp.IBGScreenRenderingData; import com.instabug.flutter.generated.ApmPigeon; import com.instabug.flutter.util.Reflection; import com.instabug.flutter.util.ThreadManager; @@ -19,7 +21,9 @@ import org.json.JSONObject; import java.lang.reflect.Method; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.concurrent.Callable; @@ -516,12 +520,49 @@ public void deviceRefreshRate(@NonNull ApmPigeon.Result result) { @Override public void endScreenRenderForAutoUiTrace(@NonNull Map data) { - + final long traceId = ((Number) data.get("traceId")).longValue(); + final long slowFramesTotalDuration = ((Number) data.get("slowFramesTotalDuration")).longValue(); + final long frozenFramesTotalDuration = ((Number) data.get("frozenFramesTotalDuration")).longValue(); + final long endTime = ((Number) data.get("endTime")).longValue(); + + // Don't cast directly to ArrayList> because the inner lists may actually be ArrayList + // Instead, cast to List> and convert each value to long explicitly + List> rawFrames = (List>) data.get("frameData"); + ArrayList frames = new ArrayList<>(); + if (rawFrames != null) { + for (List frameValues : rawFrames) { + // Defensive: check size and nulls + if (frameValues != null && frameValues.size() >= 2) { + long frameStart = frameValues.get(0).longValue(); + long frameDuration = frameValues.get(1).longValue(); + frames.add(new IBGFrameData(frameStart, frameDuration)); + } + } + } + IBGScreenRenderingData screenRenderingData = new IBGScreenRenderingData(traceId, slowFramesTotalDuration, frozenFramesTotalDuration, frames); + InternalAPM._endAutoUiTraceWithScreenRendering(screenRenderingData, endTime); } @Override public void endScreenRenderForCustomUiTrace(@NonNull Map data) { - + final long traceId = ((Number) data.get("traceId")).longValue(); + final long slowFramesTotalDuration = ((Number) data.get("slowFramesTotalDuration")).longValue(); + final long frozenFramesTotalDuration = ((Number) data.get("frozenFramesTotalDuration")).longValue(); + + List> rawFrames = (List>) data.get("frameData"); + ArrayList frames = new ArrayList<>(); + if (rawFrames != null) { + for (List frameValues : rawFrames) { + // Defensive: check size and nulls + if (frameValues != null && frameValues.size() >= 2) { + long frameStart = frameValues.get(0).longValue(); + long frameDuration = frameValues.get(1).longValue(); + frames.add(new IBGFrameData(frameStart, frameDuration)); + } + } + } + IBGScreenRenderingData screenRenderingData = new IBGScreenRenderingData(traceId, slowFramesTotalDuration, frozenFramesTotalDuration, frames); + InternalAPM._endCustomUiTraceWithScreenRenderingCP(screenRenderingData); } } diff --git a/android/src/test/java/com/instabug/flutter/ApmApiTest.java b/android/src/test/java/com/instabug/flutter/ApmApiTest.java index 4ef118cec..ab5ec93ab 100644 --- a/android/src/test/java/com/instabug/flutter/ApmApiTest.java +++ b/android/src/test/java/com/instabug/flutter/ApmApiTest.java @@ -409,6 +409,7 @@ public void testIsScreenRenderEnabled() { verify(result).success(expected); } + @Test public void testSetScreenRenderEnabled() { boolean isEnabled = false; @@ -416,4 +417,121 @@ public void testSetScreenRenderEnabled() { mAPM.verify(() -> APM.setScreenRenderingEnabled(isEnabled)); } + + @Test + public void testDeviceRefreshRate() throws Exception { + float expectedRefreshRate = 60.0f; + Double expectedResult = 60.0; + ApmPigeon.Result result = spy(makeResult((actual) -> assertEquals(expectedResult, actual))); + + // Mock the refresh rate provider to return the expected value + Callable mockRefreshRateProvider = () -> expectedRefreshRate; + ApmApi testApi = new ApmApi(mockRefreshRateProvider); + + testApi.deviceRefreshRate(result); + + verify(result).success(expectedResult); + } + + @Test + public void testDeviceRefreshRateWithException() throws Exception { + ApmPigeon.Result result = spy(makeResult((actual) -> {})); + + // Mock the refresh rate provider to throw an exception + Callable mockRefreshRateProvider = () -> { + throw new RuntimeException("Test exception"); + }; + ApmApi testApi = new ApmApi(mockRefreshRateProvider); + + testApi.deviceRefreshRate(result); + + // Verify that the method doesn't crash when an exception occurs + // The exception is caught and printed, but the result is not called + verify(result, never()).success(any()); + } + + @Test + public void testEndScreenRenderForAutoUiTrace() { + Map data = new HashMap<>(); + data.put("traceId", 123L); + data.put("slowFramesTotalDuration", 1000L); + data.put("frozenFramesTotalDuration", 2000L); + data.put("endTime", 1234567890L); + data.put("frameData", null); + + api.endScreenRenderForAutoUiTrace(data); + + mInternalApmStatic.verify(() -> InternalAPM._endAutoUiTraceWithScreenRendering(any(), eq(1234567890L))); + mInternalApmStatic.verifyNoMoreInteractions(); + } + + @Test + public void testEndScreenRenderForAutoUiTraceWithFrameData() { + Map data = new HashMap<>(); + data.put("traceId", 123L); + data.put("slowFramesTotalDuration", 1000L); + data.put("frozenFramesTotalDuration", 2000L); + data.put("endTime", 1234567890L); + + // Create frame data with ArrayList> + java.util.ArrayList> frameData = new java.util.ArrayList<>(); + java.util.ArrayList frame1 = new java.util.ArrayList<>(); + frame1.add(100L); + frame1.add(200L); + frameData.add(frame1); + + java.util.ArrayList frame2 = new java.util.ArrayList<>(); + frame2.add(300L); + frame2.add(400L); + frameData.add(frame2); + + data.put("frameData", frameData); + + api.endScreenRenderForAutoUiTrace(data); + + mInternalApmStatic.verify(() -> InternalAPM._endAutoUiTraceWithScreenRendering(any(), eq(1234567890L))); + mInternalApmStatic.verifyNoMoreInteractions(); + } + + @Test + public void testEndScreenRenderForCustomUiTrace() { + Map data = new HashMap<>(); + data.put("traceId", 123L); + data.put("slowFramesTotalDuration", 1000L); + data.put("frozenFramesTotalDuration", 2000L); + data.put("endTime", 1234567890L); + data.put("frameData", null); + + api.endScreenRenderForCustomUiTrace(data); + + mInternalApmStatic.verify(() -> InternalAPM._endCustomUiTraceWithScreenRenderingCP(any())); + mInternalApmStatic.verifyNoMoreInteractions(); + } + + @Test + public void testEndScreenRenderForCustomUiTraceWithFrameData() { + Map data = new HashMap<>(); + data.put("traceId", 123L); + data.put("slowFramesTotalDuration", 1000L); + data.put("frozenFramesTotalDuration", 2000L); + + // Create frame data with ArrayList> + java.util.ArrayList> frameData = new java.util.ArrayList<>(); + java.util.ArrayList frame1 = new java.util.ArrayList<>(); + frame1.add(100L); + frame1.add(200L); + frameData.add(frame1); + + java.util.ArrayList frame2 = new java.util.ArrayList<>(); + frame2.add(300L); + frame2.add(400L); + frameData.add(frame2); + + data.put("frameData", frameData); + + api.endScreenRenderForCustomUiTrace(data); + + mInternalApmStatic.verify(() -> InternalAPM._endCustomUiTraceWithScreenRenderingCP(any())); + mInternalApmStatic.verifyNoMoreInteractions(); + } } diff --git a/example/lib/main.dart b/example/lib/main.dart index d3a16aa52..bc67d868a 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -19,12 +19,14 @@ import 'src/widget/instabug_text_field.dart'; import 'src/widget/section_title.dart'; part 'src/components/animated_box.dart'; +part 'src/components/apm_switch.dart'; part 'src/components/fatal_crashes_content.dart'; part 'src/components/flows_content.dart'; part 'src/components/network_content.dart'; part 'src/components/non_fatal_crashes_content.dart'; part 'src/components/page.dart'; part 'src/components/screen_render.dart'; +part 'src/components/screen_render_switch.dart'; part 'src/components/traces_content.dart'; part 'src/components/ui_traces_content.dart'; part 'src/screens/apm_page.dart'; @@ -34,8 +36,6 @@ part 'src/screens/my_home_page.dart'; part 'src/screens/screen_capture_premature_extension_page.dart'; part 'src/screens/screen_loading_page.dart'; part 'src/screens/screen_render_page.dart'; -part 'src/components/apm_switch.dart'; -part 'src/components/screen_render_switch.dart'; void main() { runZonedGuarded( @@ -46,7 +46,9 @@ void main() { token: 'ed6f659591566da19b67857e1b9d40ab', invocationEvents: [InvocationEvent.floatingButton], debugLogsLevel: LogLevel.verbose, - ); + ).then((_) { + // APM.setScreenRenderEnabled(false); + }); FlutterError.onError = (FlutterErrorDetails details) { Zone.current.handleUncaughtError(details.exception, details.stack!); diff --git a/example/lib/src/screens/screen_render_page.dart b/example/lib/src/screens/screen_render_page.dart index f8dddf96b..535bd614d 100644 --- a/example/lib/src/screens/screen_render_page.dart +++ b/example/lib/src/screens/screen_render_page.dart @@ -1,14 +1,9 @@ part of '../../main.dart'; -class ScreenRenderPage extends StatefulWidget { +class ScreenRenderPage extends StatelessWidget { const ScreenRenderPage({Key? key}) : super(key: key); static const String screenName = "/screenRenderPageRoute"; - @override - State createState() => _ScreenRenderPageState(); -} - -class _ScreenRenderPageState extends State { @override Widget build(BuildContext context) { return Page(title: 'Screen Render', children: [ diff --git a/lib/src/models/instabug_screen_render_data.dart b/lib/src/models/instabug_screen_render_data.dart index 570f57115..ad9e5fe8a 100644 --- a/lib/src/models/instabug_screen_render_data.dart +++ b/lib/src/models/instabug_screen_render_data.dart @@ -1,15 +1,18 @@ import 'package:flutter/foundation.dart'; import 'package:instabug_flutter/src/models/instabug_frame_data.dart'; +import 'package:instabug_flutter/src/utils/ibg_date_time.dart'; class InstabugScreenRenderData { int traceId; - int slowFramesTotalDuration; - int frozenFramesTotalDuration; + int slowFramesTotalDurationMicro; + int frozenFramesTotalDurationMicro; + int? endTimeMicro; List frameData; InstabugScreenRenderData({ - this.slowFramesTotalDuration = 0, - this.frozenFramesTotalDuration = 0, + this.slowFramesTotalDurationMicro = 0, + this.frozenFramesTotalDurationMicro = 0, + this.endTimeMicro, required this.frameData, this.traceId = -1, }); @@ -22,15 +25,19 @@ class InstabugScreenRenderData { void clear() { traceId = -1; - frozenFramesTotalDuration = 0; - slowFramesTotalDuration = 0; + frozenFramesTotalDurationMicro = 0; + slowFramesTotalDurationMicro = 0; frameData.clear(); } + void saveEndTime() => + endTimeMicro = IBGDateTime.I.now().microsecondsSinceEpoch; + @override String toString() => '\nTraceId: $traceId\n' - 'SlowFramesTotalDuration: $slowFramesTotalDuration\n' - 'FrozenFramesTotalDuration: $frozenFramesTotalDuration\n' + 'SlowFramesTotalDuration: $slowFramesTotalDurationMicro\n' + 'FrozenFramesTotalDuration: $frozenFramesTotalDurationMicro\n' + 'EndTime: $endTimeMicro\n' 'FrameData: [${frameData.map((element) => '$element')}]'; @override @@ -38,8 +45,9 @@ class InstabugScreenRenderData { bool operator ==(covariant InstabugScreenRenderData other) { if (identical(this, other)) return true; return traceId == other.traceId && - slowFramesTotalDuration == other.slowFramesTotalDuration && - frozenFramesTotalDuration == other.frozenFramesTotalDuration && + slowFramesTotalDurationMicro == other.slowFramesTotalDurationMicro && + frozenFramesTotalDurationMicro == + other.frozenFramesTotalDurationMicro && listEquals(frameData, other.frameData); } @@ -47,8 +55,9 @@ class InstabugScreenRenderData { Map toMap() { return { 'traceId': traceId, - 'slowFramesTotalDuration': slowFramesTotalDuration, - 'frozenFramesTotalDuration': frozenFramesTotalDuration, + 'slowFramesTotalDuration': slowFramesTotalDurationMicro, + 'frozenFramesTotalDuration': frozenFramesTotalDurationMicro, + 'endTime': endTimeMicro, // Convert List to List> 'frameData': frameData.map((frame) => frame.toList()).toList(), }; diff --git a/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart b/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart index 090be0a7b..458c56e3c 100644 --- a/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart +++ b/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart @@ -27,24 +27,23 @@ class InstabugScreenRenderManager { late TimingsCallback _timingsCallback; late InstabugScreenRenderData _screenRenderForAutoUiTrace; late InstabugScreenRenderData _screenRenderForCustomUiTrace; + int _slowFramesTotalDurationMs = 0; + int _frozenFramesTotalDurationMs = 0; + bool _isTimingsListenerAttached = false; + bool screenRenderEnabled = false; final List _delayedFrames = []; + /// 1 / DeviceRefreshRate * 1000 double _deviceRefreshRate = 60; - /// Default refresh rate for 60 FPS displays + /// Default refresh rate for 60 FPS displays in milliseconds (16.67ms) double _slowFrameThresholdMs = 16.67; - /// 1/DeviceRefreshRate * 1000 - final _frozenFrameThresholdMs = 700; - /// Default frozen frame threshold in milliseconds (700ms) - int _slowFramesTotalDuration = 0; - int _frozenFramesTotalDuration = 0; - final int _microsecondsPerMillisecond = 1000; + final _frozenFrameThresholdMs = 700; - bool _isTimingsListenerAttached = false; - bool screenRenderEnabled = false; + final _microsecondsPerMillisecond = 1000; InstabugScreenRenderManager._(); @@ -86,37 +85,33 @@ class InstabugScreenRenderManager { _totalTime = frameTiming.totalSpan.inMilliseconds; _displayFrameTimingDetails(frameTiming); - if (_isUiSlow) { - _slowFramesTotalDuration += _buildTime * - _microsecondsPerMillisecond; //convert from milliseconds to microseconds - } else if (_isRasterSlow) { - _slowFramesTotalDuration += _rasterTime * - _microsecondsPerMillisecond; //convert from milliseconds to microseconds - } - if (_isUiFrozen) { - _frozenFramesTotalDuration += _buildTime * _microsecondsPerMillisecond; + _frozenFramesTotalDurationMs += _buildTime; } else if (_isRasterFrozen) { - _frozenFramesTotalDuration += _rasterTime * _microsecondsPerMillisecond; - } else if (_isFrozen) { - _frozenFramesTotalDuration += _totalTime * _microsecondsPerMillisecond; + _frozenFramesTotalDurationMs += _rasterTime; + } else if (_isTotalTimeLarge) { + _frozenFramesTotalDurationMs += _totalTime; + } + if (_isUiSlow) { + _slowFramesTotalDurationMs += _buildTime; + } else if (_isRasterSlow) { + _slowFramesTotalDurationMs += _rasterTime; } if (_isUiDelayed) { _onDelayedFrameDetected( frameTiming.timestampInMicroseconds(FramePhase.buildStart), - frameTiming.buildDuration.inMicroseconds, + _buildTime, ); } else if (_isRasterDelayed) { _onDelayedFrameDetected( frameTiming.timestampInMicroseconds(FramePhase.rasterStart), - frameTiming.rasterDuration.inMicroseconds, + _rasterTime, ); } else if (_isTotalTimeLarge) { - // todo what to do? _onDelayedFrameDetected( frameTiming.timestampInMicroseconds(FramePhase.vsyncStart), - frameTiming.totalSpan.inMicroseconds, + _totalTime, ); } } @@ -153,10 +148,7 @@ class InstabugScreenRenderManager { // Report only if the collector was active and has captured data if (_screenRenderForCustomUiTrace.isActive && _screenRenderForCustomUiTrace.isNotEmpty) { - reportScreenRending( - _screenRenderForCustomUiTrace, - UiTraceType.custom, - ); + _reportScreenRenderForCustomUiTrace(_screenRenderForCustomUiTrace); _screenRenderForCustomUiTrace.clear(); } _screenRenderForCustomUiTrace.traceId = traceId; @@ -167,7 +159,7 @@ class InstabugScreenRenderManager { // Report only if the collector was active and has captured data if (_screenRenderForAutoUiTrace.isActive && _screenRenderForAutoUiTrace.isNotEmpty) { - reportScreenRending(_screenRenderForAutoUiTrace); + _reportScreenRenderForAutoUiTrace(_screenRenderForAutoUiTrace); _screenRenderForAutoUiTrace.clear(); } _screenRenderForAutoUiTrace.traceId = traceId; @@ -188,17 +180,15 @@ class InstabugScreenRenderManager { // Sync Screen Render data for custom ui trace if exists if (_screenRenderForCustomUiTrace.isActive && _screenRenderForCustomUiTrace.isNotEmpty) { - reportScreenRending(_screenRenderForCustomUiTrace, UiTraceType.custom); + _reportScreenRenderForCustomUiTrace(_screenRenderForCustomUiTrace); } // Sync Screen Render data for auto ui trace if exists if (_screenRenderForAutoUiTrace.isActive && _screenRenderForAutoUiTrace.isNotEmpty) { - reportScreenRending(_screenRenderForAutoUiTrace); + _reportScreenRenderForAutoUiTrace(_screenRenderForAutoUiTrace); } - // Dispose Screen Render Manager - dispose(); log("$tag: stopScreenRenderCollector", name: 'andrew'); } catch (error, stackTrace) { _logExceptionErrorAndStackTrace(error, stackTrace); @@ -214,14 +204,11 @@ class InstabugScreenRenderManager { } // Save the captured screen rendering data to be synced - _screenRenderForCustomUiTrace.slowFramesTotalDuration += - _slowFramesTotalDuration; - _screenRenderForCustomUiTrace.frozenFramesTotalDuration += - _frozenFramesTotalDuration; - _screenRenderForCustomUiTrace.frameData.addAll(_delayedFrames); + _updateCustomUiData(); // Sync the saved screen rendering data - reportScreenRending(_screenRenderForCustomUiTrace, UiTraceType.custom); + _reportScreenRenderForCustomUiTrace(_screenRenderForCustomUiTrace); + _screenRenderForCustomUiTrace.clear(); log("$tag: endCustom", name: 'andrew'); } catch (error, stackTrace) { @@ -229,24 +216,6 @@ class InstabugScreenRenderManager { } } - /// Sync captures screen render data based on their type. - @visibleForTesting - Future reportScreenRending( - InstabugScreenRenderData screenRenderData, [ - UiTraceType type = UiTraceType.auto, - ]) async { - if (type == UiTraceType.auto) { - _reportScreenRenderForAutoUiTrace(screenRenderData); - } else { - _reportScreenRenderForCustomUiTrace(screenRenderData); - } - - log( - "$tag: Report ${type == UiTraceType.auto ? 'auto' : 'custom'} Data: $screenRenderData", - name: 'andrew', - ); - } - /// Dispose InstabugScreenRenderManager by removing timings callback and cashed data. void dispose() { _resetCachedFrameData(); @@ -329,8 +298,8 @@ class InstabugScreenRenderManager { /// Reset the memory cashed data void _resetCachedFrameData() { - _slowFramesTotalDuration = 0; - _frozenFramesTotalDuration = 0; + _slowFramesTotalDurationMs = 0; + _frozenFramesTotalDurationMs = 0; _delayedFrames.clear(); log( "$tag: _resetCachedFrameData ", @@ -339,8 +308,14 @@ class InstabugScreenRenderManager { } /// Save Slow/Frozen Frames data - void _onDelayedFrameDetected(int startTime, int duration) { - _delayedFrames.add(InstabugFrameData(startTime, duration)); + void _onDelayedFrameDetected(int startTime, int durationInMilliseconds) { + _delayedFrames.add( + InstabugFrameData( + startTime, + durationInMilliseconds * + _microsecondsPerMillisecond, // Convert duration from milliseconds to microSeconds + ), + ); } //todo: will be removed (is used for debugging) @@ -404,6 +379,9 @@ class InstabugScreenRenderManager { InstabugScreenRenderData screenRenderData, ) async { try { + // Save the end time for the running ui trace, it's only needed in Android SDK. + screenRenderData.saveEndTime(); + await APM.endScreenRenderForAutoUiTrace(screenRenderData); return true; } catch (error, stackTrace) { @@ -415,18 +393,10 @@ class InstabugScreenRenderManager { /// Add the memory cashed data to the objects that will be synced asynchronously to the native side. void _saveCollectedData() { if (_screenRenderForAutoUiTrace.isActive) { - _screenRenderForAutoUiTrace.slowFramesTotalDuration += - _slowFramesTotalDuration; - _screenRenderForAutoUiTrace.frozenFramesTotalDuration += - _frozenFramesTotalDuration; - _screenRenderForAutoUiTrace.frameData.addAll(_delayedFrames); + _updateAutoUiData(); } if (_screenRenderForCustomUiTrace.isActive) { - _screenRenderForCustomUiTrace.slowFramesTotalDuration += - _slowFramesTotalDuration; - _screenRenderForCustomUiTrace.frozenFramesTotalDuration += - _frozenFramesTotalDuration; - _screenRenderForCustomUiTrace.frameData.addAll(_delayedFrames); + _updateCustomUiData(); } log( "$tag: Captured data is saved ", @@ -434,6 +404,36 @@ class InstabugScreenRenderManager { ); } + /// Updates the custom UI trace screen render data with the currently collected + /// frame information and durations. + /// + /// This method accumulates the total duration of slow and frozen frames (in microseconds) + /// for the custom UI trace, and appends the list of delayed frames collected so far + /// to the trace's frame data. This prepares the custom UI trace data to be reported + /// or synced with the native side. + void _updateCustomUiData() { + _screenRenderForCustomUiTrace.slowFramesTotalDurationMicro += + _slowFramesTotalDurationMs * _microsecondsPerMillisecond; + _screenRenderForCustomUiTrace.frozenFramesTotalDurationMicro += + _frozenFramesTotalDurationMs * _microsecondsPerMillisecond; + _screenRenderForCustomUiTrace.frameData.addAll(_delayedFrames); + } + + /// Updates the auto UI trace screen render data with the currently collected + /// frame information and durations. + /// + /// This method accumulates the total duration of slow and frozen frames (in microseconds) + /// for the auto UI trace, and appends the list of delayed frames collected so far + /// to the trace's frame data. This prepares the auto UI trace data to be reported + /// or synced with the native side. + void _updateAutoUiData() { + _screenRenderForAutoUiTrace.slowFramesTotalDurationMicro += + _slowFramesTotalDurationMs * _microsecondsPerMillisecond; + _screenRenderForAutoUiTrace.frozenFramesTotalDurationMicro += + _frozenFramesTotalDurationMs * _microsecondsPerMillisecond; + _screenRenderForAutoUiTrace.frameData.addAll(_delayedFrames); + } + /// @nodoc void _logExceptionErrorAndStackTrace(Object error, StackTrace stackTrace) { InstabugLogger.I.e( @@ -465,7 +465,9 @@ class InstabugScreenRenderManager { @visibleForTesting void setFrameData(InstabugScreenRenderData data) { _delayedFrames.addAll(data.frameData); - _frozenFramesTotalDuration = data.frozenFramesTotalDuration; - _slowFramesTotalDuration = data.slowFramesTotalDuration; + _frozenFramesTotalDurationMs = + data.frozenFramesTotalDurationMicro ~/ _microsecondsPerMillisecond; + _slowFramesTotalDurationMs = + data.slowFramesTotalDurationMicro ~/ _microsecondsPerMillisecond; } } diff --git a/lib/src/utils/screen_rendering/instabug_widget_binding_observer.dart b/lib/src/utils/screen_rendering/instabug_widget_binding_observer.dart index 61cb7b013..a4567a015 100644 --- a/lib/src/utils/screen_rendering/instabug_widget_binding_observer.dart +++ b/lib/src/utils/screen_rendering/instabug_widget_binding_observer.dart @@ -22,7 +22,12 @@ class InstabugWidgetsBindingObserver extends WidgetsBindingObserver { /// Logging tag for debugging purposes. static const tag = "InstabugWidgetsBindingObserver"; - static void dispose() => WidgetsBinding.instance.removeObserver(_instance); + static void dispose() { + if (InstabugScreenRenderManager.I.screenRenderEnabled) { + InstabugScreenRenderManager.I.dispose(); + } + WidgetsBinding.instance.removeObserver(_instance); + } void _handleResumedState() { log('Performing resume actions...', name: 'andrew'); @@ -44,12 +49,17 @@ class InstabugWidgetsBindingObserver extends WidgetsBindingObserver { void _handlePausedState() { log('Performing pause actions...', name: 'andrew'); - InstabugScreenRenderManager.I.stopScreenRenderCollector(); + + if (InstabugScreenRenderManager.I.screenRenderEnabled) { + InstabugScreenRenderManager.I.stopScreenRenderCollector(); + } } void _handleDetachedState() { log('Performing detached actions...', name: 'andrew'); - InstabugScreenRenderManager.I.stopScreenRenderCollector(); + if (InstabugScreenRenderManager.I.screenRenderEnabled) { + InstabugScreenRenderManager.I.stopScreenRenderCollector(); + } dispose(); } diff --git a/test/apm_test.dart b/test/apm_test.dart index 128b4d860..e080f6f88 100644 --- a/test/apm_test.dart +++ b/test/apm_test.dart @@ -345,7 +345,7 @@ void main() { "[endUITrace] should stop screen render collector with, if screen render feature is enabled", () async { when(mHost.isScreenRenderEnabled()).thenAnswer((_) async => true); - + when(mScreenRenderManager.screenRenderEnabled).thenReturn(true); const traceName = "traceNameTest"; await APM.startUITrace(traceName); await APM.endUITrace(); @@ -361,7 +361,7 @@ void main() { "[endUITrace] should acts as normal and do nothing related to screen render, if screen render feature is disabled", () async { when(mHost.isScreenRenderEnabled()).thenAnswer((_) async => false); - + when(mScreenRenderManager.screenRenderEnabled).thenReturn(false); const traceName = "traceNameTest"; await APM.startUITrace(traceName); await APM.endUITrace(); diff --git a/test/utils/screen_render/instabug_screen_render_manager_test.dart b/test/utils/screen_render/instabug_screen_render_manager_test.dart index fc8705362..91d2fa916 100644 --- a/test/utils/screen_render/instabug_screen_render_manager_test.dart +++ b/test/utils/screen_render/instabug_screen_render_manager_test.dart @@ -70,8 +70,8 @@ void main() { InstabugFrameData(10000, 200), InstabugFrameData(20000, 1000), ], - frozenFramesTotalDuration: 1000, - slowFramesTotalDuration: 200, + frozenFramesTotalDurationMicro: 1000, + slowFramesTotalDurationMicro: 200, ); manager.startScreenRenderCollectorForTraceId(frameTestData.traceId); @@ -139,8 +139,8 @@ void main() { InstabugFrameData(10000, 200), InstabugFrameData(20000, 1000), ], - frozenFramesTotalDuration: 1000, - slowFramesTotalDuration: 200, + frozenFramesTotalDurationMicro: 1000, + slowFramesTotalDurationMicro: 200, ); manager.setFrameData(frameTestData); @@ -160,11 +160,13 @@ void main() { final frameTestData = InstabugScreenRenderData( traceId: 123, frameData: [ - InstabugFrameData(10000, 200), + InstabugFrameData(10000, 400), + InstabugFrameData(10000, 600), InstabugFrameData(20000, 1000), ], - frozenFramesTotalDuration: 1000, - slowFramesTotalDuration: 200, + frozenFramesTotalDurationMicro: 1000, + slowFramesTotalDurationMicro: 1000, + endTimeMicro: 30000, ); manager.startScreenRenderCollectorForTraceId( @@ -177,9 +179,13 @@ void main() { expect(manager.screenRenderForAutoUiTrace.isActive, true); + expect(manager.screenRenderForCustomUiTrace.isActive, false); + expect(manager.screenRenderForAutoUiTrace == frameTestData, true); - expect(manager.screenRenderForCustomUiTrace.isActive, false); + verify( + mApmHost.endScreenRenderForAutoUiTrace(any), + ); // the content has been verified in the above assertion. }); test( @@ -188,11 +194,13 @@ void main() { final frameTestData = InstabugScreenRenderData( traceId: 123, frameData: [ - InstabugFrameData(10000, 200), + InstabugFrameData(10000, 400), + InstabugFrameData(10000, 600), InstabugFrameData(20000, 1000), ], - frozenFramesTotalDuration: 1000, - slowFramesTotalDuration: 200, + frozenFramesTotalDurationMicro: 1000, + slowFramesTotalDurationMicro: 1000, + endTimeMicro: 30000, ); manager.startScreenRenderCollectorForTraceId( @@ -206,26 +214,30 @@ void main() { expect(manager.screenRenderForCustomUiTrace.isActive, true); + expect(manager.screenRenderForAutoUiTrace.isActive, false); + expect(manager.screenRenderForCustomUiTrace == frameTestData, true); - expect(manager.screenRenderForAutoUiTrace.isActive, false); + verify( + mApmHost.endScreenRenderForCustomUiTrace(any), + ); // the content has been verified in the above assertion. }); - test('should remove timing callback listener', () { + test('should not remove timing callback listener', () { final frameTestData = InstabugScreenRenderData( traceId: 123, frameData: [ InstabugFrameData(10000, 200), InstabugFrameData(20000, 1000), ], - frozenFramesTotalDuration: 1000, - slowFramesTotalDuration: 200, + frozenFramesTotalDurationMicro: 1000, + slowFramesTotalDurationMicro: 200, ); manager.setFrameData(frameTestData); manager.stopScreenRenderCollector(); - verify(mWidgetBinding.removeTimingsCallback(any)).called(1); + verifyNever(mWidgetBinding.removeTimingsCallback(any)); }); test('should report data to native side with the correct type', () async { @@ -235,8 +247,8 @@ void main() { InstabugFrameData(10000, 200), InstabugFrameData(20000, 1000), ], - frozenFramesTotalDuration: 1000, - slowFramesTotalDuration: 200, + frozenFramesTotalDurationMicro: 1000, + slowFramesTotalDurationMicro: 200, ); manager.startScreenRenderCollectorForTraceId(0, UiTraceType.custom); @@ -260,8 +272,8 @@ void main() { InstabugFrameData(10000, 200), InstabugFrameData(20000, 1000), ], - frozenFramesTotalDuration: 1000, - slowFramesTotalDuration: 200, + frozenFramesTotalDurationMicro: 1000, + slowFramesTotalDurationMicro: 200, ); manager.setFrameData(frameTestdata); @@ -281,8 +293,8 @@ void main() { InstabugFrameData(10000, 200), InstabugFrameData(20000, 1000), ], - frozenFramesTotalDuration: 1000, - slowFramesTotalDuration: 200, + frozenFramesTotalDurationMicro: 1000, + slowFramesTotalDurationMicro: 200, ); manager.startScreenRenderCollectorForTraceId( @@ -308,8 +320,8 @@ void main() { InstabugFrameData(10000, 200), InstabugFrameData(20000, 1000), ], - frozenFramesTotalDuration: 1000, - slowFramesTotalDuration: 200, + frozenFramesTotalDurationMicro: 1000, + slowFramesTotalDurationMicro: 200, ); manager.startScreenRenderCollectorForTraceId(0, UiTraceType.custom); @@ -344,10 +356,13 @@ void main() { expect(manager.screenRenderForAutoUiTrace.frameData.length, 1); expect( - manager.screenRenderForAutoUiTrace.slowFramesTotalDuration, + manager.screenRenderForAutoUiTrace.slowFramesTotalDurationMicro, buildDuration * 1000, ); // * 1000 to convert from milli to micro - expect(manager.screenRenderForAutoUiTrace.frozenFramesTotalDuration, 0); + expect( + manager.screenRenderForAutoUiTrace.frozenFramesTotalDurationMicro, + 0, + ); }); test('should detect slow frame on raster thread and record duration', () { @@ -361,10 +376,13 @@ void main() { expect(manager.screenRenderForAutoUiTrace.frameData.length, 1); expect( - manager.screenRenderForAutoUiTrace.slowFramesTotalDuration, + manager.screenRenderForAutoUiTrace.slowFramesTotalDurationMicro, rasterDuration * 1000, ); // * 1000 to convert from milli to micro - expect(manager.screenRenderForAutoUiTrace.frozenFramesTotalDuration, 0); + expect( + manager.screenRenderForAutoUiTrace.frozenFramesTotalDurationMicro, + 0, + ); }); test( @@ -379,10 +397,13 @@ void main() { expect(manager.screenRenderForAutoUiTrace.frameData.length, 1); expect( - manager.screenRenderForAutoUiTrace.frozenFramesTotalDuration, + manager.screenRenderForAutoUiTrace.frozenFramesTotalDurationMicro, buildDuration * 1000, ); // * 1000 to convert from milli to micro - expect(manager.screenRenderForAutoUiTrace.slowFramesTotalDuration, 0); + expect( + manager.screenRenderForAutoUiTrace.slowFramesTotalDurationMicro, + 0, + ); }); test( @@ -397,10 +418,13 @@ void main() { expect(manager.screenRenderForAutoUiTrace.frameData.length, 1); expect( - manager.screenRenderForAutoUiTrace.frozenFramesTotalDuration, + manager.screenRenderForAutoUiTrace.frozenFramesTotalDurationMicro, rasterBuild * 1000, ); // * 1000 to convert from milli to micro - expect(manager.screenRenderForAutoUiTrace.slowFramesTotalDuration, 0); + expect( + manager.screenRenderForAutoUiTrace.slowFramesTotalDurationMicro, + 0, + ); }); test('should detect no slow or frozen frame under thresholds', () { @@ -413,10 +437,13 @@ void main() { manager.analyzeFrameTiming(mockFrameTiming); expect(manager.screenRenderForAutoUiTrace.frameData.isEmpty, true); expect( - manager.screenRenderForAutoUiTrace.frozenFramesTotalDuration, + manager.screenRenderForAutoUiTrace.frozenFramesTotalDurationMicro, 0, ); // * 1000 to convert from milli to micro - expect(manager.screenRenderForAutoUiTrace.slowFramesTotalDuration, 0); + expect( + manager.screenRenderForAutoUiTrace.slowFramesTotalDurationMicro, + 0, + ); }); }); } diff --git a/test/utils/screen_render/instabug_widget_binding_observer_test.dart b/test/utils/screen_render/instabug_widget_binding_observer_test.dart index 54415fdb7..b97d312a0 100644 --- a/test/utils/screen_render/instabug_widget_binding_observer_test.dart +++ b/test/utils/screen_render/instabug_widget_binding_observer_test.dart @@ -22,6 +22,8 @@ void main() { late MockScreenNameMasker mockNameMasker; late MockUiTrace mockUiTrace; + TestWidgetsFlutterBinding.ensureInitialized(); + setUp(() { mockRenderManager = MockInstabugScreenRenderManager(); mockLoadingManager = MockScreenLoadingManager(); @@ -63,14 +65,20 @@ void main() { }); test('handles AppLifecycleState.paused and stops render collector', () { + when(mockRenderManager.screenRenderEnabled).thenReturn(true); + InstabugWidgetsBindingObserver.I .didChangeAppLifecycleState(AppLifecycleState.paused); + verify(mockRenderManager.stopScreenRenderCollector()).called(1); }); test('handles AppLifecycleState.detached and stops render collector', () { + when(mockRenderManager.screenRenderEnabled).thenReturn(true); + InstabugWidgetsBindingObserver.I .didChangeAppLifecycleState(AppLifecycleState.detached); + verify(mockRenderManager.stopScreenRenderCollector()).called(1); }); From a39ea76b80b06ce76287b007bdb197f693bee0db Mon Sep 17 00:00:00 2001 From: Andrew Amin Date: Sun, 13 Jul 2025 18:16:49 +0300 Subject: [PATCH 28/84] chore: remove logs --- .../utils/instabug_navigator_observer.dart | 2 - .../instabug_screen_render_manager.dart | 74 ------------------- .../instabug_widget_binding_observer.dart | 9 +-- 3 files changed, 1 insertion(+), 84 deletions(-) diff --git a/lib/src/utils/instabug_navigator_observer.dart b/lib/src/utils/instabug_navigator_observer.dart index 7f83eb279..26aa3803c 100644 --- a/lib/src/utils/instabug_navigator_observer.dart +++ b/lib/src/utils/instabug_navigator_observer.dart @@ -1,5 +1,4 @@ import 'dart:async'; -import 'dart:developer'; import 'package:flutter/material.dart'; import 'package:instabug_flutter/instabug_flutter.dart'; @@ -68,7 +67,6 @@ class InstabugNavigatorObserver extends NavigatorObserver { FutureOr _startScreenRenderCollector(int? uiTraceId) async { final isScreenRender = await FlagsConfig.screenRendering.isEnabled(); - log("isScreenRender: $isScreenRender", name: 'Andrew'); _checkForScreenRenderInitialization(isScreenRender); if (uiTraceId != null && isScreenRender) { InstabugScreenRenderManager.I diff --git a/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart b/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart index 458c56e3c..546018ccc 100644 --- a/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart +++ b/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart @@ -1,5 +1,4 @@ import 'dart:async'; -import 'dart:developer'; import 'dart:ui'; import 'package:flutter/widgets.dart'; @@ -10,8 +9,6 @@ import 'package:instabug_flutter/src/utils/instabug_logger.dart'; import 'package:instabug_flutter/src/utils/screen_rendering/instabug_widget_binding_observer.dart'; import 'package:meta/meta.dart'; -//todo: remove logs - @internal enum UiTraceType { auto, @@ -65,7 +62,6 @@ class InstabugScreenRenderManager { try { // passing WidgetsBinding? (nullable) for flutter versions prior than 3.x if (!screenRenderEnabled && widgetBinding != null) { - log("$tag: init", name: 'andrew'); _widgetsBinding = widgetBinding; _addWidgetBindingObserver(); await _initStaticValues(); @@ -84,7 +80,6 @@ class InstabugScreenRenderManager { _rasterTime = frameTiming.rasterDuration.inMilliseconds; _totalTime = frameTiming.totalSpan.inMilliseconds; - _displayFrameTimingDetails(frameTiming); if (_isUiFrozen) { _frozenFramesTotalDurationMs += _buildTime; } else if (_isRasterFrozen) { @@ -126,16 +121,8 @@ class InstabugScreenRenderManager { try { // Return if frameTimingListener not attached if (!screenRenderEnabled || !_isTimingsListenerAttached) { - log( - "$tag: startScreenRenderCollectorForTraceId returned", - name: 'andrew', - ); return; } - log( - "$tag: startScreenRenderCollectorForTraceId $traceId (${type.name})", - name: 'andrew', - ); //Save the memory cached data to be sent to native side if (_delayedFrames.isNotEmpty) { @@ -188,8 +175,6 @@ class InstabugScreenRenderManager { _screenRenderForAutoUiTrace.isNotEmpty) { _reportScreenRenderForAutoUiTrace(_screenRenderForAutoUiTrace); } - - log("$tag: stopScreenRenderCollector", name: 'andrew'); } catch (error, stackTrace) { _logExceptionErrorAndStackTrace(error, stackTrace); } @@ -210,7 +195,6 @@ class InstabugScreenRenderManager { _reportScreenRenderForCustomUiTrace(_screenRenderForCustomUiTrace); _screenRenderForCustomUiTrace.clear(); - log("$tag: endCustom", name: 'andrew'); } catch (error, stackTrace) { _logExceptionErrorAndStackTrace(error, stackTrace); } @@ -222,13 +206,10 @@ class InstabugScreenRenderManager { _removeFrameTimings(); _widgetsBinding = null; screenRenderEnabled = false; - log("$tag: dispose", name: 'andrew'); } /// --------------------------- private methods --------------------- - bool get _isSlow => _isUiSlow || _isRasterSlow; - bool get _isUiDelayed => _isUiSlow || _isUiFrozen; bool get _isRasterDelayed => _isRasterSlow || _isRasterFrozen; @@ -241,8 +222,6 @@ class InstabugScreenRenderManager { _rasterTime > _slowFrameThresholdMs && _rasterTime < _frozenFrameThresholdMs; - bool get _isFrozen => _isUiFrozen || _isRasterFrozen || _isTotalTimeLarge; - bool get _isTotalTimeLarge => _totalTime >= _frozenFrameThresholdMs; bool get _isUiFrozen => _buildTime >= _frozenFrameThresholdMs; @@ -272,7 +251,6 @@ class InstabugScreenRenderManager { _slowFrameThresholdMs = _targetMsPerFrame(_deviceRefreshRate); _screenRenderForAutoUiTrace = InstabugScreenRenderData(frameData: []); _screenRenderForCustomUiTrace = InstabugScreenRenderData(frameData: []); - log("$tag: _initStaticValues ", name: 'andrew'); } /// Add a frame observer by calling [WidgetsBinding.instance.addTimingsCallback] @@ -282,7 +260,6 @@ class InstabugScreenRenderManager { } _widgetsBinding?.addTimingsCallback(_timingsCallback); _isTimingsListenerAttached = true; - log("$tag: _initFrameTimings ", name: 'andrew'); } /// Remove the running frame observer by calling [_widgetsBinding.removeTimingsCallback] @@ -290,10 +267,6 @@ class InstabugScreenRenderManager { if (!_isTimingsListenerAttached) return; // No timings callback attached. _widgetsBinding?.removeTimingsCallback(_timingsCallback); _isTimingsListenerAttached = false; - log( - "$tag: _removeFrameTimings ", - name: 'andrew', - ); } /// Reset the memory cashed data @@ -301,10 +274,6 @@ class InstabugScreenRenderManager { _slowFramesTotalDurationMs = 0; _frozenFramesTotalDurationMs = 0; _delayedFrames.clear(); - log( - "$tag: _resetCachedFrameData ", - name: 'andrew', - ); } /// Save Slow/Frozen Frames data @@ -318,45 +287,6 @@ class InstabugScreenRenderManager { ); } - //todo: will be removed (is used for debugging) - void _displayFrameTimingDetails(FrameTiming frameTiming) { - if (_isSlow) { - debugPrint( - '========================= Slow frame detected ⚠️ =========================', - ); - } - if (_isFrozen) { - debugPrint( - '========================= Frozen frame detected 🚨 =========================', - ); - } - - if (_isFrozen || _isSlow) { - debugPrint( - "{\n\t$frameTiming\n\t" - "Timestamps(${frameTiming.timestampInMicroseconds( - FramePhase.buildStart, - )}, ${frameTiming.timestampInMicroseconds( - FramePhase.buildFinish, - )}, ${frameTiming.timestampInMicroseconds( - FramePhase.rasterStart, - )}, ${frameTiming.timestampInMicroseconds( - FramePhase.rasterFinish, - )}, ${frameTiming.timestampInMicroseconds( - FramePhase.vsyncStart, - )}, ${frameTiming.timestampInMicroseconds( - FramePhase.rasterFinishWallTime, - )}" - ")\n}\n", - ); - debugPrint("Device refresh rate: $_deviceRefreshRate FPS"); - debugPrint( - "Threshold: $_slowFrameThresholdMs ms\n" - "===============================================================================", - ); - } - } - /// Ends custom ui trace with the screen render data that has been collected for it. /// params: /// [InstabugScreenRenderData] screenRenderData. @@ -398,10 +328,6 @@ class InstabugScreenRenderManager { if (_screenRenderForCustomUiTrace.isActive) { _updateCustomUiData(); } - log( - "$tag: Captured data is saved ", - name: 'andrew', - ); } /// Updates the custom UI trace screen render data with the currently collected diff --git a/lib/src/utils/screen_rendering/instabug_widget_binding_observer.dart b/lib/src/utils/screen_rendering/instabug_widget_binding_observer.dart index a4567a015..58157e9d0 100644 --- a/lib/src/utils/screen_rendering/instabug_widget_binding_observer.dart +++ b/lib/src/utils/screen_rendering/instabug_widget_binding_observer.dart @@ -1,12 +1,9 @@ -import 'dart:developer'; - import 'package:flutter/widgets.dart'; import 'package:instabug_flutter/src/utils/screen_loading/screen_loading_manager.dart'; import 'package:instabug_flutter/src/utils/screen_name_masker.dart'; import 'package:instabug_flutter/src/utils/screen_rendering/instabug_screen_render_manager.dart'; import 'package:meta/meta.dart'; -//todo: remove logs class InstabugWidgetsBindingObserver extends WidgetsBindingObserver { InstabugWidgetsBindingObserver._(); @@ -30,7 +27,6 @@ class InstabugWidgetsBindingObserver extends WidgetsBindingObserver { } void _handleResumedState() { - log('Performing resume actions...', name: 'andrew'); final lastUiTrace = ScreenLoadingManager.I.currentUiTrace; if (lastUiTrace == null) { return; @@ -48,15 +44,12 @@ class InstabugWidgetsBindingObserver extends WidgetsBindingObserver { } void _handlePausedState() { - log('Performing pause actions...', name: 'andrew'); - if (InstabugScreenRenderManager.I.screenRenderEnabled) { InstabugScreenRenderManager.I.stopScreenRenderCollector(); } } void _handleDetachedState() { - log('Performing detached actions...', name: 'andrew'); if (InstabugScreenRenderManager.I.screenRenderEnabled) { InstabugScreenRenderManager.I.stopScreenRenderCollector(); } @@ -64,7 +57,7 @@ class InstabugWidgetsBindingObserver extends WidgetsBindingObserver { } void _handleDefaultState() { - log("handle default state", name: 'andrew'); + // Added for lint warnings } @override From cdfea378046e4967e270f4ec2b446d6c3eb288cd Mon Sep 17 00:00:00 2001 From: Andrew Amin Date: Sun, 13 Jul 2025 23:49:14 +0300 Subject: [PATCH 29/84] chore: add 2.10.5 changes --- .../instabug_widget_binding_observer.dart | 2 +- .../instabug_screen_render_manager_test.dart | 8 +- ...reen_render_manager_test_manual_mocks.dart | 759 ++++++++++++++++++ 3 files changed, 761 insertions(+), 8 deletions(-) create mode 100644 test/utils/screen_render/instabug_screen_render_manager_test_manual_mocks.dart diff --git a/lib/src/utils/screen_rendering/instabug_widget_binding_observer.dart b/lib/src/utils/screen_rendering/instabug_widget_binding_observer.dart index 58157e9d0..c4a4515e3 100644 --- a/lib/src/utils/screen_rendering/instabug_widget_binding_observer.dart +++ b/lib/src/utils/screen_rendering/instabug_widget_binding_observer.dart @@ -23,7 +23,7 @@ class InstabugWidgetsBindingObserver extends WidgetsBindingObserver { if (InstabugScreenRenderManager.I.screenRenderEnabled) { InstabugScreenRenderManager.I.dispose(); } - WidgetsBinding.instance.removeObserver(_instance); + WidgetsBinding.instance?.removeObserver(_instance); } void _handleResumedState() { diff --git a/test/utils/screen_render/instabug_screen_render_manager_test.dart b/test/utils/screen_render/instabug_screen_render_manager_test.dart index 91d2fa916..e3d1ce688 100644 --- a/test/utils/screen_render/instabug_screen_render_manager_test.dart +++ b/test/utils/screen_render/instabug_screen_render_manager_test.dart @@ -1,18 +1,12 @@ -import 'dart:ui' show FrameTiming; - -import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:instabug_flutter/instabug_flutter.dart'; -import 'package:instabug_flutter/src/generated/apm.api.g.dart'; import 'package:instabug_flutter/src/models/instabug_frame_data.dart'; import 'package:instabug_flutter/src/models/instabug_screen_render_data.dart'; import 'package:instabug_flutter/src/utils/screen_rendering/instabug_screen_render_manager.dart'; -import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; -import 'instabug_screen_render_manager_test.mocks.dart'; +import 'instabug_screen_render_manager_test_manual_mocks.dart'; -@GenerateMocks([ApmHostApi, WidgetsBinding, FrameTiming]) void main() { TestWidgetsFlutterBinding.ensureInitialized(); diff --git a/test/utils/screen_render/instabug_screen_render_manager_test_manual_mocks.dart b/test/utils/screen_render/instabug_screen_render_manager_test_manual_mocks.dart new file mode 100644 index 000000000..c09c98d20 --- /dev/null +++ b/test/utils/screen_render/instabug_screen_render_manager_test_manual_mocks.dart @@ -0,0 +1,759 @@ +// Mocks generated by Mockito 5.2.0 from annotations +// in instabug_flutter/example/ios/.symlinks/plugins/instabug_flutter/test/utils/screen_render/instabug_screen_render_manager_test.dart. +// Do not manually edit this file. + +import 'dart:async' as _i9; +import 'dart:developer' as _i13; +import 'dart:ui' as _i4; + +import 'package:flutter/foundation.dart' as _i3; +import 'package:flutter/gestures.dart' as _i6; +import 'package:flutter/rendering.dart' as _i7; +import 'package:flutter/scheduler.dart' as _i11; +import 'package:flutter/services.dart' as _i5; +import 'package:flutter/src/widgets/binding.dart' as _i10; +import 'package:flutter/src/widgets/focus_manager.dart' as _i2; +import 'package:flutter/src/widgets/framework.dart' as _i12; +import 'package:instabug_flutter/src/generated/apm.api.g.dart' as _i8; +import 'package:mockito/mockito.dart' as _i1; + +// ignore_for_file: type=lint +// ignore_for_file: avoid_redundant_argument_values +// ignore_for_file: avoid_setters_without_getters +// ignore_for_file: comment_references +// ignore_for_file: implementation_imports +// ignore_for_file: invalid_use_of_visible_for_testing_member +// ignore_for_file: prefer_const_constructors +// ignore_for_file: unnecessary_parenthesis +// ignore_for_file: camel_case_types + +class _FakeFocusManager_0 extends _i1.Fake implements _i2.FocusManager { + @override + String toString({_i3.DiagnosticLevel? minLevel = _i3.DiagnosticLevel.info}) => + super.toString(); +} + +class _FakeSingletonFlutterWindow_1 extends _i1.Fake + implements _i4.SingletonFlutterWindow {} + +class _FakePlatformDispatcher_2 extends _i1.Fake + implements _i4.PlatformDispatcher {} + +class _FakeHardwareKeyboard_3 extends _i1.Fake implements _i5.HardwareKeyboard { +} + +class _FakeKeyEventManager_4 extends _i1.Fake implements _i5.KeyEventManager {} + +class _FakeBinaryMessenger_5 extends _i1.Fake implements _i5.BinaryMessenger {} + +class _FakeChannelBuffers_6 extends _i1.Fake implements _i4.ChannelBuffers {} + +class _FakeRestorationManager_7 extends _i1.Fake + implements _i5.RestorationManager {} + +class _FakeDuration_8 extends _i1.Fake implements Duration {} + +class _FakePointerRouter_9 extends _i1.Fake implements _i6.PointerRouter {} + +class _FakeGestureArenaManager_10 extends _i1.Fake + implements _i6.GestureArenaManager {} + +class _FakePointerSignalResolver_11 extends _i1.Fake + implements _i6.PointerSignalResolver {} + +class _FakeMouseTracker_12 extends _i1.Fake implements _i7.MouseTracker {} + +class _FakePipelineOwner_13 extends _i1.Fake implements _i7.PipelineOwner {} + +class _FakeRenderView_14 extends _i1.Fake implements _i7.RenderView { + @override + String toString({_i3.DiagnosticLevel? minLevel = _i3.DiagnosticLevel.info}) => + super.toString(); +} + +class _FakeAccessibilityFeatures_15 extends _i1.Fake + implements _i4.AccessibilityFeatures {} + +class _FakeViewConfiguration_16 extends _i1.Fake + implements _i7.ViewConfiguration {} + +class _FakeSemanticsUpdateBuilder_17 extends _i1.Fake + implements _i4.SemanticsUpdateBuilder {} + +/// A class which mocks [ApmHostApi]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockApmHostApi extends _i1.Mock implements _i8.ApmHostApi { + MockApmHostApi() { + _i1.throwOnMissingStub(this); + } + + @override + _i9.Future setEnabled(bool? arg_isEnabled) => + (super.noSuchMethod(Invocation.method(#setEnabled, [arg_isEnabled]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future isEnabled() => + (super.noSuchMethod(Invocation.method(#isEnabled, []), + returnValue: Future.value(false)) as _i9.Future); + @override + _i9.Future setScreenLoadingEnabled(bool? arg_isEnabled) => + (super.noSuchMethod( + Invocation.method(#setScreenLoadingEnabled, [arg_isEnabled]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future isScreenLoadingEnabled() => + (super.noSuchMethod(Invocation.method(#isScreenLoadingEnabled, []), + returnValue: Future.value(false)) as _i9.Future); + @override + _i9.Future setColdAppLaunchEnabled(bool? arg_isEnabled) => + (super.noSuchMethod( + Invocation.method(#setColdAppLaunchEnabled, [arg_isEnabled]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future setAutoUITraceEnabled(bool? arg_isEnabled) => (super + .noSuchMethod(Invocation.method(#setAutoUITraceEnabled, [arg_isEnabled]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future startExecutionTrace(String? arg_id, String? arg_name) => + (super.noSuchMethod( + Invocation.method(#startExecutionTrace, [arg_id, arg_name]), + returnValue: Future.value()) as _i9.Future); + @override + _i9.Future startFlow(String? arg_name) => + (super.noSuchMethod(Invocation.method(#startFlow, [arg_name]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future setFlowAttribute( + String? arg_name, String? arg_key, String? arg_value) => + (super.noSuchMethod( + Invocation.method(#setFlowAttribute, [arg_name, arg_key, arg_value]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future endFlow(String? arg_name) => + (super.noSuchMethod(Invocation.method(#endFlow, [arg_name]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future setExecutionTraceAttribute( + String? arg_id, String? arg_key, String? arg_value) => + (super.noSuchMethod( + Invocation.method( + #setExecutionTraceAttribute, [arg_id, arg_key, arg_value]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future endExecutionTrace(String? arg_id) => + (super.noSuchMethod(Invocation.method(#endExecutionTrace, [arg_id]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future startUITrace(String? arg_name) => + (super.noSuchMethod(Invocation.method(#startUITrace, [arg_name]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future endUITrace() => + (super.noSuchMethod(Invocation.method(#endUITrace, []), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future endAppLaunch() => + (super.noSuchMethod(Invocation.method(#endAppLaunch, []), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future networkLogAndroid(Map? arg_data) => + (super.noSuchMethod(Invocation.method(#networkLogAndroid, [arg_data]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future startCpUiTrace( + String? arg_screenName, int? arg_microTimeStamp, int? arg_traceId) => + (super.noSuchMethod( + Invocation.method(#startCpUiTrace, + [arg_screenName, arg_microTimeStamp, arg_traceId]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future reportScreenLoadingCP(int? arg_startTimeStampMicro, + int? arg_durationMicro, int? arg_uiTraceId) => + (super.noSuchMethod( + Invocation.method(#reportScreenLoadingCP, + [arg_startTimeStampMicro, arg_durationMicro, arg_uiTraceId]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future endScreenLoadingCP( + int? arg_timeStampMicro, int? arg_uiTraceId) => + (super.noSuchMethod( + Invocation.method( + #endScreenLoadingCP, [arg_timeStampMicro, arg_uiTraceId]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future isEndScreenLoadingEnabled() => + (super.noSuchMethod(Invocation.method(#isEndScreenLoadingEnabled, []), + returnValue: Future.value(false)) as _i9.Future); + @override + _i9.Future isScreenRenderEnabled() => + (super.noSuchMethod(Invocation.method(#isScreenRenderEnabled, []), + returnValue: Future.value(false)) as _i9.Future); + @override + _i9.Future deviceRefreshRate() => + (super.noSuchMethod(Invocation.method(#deviceRefreshRate, []), + returnValue: Future.value(0.0)) as _i9.Future); + @override + _i9.Future setScreenRenderEnabled(bool? arg_isEnabled) => (super + .noSuchMethod(Invocation.method(#setScreenRenderEnabled, [arg_isEnabled]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future endScreenRenderForAutoUiTrace( + Map? arg_data) => + (super.noSuchMethod( + Invocation.method(#endScreenRenderForAutoUiTrace, [arg_data]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future endScreenRenderForCustomUiTrace( + Map? arg_data) => + (super.noSuchMethod( + Invocation.method(#endScreenRenderForCustomUiTrace, [arg_data]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); +} + +/// A class which mocks [WidgetsBinding]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockWidgetsBinding extends _i1.Mock implements _i10.WidgetsBinding { + MockWidgetsBinding() { + _i1.throwOnMissingStub(this); + } + + @override + bool get debugBuildingDirtyElements => + (super.noSuchMethod(Invocation.getter(#debugBuildingDirtyElements), + returnValue: false) as bool); + @override + set debugBuildingDirtyElements(bool? _debugBuildingDirtyElements) => + super.noSuchMethod( + Invocation.setter( + #debugBuildingDirtyElements, _debugBuildingDirtyElements), + returnValueForMissingStub: null); + @override + _i2.FocusManager get focusManager => + (super.noSuchMethod(Invocation.getter(#focusManager), + returnValue: _FakeFocusManager_0()) as _i2.FocusManager); + @override + bool get firstFrameRasterized => + (super.noSuchMethod(Invocation.getter(#firstFrameRasterized), + returnValue: false) as bool); + @override + _i9.Future get waitUntilFirstFrameRasterized => + (super.noSuchMethod(Invocation.getter(#waitUntilFirstFrameRasterized), + returnValue: Future.value()) as _i9.Future); + @override + bool get debugDidSendFirstFrameEvent => + (super.noSuchMethod(Invocation.getter(#debugDidSendFirstFrameEvent), + returnValue: false) as bool); + @override + bool get framesEnabled => + (super.noSuchMethod(Invocation.getter(#framesEnabled), returnValue: false) + as bool); + @override + bool get isRootWidgetAttached => + (super.noSuchMethod(Invocation.getter(#isRootWidgetAttached), + returnValue: false) as bool); + @override + _i4.SingletonFlutterWindow get window => + (super.noSuchMethod(Invocation.getter(#window), + returnValue: _FakeSingletonFlutterWindow_1()) + as _i4.SingletonFlutterWindow); + @override + _i4.PlatformDispatcher get platformDispatcher => + (super.noSuchMethod(Invocation.getter(#platformDispatcher), + returnValue: _FakePlatformDispatcher_2()) as _i4.PlatformDispatcher); + @override + bool get locked => + (super.noSuchMethod(Invocation.getter(#locked), returnValue: false) + as bool); + @override + _i5.HardwareKeyboard get keyboard => + (super.noSuchMethod(Invocation.getter(#keyboard), + returnValue: _FakeHardwareKeyboard_3()) as _i5.HardwareKeyboard); + @override + _i5.KeyEventManager get keyEventManager => + (super.noSuchMethod(Invocation.getter(#keyEventManager), + returnValue: _FakeKeyEventManager_4()) as _i5.KeyEventManager); + @override + _i5.BinaryMessenger get defaultBinaryMessenger => + (super.noSuchMethod(Invocation.getter(#defaultBinaryMessenger), + returnValue: _FakeBinaryMessenger_5()) as _i5.BinaryMessenger); + @override + _i4.ChannelBuffers get channelBuffers => + (super.noSuchMethod(Invocation.getter(#channelBuffers), + returnValue: _FakeChannelBuffers_6()) as _i4.ChannelBuffers); + @override + _i5.RestorationManager get restorationManager => + (super.noSuchMethod(Invocation.getter(#restorationManager), + returnValue: _FakeRestorationManager_7()) as _i5.RestorationManager); + @override + _i11.SchedulingStrategy get schedulingStrategy => + (super.noSuchMethod(Invocation.getter(#schedulingStrategy), + returnValue: ({int? priority, _i11.SchedulerBinding? scheduler}) => + false) as _i11.SchedulingStrategy); + @override + set schedulingStrategy(_i11.SchedulingStrategy? _schedulingStrategy) => super + .noSuchMethod(Invocation.setter(#schedulingStrategy, _schedulingStrategy), + returnValueForMissingStub: null); + @override + int get transientCallbackCount => + (super.noSuchMethod(Invocation.getter(#transientCallbackCount), + returnValue: 0) as int); + @override + _i9.Future get endOfFrame => + (super.noSuchMethod(Invocation.getter(#endOfFrame), + returnValue: Future.value()) as _i9.Future); + @override + bool get hasScheduledFrame => + (super.noSuchMethod(Invocation.getter(#hasScheduledFrame), + returnValue: false) as bool); + @override + _i11.SchedulerPhase get schedulerPhase => + (super.noSuchMethod(Invocation.getter(#schedulerPhase), + returnValue: _i11.SchedulerPhase.idle) as _i11.SchedulerPhase); + @override + Duration get currentFrameTimeStamp => + (super.noSuchMethod(Invocation.getter(#currentFrameTimeStamp), + returnValue: _FakeDuration_8()) as Duration); + @override + Duration get currentSystemFrameTimeStamp => + (super.noSuchMethod(Invocation.getter(#currentSystemFrameTimeStamp), + returnValue: _FakeDuration_8()) as Duration); + @override + _i6.PointerRouter get pointerRouter => + (super.noSuchMethod(Invocation.getter(#pointerRouter), + returnValue: _FakePointerRouter_9()) as _i6.PointerRouter); + @override + _i6.GestureArenaManager get gestureArena => (super.noSuchMethod( + Invocation.getter(#gestureArena), + returnValue: _FakeGestureArenaManager_10()) as _i6.GestureArenaManager); + @override + _i6.PointerSignalResolver get pointerSignalResolver => + (super.noSuchMethod(Invocation.getter(#pointerSignalResolver), + returnValue: _FakePointerSignalResolver_11()) + as _i6.PointerSignalResolver); + @override + bool get resamplingEnabled => + (super.noSuchMethod(Invocation.getter(#resamplingEnabled), + returnValue: false) as bool); + @override + set resamplingEnabled(bool? _resamplingEnabled) => super.noSuchMethod( + Invocation.setter(#resamplingEnabled, _resamplingEnabled), + returnValueForMissingStub: null); + @override + Duration get samplingOffset => + (super.noSuchMethod(Invocation.getter(#samplingOffset), + returnValue: _FakeDuration_8()) as Duration); + @override + set samplingOffset(Duration? _samplingOffset) => + super.noSuchMethod(Invocation.setter(#samplingOffset, _samplingOffset), + returnValueForMissingStub: null); + @override + _i7.MouseTracker get mouseTracker => + (super.noSuchMethod(Invocation.getter(#mouseTracker), + returnValue: _FakeMouseTracker_12()) as _i7.MouseTracker); + @override + _i7.PipelineOwner get pipelineOwner => + (super.noSuchMethod(Invocation.getter(#pipelineOwner), + returnValue: _FakePipelineOwner_13()) as _i7.PipelineOwner); + @override + _i7.RenderView get renderView => + (super.noSuchMethod(Invocation.getter(#renderView), + returnValue: _FakeRenderView_14()) as _i7.RenderView); + @override + set renderView(_i7.RenderView? value) => + super.noSuchMethod(Invocation.setter(#renderView, value), + returnValueForMissingStub: null); + @override + bool get sendFramesToEngine => + (super.noSuchMethod(Invocation.getter(#sendFramesToEngine), + returnValue: false) as bool); + @override + _i4.AccessibilityFeatures get accessibilityFeatures => + (super.noSuchMethod(Invocation.getter(#accessibilityFeatures), + returnValue: _FakeAccessibilityFeatures_15()) + as _i4.AccessibilityFeatures); + @override + bool get disableAnimations => + (super.noSuchMethod(Invocation.getter(#disableAnimations), + returnValue: false) as bool); + @override + void initInstances() => + super.noSuchMethod(Invocation.method(#initInstances, []), + returnValueForMissingStub: null); + @override + void initServiceExtensions() => + super.noSuchMethod(Invocation.method(#initServiceExtensions, []), + returnValueForMissingStub: null); + @override + void addObserver(_i10.WidgetsBindingObserver? observer) => + super.noSuchMethod(Invocation.method(#addObserver, [observer]), + returnValueForMissingStub: null); + @override + bool removeObserver(_i10.WidgetsBindingObserver? observer) => + (super.noSuchMethod(Invocation.method(#removeObserver, [observer]), + returnValue: false) as bool); + @override + void handleMetricsChanged() => + super.noSuchMethod(Invocation.method(#handleMetricsChanged, []), + returnValueForMissingStub: null); + @override + void handleTextScaleFactorChanged() => + super.noSuchMethod(Invocation.method(#handleTextScaleFactorChanged, []), + returnValueForMissingStub: null); + @override + void handlePlatformBrightnessChanged() => super.noSuchMethod( + Invocation.method(#handlePlatformBrightnessChanged, []), + returnValueForMissingStub: null); + @override + void handleAccessibilityFeaturesChanged() => super.noSuchMethod( + Invocation.method(#handleAccessibilityFeaturesChanged, []), + returnValueForMissingStub: null); + @override + void handleLocaleChanged() => + super.noSuchMethod(Invocation.method(#handleLocaleChanged, []), + returnValueForMissingStub: null); + @override + void dispatchLocalesChanged(List<_i4.Locale>? locales) => + super.noSuchMethod(Invocation.method(#dispatchLocalesChanged, [locales]), + returnValueForMissingStub: null); + @override + void dispatchAccessibilityFeaturesChanged() => super.noSuchMethod( + Invocation.method(#dispatchAccessibilityFeaturesChanged, []), + returnValueForMissingStub: null); + @override + _i9.Future handlePopRoute() => + (super.noSuchMethod(Invocation.method(#handlePopRoute, []), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future handlePushRoute(String? route) => + (super.noSuchMethod(Invocation.method(#handlePushRoute, [route]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + void handleAppLifecycleStateChanged(_i4.AppLifecycleState? state) => super + .noSuchMethod(Invocation.method(#handleAppLifecycleStateChanged, [state]), + returnValueForMissingStub: null); + @override + void handleMemoryPressure() => + super.noSuchMethod(Invocation.method(#handleMemoryPressure, []), + returnValueForMissingStub: null); + @override + void drawFrame() => super.noSuchMethod(Invocation.method(#drawFrame, []), + returnValueForMissingStub: null); + @override + void scheduleAttachRootWidget(_i12.Widget? rootWidget) => super.noSuchMethod( + Invocation.method(#scheduleAttachRootWidget, [rootWidget]), + returnValueForMissingStub: null); + @override + void attachRootWidget(_i12.Widget? rootWidget) => + super.noSuchMethod(Invocation.method(#attachRootWidget, [rootWidget]), + returnValueForMissingStub: null); + @override + _i9.Future performReassemble() => + (super.noSuchMethod(Invocation.method(#performReassemble, []), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i4.Locale? computePlatformResolvedLocale( + List<_i4.Locale>? supportedLocales) => + (super.noSuchMethod(Invocation.method( + #computePlatformResolvedLocale, [supportedLocales])) as _i4.Locale?); + @override + _i9.Future lockEvents(_i9.Future Function()? callback) => + (super.noSuchMethod(Invocation.method(#lockEvents, [callback]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + void unlocked() => super.noSuchMethod(Invocation.method(#unlocked, []), + returnValueForMissingStub: null); + @override + _i9.Future reassembleApplication() => + (super.noSuchMethod(Invocation.method(#reassembleApplication, []), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + void registerSignalServiceExtension( + {String? name, _i3.AsyncCallback? callback}) => + super.noSuchMethod( + Invocation.method(#registerSignalServiceExtension, [], + {#name: name, #callback: callback}), + returnValueForMissingStub: null); + @override + void registerBoolServiceExtension( + {String? name, + _i3.AsyncValueGetter? getter, + _i3.AsyncValueSetter? setter}) => + super.noSuchMethod( + Invocation.method(#registerBoolServiceExtension, [], + {#name: name, #getter: getter, #setter: setter}), + returnValueForMissingStub: null); + @override + void registerNumericServiceExtension( + {String? name, + _i3.AsyncValueGetter? getter, + _i3.AsyncValueSetter? setter}) => + super.noSuchMethod( + Invocation.method(#registerNumericServiceExtension, [], + {#name: name, #getter: getter, #setter: setter}), + returnValueForMissingStub: null); + @override + void postEvent(String? eventKind, Map? eventData) => + super.noSuchMethod(Invocation.method(#postEvent, [eventKind, eventData]), + returnValueForMissingStub: null); + @override + void registerStringServiceExtension( + {String? name, + _i3.AsyncValueGetter? getter, + _i3.AsyncValueSetter? setter}) => + super.noSuchMethod( + Invocation.method(#registerStringServiceExtension, [], + {#name: name, #getter: getter, #setter: setter}), + returnValueForMissingStub: null); + @override + void registerServiceExtension( + {String? name, _i3.ServiceExtensionCallback? callback}) => + super.noSuchMethod( + Invocation.method(#registerServiceExtension, [], + {#name: name, #callback: callback}), + returnValueForMissingStub: null); + @override + _i5.BinaryMessenger createBinaryMessenger() => + (super.noSuchMethod(Invocation.method(#createBinaryMessenger, []), + returnValue: _FakeBinaryMessenger_5()) as _i5.BinaryMessenger); + @override + _i9.Future handleSystemMessage(Object? systemMessage) => (super + .noSuchMethod(Invocation.method(#handleSystemMessage, [systemMessage]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + void initLicenses() => + super.noSuchMethod(Invocation.method(#initLicenses, []), + returnValueForMissingStub: null); + @override + void evict(String? asset) => + super.noSuchMethod(Invocation.method(#evict, [asset]), + returnValueForMissingStub: null); + @override + void readInitialLifecycleStateFromNativeWindow() => super.noSuchMethod( + Invocation.method(#readInitialLifecycleStateFromNativeWindow, []), + returnValueForMissingStub: null); + @override + _i5.RestorationManager createRestorationManager() => + (super.noSuchMethod(Invocation.method(#createRestorationManager, []), + returnValue: _FakeRestorationManager_7()) as _i5.RestorationManager); + @override + void setSystemUiChangeCallback(_i5.SystemUiChangeCallback? callback) => super + .noSuchMethod(Invocation.method(#setSystemUiChangeCallback, [callback]), + returnValueForMissingStub: null); + @override + void addTimingsCallback(_i4.TimingsCallback? callback) => + super.noSuchMethod(Invocation.method(#addTimingsCallback, [callback]), + returnValueForMissingStub: null); + @override + void removeTimingsCallback(_i4.TimingsCallback? callback) => + super.noSuchMethod(Invocation.method(#removeTimingsCallback, [callback]), + returnValueForMissingStub: null); + @override + _i9.Future scheduleTask( + _i11.TaskCallback? task, _i11.Priority? priority, + {String? debugLabel, _i13.Flow? flow}) => + (super.noSuchMethod( + Invocation.method(#scheduleTask, [task, priority], + {#debugLabel: debugLabel, #flow: flow}), + returnValue: Future.value(null)) as _i9.Future); + @override + bool handleEventLoopCallback() => + (super.noSuchMethod(Invocation.method(#handleEventLoopCallback, []), + returnValue: false) as bool); + @override + int scheduleFrameCallback(_i11.FrameCallback? callback, + {bool? rescheduling = false}) => + (super.noSuchMethod( + Invocation.method(#scheduleFrameCallback, [callback], + {#rescheduling: rescheduling}), + returnValue: 0) as int); + @override + void cancelFrameCallbackWithId(int? id) => + super.noSuchMethod(Invocation.method(#cancelFrameCallbackWithId, [id]), + returnValueForMissingStub: null); + @override + bool debugAssertNoTransientCallbacks(String? reason) => (super.noSuchMethod( + Invocation.method(#debugAssertNoTransientCallbacks, [reason]), + returnValue: false) as bool); + @override + void addPersistentFrameCallback(_i11.FrameCallback? callback) => super + .noSuchMethod(Invocation.method(#addPersistentFrameCallback, [callback]), + returnValueForMissingStub: null); + @override + void addPostFrameCallback(_i11.FrameCallback? callback) => + super.noSuchMethod(Invocation.method(#addPostFrameCallback, [callback]), + returnValueForMissingStub: null); + @override + void ensureFrameCallbacksRegistered() => + super.noSuchMethod(Invocation.method(#ensureFrameCallbacksRegistered, []), + returnValueForMissingStub: null); + @override + void ensureVisualUpdate() => + super.noSuchMethod(Invocation.method(#ensureVisualUpdate, []), + returnValueForMissingStub: null); + @override + void scheduleFrame() => + super.noSuchMethod(Invocation.method(#scheduleFrame, []), + returnValueForMissingStub: null); + @override + void scheduleForcedFrame() => + super.noSuchMethod(Invocation.method(#scheduleForcedFrame, []), + returnValueForMissingStub: null); + @override + void scheduleWarmUpFrame() => + super.noSuchMethod(Invocation.method(#scheduleWarmUpFrame, []), + returnValueForMissingStub: null); + @override + void resetEpoch() => super.noSuchMethod(Invocation.method(#resetEpoch, []), + returnValueForMissingStub: null); + @override + void handleBeginFrame(Duration? rawTimeStamp) => + super.noSuchMethod(Invocation.method(#handleBeginFrame, [rawTimeStamp]), + returnValueForMissingStub: null); + @override + void handleDrawFrame() => + super.noSuchMethod(Invocation.method(#handleDrawFrame, []), + returnValueForMissingStub: null); + @override + void cancelPointer(int? pointer) => + super.noSuchMethod(Invocation.method(#cancelPointer, [pointer]), + returnValueForMissingStub: null); + @override + void handlePointerEvent(_i7.PointerEvent? event) => + super.noSuchMethod(Invocation.method(#handlePointerEvent, [event]), + returnValueForMissingStub: null); + @override + void hitTest(_i7.HitTestResult? result, _i4.Offset? position) => + super.noSuchMethod(Invocation.method(#hitTest, [result, position]), + returnValueForMissingStub: null); + @override + void dispatchEvent( + _i7.PointerEvent? event, _i7.HitTestResult? hitTestResult) => + super.noSuchMethod( + Invocation.method(#dispatchEvent, [event, hitTestResult]), + returnValueForMissingStub: null); + @override + void handleEvent(_i7.PointerEvent? event, _i7.HitTestEntry? entry) => + super.noSuchMethod(Invocation.method(#handleEvent, [event, entry]), + returnValueForMissingStub: null); + @override + void resetGestureBinding() => + super.noSuchMethod(Invocation.method(#resetGestureBinding, []), + returnValueForMissingStub: null); + @override + void initRenderView() => + super.noSuchMethod(Invocation.method(#initRenderView, []), + returnValueForMissingStub: null); + @override + _i7.ViewConfiguration createViewConfiguration() => + (super.noSuchMethod(Invocation.method(#createViewConfiguration, []), + returnValue: _FakeViewConfiguration_16()) as _i7.ViewConfiguration); + @override + void initMouseTracker([_i7.MouseTracker? tracker]) => + super.noSuchMethod(Invocation.method(#initMouseTracker, [tracker]), + returnValueForMissingStub: null); + @override + void setSemanticsEnabled(bool? enabled) => + super.noSuchMethod(Invocation.method(#setSemanticsEnabled, [enabled]), + returnValueForMissingStub: null); + @override + void deferFirstFrame() => + super.noSuchMethod(Invocation.method(#deferFirstFrame, []), + returnValueForMissingStub: null); + @override + void allowFirstFrame() => + super.noSuchMethod(Invocation.method(#allowFirstFrame, []), + returnValueForMissingStub: null); + @override + void resetFirstFrameSent() => + super.noSuchMethod(Invocation.method(#resetFirstFrameSent, []), + returnValueForMissingStub: null); + @override + _i4.SemanticsUpdateBuilder createSemanticsUpdateBuilder() => + (super.noSuchMethod(Invocation.method(#createSemanticsUpdateBuilder, []), + returnValue: _FakeSemanticsUpdateBuilder_17()) + as _i4.SemanticsUpdateBuilder); +} + +/// A class which mocks [FrameTiming]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockFrameTiming extends _i1.Mock implements _i4.FrameTiming { + MockFrameTiming() { + _i1.throwOnMissingStub(this); + } + + @override + Duration get buildDuration => + (super.noSuchMethod(Invocation.getter(#buildDuration), + returnValue: _FakeDuration_8()) as Duration); + @override + Duration get rasterDuration => + (super.noSuchMethod(Invocation.getter(#rasterDuration), + returnValue: _FakeDuration_8()) as Duration); + @override + Duration get vsyncOverhead => + (super.noSuchMethod(Invocation.getter(#vsyncOverhead), + returnValue: _FakeDuration_8()) as Duration); + @override + Duration get totalSpan => (super.noSuchMethod(Invocation.getter(#totalSpan), + returnValue: _FakeDuration_8()) as Duration); + @override + int get layerCacheCount => + (super.noSuchMethod(Invocation.getter(#layerCacheCount), returnValue: 0) + as int); + @override + int get layerCacheBytes => + (super.noSuchMethod(Invocation.getter(#layerCacheBytes), returnValue: 0) + as int); + @override + double get layerCacheMegabytes => + (super.noSuchMethod(Invocation.getter(#layerCacheMegabytes), + returnValue: 0.0) as double); + @override + int get pictureCacheCount => + (super.noSuchMethod(Invocation.getter(#pictureCacheCount), returnValue: 0) + as int); + @override + int get pictureCacheBytes => + (super.noSuchMethod(Invocation.getter(#pictureCacheBytes), returnValue: 0) + as int); + @override + double get pictureCacheMegabytes => + (super.noSuchMethod(Invocation.getter(#pictureCacheMegabytes), + returnValue: 0.0) as double); + @override + int get frameNumber => + (super.noSuchMethod(Invocation.getter(#frameNumber), returnValue: 0) + as int); + @override + int timestampInMicroseconds(_i4.FramePhase? phase) => + (super.noSuchMethod(Invocation.method(#timestampInMicroseconds, [phase]), + returnValue: 0) as int); +} From 79d152c897c80180b06dceeb8c65187630340c1c Mon Sep 17 00:00:00 2001 From: Andrew Amin Date: Mon, 14 Jul 2025 00:03:25 +0300 Subject: [PATCH 30/84] chore: add 2.10.5 changes --- .../screen_rendering/instabug_widget_binding_observer.dart | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/src/utils/screen_rendering/instabug_widget_binding_observer.dart b/lib/src/utils/screen_rendering/instabug_widget_binding_observer.dart index c4a4515e3..9f11925e4 100644 --- a/lib/src/utils/screen_rendering/instabug_widget_binding_observer.dart +++ b/lib/src/utils/screen_rendering/instabug_widget_binding_observer.dart @@ -23,6 +23,8 @@ class InstabugWidgetsBindingObserver extends WidgetsBindingObserver { if (InstabugScreenRenderManager.I.screenRenderEnabled) { InstabugScreenRenderManager.I.dispose(); } + // For Flutter 2.10.5 version + // ignore: invalid_null_aware_operator WidgetsBinding.instance?.removeObserver(_instance); } From 4cdf34187bda438e43d1abfbc6433926dfcd8a9d Mon Sep 17 00:00:00 2001 From: Ahmed alaa Date: Mon, 14 Jul 2025 12:44:32 +0300 Subject: [PATCH 31/84] fix: flutter format --- .../instabug_screen_render_manager_test_manual_mocks.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/utils/screen_render/instabug_screen_render_manager_test_manual_mocks.dart b/test/utils/screen_render/instabug_screen_render_manager_test_manual_mocks.dart index c09c98d20..4e363eb75 100644 --- a/test/utils/screen_render/instabug_screen_render_manager_test_manual_mocks.dart +++ b/test/utils/screen_render/instabug_screen_render_manager_test_manual_mocks.dart @@ -39,8 +39,8 @@ class _FakeSingletonFlutterWindow_1 extends _i1.Fake class _FakePlatformDispatcher_2 extends _i1.Fake implements _i4.PlatformDispatcher {} -class _FakeHardwareKeyboard_3 extends _i1.Fake implements _i5.HardwareKeyboard { -} +class _FakeHardwareKeyboard_3 extends _i1.Fake + implements _i5.HardwareKeyboard {} class _FakeKeyEventManager_4 extends _i1.Fake implements _i5.KeyEventManager {} From cd807c4372c8661aa2ccc54f6af2bdd50a841936 Mon Sep 17 00:00:00 2001 From: AyaMahmoud148 Date: Mon, 14 Jul 2025 13:59:26 +0300 Subject: [PATCH 32/84] fix: resolve comments --- .../instabug/flutter/modules/InstabugApi.java | 36 +++-- .../com/instabug/flutter/InstabugApiTest.java | 17 ++- example/ios/InstabugTests/InstabugApiTests.m | 2 +- example/pubspec.yaml | 1 - ios/Classes/Modules/InstabugApi.m | 131 ++++++++++++------ 5 files changed, 114 insertions(+), 73 deletions(-) diff --git a/android/src/main/java/com/instabug/flutter/modules/InstabugApi.java b/android/src/main/java/com/instabug/flutter/modules/InstabugApi.java index 12286decb..f81cf3cc5 100644 --- a/android/src/main/java/com/instabug/flutter/modules/InstabugApi.java +++ b/android/src/main/java/com/instabug/flutter/modules/InstabugApi.java @@ -638,29 +638,27 @@ private void setFontIfPresent(Map themeConfig, com.instabug.libr } private Typeface getTypeface(Map map, String fileKey, String assetKey) { + String fontName = null; + + if (assetKey != null && map.containsKey(assetKey) && map.get(assetKey) != null) { + fontName = (String) map.get(assetKey); + } else if (fileKey != null && map.containsKey(fileKey) && map.get(fileKey) != null) { + fontName = (String) map.get(fileKey); + } + + if (fontName == null) { + return Typeface.DEFAULT; + } + try { - String fontName = null; - - if (assetKey != null && map.containsKey(assetKey) && map.get(assetKey) != null) { - fontName = (String) map.get(assetKey); - } else if (fileKey != null && map.containsKey(fileKey) && map.get(fileKey) != null) { - fontName = (String) map.get(fileKey); - } - - if (fontName == null) { - return Typeface.DEFAULT; - } - - + String assetPath = "fonts/" + fontName; + return Typeface.createFromAsset(context.getAssets(), assetPath); + } catch (Exception e) { try { - String assetPath = "fonts/" + fontName; - return Typeface.createFromAsset(context.getAssets(), assetPath); - } catch (Exception e) { return Typeface.create(fontName, Typeface.NORMAL); + } catch (Exception e2) { + return Typeface.DEFAULT; } - - } catch (Exception e) { - return Typeface.DEFAULT; } } diff --git a/android/src/test/java/com/instabug/flutter/InstabugApiTest.java b/android/src/test/java/com/instabug/flutter/InstabugApiTest.java index 755a9d068..158b67499 100644 --- a/android/src/test/java/com/instabug/flutter/InstabugApiTest.java +++ b/android/src/test/java/com/instabug/flutter/InstabugApiTest.java @@ -692,21 +692,20 @@ public void testSetThemeWithAllProperties() { when(mock.build()).thenReturn(mock(com.instabug.library.model.IBGTheme.class)); }); - api.setTheme(themeConfig); + api.setTheme(themeConfig); - com.instabug.library.model.IBGTheme.Builder builder = mThemeBuilder.constructed().get(0); - + com.instabug.library.model.IBGTheme.Builder builder = mThemeBuilder.constructed().get(0); + verify(builder).setPrimaryColor(anyInt()); verify(builder).setBackgroundColor(anyInt()); verify(builder).setTitleTextColor(anyInt()); verify(builder).setPrimaryTextColor(anyInt()); verify(builder).setSecondaryTextColor(anyInt()); - - verify(builder).setPrimaryTextStyle(Typeface.BOLD); - verify(builder).setSecondaryTextStyle(Typeface.ITALIC); - verify(builder).setCtaTextStyle(Typeface.BOLD_ITALIC); - - mInstabug.verify(() -> Instabug.setTheme(any(com.instabug.library.model.IBGTheme.class))); + verify(builder).setPrimaryTextStyle(Typeface.BOLD); + verify(builder).setSecondaryTextStyle(Typeface.ITALIC); + verify(builder).setCtaTextStyle(Typeface.BOLD_ITALIC); + + mInstabug.verify(() -> Instabug.setTheme(any(com.instabug.library.model.IBGTheme.class))); } diff --git a/example/ios/InstabugTests/InstabugApiTests.m b/example/ios/InstabugTests/InstabugApiTests.m index d778f830e..176e092a3 100644 --- a/example/ios/InstabugTests/InstabugApiTests.m +++ b/example/ios/InstabugTests/InstabugApiTests.m @@ -636,7 +636,7 @@ - (void)testSetThemeWithAllProperties { [self.api setThemeThemeConfig:themeConfig error:&error]; - OCMVerify([self.mInstabug setTheme:OCMArg.any]); + OCMVerify([self.mInstabug setTheme:[OCMArg isNotNil]]); } @end diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 4e2cd44b0..dfd49f2aa 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -52,7 +52,6 @@ flutter: # To add assets to your application, add an assets section, like this: # assets: # - assets/fonts/ - # assets: # - images/a_dot_burr.jpeg # - images/a_dot_ham.jpeg diff --git a/ios/Classes/Modules/InstabugApi.m b/ios/Classes/Modules/InstabugApi.m index fce1dbc2b..01b271987 100644 --- a/ios/Classes/Modules/InstabugApi.m +++ b/ios/Classes/Modules/InstabugApi.m @@ -443,55 +443,100 @@ - (void)setFontIfPresent:(NSString *)fontPath forTheme:(IBGTheme *)theme type:(N _registeredFonts = [NSMutableSet set]; } - UIFont *font = [UIFont fontWithName:fontPath size:UIFont.systemFontSize]; - - if (!font && ![_registeredFonts containsObject:fontPath]) { - NSString *fontFileName = [fontPath stringByDeletingPathExtension]; - NSArray *fontExtensions = @[@"ttf", @"otf", @"woff", @"woff2"]; - NSString *fontFilePath = nil; - - for (NSString *extension in fontExtensions) { - fontFilePath = [[NSBundle mainBundle] pathForResource:fontFileName ofType:extension]; - if (fontFilePath) break; + // Check if font is already registered + if ([_registeredFonts containsObject:fontPath]) { + UIFont *font = [UIFont fontWithName:fontPath size:UIFont.systemFontSize]; + if (font) { + [self setFont:font forTheme:theme type:type]; } + return; + } - if (fontFilePath) { - NSData *fontData = [NSData dataWithContentsOfFile:fontFilePath]; - if (fontData) { - CGDataProviderRef provider = CGDataProviderCreateWithCFData((__bridge CFDataRef)fontData); - if (provider) { - CGFontRef cgFont = CGFontCreateWithDataProvider(provider); - if (cgFont) { - CFErrorRef error = NULL; - if (CTFontManagerRegisterGraphicsFont(cgFont, &error)) { - NSString *postScriptName = (__bridge_transfer NSString *)CGFontCopyPostScriptName(cgFont); - if (postScriptName) { - font = [UIFont fontWithName:postScriptName size:UIFont.systemFontSize]; - [_registeredFonts addObject:fontPath]; - } - } else if (error) { - CFStringRef desc = CFErrorCopyDescription(error); - CFRelease(desc); - CFRelease(error); - } - CGFontRelease(cgFont); - } - CGDataProviderRelease(provider); - } - } - } - } else if (!font && [_registeredFonts containsObject:fontPath]) { - font = [UIFont fontWithName:fontPath size:UIFont.systemFontSize]; + // Try to load font from system fonts first + UIFont *font = [UIFont fontWithName:fontPath size:UIFont.systemFontSize]; + if (font) { + [_registeredFonts addObject:fontPath]; + [self setFont:font forTheme:theme type:type]; + return; } + // Try to load font from bundle + font = [self loadFontFromPath:fontPath]; if (font) { - if ([type isEqualToString:@"primary"]) { - theme.primaryTextFont = font; - } else if ([type isEqualToString:@"secondary"]) { - theme.secondaryTextFont = font; - } else if ([type isEqualToString:@"cta"]) { - theme.callToActionTextFont = font; + [_registeredFonts addObject:fontPath]; + [self setFont:font forTheme:theme type:type]; + } +} + +- (UIFont *)loadFontFromPath:(NSString *)fontPath { + NSString *fontFileName = [fontPath stringByDeletingPathExtension]; + NSArray *fontExtensions = @[@"ttf", @"otf", @"woff", @"woff2"]; + + // Find font file in bundle + NSString *fontFilePath = nil; + for (NSString *extension in fontExtensions) { + fontFilePath = [[NSBundle mainBundle] pathForResource:fontFileName ofType:extension]; + if (fontFilePath) break; + } + + if (!fontFilePath) { + return nil; + } + + // Load font data + NSData *fontData = [NSData dataWithContentsOfFile:fontFilePath]; + if (!fontData) { + return nil; + } + + // Create data provider + CGDataProviderRef provider = CGDataProviderCreateWithCFData((__bridge CFDataRef)fontData); + if (!provider) { + return nil; + } + + // Create CG font + CGFontRef cgFont = CGFontCreateWithDataProvider(provider); + CGDataProviderRelease(provider); + + if (!cgFont) { + return nil; + } + + // Register font + CFErrorRef error = NULL; + BOOL registered = CTFontManagerRegisterGraphicsFont(cgFont, &error); + + if (!registered) { + if (error) { + CFStringRef description = CFErrorCopyDescription(error); + CFRelease(description); + CFRelease(error); } + CGFontRelease(cgFont); + return nil; + } + + // Get PostScript name and create UIFont + NSString *postScriptName = (__bridge_transfer NSString *)CGFontCopyPostScriptName(cgFont); + CGFontRelease(cgFont); + + if (!postScriptName) { + return nil; + } + + return [UIFont fontWithName:postScriptName size:UIFont.systemFontSize]; +} + +- (void)setFont:(UIFont *)font forTheme:(IBGTheme *)theme type:(NSString *)type { + if (!font || !theme || !type) return; + + if ([type isEqualToString:@"primary"]) { + theme.primaryTextFont = font; + } else if ([type isEqualToString:@"secondary"]) { + theme.secondaryTextFont = font; + } else if ([type isEqualToString:@"cta"]) { + theme.callToActionTextFont = font; } } From b8d6815d0128f96bc707406eeced362403f71892 Mon Sep 17 00:00:00 2001 From: Andrew Amin Date: Wed, 16 Jul 2025 17:12:33 +0300 Subject: [PATCH 33/84] chore: apply pr comments & update the captured timestamp to be since epoch. --- .../com/instabug/flutter/modules/ApmApi.java | 146 +++++++++--------- .../instabug_screen_render_manager.dart | 24 ++- 2 files changed, 95 insertions(+), 75 deletions(-) diff --git a/android/src/main/java/com/instabug/flutter/modules/ApmApi.java b/android/src/main/java/com/instabug/flutter/modules/ApmApi.java index 7e4b58bd5..61d0fca68 100644 --- a/android/src/main/java/com/instabug/flutter/modules/ApmApi.java +++ b/android/src/main/java/com/instabug/flutter/modules/ApmApi.java @@ -110,42 +110,40 @@ public void setAutoUITraceEnabled(@NonNull Boolean isEnabled) { */ @Override public void startExecutionTrace(@NonNull String id, @NonNull String name, ApmPigeon.Result result) { - ThreadManager.runOnBackground( - new Runnable() { - @Override - public void run() { - try { - ExecutionTrace trace = APM.startExecutionTrace(name); - if (trace != null) { - traces.put(id, trace); - - ThreadManager.runOnMainThread(new Runnable() { - @Override - public void run() { - result.success(id); - } - }); - } else { - ThreadManager.runOnMainThread(new Runnable() { - @Override - public void run() { - result.success(null); - } - }); + ThreadManager.runOnBackground(new Runnable() { + @Override + public void run() { + try { + ExecutionTrace trace = APM.startExecutionTrace(name); + if (trace != null) { + traces.put(id, trace); + + ThreadManager.runOnMainThread(new Runnable() { + @Override + public void run() { + result.success(id); } - } catch (Exception e) { - e.printStackTrace(); - - ThreadManager.runOnMainThread(new Runnable() { - @Override - public void run() { - result.success(null); - } - }); - } + }); + } else { + ThreadManager.runOnMainThread(new Runnable() { + @Override + public void run() { + result.success(null); + } + }); } + } catch (Exception e) { + e.printStackTrace(); + + ThreadManager.runOnMainThread(new Runnable() { + @Override + public void run() { + result.success(null); + } + }); } - ); + } + }); } /** @@ -356,13 +354,9 @@ public void networkLogAndroid(@NonNull Map data) { } - APMCPNetworkLog.W3CExternalTraceAttributes w3cExternalTraceAttributes = - null; + APMCPNetworkLog.W3CExternalTraceAttributes w3cExternalTraceAttributes = null; if (isW3cHeaderFound != null) { - w3cExternalTraceAttributes = new APMCPNetworkLog.W3CExternalTraceAttributes( - isW3cHeaderFound, partialId == null ? null : partialId.longValue(), - networkStartTimeInSeconds == null ? null : networkStartTimeInSeconds.longValue(), - w3CGeneratedHeader, w3CCaughtHeader + w3cExternalTraceAttributes = new APMCPNetworkLog.W3CExternalTraceAttributes(isW3cHeaderFound, partialId == null ? null : partialId.longValue(), networkStartTimeInSeconds == null ? null : networkStartTimeInSeconds.longValue(), w3CGeneratedHeader, w3CCaughtHeader ); } @@ -520,49 +514,57 @@ public void deviceRefreshRate(@NonNull ApmPigeon.Result result) { @Override public void endScreenRenderForAutoUiTrace(@NonNull Map data) { - final long traceId = ((Number) data.get("traceId")).longValue(); - final long slowFramesTotalDuration = ((Number) data.get("slowFramesTotalDuration")).longValue(); - final long frozenFramesTotalDuration = ((Number) data.get("frozenFramesTotalDuration")).longValue(); - final long endTime = ((Number) data.get("endTime")).longValue(); - - // Don't cast directly to ArrayList> because the inner lists may actually be ArrayList - // Instead, cast to List> and convert each value to long explicitly - List> rawFrames = (List>) data.get("frameData"); - ArrayList frames = new ArrayList<>(); - if (rawFrames != null) { - for (List frameValues : rawFrames) { - // Defensive: check size and nulls - if (frameValues != null && frameValues.size() >= 2) { - long frameStart = frameValues.get(0).longValue(); - long frameDuration = frameValues.get(1).longValue(); - frames.add(new IBGFrameData(frameStart, frameDuration)); + try { + final long traceId = ((Number) data.get("traceId")).longValue(); + final long slowFramesTotalDuration = ((Number) data.get("slowFramesTotalDuration")).longValue(); + final long frozenFramesTotalDuration = ((Number) data.get("frozenFramesTotalDuration")).longValue(); + final long endTime = ((Number) data.get("endTime")).longValue(); + + // Don't cast directly to ArrayList> because the inner lists may actually be ArrayList + // Instead, cast to List> and convert each value to long explicitly + List> rawFrames = (List>) data.get("frameData"); + ArrayList frames = new ArrayList<>(); + if (rawFrames != null) { + for (List frameValues : rawFrames) { + // Defensive: check size and nulls + if (frameValues != null && frameValues.size() >= 2) { + long frameStart = frameValues.get(0).longValue(); + long frameDuration = frameValues.get(1).longValue(); + frames.add(new IBGFrameData(frameStart, frameDuration)); + } } } + IBGScreenRenderingData screenRenderingData = new IBGScreenRenderingData(traceId, slowFramesTotalDuration, frozenFramesTotalDuration, frames); + InternalAPM._endAutoUiTraceWithScreenRendering(screenRenderingData, endTime); + } catch (Exception e) { + e.printStackTrace(); } - IBGScreenRenderingData screenRenderingData = new IBGScreenRenderingData(traceId, slowFramesTotalDuration, frozenFramesTotalDuration, frames); - InternalAPM._endAutoUiTraceWithScreenRendering(screenRenderingData, endTime); } @Override public void endScreenRenderForCustomUiTrace(@NonNull Map data) { - final long traceId = ((Number) data.get("traceId")).longValue(); - final long slowFramesTotalDuration = ((Number) data.get("slowFramesTotalDuration")).longValue(); - final long frozenFramesTotalDuration = ((Number) data.get("frozenFramesTotalDuration")).longValue(); - - List> rawFrames = (List>) data.get("frameData"); - ArrayList frames = new ArrayList<>(); - if (rawFrames != null) { - for (List frameValues : rawFrames) { - // Defensive: check size and nulls - if (frameValues != null && frameValues.size() >= 2) { - long frameStart = frameValues.get(0).longValue(); - long frameDuration = frameValues.get(1).longValue(); - frames.add(new IBGFrameData(frameStart, frameDuration)); + try { + final long traceId = ((Number) data.get("traceId")).longValue(); + final long slowFramesTotalDuration = ((Number) data.get("slowFramesTotalDuration")).longValue(); + final long frozenFramesTotalDuration = ((Number) data.get("frozenFramesTotalDuration")).longValue(); + + List> rawFrames = (List>) data.get("frameData"); + ArrayList frames = new ArrayList<>(); + if (rawFrames != null) { + for (List frameValues : rawFrames) { + // Defensive: check size and nulls + if (frameValues != null && frameValues.size() >= 2) { + long frameStart = frameValues.get(0).longValue(); + long frameDuration = frameValues.get(1).longValue(); + frames.add(new IBGFrameData(frameStart, frameDuration)); + } } } + IBGScreenRenderingData screenRenderingData = new IBGScreenRenderingData(traceId, slowFramesTotalDuration, frozenFramesTotalDuration, frames); + InternalAPM._endCustomUiTraceWithScreenRenderingCP(screenRenderingData); + } catch (Exception e) { + e.printStackTrace(); } - IBGScreenRenderingData screenRenderingData = new IBGScreenRenderingData(traceId, slowFramesTotalDuration, frozenFramesTotalDuration, frames); - InternalAPM._endCustomUiTraceWithScreenRenderingCP(screenRenderingData); } } diff --git a/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart b/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart index 546018ccc..a68ff2835 100644 --- a/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart +++ b/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart @@ -28,6 +28,7 @@ class InstabugScreenRenderManager { int _frozenFramesTotalDurationMs = 0; bool _isTimingsListenerAttached = false; bool screenRenderEnabled = false; + int? _epochOffset; final List _delayedFrames = []; @@ -95,17 +96,23 @@ class InstabugScreenRenderManager { if (_isUiDelayed) { _onDelayedFrameDetected( - frameTiming.timestampInMicroseconds(FramePhase.buildStart), + _getMicrosecondsSinceEpoch( + frameTiming.timestampInMicroseconds(FramePhase.buildStart), + ), _buildTime, ); } else if (_isRasterDelayed) { _onDelayedFrameDetected( - frameTiming.timestampInMicroseconds(FramePhase.rasterStart), + _getMicrosecondsSinceEpoch( + frameTiming.timestampInMicroseconds(FramePhase.rasterStart), + ), _rasterTime, ); } else if (_isTotalTimeLarge) { _onDelayedFrameDetected( - frameTiming.timestampInMicroseconds(FramePhase.vsyncStart), + _getMicrosecondsSinceEpoch( + frameTiming.timestampInMicroseconds(FramePhase.vsyncStart), + ), _totalTime, ); } @@ -243,6 +250,9 @@ class InstabugScreenRenderManager { /// Initialize the static variables Future _initStaticValues() async { _timingsCallback = (timings) { + // 1. Establish the offset on the first available timing. + _epochOffset ??= _getEpochOffset(timings.first); + for (final frameTiming in timings) { analyzeFrameTiming(frameTiming); } @@ -253,6 +263,11 @@ class InstabugScreenRenderManager { _screenRenderForCustomUiTrace = InstabugScreenRenderData(frameData: []); } + int _getEpochOffset(FrameTiming firstPatchedFrameTiming) { + return DateTime.now().microsecondsSinceEpoch - + firstPatchedFrameTiming.timestampInMicroseconds(FramePhase.vsyncStart); + } + /// Add a frame observer by calling [WidgetsBinding.instance.addTimingsCallback] void _initFrameTimings() { if (_isTimingsListenerAttached) { @@ -369,6 +384,9 @@ class InstabugScreenRenderManager { ); } + int _getMicrosecondsSinceEpoch(int timeInMicroseconds) => + timeInMicroseconds + (_epochOffset ?? 0); + /// --------------------------- testing helper methods --------------------- @visibleForTesting From c1d7ff5ff0e670fb92d1c0d1999e4ce60186dcfc Mon Sep 17 00:00:00 2001 From: Ahmed alaa Date: Thu, 17 Jul 2025 12:35:18 +0300 Subject: [PATCH 34/84] fix: dart format --- .../instabug_screen_render_manager_test_manual_mocks.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/utils/screen_render/instabug_screen_render_manager_test_manual_mocks.dart b/test/utils/screen_render/instabug_screen_render_manager_test_manual_mocks.dart index c09c98d20..4e363eb75 100644 --- a/test/utils/screen_render/instabug_screen_render_manager_test_manual_mocks.dart +++ b/test/utils/screen_render/instabug_screen_render_manager_test_manual_mocks.dart @@ -39,8 +39,8 @@ class _FakeSingletonFlutterWindow_1 extends _i1.Fake class _FakePlatformDispatcher_2 extends _i1.Fake implements _i4.PlatformDispatcher {} -class _FakeHardwareKeyboard_3 extends _i1.Fake implements _i5.HardwareKeyboard { -} +class _FakeHardwareKeyboard_3 extends _i1.Fake + implements _i5.HardwareKeyboard {} class _FakeKeyEventManager_4 extends _i1.Fake implements _i5.KeyEventManager {} From db97a53ed167d493ab6cd7c7e77db75bd6517e91 Mon Sep 17 00:00:00 2001 From: Andrew Amin Date: Thu, 17 Jul 2025 16:07:09 +0300 Subject: [PATCH 35/84] chore: update logic in the sample app --- .../lib/src/screens/screen_render_page.dart | 34 +++++++++---------- .../instabug_screen_render_manager.dart | 3 +- .../instabug_screen_render_manager_test.dart | 22 ++++++------ 3 files changed, 30 insertions(+), 29 deletions(-) diff --git a/example/lib/src/screens/screen_render_page.dart b/example/lib/src/screens/screen_render_page.dart index 535bd614d..6c5ee315c 100644 --- a/example/lib/src/screens/screen_render_page.dart +++ b/example/lib/src/screens/screen_render_page.dart @@ -1,9 +1,14 @@ part of '../../main.dart'; -class ScreenRenderPage extends StatelessWidget { +class ScreenRenderPage extends StatefulWidget { const ScreenRenderPage({Key? key}) : super(key: key); static const String screenName = "/screenRenderPageRoute"; + @override + State createState() => _ScreenRenderPageState(); +} + +class _ScreenRenderPageState extends State { @override Widget build(BuildContext context) { return Page(title: 'Screen Render', children: [ @@ -16,11 +21,11 @@ class ScreenRenderPage extends StatelessWidget { SizedBox.fromSize(size: const Size.fromHeight(16.0)), InstabugButton( text: 'Trigger Slow Frame', - onPressed: () => _simulateHeavyComputationForSlowFrames(), + onPressed: () => _simulateHeavyComputation(200), ), InstabugButton( text: 'Trigger Frozen Frame', - onPressed: () => _simulateHeavyComputationForFrozenFrames(), + onPressed: () => _simulateHeavyComputation(1000), ), InstabugButton( text: 'Monitored Complex Page', @@ -42,19 +47,14 @@ class ScreenRenderPage extends StatelessWidget { } // Simulates a computationally expensive task - void _simulateHeavyComputationForSlowFrames() { - Random random = Random(); - for (int i = 0; i < 1000000; i++) { - random.nextInt(100) * random.nextInt(100); - } - } - - _simulateHeavyComputationForFrozenFrames() { - final startTime = DateTime.now(); - const pauseTime = 1000; - // Block the UI thread for ~1000ms - while (DateTime.now().difference(startTime).inMilliseconds <= pauseTime) { - // Busy waiting - } + _simulateHeavyComputation(int delayInMilliseconds) { + setState(() { + final startTime = DateTime.now(); + final pauseTime = delayInMilliseconds; + // Block the UI thread for ~delayInMilliseconds + while (DateTime.now().difference(startTime).inMilliseconds <= pauseTime) { + // Busy waiting + } + }); } } diff --git a/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart b/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart index a68ff2835..6517112e3 100644 --- a/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart +++ b/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart @@ -250,7 +250,7 @@ class InstabugScreenRenderManager { /// Initialize the static variables Future _initStaticValues() async { _timingsCallback = (timings) { - // 1. Establish the offset on the first available timing. + // Establish the offset on the first available timing. _epochOffset ??= _getEpochOffset(timings.first); for (final frameTiming in timings) { @@ -384,6 +384,7 @@ class InstabugScreenRenderManager { ); } + /// @nodoc int _getMicrosecondsSinceEpoch(int timeInMicroseconds) => timeInMicroseconds + (_epochOffset ?? 0); diff --git a/test/utils/screen_render/instabug_screen_render_manager_test.dart b/test/utils/screen_render/instabug_screen_render_manager_test.dart index e3d1ce688..15a0f439f 100644 --- a/test/utils/screen_render/instabug_screen_render_manager_test.dart +++ b/test/utils/screen_render/instabug_screen_render_manager_test.dart @@ -260,7 +260,7 @@ void main() { }); test('should not save data if no custom UI trace is started', () { - final frameTestdata = InstabugScreenRenderData( + final frameTestData = InstabugScreenRenderData( traceId: 123, frameData: [ InstabugFrameData(10000, 200), @@ -270,18 +270,18 @@ void main() { slowFramesTotalDurationMicro: 200, ); - manager.setFrameData(frameTestdata); + manager.setFrameData(frameTestData); manager.endScreenRenderCollectorForCustomUiTrace(); expect(manager.screenRenderForCustomUiTrace.isActive, false); - expect(manager.screenRenderForCustomUiTrace == frameTestdata, false); + expect(manager.screenRenderForCustomUiTrace == frameTestData, false); }); test( 'should save data to screenRenderForCustomUiTrace if custom UI trace is started', () { - final frameTestdata = InstabugScreenRenderData( + final frameTestData = InstabugScreenRenderData( traceId: 123, frameData: [ InstabugFrameData(10000, 200), @@ -292,11 +292,11 @@ void main() { ); manager.startScreenRenderCollectorForTraceId( - frameTestdata.traceId, + frameTestData.traceId, UiTraceType.custom, ); - manager.setFrameData(frameTestdata); + manager.setFrameData(frameTestData); manager.endScreenRenderCollectorForCustomUiTrace(); }); @@ -352,7 +352,7 @@ void main() { expect( manager.screenRenderForAutoUiTrace.slowFramesTotalDurationMicro, buildDuration * 1000, - ); // * 1000 to convert from milli to micro + ); // * 1000 to convert from milliseconds to microseconds expect( manager.screenRenderForAutoUiTrace.frozenFramesTotalDurationMicro, 0, @@ -372,7 +372,7 @@ void main() { expect( manager.screenRenderForAutoUiTrace.slowFramesTotalDurationMicro, rasterDuration * 1000, - ); // * 1000 to convert from milli to micro + ); // * 1000 to convert from milliseconds to microseconds expect( manager.screenRenderForAutoUiTrace.frozenFramesTotalDurationMicro, 0, @@ -393,7 +393,7 @@ void main() { expect( manager.screenRenderForAutoUiTrace.frozenFramesTotalDurationMicro, buildDuration * 1000, - ); // * 1000 to convert from milli to micro + ); // * 1000 to convert from milliseconds to microseconds expect( manager.screenRenderForAutoUiTrace.slowFramesTotalDurationMicro, 0, @@ -414,7 +414,7 @@ void main() { expect( manager.screenRenderForAutoUiTrace.frozenFramesTotalDurationMicro, rasterBuild * 1000, - ); // * 1000 to convert from milli to micro + ); // * 1000 to convert from milliseconds to microseconds expect( manager.screenRenderForAutoUiTrace.slowFramesTotalDurationMicro, 0, @@ -433,7 +433,7 @@ void main() { expect( manager.screenRenderForAutoUiTrace.frozenFramesTotalDurationMicro, 0, - ); // * 1000 to convert from milli to micro + ); // * 1000 to convert from milliseconds to microseconds expect( manager.screenRenderForAutoUiTrace.slowFramesTotalDurationMicro, 0, From 04b5972c8847fa7ba1f4df27b54ed9bf591e6c0d Mon Sep 17 00:00:00 2001 From: Ahmed alaa Date: Thu, 17 Jul 2025 16:25:52 +0300 Subject: [PATCH 36/84] fix: dart format --- .../instabug_screen_render_manager_test_manual_mocks.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/utils/screen_render/instabug_screen_render_manager_test_manual_mocks.dart b/test/utils/screen_render/instabug_screen_render_manager_test_manual_mocks.dart index c09c98d20..4e363eb75 100644 --- a/test/utils/screen_render/instabug_screen_render_manager_test_manual_mocks.dart +++ b/test/utils/screen_render/instabug_screen_render_manager_test_manual_mocks.dart @@ -39,8 +39,8 @@ class _FakeSingletonFlutterWindow_1 extends _i1.Fake class _FakePlatformDispatcher_2 extends _i1.Fake implements _i4.PlatformDispatcher {} -class _FakeHardwareKeyboard_3 extends _i1.Fake implements _i5.HardwareKeyboard { -} +class _FakeHardwareKeyboard_3 extends _i1.Fake + implements _i5.HardwareKeyboard {} class _FakeKeyEventManager_4 extends _i1.Fake implements _i5.KeyEventManager {} From d84e96f66b48654381d6df234342e5bbb6743abc Mon Sep 17 00:00:00 2001 From: Andrew Amin Date: Mon, 28 Jul 2025 13:23:42 +0300 Subject: [PATCH 37/84] chore: update capture screen rendering logic --- android/build.gradle | 2 +- example/pubspec.lock | 2 +- .../screen_loading_manager.dart | 4 -- .../instabug_screen_render_manager.dart | 42 +++++++++++++------ .../instabug_widget_binding_observer.dart | 9 ++-- .../screen_loading_manager_test.dart | 19 --------- 6 files changed, 34 insertions(+), 44 deletions(-) diff --git a/android/build.gradle b/android/build.gradle index 59335cf53..3f5817b8c 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -52,7 +52,7 @@ android { } dependencies { - api 'com.instabug.library:instabug:15.0.0.6969715-SNAPSHOT' + api 'com.instabug.library:instabug:15.0.2.7020723-SNAPSHOT' testImplementation 'junit:junit:4.13.2' testImplementation "org.mockito:mockito-inline:3.12.1" testImplementation "io.mockk:mockk:1.13.13" diff --git a/example/pubspec.lock b/example/pubspec.lock index 74b4b6b46..dbdfc1d49 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -107,7 +107,7 @@ packages: path: ".." relative: true source: path - version: "14.3.0" + version: "15.0.2" instabug_http_client: dependency: "direct main" description: diff --git a/lib/src/utils/screen_loading/screen_loading_manager.dart b/lib/src/utils/screen_loading/screen_loading_manager.dart index 9b48d6441..fce8884b4 100644 --- a/lib/src/utils/screen_loading/screen_loading_manager.dart +++ b/lib/src/utils/screen_loading/screen_loading_manager.dart @@ -148,10 +148,6 @@ class ScreenLoadingManager { try { resetDidStartScreenLoading(); - final isSDKBuilt = - await _checkInstabugSDKBuilt("APM.InstabugCaptureScreenLoading"); - if (!isSDKBuilt) return null; - // TODO: On Android, FlagsConfig.apm.isEnabled isn't implemented correctly // so we skip the isApmEnabled check on Android and only check on iOS. // This is a temporary fix until we implement the isEnabled check correctly. diff --git a/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart b/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart index 6517112e3..6a465044d 100644 --- a/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart +++ b/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart @@ -26,9 +26,10 @@ class InstabugScreenRenderManager { late InstabugScreenRenderData _screenRenderForCustomUiTrace; int _slowFramesTotalDurationMs = 0; int _frozenFramesTotalDurationMs = 0; + int? _epochOffset; bool _isTimingsListenerAttached = false; bool screenRenderEnabled = false; - int? _epochOffset; + bool _isWidgetBindingObserverAdded = false; final List _delayedFrames = []; @@ -139,9 +140,8 @@ class InstabugScreenRenderManager { //Sync the captured screen render data of the Custom UI trace when starting new one if (type == UiTraceType.custom) { - // Report only if the collector was active and has captured data - if (_screenRenderForCustomUiTrace.isActive && - _screenRenderForCustomUiTrace.isNotEmpty) { + // Report only if the collector was active + if (_screenRenderForCustomUiTrace.isActive) { _reportScreenRenderForCustomUiTrace(_screenRenderForCustomUiTrace); _screenRenderForCustomUiTrace.clear(); } @@ -150,9 +150,8 @@ class InstabugScreenRenderManager { //Sync the captured screen render data of the Auto UI trace when starting new one if (type == UiTraceType.auto) { - // Report only if the collector was active and has captured data - if (_screenRenderForAutoUiTrace.isActive && - _screenRenderForAutoUiTrace.isNotEmpty) { + // Report only if the collector was active + if (_screenRenderForAutoUiTrace.isActive) { _reportScreenRenderForAutoUiTrace(_screenRenderForAutoUiTrace); _screenRenderForAutoUiTrace.clear(); } @@ -172,14 +171,12 @@ class InstabugScreenRenderManager { } // Sync Screen Render data for custom ui trace if exists - if (_screenRenderForCustomUiTrace.isActive && - _screenRenderForCustomUiTrace.isNotEmpty) { + if (_screenRenderForCustomUiTrace.isActive) { _reportScreenRenderForCustomUiTrace(_screenRenderForCustomUiTrace); } // Sync Screen Render data for auto ui trace if exists - if (_screenRenderForAutoUiTrace.isActive && - _screenRenderForAutoUiTrace.isNotEmpty) { + if (_screenRenderForAutoUiTrace.isActive) { _reportScreenRenderForAutoUiTrace(_screenRenderForAutoUiTrace); } } catch (error, stackTrace) { @@ -211,6 +208,7 @@ class InstabugScreenRenderManager { void dispose() { _resetCachedFrameData(); _removeFrameTimings(); + _removeWidgetBindingObserver(); _widgetsBinding = null; screenRenderEnabled = false; } @@ -244,8 +242,26 @@ class InstabugScreenRenderManager { APM.getDeviceRefreshRate(); /// add new [WidgetsBindingObserver] to track app lifecycle. - void _addWidgetBindingObserver() => - _widgetsBinding?.addObserver(InstabugWidgetsBindingObserver.instance); + void _addWidgetBindingObserver() { + if (_widgetsBinding == null) { + return; + } + if (!_isWidgetBindingObserverAdded) { + _widgetsBinding!.addObserver(InstabugWidgetsBindingObserver.instance); + _isWidgetBindingObserverAdded = true; + } + } + + /// remove [WidgetsBindingObserver] from [WidgetsBinding] + void _removeWidgetBindingObserver() { + if (_widgetsBinding == null) { + return; + } + if (_isWidgetBindingObserverAdded) { + _widgetsBinding!.removeObserver(InstabugWidgetsBindingObserver.instance); + _isWidgetBindingObserverAdded = false; + } + } /// Initialize the static variables Future _initStaticValues() async { diff --git a/lib/src/utils/screen_rendering/instabug_widget_binding_observer.dart b/lib/src/utils/screen_rendering/instabug_widget_binding_observer.dart index 9f11925e4..5a27d15f0 100644 --- a/lib/src/utils/screen_rendering/instabug_widget_binding_observer.dart +++ b/lib/src/utils/screen_rendering/instabug_widget_binding_observer.dart @@ -20,12 +20,9 @@ class InstabugWidgetsBindingObserver extends WidgetsBindingObserver { static const tag = "InstabugWidgetsBindingObserver"; static void dispose() { - if (InstabugScreenRenderManager.I.screenRenderEnabled) { - InstabugScreenRenderManager.I.dispose(); - } - // For Flutter 2.10.5 version - // ignore: invalid_null_aware_operator - WidgetsBinding.instance?.removeObserver(_instance); + // Always call dispose to ensure proper cleanup with tracking flags + // The dispose method is safe to call multiple times due to state tracking + InstabugScreenRenderManager.I.dispose(); } void _handleResumedState() { diff --git a/test/utils/screen_loading/screen_loading_manager_test.dart b/test/utils/screen_loading/screen_loading_manager_test.dart index 341bc7368..6b5c954f3 100644 --- a/test/utils/screen_loading/screen_loading_manager_test.dart +++ b/test/utils/screen_loading/screen_loading_manager_test.dart @@ -168,25 +168,6 @@ void main() { when(mDateTime.now()).thenReturn(time); }); - test('[startUiTrace] with SDK not build should Log error', () async { - mScreenLoadingManager.currentUiTrace = uiTrace; - when(mInstabugHost.isBuilt()).thenAnswer((_) async => false); - - await ScreenLoadingManager.I.startUiTrace(screenName); - - final actualUiTrace = ScreenLoadingManager.I.currentUiTrace; - expect(actualUiTrace, null); - - verify( - mInstabugLogger.e( - 'Instabug API {APM.InstabugCaptureScreenLoading} was called before the SDK is built. To build it, first by following the instructions at this link:\n' - 'https://docs.instabug.com/reference#showing-and-manipulating-the-invocation', - tag: APM.tag, - ), - ).called(1); - verifyNever(mApmHost.startCpUiTrace(any, any, any)); - }); - test('[startUiTrace] with APM disabled on iOS Platform should Log error', () async { mScreenLoadingManager.currentUiTrace = uiTrace; From 751cdaa0237af645721b6688399fab8828d71b1d Mon Sep 17 00:00:00 2001 From: Andrew Amin Date: Tue, 29 Jul 2025 16:09:41 +0300 Subject: [PATCH 38/84] fix: delayed frames summation --- lib/src/modules/apm.dart | 6 +- lib/src/modules/instabug.dart | 6 - .../utils/instabug_navigator_observer.dart | 10 +- .../instabug_screen_render_manager.dart | 118 +-- .../instabug_screen_render_manager_test.dart | 33 +- ...reen_render_manager_test_manual_mocks.dart | 759 ------------------ 6 files changed, 74 insertions(+), 858 deletions(-) delete mode 100644 test/utils/screen_render/instabug_screen_render_manager_test_manual_mocks.dart diff --git a/lib/src/modules/apm.dart b/lib/src/modules/apm.dart index 3c9d9532f..d832964f8 100644 --- a/lib/src/modules/apm.dart +++ b/lib/src/modules/apm.dart @@ -392,10 +392,10 @@ class APM { /// /// Returns: /// A Future is being returned. - static Future setScreenRenderEnabled(bool isEnabled) { - return _host.setScreenRenderEnabled(isEnabled).then((_) { + static Future setScreenRenderEnabled(bool isEnabled) async { + return _host.setScreenRenderEnabled(isEnabled).then((_) async { if (isEnabled) { - InstabugScreenRenderManager.I.init(WidgetsBinding.instance); + await InstabugScreenRenderManager.I.init(WidgetsBinding.instance); } else { InstabugScreenRenderManager.I.dispose(); } diff --git a/lib/src/modules/instabug.dart b/lib/src/modules/instabug.dart index 3d7b52f1b..68658985c 100644 --- a/lib/src/modules/instabug.dart +++ b/lib/src/modules/instabug.dart @@ -23,9 +23,7 @@ import 'package:instabug_flutter/src/utils/feature_flags_manager.dart'; import 'package:instabug_flutter/src/utils/ibg_build_info.dart'; import 'package:instabug_flutter/src/utils/instabug_logger.dart'; import 'package:instabug_flutter/src/utils/screen_name_masker.dart'; -import 'package:instabug_flutter/src/utils/screen_rendering/instabug_screen_render_manager.dart'; import 'package:instabug_flutter/src/utils/screen_rendering/instabug_widget_binding_observer.dart'; -import 'package:instabug_flutter/src/utils/ui_trace/flags_config.dart'; import 'package:meta/meta.dart'; enum InvocationEvent { @@ -198,10 +196,6 @@ class Instabug { debugLogsLevel.toString(), ); - if (await FlagsConfig.screenRendering.isEnabled()) { - InstabugScreenRenderManager.I.init(WidgetsBinding.instance); - } - return FeatureFlagsManager().registerW3CFlagsListener(); } diff --git a/lib/src/utils/instabug_navigator_observer.dart b/lib/src/utils/instabug_navigator_observer.dart index 26aa3803c..5793f07fe 100644 --- a/lib/src/utils/instabug_navigator_observer.dart +++ b/lib/src/utils/instabug_navigator_observer.dart @@ -66,18 +66,18 @@ class InstabugNavigatorObserver extends NavigatorObserver { } FutureOr _startScreenRenderCollector(int? uiTraceId) async { - final isScreenRender = await FlagsConfig.screenRendering.isEnabled(); - _checkForScreenRenderInitialization(isScreenRender); - if (uiTraceId != null && isScreenRender) { + final isScreenRenderEnabled = await FlagsConfig.screenRendering.isEnabled(); + await _checkForScreenRenderInitialization(isScreenRenderEnabled); + if (uiTraceId != null && isScreenRenderEnabled) { InstabugScreenRenderManager.I .startScreenRenderCollectorForTraceId(uiTraceId); } } - void _checkForScreenRenderInitialization(bool isScreenRender) { + Future _checkForScreenRenderInitialization(bool isScreenRender) async { if (isScreenRender) { if (!InstabugScreenRenderManager.I.screenRenderEnabled) { - InstabugScreenRenderManager.I.init(WidgetsBinding.instance); + await InstabugScreenRenderManager.I.init(WidgetsBinding.instance); } } else { if (InstabugScreenRenderManager.I.screenRenderEnabled) { diff --git a/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart b/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart index 6a465044d..f36ed475d 100644 --- a/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart +++ b/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart @@ -1,4 +1,5 @@ import 'dart:async'; +import 'dart:developer' show log; import 'dart:ui'; import 'package:flutter/widgets.dart'; @@ -18,14 +19,14 @@ enum UiTraceType { @internal class InstabugScreenRenderManager { WidgetsBinding? _widgetsBinding; - late int _buildTime; - late int _rasterTime; - late int _totalTime; + late int _buildTimeMs; + late int _rasterTimeMs; + late int _totalTimeMs; late TimingsCallback _timingsCallback; late InstabugScreenRenderData _screenRenderForAutoUiTrace; late InstabugScreenRenderData _screenRenderForCustomUiTrace; - int _slowFramesTotalDurationMs = 0; - int _frozenFramesTotalDurationMs = 0; + int _slowFramesTotalDurationMicro = 0; + int _frozenFramesTotalDurationMicro = 0; int? _epochOffset; bool _isTimingsListenerAttached = false; bool screenRenderEnabled = false; @@ -42,7 +43,7 @@ class InstabugScreenRenderManager { /// Default frozen frame threshold in milliseconds (700ms) final _frozenFrameThresholdMs = 700; - final _microsecondsPerMillisecond = 1000; + // final _microsecondsPerMillisecond = 1000; InstabugScreenRenderManager._(); @@ -75,46 +76,45 @@ class InstabugScreenRenderManager { } } - /// analyze frame data in order to detect slow/frozen frame. + /// Analyze frame data to detect slow or frozen frames efficiently. @visibleForTesting void analyzeFrameTiming(FrameTiming frameTiming) { - _buildTime = frameTiming.buildDuration.inMilliseconds; - _rasterTime = frameTiming.rasterDuration.inMilliseconds; - _totalTime = frameTiming.totalSpan.inMilliseconds; - - if (_isUiFrozen) { - _frozenFramesTotalDurationMs += _buildTime; - } else if (_isRasterFrozen) { - _frozenFramesTotalDurationMs += _rasterTime; - } else if (_isTotalTimeLarge) { - _frozenFramesTotalDurationMs += _totalTime; - } - if (_isUiSlow) { - _slowFramesTotalDurationMs += _buildTime; - } else if (_isRasterSlow) { - _slowFramesTotalDurationMs += _rasterTime; - } + _buildTimeMs = frameTiming.buildDuration.inMilliseconds; + _rasterTimeMs = frameTiming.rasterDuration.inMilliseconds; + _totalTimeMs = frameTiming.totalSpan.inMilliseconds; - if (_isUiDelayed) { + if (_isTotalTimeLarge) { + final micros = frameTiming.totalSpan.inMicroseconds; + _frozenFramesTotalDurationMicro += micros; _onDelayedFrameDetected( _getMicrosecondsSinceEpoch( - frameTiming.timestampInMicroseconds(FramePhase.buildStart), + frameTiming.timestampInMicroseconds(FramePhase.vsyncStart), ), - _buildTime, + micros, ); - } else if (_isRasterDelayed) { + return; + } + + if (_isUiSlow) { + final micros = frameTiming.buildDuration.inMicroseconds; + _slowFramesTotalDurationMicro += micros; _onDelayedFrameDetected( _getMicrosecondsSinceEpoch( - frameTiming.timestampInMicroseconds(FramePhase.rasterStart), + frameTiming.timestampInMicroseconds(FramePhase.buildStart), ), - _rasterTime, + micros, ); - } else if (_isTotalTimeLarge) { + return; + } + + if (_isRasterSlow) { + final micros = frameTiming.rasterDuration.inMicroseconds; + _slowFramesTotalDurationMicro += micros; _onDelayedFrameDetected( _getMicrosecondsSinceEpoch( - frameTiming.timestampInMicroseconds(FramePhase.vsyncStart), + frameTiming.timestampInMicroseconds(FramePhase.rasterStart), ), - _totalTime, + micros, ); } } @@ -215,23 +215,15 @@ class InstabugScreenRenderManager { /// --------------------------- private methods --------------------- - bool get _isUiDelayed => _isUiSlow || _isUiFrozen; - - bool get _isRasterDelayed => _isRasterSlow || _isRasterFrozen; - bool get _isUiSlow => - _buildTime > _slowFrameThresholdMs && - _buildTime < _frozenFrameThresholdMs; + _buildTimeMs > _slowFrameThresholdMs && + _buildTimeMs < _frozenFrameThresholdMs; bool get _isRasterSlow => - _rasterTime > _slowFrameThresholdMs && - _rasterTime < _frozenFrameThresholdMs; + _rasterTimeMs > _slowFrameThresholdMs && + _rasterTimeMs < _frozenFrameThresholdMs; - bool get _isTotalTimeLarge => _totalTime >= _frozenFrameThresholdMs; - - bool get _isUiFrozen => _buildTime >= _frozenFrameThresholdMs; - - bool get _isRasterFrozen => _rasterTime >= _frozenFrameThresholdMs; + bool get _isTotalTimeLarge => _totalTimeMs >= _frozenFrameThresholdMs; /// Calculate the target time for the frame to be drawn in milliseconds based on the device refresh rate. double _targetMsPerFrame(double displayRefreshRate) => @@ -302,18 +294,21 @@ class InstabugScreenRenderManager { /// Reset the memory cashed data void _resetCachedFrameData() { - _slowFramesTotalDurationMs = 0; - _frozenFramesTotalDurationMs = 0; + _slowFramesTotalDurationMicro = 0; + _frozenFramesTotalDurationMicro = 0; _delayedFrames.clear(); } /// Save Slow/Frozen Frames data - void _onDelayedFrameDetected(int startTime, int durationInMilliseconds) { + void _onDelayedFrameDetected(int startTime, int durationInMicroseconds) { + log( + "${durationInMicroseconds >= 700000 ? "🚨Frozen" : "⚠️Slow"} Frame Detected (startTime: $startTime, duration: $durationInMicroseconds µs)", + name: tag, + ); _delayedFrames.add( InstabugFrameData( startTime, - durationInMilliseconds * - _microsecondsPerMillisecond, // Convert duration from milliseconds to microSeconds + durationInMicroseconds, ), ); } @@ -325,6 +320,10 @@ class InstabugScreenRenderManager { InstabugScreenRenderData screenRenderData, ) async { try { + log( + "reportScreenRenderForCustomUiTrace $screenRenderData", + name: tag, + ); await APM.endScreenRenderForCustomUiTrace(screenRenderData); return true; } catch (error, stackTrace) { @@ -343,7 +342,12 @@ class InstabugScreenRenderManager { // Save the end time for the running ui trace, it's only needed in Android SDK. screenRenderData.saveEndTime(); + log( + "reportScreenRenderForAutoUiTrace $screenRenderData", + name: tag, + ); await APM.endScreenRenderForAutoUiTrace(screenRenderData); + return true; } catch (error, stackTrace) { _logExceptionErrorAndStackTrace(error, stackTrace); @@ -370,9 +374,9 @@ class InstabugScreenRenderManager { /// or synced with the native side. void _updateCustomUiData() { _screenRenderForCustomUiTrace.slowFramesTotalDurationMicro += - _slowFramesTotalDurationMs * _microsecondsPerMillisecond; + _slowFramesTotalDurationMicro; _screenRenderForCustomUiTrace.frozenFramesTotalDurationMicro += - _frozenFramesTotalDurationMs * _microsecondsPerMillisecond; + _frozenFramesTotalDurationMicro; _screenRenderForCustomUiTrace.frameData.addAll(_delayedFrames); } @@ -385,9 +389,9 @@ class InstabugScreenRenderManager { /// or synced with the native side. void _updateAutoUiData() { _screenRenderForAutoUiTrace.slowFramesTotalDurationMicro += - _slowFramesTotalDurationMs * _microsecondsPerMillisecond; + _slowFramesTotalDurationMicro; _screenRenderForAutoUiTrace.frozenFramesTotalDurationMicro += - _frozenFramesTotalDurationMs * _microsecondsPerMillisecond; + _frozenFramesTotalDurationMicro; _screenRenderForAutoUiTrace.frameData.addAll(_delayedFrames); } @@ -426,9 +430,7 @@ class InstabugScreenRenderManager { @visibleForTesting void setFrameData(InstabugScreenRenderData data) { _delayedFrames.addAll(data.frameData); - _frozenFramesTotalDurationMs = - data.frozenFramesTotalDurationMicro ~/ _microsecondsPerMillisecond; - _slowFramesTotalDurationMs = - data.slowFramesTotalDurationMicro ~/ _microsecondsPerMillisecond; + _frozenFramesTotalDurationMicro = data.frozenFramesTotalDurationMicro; + _slowFramesTotalDurationMicro = data.slowFramesTotalDurationMicro; } } diff --git a/test/utils/screen_render/instabug_screen_render_manager_test.dart b/test/utils/screen_render/instabug_screen_render_manager_test.dart index 15a0f439f..9f99ac0f4 100644 --- a/test/utils/screen_render/instabug_screen_render_manager_test.dart +++ b/test/utils/screen_render/instabug_screen_render_manager_test.dart @@ -5,7 +5,7 @@ import 'package:instabug_flutter/src/models/instabug_screen_render_data.dart'; import 'package:instabug_flutter/src/utils/screen_rendering/instabug_screen_render_manager.dart'; import 'package:mockito/mockito.dart'; -import 'instabug_screen_render_manager_test_manual_mocks.dart'; +import 'instabug_screen_render_manager_test.mocks.dart'; void main() { TestWidgetsFlutterBinding.ensureInitialized(); @@ -380,32 +380,11 @@ void main() { }); test( - 'should detect frozen frame on build thread when durations are greater than or equal 700 ms', + 'should detect frozen frame when durations are greater than or equal 700 ms', () { - const buildDuration = 700; - when(mockFrameTiming.buildDuration) - .thenReturn(const Duration(milliseconds: buildDuration)); - manager.startScreenRenderCollectorForTraceId(1); // start new collector - manager.analyzeFrameTiming(mockFrameTiming); // mock frame timing - manager.stopScreenRenderCollector(); // should save data - - expect(manager.screenRenderForAutoUiTrace.frameData.length, 1); - expect( - manager.screenRenderForAutoUiTrace.frozenFramesTotalDurationMicro, - buildDuration * 1000, - ); // * 1000 to convert from milliseconds to microseconds - expect( - manager.screenRenderForAutoUiTrace.slowFramesTotalDurationMicro, - 0, - ); - }); - - test( - 'should detect frozen frame on raster thread when durations are greater than or equal 700 ms', - () { - const rasterBuild = 700; - when(mockFrameTiming.buildDuration) - .thenReturn(const Duration(milliseconds: rasterBuild)); + const totalTime = 700; + when(mockFrameTiming.totalSpan) + .thenReturn(const Duration(milliseconds: totalTime)); manager.startScreenRenderCollectorForTraceId(1); // start new collector manager.analyzeFrameTiming(mockFrameTiming); // mock frame timing manager.stopScreenRenderCollector(); // should save data @@ -413,7 +392,7 @@ void main() { expect(manager.screenRenderForAutoUiTrace.frameData.length, 1); expect( manager.screenRenderForAutoUiTrace.frozenFramesTotalDurationMicro, - rasterBuild * 1000, + totalTime * 1000, ); // * 1000 to convert from milliseconds to microseconds expect( manager.screenRenderForAutoUiTrace.slowFramesTotalDurationMicro, diff --git a/test/utils/screen_render/instabug_screen_render_manager_test_manual_mocks.dart b/test/utils/screen_render/instabug_screen_render_manager_test_manual_mocks.dart deleted file mode 100644 index 4e363eb75..000000000 --- a/test/utils/screen_render/instabug_screen_render_manager_test_manual_mocks.dart +++ /dev/null @@ -1,759 +0,0 @@ -// Mocks generated by Mockito 5.2.0 from annotations -// in instabug_flutter/example/ios/.symlinks/plugins/instabug_flutter/test/utils/screen_render/instabug_screen_render_manager_test.dart. -// Do not manually edit this file. - -import 'dart:async' as _i9; -import 'dart:developer' as _i13; -import 'dart:ui' as _i4; - -import 'package:flutter/foundation.dart' as _i3; -import 'package:flutter/gestures.dart' as _i6; -import 'package:flutter/rendering.dart' as _i7; -import 'package:flutter/scheduler.dart' as _i11; -import 'package:flutter/services.dart' as _i5; -import 'package:flutter/src/widgets/binding.dart' as _i10; -import 'package:flutter/src/widgets/focus_manager.dart' as _i2; -import 'package:flutter/src/widgets/framework.dart' as _i12; -import 'package:instabug_flutter/src/generated/apm.api.g.dart' as _i8; -import 'package:mockito/mockito.dart' as _i1; - -// ignore_for_file: type=lint -// ignore_for_file: avoid_redundant_argument_values -// ignore_for_file: avoid_setters_without_getters -// ignore_for_file: comment_references -// ignore_for_file: implementation_imports -// ignore_for_file: invalid_use_of_visible_for_testing_member -// ignore_for_file: prefer_const_constructors -// ignore_for_file: unnecessary_parenthesis -// ignore_for_file: camel_case_types - -class _FakeFocusManager_0 extends _i1.Fake implements _i2.FocusManager { - @override - String toString({_i3.DiagnosticLevel? minLevel = _i3.DiagnosticLevel.info}) => - super.toString(); -} - -class _FakeSingletonFlutterWindow_1 extends _i1.Fake - implements _i4.SingletonFlutterWindow {} - -class _FakePlatformDispatcher_2 extends _i1.Fake - implements _i4.PlatformDispatcher {} - -class _FakeHardwareKeyboard_3 extends _i1.Fake - implements _i5.HardwareKeyboard {} - -class _FakeKeyEventManager_4 extends _i1.Fake implements _i5.KeyEventManager {} - -class _FakeBinaryMessenger_5 extends _i1.Fake implements _i5.BinaryMessenger {} - -class _FakeChannelBuffers_6 extends _i1.Fake implements _i4.ChannelBuffers {} - -class _FakeRestorationManager_7 extends _i1.Fake - implements _i5.RestorationManager {} - -class _FakeDuration_8 extends _i1.Fake implements Duration {} - -class _FakePointerRouter_9 extends _i1.Fake implements _i6.PointerRouter {} - -class _FakeGestureArenaManager_10 extends _i1.Fake - implements _i6.GestureArenaManager {} - -class _FakePointerSignalResolver_11 extends _i1.Fake - implements _i6.PointerSignalResolver {} - -class _FakeMouseTracker_12 extends _i1.Fake implements _i7.MouseTracker {} - -class _FakePipelineOwner_13 extends _i1.Fake implements _i7.PipelineOwner {} - -class _FakeRenderView_14 extends _i1.Fake implements _i7.RenderView { - @override - String toString({_i3.DiagnosticLevel? minLevel = _i3.DiagnosticLevel.info}) => - super.toString(); -} - -class _FakeAccessibilityFeatures_15 extends _i1.Fake - implements _i4.AccessibilityFeatures {} - -class _FakeViewConfiguration_16 extends _i1.Fake - implements _i7.ViewConfiguration {} - -class _FakeSemanticsUpdateBuilder_17 extends _i1.Fake - implements _i4.SemanticsUpdateBuilder {} - -/// A class which mocks [ApmHostApi]. -/// -/// See the documentation for Mockito's code generation for more information. -class MockApmHostApi extends _i1.Mock implements _i8.ApmHostApi { - MockApmHostApi() { - _i1.throwOnMissingStub(this); - } - - @override - _i9.Future setEnabled(bool? arg_isEnabled) => - (super.noSuchMethod(Invocation.method(#setEnabled, [arg_isEnabled]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - _i9.Future isEnabled() => - (super.noSuchMethod(Invocation.method(#isEnabled, []), - returnValue: Future.value(false)) as _i9.Future); - @override - _i9.Future setScreenLoadingEnabled(bool? arg_isEnabled) => - (super.noSuchMethod( - Invocation.method(#setScreenLoadingEnabled, [arg_isEnabled]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - _i9.Future isScreenLoadingEnabled() => - (super.noSuchMethod(Invocation.method(#isScreenLoadingEnabled, []), - returnValue: Future.value(false)) as _i9.Future); - @override - _i9.Future setColdAppLaunchEnabled(bool? arg_isEnabled) => - (super.noSuchMethod( - Invocation.method(#setColdAppLaunchEnabled, [arg_isEnabled]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - _i9.Future setAutoUITraceEnabled(bool? arg_isEnabled) => (super - .noSuchMethod(Invocation.method(#setAutoUITraceEnabled, [arg_isEnabled]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - _i9.Future startExecutionTrace(String? arg_id, String? arg_name) => - (super.noSuchMethod( - Invocation.method(#startExecutionTrace, [arg_id, arg_name]), - returnValue: Future.value()) as _i9.Future); - @override - _i9.Future startFlow(String? arg_name) => - (super.noSuchMethod(Invocation.method(#startFlow, [arg_name]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - _i9.Future setFlowAttribute( - String? arg_name, String? arg_key, String? arg_value) => - (super.noSuchMethod( - Invocation.method(#setFlowAttribute, [arg_name, arg_key, arg_value]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - _i9.Future endFlow(String? arg_name) => - (super.noSuchMethod(Invocation.method(#endFlow, [arg_name]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - _i9.Future setExecutionTraceAttribute( - String? arg_id, String? arg_key, String? arg_value) => - (super.noSuchMethod( - Invocation.method( - #setExecutionTraceAttribute, [arg_id, arg_key, arg_value]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - _i9.Future endExecutionTrace(String? arg_id) => - (super.noSuchMethod(Invocation.method(#endExecutionTrace, [arg_id]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - _i9.Future startUITrace(String? arg_name) => - (super.noSuchMethod(Invocation.method(#startUITrace, [arg_name]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - _i9.Future endUITrace() => - (super.noSuchMethod(Invocation.method(#endUITrace, []), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - _i9.Future endAppLaunch() => - (super.noSuchMethod(Invocation.method(#endAppLaunch, []), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - _i9.Future networkLogAndroid(Map? arg_data) => - (super.noSuchMethod(Invocation.method(#networkLogAndroid, [arg_data]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - _i9.Future startCpUiTrace( - String? arg_screenName, int? arg_microTimeStamp, int? arg_traceId) => - (super.noSuchMethod( - Invocation.method(#startCpUiTrace, - [arg_screenName, arg_microTimeStamp, arg_traceId]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - _i9.Future reportScreenLoadingCP(int? arg_startTimeStampMicro, - int? arg_durationMicro, int? arg_uiTraceId) => - (super.noSuchMethod( - Invocation.method(#reportScreenLoadingCP, - [arg_startTimeStampMicro, arg_durationMicro, arg_uiTraceId]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - _i9.Future endScreenLoadingCP( - int? arg_timeStampMicro, int? arg_uiTraceId) => - (super.noSuchMethod( - Invocation.method( - #endScreenLoadingCP, [arg_timeStampMicro, arg_uiTraceId]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - _i9.Future isEndScreenLoadingEnabled() => - (super.noSuchMethod(Invocation.method(#isEndScreenLoadingEnabled, []), - returnValue: Future.value(false)) as _i9.Future); - @override - _i9.Future isScreenRenderEnabled() => - (super.noSuchMethod(Invocation.method(#isScreenRenderEnabled, []), - returnValue: Future.value(false)) as _i9.Future); - @override - _i9.Future deviceRefreshRate() => - (super.noSuchMethod(Invocation.method(#deviceRefreshRate, []), - returnValue: Future.value(0.0)) as _i9.Future); - @override - _i9.Future setScreenRenderEnabled(bool? arg_isEnabled) => (super - .noSuchMethod(Invocation.method(#setScreenRenderEnabled, [arg_isEnabled]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - _i9.Future endScreenRenderForAutoUiTrace( - Map? arg_data) => - (super.noSuchMethod( - Invocation.method(#endScreenRenderForAutoUiTrace, [arg_data]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - _i9.Future endScreenRenderForCustomUiTrace( - Map? arg_data) => - (super.noSuchMethod( - Invocation.method(#endScreenRenderForCustomUiTrace, [arg_data]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); -} - -/// A class which mocks [WidgetsBinding]. -/// -/// See the documentation for Mockito's code generation for more information. -class MockWidgetsBinding extends _i1.Mock implements _i10.WidgetsBinding { - MockWidgetsBinding() { - _i1.throwOnMissingStub(this); - } - - @override - bool get debugBuildingDirtyElements => - (super.noSuchMethod(Invocation.getter(#debugBuildingDirtyElements), - returnValue: false) as bool); - @override - set debugBuildingDirtyElements(bool? _debugBuildingDirtyElements) => - super.noSuchMethod( - Invocation.setter( - #debugBuildingDirtyElements, _debugBuildingDirtyElements), - returnValueForMissingStub: null); - @override - _i2.FocusManager get focusManager => - (super.noSuchMethod(Invocation.getter(#focusManager), - returnValue: _FakeFocusManager_0()) as _i2.FocusManager); - @override - bool get firstFrameRasterized => - (super.noSuchMethod(Invocation.getter(#firstFrameRasterized), - returnValue: false) as bool); - @override - _i9.Future get waitUntilFirstFrameRasterized => - (super.noSuchMethod(Invocation.getter(#waitUntilFirstFrameRasterized), - returnValue: Future.value()) as _i9.Future); - @override - bool get debugDidSendFirstFrameEvent => - (super.noSuchMethod(Invocation.getter(#debugDidSendFirstFrameEvent), - returnValue: false) as bool); - @override - bool get framesEnabled => - (super.noSuchMethod(Invocation.getter(#framesEnabled), returnValue: false) - as bool); - @override - bool get isRootWidgetAttached => - (super.noSuchMethod(Invocation.getter(#isRootWidgetAttached), - returnValue: false) as bool); - @override - _i4.SingletonFlutterWindow get window => - (super.noSuchMethod(Invocation.getter(#window), - returnValue: _FakeSingletonFlutterWindow_1()) - as _i4.SingletonFlutterWindow); - @override - _i4.PlatformDispatcher get platformDispatcher => - (super.noSuchMethod(Invocation.getter(#platformDispatcher), - returnValue: _FakePlatformDispatcher_2()) as _i4.PlatformDispatcher); - @override - bool get locked => - (super.noSuchMethod(Invocation.getter(#locked), returnValue: false) - as bool); - @override - _i5.HardwareKeyboard get keyboard => - (super.noSuchMethod(Invocation.getter(#keyboard), - returnValue: _FakeHardwareKeyboard_3()) as _i5.HardwareKeyboard); - @override - _i5.KeyEventManager get keyEventManager => - (super.noSuchMethod(Invocation.getter(#keyEventManager), - returnValue: _FakeKeyEventManager_4()) as _i5.KeyEventManager); - @override - _i5.BinaryMessenger get defaultBinaryMessenger => - (super.noSuchMethod(Invocation.getter(#defaultBinaryMessenger), - returnValue: _FakeBinaryMessenger_5()) as _i5.BinaryMessenger); - @override - _i4.ChannelBuffers get channelBuffers => - (super.noSuchMethod(Invocation.getter(#channelBuffers), - returnValue: _FakeChannelBuffers_6()) as _i4.ChannelBuffers); - @override - _i5.RestorationManager get restorationManager => - (super.noSuchMethod(Invocation.getter(#restorationManager), - returnValue: _FakeRestorationManager_7()) as _i5.RestorationManager); - @override - _i11.SchedulingStrategy get schedulingStrategy => - (super.noSuchMethod(Invocation.getter(#schedulingStrategy), - returnValue: ({int? priority, _i11.SchedulerBinding? scheduler}) => - false) as _i11.SchedulingStrategy); - @override - set schedulingStrategy(_i11.SchedulingStrategy? _schedulingStrategy) => super - .noSuchMethod(Invocation.setter(#schedulingStrategy, _schedulingStrategy), - returnValueForMissingStub: null); - @override - int get transientCallbackCount => - (super.noSuchMethod(Invocation.getter(#transientCallbackCount), - returnValue: 0) as int); - @override - _i9.Future get endOfFrame => - (super.noSuchMethod(Invocation.getter(#endOfFrame), - returnValue: Future.value()) as _i9.Future); - @override - bool get hasScheduledFrame => - (super.noSuchMethod(Invocation.getter(#hasScheduledFrame), - returnValue: false) as bool); - @override - _i11.SchedulerPhase get schedulerPhase => - (super.noSuchMethod(Invocation.getter(#schedulerPhase), - returnValue: _i11.SchedulerPhase.idle) as _i11.SchedulerPhase); - @override - Duration get currentFrameTimeStamp => - (super.noSuchMethod(Invocation.getter(#currentFrameTimeStamp), - returnValue: _FakeDuration_8()) as Duration); - @override - Duration get currentSystemFrameTimeStamp => - (super.noSuchMethod(Invocation.getter(#currentSystemFrameTimeStamp), - returnValue: _FakeDuration_8()) as Duration); - @override - _i6.PointerRouter get pointerRouter => - (super.noSuchMethod(Invocation.getter(#pointerRouter), - returnValue: _FakePointerRouter_9()) as _i6.PointerRouter); - @override - _i6.GestureArenaManager get gestureArena => (super.noSuchMethod( - Invocation.getter(#gestureArena), - returnValue: _FakeGestureArenaManager_10()) as _i6.GestureArenaManager); - @override - _i6.PointerSignalResolver get pointerSignalResolver => - (super.noSuchMethod(Invocation.getter(#pointerSignalResolver), - returnValue: _FakePointerSignalResolver_11()) - as _i6.PointerSignalResolver); - @override - bool get resamplingEnabled => - (super.noSuchMethod(Invocation.getter(#resamplingEnabled), - returnValue: false) as bool); - @override - set resamplingEnabled(bool? _resamplingEnabled) => super.noSuchMethod( - Invocation.setter(#resamplingEnabled, _resamplingEnabled), - returnValueForMissingStub: null); - @override - Duration get samplingOffset => - (super.noSuchMethod(Invocation.getter(#samplingOffset), - returnValue: _FakeDuration_8()) as Duration); - @override - set samplingOffset(Duration? _samplingOffset) => - super.noSuchMethod(Invocation.setter(#samplingOffset, _samplingOffset), - returnValueForMissingStub: null); - @override - _i7.MouseTracker get mouseTracker => - (super.noSuchMethod(Invocation.getter(#mouseTracker), - returnValue: _FakeMouseTracker_12()) as _i7.MouseTracker); - @override - _i7.PipelineOwner get pipelineOwner => - (super.noSuchMethod(Invocation.getter(#pipelineOwner), - returnValue: _FakePipelineOwner_13()) as _i7.PipelineOwner); - @override - _i7.RenderView get renderView => - (super.noSuchMethod(Invocation.getter(#renderView), - returnValue: _FakeRenderView_14()) as _i7.RenderView); - @override - set renderView(_i7.RenderView? value) => - super.noSuchMethod(Invocation.setter(#renderView, value), - returnValueForMissingStub: null); - @override - bool get sendFramesToEngine => - (super.noSuchMethod(Invocation.getter(#sendFramesToEngine), - returnValue: false) as bool); - @override - _i4.AccessibilityFeatures get accessibilityFeatures => - (super.noSuchMethod(Invocation.getter(#accessibilityFeatures), - returnValue: _FakeAccessibilityFeatures_15()) - as _i4.AccessibilityFeatures); - @override - bool get disableAnimations => - (super.noSuchMethod(Invocation.getter(#disableAnimations), - returnValue: false) as bool); - @override - void initInstances() => - super.noSuchMethod(Invocation.method(#initInstances, []), - returnValueForMissingStub: null); - @override - void initServiceExtensions() => - super.noSuchMethod(Invocation.method(#initServiceExtensions, []), - returnValueForMissingStub: null); - @override - void addObserver(_i10.WidgetsBindingObserver? observer) => - super.noSuchMethod(Invocation.method(#addObserver, [observer]), - returnValueForMissingStub: null); - @override - bool removeObserver(_i10.WidgetsBindingObserver? observer) => - (super.noSuchMethod(Invocation.method(#removeObserver, [observer]), - returnValue: false) as bool); - @override - void handleMetricsChanged() => - super.noSuchMethod(Invocation.method(#handleMetricsChanged, []), - returnValueForMissingStub: null); - @override - void handleTextScaleFactorChanged() => - super.noSuchMethod(Invocation.method(#handleTextScaleFactorChanged, []), - returnValueForMissingStub: null); - @override - void handlePlatformBrightnessChanged() => super.noSuchMethod( - Invocation.method(#handlePlatformBrightnessChanged, []), - returnValueForMissingStub: null); - @override - void handleAccessibilityFeaturesChanged() => super.noSuchMethod( - Invocation.method(#handleAccessibilityFeaturesChanged, []), - returnValueForMissingStub: null); - @override - void handleLocaleChanged() => - super.noSuchMethod(Invocation.method(#handleLocaleChanged, []), - returnValueForMissingStub: null); - @override - void dispatchLocalesChanged(List<_i4.Locale>? locales) => - super.noSuchMethod(Invocation.method(#dispatchLocalesChanged, [locales]), - returnValueForMissingStub: null); - @override - void dispatchAccessibilityFeaturesChanged() => super.noSuchMethod( - Invocation.method(#dispatchAccessibilityFeaturesChanged, []), - returnValueForMissingStub: null); - @override - _i9.Future handlePopRoute() => - (super.noSuchMethod(Invocation.method(#handlePopRoute, []), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - _i9.Future handlePushRoute(String? route) => - (super.noSuchMethod(Invocation.method(#handlePushRoute, [route]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - void handleAppLifecycleStateChanged(_i4.AppLifecycleState? state) => super - .noSuchMethod(Invocation.method(#handleAppLifecycleStateChanged, [state]), - returnValueForMissingStub: null); - @override - void handleMemoryPressure() => - super.noSuchMethod(Invocation.method(#handleMemoryPressure, []), - returnValueForMissingStub: null); - @override - void drawFrame() => super.noSuchMethod(Invocation.method(#drawFrame, []), - returnValueForMissingStub: null); - @override - void scheduleAttachRootWidget(_i12.Widget? rootWidget) => super.noSuchMethod( - Invocation.method(#scheduleAttachRootWidget, [rootWidget]), - returnValueForMissingStub: null); - @override - void attachRootWidget(_i12.Widget? rootWidget) => - super.noSuchMethod(Invocation.method(#attachRootWidget, [rootWidget]), - returnValueForMissingStub: null); - @override - _i9.Future performReassemble() => - (super.noSuchMethod(Invocation.method(#performReassemble, []), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - _i4.Locale? computePlatformResolvedLocale( - List<_i4.Locale>? supportedLocales) => - (super.noSuchMethod(Invocation.method( - #computePlatformResolvedLocale, [supportedLocales])) as _i4.Locale?); - @override - _i9.Future lockEvents(_i9.Future Function()? callback) => - (super.noSuchMethod(Invocation.method(#lockEvents, [callback]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - void unlocked() => super.noSuchMethod(Invocation.method(#unlocked, []), - returnValueForMissingStub: null); - @override - _i9.Future reassembleApplication() => - (super.noSuchMethod(Invocation.method(#reassembleApplication, []), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - void registerSignalServiceExtension( - {String? name, _i3.AsyncCallback? callback}) => - super.noSuchMethod( - Invocation.method(#registerSignalServiceExtension, [], - {#name: name, #callback: callback}), - returnValueForMissingStub: null); - @override - void registerBoolServiceExtension( - {String? name, - _i3.AsyncValueGetter? getter, - _i3.AsyncValueSetter? setter}) => - super.noSuchMethod( - Invocation.method(#registerBoolServiceExtension, [], - {#name: name, #getter: getter, #setter: setter}), - returnValueForMissingStub: null); - @override - void registerNumericServiceExtension( - {String? name, - _i3.AsyncValueGetter? getter, - _i3.AsyncValueSetter? setter}) => - super.noSuchMethod( - Invocation.method(#registerNumericServiceExtension, [], - {#name: name, #getter: getter, #setter: setter}), - returnValueForMissingStub: null); - @override - void postEvent(String? eventKind, Map? eventData) => - super.noSuchMethod(Invocation.method(#postEvent, [eventKind, eventData]), - returnValueForMissingStub: null); - @override - void registerStringServiceExtension( - {String? name, - _i3.AsyncValueGetter? getter, - _i3.AsyncValueSetter? setter}) => - super.noSuchMethod( - Invocation.method(#registerStringServiceExtension, [], - {#name: name, #getter: getter, #setter: setter}), - returnValueForMissingStub: null); - @override - void registerServiceExtension( - {String? name, _i3.ServiceExtensionCallback? callback}) => - super.noSuchMethod( - Invocation.method(#registerServiceExtension, [], - {#name: name, #callback: callback}), - returnValueForMissingStub: null); - @override - _i5.BinaryMessenger createBinaryMessenger() => - (super.noSuchMethod(Invocation.method(#createBinaryMessenger, []), - returnValue: _FakeBinaryMessenger_5()) as _i5.BinaryMessenger); - @override - _i9.Future handleSystemMessage(Object? systemMessage) => (super - .noSuchMethod(Invocation.method(#handleSystemMessage, [systemMessage]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - void initLicenses() => - super.noSuchMethod(Invocation.method(#initLicenses, []), - returnValueForMissingStub: null); - @override - void evict(String? asset) => - super.noSuchMethod(Invocation.method(#evict, [asset]), - returnValueForMissingStub: null); - @override - void readInitialLifecycleStateFromNativeWindow() => super.noSuchMethod( - Invocation.method(#readInitialLifecycleStateFromNativeWindow, []), - returnValueForMissingStub: null); - @override - _i5.RestorationManager createRestorationManager() => - (super.noSuchMethod(Invocation.method(#createRestorationManager, []), - returnValue: _FakeRestorationManager_7()) as _i5.RestorationManager); - @override - void setSystemUiChangeCallback(_i5.SystemUiChangeCallback? callback) => super - .noSuchMethod(Invocation.method(#setSystemUiChangeCallback, [callback]), - returnValueForMissingStub: null); - @override - void addTimingsCallback(_i4.TimingsCallback? callback) => - super.noSuchMethod(Invocation.method(#addTimingsCallback, [callback]), - returnValueForMissingStub: null); - @override - void removeTimingsCallback(_i4.TimingsCallback? callback) => - super.noSuchMethod(Invocation.method(#removeTimingsCallback, [callback]), - returnValueForMissingStub: null); - @override - _i9.Future scheduleTask( - _i11.TaskCallback? task, _i11.Priority? priority, - {String? debugLabel, _i13.Flow? flow}) => - (super.noSuchMethod( - Invocation.method(#scheduleTask, [task, priority], - {#debugLabel: debugLabel, #flow: flow}), - returnValue: Future.value(null)) as _i9.Future); - @override - bool handleEventLoopCallback() => - (super.noSuchMethod(Invocation.method(#handleEventLoopCallback, []), - returnValue: false) as bool); - @override - int scheduleFrameCallback(_i11.FrameCallback? callback, - {bool? rescheduling = false}) => - (super.noSuchMethod( - Invocation.method(#scheduleFrameCallback, [callback], - {#rescheduling: rescheduling}), - returnValue: 0) as int); - @override - void cancelFrameCallbackWithId(int? id) => - super.noSuchMethod(Invocation.method(#cancelFrameCallbackWithId, [id]), - returnValueForMissingStub: null); - @override - bool debugAssertNoTransientCallbacks(String? reason) => (super.noSuchMethod( - Invocation.method(#debugAssertNoTransientCallbacks, [reason]), - returnValue: false) as bool); - @override - void addPersistentFrameCallback(_i11.FrameCallback? callback) => super - .noSuchMethod(Invocation.method(#addPersistentFrameCallback, [callback]), - returnValueForMissingStub: null); - @override - void addPostFrameCallback(_i11.FrameCallback? callback) => - super.noSuchMethod(Invocation.method(#addPostFrameCallback, [callback]), - returnValueForMissingStub: null); - @override - void ensureFrameCallbacksRegistered() => - super.noSuchMethod(Invocation.method(#ensureFrameCallbacksRegistered, []), - returnValueForMissingStub: null); - @override - void ensureVisualUpdate() => - super.noSuchMethod(Invocation.method(#ensureVisualUpdate, []), - returnValueForMissingStub: null); - @override - void scheduleFrame() => - super.noSuchMethod(Invocation.method(#scheduleFrame, []), - returnValueForMissingStub: null); - @override - void scheduleForcedFrame() => - super.noSuchMethod(Invocation.method(#scheduleForcedFrame, []), - returnValueForMissingStub: null); - @override - void scheduleWarmUpFrame() => - super.noSuchMethod(Invocation.method(#scheduleWarmUpFrame, []), - returnValueForMissingStub: null); - @override - void resetEpoch() => super.noSuchMethod(Invocation.method(#resetEpoch, []), - returnValueForMissingStub: null); - @override - void handleBeginFrame(Duration? rawTimeStamp) => - super.noSuchMethod(Invocation.method(#handleBeginFrame, [rawTimeStamp]), - returnValueForMissingStub: null); - @override - void handleDrawFrame() => - super.noSuchMethod(Invocation.method(#handleDrawFrame, []), - returnValueForMissingStub: null); - @override - void cancelPointer(int? pointer) => - super.noSuchMethod(Invocation.method(#cancelPointer, [pointer]), - returnValueForMissingStub: null); - @override - void handlePointerEvent(_i7.PointerEvent? event) => - super.noSuchMethod(Invocation.method(#handlePointerEvent, [event]), - returnValueForMissingStub: null); - @override - void hitTest(_i7.HitTestResult? result, _i4.Offset? position) => - super.noSuchMethod(Invocation.method(#hitTest, [result, position]), - returnValueForMissingStub: null); - @override - void dispatchEvent( - _i7.PointerEvent? event, _i7.HitTestResult? hitTestResult) => - super.noSuchMethod( - Invocation.method(#dispatchEvent, [event, hitTestResult]), - returnValueForMissingStub: null); - @override - void handleEvent(_i7.PointerEvent? event, _i7.HitTestEntry? entry) => - super.noSuchMethod(Invocation.method(#handleEvent, [event, entry]), - returnValueForMissingStub: null); - @override - void resetGestureBinding() => - super.noSuchMethod(Invocation.method(#resetGestureBinding, []), - returnValueForMissingStub: null); - @override - void initRenderView() => - super.noSuchMethod(Invocation.method(#initRenderView, []), - returnValueForMissingStub: null); - @override - _i7.ViewConfiguration createViewConfiguration() => - (super.noSuchMethod(Invocation.method(#createViewConfiguration, []), - returnValue: _FakeViewConfiguration_16()) as _i7.ViewConfiguration); - @override - void initMouseTracker([_i7.MouseTracker? tracker]) => - super.noSuchMethod(Invocation.method(#initMouseTracker, [tracker]), - returnValueForMissingStub: null); - @override - void setSemanticsEnabled(bool? enabled) => - super.noSuchMethod(Invocation.method(#setSemanticsEnabled, [enabled]), - returnValueForMissingStub: null); - @override - void deferFirstFrame() => - super.noSuchMethod(Invocation.method(#deferFirstFrame, []), - returnValueForMissingStub: null); - @override - void allowFirstFrame() => - super.noSuchMethod(Invocation.method(#allowFirstFrame, []), - returnValueForMissingStub: null); - @override - void resetFirstFrameSent() => - super.noSuchMethod(Invocation.method(#resetFirstFrameSent, []), - returnValueForMissingStub: null); - @override - _i4.SemanticsUpdateBuilder createSemanticsUpdateBuilder() => - (super.noSuchMethod(Invocation.method(#createSemanticsUpdateBuilder, []), - returnValue: _FakeSemanticsUpdateBuilder_17()) - as _i4.SemanticsUpdateBuilder); -} - -/// A class which mocks [FrameTiming]. -/// -/// See the documentation for Mockito's code generation for more information. -class MockFrameTiming extends _i1.Mock implements _i4.FrameTiming { - MockFrameTiming() { - _i1.throwOnMissingStub(this); - } - - @override - Duration get buildDuration => - (super.noSuchMethod(Invocation.getter(#buildDuration), - returnValue: _FakeDuration_8()) as Duration); - @override - Duration get rasterDuration => - (super.noSuchMethod(Invocation.getter(#rasterDuration), - returnValue: _FakeDuration_8()) as Duration); - @override - Duration get vsyncOverhead => - (super.noSuchMethod(Invocation.getter(#vsyncOverhead), - returnValue: _FakeDuration_8()) as Duration); - @override - Duration get totalSpan => (super.noSuchMethod(Invocation.getter(#totalSpan), - returnValue: _FakeDuration_8()) as Duration); - @override - int get layerCacheCount => - (super.noSuchMethod(Invocation.getter(#layerCacheCount), returnValue: 0) - as int); - @override - int get layerCacheBytes => - (super.noSuchMethod(Invocation.getter(#layerCacheBytes), returnValue: 0) - as int); - @override - double get layerCacheMegabytes => - (super.noSuchMethod(Invocation.getter(#layerCacheMegabytes), - returnValue: 0.0) as double); - @override - int get pictureCacheCount => - (super.noSuchMethod(Invocation.getter(#pictureCacheCount), returnValue: 0) - as int); - @override - int get pictureCacheBytes => - (super.noSuchMethod(Invocation.getter(#pictureCacheBytes), returnValue: 0) - as int); - @override - double get pictureCacheMegabytes => - (super.noSuchMethod(Invocation.getter(#pictureCacheMegabytes), - returnValue: 0.0) as double); - @override - int get frameNumber => - (super.noSuchMethod(Invocation.getter(#frameNumber), returnValue: 0) - as int); - @override - int timestampInMicroseconds(_i4.FramePhase? phase) => - (super.noSuchMethod(Invocation.method(#timestampInMicroseconds, [phase]), - returnValue: 0) as int); -} From 548513209f9f38e20513b6ff1de5e9bb8760a5ce Mon Sep 17 00:00:00 2001 From: Andrew Amin Date: Tue, 29 Jul 2025 16:44:11 +0300 Subject: [PATCH 39/84] chore: update Instabug dependency to version 15.1.17 in Podfile and related files --- example/ios/Podfile | 2 +- example/ios/Podfile.lock | 14 +++++++------- ios/instabug_flutter.podspec | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/example/ios/Podfile b/example/ios/Podfile index f74d6afed..a6e26b957 100644 --- a/example/ios/Podfile +++ b/example/ios/Podfile @@ -30,7 +30,7 @@ target 'Runner' do use_frameworks! use_modular_headers! - pod 'Instabug', :podspec => 'https://ios-releases.instabug.com/custom/faeture-screen_rendering-release/15.1.13/Instabug.podspec' + pod 'Instabug', :podspec => 'https://ios-releases.instabug.com/custom/faeture-screen_rendering-release/15.1.17/Instabug.podspec' flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) end diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index f691b0f5f..45894bba4 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -1,14 +1,14 @@ PODS: - Flutter (1.0.0) - - Instabug (15.1.13) + - Instabug (15.1.17) - instabug_flutter (14.3.0): - Flutter - - Instabug (= 15.1.13) + - Instabug (= 15.1.17) - OCMock (3.6) DEPENDENCIES: - Flutter (from `Flutter`) - - Instabug (from `https://ios-releases.instabug.com/custom/faeture-screen_rendering-release/15.1.13/Instabug.podspec`) + - Instabug (from `https://ios-releases.instabug.com/custom/faeture-screen_rendering-release/15.1.17/Instabug.podspec`) - instabug_flutter (from `.symlinks/plugins/instabug_flutter/ios`) - OCMock (= 3.6) @@ -20,16 +20,16 @@ EXTERNAL SOURCES: Flutter: :path: Flutter Instabug: - :podspec: https://ios-releases.instabug.com/custom/faeture-screen_rendering-release/15.1.13/Instabug.podspec + :podspec: https://ios-releases.instabug.com/custom/faeture-screen_rendering-release/15.1.17/Instabug.podspec instabug_flutter: :path: ".symlinks/plugins/instabug_flutter/ios" SPEC CHECKSUMS: Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 - Instabug: 697dc090bbdb9b99a9a91758558f8a2014ee5725 - instabug_flutter: 1093324eaca70f9d310a4bc7f1f3537c746c1d6c + Instabug: 316559a02c9b752a3854a6453c2fa414d36252f3 + instabug_flutter: 7ae7f3d1c47b9a699e76a7358b6a3e818a253ac3 OCMock: 5ea90566be239f179ba766fd9fbae5885040b992 -PODFILE CHECKSUM: 509cc3728286920762d8cbecfac090a3af93635d +PODFILE CHECKSUM: 8f3e14dab36cc02b0a8767c3086e109fadaa55f3 COCOAPODS: 1.15.2 diff --git a/ios/instabug_flutter.podspec b/ios/instabug_flutter.podspec index 002c8d443..4cda9fd30 100644 --- a/ios/instabug_flutter.podspec +++ b/ios/instabug_flutter.podspec @@ -17,6 +17,6 @@ Pod::Spec.new do |s| s.pod_target_xcconfig = { 'OTHER_LDFLAGS' => '-framework "Flutter" -framework "InstabugSDK"'} s.dependency 'Flutter' - s.dependency 'Instabug', '15.1.13' + s.dependency 'Instabug', '15.1.17' end From a49ae10f3ef7dc631c1a74f305387048bc5a8e0a Mon Sep 17 00:00:00 2001 From: Andrew Amin Date: Wed, 30 Jul 2025 10:36:25 +0300 Subject: [PATCH 40/84] prepare for ci --- .../instabug_screen_render_manager.dart | 16 +- .../instabug_screen_render_manager_test.dart | 2 +- ...reen_render_manager_test_manual_mocks.dart | 759 ++++++++++++++++++ 3 files changed, 761 insertions(+), 16 deletions(-) create mode 100644 test/utils/screen_render/instabug_screen_render_manager_test_manual_mocks.dart diff --git a/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart b/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart index f36ed475d..eed37d9e5 100644 --- a/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart +++ b/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart @@ -1,6 +1,5 @@ import 'dart:async'; -import 'dart:developer' show log; -import 'dart:ui'; +import 'dart:ui' show TimingsCallback, FrameTiming, FramePhase; import 'package:flutter/widgets.dart'; import 'package:instabug_flutter/src/models/instabug_frame_data.dart'; @@ -301,10 +300,6 @@ class InstabugScreenRenderManager { /// Save Slow/Frozen Frames data void _onDelayedFrameDetected(int startTime, int durationInMicroseconds) { - log( - "${durationInMicroseconds >= 700000 ? "🚨Frozen" : "⚠️Slow"} Frame Detected (startTime: $startTime, duration: $durationInMicroseconds µs)", - name: tag, - ); _delayedFrames.add( InstabugFrameData( startTime, @@ -320,10 +315,6 @@ class InstabugScreenRenderManager { InstabugScreenRenderData screenRenderData, ) async { try { - log( - "reportScreenRenderForCustomUiTrace $screenRenderData", - name: tag, - ); await APM.endScreenRenderForCustomUiTrace(screenRenderData); return true; } catch (error, stackTrace) { @@ -341,11 +332,6 @@ class InstabugScreenRenderManager { try { // Save the end time for the running ui trace, it's only needed in Android SDK. screenRenderData.saveEndTime(); - - log( - "reportScreenRenderForAutoUiTrace $screenRenderData", - name: tag, - ); await APM.endScreenRenderForAutoUiTrace(screenRenderData); return true; diff --git a/test/utils/screen_render/instabug_screen_render_manager_test.dart b/test/utils/screen_render/instabug_screen_render_manager_test.dart index 9f99ac0f4..4565f22fb 100644 --- a/test/utils/screen_render/instabug_screen_render_manager_test.dart +++ b/test/utils/screen_render/instabug_screen_render_manager_test.dart @@ -5,7 +5,7 @@ import 'package:instabug_flutter/src/models/instabug_screen_render_data.dart'; import 'package:instabug_flutter/src/utils/screen_rendering/instabug_screen_render_manager.dart'; import 'package:mockito/mockito.dart'; -import 'instabug_screen_render_manager_test.mocks.dart'; +import 'instabug_screen_render_manager_test_manual_mocks.dart'; void main() { TestWidgetsFlutterBinding.ensureInitialized(); diff --git a/test/utils/screen_render/instabug_screen_render_manager_test_manual_mocks.dart b/test/utils/screen_render/instabug_screen_render_manager_test_manual_mocks.dart new file mode 100644 index 000000000..4e363eb75 --- /dev/null +++ b/test/utils/screen_render/instabug_screen_render_manager_test_manual_mocks.dart @@ -0,0 +1,759 @@ +// Mocks generated by Mockito 5.2.0 from annotations +// in instabug_flutter/example/ios/.symlinks/plugins/instabug_flutter/test/utils/screen_render/instabug_screen_render_manager_test.dart. +// Do not manually edit this file. + +import 'dart:async' as _i9; +import 'dart:developer' as _i13; +import 'dart:ui' as _i4; + +import 'package:flutter/foundation.dart' as _i3; +import 'package:flutter/gestures.dart' as _i6; +import 'package:flutter/rendering.dart' as _i7; +import 'package:flutter/scheduler.dart' as _i11; +import 'package:flutter/services.dart' as _i5; +import 'package:flutter/src/widgets/binding.dart' as _i10; +import 'package:flutter/src/widgets/focus_manager.dart' as _i2; +import 'package:flutter/src/widgets/framework.dart' as _i12; +import 'package:instabug_flutter/src/generated/apm.api.g.dart' as _i8; +import 'package:mockito/mockito.dart' as _i1; + +// ignore_for_file: type=lint +// ignore_for_file: avoid_redundant_argument_values +// ignore_for_file: avoid_setters_without_getters +// ignore_for_file: comment_references +// ignore_for_file: implementation_imports +// ignore_for_file: invalid_use_of_visible_for_testing_member +// ignore_for_file: prefer_const_constructors +// ignore_for_file: unnecessary_parenthesis +// ignore_for_file: camel_case_types + +class _FakeFocusManager_0 extends _i1.Fake implements _i2.FocusManager { + @override + String toString({_i3.DiagnosticLevel? minLevel = _i3.DiagnosticLevel.info}) => + super.toString(); +} + +class _FakeSingletonFlutterWindow_1 extends _i1.Fake + implements _i4.SingletonFlutterWindow {} + +class _FakePlatformDispatcher_2 extends _i1.Fake + implements _i4.PlatformDispatcher {} + +class _FakeHardwareKeyboard_3 extends _i1.Fake + implements _i5.HardwareKeyboard {} + +class _FakeKeyEventManager_4 extends _i1.Fake implements _i5.KeyEventManager {} + +class _FakeBinaryMessenger_5 extends _i1.Fake implements _i5.BinaryMessenger {} + +class _FakeChannelBuffers_6 extends _i1.Fake implements _i4.ChannelBuffers {} + +class _FakeRestorationManager_7 extends _i1.Fake + implements _i5.RestorationManager {} + +class _FakeDuration_8 extends _i1.Fake implements Duration {} + +class _FakePointerRouter_9 extends _i1.Fake implements _i6.PointerRouter {} + +class _FakeGestureArenaManager_10 extends _i1.Fake + implements _i6.GestureArenaManager {} + +class _FakePointerSignalResolver_11 extends _i1.Fake + implements _i6.PointerSignalResolver {} + +class _FakeMouseTracker_12 extends _i1.Fake implements _i7.MouseTracker {} + +class _FakePipelineOwner_13 extends _i1.Fake implements _i7.PipelineOwner {} + +class _FakeRenderView_14 extends _i1.Fake implements _i7.RenderView { + @override + String toString({_i3.DiagnosticLevel? minLevel = _i3.DiagnosticLevel.info}) => + super.toString(); +} + +class _FakeAccessibilityFeatures_15 extends _i1.Fake + implements _i4.AccessibilityFeatures {} + +class _FakeViewConfiguration_16 extends _i1.Fake + implements _i7.ViewConfiguration {} + +class _FakeSemanticsUpdateBuilder_17 extends _i1.Fake + implements _i4.SemanticsUpdateBuilder {} + +/// A class which mocks [ApmHostApi]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockApmHostApi extends _i1.Mock implements _i8.ApmHostApi { + MockApmHostApi() { + _i1.throwOnMissingStub(this); + } + + @override + _i9.Future setEnabled(bool? arg_isEnabled) => + (super.noSuchMethod(Invocation.method(#setEnabled, [arg_isEnabled]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future isEnabled() => + (super.noSuchMethod(Invocation.method(#isEnabled, []), + returnValue: Future.value(false)) as _i9.Future); + @override + _i9.Future setScreenLoadingEnabled(bool? arg_isEnabled) => + (super.noSuchMethod( + Invocation.method(#setScreenLoadingEnabled, [arg_isEnabled]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future isScreenLoadingEnabled() => + (super.noSuchMethod(Invocation.method(#isScreenLoadingEnabled, []), + returnValue: Future.value(false)) as _i9.Future); + @override + _i9.Future setColdAppLaunchEnabled(bool? arg_isEnabled) => + (super.noSuchMethod( + Invocation.method(#setColdAppLaunchEnabled, [arg_isEnabled]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future setAutoUITraceEnabled(bool? arg_isEnabled) => (super + .noSuchMethod(Invocation.method(#setAutoUITraceEnabled, [arg_isEnabled]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future startExecutionTrace(String? arg_id, String? arg_name) => + (super.noSuchMethod( + Invocation.method(#startExecutionTrace, [arg_id, arg_name]), + returnValue: Future.value()) as _i9.Future); + @override + _i9.Future startFlow(String? arg_name) => + (super.noSuchMethod(Invocation.method(#startFlow, [arg_name]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future setFlowAttribute( + String? arg_name, String? arg_key, String? arg_value) => + (super.noSuchMethod( + Invocation.method(#setFlowAttribute, [arg_name, arg_key, arg_value]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future endFlow(String? arg_name) => + (super.noSuchMethod(Invocation.method(#endFlow, [arg_name]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future setExecutionTraceAttribute( + String? arg_id, String? arg_key, String? arg_value) => + (super.noSuchMethod( + Invocation.method( + #setExecutionTraceAttribute, [arg_id, arg_key, arg_value]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future endExecutionTrace(String? arg_id) => + (super.noSuchMethod(Invocation.method(#endExecutionTrace, [arg_id]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future startUITrace(String? arg_name) => + (super.noSuchMethod(Invocation.method(#startUITrace, [arg_name]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future endUITrace() => + (super.noSuchMethod(Invocation.method(#endUITrace, []), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future endAppLaunch() => + (super.noSuchMethod(Invocation.method(#endAppLaunch, []), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future networkLogAndroid(Map? arg_data) => + (super.noSuchMethod(Invocation.method(#networkLogAndroid, [arg_data]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future startCpUiTrace( + String? arg_screenName, int? arg_microTimeStamp, int? arg_traceId) => + (super.noSuchMethod( + Invocation.method(#startCpUiTrace, + [arg_screenName, arg_microTimeStamp, arg_traceId]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future reportScreenLoadingCP(int? arg_startTimeStampMicro, + int? arg_durationMicro, int? arg_uiTraceId) => + (super.noSuchMethod( + Invocation.method(#reportScreenLoadingCP, + [arg_startTimeStampMicro, arg_durationMicro, arg_uiTraceId]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future endScreenLoadingCP( + int? arg_timeStampMicro, int? arg_uiTraceId) => + (super.noSuchMethod( + Invocation.method( + #endScreenLoadingCP, [arg_timeStampMicro, arg_uiTraceId]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future isEndScreenLoadingEnabled() => + (super.noSuchMethod(Invocation.method(#isEndScreenLoadingEnabled, []), + returnValue: Future.value(false)) as _i9.Future); + @override + _i9.Future isScreenRenderEnabled() => + (super.noSuchMethod(Invocation.method(#isScreenRenderEnabled, []), + returnValue: Future.value(false)) as _i9.Future); + @override + _i9.Future deviceRefreshRate() => + (super.noSuchMethod(Invocation.method(#deviceRefreshRate, []), + returnValue: Future.value(0.0)) as _i9.Future); + @override + _i9.Future setScreenRenderEnabled(bool? arg_isEnabled) => (super + .noSuchMethod(Invocation.method(#setScreenRenderEnabled, [arg_isEnabled]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future endScreenRenderForAutoUiTrace( + Map? arg_data) => + (super.noSuchMethod( + Invocation.method(#endScreenRenderForAutoUiTrace, [arg_data]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future endScreenRenderForCustomUiTrace( + Map? arg_data) => + (super.noSuchMethod( + Invocation.method(#endScreenRenderForCustomUiTrace, [arg_data]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); +} + +/// A class which mocks [WidgetsBinding]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockWidgetsBinding extends _i1.Mock implements _i10.WidgetsBinding { + MockWidgetsBinding() { + _i1.throwOnMissingStub(this); + } + + @override + bool get debugBuildingDirtyElements => + (super.noSuchMethod(Invocation.getter(#debugBuildingDirtyElements), + returnValue: false) as bool); + @override + set debugBuildingDirtyElements(bool? _debugBuildingDirtyElements) => + super.noSuchMethod( + Invocation.setter( + #debugBuildingDirtyElements, _debugBuildingDirtyElements), + returnValueForMissingStub: null); + @override + _i2.FocusManager get focusManager => + (super.noSuchMethod(Invocation.getter(#focusManager), + returnValue: _FakeFocusManager_0()) as _i2.FocusManager); + @override + bool get firstFrameRasterized => + (super.noSuchMethod(Invocation.getter(#firstFrameRasterized), + returnValue: false) as bool); + @override + _i9.Future get waitUntilFirstFrameRasterized => + (super.noSuchMethod(Invocation.getter(#waitUntilFirstFrameRasterized), + returnValue: Future.value()) as _i9.Future); + @override + bool get debugDidSendFirstFrameEvent => + (super.noSuchMethod(Invocation.getter(#debugDidSendFirstFrameEvent), + returnValue: false) as bool); + @override + bool get framesEnabled => + (super.noSuchMethod(Invocation.getter(#framesEnabled), returnValue: false) + as bool); + @override + bool get isRootWidgetAttached => + (super.noSuchMethod(Invocation.getter(#isRootWidgetAttached), + returnValue: false) as bool); + @override + _i4.SingletonFlutterWindow get window => + (super.noSuchMethod(Invocation.getter(#window), + returnValue: _FakeSingletonFlutterWindow_1()) + as _i4.SingletonFlutterWindow); + @override + _i4.PlatformDispatcher get platformDispatcher => + (super.noSuchMethod(Invocation.getter(#platformDispatcher), + returnValue: _FakePlatformDispatcher_2()) as _i4.PlatformDispatcher); + @override + bool get locked => + (super.noSuchMethod(Invocation.getter(#locked), returnValue: false) + as bool); + @override + _i5.HardwareKeyboard get keyboard => + (super.noSuchMethod(Invocation.getter(#keyboard), + returnValue: _FakeHardwareKeyboard_3()) as _i5.HardwareKeyboard); + @override + _i5.KeyEventManager get keyEventManager => + (super.noSuchMethod(Invocation.getter(#keyEventManager), + returnValue: _FakeKeyEventManager_4()) as _i5.KeyEventManager); + @override + _i5.BinaryMessenger get defaultBinaryMessenger => + (super.noSuchMethod(Invocation.getter(#defaultBinaryMessenger), + returnValue: _FakeBinaryMessenger_5()) as _i5.BinaryMessenger); + @override + _i4.ChannelBuffers get channelBuffers => + (super.noSuchMethod(Invocation.getter(#channelBuffers), + returnValue: _FakeChannelBuffers_6()) as _i4.ChannelBuffers); + @override + _i5.RestorationManager get restorationManager => + (super.noSuchMethod(Invocation.getter(#restorationManager), + returnValue: _FakeRestorationManager_7()) as _i5.RestorationManager); + @override + _i11.SchedulingStrategy get schedulingStrategy => + (super.noSuchMethod(Invocation.getter(#schedulingStrategy), + returnValue: ({int? priority, _i11.SchedulerBinding? scheduler}) => + false) as _i11.SchedulingStrategy); + @override + set schedulingStrategy(_i11.SchedulingStrategy? _schedulingStrategy) => super + .noSuchMethod(Invocation.setter(#schedulingStrategy, _schedulingStrategy), + returnValueForMissingStub: null); + @override + int get transientCallbackCount => + (super.noSuchMethod(Invocation.getter(#transientCallbackCount), + returnValue: 0) as int); + @override + _i9.Future get endOfFrame => + (super.noSuchMethod(Invocation.getter(#endOfFrame), + returnValue: Future.value()) as _i9.Future); + @override + bool get hasScheduledFrame => + (super.noSuchMethod(Invocation.getter(#hasScheduledFrame), + returnValue: false) as bool); + @override + _i11.SchedulerPhase get schedulerPhase => + (super.noSuchMethod(Invocation.getter(#schedulerPhase), + returnValue: _i11.SchedulerPhase.idle) as _i11.SchedulerPhase); + @override + Duration get currentFrameTimeStamp => + (super.noSuchMethod(Invocation.getter(#currentFrameTimeStamp), + returnValue: _FakeDuration_8()) as Duration); + @override + Duration get currentSystemFrameTimeStamp => + (super.noSuchMethod(Invocation.getter(#currentSystemFrameTimeStamp), + returnValue: _FakeDuration_8()) as Duration); + @override + _i6.PointerRouter get pointerRouter => + (super.noSuchMethod(Invocation.getter(#pointerRouter), + returnValue: _FakePointerRouter_9()) as _i6.PointerRouter); + @override + _i6.GestureArenaManager get gestureArena => (super.noSuchMethod( + Invocation.getter(#gestureArena), + returnValue: _FakeGestureArenaManager_10()) as _i6.GestureArenaManager); + @override + _i6.PointerSignalResolver get pointerSignalResolver => + (super.noSuchMethod(Invocation.getter(#pointerSignalResolver), + returnValue: _FakePointerSignalResolver_11()) + as _i6.PointerSignalResolver); + @override + bool get resamplingEnabled => + (super.noSuchMethod(Invocation.getter(#resamplingEnabled), + returnValue: false) as bool); + @override + set resamplingEnabled(bool? _resamplingEnabled) => super.noSuchMethod( + Invocation.setter(#resamplingEnabled, _resamplingEnabled), + returnValueForMissingStub: null); + @override + Duration get samplingOffset => + (super.noSuchMethod(Invocation.getter(#samplingOffset), + returnValue: _FakeDuration_8()) as Duration); + @override + set samplingOffset(Duration? _samplingOffset) => + super.noSuchMethod(Invocation.setter(#samplingOffset, _samplingOffset), + returnValueForMissingStub: null); + @override + _i7.MouseTracker get mouseTracker => + (super.noSuchMethod(Invocation.getter(#mouseTracker), + returnValue: _FakeMouseTracker_12()) as _i7.MouseTracker); + @override + _i7.PipelineOwner get pipelineOwner => + (super.noSuchMethod(Invocation.getter(#pipelineOwner), + returnValue: _FakePipelineOwner_13()) as _i7.PipelineOwner); + @override + _i7.RenderView get renderView => + (super.noSuchMethod(Invocation.getter(#renderView), + returnValue: _FakeRenderView_14()) as _i7.RenderView); + @override + set renderView(_i7.RenderView? value) => + super.noSuchMethod(Invocation.setter(#renderView, value), + returnValueForMissingStub: null); + @override + bool get sendFramesToEngine => + (super.noSuchMethod(Invocation.getter(#sendFramesToEngine), + returnValue: false) as bool); + @override + _i4.AccessibilityFeatures get accessibilityFeatures => + (super.noSuchMethod(Invocation.getter(#accessibilityFeatures), + returnValue: _FakeAccessibilityFeatures_15()) + as _i4.AccessibilityFeatures); + @override + bool get disableAnimations => + (super.noSuchMethod(Invocation.getter(#disableAnimations), + returnValue: false) as bool); + @override + void initInstances() => + super.noSuchMethod(Invocation.method(#initInstances, []), + returnValueForMissingStub: null); + @override + void initServiceExtensions() => + super.noSuchMethod(Invocation.method(#initServiceExtensions, []), + returnValueForMissingStub: null); + @override + void addObserver(_i10.WidgetsBindingObserver? observer) => + super.noSuchMethod(Invocation.method(#addObserver, [observer]), + returnValueForMissingStub: null); + @override + bool removeObserver(_i10.WidgetsBindingObserver? observer) => + (super.noSuchMethod(Invocation.method(#removeObserver, [observer]), + returnValue: false) as bool); + @override + void handleMetricsChanged() => + super.noSuchMethod(Invocation.method(#handleMetricsChanged, []), + returnValueForMissingStub: null); + @override + void handleTextScaleFactorChanged() => + super.noSuchMethod(Invocation.method(#handleTextScaleFactorChanged, []), + returnValueForMissingStub: null); + @override + void handlePlatformBrightnessChanged() => super.noSuchMethod( + Invocation.method(#handlePlatformBrightnessChanged, []), + returnValueForMissingStub: null); + @override + void handleAccessibilityFeaturesChanged() => super.noSuchMethod( + Invocation.method(#handleAccessibilityFeaturesChanged, []), + returnValueForMissingStub: null); + @override + void handleLocaleChanged() => + super.noSuchMethod(Invocation.method(#handleLocaleChanged, []), + returnValueForMissingStub: null); + @override + void dispatchLocalesChanged(List<_i4.Locale>? locales) => + super.noSuchMethod(Invocation.method(#dispatchLocalesChanged, [locales]), + returnValueForMissingStub: null); + @override + void dispatchAccessibilityFeaturesChanged() => super.noSuchMethod( + Invocation.method(#dispatchAccessibilityFeaturesChanged, []), + returnValueForMissingStub: null); + @override + _i9.Future handlePopRoute() => + (super.noSuchMethod(Invocation.method(#handlePopRoute, []), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future handlePushRoute(String? route) => + (super.noSuchMethod(Invocation.method(#handlePushRoute, [route]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + void handleAppLifecycleStateChanged(_i4.AppLifecycleState? state) => super + .noSuchMethod(Invocation.method(#handleAppLifecycleStateChanged, [state]), + returnValueForMissingStub: null); + @override + void handleMemoryPressure() => + super.noSuchMethod(Invocation.method(#handleMemoryPressure, []), + returnValueForMissingStub: null); + @override + void drawFrame() => super.noSuchMethod(Invocation.method(#drawFrame, []), + returnValueForMissingStub: null); + @override + void scheduleAttachRootWidget(_i12.Widget? rootWidget) => super.noSuchMethod( + Invocation.method(#scheduleAttachRootWidget, [rootWidget]), + returnValueForMissingStub: null); + @override + void attachRootWidget(_i12.Widget? rootWidget) => + super.noSuchMethod(Invocation.method(#attachRootWidget, [rootWidget]), + returnValueForMissingStub: null); + @override + _i9.Future performReassemble() => + (super.noSuchMethod(Invocation.method(#performReassemble, []), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i4.Locale? computePlatformResolvedLocale( + List<_i4.Locale>? supportedLocales) => + (super.noSuchMethod(Invocation.method( + #computePlatformResolvedLocale, [supportedLocales])) as _i4.Locale?); + @override + _i9.Future lockEvents(_i9.Future Function()? callback) => + (super.noSuchMethod(Invocation.method(#lockEvents, [callback]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + void unlocked() => super.noSuchMethod(Invocation.method(#unlocked, []), + returnValueForMissingStub: null); + @override + _i9.Future reassembleApplication() => + (super.noSuchMethod(Invocation.method(#reassembleApplication, []), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + void registerSignalServiceExtension( + {String? name, _i3.AsyncCallback? callback}) => + super.noSuchMethod( + Invocation.method(#registerSignalServiceExtension, [], + {#name: name, #callback: callback}), + returnValueForMissingStub: null); + @override + void registerBoolServiceExtension( + {String? name, + _i3.AsyncValueGetter? getter, + _i3.AsyncValueSetter? setter}) => + super.noSuchMethod( + Invocation.method(#registerBoolServiceExtension, [], + {#name: name, #getter: getter, #setter: setter}), + returnValueForMissingStub: null); + @override + void registerNumericServiceExtension( + {String? name, + _i3.AsyncValueGetter? getter, + _i3.AsyncValueSetter? setter}) => + super.noSuchMethod( + Invocation.method(#registerNumericServiceExtension, [], + {#name: name, #getter: getter, #setter: setter}), + returnValueForMissingStub: null); + @override + void postEvent(String? eventKind, Map? eventData) => + super.noSuchMethod(Invocation.method(#postEvent, [eventKind, eventData]), + returnValueForMissingStub: null); + @override + void registerStringServiceExtension( + {String? name, + _i3.AsyncValueGetter? getter, + _i3.AsyncValueSetter? setter}) => + super.noSuchMethod( + Invocation.method(#registerStringServiceExtension, [], + {#name: name, #getter: getter, #setter: setter}), + returnValueForMissingStub: null); + @override + void registerServiceExtension( + {String? name, _i3.ServiceExtensionCallback? callback}) => + super.noSuchMethod( + Invocation.method(#registerServiceExtension, [], + {#name: name, #callback: callback}), + returnValueForMissingStub: null); + @override + _i5.BinaryMessenger createBinaryMessenger() => + (super.noSuchMethod(Invocation.method(#createBinaryMessenger, []), + returnValue: _FakeBinaryMessenger_5()) as _i5.BinaryMessenger); + @override + _i9.Future handleSystemMessage(Object? systemMessage) => (super + .noSuchMethod(Invocation.method(#handleSystemMessage, [systemMessage]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + void initLicenses() => + super.noSuchMethod(Invocation.method(#initLicenses, []), + returnValueForMissingStub: null); + @override + void evict(String? asset) => + super.noSuchMethod(Invocation.method(#evict, [asset]), + returnValueForMissingStub: null); + @override + void readInitialLifecycleStateFromNativeWindow() => super.noSuchMethod( + Invocation.method(#readInitialLifecycleStateFromNativeWindow, []), + returnValueForMissingStub: null); + @override + _i5.RestorationManager createRestorationManager() => + (super.noSuchMethod(Invocation.method(#createRestorationManager, []), + returnValue: _FakeRestorationManager_7()) as _i5.RestorationManager); + @override + void setSystemUiChangeCallback(_i5.SystemUiChangeCallback? callback) => super + .noSuchMethod(Invocation.method(#setSystemUiChangeCallback, [callback]), + returnValueForMissingStub: null); + @override + void addTimingsCallback(_i4.TimingsCallback? callback) => + super.noSuchMethod(Invocation.method(#addTimingsCallback, [callback]), + returnValueForMissingStub: null); + @override + void removeTimingsCallback(_i4.TimingsCallback? callback) => + super.noSuchMethod(Invocation.method(#removeTimingsCallback, [callback]), + returnValueForMissingStub: null); + @override + _i9.Future scheduleTask( + _i11.TaskCallback? task, _i11.Priority? priority, + {String? debugLabel, _i13.Flow? flow}) => + (super.noSuchMethod( + Invocation.method(#scheduleTask, [task, priority], + {#debugLabel: debugLabel, #flow: flow}), + returnValue: Future.value(null)) as _i9.Future); + @override + bool handleEventLoopCallback() => + (super.noSuchMethod(Invocation.method(#handleEventLoopCallback, []), + returnValue: false) as bool); + @override + int scheduleFrameCallback(_i11.FrameCallback? callback, + {bool? rescheduling = false}) => + (super.noSuchMethod( + Invocation.method(#scheduleFrameCallback, [callback], + {#rescheduling: rescheduling}), + returnValue: 0) as int); + @override + void cancelFrameCallbackWithId(int? id) => + super.noSuchMethod(Invocation.method(#cancelFrameCallbackWithId, [id]), + returnValueForMissingStub: null); + @override + bool debugAssertNoTransientCallbacks(String? reason) => (super.noSuchMethod( + Invocation.method(#debugAssertNoTransientCallbacks, [reason]), + returnValue: false) as bool); + @override + void addPersistentFrameCallback(_i11.FrameCallback? callback) => super + .noSuchMethod(Invocation.method(#addPersistentFrameCallback, [callback]), + returnValueForMissingStub: null); + @override + void addPostFrameCallback(_i11.FrameCallback? callback) => + super.noSuchMethod(Invocation.method(#addPostFrameCallback, [callback]), + returnValueForMissingStub: null); + @override + void ensureFrameCallbacksRegistered() => + super.noSuchMethod(Invocation.method(#ensureFrameCallbacksRegistered, []), + returnValueForMissingStub: null); + @override + void ensureVisualUpdate() => + super.noSuchMethod(Invocation.method(#ensureVisualUpdate, []), + returnValueForMissingStub: null); + @override + void scheduleFrame() => + super.noSuchMethod(Invocation.method(#scheduleFrame, []), + returnValueForMissingStub: null); + @override + void scheduleForcedFrame() => + super.noSuchMethod(Invocation.method(#scheduleForcedFrame, []), + returnValueForMissingStub: null); + @override + void scheduleWarmUpFrame() => + super.noSuchMethod(Invocation.method(#scheduleWarmUpFrame, []), + returnValueForMissingStub: null); + @override + void resetEpoch() => super.noSuchMethod(Invocation.method(#resetEpoch, []), + returnValueForMissingStub: null); + @override + void handleBeginFrame(Duration? rawTimeStamp) => + super.noSuchMethod(Invocation.method(#handleBeginFrame, [rawTimeStamp]), + returnValueForMissingStub: null); + @override + void handleDrawFrame() => + super.noSuchMethod(Invocation.method(#handleDrawFrame, []), + returnValueForMissingStub: null); + @override + void cancelPointer(int? pointer) => + super.noSuchMethod(Invocation.method(#cancelPointer, [pointer]), + returnValueForMissingStub: null); + @override + void handlePointerEvent(_i7.PointerEvent? event) => + super.noSuchMethod(Invocation.method(#handlePointerEvent, [event]), + returnValueForMissingStub: null); + @override + void hitTest(_i7.HitTestResult? result, _i4.Offset? position) => + super.noSuchMethod(Invocation.method(#hitTest, [result, position]), + returnValueForMissingStub: null); + @override + void dispatchEvent( + _i7.PointerEvent? event, _i7.HitTestResult? hitTestResult) => + super.noSuchMethod( + Invocation.method(#dispatchEvent, [event, hitTestResult]), + returnValueForMissingStub: null); + @override + void handleEvent(_i7.PointerEvent? event, _i7.HitTestEntry? entry) => + super.noSuchMethod(Invocation.method(#handleEvent, [event, entry]), + returnValueForMissingStub: null); + @override + void resetGestureBinding() => + super.noSuchMethod(Invocation.method(#resetGestureBinding, []), + returnValueForMissingStub: null); + @override + void initRenderView() => + super.noSuchMethod(Invocation.method(#initRenderView, []), + returnValueForMissingStub: null); + @override + _i7.ViewConfiguration createViewConfiguration() => + (super.noSuchMethod(Invocation.method(#createViewConfiguration, []), + returnValue: _FakeViewConfiguration_16()) as _i7.ViewConfiguration); + @override + void initMouseTracker([_i7.MouseTracker? tracker]) => + super.noSuchMethod(Invocation.method(#initMouseTracker, [tracker]), + returnValueForMissingStub: null); + @override + void setSemanticsEnabled(bool? enabled) => + super.noSuchMethod(Invocation.method(#setSemanticsEnabled, [enabled]), + returnValueForMissingStub: null); + @override + void deferFirstFrame() => + super.noSuchMethod(Invocation.method(#deferFirstFrame, []), + returnValueForMissingStub: null); + @override + void allowFirstFrame() => + super.noSuchMethod(Invocation.method(#allowFirstFrame, []), + returnValueForMissingStub: null); + @override + void resetFirstFrameSent() => + super.noSuchMethod(Invocation.method(#resetFirstFrameSent, []), + returnValueForMissingStub: null); + @override + _i4.SemanticsUpdateBuilder createSemanticsUpdateBuilder() => + (super.noSuchMethod(Invocation.method(#createSemanticsUpdateBuilder, []), + returnValue: _FakeSemanticsUpdateBuilder_17()) + as _i4.SemanticsUpdateBuilder); +} + +/// A class which mocks [FrameTiming]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockFrameTiming extends _i1.Mock implements _i4.FrameTiming { + MockFrameTiming() { + _i1.throwOnMissingStub(this); + } + + @override + Duration get buildDuration => + (super.noSuchMethod(Invocation.getter(#buildDuration), + returnValue: _FakeDuration_8()) as Duration); + @override + Duration get rasterDuration => + (super.noSuchMethod(Invocation.getter(#rasterDuration), + returnValue: _FakeDuration_8()) as Duration); + @override + Duration get vsyncOverhead => + (super.noSuchMethod(Invocation.getter(#vsyncOverhead), + returnValue: _FakeDuration_8()) as Duration); + @override + Duration get totalSpan => (super.noSuchMethod(Invocation.getter(#totalSpan), + returnValue: _FakeDuration_8()) as Duration); + @override + int get layerCacheCount => + (super.noSuchMethod(Invocation.getter(#layerCacheCount), returnValue: 0) + as int); + @override + int get layerCacheBytes => + (super.noSuchMethod(Invocation.getter(#layerCacheBytes), returnValue: 0) + as int); + @override + double get layerCacheMegabytes => + (super.noSuchMethod(Invocation.getter(#layerCacheMegabytes), + returnValue: 0.0) as double); + @override + int get pictureCacheCount => + (super.noSuchMethod(Invocation.getter(#pictureCacheCount), returnValue: 0) + as int); + @override + int get pictureCacheBytes => + (super.noSuchMethod(Invocation.getter(#pictureCacheBytes), returnValue: 0) + as int); + @override + double get pictureCacheMegabytes => + (super.noSuchMethod(Invocation.getter(#pictureCacheMegabytes), + returnValue: 0.0) as double); + @override + int get frameNumber => + (super.noSuchMethod(Invocation.getter(#frameNumber), returnValue: 0) + as int); + @override + int timestampInMicroseconds(_i4.FramePhase? phase) => + (super.noSuchMethod(Invocation.method(#timestampInMicroseconds, [phase]), + returnValue: 0) as int); +} From 6227629be527b39c21447dc3fb040c6b70e90a35 Mon Sep 17 00:00:00 2001 From: Andrew Amin Date: Wed, 30 Jul 2025 16:56:21 +0300 Subject: [PATCH 41/84] update ios pods --- example/ios/Podfile | 2 +- example/ios/Podfile.lock | 14 +- ios/instabug_flutter.podspec | 2 +- .../instabug_screen_render_manager.dart | 13 + .../instabug_screen_render_manager_test.dart | 2 +- ...reen_render_manager_test_manual_mocks.dart | 759 ------------------ 6 files changed, 23 insertions(+), 769 deletions(-) delete mode 100644 test/utils/screen_render/instabug_screen_render_manager_test_manual_mocks.dart diff --git a/example/ios/Podfile b/example/ios/Podfile index a6e26b957..ee4476ba0 100644 --- a/example/ios/Podfile +++ b/example/ios/Podfile @@ -30,7 +30,7 @@ target 'Runner' do use_frameworks! use_modular_headers! - pod 'Instabug', :podspec => 'https://ios-releases.instabug.com/custom/faeture-screen_rendering-release/15.1.17/Instabug.podspec' + pod 'Instabug', :podspec => 'https://ios-releases.instabug.com/custom/faeture-screen_rendering-release/15.1.19/Instabug.podspec' flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) end diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index 45894bba4..703787e60 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -1,14 +1,14 @@ PODS: - Flutter (1.0.0) - - Instabug (15.1.17) + - Instabug (15.1.19) - instabug_flutter (14.3.0): - Flutter - - Instabug (= 15.1.17) + - Instabug (= 15.1.19) - OCMock (3.6) DEPENDENCIES: - Flutter (from `Flutter`) - - Instabug (from `https://ios-releases.instabug.com/custom/faeture-screen_rendering-release/15.1.17/Instabug.podspec`) + - Instabug (from `https://ios-releases.instabug.com/custom/faeture-screen_rendering-release/15.1.19/Instabug.podspec`) - instabug_flutter (from `.symlinks/plugins/instabug_flutter/ios`) - OCMock (= 3.6) @@ -20,16 +20,16 @@ EXTERNAL SOURCES: Flutter: :path: Flutter Instabug: - :podspec: https://ios-releases.instabug.com/custom/faeture-screen_rendering-release/15.1.17/Instabug.podspec + :podspec: https://ios-releases.instabug.com/custom/faeture-screen_rendering-release/15.1.19/Instabug.podspec instabug_flutter: :path: ".symlinks/plugins/instabug_flutter/ios" SPEC CHECKSUMS: Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 - Instabug: 316559a02c9b752a3854a6453c2fa414d36252f3 - instabug_flutter: 7ae7f3d1c47b9a699e76a7358b6a3e818a253ac3 + Instabug: 74377abfdaa9f9f3dff7793353e150e91d2186f7 + instabug_flutter: aa9b2365fe41d8a49f9258ab350864bfb5bdce9e OCMock: 5ea90566be239f179ba766fd9fbae5885040b992 -PODFILE CHECKSUM: 8f3e14dab36cc02b0a8767c3086e109fadaa55f3 +PODFILE CHECKSUM: d61a5c8efcff86500b76349ccad5201d7756fdea COCOAPODS: 1.15.2 diff --git a/ios/instabug_flutter.podspec b/ios/instabug_flutter.podspec index 4cda9fd30..30a9289c2 100644 --- a/ios/instabug_flutter.podspec +++ b/ios/instabug_flutter.podspec @@ -17,6 +17,6 @@ Pod::Spec.new do |s| s.pod_target_xcconfig = { 'OTHER_LDFLAGS' => '-framework "Flutter" -framework "InstabugSDK"'} s.dependency 'Flutter' - s.dependency 'Instabug', '15.1.17' + s.dependency 'Instabug', '15.1.19' end diff --git a/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart b/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart index eed37d9e5..b89b3c312 100644 --- a/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart +++ b/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart @@ -1,4 +1,5 @@ import 'dart:async'; +import 'dart:developer' show log; import 'dart:ui' show TimingsCallback, FrameTiming, FramePhase; import 'package:flutter/widgets.dart'; @@ -300,6 +301,10 @@ class InstabugScreenRenderManager { /// Save Slow/Frozen Frames data void _onDelayedFrameDetected(int startTime, int durationInMicroseconds) { + log( + "${durationInMicroseconds >= 700000 ? "🚨Frozen" : "⚠️Slow"} Frame Detected (startTime: $startTime, duration: $durationInMicroseconds µs)", + name: tag, + ); _delayedFrames.add( InstabugFrameData( startTime, @@ -315,6 +320,10 @@ class InstabugScreenRenderManager { InstabugScreenRenderData screenRenderData, ) async { try { + log( + "reportScreenRenderForCustomUiTrace $screenRenderData", + name: tag, + ); await APM.endScreenRenderForCustomUiTrace(screenRenderData); return true; } catch (error, stackTrace) { @@ -332,6 +341,10 @@ class InstabugScreenRenderManager { try { // Save the end time for the running ui trace, it's only needed in Android SDK. screenRenderData.saveEndTime(); + log( + "reportScreenRenderForAutoUiTrace $screenRenderData", + name: tag, + ); await APM.endScreenRenderForAutoUiTrace(screenRenderData); return true; diff --git a/test/utils/screen_render/instabug_screen_render_manager_test.dart b/test/utils/screen_render/instabug_screen_render_manager_test.dart index 4565f22fb..9f99ac0f4 100644 --- a/test/utils/screen_render/instabug_screen_render_manager_test.dart +++ b/test/utils/screen_render/instabug_screen_render_manager_test.dart @@ -5,7 +5,7 @@ import 'package:instabug_flutter/src/models/instabug_screen_render_data.dart'; import 'package:instabug_flutter/src/utils/screen_rendering/instabug_screen_render_manager.dart'; import 'package:mockito/mockito.dart'; -import 'instabug_screen_render_manager_test_manual_mocks.dart'; +import 'instabug_screen_render_manager_test.mocks.dart'; void main() { TestWidgetsFlutterBinding.ensureInitialized(); diff --git a/test/utils/screen_render/instabug_screen_render_manager_test_manual_mocks.dart b/test/utils/screen_render/instabug_screen_render_manager_test_manual_mocks.dart deleted file mode 100644 index 4e363eb75..000000000 --- a/test/utils/screen_render/instabug_screen_render_manager_test_manual_mocks.dart +++ /dev/null @@ -1,759 +0,0 @@ -// Mocks generated by Mockito 5.2.0 from annotations -// in instabug_flutter/example/ios/.symlinks/plugins/instabug_flutter/test/utils/screen_render/instabug_screen_render_manager_test.dart. -// Do not manually edit this file. - -import 'dart:async' as _i9; -import 'dart:developer' as _i13; -import 'dart:ui' as _i4; - -import 'package:flutter/foundation.dart' as _i3; -import 'package:flutter/gestures.dart' as _i6; -import 'package:flutter/rendering.dart' as _i7; -import 'package:flutter/scheduler.dart' as _i11; -import 'package:flutter/services.dart' as _i5; -import 'package:flutter/src/widgets/binding.dart' as _i10; -import 'package:flutter/src/widgets/focus_manager.dart' as _i2; -import 'package:flutter/src/widgets/framework.dart' as _i12; -import 'package:instabug_flutter/src/generated/apm.api.g.dart' as _i8; -import 'package:mockito/mockito.dart' as _i1; - -// ignore_for_file: type=lint -// ignore_for_file: avoid_redundant_argument_values -// ignore_for_file: avoid_setters_without_getters -// ignore_for_file: comment_references -// ignore_for_file: implementation_imports -// ignore_for_file: invalid_use_of_visible_for_testing_member -// ignore_for_file: prefer_const_constructors -// ignore_for_file: unnecessary_parenthesis -// ignore_for_file: camel_case_types - -class _FakeFocusManager_0 extends _i1.Fake implements _i2.FocusManager { - @override - String toString({_i3.DiagnosticLevel? minLevel = _i3.DiagnosticLevel.info}) => - super.toString(); -} - -class _FakeSingletonFlutterWindow_1 extends _i1.Fake - implements _i4.SingletonFlutterWindow {} - -class _FakePlatformDispatcher_2 extends _i1.Fake - implements _i4.PlatformDispatcher {} - -class _FakeHardwareKeyboard_3 extends _i1.Fake - implements _i5.HardwareKeyboard {} - -class _FakeKeyEventManager_4 extends _i1.Fake implements _i5.KeyEventManager {} - -class _FakeBinaryMessenger_5 extends _i1.Fake implements _i5.BinaryMessenger {} - -class _FakeChannelBuffers_6 extends _i1.Fake implements _i4.ChannelBuffers {} - -class _FakeRestorationManager_7 extends _i1.Fake - implements _i5.RestorationManager {} - -class _FakeDuration_8 extends _i1.Fake implements Duration {} - -class _FakePointerRouter_9 extends _i1.Fake implements _i6.PointerRouter {} - -class _FakeGestureArenaManager_10 extends _i1.Fake - implements _i6.GestureArenaManager {} - -class _FakePointerSignalResolver_11 extends _i1.Fake - implements _i6.PointerSignalResolver {} - -class _FakeMouseTracker_12 extends _i1.Fake implements _i7.MouseTracker {} - -class _FakePipelineOwner_13 extends _i1.Fake implements _i7.PipelineOwner {} - -class _FakeRenderView_14 extends _i1.Fake implements _i7.RenderView { - @override - String toString({_i3.DiagnosticLevel? minLevel = _i3.DiagnosticLevel.info}) => - super.toString(); -} - -class _FakeAccessibilityFeatures_15 extends _i1.Fake - implements _i4.AccessibilityFeatures {} - -class _FakeViewConfiguration_16 extends _i1.Fake - implements _i7.ViewConfiguration {} - -class _FakeSemanticsUpdateBuilder_17 extends _i1.Fake - implements _i4.SemanticsUpdateBuilder {} - -/// A class which mocks [ApmHostApi]. -/// -/// See the documentation for Mockito's code generation for more information. -class MockApmHostApi extends _i1.Mock implements _i8.ApmHostApi { - MockApmHostApi() { - _i1.throwOnMissingStub(this); - } - - @override - _i9.Future setEnabled(bool? arg_isEnabled) => - (super.noSuchMethod(Invocation.method(#setEnabled, [arg_isEnabled]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - _i9.Future isEnabled() => - (super.noSuchMethod(Invocation.method(#isEnabled, []), - returnValue: Future.value(false)) as _i9.Future); - @override - _i9.Future setScreenLoadingEnabled(bool? arg_isEnabled) => - (super.noSuchMethod( - Invocation.method(#setScreenLoadingEnabled, [arg_isEnabled]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - _i9.Future isScreenLoadingEnabled() => - (super.noSuchMethod(Invocation.method(#isScreenLoadingEnabled, []), - returnValue: Future.value(false)) as _i9.Future); - @override - _i9.Future setColdAppLaunchEnabled(bool? arg_isEnabled) => - (super.noSuchMethod( - Invocation.method(#setColdAppLaunchEnabled, [arg_isEnabled]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - _i9.Future setAutoUITraceEnabled(bool? arg_isEnabled) => (super - .noSuchMethod(Invocation.method(#setAutoUITraceEnabled, [arg_isEnabled]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - _i9.Future startExecutionTrace(String? arg_id, String? arg_name) => - (super.noSuchMethod( - Invocation.method(#startExecutionTrace, [arg_id, arg_name]), - returnValue: Future.value()) as _i9.Future); - @override - _i9.Future startFlow(String? arg_name) => - (super.noSuchMethod(Invocation.method(#startFlow, [arg_name]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - _i9.Future setFlowAttribute( - String? arg_name, String? arg_key, String? arg_value) => - (super.noSuchMethod( - Invocation.method(#setFlowAttribute, [arg_name, arg_key, arg_value]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - _i9.Future endFlow(String? arg_name) => - (super.noSuchMethod(Invocation.method(#endFlow, [arg_name]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - _i9.Future setExecutionTraceAttribute( - String? arg_id, String? arg_key, String? arg_value) => - (super.noSuchMethod( - Invocation.method( - #setExecutionTraceAttribute, [arg_id, arg_key, arg_value]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - _i9.Future endExecutionTrace(String? arg_id) => - (super.noSuchMethod(Invocation.method(#endExecutionTrace, [arg_id]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - _i9.Future startUITrace(String? arg_name) => - (super.noSuchMethod(Invocation.method(#startUITrace, [arg_name]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - _i9.Future endUITrace() => - (super.noSuchMethod(Invocation.method(#endUITrace, []), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - _i9.Future endAppLaunch() => - (super.noSuchMethod(Invocation.method(#endAppLaunch, []), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - _i9.Future networkLogAndroid(Map? arg_data) => - (super.noSuchMethod(Invocation.method(#networkLogAndroid, [arg_data]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - _i9.Future startCpUiTrace( - String? arg_screenName, int? arg_microTimeStamp, int? arg_traceId) => - (super.noSuchMethod( - Invocation.method(#startCpUiTrace, - [arg_screenName, arg_microTimeStamp, arg_traceId]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - _i9.Future reportScreenLoadingCP(int? arg_startTimeStampMicro, - int? arg_durationMicro, int? arg_uiTraceId) => - (super.noSuchMethod( - Invocation.method(#reportScreenLoadingCP, - [arg_startTimeStampMicro, arg_durationMicro, arg_uiTraceId]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - _i9.Future endScreenLoadingCP( - int? arg_timeStampMicro, int? arg_uiTraceId) => - (super.noSuchMethod( - Invocation.method( - #endScreenLoadingCP, [arg_timeStampMicro, arg_uiTraceId]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - _i9.Future isEndScreenLoadingEnabled() => - (super.noSuchMethod(Invocation.method(#isEndScreenLoadingEnabled, []), - returnValue: Future.value(false)) as _i9.Future); - @override - _i9.Future isScreenRenderEnabled() => - (super.noSuchMethod(Invocation.method(#isScreenRenderEnabled, []), - returnValue: Future.value(false)) as _i9.Future); - @override - _i9.Future deviceRefreshRate() => - (super.noSuchMethod(Invocation.method(#deviceRefreshRate, []), - returnValue: Future.value(0.0)) as _i9.Future); - @override - _i9.Future setScreenRenderEnabled(bool? arg_isEnabled) => (super - .noSuchMethod(Invocation.method(#setScreenRenderEnabled, [arg_isEnabled]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - _i9.Future endScreenRenderForAutoUiTrace( - Map? arg_data) => - (super.noSuchMethod( - Invocation.method(#endScreenRenderForAutoUiTrace, [arg_data]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - _i9.Future endScreenRenderForCustomUiTrace( - Map? arg_data) => - (super.noSuchMethod( - Invocation.method(#endScreenRenderForCustomUiTrace, [arg_data]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); -} - -/// A class which mocks [WidgetsBinding]. -/// -/// See the documentation for Mockito's code generation for more information. -class MockWidgetsBinding extends _i1.Mock implements _i10.WidgetsBinding { - MockWidgetsBinding() { - _i1.throwOnMissingStub(this); - } - - @override - bool get debugBuildingDirtyElements => - (super.noSuchMethod(Invocation.getter(#debugBuildingDirtyElements), - returnValue: false) as bool); - @override - set debugBuildingDirtyElements(bool? _debugBuildingDirtyElements) => - super.noSuchMethod( - Invocation.setter( - #debugBuildingDirtyElements, _debugBuildingDirtyElements), - returnValueForMissingStub: null); - @override - _i2.FocusManager get focusManager => - (super.noSuchMethod(Invocation.getter(#focusManager), - returnValue: _FakeFocusManager_0()) as _i2.FocusManager); - @override - bool get firstFrameRasterized => - (super.noSuchMethod(Invocation.getter(#firstFrameRasterized), - returnValue: false) as bool); - @override - _i9.Future get waitUntilFirstFrameRasterized => - (super.noSuchMethod(Invocation.getter(#waitUntilFirstFrameRasterized), - returnValue: Future.value()) as _i9.Future); - @override - bool get debugDidSendFirstFrameEvent => - (super.noSuchMethod(Invocation.getter(#debugDidSendFirstFrameEvent), - returnValue: false) as bool); - @override - bool get framesEnabled => - (super.noSuchMethod(Invocation.getter(#framesEnabled), returnValue: false) - as bool); - @override - bool get isRootWidgetAttached => - (super.noSuchMethod(Invocation.getter(#isRootWidgetAttached), - returnValue: false) as bool); - @override - _i4.SingletonFlutterWindow get window => - (super.noSuchMethod(Invocation.getter(#window), - returnValue: _FakeSingletonFlutterWindow_1()) - as _i4.SingletonFlutterWindow); - @override - _i4.PlatformDispatcher get platformDispatcher => - (super.noSuchMethod(Invocation.getter(#platformDispatcher), - returnValue: _FakePlatformDispatcher_2()) as _i4.PlatformDispatcher); - @override - bool get locked => - (super.noSuchMethod(Invocation.getter(#locked), returnValue: false) - as bool); - @override - _i5.HardwareKeyboard get keyboard => - (super.noSuchMethod(Invocation.getter(#keyboard), - returnValue: _FakeHardwareKeyboard_3()) as _i5.HardwareKeyboard); - @override - _i5.KeyEventManager get keyEventManager => - (super.noSuchMethod(Invocation.getter(#keyEventManager), - returnValue: _FakeKeyEventManager_4()) as _i5.KeyEventManager); - @override - _i5.BinaryMessenger get defaultBinaryMessenger => - (super.noSuchMethod(Invocation.getter(#defaultBinaryMessenger), - returnValue: _FakeBinaryMessenger_5()) as _i5.BinaryMessenger); - @override - _i4.ChannelBuffers get channelBuffers => - (super.noSuchMethod(Invocation.getter(#channelBuffers), - returnValue: _FakeChannelBuffers_6()) as _i4.ChannelBuffers); - @override - _i5.RestorationManager get restorationManager => - (super.noSuchMethod(Invocation.getter(#restorationManager), - returnValue: _FakeRestorationManager_7()) as _i5.RestorationManager); - @override - _i11.SchedulingStrategy get schedulingStrategy => - (super.noSuchMethod(Invocation.getter(#schedulingStrategy), - returnValue: ({int? priority, _i11.SchedulerBinding? scheduler}) => - false) as _i11.SchedulingStrategy); - @override - set schedulingStrategy(_i11.SchedulingStrategy? _schedulingStrategy) => super - .noSuchMethod(Invocation.setter(#schedulingStrategy, _schedulingStrategy), - returnValueForMissingStub: null); - @override - int get transientCallbackCount => - (super.noSuchMethod(Invocation.getter(#transientCallbackCount), - returnValue: 0) as int); - @override - _i9.Future get endOfFrame => - (super.noSuchMethod(Invocation.getter(#endOfFrame), - returnValue: Future.value()) as _i9.Future); - @override - bool get hasScheduledFrame => - (super.noSuchMethod(Invocation.getter(#hasScheduledFrame), - returnValue: false) as bool); - @override - _i11.SchedulerPhase get schedulerPhase => - (super.noSuchMethod(Invocation.getter(#schedulerPhase), - returnValue: _i11.SchedulerPhase.idle) as _i11.SchedulerPhase); - @override - Duration get currentFrameTimeStamp => - (super.noSuchMethod(Invocation.getter(#currentFrameTimeStamp), - returnValue: _FakeDuration_8()) as Duration); - @override - Duration get currentSystemFrameTimeStamp => - (super.noSuchMethod(Invocation.getter(#currentSystemFrameTimeStamp), - returnValue: _FakeDuration_8()) as Duration); - @override - _i6.PointerRouter get pointerRouter => - (super.noSuchMethod(Invocation.getter(#pointerRouter), - returnValue: _FakePointerRouter_9()) as _i6.PointerRouter); - @override - _i6.GestureArenaManager get gestureArena => (super.noSuchMethod( - Invocation.getter(#gestureArena), - returnValue: _FakeGestureArenaManager_10()) as _i6.GestureArenaManager); - @override - _i6.PointerSignalResolver get pointerSignalResolver => - (super.noSuchMethod(Invocation.getter(#pointerSignalResolver), - returnValue: _FakePointerSignalResolver_11()) - as _i6.PointerSignalResolver); - @override - bool get resamplingEnabled => - (super.noSuchMethod(Invocation.getter(#resamplingEnabled), - returnValue: false) as bool); - @override - set resamplingEnabled(bool? _resamplingEnabled) => super.noSuchMethod( - Invocation.setter(#resamplingEnabled, _resamplingEnabled), - returnValueForMissingStub: null); - @override - Duration get samplingOffset => - (super.noSuchMethod(Invocation.getter(#samplingOffset), - returnValue: _FakeDuration_8()) as Duration); - @override - set samplingOffset(Duration? _samplingOffset) => - super.noSuchMethod(Invocation.setter(#samplingOffset, _samplingOffset), - returnValueForMissingStub: null); - @override - _i7.MouseTracker get mouseTracker => - (super.noSuchMethod(Invocation.getter(#mouseTracker), - returnValue: _FakeMouseTracker_12()) as _i7.MouseTracker); - @override - _i7.PipelineOwner get pipelineOwner => - (super.noSuchMethod(Invocation.getter(#pipelineOwner), - returnValue: _FakePipelineOwner_13()) as _i7.PipelineOwner); - @override - _i7.RenderView get renderView => - (super.noSuchMethod(Invocation.getter(#renderView), - returnValue: _FakeRenderView_14()) as _i7.RenderView); - @override - set renderView(_i7.RenderView? value) => - super.noSuchMethod(Invocation.setter(#renderView, value), - returnValueForMissingStub: null); - @override - bool get sendFramesToEngine => - (super.noSuchMethod(Invocation.getter(#sendFramesToEngine), - returnValue: false) as bool); - @override - _i4.AccessibilityFeatures get accessibilityFeatures => - (super.noSuchMethod(Invocation.getter(#accessibilityFeatures), - returnValue: _FakeAccessibilityFeatures_15()) - as _i4.AccessibilityFeatures); - @override - bool get disableAnimations => - (super.noSuchMethod(Invocation.getter(#disableAnimations), - returnValue: false) as bool); - @override - void initInstances() => - super.noSuchMethod(Invocation.method(#initInstances, []), - returnValueForMissingStub: null); - @override - void initServiceExtensions() => - super.noSuchMethod(Invocation.method(#initServiceExtensions, []), - returnValueForMissingStub: null); - @override - void addObserver(_i10.WidgetsBindingObserver? observer) => - super.noSuchMethod(Invocation.method(#addObserver, [observer]), - returnValueForMissingStub: null); - @override - bool removeObserver(_i10.WidgetsBindingObserver? observer) => - (super.noSuchMethod(Invocation.method(#removeObserver, [observer]), - returnValue: false) as bool); - @override - void handleMetricsChanged() => - super.noSuchMethod(Invocation.method(#handleMetricsChanged, []), - returnValueForMissingStub: null); - @override - void handleTextScaleFactorChanged() => - super.noSuchMethod(Invocation.method(#handleTextScaleFactorChanged, []), - returnValueForMissingStub: null); - @override - void handlePlatformBrightnessChanged() => super.noSuchMethod( - Invocation.method(#handlePlatformBrightnessChanged, []), - returnValueForMissingStub: null); - @override - void handleAccessibilityFeaturesChanged() => super.noSuchMethod( - Invocation.method(#handleAccessibilityFeaturesChanged, []), - returnValueForMissingStub: null); - @override - void handleLocaleChanged() => - super.noSuchMethod(Invocation.method(#handleLocaleChanged, []), - returnValueForMissingStub: null); - @override - void dispatchLocalesChanged(List<_i4.Locale>? locales) => - super.noSuchMethod(Invocation.method(#dispatchLocalesChanged, [locales]), - returnValueForMissingStub: null); - @override - void dispatchAccessibilityFeaturesChanged() => super.noSuchMethod( - Invocation.method(#dispatchAccessibilityFeaturesChanged, []), - returnValueForMissingStub: null); - @override - _i9.Future handlePopRoute() => - (super.noSuchMethod(Invocation.method(#handlePopRoute, []), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - _i9.Future handlePushRoute(String? route) => - (super.noSuchMethod(Invocation.method(#handlePushRoute, [route]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - void handleAppLifecycleStateChanged(_i4.AppLifecycleState? state) => super - .noSuchMethod(Invocation.method(#handleAppLifecycleStateChanged, [state]), - returnValueForMissingStub: null); - @override - void handleMemoryPressure() => - super.noSuchMethod(Invocation.method(#handleMemoryPressure, []), - returnValueForMissingStub: null); - @override - void drawFrame() => super.noSuchMethod(Invocation.method(#drawFrame, []), - returnValueForMissingStub: null); - @override - void scheduleAttachRootWidget(_i12.Widget? rootWidget) => super.noSuchMethod( - Invocation.method(#scheduleAttachRootWidget, [rootWidget]), - returnValueForMissingStub: null); - @override - void attachRootWidget(_i12.Widget? rootWidget) => - super.noSuchMethod(Invocation.method(#attachRootWidget, [rootWidget]), - returnValueForMissingStub: null); - @override - _i9.Future performReassemble() => - (super.noSuchMethod(Invocation.method(#performReassemble, []), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - _i4.Locale? computePlatformResolvedLocale( - List<_i4.Locale>? supportedLocales) => - (super.noSuchMethod(Invocation.method( - #computePlatformResolvedLocale, [supportedLocales])) as _i4.Locale?); - @override - _i9.Future lockEvents(_i9.Future Function()? callback) => - (super.noSuchMethod(Invocation.method(#lockEvents, [callback]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - void unlocked() => super.noSuchMethod(Invocation.method(#unlocked, []), - returnValueForMissingStub: null); - @override - _i9.Future reassembleApplication() => - (super.noSuchMethod(Invocation.method(#reassembleApplication, []), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - void registerSignalServiceExtension( - {String? name, _i3.AsyncCallback? callback}) => - super.noSuchMethod( - Invocation.method(#registerSignalServiceExtension, [], - {#name: name, #callback: callback}), - returnValueForMissingStub: null); - @override - void registerBoolServiceExtension( - {String? name, - _i3.AsyncValueGetter? getter, - _i3.AsyncValueSetter? setter}) => - super.noSuchMethod( - Invocation.method(#registerBoolServiceExtension, [], - {#name: name, #getter: getter, #setter: setter}), - returnValueForMissingStub: null); - @override - void registerNumericServiceExtension( - {String? name, - _i3.AsyncValueGetter? getter, - _i3.AsyncValueSetter? setter}) => - super.noSuchMethod( - Invocation.method(#registerNumericServiceExtension, [], - {#name: name, #getter: getter, #setter: setter}), - returnValueForMissingStub: null); - @override - void postEvent(String? eventKind, Map? eventData) => - super.noSuchMethod(Invocation.method(#postEvent, [eventKind, eventData]), - returnValueForMissingStub: null); - @override - void registerStringServiceExtension( - {String? name, - _i3.AsyncValueGetter? getter, - _i3.AsyncValueSetter? setter}) => - super.noSuchMethod( - Invocation.method(#registerStringServiceExtension, [], - {#name: name, #getter: getter, #setter: setter}), - returnValueForMissingStub: null); - @override - void registerServiceExtension( - {String? name, _i3.ServiceExtensionCallback? callback}) => - super.noSuchMethod( - Invocation.method(#registerServiceExtension, [], - {#name: name, #callback: callback}), - returnValueForMissingStub: null); - @override - _i5.BinaryMessenger createBinaryMessenger() => - (super.noSuchMethod(Invocation.method(#createBinaryMessenger, []), - returnValue: _FakeBinaryMessenger_5()) as _i5.BinaryMessenger); - @override - _i9.Future handleSystemMessage(Object? systemMessage) => (super - .noSuchMethod(Invocation.method(#handleSystemMessage, [systemMessage]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - void initLicenses() => - super.noSuchMethod(Invocation.method(#initLicenses, []), - returnValueForMissingStub: null); - @override - void evict(String? asset) => - super.noSuchMethod(Invocation.method(#evict, [asset]), - returnValueForMissingStub: null); - @override - void readInitialLifecycleStateFromNativeWindow() => super.noSuchMethod( - Invocation.method(#readInitialLifecycleStateFromNativeWindow, []), - returnValueForMissingStub: null); - @override - _i5.RestorationManager createRestorationManager() => - (super.noSuchMethod(Invocation.method(#createRestorationManager, []), - returnValue: _FakeRestorationManager_7()) as _i5.RestorationManager); - @override - void setSystemUiChangeCallback(_i5.SystemUiChangeCallback? callback) => super - .noSuchMethod(Invocation.method(#setSystemUiChangeCallback, [callback]), - returnValueForMissingStub: null); - @override - void addTimingsCallback(_i4.TimingsCallback? callback) => - super.noSuchMethod(Invocation.method(#addTimingsCallback, [callback]), - returnValueForMissingStub: null); - @override - void removeTimingsCallback(_i4.TimingsCallback? callback) => - super.noSuchMethod(Invocation.method(#removeTimingsCallback, [callback]), - returnValueForMissingStub: null); - @override - _i9.Future scheduleTask( - _i11.TaskCallback? task, _i11.Priority? priority, - {String? debugLabel, _i13.Flow? flow}) => - (super.noSuchMethod( - Invocation.method(#scheduleTask, [task, priority], - {#debugLabel: debugLabel, #flow: flow}), - returnValue: Future.value(null)) as _i9.Future); - @override - bool handleEventLoopCallback() => - (super.noSuchMethod(Invocation.method(#handleEventLoopCallback, []), - returnValue: false) as bool); - @override - int scheduleFrameCallback(_i11.FrameCallback? callback, - {bool? rescheduling = false}) => - (super.noSuchMethod( - Invocation.method(#scheduleFrameCallback, [callback], - {#rescheduling: rescheduling}), - returnValue: 0) as int); - @override - void cancelFrameCallbackWithId(int? id) => - super.noSuchMethod(Invocation.method(#cancelFrameCallbackWithId, [id]), - returnValueForMissingStub: null); - @override - bool debugAssertNoTransientCallbacks(String? reason) => (super.noSuchMethod( - Invocation.method(#debugAssertNoTransientCallbacks, [reason]), - returnValue: false) as bool); - @override - void addPersistentFrameCallback(_i11.FrameCallback? callback) => super - .noSuchMethod(Invocation.method(#addPersistentFrameCallback, [callback]), - returnValueForMissingStub: null); - @override - void addPostFrameCallback(_i11.FrameCallback? callback) => - super.noSuchMethod(Invocation.method(#addPostFrameCallback, [callback]), - returnValueForMissingStub: null); - @override - void ensureFrameCallbacksRegistered() => - super.noSuchMethod(Invocation.method(#ensureFrameCallbacksRegistered, []), - returnValueForMissingStub: null); - @override - void ensureVisualUpdate() => - super.noSuchMethod(Invocation.method(#ensureVisualUpdate, []), - returnValueForMissingStub: null); - @override - void scheduleFrame() => - super.noSuchMethod(Invocation.method(#scheduleFrame, []), - returnValueForMissingStub: null); - @override - void scheduleForcedFrame() => - super.noSuchMethod(Invocation.method(#scheduleForcedFrame, []), - returnValueForMissingStub: null); - @override - void scheduleWarmUpFrame() => - super.noSuchMethod(Invocation.method(#scheduleWarmUpFrame, []), - returnValueForMissingStub: null); - @override - void resetEpoch() => super.noSuchMethod(Invocation.method(#resetEpoch, []), - returnValueForMissingStub: null); - @override - void handleBeginFrame(Duration? rawTimeStamp) => - super.noSuchMethod(Invocation.method(#handleBeginFrame, [rawTimeStamp]), - returnValueForMissingStub: null); - @override - void handleDrawFrame() => - super.noSuchMethod(Invocation.method(#handleDrawFrame, []), - returnValueForMissingStub: null); - @override - void cancelPointer(int? pointer) => - super.noSuchMethod(Invocation.method(#cancelPointer, [pointer]), - returnValueForMissingStub: null); - @override - void handlePointerEvent(_i7.PointerEvent? event) => - super.noSuchMethod(Invocation.method(#handlePointerEvent, [event]), - returnValueForMissingStub: null); - @override - void hitTest(_i7.HitTestResult? result, _i4.Offset? position) => - super.noSuchMethod(Invocation.method(#hitTest, [result, position]), - returnValueForMissingStub: null); - @override - void dispatchEvent( - _i7.PointerEvent? event, _i7.HitTestResult? hitTestResult) => - super.noSuchMethod( - Invocation.method(#dispatchEvent, [event, hitTestResult]), - returnValueForMissingStub: null); - @override - void handleEvent(_i7.PointerEvent? event, _i7.HitTestEntry? entry) => - super.noSuchMethod(Invocation.method(#handleEvent, [event, entry]), - returnValueForMissingStub: null); - @override - void resetGestureBinding() => - super.noSuchMethod(Invocation.method(#resetGestureBinding, []), - returnValueForMissingStub: null); - @override - void initRenderView() => - super.noSuchMethod(Invocation.method(#initRenderView, []), - returnValueForMissingStub: null); - @override - _i7.ViewConfiguration createViewConfiguration() => - (super.noSuchMethod(Invocation.method(#createViewConfiguration, []), - returnValue: _FakeViewConfiguration_16()) as _i7.ViewConfiguration); - @override - void initMouseTracker([_i7.MouseTracker? tracker]) => - super.noSuchMethod(Invocation.method(#initMouseTracker, [tracker]), - returnValueForMissingStub: null); - @override - void setSemanticsEnabled(bool? enabled) => - super.noSuchMethod(Invocation.method(#setSemanticsEnabled, [enabled]), - returnValueForMissingStub: null); - @override - void deferFirstFrame() => - super.noSuchMethod(Invocation.method(#deferFirstFrame, []), - returnValueForMissingStub: null); - @override - void allowFirstFrame() => - super.noSuchMethod(Invocation.method(#allowFirstFrame, []), - returnValueForMissingStub: null); - @override - void resetFirstFrameSent() => - super.noSuchMethod(Invocation.method(#resetFirstFrameSent, []), - returnValueForMissingStub: null); - @override - _i4.SemanticsUpdateBuilder createSemanticsUpdateBuilder() => - (super.noSuchMethod(Invocation.method(#createSemanticsUpdateBuilder, []), - returnValue: _FakeSemanticsUpdateBuilder_17()) - as _i4.SemanticsUpdateBuilder); -} - -/// A class which mocks [FrameTiming]. -/// -/// See the documentation for Mockito's code generation for more information. -class MockFrameTiming extends _i1.Mock implements _i4.FrameTiming { - MockFrameTiming() { - _i1.throwOnMissingStub(this); - } - - @override - Duration get buildDuration => - (super.noSuchMethod(Invocation.getter(#buildDuration), - returnValue: _FakeDuration_8()) as Duration); - @override - Duration get rasterDuration => - (super.noSuchMethod(Invocation.getter(#rasterDuration), - returnValue: _FakeDuration_8()) as Duration); - @override - Duration get vsyncOverhead => - (super.noSuchMethod(Invocation.getter(#vsyncOverhead), - returnValue: _FakeDuration_8()) as Duration); - @override - Duration get totalSpan => (super.noSuchMethod(Invocation.getter(#totalSpan), - returnValue: _FakeDuration_8()) as Duration); - @override - int get layerCacheCount => - (super.noSuchMethod(Invocation.getter(#layerCacheCount), returnValue: 0) - as int); - @override - int get layerCacheBytes => - (super.noSuchMethod(Invocation.getter(#layerCacheBytes), returnValue: 0) - as int); - @override - double get layerCacheMegabytes => - (super.noSuchMethod(Invocation.getter(#layerCacheMegabytes), - returnValue: 0.0) as double); - @override - int get pictureCacheCount => - (super.noSuchMethod(Invocation.getter(#pictureCacheCount), returnValue: 0) - as int); - @override - int get pictureCacheBytes => - (super.noSuchMethod(Invocation.getter(#pictureCacheBytes), returnValue: 0) - as int); - @override - double get pictureCacheMegabytes => - (super.noSuchMethod(Invocation.getter(#pictureCacheMegabytes), - returnValue: 0.0) as double); - @override - int get frameNumber => - (super.noSuchMethod(Invocation.getter(#frameNumber), returnValue: 0) - as int); - @override - int timestampInMicroseconds(_i4.FramePhase? phase) => - (super.noSuchMethod(Invocation.method(#timestampInMicroseconds, [phase]), - returnValue: 0) as int); -} From 3a281998326044db9805c6ab9b38e5d56a4fa2c4 Mon Sep 17 00:00:00 2001 From: AyaMahmoud148 Date: Thu, 31 Jul 2025 15:16:00 +0300 Subject: [PATCH 42/84] chore: remove deprecated apis --- .../com/instabug/flutter/modules/ApmApi.java | 74 +------------------ .../flutter/modules/BugReportingApi.java | 2 +- .../instabug/flutter/modules/InstabugApi.java | 14 ---- .../java/com/instabug/flutter/ApmApiTest.java | 57 -------------- .../instabug/flutter/BugReportingApiTest.java | 2 +- .../com/instabug/flutter/InstabugApiTest.java | 29 -------- example/ios/InstabugTests/ApmApiTests.m | 33 --------- example/ios/InstabugTests/InstabugApiTests.m | 25 ------- ios/Classes/Modules/ApmApi.m | 38 ---------- ios/Classes/Modules/BugReportingApi.m | 5 +- ios/Classes/Modules/InstabugApi.m | 10 --- lib/instabug_flutter.dart | 1 - lib/src/models/trace.dart | 44 ----------- lib/src/modules/apm.dart | 52 ------------- lib/src/modules/instabug.dart | 32 ++------ pigeons/apm.api.dart | 9 --- pigeons/instabug.api.dart | 3 - test/apm_test.dart | 42 ----------- test/instabug_test.dart | 31 -------- test/trace_test.dart | 46 ------------ 20 files changed, 11 insertions(+), 538 deletions(-) delete mode 100644 lib/src/models/trace.dart delete mode 100644 test/trace_test.dart diff --git a/android/src/main/java/com/instabug/flutter/modules/ApmApi.java b/android/src/main/java/com/instabug/flutter/modules/ApmApi.java index 607c569a4..b5ce437da 100644 --- a/android/src/main/java/com/instabug/flutter/modules/ApmApi.java +++ b/android/src/main/java/com/instabug/flutter/modules/ApmApi.java @@ -9,7 +9,6 @@ import com.instabug.apm.InternalAPM; import com.instabug.apm.configuration.cp.APMFeature; import com.instabug.apm.configuration.cp.FeatureAvailabilityCallback; -import com.instabug.apm.model.ExecutionTrace; import com.instabug.apm.networking.APMNetworkLogger; import com.instabug.apm.networkinterception.cp.APMCPNetworkLog; import com.instabug.flutter.generated.ApmPigeon; @@ -26,7 +25,6 @@ public class ApmApi implements ApmPigeon.ApmHostApi { private final String TAG = ApmApi.class.getName(); - private final HashMap traces = new HashMap<>(); public static void init(BinaryMessenger messenger) { final ApmApi api = new ApmApi(); @@ -98,45 +96,7 @@ public void setAutoUITraceEnabled(@NonNull Boolean isEnabled) { * * @deprecated see {@link #startFlow} */ - @Override - public void startExecutionTrace(@NonNull String id, @NonNull String name, ApmPigeon.Result result) { - ThreadManager.runOnBackground( - new Runnable() { - @Override - public void run() { - try { - ExecutionTrace trace = APM.startExecutionTrace(name); - if (trace != null) { - traces.put(id, trace); - - ThreadManager.runOnMainThread(new Runnable() { - @Override - public void run() { - result.success(id); - } - }); - } else { - ThreadManager.runOnMainThread(new Runnable() { - @Override - public void run() { - result.success(null); - } - }); - } - } catch (Exception e) { - e.printStackTrace(); - - ThreadManager.runOnMainThread(new Runnable() { - @Override - public void run() { - result.success(null); - } - }); - } - } - } - ); - } + /** * Starts an AppFlow with the specified name. @@ -201,39 +161,7 @@ public void endFlow(@NonNull String name) { } } - /** - * Adds a new attribute to trace - * - * @param id String id of the trace. - * @param key attribute key - * @param value attribute value. Null to remove attribute - * - * @deprecated see {@link #setFlowAttribute} - */ - @Override - public void setExecutionTraceAttribute(@NonNull String id, @NonNull String key, @NonNull String value) { - try { - traces.get(id).setAttribute(key, value); - } catch (Exception e) { - e.printStackTrace(); - } - } - /** - * Ends a trace - * - * @param id string id of the trace. - * - * @deprecated see {@link #endFlow} - */ - @Override - public void endExecutionTrace(@NonNull String id) { - try { - traces.get(id).end(); - } catch (Exception e) { - e.printStackTrace(); - } - } /** * Starts a UI trace. diff --git a/android/src/main/java/com/instabug/flutter/modules/BugReportingApi.java b/android/src/main/java/com/instabug/flutter/modules/BugReportingApi.java index f3236bb4e..c845de0c1 100644 --- a/android/src/main/java/com/instabug/flutter/modules/BugReportingApi.java +++ b/android/src/main/java/com/instabug/flutter/modules/BugReportingApi.java @@ -184,7 +184,7 @@ public void setCommentMinimumCharacterCount(@NonNull Long limit, @Nullable List< reportTypesArray[i] = ArgsRegistry.reportTypes.get(key); } } - BugReporting.setCommentMinimumCharacterCount(limit.intValue(), reportTypesArray); + BugReporting.setCommentMinimumCharacterCountForBugReportType(limit.intValue(), reportTypesArray); } @Override diff --git a/android/src/main/java/com/instabug/flutter/modules/InstabugApi.java b/android/src/main/java/com/instabug/flutter/modules/InstabugApi.java index edfde055a..dde45ecb0 100644 --- a/android/src/main/java/com/instabug/flutter/modules/InstabugApi.java +++ b/android/src/main/java/com/instabug/flutter/modules/InstabugApi.java @@ -176,7 +176,6 @@ public void setWelcomeMessageMode(@NonNull String mode) { @Override public void setPrimaryColor(@NonNull Long color) { - Instabug.setPrimaryColor(color.intValue()); } @Override @@ -228,20 +227,7 @@ public void run() { ); } - @Override - public void addExperiments(@NonNull List experiments) { - Instabug.addExperiments(experiments); - } - @Override - public void removeExperiments(@NonNull List experiments) { - Instabug.removeExperiments(experiments); - } - - @Override - public void clearAllExperiments() { - Instabug.clearAllExperiments(); - } @Override public void addFeatureFlags(@NonNull Map featureFlags) { diff --git a/android/src/test/java/com/instabug/flutter/ApmApiTest.java b/android/src/test/java/com/instabug/flutter/ApmApiTest.java index 725d3bd98..39728c20c 100644 --- a/android/src/test/java/com/instabug/flutter/ApmApiTest.java +++ b/android/src/test/java/com/instabug/flutter/ApmApiTest.java @@ -17,7 +17,6 @@ import com.instabug.apm.InternalAPM; import com.instabug.apm.configuration.cp.APMFeature; import com.instabug.apm.configuration.cp.FeatureAvailabilityCallback; -import com.instabug.apm.model.ExecutionTrace; import com.instabug.apm.networking.APMNetworkLogger; import com.instabug.flutter.generated.ApmPigeon; import com.instabug.flutter.modules.ApmApi; @@ -68,16 +67,6 @@ public void cleanUp() { GlobalMocks.close(); } - private ExecutionTrace mockTrace(String id) { - String name = "trace-name"; - ExecutionTrace mTrace = mock(ExecutionTrace.class); - - mAPM.when(() -> APM.startExecutionTrace(name)).thenReturn(mTrace); - - api.startExecutionTrace(id, name, makeResult()); - - return mTrace; - } @Test public void testInit() { @@ -115,53 +104,7 @@ public void testSetAutoUITraceEnabled() { mAPM.verify(() -> APM.setAutoUITraceEnabled(isEnabled)); } - @Test - public void testStartExecutionTraceWhenTraceNotNull() { - String expectedId = "trace-id"; - String name = "trace-name"; - ApmPigeon.Result result = makeResult((String actualId) -> assertEquals(expectedId, actualId)); - - mAPM.when(() -> APM.startExecutionTrace(name)).thenReturn(new ExecutionTrace(name)); - - api.startExecutionTrace(expectedId, name, result); - - mAPM.verify(() -> APM.startExecutionTrace(name)); - } - - @Test - public void testStartExecutionTraceWhenTraceIsNull() { - String id = "trace-id"; - String name = "trace-name"; - ApmPigeon.Result result = makeResult(Assert::assertNull); - - mAPM.when(() -> APM.startExecutionTrace(name)).thenReturn(null); - - api.startExecutionTrace(id, name, result); - - mAPM.verify(() -> APM.startExecutionTrace(name)); - } - - @Test - public void testSetExecutionTraceAttribute() { - String id = "trace-id"; - String key = "is_premium"; - String value = "true"; - ExecutionTrace mTrace = mockTrace(id); - - api.setExecutionTraceAttribute(id, key, value); - - verify(mTrace).setAttribute(key, value); - } - - @Test - public void testEndExecutionTrace() { - String id = "trace-id"; - ExecutionTrace mTrace = mockTrace(id); - - api.endExecutionTrace(id); - verify(mTrace).end(); - } @Test public void testStartFlow() { diff --git a/android/src/test/java/com/instabug/flutter/BugReportingApiTest.java b/android/src/test/java/com/instabug/flutter/BugReportingApiTest.java index 6d22e26b8..50722762f 100644 --- a/android/src/test/java/com/instabug/flutter/BugReportingApiTest.java +++ b/android/src/test/java/com/instabug/flutter/BugReportingApiTest.java @@ -192,7 +192,7 @@ public void testSetCommentMinimumCharacterCount() { api.setCommentMinimumCharacterCount(limit, reportTypes); - mBugReporting.verify(() -> BugReporting.setCommentMinimumCharacterCount(limit.intValue(), BugReporting.ReportType.BUG, BugReporting.ReportType.QUESTION)); + mBugReporting.verify(() -> BugReporting.setCommentMinimumCharacterCountForBugReportType(limit.intValue(), BugReporting.ReportType.BUG, BugReporting.ReportType.QUESTION)); } @Test diff --git a/android/src/test/java/com/instabug/flutter/InstabugApiTest.java b/android/src/test/java/com/instabug/flutter/InstabugApiTest.java index 97b9cdf7b..73717f2ff 100644 --- a/android/src/test/java/com/instabug/flutter/InstabugApiTest.java +++ b/android/src/test/java/com/instabug/flutter/InstabugApiTest.java @@ -276,13 +276,7 @@ public void testSetWelcomeMessageMode() { @Test public void testSetPrimaryColor() { - Long color = 0xFF0000L; - - api.setPrimaryColor(color); - - mInstabug.verify(() -> Instabug.setPrimaryColor(0xFF0000)); } - @Test public void testSetSessionProfilerEnabledGivenTrue() { Boolean isEnabled = true; @@ -346,30 +340,7 @@ public void testGetTags() { mInstabug.verify(Instabug::getTags); } - @Test - public void testAddExperiments() { - List experiments = Arrays.asList("premium", "star"); - - api.addExperiments(experiments); - - mInstabug.verify(() -> Instabug.addExperiments(experiments)); - } - @Test - public void testRemoveExperiments() { - List experiments = Arrays.asList("premium", "star"); - - api.removeExperiments(experiments); - - mInstabug.verify(() -> Instabug.removeExperiments(experiments)); - } - - @Test - public void testClearAllExperiments() { - api.clearAllExperiments(); - - mInstabug.verify(Instabug::clearAllExperiments); - } @Test public void testAddFeatureFlags() { diff --git a/example/ios/InstabugTests/ApmApiTests.m b/example/ios/InstabugTests/ApmApiTests.m index bdb710ac7..bf2fdce54 100644 --- a/example/ios/InstabugTests/ApmApiTests.m +++ b/example/ios/InstabugTests/ApmApiTests.m @@ -116,40 +116,7 @@ - (void)testSetAutoUITraceEnabled { OCMVerify([self.mAPM setAutoUITraceEnabled:YES]); } -- (void)testStartExecutionTraceWhenTraceNotNil { - NSString *expectedId = @"trace-id"; - NSString *name = @"trace-name"; - XCTestExpectation *expectation = [self expectationWithDescription:@"Call completion handler"]; - - IBGExecutionTrace *mTrace = OCMClassMock([IBGExecutionTrace class]); - OCMStub([self.mAPM startExecutionTraceWithName:name]).andReturn(mTrace); - - [self.api startExecutionTraceId:expectedId name:name completion:^(NSString *actualId, FlutterError *error) { - [expectation fulfill]; - XCTAssertEqual(actualId, expectedId); - XCTAssertNil(error); - }]; - - OCMVerify([self.mAPM startExecutionTraceWithName:name]); - [self waitForExpectations:@[expectation] timeout:5.0]; -} -- (void)testStartExecutionTraceWhenTraceIsNil { - NSString *traceId = @"trace-id"; - NSString *name = @"trace-name"; - XCTestExpectation *expectation = [self expectationWithDescription:@"Call completion handler"]; - - OCMStub([self.mAPM startExecutionTraceWithName:name]).andReturn(nil); - - [self.api startExecutionTraceId:traceId name:name completion:^(NSString *actualId, FlutterError *error) { - [expectation fulfill]; - XCTAssertNil(actualId); - XCTAssertNil(error); - }]; - - OCMVerify([self.mAPM startExecutionTraceWithName:name]); - [self waitForExpectations:@[expectation] timeout:5.0]; -} - (void)testSetExecutionTraceAttribute { diff --git a/example/ios/InstabugTests/InstabugApiTests.m b/example/ios/InstabugTests/InstabugApiTests.m index 9f2c04373..22a4a2df0 100644 --- a/example/ios/InstabugTests/InstabugApiTests.m +++ b/example/ios/InstabugTests/InstabugApiTests.m @@ -200,31 +200,6 @@ - (void)testGetTags { [self waitForExpectations:@[expectation] timeout:5.0]; } -- (void)testAddExperiments { - NSArray *experiments = @[@"premium", @"star"]; - FlutterError *error; - - [self.api addExperimentsExperiments:experiments error:&error]; - - OCMVerify([self.mInstabug addExperiments:experiments]); -} - -- (void)testRemoveExperiments { - NSArray *experiments = @[@"premium", @"star"]; - FlutterError *error; - - [self.api removeExperimentsExperiments:experiments error:&error]; - - OCMVerify([self.mInstabug removeExperiments:experiments]); -} - -- (void)testClearAllExperiments { - FlutterError *error; - - [self.api clearAllExperimentsWithError:&error]; - - OCMVerify([self.mInstabug clearAllExperiments]); -} - (void)testAddFeatureFlags { NSDictionary *featureFlagsMap = @{ @"key13" : @"value1", @"key2" : @"value2"}; diff --git a/ios/Classes/Modules/ApmApi.m b/ios/Classes/Modules/ApmApi.m index c6295ce67..a8c5c1bd3 100644 --- a/ios/Classes/Modules/ApmApi.m +++ b/ios/Classes/Modules/ApmApi.m @@ -70,44 +70,6 @@ - (void)setAutoUITraceEnabledIsEnabled:(NSNumber *)isEnabled error:(FlutterError IBGAPM.autoUITraceEnabled = [isEnabled boolValue]; } -// This method is responsible for starting an execution trace -// with a given `id` and `name`. -// -// Deprecated - see [startFlowName, setFlowAttributeName & endFlowName]. -- (void)startExecutionTraceId:(NSString *)id name:(NSString *)name completion:(void(^)(NSString *_Nullable, FlutterError *_Nullable))completion { - IBGExecutionTrace *trace = [IBGAPM startExecutionTraceWithName:name]; - - if (trace != nil) { - [traces setObject:trace forKey:id]; - return completion(id, nil); - } else { - return completion(nil, nil); - } -} - -// This method is responsible for setting an attribute for a specific -// execution trace identified by the provided `id`. -// -// Deprecated - see [startFlowName, setFlowAttributeName & endFlowName]. -- (void)setExecutionTraceAttributeId:(NSString *)id key:(NSString *)key value:(NSString *)value error:(FlutterError *_Nullable *_Nonnull)error { - IBGExecutionTrace *trace = [traces objectForKey:id]; - - if (trace != nil) { - [trace setAttributeWithKey:key value:value]; - } -} - -// This method `endExecutionTraceId` is responsible for ending an execution trace identified by the -// provided `id`. -// -// Deprecated - see [startFlowName, setFlowAttributeName & endFlowName]. -- (void)endExecutionTraceId:(NSString *)id error:(FlutterError *_Nullable *_Nonnull)error { - IBGExecutionTrace *trace = [traces objectForKey:id]; - - if (trace != nil) { - [trace end]; - } -} // This method is responsible for starting a flow with the given `name`. This functionality is used to // track and monitor the performance of specific flows within the application. diff --git a/ios/Classes/Modules/BugReportingApi.m b/ios/Classes/Modules/BugReportingApi.m index bb97810b8..7a92a9563 100644 --- a/ios/Classes/Modules/BugReportingApi.m +++ b/ios/Classes/Modules/BugReportingApi.m @@ -151,8 +151,7 @@ - (void)setDisclaimerTextText:(NSString *)text error:(FlutterError *_Nullable *_ } - (void)setCommentMinimumCharacterCountLimit:(NSNumber *)limit reportTypes:(nullable NSArray *)reportTypes error:(FlutterError *_Nullable *_Nonnull)error { - IBGBugReportingReportType resolvedTypes = 0; - + IBGBugReportingType resolvedTypes = 0; if (![reportTypes count]) { resolvedTypes = (ArgsRegistry.reportTypes[@"ReportType.bug"]).integerValue | (ArgsRegistry.reportTypes[@"ReportType.feedback"]).integerValue | (ArgsRegistry.reportTypes[@"ReportType.question"]).integerValue; } @@ -162,7 +161,7 @@ - (void)setCommentMinimumCharacterCountLimit:(NSNumber *)limit reportTypes:(null } } - [IBGBugReporting setCommentMinimumCharacterCountForReportTypes:resolvedTypes withLimit:limit.intValue]; + [IBGBugReporting setCommentMinimumCharacterCount:[limit integerValue] forBugReportType:resolvedTypes]; } - (void)addUserConsentsKey:(NSString *)key diff --git a/ios/Classes/Modules/InstabugApi.m b/ios/Classes/Modules/InstabugApi.m index 3bdc465f0..aeab423b0 100644 --- a/ios/Classes/Modules/InstabugApi.m +++ b/ios/Classes/Modules/InstabugApi.m @@ -127,17 +127,7 @@ - (void)getTagsWithCompletion:(nonnull void (^)(NSArray * _Nullable, completion([Instabug getTags], nil); } -- (void)addExperimentsExperiments:(NSArray *)experiments error:(FlutterError *_Nullable *_Nonnull)error { - [Instabug addExperiments:experiments]; -} - -- (void)removeExperimentsExperiments:(NSArray *)experiments error:(FlutterError *_Nullable *_Nonnull)error { - [Instabug removeExperiments:experiments]; -} -- (void)clearAllExperimentsWithError:(FlutterError *_Nullable *_Nonnull)error { - [Instabug clearAllExperiments]; -} - (void)setUserAttributeValue:(NSString *)value key:(NSString *)key error:(FlutterError *_Nullable *_Nonnull)error { [Instabug setUserAttribute:value withKey:key]; diff --git a/lib/instabug_flutter.dart b/lib/instabug_flutter.dart index e38545897..46df8597a 100644 --- a/lib/instabug_flutter.dart +++ b/lib/instabug_flutter.dart @@ -3,7 +3,6 @@ export 'src/models/crash_data.dart'; export 'src/models/exception_data.dart'; export 'src/models/feature_flag.dart'; export 'src/models/network_data.dart'; -export 'src/models/trace.dart'; export 'src/models/w3c_header.dart'; // Modules diff --git a/lib/src/models/trace.dart b/lib/src/models/trace.dart deleted file mode 100644 index bf267640b..000000000 --- a/lib/src/models/trace.dart +++ /dev/null @@ -1,44 +0,0 @@ -import 'package:instabug_flutter/src/modules/apm.dart'; - -class Trace { - Trace({ - required this.id, - required this.name, - }); - - final String id; - final String name; - final Map attributes = {}; - - /// Sets attribute of execution trace. - /// [String] id of the trace. - /// [String] key of attribute. - /// [String] value of attribute. - /// - /// Please migrate to the App Flows APIs: [APM.startFlow], [APM.setFlowAttribute], and [APM.endFlow]. - @Deprecated( - 'Please migrate to the App Flows APIs: APM.startAppFlow, APM.endFlow, and APM.setFlowAttribute. This feature was deprecated in v13.0.0', - ) - void setAttribute(String key, String value) { - APM.setExecutionTraceAttribute(id, key, value); - attributes[key] = value; - } - - /// Ends Execution Trace - /// - /// Please migrate to the App Flows APIs: [APM.startFlow], [APM.setFlowAttribute], and [APM.endFlow]. - @Deprecated( - 'Please migrate to the App Flows APIs: APM.startAppFlow, APM.endFlow, and APM.setFlowAttribute. This feature was deprecated in v13.0.0', - ) - void end() { - APM.endExecutionTrace(id); - } - - Map toJson() { - return { - 'id': id, - 'name': name, - 'attributes': attributes, - }; - } -} diff --git a/lib/src/modules/apm.dart b/lib/src/modules/apm.dart index a9f6e0a7c..7d6d5195c 100644 --- a/lib/src/modules/apm.dart +++ b/lib/src/modules/apm.dart @@ -72,58 +72,6 @@ class APM { return _host.setColdAppLaunchEnabled(isEnabled); } - /// Starts an execution trace. - /// [String] name of the trace. - /// - /// Please migrate to the App Flows APIs: [startFlow], [setFlowAttribute], and [endFlow]. - @Deprecated( - 'Please migrate to the App Flows APIs: APM.startAppFlow, APM.endFlow, and APM.setFlowAttribute. This feature was deprecated in v13.0.0', - ) - static Future startExecutionTrace(String name) async { - final id = IBGDateTime.instance.now(); - final traceId = await _host.startExecutionTrace(id.toString(), name); - - if (traceId == null) { - return Future.error( - "Execution trace $name wasn't created. Please make sure to enable APM first by following " - 'the instructions at this link: https://docs.instabug.com/reference#enable-or-disable-apm', - ); - } - - return Trace( - id: traceId, - name: name, - ); - } - - /// Sets attribute of an execution trace. - /// [String] id of the trace. - /// [String] key of attribute. - /// [String] value of attribute. - /// - /// Please migrate to the App Flows APIs: [startFlow], [setFlowAttribute], and [endFlow]. - @Deprecated( - 'Please migrate to the App Flows APIs: APM.startAppFlow, APM.endFlow, and APM.setFlowAttribute. This feature was deprecated in v13.0.0', - ) - static Future setExecutionTraceAttribute( - String id, - String key, - String value, - ) async { - return _host.setExecutionTraceAttribute(id, key, value); - } - - /// Ends an execution trace. - /// [String] id of the trace. - /// - /// Please migrate to the App Flows APIs: [startFlow], [setFlowAttribute], and [endFlow]. - @Deprecated( - 'Please migrate to the App Flows APIs: APM.startAppFlow, APM.endFlow, and APM.setFlowAttribute. This feature was deprecated in v13.0.0', - ) - static Future endExecutionTrace(String id) async { - return _host.endExecutionTrace(id); - } - /// Starts an AppFlow with the given [name]. /// /// The [name] must not be an empty string. It should be unique and not exceed 150 characters, diff --git a/lib/src/modules/instabug.dart b/lib/src/modules/instabug.dart index 6bba8ed1f..4745359d1 100644 --- a/lib/src/modules/instabug.dart +++ b/lib/src/modules/instabug.dart @@ -258,31 +258,6 @@ class Instabug { return tags?.cast(); } - /// Adds experiments to the next report. - @Deprecated( - 'Please migrate to the new feature flags APIs: Instabug.addFeatureFlags.', - ) - static Future addExperiments(List experiments) async { - return _host.addExperiments(experiments); - } - - /// Removes certain experiments from the next report. - @Deprecated( - 'Please migrate to the new feature flags APIs: Instabug.removeFeatureFlags.', - ) - static Future removeExperiments(List experiments) async { - return _host.removeExperiments(experiments); - } - - /// Clears all experiments from the next report. - - @Deprecated( - 'Please migrate to the new feature flags APIs: Instabug.clearAllFeatureFlags.', - ) - static Future clearAllExperiments() async { - return _host.clearAllExperiments(); - } - /// Adds feature flags to the next report. static Future addFeatureFlags(List featureFlags) async { final map = {}; @@ -358,8 +333,13 @@ class Instabug { /// Sets the primary color of the SDK's UI. /// Sets the color of UI elements indicating interactivity or call to action. /// [color] primaryColor A color to set the UI elements of the SDK to. + /// + /// Note: This API is deprecated. Please use `Instabug.setTheme` instead. + @Deprecated( + 'This API is deprecated. Please use Instabug.setTheme instead.', + ) static Future setPrimaryColor(Color color) async { - return _host.setPrimaryColor(color.value); + await setTheme(ThemeConfig(primaryColor: color)); } /// Adds specific user data that you need to be added to the reports diff --git a/pigeons/apm.api.dart b/pigeons/apm.api.dart index 84fe9eb8e..25beca00e 100644 --- a/pigeons/apm.api.dart +++ b/pigeons/apm.api.dart @@ -11,18 +11,9 @@ abstract class ApmHostApi { void setColdAppLaunchEnabled(bool isEnabled); void setAutoUITraceEnabled(bool isEnabled); - @async - String? startExecutionTrace(String id, String name); - void startFlow(String name); void setFlowAttribute(String name, String key, String? value); void endFlow(String name); - void setExecutionTraceAttribute( - String id, - String key, - String value, - ); - void endExecutionTrace(String id); void startUITrace(String name); void endUITrace(); void endAppLaunch(); diff --git a/pigeons/instabug.api.dart b/pigeons/instabug.api.dart index 275306987..dc47f22b3 100644 --- a/pigeons/instabug.api.dart +++ b/pigeons/instabug.api.dart @@ -37,9 +37,6 @@ abstract class InstabugHostApi { @async List? getTags(); - void addExperiments(List experiments); - void removeExperiments(List experiments); - void clearAllExperiments(); void addFeatureFlags(Map featureFlagsMap); void removeFeatureFlags(List featureFlags); void removeAllFeatureFlags(); diff --git a/test/apm_test.dart b/test/apm_test.dart index c801926f3..16cc2f26d 100644 --- a/test/apm_test.dart +++ b/test/apm_test.dart @@ -86,48 +86,6 @@ void main() { ).called(1); }); - test('[startExecutionTrace] should call host method', () async { - final id = DateTime.now(); - const name = "trace"; - - when(mDateTime.now()).thenAnswer((_) => id); - when(mHost.startExecutionTrace(id.toString(), name)) - .thenAnswer((_) async => id.toString()); - - // ignore: deprecated_member_use_from_same_package - final trace = await APM.startExecutionTrace(name); - - expect(trace.id, id.toString()); - - verify( - mHost.startExecutionTrace(id.toString(), name), - ).called(1); - }); - - test('[setExecutionTraceAttribute] should call host method', () async { - final id = DateTime.now().toString(); - const key = "attr-key"; - const attribute = "Trace Attribute"; - - // ignore: deprecated_member_use_from_same_package - await APM.setExecutionTraceAttribute(id, key, attribute); - - verify( - mHost.setExecutionTraceAttribute(id, key, attribute), - ).called(1); - }); - - test('[endExecutionTrace] should call host method', () async { - final id = DateTime.now().toString(); - - // ignore: deprecated_member_use_from_same_package - await APM.endExecutionTrace(id); - - verify( - mHost.endExecutionTrace(id), - ).called(1); - }); - test('[startFlow] should call host method', () async { const flowName = "flow-name"; await APM.startFlow(flowName); diff --git a/test/instabug_test.dart b/test/instabug_test.dart index e2fd7d298..f9f1a6993 100644 --- a/test/instabug_test.dart +++ b/test/instabug_test.dart @@ -258,37 +258,6 @@ void main() { ).called(1); }); - test('[addExperiments] should call host method', () async { - const experiments = ["exp-1", "exp-2"]; - - // ignore: deprecated_member_use_from_same_package - await Instabug.addExperiments(experiments); - - verify( - mHost.addExperiments(experiments), - ).called(1); - }); - - test('[removeExperiments] should call host method', () async { - const experiments = ["exp-1", "exp-2"]; - - // ignore: deprecated_member_use_from_same_package - await Instabug.removeExperiments(experiments); - - verify( - mHost.removeExperiments(experiments), - ).called(1); - }); - - test('[clearAllExperiments] should call host method', () async { - // ignore: deprecated_member_use_from_same_package - await Instabug.clearAllExperiments(); - - verify( - mHost.clearAllExperiments(), - ).called(1); - }); - test('[addFeatureFlags] should call host method', () async { await Instabug.addFeatureFlags([ FeatureFlag(name: 'name1', variant: 'variant1'), diff --git a/test/trace_test.dart b/test/trace_test.dart deleted file mode 100644 index 2415420be..000000000 --- a/test/trace_test.dart +++ /dev/null @@ -1,46 +0,0 @@ -import 'package:flutter/widgets.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:instabug_flutter/instabug_flutter.dart'; -import 'package:instabug_flutter/src/generated/apm.api.g.dart'; -import 'package:mockito/annotations.dart'; -import 'package:mockito/mockito.dart'; - -import 'trace_test.mocks.dart'; - -@GenerateMocks([ - ApmHostApi, -]) -void main() { - TestWidgetsFlutterBinding.ensureInitialized(); - WidgetsFlutterBinding.ensureInitialized(); - - final mHost = MockApmHostApi(); - final trace = Trace( - id: "trace", - name: "Execution Trace", - ); - - setUpAll(() { - APM.$setHostApi(mHost); - }); - - test('[end] should call host method', () async { - // ignore: deprecated_member_use_from_same_package - trace.end(); - - verify( - mHost.endExecutionTrace(trace.id), - ).called(1); - }); - - test('[setAttribute] should call host method', () async { - const key = "attr-key"; - const attribute = "Trace Attribute"; - // ignore: deprecated_member_use_from_same_package - trace.setAttribute(key, attribute); - - verify( - mHost.setExecutionTraceAttribute(trace.id, key, attribute), - ).called(1); - }); -} From cb1938393427fa3557b0beb72470b52092e85925 Mon Sep 17 00:00:00 2001 From: AyaMahmoud148 Date: Thu, 31 Jul 2025 15:18:39 +0300 Subject: [PATCH 43/84] chore: add changelog --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9cb867f5c..c980f4616 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## [Unreleased](https://github.com/Instabug/Instabug-Flutter/compare/v15.0.2...dev) + +### Changed + +- **BREAKING** Remove deprecated APIs ([#614](https://github.com/Instabug/Instabug-Flutter/pull/614)). See migration guide for more details. + ## [15.0.2](https://github.com/Instabug/Instabug-Flutter/compare/v14.3.0...15.0.2) (Jul 7, 2025) ### Added From 4257f33846f1c5a92616c4d25f6a9390946be627 Mon Sep 17 00:00:00 2001 From: AyaMahmoud148 Date: Thu, 31 Jul 2025 15:27:15 +0300 Subject: [PATCH 44/84] fix: setTheme calling --- lib/src/modules/instabug.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/modules/instabug.dart b/lib/src/modules/instabug.dart index cd4095c0f..b36e60ab9 100644 --- a/lib/src/modules/instabug.dart +++ b/lib/src/modules/instabug.dart @@ -339,7 +339,7 @@ class Instabug { 'This API is deprecated. Please use Instabug.setTheme instead.', ) static Future setPrimaryColor(Color color) async { - await setTheme(ThemeConfig(primaryColor: color)); + await setTheme(ThemeConfig(primaryColor: color.toString())); } /// Adds specific user data that you need to be added to the reports From 5c59d8c2de130a9c9f387df72e8a3f0fda0c17e5 Mon Sep 17 00:00:00 2001 From: AyaMahmoud148 Date: Thu, 31 Jul 2025 15:30:29 +0300 Subject: [PATCH 45/84] fix: formatte --- lib/src/modules/apm.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/src/modules/apm.dart b/lib/src/modules/apm.dart index 7d6d5195c..7195e40cd 100644 --- a/lib/src/modules/apm.dart +++ b/lib/src/modules/apm.dart @@ -5,7 +5,6 @@ import 'dart:async'; import 'package:flutter/widgets.dart' show WidgetBuilder; import 'package:instabug_flutter/src/generated/apm.api.g.dart'; import 'package:instabug_flutter/src/models/network_data.dart'; -import 'package:instabug_flutter/src/models/trace.dart'; import 'package:instabug_flutter/src/utils/ibg_build_info.dart'; import 'package:instabug_flutter/src/utils/ibg_date_time.dart'; import 'package:instabug_flutter/src/utils/instabug_logger.dart'; From 47d148f6caecff0b13b4dc82b15681c3091ef3c7 Mon Sep 17 00:00:00 2001 From: Andrew Amin Date: Thu, 31 Jul 2025 17:19:46 +0300 Subject: [PATCH 46/84] add: tolerance value to screen render capturing --- android/build.gradle | 2 +- .../com/instabug/flutter/modules/ApmApi.java | 60 +++++++++++-------- .../flutter/modules/BugReportingApi.java | 2 +- .../instabug/flutter/modules/InstabugApi.java | 2 +- ios/Classes/Modules/ApmApi.m | 21 ++++--- lib/src/modules/apm.dart | 8 ++- .../instabug_screen_render_manager.dart | 25 +++++--- pigeons/apm.api.dart | 2 +- test/apm_test.dart | 11 ++-- .../instabug_screen_render_manager_test.dart | 40 ++++++++++++- 10 files changed, 120 insertions(+), 53 deletions(-) diff --git a/android/build.gradle b/android/build.gradle index 3f5817b8c..32428f00e 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -52,7 +52,7 @@ android { } dependencies { - api 'com.instabug.library:instabug:15.0.2.7020723-SNAPSHOT' + api 'com.instabug.library:instabug:15.0.2.7046628-SNAPSHOT' testImplementation 'junit:junit:4.13.2' testImplementation "org.mockito:mockito-inline:3.12.1" testImplementation "io.mockk:mockk:1.13.13" diff --git a/android/src/main/java/com/instabug/flutter/modules/ApmApi.java b/android/src/main/java/com/instabug/flutter/modules/ApmApi.java index 61d0fca68..66f589197 100644 --- a/android/src/main/java/com/instabug/flutter/modules/ApmApi.java +++ b/android/src/main/java/com/instabug/flutter/modules/ApmApi.java @@ -9,7 +9,8 @@ import com.instabug.apm.InternalAPM; import com.instabug.apm.configuration.cp.APMFeature; import com.instabug.apm.configuration.cp.FeatureAvailabilityCallback; -import com.instabug.apm.model.ExecutionTrace; +import com.instabug.apm.configuration.cp.ToleranceValueCallback; +//import com.instabug.apm.model.ExecutionTrace; import com.instabug.apm.networking.APMNetworkLogger; import com.instabug.apm.networkinterception.cp.APMCPNetworkLog; import com.instabug.apm.screenrendering.models.cp.IBGFrameData; @@ -31,11 +32,11 @@ public class ApmApi implements ApmPigeon.ApmHostApi { private final String TAG = ApmApi.class.getName(); - private final HashMap traces = new HashMap<>(); - private final Callable refreshRate; +// private final HashMap traces = new HashMap<>(); + private final Callable refreshRateCallback; public ApmApi(Callable refreshRate) { - this.refreshRate = refreshRate; + this.refreshRateCallback = refreshRate; } public static void init(BinaryMessenger messenger, Callable refreshRateProvider) { @@ -114,24 +115,24 @@ public void startExecutionTrace(@NonNull String id, @NonNull String name, ApmPig @Override public void run() { try { - ExecutionTrace trace = APM.startExecutionTrace(name); - if (trace != null) { - traces.put(id, trace); - - ThreadManager.runOnMainThread(new Runnable() { - @Override - public void run() { - result.success(id); - } - }); - } else { - ThreadManager.runOnMainThread(new Runnable() { - @Override - public void run() { - result.success(null); - } - }); - } +// ExecutionTrace trace = APM.startExecutionTrace(name); +// if (trace != null) { +// traces.put(id, trace); +// +// ThreadManager.runOnMainThread(new Runnable() { +// @Override +// public void run() { +// result.success(id); +// } +// }); +// } else { +// ThreadManager.runOnMainThread(new Runnable() { +// @Override +// public void run() { +// result.success(null); +// } +// }); +// } } catch (Exception e) { e.printStackTrace(); @@ -220,7 +221,7 @@ public void endFlow(@NonNull String name) { @Override public void setExecutionTraceAttribute(@NonNull String id, @NonNull String key, @NonNull String value) { try { - traces.get(id).setAttribute(key, value); +// traces.get(id).setAttribute(key, value); } catch (Exception e) { e.printStackTrace(); } @@ -235,7 +236,7 @@ public void setExecutionTraceAttribute(@NonNull String id, @NonNull String key, @Override public void endExecutionTrace(@NonNull String id) { try { - traces.get(id).end(); +// traces.get(id).end(); } catch (Exception e) { e.printStackTrace(); } @@ -504,9 +505,16 @@ public void invoke(boolean isEnabled) { } @Override - public void deviceRefreshRate(@NonNull ApmPigeon.Result result) { + public void getDeviceRefreshRateAndTolerance(@NonNull ApmPigeon.Result> result) { try { - result.success(refreshRate.call().doubleValue()); + final double refreshRate = refreshRateCallback.call().doubleValue(); + InternalAPM._getToleranceValueForScreenRenderingCP(new ToleranceValueCallback() { + @Override + public void invoke(long tolerance) { + result.success(java.util.Arrays.asList(refreshRate, (double) tolerance)); + } + }); + } catch (Exception e) { e.printStackTrace(); } diff --git a/android/src/main/java/com/instabug/flutter/modules/BugReportingApi.java b/android/src/main/java/com/instabug/flutter/modules/BugReportingApi.java index f3236bb4e..13ea24a0b 100644 --- a/android/src/main/java/com/instabug/flutter/modules/BugReportingApi.java +++ b/android/src/main/java/com/instabug/flutter/modules/BugReportingApi.java @@ -184,7 +184,7 @@ public void setCommentMinimumCharacterCount(@NonNull Long limit, @Nullable List< reportTypesArray[i] = ArgsRegistry.reportTypes.get(key); } } - BugReporting.setCommentMinimumCharacterCount(limit.intValue(), reportTypesArray); +// BugReporting.setCommentMinimumCharacterCount(limit.intValue(), reportTypesArray); } @Override diff --git a/android/src/main/java/com/instabug/flutter/modules/InstabugApi.java b/android/src/main/java/com/instabug/flutter/modules/InstabugApi.java index edfde055a..057128f47 100644 --- a/android/src/main/java/com/instabug/flutter/modules/InstabugApi.java +++ b/android/src/main/java/com/instabug/flutter/modules/InstabugApi.java @@ -176,7 +176,7 @@ public void setWelcomeMessageMode(@NonNull String mode) { @Override public void setPrimaryColor(@NonNull Long color) { - Instabug.setPrimaryColor(color.intValue()); + } @Override diff --git a/ios/Classes/Modules/ApmApi.m b/ios/Classes/Modules/ApmApi.m index 4787a9b22..9f6daef14 100644 --- a/ios/Classes/Modules/ApmApi.m +++ b/ios/Classes/Modules/ApmApi.m @@ -208,15 +208,6 @@ - (void)setScreenRenderEnabledIsEnabled:(nonnull NSNumber *)isEnabled error:(Flu } -- (void)deviceRefreshRateWithCompletion:(void (^)(NSNumber * _Nullable, FlutterError * _Nullable))completion{ - if (@available(iOS 10.3, *)) { - double refreshRate = [UIScreen mainScreen].maximumFramesPerSecond; - completion(@(refreshRate) ,nil); - } else { - // Fallback for very old iOS versions. - completion(@(60.0) , nil); - } -} - (void)endScreenRenderForAutoUiTraceData:(nonnull NSDictionary *)data error:(FlutterError * _Nullable __autoreleasing * _Nonnull)error { NSArray *> *rawFrames = data[@"frameData"]; @@ -254,6 +245,18 @@ - (void)endScreenRenderForCustomUiTraceData:(nonnull NSDictionary [IBGAPM endCustomUITraceCPWithFrames:frameInfos]; } +- (void)getDeviceRefreshRateAndToleranceWithCompletion:(nonnull void (^)(NSArray * _Nullable, FlutterError * _Nullable))completion { + if (@available(iOS 10.3, *)) { + double refreshRate = [UIScreen mainScreen].maximumFramesPerSecond; + double tolerance = 10; + completion(@[@(refreshRate), @(tolerance)] ,nil); + } else { + // Fallback for very old iOS versions. + completion(@[@(60.0), @(10.0)] , nil); + } +} + + @end diff --git a/lib/src/modules/apm.dart b/lib/src/modules/apm.dart index d832964f8..9324515ed 100644 --- a/lib/src/modules/apm.dart +++ b/lib/src/modules/apm.dart @@ -378,9 +378,13 @@ class APM { /// /// Returns: /// A Future that represent the refresh rate. + /// Retrieve the device refresh rate and tolerance value from native side. + /// + /// Returns: + /// A Future> where the first element is the refresh rate and the second is the tolerance value. @internal - static Future getDeviceRefreshRate() { - return _host.deviceRefreshRate(); + static Future> getDeviceRefreshRateAndTolerance() { + return _host.getDeviceRefreshRateAndTolerance(); } /// Sets the screen Render state based on the provided boolean value. diff --git a/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart b/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart index b89b3c312..efad33dbe 100644 --- a/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart +++ b/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart @@ -34,9 +34,6 @@ class InstabugScreenRenderManager { final List _delayedFrames = []; - /// 1 / DeviceRefreshRate * 1000 - double _deviceRefreshRate = 60; - /// Default refresh rate for 60 FPS displays in milliseconds (16.67ms) double _slowFrameThresholdMs = 16.67; @@ -230,8 +227,8 @@ class InstabugScreenRenderManager { 1 / displayRefreshRate * 1000; /// Get device refresh rate from native side. - Future get _getDeviceRefreshRateFromNative => - APM.getDeviceRefreshRate(); + Future> get _getDeviceRefreshRateAndToleranceFromNative => + APM.getDeviceRefreshRateAndTolerance(); /// add new [WidgetsBindingObserver] to track app lifecycle. void _addWidgetBindingObserver() { @@ -265,12 +262,26 @@ class InstabugScreenRenderManager { analyzeFrameTiming(frameTiming); } }; - _deviceRefreshRate = await _getDeviceRefreshRateFromNative; - _slowFrameThresholdMs = _targetMsPerFrame(_deviceRefreshRate); + _slowFrameThresholdMs = await _getSlowFrameThresholdMs; _screenRenderForAutoUiTrace = InstabugScreenRenderData(frameData: []); _screenRenderForCustomUiTrace = InstabugScreenRenderData(frameData: []); } + Future get _getSlowFrameThresholdMs async { + final deviceRefreshRateAndTolerance = + await _getDeviceRefreshRateAndToleranceFromNative; + final deviceRefreshRate = deviceRefreshRateAndTolerance[0] ?? + 60; // default to 60 FPS if not available + final toleranceMs = (deviceRefreshRateAndTolerance[1] ?? 10) / + 1000; // convert the tolerance from microseconds to milliseconds + final targetMsPerFrame = _targetMsPerFrame(deviceRefreshRate); + return double.parse( + (targetMsPerFrame + toleranceMs).toStringAsFixed( + 2, + ), + ); // round the result to the nearest 2 precision digits + } + int _getEpochOffset(FrameTiming firstPatchedFrameTiming) { return DateTime.now().microsecondsSinceEpoch - firstPatchedFrameTiming.timestampInMicroseconds(FramePhase.vsyncStart); diff --git a/pigeons/apm.api.dart b/pigeons/apm.api.dart index 3711d53fc..729103ba8 100644 --- a/pigeons/apm.api.dart +++ b/pigeons/apm.api.dart @@ -58,7 +58,7 @@ abstract class ApmHostApi { bool isScreenRenderEnabled(); @async - double deviceRefreshRate(); + List getDeviceRefreshRateAndTolerance(); void setScreenRenderEnabled(bool isEnabled); diff --git a/test/apm_test.dart b/test/apm_test.dart index e080f6f88..f27c4eb63 100644 --- a/test/apm_test.dart +++ b/test/apm_test.dart @@ -275,10 +275,13 @@ void main() { verify(mHost.isScreenRenderEnabled()); }); - test("[getDeviceRefreshRate] should call host method", () async { - when(mHost.deviceRefreshRate()).thenAnswer((_) async => 60.0); - await APM.getDeviceRefreshRate(); - verify(mHost.deviceRefreshRate()).called(1); + test("[getDeviceRefreshRateAndTolerance] should call host method", + () async { + when(mHost.getDeviceRefreshRateAndTolerance()).thenAnswer( + (_) async => [60.0, 10.0], + ); + await APM.getDeviceRefreshRateAndTolerance(); + verify(mHost.getDeviceRefreshRateAndTolerance()).called(1); }); test("[setScreenRenderEnabled] should call host method", () async { diff --git a/test/utils/screen_render/instabug_screen_render_manager_test.dart b/test/utils/screen_render/instabug_screen_render_manager_test.dart index 9f99ac0f4..c5ab4d8df 100644 --- a/test/utils/screen_render/instabug_screen_render_manager_test.dart +++ b/test/utils/screen_render/instabug_screen_render_manager_test.dart @@ -1,12 +1,17 @@ +import 'package:flutter/scheduler.dart' show FrameTiming; +import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:instabug_flutter/instabug_flutter.dart'; +import 'package:instabug_flutter/src/generated/apm.api.g.dart'; import 'package:instabug_flutter/src/models/instabug_frame_data.dart'; import 'package:instabug_flutter/src/models/instabug_screen_render_data.dart'; import 'package:instabug_flutter/src/utils/screen_rendering/instabug_screen_render_manager.dart'; +import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; import 'instabug_screen_render_manager_test.mocks.dart'; +@GenerateMocks([ApmHostApi, FrameTiming, WidgetsBinding]) void main() { TestWidgetsFlutterBinding.ensureInitialized(); @@ -19,7 +24,8 @@ void main() { mWidgetBinding = MockWidgetsBinding(); manager = InstabugScreenRenderManager.init(); // test-only constructor APM.$setHostApi(mApmHost); - when(mApmHost.deviceRefreshRate()).thenAnswer((_) async => 60); + when(mApmHost.getDeviceRefreshRateAndTolerance()) + .thenAnswer((_) async => [60, 0]); manager.init(mWidgetBinding); }); @@ -44,6 +50,38 @@ void main() { }); }); + // group('_initStaticValues', () { + // + // test('should initialize _timingsCallback', () async { + // await manager.callInitStaticValues(); + // expect(manager.timingsCallback, isNotNull); + // }); + // + // test('should initialize _slowFrameThresholdMs with value from _getSlowFrameThresholdMs', () async { + // // Patch the getter to return a known value + // manager.slowFrameThresholdMs = 0.0; + // manager.getSlowFrameThresholdMsFuture = () async => 42.0; + // await manager.callInitStaticValues(); + // expect(manager.slowFrameThresholdMs, 42.0); + // }); + // + // test('should initialize _screenRenderForAutoUiTrace and _screenRenderForCustomUiTrace as empty InstabugScreenRenderData', () async { + // await manager.callInitStaticValues(); + // expect(manager.screenRenderForAutoUiTrace, isA()); + // expect(manager.screenRenderForAutoUiTrace.frameData, isEmpty); + // expect(manager.screenRenderForCustomUiTrace, isA()); + // expect(manager.screenRenderForCustomUiTrace.frameData, isEmpty); + // }); + // + // test('should set _epochOffset on first timing in _timingsCallback', () async { + // await manager.callInitStaticValues(); + // final mockFrameTiming = MockFrameTiming(); + // manager.epochOffset = null; + // manager.timingsCallback([mockFrameTiming]); + // expect(manager.epochOffset, isNotNull); + // }); + // }); + group('startScreenRenderCollectorForTraceId()', () { test('should not attach timing listener if it is attached', () async { manager.startScreenRenderCollectorForTraceId(1); From e7c05cf48e58e85b06d55c0a3cdba46fd9a8f745 Mon Sep 17 00:00:00 2001 From: Andrew Amin Date: Thu, 31 Jul 2025 17:40:03 +0300 Subject: [PATCH 47/84] chore: update iOS pods --- example/ios/Podfile | 2 +- example/ios/Podfile.lock | 14 +++++++------- ios/instabug_flutter.podspec | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/example/ios/Podfile b/example/ios/Podfile index ee4476ba0..9b49aa25b 100644 --- a/example/ios/Podfile +++ b/example/ios/Podfile @@ -30,7 +30,7 @@ target 'Runner' do use_frameworks! use_modular_headers! - pod 'Instabug', :podspec => 'https://ios-releases.instabug.com/custom/faeture-screen_rendering-release/15.1.19/Instabug.podspec' + pod 'Instabug', :podspec => 'https://ios-releases.instabug.com/custom/faeture-screen_rendering-release/15.1.23/Instabug.podspec' flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) end diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index 703787e60..43ffb07ea 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -1,14 +1,14 @@ PODS: - Flutter (1.0.0) - - Instabug (15.1.19) + - Instabug (15.1.23) - instabug_flutter (14.3.0): - Flutter - - Instabug (= 15.1.19) + - Instabug (= 15.1.23) - OCMock (3.6) DEPENDENCIES: - Flutter (from `Flutter`) - - Instabug (from `https://ios-releases.instabug.com/custom/faeture-screen_rendering-release/15.1.19/Instabug.podspec`) + - Instabug (from `https://ios-releases.instabug.com/custom/faeture-screen_rendering-release/15.1.23/Instabug.podspec`) - instabug_flutter (from `.symlinks/plugins/instabug_flutter/ios`) - OCMock (= 3.6) @@ -20,16 +20,16 @@ EXTERNAL SOURCES: Flutter: :path: Flutter Instabug: - :podspec: https://ios-releases.instabug.com/custom/faeture-screen_rendering-release/15.1.19/Instabug.podspec + :podspec: https://ios-releases.instabug.com/custom/faeture-screen_rendering-release/15.1.23/Instabug.podspec instabug_flutter: :path: ".symlinks/plugins/instabug_flutter/ios" SPEC CHECKSUMS: Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 - Instabug: 74377abfdaa9f9f3dff7793353e150e91d2186f7 - instabug_flutter: aa9b2365fe41d8a49f9258ab350864bfb5bdce9e + Instabug: b4659339dc6f67693cf9bd1224abc66831b8722f + instabug_flutter: eeb2e13eefca00e94de1f9156df4889f5481506a OCMock: 5ea90566be239f179ba766fd9fbae5885040b992 -PODFILE CHECKSUM: d61a5c8efcff86500b76349ccad5201d7756fdea +PODFILE CHECKSUM: 6d8ca5577997736d9cc2249886c9f6d10238385d COCOAPODS: 1.15.2 diff --git a/ios/instabug_flutter.podspec b/ios/instabug_flutter.podspec index 30a9289c2..b4625d3ad 100644 --- a/ios/instabug_flutter.podspec +++ b/ios/instabug_flutter.podspec @@ -17,6 +17,6 @@ Pod::Spec.new do |s| s.pod_target_xcconfig = { 'OTHER_LDFLAGS' => '-framework "Flutter" -framework "InstabugSDK"'} s.dependency 'Flutter' - s.dependency 'Instabug', '15.1.19' + s.dependency 'Instabug', '15.1.23' end From 61da8163fcd51275a12c4f12c8ec12ca52158340 Mon Sep 17 00:00:00 2001 From: AyaMahmoud148 Date: Thu, 31 Jul 2025 22:12:43 +0300 Subject: [PATCH 48/84] fix: formate --- example/lib/main.dart | 2 - .../lib/src/components/traces_content.dart | 157 ------------------ example/lib/src/screens/apm_page.dart | 2 - test/instabug_test.dart | 4 +- 4 files changed, 2 insertions(+), 163 deletions(-) delete mode 100644 example/lib/src/components/traces_content.dart diff --git a/example/lib/main.dart b/example/lib/main.dart index 91b0a67e7..ca49f801e 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -38,8 +38,6 @@ part 'src/components/network_content.dart'; part 'src/components/page.dart'; -part 'src/components/traces_content.dart'; - part 'src/components/flows_content.dart'; void main() { diff --git a/example/lib/src/components/traces_content.dart b/example/lib/src/components/traces_content.dart deleted file mode 100644 index 888460d43..000000000 --- a/example/lib/src/components/traces_content.dart +++ /dev/null @@ -1,157 +0,0 @@ -part of '../../main.dart'; - -class TracesContent extends StatefulWidget { - const TracesContent({Key? key}) : super(key: key); - - @override - State createState() => _TracesContentState(); -} - -class _TracesContentState extends State { - final traceNameController = TextEditingController(); - final traceKeyAttributeController = TextEditingController(); - final traceValueAttributeController = TextEditingController(); - - bool? didTraceEnd; - - Trace? trace; - - @override - Widget build(BuildContext context) { - final textTheme = Theme.of(context).textTheme; - return Column( - children: [ - InstabugTextField( - label: 'Trace name', - labelStyle: textTheme.labelMedium, - controller: traceNameController, - ), - SizedBox.fromSize( - size: const Size.fromHeight(10.0), - ), - Row( - children: [ - Flexible( - flex: 5, - child: InstabugButton.smallFontSize( - text: 'Start Trace', - onPressed: () => _startTrace(traceNameController.text), - margin: const EdgeInsetsDirectional.only( - start: 20.0, - end: 10.0, - ), - ), - ), - Flexible( - flex: 5, - child: InstabugButton.smallFontSize( - text: 'Start Trace With Delay', - onPressed: () => _startTrace( - traceNameController.text, - delayInMilliseconds: 5000, - ), - margin: const EdgeInsetsDirectional.only( - start: 10.0, - end: 20.0, - ), - ), - ), - ], - ), - Row( - children: [ - Flexible( - flex: 5, - child: InstabugTextField( - label: 'Trace Key Attribute', - controller: traceKeyAttributeController, - labelStyle: textTheme.labelMedium, - margin: const EdgeInsetsDirectional.only( - end: 10.0, - start: 20.0, - ), - ), - ), - Flexible( - flex: 5, - child: InstabugTextField( - label: 'Trace Value Attribute', - labelStyle: textTheme.labelMedium, - controller: traceValueAttributeController, - margin: const EdgeInsetsDirectional.only( - start: 10.0, - end: 20.0, - ), - ), - ), - ], - ), - SizedBox.fromSize( - size: const Size.fromHeight(10.0), - ), - InstabugButton( - text: 'Set Trace Attribute', - onPressed: () => _setTraceAttribute( - trace, - traceKeyAttribute: traceKeyAttributeController.text, - traceValueAttribute: traceValueAttributeController.text, - ), - ), - InstabugButton( - text: 'End Trace', - onPressed: () => _endTrace(), - ), - ], - ); - } - - void _startTrace( - String traceName, { - int delayInMilliseconds = 0, - }) { - if (traceName.trim().isNotEmpty) { - log('_startTrace — traceName: $traceName, delay in Milliseconds: $delayInMilliseconds'); - log('traceName: $traceName'); - Future.delayed( - Duration(milliseconds: delayInMilliseconds), - () => APM - .startExecutionTrace(traceName) - .then((value) => trace = value)); - } else { - log('startTrace - Please enter a trace name'); - } - } - - void _endTrace() { - if (didTraceEnd == true) { - log('_endTrace — Please, start a new trace before setting attributes.'); - } - if (trace == null) { - log('_endTrace — Please, start a trace before ending it.'); - } - log('_endTrace — ending Trace.'); - trace?.end(); - didTraceEnd = true; - } - - void _setTraceAttribute( - Trace? trace, { - required String traceKeyAttribute, - required String traceValueAttribute, - }) { - if (trace == null) { - log('_setTraceAttribute — Please, start a trace before setting attributes.'); - } - if (didTraceEnd == true) { - log('_setTraceAttribute — Please, start a new trace before setting attributes.'); - } - if (traceKeyAttribute.trim().isEmpty) { - log('_setTraceAttribute — Please, fill the trace key attribute input before settings attributes.'); - } - if (traceValueAttribute.trim().isEmpty) { - log('_setTraceAttribute — Please, fill the trace value attribute input before settings attributes.'); - } - log('_setTraceAttribute — setting attributes -> key: $traceKeyAttribute, value: $traceValueAttribute.'); - trace?.setAttribute(traceKeyAttribute, traceValueAttribute); - } -} diff --git a/example/lib/src/screens/apm_page.dart b/example/lib/src/screens/apm_page.dart index 798e906fa..d4ad53ca6 100644 --- a/example/lib/src/screens/apm_page.dart +++ b/example/lib/src/screens/apm_page.dart @@ -36,8 +36,6 @@ class _ApmPageState extends State { ), const SectionTitle('Network'), const NetworkContent(), - const SectionTitle('Traces'), - const TracesContent(), const SectionTitle('Flows'), const FlowsContent(), const SectionTitle('Screen Loading'), diff --git a/test/instabug_test.dart b/test/instabug_test.dart index f9f1a6993..5b85fd598 100644 --- a/test/instabug_test.dart +++ b/test/instabug_test.dart @@ -197,13 +197,13 @@ void main() { ).called(1); }); - test('[setPrimaryColor] should call host method', () async { + test('[setPrimaryColor] should call setTheme method', () async { const color = Color(0x00000000); await Instabug.setPrimaryColor(color); verify( - mHost.setPrimaryColor(color.value), + mHost.setTheme({'primaryColor': color.toString()}), ).called(1); }); From 924f1d9342e9dffe091f3f4ebc1d46b4742e1819 Mon Sep 17 00:00:00 2001 From: AyaMahmoud148 Date: Thu, 31 Jul 2025 22:30:00 +0300 Subject: [PATCH 49/84] fix: formatting --- lib/src/modules/apm.dart | 1 - test/instabug_test.dart | 10 ---------- 2 files changed, 11 deletions(-) diff --git a/lib/src/modules/apm.dart b/lib/src/modules/apm.dart index 7195e40cd..970c9330e 100644 --- a/lib/src/modules/apm.dart +++ b/lib/src/modules/apm.dart @@ -6,7 +6,6 @@ import 'package:flutter/widgets.dart' show WidgetBuilder; import 'package:instabug_flutter/src/generated/apm.api.g.dart'; import 'package:instabug_flutter/src/models/network_data.dart'; import 'package:instabug_flutter/src/utils/ibg_build_info.dart'; -import 'package:instabug_flutter/src/utils/ibg_date_time.dart'; import 'package:instabug_flutter/src/utils/instabug_logger.dart'; import 'package:instabug_flutter/src/utils/screen_loading/screen_loading_manager.dart'; import 'package:meta/meta.dart'; diff --git a/test/instabug_test.dart b/test/instabug_test.dart index 5b85fd598..b5d7bd55c 100644 --- a/test/instabug_test.dart +++ b/test/instabug_test.dart @@ -197,16 +197,6 @@ void main() { ).called(1); }); - test('[setPrimaryColor] should call setTheme method', () async { - const color = Color(0x00000000); - - await Instabug.setPrimaryColor(color); - - verify( - mHost.setTheme({'primaryColor': color.toString()}), - ).called(1); - }); - test('[setSessionProfilerEnabled] should call host method', () async { const enabled = true; From 270940c2c7cf947744b34fca5bc473c6f5935149 Mon Sep 17 00:00:00 2001 From: AyaMahmoud148 Date: Thu, 31 Jul 2025 22:43:20 +0300 Subject: [PATCH 50/84] fix: ios tests --- example/ios/InstabugTests/ApmApiTests.m | 34 ------------------------- 1 file changed, 34 deletions(-) diff --git a/example/ios/InstabugTests/ApmApiTests.m b/example/ios/InstabugTests/ApmApiTests.m index bf2fdce54..3be2288d2 100644 --- a/example/ios/InstabugTests/ApmApiTests.m +++ b/example/ios/InstabugTests/ApmApiTests.m @@ -19,16 +19,6 @@ - (void)setUp { self.api = [[ApmApi alloc] init]; } -- (IBGExecutionTrace *)mockTraceWithId:(NSString *)traceId { - NSString* name = @"trace-name"; - IBGExecutionTrace *mTrace = OCMClassMock([IBGExecutionTrace class]); - - OCMStub([self.mAPM startExecutionTraceWithName:name]).andReturn(mTrace); - - [self.api startExecutionTraceId:traceId name:name completion:^(NSString * _Nullable _, FlutterError * _Nullable __) {}]; - - return mTrace; -} - (void)testSetEnabled { NSNumber *isEnabled = @1; @@ -117,30 +107,6 @@ - (void)testSetAutoUITraceEnabled { } - - -- (void)testSetExecutionTraceAttribute { - NSString *traceId = @"trace-id"; - NSString *key = @"is_premium"; - NSString *value = @"true"; - FlutterError *error; - id mTrace = [self mockTraceWithId:traceId]; - - [self.api setExecutionTraceAttributeId:traceId key:key value:value error:&error]; - - OCMVerify([mTrace setAttributeWithKey:key value:value]); -} - -- (void)testEndExecutionTrace { - NSString *traceId = @"trace-id"; - FlutterError *error; - IBGExecutionTrace *mTrace = [self mockTraceWithId:traceId]; - - [self.api endExecutionTraceId:traceId error:&error]; - - OCMVerify([mTrace end]); -} - - (void) testStartFlow { NSString* appFlowName = @"app-flow-name"; FlutterError *error; From 7f301c13cb5abe3a9fd79960c6af5eeb07182959 Mon Sep 17 00:00:00 2001 From: Andrew Amin Date: Fri, 1 Aug 2025 16:31:41 +0300 Subject: [PATCH 51/84] chore: separate the start and end methods of screenRenderCollector --- example/lib/main.dart | 1 + lib/src/modules/apm.dart | 5 +- .../utils/instabug_navigator_observer.dart | 3 + .../instabug_screen_render_manager.dart | 63 +++++++-------- test/apm_test.dart | 7 +- .../instabug_screen_render_manager_test.dart | 79 +++++++++++++------ 6 files changed, 95 insertions(+), 63 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index bc67d868a..aa1719503 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -44,6 +44,7 @@ void main() { Instabug.init( token: 'ed6f659591566da19b67857e1b9d40ab', + // token: '4d75635ae06e5afb4360c04cfcf1987c', invocationEvents: [InvocationEvent.floatingButton], debugLogsLevel: LogLevel.verbose, ).then((_) { diff --git a/lib/src/modules/apm.dart b/lib/src/modules/apm.dart index d832964f8..41cf7d676 100644 --- a/lib/src/modules/apm.dart +++ b/lib/src/modules/apm.dart @@ -196,6 +196,9 @@ class APM { (_) async { // Start screen render collector for custom ui trace if enabled. if (await FlagsConfig.screenRendering.isEnabled()) { + InstabugScreenRenderManager.I.endScreenRenderCollector(); + + // final uiTraceId = IBGDateTime.I.now().millisecondsSinceEpoch; InstabugScreenRenderManager.I .startScreenRenderCollectorForTraceId(0, UiTraceType.custom); } @@ -211,7 +214,7 @@ class APM { // End screen render collector for custom ui trace if enabled. if (InstabugScreenRenderManager.I.screenRenderEnabled) { return InstabugScreenRenderManager.I - .endScreenRenderCollectorForCustomUiTrace(); + .endScreenRenderCollector(); } return _host.endUITrace(); diff --git a/lib/src/utils/instabug_navigator_observer.dart b/lib/src/utils/instabug_navigator_observer.dart index 5793f07fe..3dc9c078c 100644 --- a/lib/src/utils/instabug_navigator_observer.dart +++ b/lib/src/utils/instabug_navigator_observer.dart @@ -1,4 +1,5 @@ import 'dart:async'; +import 'dart:developer'; import 'package:flutter/material.dart'; import 'package:instabug_flutter/instabug_flutter.dart'; @@ -27,6 +28,7 @@ class InstabugNavigatorObserver extends NavigatorObserver { name: maskedScreenName, ); + InstabugScreenRenderManager.I.endScreenRenderCollector(); ScreenLoadingManager.I .startUiTrace(maskedScreenName, screenName) .then(_startScreenRenderCollector); @@ -67,6 +69,7 @@ class InstabugNavigatorObserver extends NavigatorObserver { FutureOr _startScreenRenderCollector(int? uiTraceId) async { final isScreenRenderEnabled = await FlagsConfig.screenRendering.isEnabled(); + log("isScreenRenderEnabled $isScreenRenderEnabled" , name: "Andrew"); await _checkForScreenRenderInitialization(isScreenRenderEnabled); if (uiTraceId != null && isScreenRenderEnabled) { InstabugScreenRenderManager.I diff --git a/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart b/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart index b89b3c312..4876d0b15 100644 --- a/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart +++ b/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart @@ -132,29 +132,11 @@ class InstabugScreenRenderManager { return; } - //Save the memory cached data to be sent to native side - if (_delayedFrames.isNotEmpty) { - _saveCollectedData(); - _resetCachedFrameData(); - } - - //Sync the captured screen render data of the Custom UI trace when starting new one if (type == UiTraceType.custom) { - // Report only if the collector was active - if (_screenRenderForCustomUiTrace.isActive) { - _reportScreenRenderForCustomUiTrace(_screenRenderForCustomUiTrace); - _screenRenderForCustomUiTrace.clear(); - } _screenRenderForCustomUiTrace.traceId = traceId; } - //Sync the captured screen render data of the Auto UI trace when starting new one if (type == UiTraceType.auto) { - // Report only if the collector was active - if (_screenRenderForAutoUiTrace.isActive) { - _reportScreenRenderForAutoUiTrace(_screenRenderForAutoUiTrace); - _screenRenderForAutoUiTrace.clear(); - } _screenRenderForAutoUiTrace.traceId = traceId; } } catch (error, stackTrace) { @@ -162,43 +144,56 @@ class InstabugScreenRenderManager { } } - /// Stop screen render collector and sync the captured data. @internal - void stopScreenRenderCollector() { + void endScreenRenderCollector([ + UiTraceType type = UiTraceType.auto, + ]) { try { + // Return if frameTimingListener not attached + if (!screenRenderEnabled || !_isTimingsListenerAttached) { + return; + } + + //Save the memory cached data to be sent to native side if (_delayedFrames.isNotEmpty) { _saveCollectedData(); + _resetCachedFrameData(); } - // Sync Screen Render data for custom ui trace if exists - if (_screenRenderForCustomUiTrace.isActive) { + //Sync the captured screen render data of the Custom UI trace if the collector was active + if (type == UiTraceType.custom && + _screenRenderForCustomUiTrace.isActive) { _reportScreenRenderForCustomUiTrace(_screenRenderForCustomUiTrace); + _screenRenderForCustomUiTrace.clear(); } - // Sync Screen Render data for auto ui trace if exists - if (_screenRenderForAutoUiTrace.isActive) { + //Sync the captured screen render data of the Auto UI trace if the collector was active + if (type == UiTraceType.auto && _screenRenderForAutoUiTrace.isActive) { _reportScreenRenderForAutoUiTrace(_screenRenderForAutoUiTrace); + _screenRenderForAutoUiTrace.clear(); } } catch (error, stackTrace) { _logExceptionErrorAndStackTrace(error, stackTrace); } } - /// Sync the capture screen render data of the custom UI trace without stopping the collector. + /// Stop screen render collector and sync the captured data. @internal - void endScreenRenderCollectorForCustomUiTrace() { + void stopScreenRenderCollector() { try { - if (!_screenRenderForCustomUiTrace.isActive) { - return; + if (_delayedFrames.isNotEmpty) { + _saveCollectedData(); } - // Save the captured screen rendering data to be synced - _updateCustomUiData(); - - // Sync the saved screen rendering data - _reportScreenRenderForCustomUiTrace(_screenRenderForCustomUiTrace); + // Sync Screen Render data for custom ui trace if exists + if (_screenRenderForCustomUiTrace.isActive) { + _reportScreenRenderForCustomUiTrace(_screenRenderForCustomUiTrace); + } - _screenRenderForCustomUiTrace.clear(); + // Sync Screen Render data for auto ui trace if exists + if (_screenRenderForAutoUiTrace.isActive) { + _reportScreenRenderForAutoUiTrace(_screenRenderForAutoUiTrace); + } } catch (error, stackTrace) { _logExceptionErrorAndStackTrace(error, stackTrace); } diff --git a/test/apm_test.dart b/test/apm_test.dart index e080f6f88..76aaf28f4 100644 --- a/test/apm_test.dart +++ b/test/apm_test.dart @@ -346,13 +346,10 @@ void main() { () async { when(mHost.isScreenRenderEnabled()).thenAnswer((_) async => true); when(mScreenRenderManager.screenRenderEnabled).thenReturn(true); - const traceName = "traceNameTest"; - await APM.startUITrace(traceName); await APM.endUITrace(); - verify(mHost.startUITrace(traceName)).called(1); verify( - mScreenRenderManager.endScreenRenderCollectorForCustomUiTrace(), + mScreenRenderManager.endScreenRenderCollector(), ).called(1); verifyNever(mHost.endUITrace()); }); @@ -371,7 +368,7 @@ void main() { mHost.endUITrace(), ).called(1); verifyNever( - mScreenRenderManager.endScreenRenderCollectorForCustomUiTrace(), + mScreenRenderManager.endScreenRenderCollector(), ); }); }); diff --git a/test/utils/screen_render/instabug_screen_render_manager_test.dart b/test/utils/screen_render/instabug_screen_render_manager_test.dart index 9f99ac0f4..2eefa667a 100644 --- a/test/utils/screen_render/instabug_screen_render_manager_test.dart +++ b/test/utils/screen_render/instabug_screen_render_manager_test.dart @@ -1,12 +1,18 @@ +import 'dart:ui' show FrameTiming; + +import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:instabug_flutter/instabug_flutter.dart'; +import 'package:instabug_flutter/src/generated/apm.api.g.dart'; import 'package:instabug_flutter/src/models/instabug_frame_data.dart'; import 'package:instabug_flutter/src/models/instabug_screen_render_data.dart'; import 'package:instabug_flutter/src/utils/screen_rendering/instabug_screen_render_manager.dart'; +import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; import 'instabug_screen_render_manager_test.mocks.dart'; +@GenerateMocks([ApmHostApi, WidgetsBinding, FrameTiming]) void main() { TestWidgetsFlutterBinding.ensureInitialized(); @@ -55,25 +61,6 @@ void main() { ); // the one form initForTesting() }); - test( - 'should report data to native when starting new trace from the same type', - () async { - final frameTestData = InstabugScreenRenderData( - traceId: 123, - frameData: [ - InstabugFrameData(10000, 200), - InstabugFrameData(20000, 1000), - ], - frozenFramesTotalDurationMicro: 1000, - slowFramesTotalDurationMicro: 200, - ); - - manager.startScreenRenderCollectorForTraceId(frameTestData.traceId); - manager.setFrameData(frameTestData); - manager.startScreenRenderCollectorForTraceId(2); - verify(mApmHost.endScreenRenderForAutoUiTrace(any)).called(1); - }); - test('should attach timing listener if it is not attached', () async { manager.stopScreenRenderCollector(); // this should detach listener safely @@ -272,7 +259,7 @@ void main() { manager.setFrameData(frameTestData); - manager.endScreenRenderCollectorForCustomUiTrace(); + manager.endScreenRenderCollector(); expect(manager.screenRenderForCustomUiTrace.isActive, false); expect(manager.screenRenderForCustomUiTrace == frameTestData, false); @@ -298,11 +285,11 @@ void main() { manager.setFrameData(frameTestData); - manager.endScreenRenderCollectorForCustomUiTrace(); + manager.endScreenRenderCollector(); }); test('should not remove timing callback listener', () { - manager.endScreenRenderCollectorForCustomUiTrace(); + manager.endScreenRenderCollector(); verifyNever(mWidgetBinding.removeTimingsCallback(any)); }); @@ -320,7 +307,7 @@ void main() { manager.startScreenRenderCollectorForTraceId(0, UiTraceType.custom); manager.setFrameData(frameTestData); - manager.endScreenRenderCollectorForCustomUiTrace(); + manager.endScreenRenderCollector(UiTraceType.custom); verify(mApmHost.endScreenRenderForCustomUiTrace(any)).called(1); }); }); @@ -419,4 +406,50 @@ void main() { ); }); }); + + group('InstabugScreenRenderManager.endScreenRenderCollector', () { + test('should save and reset cached data if delayed frames exist', () { + final frameTestData = InstabugScreenRenderData( + traceId: 123, + frameData: [ + InstabugFrameData(10000, 200), + InstabugFrameData(20000, 1000), + ], + frozenFramesTotalDurationMicro: 1000, + slowFramesTotalDurationMicro: 200, + ); + manager.startScreenRenderCollectorForTraceId(1); + manager.setFrameData(frameTestData); + manager.endScreenRenderCollector(); + verify(mApmHost.endScreenRenderForAutoUiTrace(any)).called(1); + expect(manager.screenRenderForAutoUiTrace.isEmpty, true); + expect(manager.screenRenderForAutoUiTrace.isActive, false); + }); + + test('should report and clear custom trace if type is custom and active', + () { + final frameTestData = InstabugScreenRenderData( + traceId: 123, + frameData: [ + InstabugFrameData(10000, 200), + InstabugFrameData(20000, 1000), + ], + frozenFramesTotalDurationMicro: 1000, + slowFramesTotalDurationMicro: 200, + ); + manager.startScreenRenderCollectorForTraceId(1, UiTraceType.custom); + manager.setFrameData(frameTestData); + manager.endScreenRenderCollector(UiTraceType.custom); + verify(mApmHost.endScreenRenderForCustomUiTrace(any)).called(1); + expect(manager.screenRenderForCustomUiTrace.isEmpty, true); + expect(manager.screenRenderForCustomUiTrace.isActive, false); + }); + + test('should return early if not enabled or timings not attached', () { + manager.screenRenderEnabled = false; + manager.endScreenRenderCollector(); + verifyNever(mApmHost.endScreenRenderForAutoUiTrace(any)); + verifyNever(mApmHost.endScreenRenderForCustomUiTrace(any)); + }); + }); } From 3aa618b4a12f0a12ba37024d91a7ecdb67ce42fe Mon Sep 17 00:00:00 2001 From: AyaMahmoud148 Date: Sun, 3 Aug 2025 11:03:04 +0300 Subject: [PATCH 52/84] fix: ios tests --- example/ios/InstabugTests/BugReportingApiTests.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/example/ios/InstabugTests/BugReportingApiTests.m b/example/ios/InstabugTests/BugReportingApiTests.m index e01df21d2..5b6954d59 100644 --- a/example/ios/InstabugTests/BugReportingApiTests.m +++ b/example/ios/InstabugTests/BugReportingApiTests.m @@ -162,7 +162,7 @@ - (void)testSetCommentMinimumCharacterCountGivenReportTypes { [self.api setCommentMinimumCharacterCountLimit:limit reportTypes:reportTypes error:&error]; - OCMVerify([self.mBugReporting setCommentMinimumCharacterCountForReportTypes:IBGBugReportingReportTypeBug | IBGBugReportingReportTypeQuestion withLimit:limit.intValue]); + OCMVerify([self.mBugReporting setCommentMinimumCharacterCount:limit.intValue forBugReportType:IBGBugReportingReportTypeBug | IBGBugReportingReportTypeQuestion]); } - (void)testSetCommentMinimumCharacterCountGivenNoReportTypes { @@ -172,7 +172,7 @@ - (void)testSetCommentMinimumCharacterCountGivenNoReportTypes { [self.api setCommentMinimumCharacterCountLimit:limit reportTypes:reportTypes error:&error]; - OCMVerify([self.mBugReporting setCommentMinimumCharacterCountForReportTypes:IBGBugReportingReportTypeBug | IBGBugReportingReportTypeFeedback | IBGBugReportingReportTypeQuestion withLimit:limit.intValue]); + OCMVerify([self.mBugReporting setCommentMinimumCharacterCount:limit.intValue forBugReportType:IBGBugReportingReportTypeBug | IBGBugReportingReportTypeFeedback | IBGBugReportingReportTypeQuestion]); } - (void)testAddUserConsentWithKey { NSString *key = @"testKey"; From 6e88be4f8ed81c068bd6c6791c1e61f9d611ed11 Mon Sep 17 00:00:00 2001 From: AyaMahmoud148 Date: Sun, 3 Aug 2025 11:17:23 +0300 Subject: [PATCH 53/84] fix: e2e tests --- example/lib/src/screens/my_home_page.dart | 5 ++--- test/instabug_test.dart | 20 ++++++++++++++++++++ 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/example/lib/src/screens/my_home_page.dart b/example/lib/src/screens/my_home_page.dart index 404d79cdd..bd85fe65b 100644 --- a/example/lib/src/screens/my_home_page.dart +++ b/example/lib/src/screens/my_home_page.dart @@ -115,9 +115,8 @@ class _MyHomePageState extends State { } void changePrimaryColor() { - String text = 'FF' + primaryColorController.text.replaceAll('#', ''); - Color color = Color(int.parse(text, radix: 16)); - Instabug.setPrimaryColor(color); + String text = primaryColorController.text.replaceAll('#', ''); + Instabug.setTheme(ThemeConfig(primaryColor: '#$text')); } void setColorTheme(ColorTheme colorTheme) { diff --git a/test/instabug_test.dart b/test/instabug_test.dart index b5d7bd55c..13f6c2516 100644 --- a/test/instabug_test.dart +++ b/test/instabug_test.dart @@ -433,4 +433,24 @@ void main() { mHost.willRedirectToStore(), ).called(1); }); + + test('[setTheme] should call host method with theme config', () async { + const themeConfig = ThemeConfig(primaryColor: '#FF0000'); + + await Instabug.setTheme(themeConfig); + + verify( + mHost.setTheme(themeConfig.toMap()), + ).called(1); + }); + + test('[setPrimaryColor] should call setTheme with primary color', () async { + const color = Color(0xFFFF0000); + + await Instabug.setPrimaryColor(color); + + verify( + mHost.setTheme(any), + ).called(1); + }); } From 985709a82652f3687e3ace4a6907cee785b32b57 Mon Sep 17 00:00:00 2001 From: AyaMahmoud148 Date: Sun, 3 Aug 2025 11:23:21 +0300 Subject: [PATCH 54/84] fix: formate analyze --- test/instabug_test.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/test/instabug_test.dart b/test/instabug_test.dart index 13f6c2516..abedf0a92 100644 --- a/test/instabug_test.dart +++ b/test/instabug_test.dart @@ -447,6 +447,7 @@ void main() { test('[setPrimaryColor] should call setTheme with primary color', () async { const color = Color(0xFFFF0000); + // ignore: deprecated_member_use await Instabug.setPrimaryColor(color); verify( From d82c1d473a669f3570643c68107ba7743c5aa4c6 Mon Sep 17 00:00:00 2001 From: AyaMahmoud148 Date: Sun, 3 Aug 2025 13:17:48 +0300 Subject: [PATCH 55/84] fix: e2e ios testing --- example/lib/src/screens/my_home_page.dart | 5 +++-- test/instabug_test.dart | 11 ----------- 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/example/lib/src/screens/my_home_page.dart b/example/lib/src/screens/my_home_page.dart index bd85fe65b..5f7d50a88 100644 --- a/example/lib/src/screens/my_home_page.dart +++ b/example/lib/src/screens/my_home_page.dart @@ -114,9 +114,10 @@ class _MyHomePageState extends State { BugReporting.setInvocationEvents([invocationEvent]); } - void changePrimaryColor() { + void changePrimaryColor() async { String text = primaryColorController.text.replaceAll('#', ''); - Instabug.setTheme(ThemeConfig(primaryColor: '#$text')); + await Instabug.setTheme(ThemeConfig(primaryColor: '#$text')); + await Future.delayed(const Duration(milliseconds: 500)); } void setColorTheme(ColorTheme colorTheme) { diff --git a/test/instabug_test.dart b/test/instabug_test.dart index abedf0a92..5b5606b21 100644 --- a/test/instabug_test.dart +++ b/test/instabug_test.dart @@ -443,15 +443,4 @@ void main() { mHost.setTheme(themeConfig.toMap()), ).called(1); }); - - test('[setPrimaryColor] should call setTheme with primary color', () async { - const color = Color(0xFFFF0000); - - // ignore: deprecated_member_use - await Instabug.setPrimaryColor(color); - - verify( - mHost.setTheme(any), - ).called(1); - }); } From e01e27124f0266b961d5f3addc8b597841ccc43d Mon Sep 17 00:00:00 2001 From: Andrew Amin Date: Sun, 3 Aug 2025 14:59:33 +0300 Subject: [PATCH 56/84] chore: format code --- example/lib/main.dart | 1 + lib/src/modules/apm.dart | 3 +-- lib/src/utils/instabug_navigator_observer.dart | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index aa1719503..ada18a241 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -20,6 +20,7 @@ import 'src/widget/section_title.dart'; part 'src/components/animated_box.dart'; part 'src/components/apm_switch.dart'; + part 'src/components/fatal_crashes_content.dart'; part 'src/components/flows_content.dart'; part 'src/components/network_content.dart'; diff --git a/lib/src/modules/apm.dart b/lib/src/modules/apm.dart index 41cf7d676..05b2298c8 100644 --- a/lib/src/modules/apm.dart +++ b/lib/src/modules/apm.dart @@ -213,8 +213,7 @@ class APM { static Future endUITrace() async { // End screen render collector for custom ui trace if enabled. if (InstabugScreenRenderManager.I.screenRenderEnabled) { - return InstabugScreenRenderManager.I - .endScreenRenderCollector(); + return InstabugScreenRenderManager.I.endScreenRenderCollector(); } return _host.endUITrace(); diff --git a/lib/src/utils/instabug_navigator_observer.dart b/lib/src/utils/instabug_navigator_observer.dart index 3dc9c078c..b20b56b89 100644 --- a/lib/src/utils/instabug_navigator_observer.dart +++ b/lib/src/utils/instabug_navigator_observer.dart @@ -69,7 +69,7 @@ class InstabugNavigatorObserver extends NavigatorObserver { FutureOr _startScreenRenderCollector(int? uiTraceId) async { final isScreenRenderEnabled = await FlagsConfig.screenRendering.isEnabled(); - log("isScreenRenderEnabled $isScreenRenderEnabled" , name: "Andrew"); + log("isScreenRenderEnabled $isScreenRenderEnabled", name: "Andrew"); await _checkForScreenRenderInitialization(isScreenRenderEnabled); if (uiTraceId != null && isScreenRenderEnabled) { InstabugScreenRenderManager.I From 61522cf4abd23690bf7619cd194ea2b6ebbb365b Mon Sep 17 00:00:00 2001 From: Andrew Amin Date: Mon, 4 Aug 2025 13:56:01 +0300 Subject: [PATCH 57/84] chore: update iOS pods & implement tolerance in iOS --- example/ios/Podfile | 2 +- example/ios/Podfile.lock | 14 +++++++------- ios/Classes/Modules/ApmApi.m | 6 +++--- ios/Classes/Util/IBGAPM+PrivateAPIs.h | 2 ++ ios/instabug_flutter.podspec | 2 +- 5 files changed, 14 insertions(+), 12 deletions(-) diff --git a/example/ios/Podfile b/example/ios/Podfile index ee4476ba0..bbb7ad1f7 100644 --- a/example/ios/Podfile +++ b/example/ios/Podfile @@ -30,7 +30,7 @@ target 'Runner' do use_frameworks! use_modular_headers! - pod 'Instabug', :podspec => 'https://ios-releases.instabug.com/custom/faeture-screen_rendering-release/15.1.19/Instabug.podspec' + pod 'Instabug', :podspec => 'https://ios-releases.instabug.com/custom/faeture-screen_rendering-release/15.1.24/Instabug.podspec' flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) end diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index 703787e60..53dc15ace 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -1,14 +1,14 @@ PODS: - Flutter (1.0.0) - - Instabug (15.1.19) + - Instabug (15.1.24) - instabug_flutter (14.3.0): - Flutter - - Instabug (= 15.1.19) + - Instabug (= 15.1.24) - OCMock (3.6) DEPENDENCIES: - Flutter (from `Flutter`) - - Instabug (from `https://ios-releases.instabug.com/custom/faeture-screen_rendering-release/15.1.19/Instabug.podspec`) + - Instabug (from `https://ios-releases.instabug.com/custom/faeture-screen_rendering-release/15.1.24/Instabug.podspec`) - instabug_flutter (from `.symlinks/plugins/instabug_flutter/ios`) - OCMock (= 3.6) @@ -20,16 +20,16 @@ EXTERNAL SOURCES: Flutter: :path: Flutter Instabug: - :podspec: https://ios-releases.instabug.com/custom/faeture-screen_rendering-release/15.1.19/Instabug.podspec + :podspec: https://ios-releases.instabug.com/custom/faeture-screen_rendering-release/15.1.24/Instabug.podspec instabug_flutter: :path: ".symlinks/plugins/instabug_flutter/ios" SPEC CHECKSUMS: Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 - Instabug: 74377abfdaa9f9f3dff7793353e150e91d2186f7 - instabug_flutter: aa9b2365fe41d8a49f9258ab350864bfb5bdce9e + Instabug: 81ff406348f7a9784ad2c681c94279a0ad3fcab7 + instabug_flutter: 7aeb6ad19cf4c388aef8955c3aad12ee5373adab OCMock: 5ea90566be239f179ba766fd9fbae5885040b992 -PODFILE CHECKSUM: d61a5c8efcff86500b76349ccad5201d7756fdea +PODFILE CHECKSUM: fb14c1a442ef94a558e4e301f3ea6ba54be132dd COCOAPODS: 1.15.2 diff --git a/ios/Classes/Modules/ApmApi.m b/ios/Classes/Modules/ApmApi.m index 9f6daef14..913563ad6 100644 --- a/ios/Classes/Modules/ApmApi.m +++ b/ios/Classes/Modules/ApmApi.m @@ -245,14 +245,14 @@ - (void)endScreenRenderForCustomUiTraceData:(nonnull NSDictionary [IBGAPM endCustomUITraceCPWithFrames:frameInfos]; } -- (void)getDeviceRefreshRateAndToleranceWithCompletion:(nonnull void (^)(NSArray * _Nullable, FlutterError * _Nullable))completion { +- (void)getDeviceRefreshRateAndToleranceWithCompletion:(nonnull void (^)(NSArray * _Nullable, FlutterError * _Nullable))completion { + double tolerance = IBGAPM.screenRenderingThreshold; if (@available(iOS 10.3, *)) { double refreshRate = [UIScreen mainScreen].maximumFramesPerSecond; - double tolerance = 10; completion(@[@(refreshRate), @(tolerance)] ,nil); } else { // Fallback for very old iOS versions. - completion(@[@(60.0), @(10.0)] , nil); + completion(@[@(60.0), @(tolerance)] , nil); } } diff --git a/ios/Classes/Util/IBGAPM+PrivateAPIs.h b/ios/Classes/Util/IBGAPM+PrivateAPIs.h index c562e629e..bc8a1e90a 100644 --- a/ios/Classes/Util/IBGAPM+PrivateAPIs.h +++ b/ios/Classes/Util/IBGAPM+PrivateAPIs.h @@ -31,4 +31,6 @@ + (void)endCustomUITraceCPWithFrames:(nullable NSArray *)frames; ++ (double)screenRenderingThreshold; + @end diff --git a/ios/instabug_flutter.podspec b/ios/instabug_flutter.podspec index 30a9289c2..20348234e 100644 --- a/ios/instabug_flutter.podspec +++ b/ios/instabug_flutter.podspec @@ -17,6 +17,6 @@ Pod::Spec.new do |s| s.pod_target_xcconfig = { 'OTHER_LDFLAGS' => '-framework "Flutter" -framework "InstabugSDK"'} s.dependency 'Flutter' - s.dependency 'Instabug', '15.1.19' + s.dependency 'Instabug', '15.1.24' end From 2018d9f6144e61c59f279761725cfd8fb528e127 Mon Sep 17 00:00:00 2001 From: Andrew Amin Date: Mon, 4 Aug 2025 23:28:46 +0300 Subject: [PATCH 58/84] chore: run mockito on 2.10.5 --- .../instabug_screen_render_manager_test.dart | 8 +- ...reen_render_manager_test_manual_mocks.dart | 759 ++++++++++++++++++ 2 files changed, 760 insertions(+), 7 deletions(-) create mode 100644 test/utils/screen_render/instabug_screen_render_manager_test_manual_mocks.dart diff --git a/test/utils/screen_render/instabug_screen_render_manager_test.dart b/test/utils/screen_render/instabug_screen_render_manager_test.dart index 2eefa667a..adbe7d74d 100644 --- a/test/utils/screen_render/instabug_screen_render_manager_test.dart +++ b/test/utils/screen_render/instabug_screen_render_manager_test.dart @@ -1,18 +1,12 @@ -import 'dart:ui' show FrameTiming; - -import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:instabug_flutter/instabug_flutter.dart'; -import 'package:instabug_flutter/src/generated/apm.api.g.dart'; import 'package:instabug_flutter/src/models/instabug_frame_data.dart'; import 'package:instabug_flutter/src/models/instabug_screen_render_data.dart'; import 'package:instabug_flutter/src/utils/screen_rendering/instabug_screen_render_manager.dart'; -import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; -import 'instabug_screen_render_manager_test.mocks.dart'; +import 'instabug_screen_render_manager_test_manual_mocks.dart'; -@GenerateMocks([ApmHostApi, WidgetsBinding, FrameTiming]) void main() { TestWidgetsFlutterBinding.ensureInitialized(); diff --git a/test/utils/screen_render/instabug_screen_render_manager_test_manual_mocks.dart b/test/utils/screen_render/instabug_screen_render_manager_test_manual_mocks.dart new file mode 100644 index 000000000..64d147846 --- /dev/null +++ b/test/utils/screen_render/instabug_screen_render_manager_test_manual_mocks.dart @@ -0,0 +1,759 @@ +// Mocks generated by Mockito 5.2.0 from annotations +// in instabug_flutter/example/ios/.symlinks/plugins/instabug_flutter/test/utils/screen_render/instabug_screen_render_manager_test.dart. +// Do not manually edit this file. + +import 'dart:async' as _i9; +import 'dart:developer' as _i13; +import 'dart:ui' as _i4; + +import 'package:flutter/foundation.dart' as _i3; +import 'package:flutter/gestures.dart' as _i6; +import 'package:flutter/rendering.dart' as _i7; +import 'package:flutter/scheduler.dart' as _i11; +import 'package:flutter/services.dart' as _i5; +import 'package:flutter/src/widgets/binding.dart' as _i10; +import 'package:flutter/src/widgets/focus_manager.dart' as _i2; +import 'package:flutter/src/widgets/framework.dart' as _i12; +import 'package:instabug_flutter/src/generated/apm.api.g.dart' as _i8; +import 'package:mockito/mockito.dart' as _i1; + +// ignore_for_file: type=lint +// ignore_for_file: avoid_redundant_argument_values +// ignore_for_file: avoid_setters_without_getters +// ignore_for_file: comment_references +// ignore_for_file: implementation_imports +// ignore_for_file: invalid_use_of_visible_for_testing_member +// ignore_for_file: prefer_const_constructors +// ignore_for_file: unnecessary_parenthesis +// ignore_for_file: camel_case_types + +class _FakeFocusManager_0 extends _i1.Fake implements _i2.FocusManager { + @override + String toString({_i3.DiagnosticLevel? minLevel = _i3.DiagnosticLevel.info}) => + super.toString(); +} + +class _FakeSingletonFlutterWindow_1 extends _i1.Fake + implements _i4.SingletonFlutterWindow {} + +class _FakePlatformDispatcher_2 extends _i1.Fake + implements _i4.PlatformDispatcher {} + +class _FakeHardwareKeyboard_3 extends _i1.Fake implements + _i5.HardwareKeyboard {} + +class _FakeKeyEventManager_4 extends _i1.Fake implements _i5.KeyEventManager {} + +class _FakeBinaryMessenger_5 extends _i1.Fake implements _i5.BinaryMessenger {} + +class _FakeChannelBuffers_6 extends _i1.Fake implements _i4.ChannelBuffers {} + +class _FakeRestorationManager_7 extends _i1.Fake + implements _i5.RestorationManager {} + +class _FakeDuration_8 extends _i1.Fake implements Duration {} + +class _FakePointerRouter_9 extends _i1.Fake implements _i6.PointerRouter {} + +class _FakeGestureArenaManager_10 extends _i1.Fake + implements _i6.GestureArenaManager {} + +class _FakePointerSignalResolver_11 extends _i1.Fake + implements _i6.PointerSignalResolver {} + +class _FakeMouseTracker_12 extends _i1.Fake implements _i7.MouseTracker {} + +class _FakePipelineOwner_13 extends _i1.Fake implements _i7.PipelineOwner {} + +class _FakeRenderView_14 extends _i1.Fake implements _i7.RenderView { + @override + String toString({_i3.DiagnosticLevel? minLevel = _i3.DiagnosticLevel.info}) => + super.toString(); +} + +class _FakeAccessibilityFeatures_15 extends _i1.Fake + implements _i4.AccessibilityFeatures {} + +class _FakeViewConfiguration_16 extends _i1.Fake + implements _i7.ViewConfiguration {} + +class _FakeSemanticsUpdateBuilder_17 extends _i1.Fake + implements _i4.SemanticsUpdateBuilder {} + +/// A class which mocks [ApmHostApi]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockApmHostApi extends _i1.Mock implements _i8.ApmHostApi { + MockApmHostApi() { + _i1.throwOnMissingStub(this); + } + + @override + _i9.Future setEnabled(bool? arg_isEnabled) => + (super.noSuchMethod(Invocation.method(#setEnabled, [arg_isEnabled]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future isEnabled() => + (super.noSuchMethod(Invocation.method(#isEnabled, []), + returnValue: Future.value(false)) as _i9.Future); + @override + _i9.Future setScreenLoadingEnabled(bool? arg_isEnabled) => + (super.noSuchMethod( + Invocation.method(#setScreenLoadingEnabled, [arg_isEnabled]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future isScreenLoadingEnabled() => + (super.noSuchMethod(Invocation.method(#isScreenLoadingEnabled, []), + returnValue: Future.value(false)) as _i9.Future); + @override + _i9.Future setColdAppLaunchEnabled(bool? arg_isEnabled) => + (super.noSuchMethod( + Invocation.method(#setColdAppLaunchEnabled, [arg_isEnabled]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future setAutoUITraceEnabled(bool? arg_isEnabled) => (super + .noSuchMethod(Invocation.method(#setAutoUITraceEnabled, [arg_isEnabled]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future startExecutionTrace(String? arg_id, String? arg_name) => + (super.noSuchMethod( + Invocation.method(#startExecutionTrace, [arg_id, arg_name]), + returnValue: Future.value()) as _i9.Future); + @override + _i9.Future startFlow(String? arg_name) => + (super.noSuchMethod(Invocation.method(#startFlow, [arg_name]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future setFlowAttribute( + String? arg_name, String? arg_key, String? arg_value) => + (super.noSuchMethod( + Invocation.method(#setFlowAttribute, [arg_name, arg_key, arg_value]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future endFlow(String? arg_name) => + (super.noSuchMethod(Invocation.method(#endFlow, [arg_name]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future setExecutionTraceAttribute( + String? arg_id, String? arg_key, String? arg_value) => + (super.noSuchMethod( + Invocation.method( + #setExecutionTraceAttribute, [arg_id, arg_key, arg_value]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future endExecutionTrace(String? arg_id) => + (super.noSuchMethod(Invocation.method(#endExecutionTrace, [arg_id]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future startUITrace(String? arg_name) => + (super.noSuchMethod(Invocation.method(#startUITrace, [arg_name]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future endUITrace() => + (super.noSuchMethod(Invocation.method(#endUITrace, []), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future endAppLaunch() => + (super.noSuchMethod(Invocation.method(#endAppLaunch, []), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future networkLogAndroid(Map? arg_data) => + (super.noSuchMethod(Invocation.method(#networkLogAndroid, [arg_data]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future startCpUiTrace( + String? arg_screenName, int? arg_microTimeStamp, int? arg_traceId) => + (super.noSuchMethod( + Invocation.method(#startCpUiTrace, + [arg_screenName, arg_microTimeStamp, arg_traceId]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future reportScreenLoadingCP(int? arg_startTimeStampMicro, + int? arg_durationMicro, int? arg_uiTraceId) => + (super.noSuchMethod( + Invocation.method(#reportScreenLoadingCP, + [arg_startTimeStampMicro, arg_durationMicro, arg_uiTraceId]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future endScreenLoadingCP( + int? arg_timeStampMicro, int? arg_uiTraceId) => + (super.noSuchMethod( + Invocation.method( + #endScreenLoadingCP, [arg_timeStampMicro, arg_uiTraceId]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future isEndScreenLoadingEnabled() => + (super.noSuchMethod(Invocation.method(#isEndScreenLoadingEnabled, []), + returnValue: Future.value(false)) as _i9.Future); + @override + _i9.Future isScreenRenderEnabled() => + (super.noSuchMethod(Invocation.method(#isScreenRenderEnabled, []), + returnValue: Future.value(false)) as _i9.Future); + @override + _i9.Future deviceRefreshRate() => + (super.noSuchMethod(Invocation.method(#deviceRefreshRate, []), + returnValue: Future.value(0.0)) as _i9.Future); + @override + _i9.Future setScreenRenderEnabled(bool? arg_isEnabled) => (super + .noSuchMethod(Invocation.method(#setScreenRenderEnabled, [arg_isEnabled]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future endScreenRenderForAutoUiTrace( + Map? arg_data) => + (super.noSuchMethod( + Invocation.method(#endScreenRenderForAutoUiTrace, [arg_data]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future endScreenRenderForCustomUiTrace( + Map? arg_data) => + (super.noSuchMethod( + Invocation.method(#endScreenRenderForCustomUiTrace, [arg_data]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); +} + +/// A class which mocks [WidgetsBinding]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockWidgetsBinding extends _i1.Mock implements _i10.WidgetsBinding { + MockWidgetsBinding() { + _i1.throwOnMissingStub(this); + } + + @override + bool get debugBuildingDirtyElements => + (super.noSuchMethod(Invocation.getter(#debugBuildingDirtyElements), + returnValue: false) as bool); + @override + set debugBuildingDirtyElements(bool? _debugBuildingDirtyElements) => + super.noSuchMethod( + Invocation.setter( + #debugBuildingDirtyElements, _debugBuildingDirtyElements), + returnValueForMissingStub: null); + @override + _i2.FocusManager get focusManager => + (super.noSuchMethod(Invocation.getter(#focusManager), + returnValue: _FakeFocusManager_0()) as _i2.FocusManager); + @override + bool get firstFrameRasterized => + (super.noSuchMethod(Invocation.getter(#firstFrameRasterized), + returnValue: false) as bool); + @override + _i9.Future get waitUntilFirstFrameRasterized => + (super.noSuchMethod(Invocation.getter(#waitUntilFirstFrameRasterized), + returnValue: Future.value()) as _i9.Future); + @override + bool get debugDidSendFirstFrameEvent => + (super.noSuchMethod(Invocation.getter(#debugDidSendFirstFrameEvent), + returnValue: false) as bool); + @override + bool get framesEnabled => + (super.noSuchMethod(Invocation.getter(#framesEnabled), returnValue: false) + as bool); + @override + bool get isRootWidgetAttached => + (super.noSuchMethod(Invocation.getter(#isRootWidgetAttached), + returnValue: false) as bool); + @override + _i4.SingletonFlutterWindow get window => + (super.noSuchMethod(Invocation.getter(#window), + returnValue: _FakeSingletonFlutterWindow_1()) + as _i4.SingletonFlutterWindow); + @override + _i4.PlatformDispatcher get platformDispatcher => + (super.noSuchMethod(Invocation.getter(#platformDispatcher), + returnValue: _FakePlatformDispatcher_2()) as _i4.PlatformDispatcher); + @override + bool get locked => + (super.noSuchMethod(Invocation.getter(#locked), returnValue: false) + as bool); + @override + _i5.HardwareKeyboard get keyboard => + (super.noSuchMethod(Invocation.getter(#keyboard), + returnValue: _FakeHardwareKeyboard_3()) as _i5.HardwareKeyboard); + @override + _i5.KeyEventManager get keyEventManager => + (super.noSuchMethod(Invocation.getter(#keyEventManager), + returnValue: _FakeKeyEventManager_4()) as _i5.KeyEventManager); + @override + _i5.BinaryMessenger get defaultBinaryMessenger => + (super.noSuchMethod(Invocation.getter(#defaultBinaryMessenger), + returnValue: _FakeBinaryMessenger_5()) as _i5.BinaryMessenger); + @override + _i4.ChannelBuffers get channelBuffers => + (super.noSuchMethod(Invocation.getter(#channelBuffers), + returnValue: _FakeChannelBuffers_6()) as _i4.ChannelBuffers); + @override + _i5.RestorationManager get restorationManager => + (super.noSuchMethod(Invocation.getter(#restorationManager), + returnValue: _FakeRestorationManager_7()) as _i5.RestorationManager); + @override + _i11.SchedulingStrategy get schedulingStrategy => + (super.noSuchMethod(Invocation.getter(#schedulingStrategy), + returnValue: ({int? priority, _i11.SchedulerBinding? scheduler}) => + false) as _i11.SchedulingStrategy); + @override + set schedulingStrategy(_i11.SchedulingStrategy? _schedulingStrategy) => super + .noSuchMethod(Invocation.setter(#schedulingStrategy, _schedulingStrategy), + returnValueForMissingStub: null); + @override + int get transientCallbackCount => + (super.noSuchMethod(Invocation.getter(#transientCallbackCount), + returnValue: 0) as int); + @override + _i9.Future get endOfFrame => + (super.noSuchMethod(Invocation.getter(#endOfFrame), + returnValue: Future.value()) as _i9.Future); + @override + bool get hasScheduledFrame => + (super.noSuchMethod(Invocation.getter(#hasScheduledFrame), + returnValue: false) as bool); + @override + _i11.SchedulerPhase get schedulerPhase => + (super.noSuchMethod(Invocation.getter(#schedulerPhase), + returnValue: _i11.SchedulerPhase.idle) as _i11.SchedulerPhase); + @override + Duration get currentFrameTimeStamp => + (super.noSuchMethod(Invocation.getter(#currentFrameTimeStamp), + returnValue: _FakeDuration_8()) as Duration); + @override + Duration get currentSystemFrameTimeStamp => + (super.noSuchMethod(Invocation.getter(#currentSystemFrameTimeStamp), + returnValue: _FakeDuration_8()) as Duration); + @override + _i6.PointerRouter get pointerRouter => + (super.noSuchMethod(Invocation.getter(#pointerRouter), + returnValue: _FakePointerRouter_9()) as _i6.PointerRouter); + @override + _i6.GestureArenaManager get gestureArena => (super.noSuchMethod( + Invocation.getter(#gestureArena), + returnValue: _FakeGestureArenaManager_10()) as _i6.GestureArenaManager); + @override + _i6.PointerSignalResolver get pointerSignalResolver => + (super.noSuchMethod(Invocation.getter(#pointerSignalResolver), + returnValue: _FakePointerSignalResolver_11()) + as _i6.PointerSignalResolver); + @override + bool get resamplingEnabled => + (super.noSuchMethod(Invocation.getter(#resamplingEnabled), + returnValue: false) as bool); + @override + set resamplingEnabled(bool? _resamplingEnabled) => super.noSuchMethod( + Invocation.setter(#resamplingEnabled, _resamplingEnabled), + returnValueForMissingStub: null); + @override + Duration get samplingOffset => + (super.noSuchMethod(Invocation.getter(#samplingOffset), + returnValue: _FakeDuration_8()) as Duration); + @override + set samplingOffset(Duration? _samplingOffset) => + super.noSuchMethod(Invocation.setter(#samplingOffset, _samplingOffset), + returnValueForMissingStub: null); + @override + _i7.MouseTracker get mouseTracker => + (super.noSuchMethod(Invocation.getter(#mouseTracker), + returnValue: _FakeMouseTracker_12()) as _i7.MouseTracker); + @override + _i7.PipelineOwner get pipelineOwner => + (super.noSuchMethod(Invocation.getter(#pipelineOwner), + returnValue: _FakePipelineOwner_13()) as _i7.PipelineOwner); + @override + _i7.RenderView get renderView => + (super.noSuchMethod(Invocation.getter(#renderView), + returnValue: _FakeRenderView_14()) as _i7.RenderView); + @override + set renderView(_i7.RenderView? value) => + super.noSuchMethod(Invocation.setter(#renderView, value), + returnValueForMissingStub: null); + @override + bool get sendFramesToEngine => + (super.noSuchMethod(Invocation.getter(#sendFramesToEngine), + returnValue: false) as bool); + @override + _i4.AccessibilityFeatures get accessibilityFeatures => + (super.noSuchMethod(Invocation.getter(#accessibilityFeatures), + returnValue: _FakeAccessibilityFeatures_15()) + as _i4.AccessibilityFeatures); + @override + bool get disableAnimations => + (super.noSuchMethod(Invocation.getter(#disableAnimations), + returnValue: false) as bool); + @override + void initInstances() => + super.noSuchMethod(Invocation.method(#initInstances, []), + returnValueForMissingStub: null); + @override + void initServiceExtensions() => + super.noSuchMethod(Invocation.method(#initServiceExtensions, []), + returnValueForMissingStub: null); + @override + void addObserver(_i10.WidgetsBindingObserver? observer) => + super.noSuchMethod(Invocation.method(#addObserver, [observer]), + returnValueForMissingStub: null); + @override + bool removeObserver(_i10.WidgetsBindingObserver? observer) => + (super.noSuchMethod(Invocation.method(#removeObserver, [observer]), + returnValue: false) as bool); + @override + void handleMetricsChanged() => + super.noSuchMethod(Invocation.method(#handleMetricsChanged, []), + returnValueForMissingStub: null); + @override + void handleTextScaleFactorChanged() => + super.noSuchMethod(Invocation.method(#handleTextScaleFactorChanged, []), + returnValueForMissingStub: null); + @override + void handlePlatformBrightnessChanged() => super.noSuchMethod( + Invocation.method(#handlePlatformBrightnessChanged, []), + returnValueForMissingStub: null); + @override + void handleAccessibilityFeaturesChanged() => super.noSuchMethod( + Invocation.method(#handleAccessibilityFeaturesChanged, []), + returnValueForMissingStub: null); + @override + void handleLocaleChanged() => + super.noSuchMethod(Invocation.method(#handleLocaleChanged, []), + returnValueForMissingStub: null); + @override + void dispatchLocalesChanged(List<_i4.Locale>? locales) => + super.noSuchMethod(Invocation.method(#dispatchLocalesChanged, [locales]), + returnValueForMissingStub: null); + @override + void dispatchAccessibilityFeaturesChanged() => super.noSuchMethod( + Invocation.method(#dispatchAccessibilityFeaturesChanged, []), + returnValueForMissingStub: null); + @override + _i9.Future handlePopRoute() => + (super.noSuchMethod(Invocation.method(#handlePopRoute, []), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future handlePushRoute(String? route) => + (super.noSuchMethod(Invocation.method(#handlePushRoute, [route]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + void handleAppLifecycleStateChanged(_i4.AppLifecycleState? state) => super + .noSuchMethod(Invocation.method(#handleAppLifecycleStateChanged, [state]), + returnValueForMissingStub: null); + @override + void handleMemoryPressure() => + super.noSuchMethod(Invocation.method(#handleMemoryPressure, []), + returnValueForMissingStub: null); + @override + void drawFrame() => super.noSuchMethod(Invocation.method(#drawFrame, []), + returnValueForMissingStub: null); + @override + void scheduleAttachRootWidget(_i12.Widget? rootWidget) => super.noSuchMethod( + Invocation.method(#scheduleAttachRootWidget, [rootWidget]), + returnValueForMissingStub: null); + @override + void attachRootWidget(_i12.Widget? rootWidget) => + super.noSuchMethod(Invocation.method(#attachRootWidget, [rootWidget]), + returnValueForMissingStub: null); + @override + _i9.Future performReassemble() => + (super.noSuchMethod(Invocation.method(#performReassemble, []), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i4.Locale? computePlatformResolvedLocale( + List<_i4.Locale>? supportedLocales) => + (super.noSuchMethod(Invocation.method( + #computePlatformResolvedLocale, [supportedLocales])) as _i4.Locale?); + @override + _i9.Future lockEvents(_i9.Future Function()? callback) => + (super.noSuchMethod(Invocation.method(#lockEvents, [callback]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + void unlocked() => super.noSuchMethod(Invocation.method(#unlocked, []), + returnValueForMissingStub: null); + @override + _i9.Future reassembleApplication() => + (super.noSuchMethod(Invocation.method(#reassembleApplication, []), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + void registerSignalServiceExtension( + {String? name, _i3.AsyncCallback? callback}) => + super.noSuchMethod( + Invocation.method(#registerSignalServiceExtension, [], + {#name: name, #callback: callback}), + returnValueForMissingStub: null); + @override + void registerBoolServiceExtension( + {String? name, + _i3.AsyncValueGetter? getter, + _i3.AsyncValueSetter? setter}) => + super.noSuchMethod( + Invocation.method(#registerBoolServiceExtension, [], + {#name: name, #getter: getter, #setter: setter}), + returnValueForMissingStub: null); + @override + void registerNumericServiceExtension( + {String? name, + _i3.AsyncValueGetter? getter, + _i3.AsyncValueSetter? setter}) => + super.noSuchMethod( + Invocation.method(#registerNumericServiceExtension, [], + {#name: name, #getter: getter, #setter: setter}), + returnValueForMissingStub: null); + @override + void postEvent(String? eventKind, Map? eventData) => + super.noSuchMethod(Invocation.method(#postEvent, [eventKind, eventData]), + returnValueForMissingStub: null); + @override + void registerStringServiceExtension( + {String? name, + _i3.AsyncValueGetter? getter, + _i3.AsyncValueSetter? setter}) => + super.noSuchMethod( + Invocation.method(#registerStringServiceExtension, [], + {#name: name, #getter: getter, #setter: setter}), + returnValueForMissingStub: null); + @override + void registerServiceExtension( + {String? name, _i3.ServiceExtensionCallback? callback}) => + super.noSuchMethod( + Invocation.method(#registerServiceExtension, [], + {#name: name, #callback: callback}), + returnValueForMissingStub: null); + @override + _i5.BinaryMessenger createBinaryMessenger() => + (super.noSuchMethod(Invocation.method(#createBinaryMessenger, []), + returnValue: _FakeBinaryMessenger_5()) as _i5.BinaryMessenger); + @override + _i9.Future handleSystemMessage(Object? systemMessage) => (super + .noSuchMethod(Invocation.method(#handleSystemMessage, [systemMessage]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + void initLicenses() => + super.noSuchMethod(Invocation.method(#initLicenses, []), + returnValueForMissingStub: null); + @override + void evict(String? asset) => + super.noSuchMethod(Invocation.method(#evict, [asset]), + returnValueForMissingStub: null); + @override + void readInitialLifecycleStateFromNativeWindow() => super.noSuchMethod( + Invocation.method(#readInitialLifecycleStateFromNativeWindow, []), + returnValueForMissingStub: null); + @override + _i5.RestorationManager createRestorationManager() => + (super.noSuchMethod(Invocation.method(#createRestorationManager, []), + returnValue: _FakeRestorationManager_7()) as _i5.RestorationManager); + @override + void setSystemUiChangeCallback(_i5.SystemUiChangeCallback? callback) => super + .noSuchMethod(Invocation.method(#setSystemUiChangeCallback, [callback]), + returnValueForMissingStub: null); + @override + void addTimingsCallback(_i4.TimingsCallback? callback) => + super.noSuchMethod(Invocation.method(#addTimingsCallback, [callback]), + returnValueForMissingStub: null); + @override + void removeTimingsCallback(_i4.TimingsCallback? callback) => + super.noSuchMethod(Invocation.method(#removeTimingsCallback, [callback]), + returnValueForMissingStub: null); + @override + _i9.Future scheduleTask( + _i11.TaskCallback? task, _i11.Priority? priority, + {String? debugLabel, _i13.Flow? flow}) => + (super.noSuchMethod( + Invocation.method(#scheduleTask, [task, priority], + {#debugLabel: debugLabel, #flow: flow}), + returnValue: Future.value(null)) as _i9.Future); + @override + bool handleEventLoopCallback() => + (super.noSuchMethod(Invocation.method(#handleEventLoopCallback, []), + returnValue: false) as bool); + @override + int scheduleFrameCallback(_i11.FrameCallback? callback, + {bool? rescheduling = false}) => + (super.noSuchMethod( + Invocation.method(#scheduleFrameCallback, [callback], + {#rescheduling: rescheduling}), + returnValue: 0) as int); + @override + void cancelFrameCallbackWithId(int? id) => + super.noSuchMethod(Invocation.method(#cancelFrameCallbackWithId, [id]), + returnValueForMissingStub: null); + @override + bool debugAssertNoTransientCallbacks(String? reason) => (super.noSuchMethod( + Invocation.method(#debugAssertNoTransientCallbacks, [reason]), + returnValue: false) as bool); + @override + void addPersistentFrameCallback(_i11.FrameCallback? callback) => super + .noSuchMethod(Invocation.method(#addPersistentFrameCallback, [callback]), + returnValueForMissingStub: null); + @override + void addPostFrameCallback(_i11.FrameCallback? callback) => + super.noSuchMethod(Invocation.method(#addPostFrameCallback, [callback]), + returnValueForMissingStub: null); + @override + void ensureFrameCallbacksRegistered() => + super.noSuchMethod(Invocation.method(#ensureFrameCallbacksRegistered, []), + returnValueForMissingStub: null); + @override + void ensureVisualUpdate() => + super.noSuchMethod(Invocation.method(#ensureVisualUpdate, []), + returnValueForMissingStub: null); + @override + void scheduleFrame() => + super.noSuchMethod(Invocation.method(#scheduleFrame, []), + returnValueForMissingStub: null); + @override + void scheduleForcedFrame() => + super.noSuchMethod(Invocation.method(#scheduleForcedFrame, []), + returnValueForMissingStub: null); + @override + void scheduleWarmUpFrame() => + super.noSuchMethod(Invocation.method(#scheduleWarmUpFrame, []), + returnValueForMissingStub: null); + @override + void resetEpoch() => super.noSuchMethod(Invocation.method(#resetEpoch, []), + returnValueForMissingStub: null); + @override + void handleBeginFrame(Duration? rawTimeStamp) => + super.noSuchMethod(Invocation.method(#handleBeginFrame, [rawTimeStamp]), + returnValueForMissingStub: null); + @override + void handleDrawFrame() => + super.noSuchMethod(Invocation.method(#handleDrawFrame, []), + returnValueForMissingStub: null); + @override + void cancelPointer(int? pointer) => + super.noSuchMethod(Invocation.method(#cancelPointer, [pointer]), + returnValueForMissingStub: null); + @override + void handlePointerEvent(_i6.PointerEvent? event) => + super.noSuchMethod(Invocation.method(#handlePointerEvent, [event]), + returnValueForMissingStub: null); + @override + void hitTest(_i6.HitTestResult? result, _i4.Offset? position) => + super.noSuchMethod(Invocation.method(#hitTest, [result, position]), + returnValueForMissingStub: null); + @override + void dispatchEvent( + _i6.PointerEvent? event, _i6.HitTestResult? hitTestResult) => + super.noSuchMethod( + Invocation.method(#dispatchEvent, [event, hitTestResult]), + returnValueForMissingStub: null); + @override + void handleEvent(_i6.PointerEvent? event, _i6.HitTestEntry? entry) => + super.noSuchMethod(Invocation.method(#handleEvent, [event, entry]), + returnValueForMissingStub: null); + @override + void resetGestureBinding() => + super.noSuchMethod(Invocation.method(#resetGestureBinding, []), + returnValueForMissingStub: null); + @override + void initRenderView() => + super.noSuchMethod(Invocation.method(#initRenderView, []), + returnValueForMissingStub: null); + @override + _i7.ViewConfiguration createViewConfiguration() => + (super.noSuchMethod(Invocation.method(#createViewConfiguration, []), + returnValue: _FakeViewConfiguration_16()) as _i7.ViewConfiguration); + @override + void initMouseTracker([_i7.MouseTracker? tracker]) => + super.noSuchMethod(Invocation.method(#initMouseTracker, [tracker]), + returnValueForMissingStub: null); + @override + void setSemanticsEnabled(bool? enabled) => + super.noSuchMethod(Invocation.method(#setSemanticsEnabled, [enabled]), + returnValueForMissingStub: null); + @override + void deferFirstFrame() => + super.noSuchMethod(Invocation.method(#deferFirstFrame, []), + returnValueForMissingStub: null); + @override + void allowFirstFrame() => + super.noSuchMethod(Invocation.method(#allowFirstFrame, []), + returnValueForMissingStub: null); + @override + void resetFirstFrameSent() => + super.noSuchMethod(Invocation.method(#resetFirstFrameSent, []), + returnValueForMissingStub: null); + @override + _i4.SemanticsUpdateBuilder createSemanticsUpdateBuilder() => + (super.noSuchMethod(Invocation.method(#createSemanticsUpdateBuilder, []), + returnValue: _FakeSemanticsUpdateBuilder_17()) + as _i4.SemanticsUpdateBuilder); +} + +/// A class which mocks [FrameTiming]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockFrameTiming extends _i1.Mock implements _i4.FrameTiming { + MockFrameTiming() { + _i1.throwOnMissingStub(this); + } + + @override + Duration get buildDuration => + (super.noSuchMethod(Invocation.getter(#buildDuration), + returnValue: _FakeDuration_8()) as Duration); + @override + Duration get rasterDuration => + (super.noSuchMethod(Invocation.getter(#rasterDuration), + returnValue: _FakeDuration_8()) as Duration); + @override + Duration get vsyncOverhead => + (super.noSuchMethod(Invocation.getter(#vsyncOverhead), + returnValue: _FakeDuration_8()) as Duration); + @override + Duration get totalSpan => (super.noSuchMethod(Invocation.getter(#totalSpan), + returnValue: _FakeDuration_8()) as Duration); + @override + int get layerCacheCount => + (super.noSuchMethod(Invocation.getter(#layerCacheCount), returnValue: 0) + as int); + @override + int get layerCacheBytes => + (super.noSuchMethod(Invocation.getter(#layerCacheBytes), returnValue: 0) + as int); + @override + double get layerCacheMegabytes => + (super.noSuchMethod(Invocation.getter(#layerCacheMegabytes), + returnValue: 0.0) as double); + @override + int get pictureCacheCount => + (super.noSuchMethod(Invocation.getter(#pictureCacheCount), returnValue: 0) + as int); + @override + int get pictureCacheBytes => + (super.noSuchMethod(Invocation.getter(#pictureCacheBytes), returnValue: 0) + as int); + @override + double get pictureCacheMegabytes => + (super.noSuchMethod(Invocation.getter(#pictureCacheMegabytes), + returnValue: 0.0) as double); + @override + int get frameNumber => + (super.noSuchMethod(Invocation.getter(#frameNumber), returnValue: 0) + as int); + @override + int timestampInMicroseconds(_i4.FramePhase? phase) => + (super.noSuchMethod(Invocation.method(#timestampInMicroseconds, [phase]), + returnValue: 0) as int); +} From 7324592f2573ca476dbb2c5879f3bfde33a7e994 Mon Sep 17 00:00:00 2001 From: Andrew Amin Date: Tue, 5 Aug 2025 20:21:58 +0300 Subject: [PATCH 59/84] chore: resolve conflict with remove deprecated apis branch, update CHANGELOG.md, fix some sync logic --- CHANGELOG.md | 4 +- .../java/com/instabug/flutter/ApmApiTest.java | 56 +- example/ios/InstabugTests/ApmApiTests.m | 51 +- example/lib/main.dart | 3 - example/pubspec.lock | 4 +- lib/src/modules/apm.dart | 7 +- .../instabug_screen_render_manager.dart | 26 +- .../instabug_widget_binding_observer.dart | 1 + test/apm_test.dart | 2 +- .../instabug_screen_render_manager_test.dart | 66 +- ...reen_render_manager_test_manual_mocks.dart | 759 ------------------ 11 files changed, 109 insertions(+), 870 deletions(-) delete mode 100644 test/utils/screen_render/instabug_screen_render_manager_test_manual_mocks.dart diff --git a/CHANGELOG.md b/CHANGELOG.md index 324ce8a07..fa026330e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,9 @@ - **BREAKING** Remove deprecated APIs ([#614](https://github.com/Instabug/Instabug-Flutter/pull/614)). See migration guide for more details. ### Added -- Add support for Advanced UI customization with comprehensive theming capabilities ([#599](https://github.com/Instabug/Instabug-Flutter/pull/599)) +- Add support for Advanced UI customization with comprehensive theming capabilities. ([#599](https://github.com/Instabug/Instabug-Flutter/pull/599)) + +- Add screen rendering monitoring functionality within the APM product. ([#605](https://github.com/Instabug/Instabug-Flutter/pull/605)) ## [15.0.2](https://github.com/Instabug/Instabug-Flutter/compare/v14.3.0...15.0.2) (Jul 7, 2025) diff --git a/android/src/test/java/com/instabug/flutter/ApmApiTest.java b/android/src/test/java/com/instabug/flutter/ApmApiTest.java index b75b0b4e3..d7bacc450 100644 --- a/android/src/test/java/com/instabug/flutter/ApmApiTest.java +++ b/android/src/test/java/com/instabug/flutter/ApmApiTest.java @@ -5,7 +5,6 @@ import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mockStatic; @@ -16,6 +15,7 @@ import com.instabug.apm.InternalAPM; import com.instabug.apm.configuration.cp.APMFeature; import com.instabug.apm.configuration.cp.FeatureAvailabilityCallback; +import com.instabug.apm.configuration.cp.ToleranceValueCallback; import com.instabug.apm.networking.APMNetworkLogger; import com.instabug.flutter.generated.ApmPigeon; import com.instabug.flutter.modules.ApmApi; @@ -24,20 +24,18 @@ import org.json.JSONObject; import org.junit.After; -import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.mockito.MockedConstruction; import org.mockito.MockedStatic; +import java.lang.reflect.Array; +import java.util.Arrays; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.concurrent.Callable; -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.*; import static org.mockito.Mockito.*; import io.flutter.plugin.common.BinaryMessenger; @@ -361,24 +359,10 @@ public void testSetScreenRenderEnabled() { mAPM.verify(() -> APM.setScreenRenderingEnabled(isEnabled)); } - @Test - public void testDeviceRefreshRate() throws Exception { - float expectedRefreshRate = 60.0f; - Double expectedResult = 60.0; - ApmPigeon.Result result = spy(makeResult((actual) -> assertEquals(expectedResult, actual))); - - // Mock the refresh rate provider to return the expected value - Callable mockRefreshRateProvider = () -> expectedRefreshRate; - ApmApi testApi = new ApmApi(mockRefreshRateProvider); - - testApi.deviceRefreshRate(result); - - verify(result).success(expectedResult); - } @Test public void testDeviceRefreshRateWithException() throws Exception { - ApmPigeon.Result result = spy(makeResult((actual) -> {})); + ApmPigeon.Result> result = spy(makeResult((actual) -> {})); // Mock the refresh rate provider to throw an exception Callable mockRefreshRateProvider = () -> { @@ -386,13 +370,41 @@ public void testDeviceRefreshRateWithException() throws Exception { }; ApmApi testApi = new ApmApi(mockRefreshRateProvider); - testApi.deviceRefreshRate(result); + testApi.getDeviceRefreshRateAndTolerance(result); // Verify that the method doesn't crash when an exception occurs // The exception is caught and printed, but the result is not called verify(result, never()).success(any()); } + @Test + public void testGetDeviceRefreshRateAndTolerance() throws Exception { + // Arrange + double expectedRefreshRate = 60.0; + long expectedTolerance = 5L; + List expectedResult = Arrays.asList(expectedRefreshRate, (double) expectedTolerance); + ApmPigeon.Result> result = spy(makeResult((actual) -> assertEquals(expectedResult, actual))); + + // Mock the refresh rate provider + Callable mockRefreshRateProvider = () -> (float) expectedRefreshRate; + ApmApi testApi = new ApmApi(mockRefreshRateProvider); + + // Mock the tolerance callback + mInternalApmStatic.when(() -> InternalAPM._getToleranceValueForScreenRenderingCP(any(ToleranceValueCallback.class))).thenAnswer(invocation -> { + ToleranceValueCallback callback = invocation.getArgument(0); + callback.invoke(expectedTolerance); + return null; + }); + + // Act + testApi.getDeviceRefreshRateAndTolerance(result); + + // Assert + verify(result).success(expectedResult); + mInternalApmStatic.verify(() -> InternalAPM._getToleranceValueForScreenRenderingCP(any(ToleranceValueCallback.class))); + mInternalApmStatic.verifyNoMoreInteractions(); + } + @Test public void testEndScreenRenderForAutoUiTrace() { Map data = new HashMap<>(); diff --git a/example/ios/InstabugTests/ApmApiTests.m b/example/ios/InstabugTests/ApmApiTests.m index 0d59dcbf9..e18643bf7 100644 --- a/example/ios/InstabugTests/ApmApiTests.m +++ b/example/ios/InstabugTests/ApmApiTests.m @@ -249,50 +249,41 @@ - (void)testSetScreenRenderDisabled { OCMVerify([self.mAPM setScreenRenderingEnabled:NO]); } -- (void)testDeviceRefreshRate { +- (void)testGetDeviceRefreshRateAndTolerance { XCTestExpectation *expectation = [self expectationWithDescription:@"Call completion handler"]; - // Mock UIScreen for iOS 10.3+ - id mockScreen = OCMClassMock([UIScreen class]); - OCMStub([mockScreen mainScreen]).andReturn(mockScreen); - OCMStub([mockScreen maximumFramesPerSecond]).andReturn(120.0); + // Mock values + double expectedTolerance = 5.0; + double expectedRefreshRate = 60.0; - [self.api deviceRefreshRateWithCompletion:^(NSNumber *refreshRate, FlutterError *error) { - [expectation fulfill]; - - XCTAssertEqualObjects(refreshRate, @(120.0)); - XCTAssertNil(error); - }]; - - [self waitForExpectations:@[expectation] timeout:5.0]; + // Mock the tolerance value + OCMStub([self.mAPM screenRenderingThreshold]).andReturn(expectedTolerance); - [mockScreen stopMocking]; -} - -- (void)testDeviceRefreshRateFallback { - XCTestExpectation *expectation = [self expectationWithDescription:@"Call completion handler"]; - - // Note: Testing the fallback behavior for iOS < 10.3 is challenging in unit tests - // since we can't easily mock the iOS version check. In a real scenario, this would - // return 60.0 for older iOS versions. For now, we'll test the normal case. + // Mock UIScreen class methods + id mockUIScreen = OCMClassMock([UIScreen class]); + id mockMainScreen = OCMClassMock([UIScreen class]); - // Mock UIScreen to return 60.0 (typical fallback value) - id mockScreen = OCMClassMock([UIScreen class]); - OCMStub([mockScreen mainScreen]).andReturn(mockScreen); - OCMStub([mockScreen maximumFramesPerSecond]).andReturn(60.0); + // Stub the class method and instance property + OCMStub([mockUIScreen mainScreen]).andReturn(mockMainScreen); + OCMStub([mockMainScreen maximumFramesPerSecond]).andReturn(expectedRefreshRate); - [self.api deviceRefreshRateWithCompletion:^(NSNumber *refreshRate, FlutterError *error) { + [self.api getDeviceRefreshRateAndToleranceWithCompletion:^(NSArray *result, FlutterError *error) { [expectation fulfill]; - XCTAssertEqualObjects(refreshRate, @(60.0)); + XCTAssertNotNil(result); + XCTAssertEqual(result.count, 2); + XCTAssertEqualObjects(result[0], @(expectedRefreshRate)); + XCTAssertEqualObjects(result[1], @(expectedTolerance)); XCTAssertNil(error); }]; - + [self waitForExpectations:@[expectation] timeout:5.0]; - [mockScreen stopMocking]; + [mockUIScreen stopMocking]; + [mockMainScreen stopMocking]; } + - (void)testEndScreenRenderForAutoUiTrace { FlutterError *error; diff --git a/example/lib/main.dart b/example/lib/main.dart index 3993be3ae..fa332490c 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -28,7 +28,6 @@ part 'src/components/non_fatal_crashes_content.dart'; part 'src/components/page.dart'; part 'src/components/screen_render.dart'; part 'src/components/screen_render_switch.dart'; -part 'src/components/traces_content.dart'; part 'src/components/ui_traces_content.dart'; part 'src/screens/apm_page.dart'; part 'src/screens/complex_page.dart'; @@ -38,8 +37,6 @@ part 'src/screens/screen_capture_premature_extension_page.dart'; part 'src/screens/screen_loading_page.dart'; part 'src/screens/screen_render_page.dart'; -part 'src/components/flows_content.dart'; - void main() { runZonedGuarded( () { diff --git a/example/pubspec.lock b/example/pubspec.lock index dbdfc1d49..1221be412 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -112,10 +112,10 @@ packages: dependency: "direct main" description: name: instabug_http_client - sha256: "97a6ab88491eff87e42437564b528d6986a65eb3f3262f73373009f949cb4560" + sha256: a38bed979f549ffe85efa46c46ca743cbfab95a51295b60f143f249b71655231 url: "https://pub.dev" source: hosted - version: "2.5.1" + version: "2.6.0" leak_tracker: dependency: transitive description: diff --git a/lib/src/modules/apm.dart b/lib/src/modules/apm.dart index ebbc1e57b..09b69ed68 100644 --- a/lib/src/modules/apm.dart +++ b/lib/src/modules/apm.dart @@ -142,9 +142,9 @@ class APM { (_) async { // Start screen render collector for custom ui trace if enabled. if (await FlagsConfig.screenRendering.isEnabled()) { - InstabugScreenRenderManager.I.endScreenRenderCollector(); + InstabugScreenRenderManager.I + .endScreenRenderCollector(UiTraceType.custom); - // final uiTraceId = IBGDateTime.I.now().millisecondsSinceEpoch; InstabugScreenRenderManager.I .startScreenRenderCollectorForTraceId(0, UiTraceType.custom); } @@ -159,7 +159,8 @@ class APM { static Future endUITrace() async { // End screen render collector for custom ui trace if enabled. if (InstabugScreenRenderManager.I.screenRenderEnabled) { - return InstabugScreenRenderManager.I.endScreenRenderCollector(); + return InstabugScreenRenderManager.I + .endScreenRenderCollector(UiTraceType.custom); } return _host.endUITrace(); diff --git a/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart b/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart index dee64306a..7dd74ea16 100644 --- a/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart +++ b/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart @@ -125,9 +125,7 @@ class InstabugScreenRenderManager { ]) { try { // Return if frameTimingListener not attached - if (!screenRenderEnabled || !_isTimingsListenerAttached) { - return; - } + if (frameCollectorIsNotActive) return; if (type == UiTraceType.custom) { _screenRenderForCustomUiTrace.traceId = traceId; @@ -147,13 +145,12 @@ class InstabugScreenRenderManager { ]) { try { // Return if frameTimingListener not attached - if (!screenRenderEnabled || !_isTimingsListenerAttached) { - return; - } + // log("frameCollectorIsNotActive $frameCollectorIsNotActive"); + if (frameCollectorIsNotActive) return; //Save the memory cached data to be sent to native side if (_delayedFrames.isNotEmpty) { - _saveCollectedData(); + saveCollectedData(); _resetCachedFrameData(); } @@ -178,24 +175,33 @@ class InstabugScreenRenderManager { @internal void stopScreenRenderCollector() { try { + // Return if frameTimingListener not attached + if (frameCollectorIsNotActive) return; + if (_delayedFrames.isNotEmpty) { - _saveCollectedData(); + saveCollectedData(); + _resetCachedFrameData(); } // Sync Screen Render data for custom ui trace if exists if (_screenRenderForCustomUiTrace.isActive) { _reportScreenRenderForCustomUiTrace(_screenRenderForCustomUiTrace); + _screenRenderForCustomUiTrace.clear(); } // Sync Screen Render data for auto ui trace if exists if (_screenRenderForAutoUiTrace.isActive) { _reportScreenRenderForAutoUiTrace(_screenRenderForAutoUiTrace); + _screenRenderForAutoUiTrace.clear(); } } catch (error, stackTrace) { _logExceptionErrorAndStackTrace(error, stackTrace); } } + bool get frameCollectorIsNotActive => + !screenRenderEnabled || !_isTimingsListenerAttached; + /// Dispose InstabugScreenRenderManager by removing timings callback and cashed data. void dispose() { _resetCachedFrameData(); @@ -326,6 +332,7 @@ class InstabugScreenRenderManager { InstabugScreenRenderData screenRenderData, ) async { try { + screenRenderData.saveEndTime(); log( "reportScreenRenderForCustomUiTrace $screenRenderData", name: tag, @@ -361,7 +368,8 @@ class InstabugScreenRenderManager { } /// Add the memory cashed data to the objects that will be synced asynchronously to the native side. - void _saveCollectedData() { + @visibleForTesting + void saveCollectedData() { if (_screenRenderForAutoUiTrace.isActive) { _updateAutoUiData(); } diff --git a/lib/src/utils/screen_rendering/instabug_widget_binding_observer.dart b/lib/src/utils/screen_rendering/instabug_widget_binding_observer.dart index 5a27d15f0..3c18b1642 100644 --- a/lib/src/utils/screen_rendering/instabug_widget_binding_observer.dart +++ b/lib/src/utils/screen_rendering/instabug_widget_binding_observer.dart @@ -36,6 +36,7 @@ class InstabugWidgetsBindingObserver extends WidgetsBindingObserver { .then((uiTraceId) { if (uiTraceId != null && InstabugScreenRenderManager.I.screenRenderEnabled) { + InstabugScreenRenderManager.I.endScreenRenderCollector(); InstabugScreenRenderManager.I .startScreenRenderCollectorForTraceId(uiTraceId); } diff --git a/test/apm_test.dart b/test/apm_test.dart index 2c5fb8b5c..3ca288f68 100644 --- a/test/apm_test.dart +++ b/test/apm_test.dart @@ -310,7 +310,7 @@ void main() { await APM.endUITrace(); verify( - mScreenRenderManager.endScreenRenderCollector(), + mScreenRenderManager.endScreenRenderCollector(UiTraceType.custom), ).called(1); verifyNever(mHost.endUITrace()); }); diff --git a/test/utils/screen_render/instabug_screen_render_manager_test.dart b/test/utils/screen_render/instabug_screen_render_manager_test.dart index 26983dcfa..00e80da15 100644 --- a/test/utils/screen_render/instabug_screen_render_manager_test.dart +++ b/test/utils/screen_render/instabug_screen_render_manager_test.dart @@ -9,7 +9,7 @@ import 'package:instabug_flutter/src/utils/screen_rendering/instabug_screen_rend import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; -import 'instabug_screen_render_manager_test_manual_mocks.dart'; +import 'instabug_screen_render_manager_test.mocks.dart'; @GenerateMocks([ApmHostApi, FrameTiming, WidgetsBinding]) void main() { @@ -168,15 +168,11 @@ void main() { }); test( - 'should save and data to screenRenderForAutoUiTrace when for autoUITrace', + 'for auto UITrace should report data to native using endScreenRenderForAutoUiTrace', () { final frameTestData = InstabugScreenRenderData( traceId: 123, - frameData: [ - InstabugFrameData(10000, 400), - InstabugFrameData(10000, 600), - InstabugFrameData(20000, 1000), - ], + frameData: [], frozenFramesTotalDurationMicro: 1000, slowFramesTotalDurationMicro: 1000, endTimeMicro: 30000, @@ -186,23 +182,28 @@ void main() { frameTestData.traceId, ); + manager.startScreenRenderCollectorForTraceId( + frameTestData.traceId + 1, + UiTraceType.custom, + ); + manager.setFrameData(frameTestData); manager.stopScreenRenderCollector(); - expect(manager.screenRenderForAutoUiTrace.isActive, true); - - expect(manager.screenRenderForCustomUiTrace.isActive, false); - - expect(manager.screenRenderForAutoUiTrace == frameTestData, true); - verify( mApmHost.endScreenRenderForAutoUiTrace(any), ); // the content has been verified in the above assertion. + + expect(manager.screenRenderForAutoUiTrace.isActive, false); + + expect(manager.screenRenderForCustomUiTrace.isActive, false); + + expect(manager.screenRenderForAutoUiTrace.isEmpty, true); }); test( - 'should save and data to screenRenderForCustomUiTrace when for customUITrace', + 'for custom UITrace should report data to native using endScreenRenderForCustomUiTrace', () { final frameTestData = InstabugScreenRenderData( traceId: 123, @@ -225,11 +226,11 @@ void main() { manager.stopScreenRenderCollector(); - expect(manager.screenRenderForCustomUiTrace.isActive, true); + expect(manager.screenRenderForCustomUiTrace.isActive, false); expect(manager.screenRenderForAutoUiTrace.isActive, false); - expect(manager.screenRenderForCustomUiTrace == frameTestData, true); + expect(manager.screenRenderForCustomUiTrace.isEmpty, true); verify( mApmHost.endScreenRenderForCustomUiTrace(any), @@ -367,15 +368,10 @@ void main() { manager.analyzeFrameTiming(mockFrameTiming); // mock frame timing manager.stopScreenRenderCollector(); // should save data - expect(manager.screenRenderForAutoUiTrace.frameData.length, 1); - expect( - manager.screenRenderForAutoUiTrace.slowFramesTotalDurationMicro, - buildDuration * 1000, - ); // * 1000 to convert from milliseconds to microseconds expect( - manager.screenRenderForAutoUiTrace.frozenFramesTotalDurationMicro, - 0, - ); + manager.screenRenderForAutoUiTrace.frameData.isEmpty, + true, + ); // reset cached data after sync }); test('should detect slow frame on raster thread and record duration', () { @@ -387,15 +383,10 @@ void main() { manager.analyzeFrameTiming(mockFrameTiming); // mock frame timing manager.stopScreenRenderCollector(); // should save data - expect(manager.screenRenderForAutoUiTrace.frameData.length, 1); - expect( - manager.screenRenderForAutoUiTrace.slowFramesTotalDurationMicro, - rasterDuration * 1000, - ); // * 1000 to convert from milliseconds to microseconds expect( - manager.screenRenderForAutoUiTrace.frozenFramesTotalDurationMicro, - 0, - ); + manager.screenRenderForAutoUiTrace.frameData.isEmpty, + true, + ); // reset cached data after sync }); test( @@ -408,15 +399,10 @@ void main() { manager.analyzeFrameTiming(mockFrameTiming); // mock frame timing manager.stopScreenRenderCollector(); // should save data - expect(manager.screenRenderForAutoUiTrace.frameData.length, 1); - expect( - manager.screenRenderForAutoUiTrace.frozenFramesTotalDurationMicro, - totalTime * 1000, - ); // * 1000 to convert from milliseconds to microseconds expect( - manager.screenRenderForAutoUiTrace.slowFramesTotalDurationMicro, - 0, - ); + manager.screenRenderForAutoUiTrace.frameData.isEmpty, + true, + ); // reset cached data after sync }); test('should detect no slow or frozen frame under thresholds', () { diff --git a/test/utils/screen_render/instabug_screen_render_manager_test_manual_mocks.dart b/test/utils/screen_render/instabug_screen_render_manager_test_manual_mocks.dart deleted file mode 100644 index 64d147846..000000000 --- a/test/utils/screen_render/instabug_screen_render_manager_test_manual_mocks.dart +++ /dev/null @@ -1,759 +0,0 @@ -// Mocks generated by Mockito 5.2.0 from annotations -// in instabug_flutter/example/ios/.symlinks/plugins/instabug_flutter/test/utils/screen_render/instabug_screen_render_manager_test.dart. -// Do not manually edit this file. - -import 'dart:async' as _i9; -import 'dart:developer' as _i13; -import 'dart:ui' as _i4; - -import 'package:flutter/foundation.dart' as _i3; -import 'package:flutter/gestures.dart' as _i6; -import 'package:flutter/rendering.dart' as _i7; -import 'package:flutter/scheduler.dart' as _i11; -import 'package:flutter/services.dart' as _i5; -import 'package:flutter/src/widgets/binding.dart' as _i10; -import 'package:flutter/src/widgets/focus_manager.dart' as _i2; -import 'package:flutter/src/widgets/framework.dart' as _i12; -import 'package:instabug_flutter/src/generated/apm.api.g.dart' as _i8; -import 'package:mockito/mockito.dart' as _i1; - -// ignore_for_file: type=lint -// ignore_for_file: avoid_redundant_argument_values -// ignore_for_file: avoid_setters_without_getters -// ignore_for_file: comment_references -// ignore_for_file: implementation_imports -// ignore_for_file: invalid_use_of_visible_for_testing_member -// ignore_for_file: prefer_const_constructors -// ignore_for_file: unnecessary_parenthesis -// ignore_for_file: camel_case_types - -class _FakeFocusManager_0 extends _i1.Fake implements _i2.FocusManager { - @override - String toString({_i3.DiagnosticLevel? minLevel = _i3.DiagnosticLevel.info}) => - super.toString(); -} - -class _FakeSingletonFlutterWindow_1 extends _i1.Fake - implements _i4.SingletonFlutterWindow {} - -class _FakePlatformDispatcher_2 extends _i1.Fake - implements _i4.PlatformDispatcher {} - -class _FakeHardwareKeyboard_3 extends _i1.Fake implements - _i5.HardwareKeyboard {} - -class _FakeKeyEventManager_4 extends _i1.Fake implements _i5.KeyEventManager {} - -class _FakeBinaryMessenger_5 extends _i1.Fake implements _i5.BinaryMessenger {} - -class _FakeChannelBuffers_6 extends _i1.Fake implements _i4.ChannelBuffers {} - -class _FakeRestorationManager_7 extends _i1.Fake - implements _i5.RestorationManager {} - -class _FakeDuration_8 extends _i1.Fake implements Duration {} - -class _FakePointerRouter_9 extends _i1.Fake implements _i6.PointerRouter {} - -class _FakeGestureArenaManager_10 extends _i1.Fake - implements _i6.GestureArenaManager {} - -class _FakePointerSignalResolver_11 extends _i1.Fake - implements _i6.PointerSignalResolver {} - -class _FakeMouseTracker_12 extends _i1.Fake implements _i7.MouseTracker {} - -class _FakePipelineOwner_13 extends _i1.Fake implements _i7.PipelineOwner {} - -class _FakeRenderView_14 extends _i1.Fake implements _i7.RenderView { - @override - String toString({_i3.DiagnosticLevel? minLevel = _i3.DiagnosticLevel.info}) => - super.toString(); -} - -class _FakeAccessibilityFeatures_15 extends _i1.Fake - implements _i4.AccessibilityFeatures {} - -class _FakeViewConfiguration_16 extends _i1.Fake - implements _i7.ViewConfiguration {} - -class _FakeSemanticsUpdateBuilder_17 extends _i1.Fake - implements _i4.SemanticsUpdateBuilder {} - -/// A class which mocks [ApmHostApi]. -/// -/// See the documentation for Mockito's code generation for more information. -class MockApmHostApi extends _i1.Mock implements _i8.ApmHostApi { - MockApmHostApi() { - _i1.throwOnMissingStub(this); - } - - @override - _i9.Future setEnabled(bool? arg_isEnabled) => - (super.noSuchMethod(Invocation.method(#setEnabled, [arg_isEnabled]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - _i9.Future isEnabled() => - (super.noSuchMethod(Invocation.method(#isEnabled, []), - returnValue: Future.value(false)) as _i9.Future); - @override - _i9.Future setScreenLoadingEnabled(bool? arg_isEnabled) => - (super.noSuchMethod( - Invocation.method(#setScreenLoadingEnabled, [arg_isEnabled]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - _i9.Future isScreenLoadingEnabled() => - (super.noSuchMethod(Invocation.method(#isScreenLoadingEnabled, []), - returnValue: Future.value(false)) as _i9.Future); - @override - _i9.Future setColdAppLaunchEnabled(bool? arg_isEnabled) => - (super.noSuchMethod( - Invocation.method(#setColdAppLaunchEnabled, [arg_isEnabled]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - _i9.Future setAutoUITraceEnabled(bool? arg_isEnabled) => (super - .noSuchMethod(Invocation.method(#setAutoUITraceEnabled, [arg_isEnabled]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - _i9.Future startExecutionTrace(String? arg_id, String? arg_name) => - (super.noSuchMethod( - Invocation.method(#startExecutionTrace, [arg_id, arg_name]), - returnValue: Future.value()) as _i9.Future); - @override - _i9.Future startFlow(String? arg_name) => - (super.noSuchMethod(Invocation.method(#startFlow, [arg_name]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - _i9.Future setFlowAttribute( - String? arg_name, String? arg_key, String? arg_value) => - (super.noSuchMethod( - Invocation.method(#setFlowAttribute, [arg_name, arg_key, arg_value]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - _i9.Future endFlow(String? arg_name) => - (super.noSuchMethod(Invocation.method(#endFlow, [arg_name]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - _i9.Future setExecutionTraceAttribute( - String? arg_id, String? arg_key, String? arg_value) => - (super.noSuchMethod( - Invocation.method( - #setExecutionTraceAttribute, [arg_id, arg_key, arg_value]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - _i9.Future endExecutionTrace(String? arg_id) => - (super.noSuchMethod(Invocation.method(#endExecutionTrace, [arg_id]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - _i9.Future startUITrace(String? arg_name) => - (super.noSuchMethod(Invocation.method(#startUITrace, [arg_name]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - _i9.Future endUITrace() => - (super.noSuchMethod(Invocation.method(#endUITrace, []), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - _i9.Future endAppLaunch() => - (super.noSuchMethod(Invocation.method(#endAppLaunch, []), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - _i9.Future networkLogAndroid(Map? arg_data) => - (super.noSuchMethod(Invocation.method(#networkLogAndroid, [arg_data]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - _i9.Future startCpUiTrace( - String? arg_screenName, int? arg_microTimeStamp, int? arg_traceId) => - (super.noSuchMethod( - Invocation.method(#startCpUiTrace, - [arg_screenName, arg_microTimeStamp, arg_traceId]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - _i9.Future reportScreenLoadingCP(int? arg_startTimeStampMicro, - int? arg_durationMicro, int? arg_uiTraceId) => - (super.noSuchMethod( - Invocation.method(#reportScreenLoadingCP, - [arg_startTimeStampMicro, arg_durationMicro, arg_uiTraceId]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - _i9.Future endScreenLoadingCP( - int? arg_timeStampMicro, int? arg_uiTraceId) => - (super.noSuchMethod( - Invocation.method( - #endScreenLoadingCP, [arg_timeStampMicro, arg_uiTraceId]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - _i9.Future isEndScreenLoadingEnabled() => - (super.noSuchMethod(Invocation.method(#isEndScreenLoadingEnabled, []), - returnValue: Future.value(false)) as _i9.Future); - @override - _i9.Future isScreenRenderEnabled() => - (super.noSuchMethod(Invocation.method(#isScreenRenderEnabled, []), - returnValue: Future.value(false)) as _i9.Future); - @override - _i9.Future deviceRefreshRate() => - (super.noSuchMethod(Invocation.method(#deviceRefreshRate, []), - returnValue: Future.value(0.0)) as _i9.Future); - @override - _i9.Future setScreenRenderEnabled(bool? arg_isEnabled) => (super - .noSuchMethod(Invocation.method(#setScreenRenderEnabled, [arg_isEnabled]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - _i9.Future endScreenRenderForAutoUiTrace( - Map? arg_data) => - (super.noSuchMethod( - Invocation.method(#endScreenRenderForAutoUiTrace, [arg_data]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - _i9.Future endScreenRenderForCustomUiTrace( - Map? arg_data) => - (super.noSuchMethod( - Invocation.method(#endScreenRenderForCustomUiTrace, [arg_data]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); -} - -/// A class which mocks [WidgetsBinding]. -/// -/// See the documentation for Mockito's code generation for more information. -class MockWidgetsBinding extends _i1.Mock implements _i10.WidgetsBinding { - MockWidgetsBinding() { - _i1.throwOnMissingStub(this); - } - - @override - bool get debugBuildingDirtyElements => - (super.noSuchMethod(Invocation.getter(#debugBuildingDirtyElements), - returnValue: false) as bool); - @override - set debugBuildingDirtyElements(bool? _debugBuildingDirtyElements) => - super.noSuchMethod( - Invocation.setter( - #debugBuildingDirtyElements, _debugBuildingDirtyElements), - returnValueForMissingStub: null); - @override - _i2.FocusManager get focusManager => - (super.noSuchMethod(Invocation.getter(#focusManager), - returnValue: _FakeFocusManager_0()) as _i2.FocusManager); - @override - bool get firstFrameRasterized => - (super.noSuchMethod(Invocation.getter(#firstFrameRasterized), - returnValue: false) as bool); - @override - _i9.Future get waitUntilFirstFrameRasterized => - (super.noSuchMethod(Invocation.getter(#waitUntilFirstFrameRasterized), - returnValue: Future.value()) as _i9.Future); - @override - bool get debugDidSendFirstFrameEvent => - (super.noSuchMethod(Invocation.getter(#debugDidSendFirstFrameEvent), - returnValue: false) as bool); - @override - bool get framesEnabled => - (super.noSuchMethod(Invocation.getter(#framesEnabled), returnValue: false) - as bool); - @override - bool get isRootWidgetAttached => - (super.noSuchMethod(Invocation.getter(#isRootWidgetAttached), - returnValue: false) as bool); - @override - _i4.SingletonFlutterWindow get window => - (super.noSuchMethod(Invocation.getter(#window), - returnValue: _FakeSingletonFlutterWindow_1()) - as _i4.SingletonFlutterWindow); - @override - _i4.PlatformDispatcher get platformDispatcher => - (super.noSuchMethod(Invocation.getter(#platformDispatcher), - returnValue: _FakePlatformDispatcher_2()) as _i4.PlatformDispatcher); - @override - bool get locked => - (super.noSuchMethod(Invocation.getter(#locked), returnValue: false) - as bool); - @override - _i5.HardwareKeyboard get keyboard => - (super.noSuchMethod(Invocation.getter(#keyboard), - returnValue: _FakeHardwareKeyboard_3()) as _i5.HardwareKeyboard); - @override - _i5.KeyEventManager get keyEventManager => - (super.noSuchMethod(Invocation.getter(#keyEventManager), - returnValue: _FakeKeyEventManager_4()) as _i5.KeyEventManager); - @override - _i5.BinaryMessenger get defaultBinaryMessenger => - (super.noSuchMethod(Invocation.getter(#defaultBinaryMessenger), - returnValue: _FakeBinaryMessenger_5()) as _i5.BinaryMessenger); - @override - _i4.ChannelBuffers get channelBuffers => - (super.noSuchMethod(Invocation.getter(#channelBuffers), - returnValue: _FakeChannelBuffers_6()) as _i4.ChannelBuffers); - @override - _i5.RestorationManager get restorationManager => - (super.noSuchMethod(Invocation.getter(#restorationManager), - returnValue: _FakeRestorationManager_7()) as _i5.RestorationManager); - @override - _i11.SchedulingStrategy get schedulingStrategy => - (super.noSuchMethod(Invocation.getter(#schedulingStrategy), - returnValue: ({int? priority, _i11.SchedulerBinding? scheduler}) => - false) as _i11.SchedulingStrategy); - @override - set schedulingStrategy(_i11.SchedulingStrategy? _schedulingStrategy) => super - .noSuchMethod(Invocation.setter(#schedulingStrategy, _schedulingStrategy), - returnValueForMissingStub: null); - @override - int get transientCallbackCount => - (super.noSuchMethod(Invocation.getter(#transientCallbackCount), - returnValue: 0) as int); - @override - _i9.Future get endOfFrame => - (super.noSuchMethod(Invocation.getter(#endOfFrame), - returnValue: Future.value()) as _i9.Future); - @override - bool get hasScheduledFrame => - (super.noSuchMethod(Invocation.getter(#hasScheduledFrame), - returnValue: false) as bool); - @override - _i11.SchedulerPhase get schedulerPhase => - (super.noSuchMethod(Invocation.getter(#schedulerPhase), - returnValue: _i11.SchedulerPhase.idle) as _i11.SchedulerPhase); - @override - Duration get currentFrameTimeStamp => - (super.noSuchMethod(Invocation.getter(#currentFrameTimeStamp), - returnValue: _FakeDuration_8()) as Duration); - @override - Duration get currentSystemFrameTimeStamp => - (super.noSuchMethod(Invocation.getter(#currentSystemFrameTimeStamp), - returnValue: _FakeDuration_8()) as Duration); - @override - _i6.PointerRouter get pointerRouter => - (super.noSuchMethod(Invocation.getter(#pointerRouter), - returnValue: _FakePointerRouter_9()) as _i6.PointerRouter); - @override - _i6.GestureArenaManager get gestureArena => (super.noSuchMethod( - Invocation.getter(#gestureArena), - returnValue: _FakeGestureArenaManager_10()) as _i6.GestureArenaManager); - @override - _i6.PointerSignalResolver get pointerSignalResolver => - (super.noSuchMethod(Invocation.getter(#pointerSignalResolver), - returnValue: _FakePointerSignalResolver_11()) - as _i6.PointerSignalResolver); - @override - bool get resamplingEnabled => - (super.noSuchMethod(Invocation.getter(#resamplingEnabled), - returnValue: false) as bool); - @override - set resamplingEnabled(bool? _resamplingEnabled) => super.noSuchMethod( - Invocation.setter(#resamplingEnabled, _resamplingEnabled), - returnValueForMissingStub: null); - @override - Duration get samplingOffset => - (super.noSuchMethod(Invocation.getter(#samplingOffset), - returnValue: _FakeDuration_8()) as Duration); - @override - set samplingOffset(Duration? _samplingOffset) => - super.noSuchMethod(Invocation.setter(#samplingOffset, _samplingOffset), - returnValueForMissingStub: null); - @override - _i7.MouseTracker get mouseTracker => - (super.noSuchMethod(Invocation.getter(#mouseTracker), - returnValue: _FakeMouseTracker_12()) as _i7.MouseTracker); - @override - _i7.PipelineOwner get pipelineOwner => - (super.noSuchMethod(Invocation.getter(#pipelineOwner), - returnValue: _FakePipelineOwner_13()) as _i7.PipelineOwner); - @override - _i7.RenderView get renderView => - (super.noSuchMethod(Invocation.getter(#renderView), - returnValue: _FakeRenderView_14()) as _i7.RenderView); - @override - set renderView(_i7.RenderView? value) => - super.noSuchMethod(Invocation.setter(#renderView, value), - returnValueForMissingStub: null); - @override - bool get sendFramesToEngine => - (super.noSuchMethod(Invocation.getter(#sendFramesToEngine), - returnValue: false) as bool); - @override - _i4.AccessibilityFeatures get accessibilityFeatures => - (super.noSuchMethod(Invocation.getter(#accessibilityFeatures), - returnValue: _FakeAccessibilityFeatures_15()) - as _i4.AccessibilityFeatures); - @override - bool get disableAnimations => - (super.noSuchMethod(Invocation.getter(#disableAnimations), - returnValue: false) as bool); - @override - void initInstances() => - super.noSuchMethod(Invocation.method(#initInstances, []), - returnValueForMissingStub: null); - @override - void initServiceExtensions() => - super.noSuchMethod(Invocation.method(#initServiceExtensions, []), - returnValueForMissingStub: null); - @override - void addObserver(_i10.WidgetsBindingObserver? observer) => - super.noSuchMethod(Invocation.method(#addObserver, [observer]), - returnValueForMissingStub: null); - @override - bool removeObserver(_i10.WidgetsBindingObserver? observer) => - (super.noSuchMethod(Invocation.method(#removeObserver, [observer]), - returnValue: false) as bool); - @override - void handleMetricsChanged() => - super.noSuchMethod(Invocation.method(#handleMetricsChanged, []), - returnValueForMissingStub: null); - @override - void handleTextScaleFactorChanged() => - super.noSuchMethod(Invocation.method(#handleTextScaleFactorChanged, []), - returnValueForMissingStub: null); - @override - void handlePlatformBrightnessChanged() => super.noSuchMethod( - Invocation.method(#handlePlatformBrightnessChanged, []), - returnValueForMissingStub: null); - @override - void handleAccessibilityFeaturesChanged() => super.noSuchMethod( - Invocation.method(#handleAccessibilityFeaturesChanged, []), - returnValueForMissingStub: null); - @override - void handleLocaleChanged() => - super.noSuchMethod(Invocation.method(#handleLocaleChanged, []), - returnValueForMissingStub: null); - @override - void dispatchLocalesChanged(List<_i4.Locale>? locales) => - super.noSuchMethod(Invocation.method(#dispatchLocalesChanged, [locales]), - returnValueForMissingStub: null); - @override - void dispatchAccessibilityFeaturesChanged() => super.noSuchMethod( - Invocation.method(#dispatchAccessibilityFeaturesChanged, []), - returnValueForMissingStub: null); - @override - _i9.Future handlePopRoute() => - (super.noSuchMethod(Invocation.method(#handlePopRoute, []), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - _i9.Future handlePushRoute(String? route) => - (super.noSuchMethod(Invocation.method(#handlePushRoute, [route]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - void handleAppLifecycleStateChanged(_i4.AppLifecycleState? state) => super - .noSuchMethod(Invocation.method(#handleAppLifecycleStateChanged, [state]), - returnValueForMissingStub: null); - @override - void handleMemoryPressure() => - super.noSuchMethod(Invocation.method(#handleMemoryPressure, []), - returnValueForMissingStub: null); - @override - void drawFrame() => super.noSuchMethod(Invocation.method(#drawFrame, []), - returnValueForMissingStub: null); - @override - void scheduleAttachRootWidget(_i12.Widget? rootWidget) => super.noSuchMethod( - Invocation.method(#scheduleAttachRootWidget, [rootWidget]), - returnValueForMissingStub: null); - @override - void attachRootWidget(_i12.Widget? rootWidget) => - super.noSuchMethod(Invocation.method(#attachRootWidget, [rootWidget]), - returnValueForMissingStub: null); - @override - _i9.Future performReassemble() => - (super.noSuchMethod(Invocation.method(#performReassemble, []), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - _i4.Locale? computePlatformResolvedLocale( - List<_i4.Locale>? supportedLocales) => - (super.noSuchMethod(Invocation.method( - #computePlatformResolvedLocale, [supportedLocales])) as _i4.Locale?); - @override - _i9.Future lockEvents(_i9.Future Function()? callback) => - (super.noSuchMethod(Invocation.method(#lockEvents, [callback]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - void unlocked() => super.noSuchMethod(Invocation.method(#unlocked, []), - returnValueForMissingStub: null); - @override - _i9.Future reassembleApplication() => - (super.noSuchMethod(Invocation.method(#reassembleApplication, []), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - void registerSignalServiceExtension( - {String? name, _i3.AsyncCallback? callback}) => - super.noSuchMethod( - Invocation.method(#registerSignalServiceExtension, [], - {#name: name, #callback: callback}), - returnValueForMissingStub: null); - @override - void registerBoolServiceExtension( - {String? name, - _i3.AsyncValueGetter? getter, - _i3.AsyncValueSetter? setter}) => - super.noSuchMethod( - Invocation.method(#registerBoolServiceExtension, [], - {#name: name, #getter: getter, #setter: setter}), - returnValueForMissingStub: null); - @override - void registerNumericServiceExtension( - {String? name, - _i3.AsyncValueGetter? getter, - _i3.AsyncValueSetter? setter}) => - super.noSuchMethod( - Invocation.method(#registerNumericServiceExtension, [], - {#name: name, #getter: getter, #setter: setter}), - returnValueForMissingStub: null); - @override - void postEvent(String? eventKind, Map? eventData) => - super.noSuchMethod(Invocation.method(#postEvent, [eventKind, eventData]), - returnValueForMissingStub: null); - @override - void registerStringServiceExtension( - {String? name, - _i3.AsyncValueGetter? getter, - _i3.AsyncValueSetter? setter}) => - super.noSuchMethod( - Invocation.method(#registerStringServiceExtension, [], - {#name: name, #getter: getter, #setter: setter}), - returnValueForMissingStub: null); - @override - void registerServiceExtension( - {String? name, _i3.ServiceExtensionCallback? callback}) => - super.noSuchMethod( - Invocation.method(#registerServiceExtension, [], - {#name: name, #callback: callback}), - returnValueForMissingStub: null); - @override - _i5.BinaryMessenger createBinaryMessenger() => - (super.noSuchMethod(Invocation.method(#createBinaryMessenger, []), - returnValue: _FakeBinaryMessenger_5()) as _i5.BinaryMessenger); - @override - _i9.Future handleSystemMessage(Object? systemMessage) => (super - .noSuchMethod(Invocation.method(#handleSystemMessage, [systemMessage]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - void initLicenses() => - super.noSuchMethod(Invocation.method(#initLicenses, []), - returnValueForMissingStub: null); - @override - void evict(String? asset) => - super.noSuchMethod(Invocation.method(#evict, [asset]), - returnValueForMissingStub: null); - @override - void readInitialLifecycleStateFromNativeWindow() => super.noSuchMethod( - Invocation.method(#readInitialLifecycleStateFromNativeWindow, []), - returnValueForMissingStub: null); - @override - _i5.RestorationManager createRestorationManager() => - (super.noSuchMethod(Invocation.method(#createRestorationManager, []), - returnValue: _FakeRestorationManager_7()) as _i5.RestorationManager); - @override - void setSystemUiChangeCallback(_i5.SystemUiChangeCallback? callback) => super - .noSuchMethod(Invocation.method(#setSystemUiChangeCallback, [callback]), - returnValueForMissingStub: null); - @override - void addTimingsCallback(_i4.TimingsCallback? callback) => - super.noSuchMethod(Invocation.method(#addTimingsCallback, [callback]), - returnValueForMissingStub: null); - @override - void removeTimingsCallback(_i4.TimingsCallback? callback) => - super.noSuchMethod(Invocation.method(#removeTimingsCallback, [callback]), - returnValueForMissingStub: null); - @override - _i9.Future scheduleTask( - _i11.TaskCallback? task, _i11.Priority? priority, - {String? debugLabel, _i13.Flow? flow}) => - (super.noSuchMethod( - Invocation.method(#scheduleTask, [task, priority], - {#debugLabel: debugLabel, #flow: flow}), - returnValue: Future.value(null)) as _i9.Future); - @override - bool handleEventLoopCallback() => - (super.noSuchMethod(Invocation.method(#handleEventLoopCallback, []), - returnValue: false) as bool); - @override - int scheduleFrameCallback(_i11.FrameCallback? callback, - {bool? rescheduling = false}) => - (super.noSuchMethod( - Invocation.method(#scheduleFrameCallback, [callback], - {#rescheduling: rescheduling}), - returnValue: 0) as int); - @override - void cancelFrameCallbackWithId(int? id) => - super.noSuchMethod(Invocation.method(#cancelFrameCallbackWithId, [id]), - returnValueForMissingStub: null); - @override - bool debugAssertNoTransientCallbacks(String? reason) => (super.noSuchMethod( - Invocation.method(#debugAssertNoTransientCallbacks, [reason]), - returnValue: false) as bool); - @override - void addPersistentFrameCallback(_i11.FrameCallback? callback) => super - .noSuchMethod(Invocation.method(#addPersistentFrameCallback, [callback]), - returnValueForMissingStub: null); - @override - void addPostFrameCallback(_i11.FrameCallback? callback) => - super.noSuchMethod(Invocation.method(#addPostFrameCallback, [callback]), - returnValueForMissingStub: null); - @override - void ensureFrameCallbacksRegistered() => - super.noSuchMethod(Invocation.method(#ensureFrameCallbacksRegistered, []), - returnValueForMissingStub: null); - @override - void ensureVisualUpdate() => - super.noSuchMethod(Invocation.method(#ensureVisualUpdate, []), - returnValueForMissingStub: null); - @override - void scheduleFrame() => - super.noSuchMethod(Invocation.method(#scheduleFrame, []), - returnValueForMissingStub: null); - @override - void scheduleForcedFrame() => - super.noSuchMethod(Invocation.method(#scheduleForcedFrame, []), - returnValueForMissingStub: null); - @override - void scheduleWarmUpFrame() => - super.noSuchMethod(Invocation.method(#scheduleWarmUpFrame, []), - returnValueForMissingStub: null); - @override - void resetEpoch() => super.noSuchMethod(Invocation.method(#resetEpoch, []), - returnValueForMissingStub: null); - @override - void handleBeginFrame(Duration? rawTimeStamp) => - super.noSuchMethod(Invocation.method(#handleBeginFrame, [rawTimeStamp]), - returnValueForMissingStub: null); - @override - void handleDrawFrame() => - super.noSuchMethod(Invocation.method(#handleDrawFrame, []), - returnValueForMissingStub: null); - @override - void cancelPointer(int? pointer) => - super.noSuchMethod(Invocation.method(#cancelPointer, [pointer]), - returnValueForMissingStub: null); - @override - void handlePointerEvent(_i6.PointerEvent? event) => - super.noSuchMethod(Invocation.method(#handlePointerEvent, [event]), - returnValueForMissingStub: null); - @override - void hitTest(_i6.HitTestResult? result, _i4.Offset? position) => - super.noSuchMethod(Invocation.method(#hitTest, [result, position]), - returnValueForMissingStub: null); - @override - void dispatchEvent( - _i6.PointerEvent? event, _i6.HitTestResult? hitTestResult) => - super.noSuchMethod( - Invocation.method(#dispatchEvent, [event, hitTestResult]), - returnValueForMissingStub: null); - @override - void handleEvent(_i6.PointerEvent? event, _i6.HitTestEntry? entry) => - super.noSuchMethod(Invocation.method(#handleEvent, [event, entry]), - returnValueForMissingStub: null); - @override - void resetGestureBinding() => - super.noSuchMethod(Invocation.method(#resetGestureBinding, []), - returnValueForMissingStub: null); - @override - void initRenderView() => - super.noSuchMethod(Invocation.method(#initRenderView, []), - returnValueForMissingStub: null); - @override - _i7.ViewConfiguration createViewConfiguration() => - (super.noSuchMethod(Invocation.method(#createViewConfiguration, []), - returnValue: _FakeViewConfiguration_16()) as _i7.ViewConfiguration); - @override - void initMouseTracker([_i7.MouseTracker? tracker]) => - super.noSuchMethod(Invocation.method(#initMouseTracker, [tracker]), - returnValueForMissingStub: null); - @override - void setSemanticsEnabled(bool? enabled) => - super.noSuchMethod(Invocation.method(#setSemanticsEnabled, [enabled]), - returnValueForMissingStub: null); - @override - void deferFirstFrame() => - super.noSuchMethod(Invocation.method(#deferFirstFrame, []), - returnValueForMissingStub: null); - @override - void allowFirstFrame() => - super.noSuchMethod(Invocation.method(#allowFirstFrame, []), - returnValueForMissingStub: null); - @override - void resetFirstFrameSent() => - super.noSuchMethod(Invocation.method(#resetFirstFrameSent, []), - returnValueForMissingStub: null); - @override - _i4.SemanticsUpdateBuilder createSemanticsUpdateBuilder() => - (super.noSuchMethod(Invocation.method(#createSemanticsUpdateBuilder, []), - returnValue: _FakeSemanticsUpdateBuilder_17()) - as _i4.SemanticsUpdateBuilder); -} - -/// A class which mocks [FrameTiming]. -/// -/// See the documentation for Mockito's code generation for more information. -class MockFrameTiming extends _i1.Mock implements _i4.FrameTiming { - MockFrameTiming() { - _i1.throwOnMissingStub(this); - } - - @override - Duration get buildDuration => - (super.noSuchMethod(Invocation.getter(#buildDuration), - returnValue: _FakeDuration_8()) as Duration); - @override - Duration get rasterDuration => - (super.noSuchMethod(Invocation.getter(#rasterDuration), - returnValue: _FakeDuration_8()) as Duration); - @override - Duration get vsyncOverhead => - (super.noSuchMethod(Invocation.getter(#vsyncOverhead), - returnValue: _FakeDuration_8()) as Duration); - @override - Duration get totalSpan => (super.noSuchMethod(Invocation.getter(#totalSpan), - returnValue: _FakeDuration_8()) as Duration); - @override - int get layerCacheCount => - (super.noSuchMethod(Invocation.getter(#layerCacheCount), returnValue: 0) - as int); - @override - int get layerCacheBytes => - (super.noSuchMethod(Invocation.getter(#layerCacheBytes), returnValue: 0) - as int); - @override - double get layerCacheMegabytes => - (super.noSuchMethod(Invocation.getter(#layerCacheMegabytes), - returnValue: 0.0) as double); - @override - int get pictureCacheCount => - (super.noSuchMethod(Invocation.getter(#pictureCacheCount), returnValue: 0) - as int); - @override - int get pictureCacheBytes => - (super.noSuchMethod(Invocation.getter(#pictureCacheBytes), returnValue: 0) - as int); - @override - double get pictureCacheMegabytes => - (super.noSuchMethod(Invocation.getter(#pictureCacheMegabytes), - returnValue: 0.0) as double); - @override - int get frameNumber => - (super.noSuchMethod(Invocation.getter(#frameNumber), returnValue: 0) - as int); - @override - int timestampInMicroseconds(_i4.FramePhase? phase) => - (super.noSuchMethod(Invocation.method(#timestampInMicroseconds, [phase]), - returnValue: 0) as int); -} From ba40474453c826ed44ba3d720f9bbd908d13958f Mon Sep 17 00:00:00 2001 From: Andrew Amin Date: Tue, 5 Aug 2025 21:36:52 +0300 Subject: [PATCH 60/84] chore: run mockito of flutter 2.10.5 --- example/pubspec.lock | 189 ++--- .../instabug_screen_render_manager.dart | 7 +- .../instabug_screen_render_manager_test.dart | 7 +- ...abug_screen_render_manager_test_mocks.dart | 743 ++++++++++++++++++ 4 files changed, 825 insertions(+), 121 deletions(-) create mode 100644 test/utils/screen_render/instabug_screen_render_manager_test_mocks.dart diff --git a/example/pubspec.lock b/example/pubspec.lock index 1221be412..ed56bbe53 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -1,62 +1,76 @@ # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: + archive: + dependency: transitive + description: + name: archive + url: "https://pub.dartlang.org" + source: hosted + version: "3.1.6" async: dependency: transitive description: name: async - sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb" - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "2.13.0" + version: "2.8.2" boolean_selector: dependency: transitive description: name: boolean_selector - sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "2.1.2" + version: "2.1.0" characters: dependency: transitive description: name: characters - sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 - url: "https://pub.dev" + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.0" + charcode: + dependency: transitive + description: + name: charcode + url: "https://pub.dartlang.org" source: hosted - version: "1.4.0" + version: "1.3.1" clock: dependency: transitive description: name: clock - sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "1.1.2" + version: "1.1.0" collection: dependency: transitive description: name: collection - sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "1.19.1" + version: "1.15.0" + crypto: + dependency: transitive + description: + name: crypto + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.1" fake_async: dependency: transitive description: name: fake_async - sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "1.3.3" + version: "1.2.0" file: dependency: transitive description: name: file - sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "7.0.1" + version: "6.1.2" flutter: dependency: "direct main" description: flutter @@ -71,8 +85,7 @@ packages: dependency: "direct dev" description: name: flutter_lints - sha256: b543301ad291598523947dc534aaddc5aaad597b709d2426d3a0e0d44c5cb493 - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted version: "1.0.4" flutter_test: @@ -89,18 +102,16 @@ packages: dependency: "direct main" description: name: http - sha256: "5895291c13fa8a3bd82e76d5627f69e0d85ca6a30dcac95c4ea19a5d555879c2" - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "0.13.6" + version: "0.13.5" http_parser: dependency: transitive description: name: http_parser - sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571" - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "4.1.2" + version: "4.0.2" instabug_flutter: dependency: "direct main" description: @@ -112,183 +123,139 @@ packages: dependency: "direct main" description: name: instabug_http_client - sha256: a38bed979f549ffe85efa46c46ca743cbfab95a51295b60f143f249b71655231 - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted version: "2.6.0" - leak_tracker: - dependency: transitive - description: - name: leak_tracker - sha256: "6bb818ecbdffe216e81182c2f0714a2e62b593f4a4f13098713ff1685dfb6ab0" - url: "https://pub.dev" - source: hosted - version: "10.0.9" - leak_tracker_flutter_testing: - dependency: transitive - description: - name: leak_tracker_flutter_testing - sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573 - url: "https://pub.dev" - source: hosted - version: "3.0.9" - leak_tracker_testing: - dependency: transitive - description: - name: leak_tracker_testing - sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" - url: "https://pub.dev" - source: hosted - version: "3.0.1" lints: dependency: transitive description: name: lints - sha256: a2c3d198cb5ea2e179926622d433331d8b58374ab8f29cdda6e863bd62fd369c - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted version: "1.0.1" matcher: dependency: transitive description: name: matcher - sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "0.12.17" + version: "0.12.11" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "0.11.1" + version: "0.1.3" meta: dependency: transitive description: name: meta - sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "1.16.0" + version: "1.7.0" path: dependency: transitive description: name: path - sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "1.9.1" + version: "1.8.0" platform: dependency: transitive description: name: platform - sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984" - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "3.1.6" + version: "3.1.0" process: dependency: transitive description: name: process - sha256: "107d8be718f120bbba9dcd1e95e3bd325b1b4a4f07db64154635ba03f2567a0d" - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "5.0.3" + version: "4.2.4" sky_engine: dependency: transitive description: flutter source: sdk - version: "0.0.0" + version: "0.0.99" source_span: dependency: transitive description: name: source_span - sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c" - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "1.10.1" + version: "1.8.1" stack_trace: dependency: transitive description: name: stack_trace - sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "1.12.1" + version: "1.10.0" stream_channel: dependency: transitive description: name: stream_channel - sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "2.1.4" + version: "2.1.0" string_scanner: dependency: transitive description: name: string_scanner - sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "1.4.1" + version: "1.1.0" sync_http: dependency: transitive description: name: sync_http - sha256: "7f0cd72eca000d2e026bcd6f990b81d0ca06022ef4e32fb257b30d3d1014a961" - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "0.3.1" + version: "0.3.0" term_glyph: dependency: transitive description: name: term_glyph - sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "1.2.2" + version: "1.2.0" test_api: dependency: transitive description: name: test_api - sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "0.7.4" + version: "0.4.8" typed_data: dependency: transitive description: name: typed_data - sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "1.4.0" + version: "1.3.0" vector_math: dependency: transitive description: name: vector_math - sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "2.1.4" + version: "2.1.1" vm_service: dependency: transitive description: name: vm_service - sha256: ddfa8d30d89985b96407efce8acbdd124701f96741f2d981ca860662f1c0dc02 - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "15.0.0" + version: "7.5.0" webdriver: dependency: transitive description: name: webdriver - sha256: "2f3a14ca026957870cfd9c635b83507e0e51d8091568e90129fbf805aba7cade" - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "3.1.0" + version: "3.0.0" sdks: - dart: ">=3.7.0-0 <4.0.0" - flutter: ">=3.18.0-18.0.pre.54" + dart: ">=2.14.0 <3.0.0" diff --git a/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart b/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart index 7dd74ea16..3a9ff003d 100644 --- a/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart +++ b/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart @@ -150,7 +150,7 @@ class InstabugScreenRenderManager { //Save the memory cached data to be sent to native side if (_delayedFrames.isNotEmpty) { - saveCollectedData(); + _saveCollectedData(); _resetCachedFrameData(); } @@ -179,7 +179,7 @@ class InstabugScreenRenderManager { if (frameCollectorIsNotActive) return; if (_delayedFrames.isNotEmpty) { - saveCollectedData(); + _saveCollectedData(); _resetCachedFrameData(); } @@ -368,8 +368,7 @@ class InstabugScreenRenderManager { } /// Add the memory cashed data to the objects that will be synced asynchronously to the native side. - @visibleForTesting - void saveCollectedData() { + void _saveCollectedData() { if (_screenRenderForAutoUiTrace.isActive) { _updateAutoUiData(); } diff --git a/test/utils/screen_render/instabug_screen_render_manager_test.dart b/test/utils/screen_render/instabug_screen_render_manager_test.dart index 00e80da15..22a1a710f 100644 --- a/test/utils/screen_render/instabug_screen_render_manager_test.dart +++ b/test/utils/screen_render/instabug_screen_render_manager_test.dart @@ -1,17 +1,12 @@ -import 'package:flutter/scheduler.dart' show FrameTiming; -import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:instabug_flutter/instabug_flutter.dart'; -import 'package:instabug_flutter/src/generated/apm.api.g.dart'; import 'package:instabug_flutter/src/models/instabug_frame_data.dart'; import 'package:instabug_flutter/src/models/instabug_screen_render_data.dart'; import 'package:instabug_flutter/src/utils/screen_rendering/instabug_screen_render_manager.dart'; -import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; -import 'instabug_screen_render_manager_test.mocks.dart'; +import 'instabug_screen_render_manager_test_mocks.dart'; -@GenerateMocks([ApmHostApi, FrameTiming, WidgetsBinding]) void main() { TestWidgetsFlutterBinding.ensureInitialized(); diff --git a/test/utils/screen_render/instabug_screen_render_manager_test_mocks.dart b/test/utils/screen_render/instabug_screen_render_manager_test_mocks.dart new file mode 100644 index 000000000..5c2bba6c4 --- /dev/null +++ b/test/utils/screen_render/instabug_screen_render_manager_test_mocks.dart @@ -0,0 +1,743 @@ +// Mocks generated by Mockito 5.2.0 from annotations +// in instabug_flutter/example/ios/.symlinks/plugins/instabug_flutter/test/utils/screen_render/instabug_screen_render_manager_test.dart. +// Do not manually edit this file. + +import 'dart:async' as _i9; +import 'dart:developer' as _i13; +import 'dart:ui' as _i4; + +import 'package:flutter/foundation.dart' as _i3; +import 'package:flutter/gestures.dart' as _i6; +import 'package:flutter/rendering.dart' as _i7; +import 'package:flutter/scheduler.dart' as _i11; +import 'package:flutter/services.dart' as _i5; +import 'package:flutter/src/widgets/binding.dart' as _i10; +import 'package:flutter/src/widgets/focus_manager.dart' as _i2; +import 'package:flutter/src/widgets/framework.dart' as _i12; +import 'package:instabug_flutter/src/generated/apm.api.g.dart' as _i8; +import 'package:mockito/mockito.dart' as _i1; + +// ignore_for_file: type=lint +// ignore_for_file: avoid_redundant_argument_values +// ignore_for_file: avoid_setters_without_getters +// ignore_for_file: comment_references +// ignore_for_file: implementation_imports +// ignore_for_file: invalid_use_of_visible_for_testing_member +// ignore_for_file: prefer_const_constructors +// ignore_for_file: unnecessary_parenthesis +// ignore_for_file: camel_case_types + +class _FakeDuration_0 extends _i1.Fake implements Duration {} + +class _FakeFocusManager_1 extends _i1.Fake implements _i2.FocusManager { + @override + String toString({_i3.DiagnosticLevel? minLevel = _i3.DiagnosticLevel.info}) => + super.toString(); +} + +class _FakeSingletonFlutterWindow_2 extends _i1.Fake + implements _i4.SingletonFlutterWindow {} + +class _FakePlatformDispatcher_3 extends _i1.Fake + implements _i4.PlatformDispatcher {} + +class _FakeHardwareKeyboard_4 extends _i1.Fake implements _i5.HardwareKeyboard { +} + +class _FakeKeyEventManager_5 extends _i1.Fake implements _i5.KeyEventManager {} + +class _FakeBinaryMessenger_6 extends _i1.Fake implements _i5.BinaryMessenger {} + +class _FakeChannelBuffers_7 extends _i1.Fake implements _i4.ChannelBuffers {} + +class _FakeRestorationManager_8 extends _i1.Fake + implements _i5.RestorationManager {} + +class _FakePointerRouter_9 extends _i1.Fake implements _i6.PointerRouter {} + +class _FakeGestureArenaManager_10 extends _i1.Fake + implements _i6.GestureArenaManager {} + +class _FakePointerSignalResolver_11 extends _i1.Fake + implements _i6.PointerSignalResolver {} + +class _FakeMouseTracker_12 extends _i1.Fake implements _i7.MouseTracker {} + +class _FakePipelineOwner_13 extends _i1.Fake implements _i7.PipelineOwner {} + +class _FakeRenderView_14 extends _i1.Fake implements _i7.RenderView { + @override + String toString({_i3.DiagnosticLevel? minLevel = _i3.DiagnosticLevel.info}) => + super.toString(); +} + +class _FakeAccessibilityFeatures_15 extends _i1.Fake + implements _i4.AccessibilityFeatures {} + +class _FakeViewConfiguration_16 extends _i1.Fake + implements _i7.ViewConfiguration {} + +class _FakeSemanticsUpdateBuilder_17 extends _i1.Fake + implements _i4.SemanticsUpdateBuilder {} + +/// A class which mocks [ApmHostApi]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockApmHostApi extends _i1.Mock implements _i8.ApmHostApi { + MockApmHostApi() { + _i1.throwOnMissingStub(this); + } + + @override + _i9.Future setEnabled(bool? arg_isEnabled) => + (super.noSuchMethod(Invocation.method(#setEnabled, [arg_isEnabled]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future isEnabled() => + (super.noSuchMethod(Invocation.method(#isEnabled, []), + returnValue: Future.value(false)) as _i9.Future); + @override + _i9.Future setScreenLoadingEnabled(bool? arg_isEnabled) => + (super.noSuchMethod( + Invocation.method(#setScreenLoadingEnabled, [arg_isEnabled]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future isScreenLoadingEnabled() => + (super.noSuchMethod(Invocation.method(#isScreenLoadingEnabled, []), + returnValue: Future.value(false)) as _i9.Future); + @override + _i9.Future setColdAppLaunchEnabled(bool? arg_isEnabled) => + (super.noSuchMethod( + Invocation.method(#setColdAppLaunchEnabled, [arg_isEnabled]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future setAutoUITraceEnabled(bool? arg_isEnabled) => (super + .noSuchMethod(Invocation.method(#setAutoUITraceEnabled, [arg_isEnabled]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future startFlow(String? arg_name) => + (super.noSuchMethod(Invocation.method(#startFlow, [arg_name]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future setFlowAttribute( + String? arg_name, String? arg_key, String? arg_value) => + (super.noSuchMethod( + Invocation.method(#setFlowAttribute, [arg_name, arg_key, arg_value]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future endFlow(String? arg_name) => + (super.noSuchMethod(Invocation.method(#endFlow, [arg_name]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future startUITrace(String? arg_name) => + (super.noSuchMethod(Invocation.method(#startUITrace, [arg_name]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future endUITrace() => + (super.noSuchMethod(Invocation.method(#endUITrace, []), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future endAppLaunch() => + (super.noSuchMethod(Invocation.method(#endAppLaunch, []), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future networkLogAndroid(Map? arg_data) => + (super.noSuchMethod(Invocation.method(#networkLogAndroid, [arg_data]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future startCpUiTrace( + String? arg_screenName, int? arg_microTimeStamp, int? arg_traceId) => + (super.noSuchMethod( + Invocation.method(#startCpUiTrace, + [arg_screenName, arg_microTimeStamp, arg_traceId]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future reportScreenLoadingCP(int? arg_startTimeStampMicro, + int? arg_durationMicro, int? arg_uiTraceId) => + (super.noSuchMethod( + Invocation.method(#reportScreenLoadingCP, + [arg_startTimeStampMicro, arg_durationMicro, arg_uiTraceId]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future endScreenLoadingCP( + int? arg_timeStampMicro, int? arg_uiTraceId) => + (super.noSuchMethod( + Invocation.method( + #endScreenLoadingCP, [arg_timeStampMicro, arg_uiTraceId]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future isEndScreenLoadingEnabled() => + (super.noSuchMethod(Invocation.method(#isEndScreenLoadingEnabled, []), + returnValue: Future.value(false)) as _i9.Future); + @override + _i9.Future isScreenRenderEnabled() => + (super.noSuchMethod(Invocation.method(#isScreenRenderEnabled, []), + returnValue: Future.value(false)) as _i9.Future); + @override + _i9.Future> getDeviceRefreshRateAndTolerance() => + (super.noSuchMethod( + Invocation.method(#getDeviceRefreshRateAndTolerance, []), + returnValue: Future>.value([])) + as _i9.Future>); + @override + _i9.Future setScreenRenderEnabled(bool? arg_isEnabled) => (super + .noSuchMethod(Invocation.method(#setScreenRenderEnabled, [arg_isEnabled]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future endScreenRenderForAutoUiTrace( + Map? arg_data) => + (super.noSuchMethod( + Invocation.method(#endScreenRenderForAutoUiTrace, [arg_data]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future endScreenRenderForCustomUiTrace( + Map? arg_data) => + (super.noSuchMethod( + Invocation.method(#endScreenRenderForCustomUiTrace, [arg_data]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); +} + +/// A class which mocks [FrameTiming]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockFrameTiming extends _i1.Mock implements _i4.FrameTiming { + MockFrameTiming() { + _i1.throwOnMissingStub(this); + } + + @override + Duration get buildDuration => + (super.noSuchMethod(Invocation.getter(#buildDuration), + returnValue: _FakeDuration_0()) as Duration); + @override + Duration get rasterDuration => + (super.noSuchMethod(Invocation.getter(#rasterDuration), + returnValue: _FakeDuration_0()) as Duration); + @override + Duration get vsyncOverhead => + (super.noSuchMethod(Invocation.getter(#vsyncOverhead), + returnValue: _FakeDuration_0()) as Duration); + @override + Duration get totalSpan => (super.noSuchMethod(Invocation.getter(#totalSpan), + returnValue: _FakeDuration_0()) as Duration); + @override + int get layerCacheCount => + (super.noSuchMethod(Invocation.getter(#layerCacheCount), returnValue: 0) + as int); + @override + int get layerCacheBytes => + (super.noSuchMethod(Invocation.getter(#layerCacheBytes), returnValue: 0) + as int); + @override + double get layerCacheMegabytes => + (super.noSuchMethod(Invocation.getter(#layerCacheMegabytes), + returnValue: 0.0) as double); + @override + int get pictureCacheCount => + (super.noSuchMethod(Invocation.getter(#pictureCacheCount), returnValue: 0) + as int); + @override + int get pictureCacheBytes => + (super.noSuchMethod(Invocation.getter(#pictureCacheBytes), returnValue: 0) + as int); + @override + double get pictureCacheMegabytes => + (super.noSuchMethod(Invocation.getter(#pictureCacheMegabytes), + returnValue: 0.0) as double); + @override + int get frameNumber => + (super.noSuchMethod(Invocation.getter(#frameNumber), returnValue: 0) + as int); + @override + int timestampInMicroseconds(_i4.FramePhase? phase) => + (super.noSuchMethod(Invocation.method(#timestampInMicroseconds, [phase]), + returnValue: 0) as int); +} + +/// A class which mocks [WidgetsBinding]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockWidgetsBinding extends _i1.Mock implements _i10.WidgetsBinding { + MockWidgetsBinding() { + _i1.throwOnMissingStub(this); + } + + @override + bool get debugBuildingDirtyElements => + (super.noSuchMethod(Invocation.getter(#debugBuildingDirtyElements), + returnValue: false) as bool); + @override + set debugBuildingDirtyElements(bool? _debugBuildingDirtyElements) => + super.noSuchMethod( + Invocation.setter( + #debugBuildingDirtyElements, _debugBuildingDirtyElements), + returnValueForMissingStub: null); + @override + _i2.FocusManager get focusManager => + (super.noSuchMethod(Invocation.getter(#focusManager), + returnValue: _FakeFocusManager_1()) as _i2.FocusManager); + @override + bool get firstFrameRasterized => + (super.noSuchMethod(Invocation.getter(#firstFrameRasterized), + returnValue: false) as bool); + @override + _i9.Future get waitUntilFirstFrameRasterized => + (super.noSuchMethod(Invocation.getter(#waitUntilFirstFrameRasterized), + returnValue: Future.value()) as _i9.Future); + @override + bool get debugDidSendFirstFrameEvent => + (super.noSuchMethod(Invocation.getter(#debugDidSendFirstFrameEvent), + returnValue: false) as bool); + @override + bool get framesEnabled => + (super.noSuchMethod(Invocation.getter(#framesEnabled), returnValue: false) + as bool); + @override + bool get isRootWidgetAttached => + (super.noSuchMethod(Invocation.getter(#isRootWidgetAttached), + returnValue: false) as bool); + @override + _i4.SingletonFlutterWindow get window => + (super.noSuchMethod(Invocation.getter(#window), + returnValue: _FakeSingletonFlutterWindow_2()) + as _i4.SingletonFlutterWindow); + @override + _i4.PlatformDispatcher get platformDispatcher => + (super.noSuchMethod(Invocation.getter(#platformDispatcher), + returnValue: _FakePlatformDispatcher_3()) as _i4.PlatformDispatcher); + @override + bool get locked => + (super.noSuchMethod(Invocation.getter(#locked), returnValue: false) + as bool); + @override + _i5.HardwareKeyboard get keyboard => + (super.noSuchMethod(Invocation.getter(#keyboard), + returnValue: _FakeHardwareKeyboard_4()) as _i5.HardwareKeyboard); + @override + _i5.KeyEventManager get keyEventManager => + (super.noSuchMethod(Invocation.getter(#keyEventManager), + returnValue: _FakeKeyEventManager_5()) as _i5.KeyEventManager); + @override + _i5.BinaryMessenger get defaultBinaryMessenger => + (super.noSuchMethod(Invocation.getter(#defaultBinaryMessenger), + returnValue: _FakeBinaryMessenger_6()) as _i5.BinaryMessenger); + @override + _i4.ChannelBuffers get channelBuffers => + (super.noSuchMethod(Invocation.getter(#channelBuffers), + returnValue: _FakeChannelBuffers_7()) as _i4.ChannelBuffers); + @override + _i5.RestorationManager get restorationManager => + (super.noSuchMethod(Invocation.getter(#restorationManager), + returnValue: _FakeRestorationManager_8()) as _i5.RestorationManager); + @override + _i11.SchedulingStrategy get schedulingStrategy => + (super.noSuchMethod(Invocation.getter(#schedulingStrategy), + returnValue: ({int? priority, _i11.SchedulerBinding? scheduler}) => + false) as _i11.SchedulingStrategy); + @override + set schedulingStrategy(_i11.SchedulingStrategy? _schedulingStrategy) => super + .noSuchMethod(Invocation.setter(#schedulingStrategy, _schedulingStrategy), + returnValueForMissingStub: null); + @override + int get transientCallbackCount => + (super.noSuchMethod(Invocation.getter(#transientCallbackCount), + returnValue: 0) as int); + @override + _i9.Future get endOfFrame => + (super.noSuchMethod(Invocation.getter(#endOfFrame), + returnValue: Future.value()) as _i9.Future); + @override + bool get hasScheduledFrame => + (super.noSuchMethod(Invocation.getter(#hasScheduledFrame), + returnValue: false) as bool); + @override + _i11.SchedulerPhase get schedulerPhase => + (super.noSuchMethod(Invocation.getter(#schedulerPhase), + returnValue: _i11.SchedulerPhase.idle) as _i11.SchedulerPhase); + @override + Duration get currentFrameTimeStamp => + (super.noSuchMethod(Invocation.getter(#currentFrameTimeStamp), + returnValue: _FakeDuration_0()) as Duration); + @override + Duration get currentSystemFrameTimeStamp => + (super.noSuchMethod(Invocation.getter(#currentSystemFrameTimeStamp), + returnValue: _FakeDuration_0()) as Duration); + @override + _i6.PointerRouter get pointerRouter => + (super.noSuchMethod(Invocation.getter(#pointerRouter), + returnValue: _FakePointerRouter_9()) as _i6.PointerRouter); + @override + _i6.GestureArenaManager get gestureArena => (super.noSuchMethod( + Invocation.getter(#gestureArena), + returnValue: _FakeGestureArenaManager_10()) as _i6.GestureArenaManager); + @override + _i6.PointerSignalResolver get pointerSignalResolver => + (super.noSuchMethod(Invocation.getter(#pointerSignalResolver), + returnValue: _FakePointerSignalResolver_11()) + as _i6.PointerSignalResolver); + @override + bool get resamplingEnabled => + (super.noSuchMethod(Invocation.getter(#resamplingEnabled), + returnValue: false) as bool); + @override + set resamplingEnabled(bool? _resamplingEnabled) => super.noSuchMethod( + Invocation.setter(#resamplingEnabled, _resamplingEnabled), + returnValueForMissingStub: null); + @override + Duration get samplingOffset => + (super.noSuchMethod(Invocation.getter(#samplingOffset), + returnValue: _FakeDuration_0()) as Duration); + @override + set samplingOffset(Duration? _samplingOffset) => + super.noSuchMethod(Invocation.setter(#samplingOffset, _samplingOffset), + returnValueForMissingStub: null); + @override + _i7.MouseTracker get mouseTracker => + (super.noSuchMethod(Invocation.getter(#mouseTracker), + returnValue: _FakeMouseTracker_12()) as _i7.MouseTracker); + @override + _i7.PipelineOwner get pipelineOwner => + (super.noSuchMethod(Invocation.getter(#pipelineOwner), + returnValue: _FakePipelineOwner_13()) as _i7.PipelineOwner); + @override + _i7.RenderView get renderView => + (super.noSuchMethod(Invocation.getter(#renderView), + returnValue: _FakeRenderView_14()) as _i7.RenderView); + @override + set renderView(_i7.RenderView? value) => + super.noSuchMethod(Invocation.setter(#renderView, value), + returnValueForMissingStub: null); + @override + bool get sendFramesToEngine => + (super.noSuchMethod(Invocation.getter(#sendFramesToEngine), + returnValue: false) as bool); + @override + _i4.AccessibilityFeatures get accessibilityFeatures => + (super.noSuchMethod(Invocation.getter(#accessibilityFeatures), + returnValue: _FakeAccessibilityFeatures_15()) + as _i4.AccessibilityFeatures); + @override + bool get disableAnimations => + (super.noSuchMethod(Invocation.getter(#disableAnimations), + returnValue: false) as bool); + @override + void initInstances() => + super.noSuchMethod(Invocation.method(#initInstances, []), + returnValueForMissingStub: null); + @override + void initServiceExtensions() => + super.noSuchMethod(Invocation.method(#initServiceExtensions, []), + returnValueForMissingStub: null); + @override + void addObserver(_i10.WidgetsBindingObserver? observer) => + super.noSuchMethod(Invocation.method(#addObserver, [observer]), + returnValueForMissingStub: null); + @override + bool removeObserver(_i10.WidgetsBindingObserver? observer) => + (super.noSuchMethod(Invocation.method(#removeObserver, [observer]), + returnValue: false) as bool); + @override + void handleMetricsChanged() => + super.noSuchMethod(Invocation.method(#handleMetricsChanged, []), + returnValueForMissingStub: null); + @override + void handleTextScaleFactorChanged() => + super.noSuchMethod(Invocation.method(#handleTextScaleFactorChanged, []), + returnValueForMissingStub: null); + @override + void handlePlatformBrightnessChanged() => super.noSuchMethod( + Invocation.method(#handlePlatformBrightnessChanged, []), + returnValueForMissingStub: null); + @override + void handleAccessibilityFeaturesChanged() => super.noSuchMethod( + Invocation.method(#handleAccessibilityFeaturesChanged, []), + returnValueForMissingStub: null); + @override + void handleLocaleChanged() => + super.noSuchMethod(Invocation.method(#handleLocaleChanged, []), + returnValueForMissingStub: null); + @override + void dispatchLocalesChanged(List<_i4.Locale>? locales) => + super.noSuchMethod(Invocation.method(#dispatchLocalesChanged, [locales]), + returnValueForMissingStub: null); + @override + void dispatchAccessibilityFeaturesChanged() => super.noSuchMethod( + Invocation.method(#dispatchAccessibilityFeaturesChanged, []), + returnValueForMissingStub: null); + @override + _i9.Future handlePopRoute() => + (super.noSuchMethod(Invocation.method(#handlePopRoute, []), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future handlePushRoute(String? route) => + (super.noSuchMethod(Invocation.method(#handlePushRoute, [route]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + void handleAppLifecycleStateChanged(_i4.AppLifecycleState? state) => super + .noSuchMethod(Invocation.method(#handleAppLifecycleStateChanged, [state]), + returnValueForMissingStub: null); + @override + void handleMemoryPressure() => + super.noSuchMethod(Invocation.method(#handleMemoryPressure, []), + returnValueForMissingStub: null); + @override + void drawFrame() => super.noSuchMethod(Invocation.method(#drawFrame, []), + returnValueForMissingStub: null); + @override + void scheduleAttachRootWidget(_i12.Widget? rootWidget) => super.noSuchMethod( + Invocation.method(#scheduleAttachRootWidget, [rootWidget]), + returnValueForMissingStub: null); + @override + void attachRootWidget(_i12.Widget? rootWidget) => + super.noSuchMethod(Invocation.method(#attachRootWidget, [rootWidget]), + returnValueForMissingStub: null); + @override + _i9.Future performReassemble() => + (super.noSuchMethod(Invocation.method(#performReassemble, []), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i4.Locale? computePlatformResolvedLocale( + List<_i4.Locale>? supportedLocales) => + (super.noSuchMethod(Invocation.method( + #computePlatformResolvedLocale, [supportedLocales])) as _i4.Locale?); + @override + _i9.Future lockEvents(_i9.Future Function()? callback) => + (super.noSuchMethod(Invocation.method(#lockEvents, [callback]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + void unlocked() => super.noSuchMethod(Invocation.method(#unlocked, []), + returnValueForMissingStub: null); + @override + _i9.Future reassembleApplication() => + (super.noSuchMethod(Invocation.method(#reassembleApplication, []), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + void registerSignalServiceExtension( + {String? name, _i3.AsyncCallback? callback}) => + super.noSuchMethod( + Invocation.method(#registerSignalServiceExtension, [], + {#name: name, #callback: callback}), + returnValueForMissingStub: null); + @override + void registerBoolServiceExtension( + {String? name, + _i3.AsyncValueGetter? getter, + _i3.AsyncValueSetter? setter}) => + super.noSuchMethod( + Invocation.method(#registerBoolServiceExtension, [], + {#name: name, #getter: getter, #setter: setter}), + returnValueForMissingStub: null); + @override + void registerNumericServiceExtension( + {String? name, + _i3.AsyncValueGetter? getter, + _i3.AsyncValueSetter? setter}) => + super.noSuchMethod( + Invocation.method(#registerNumericServiceExtension, [], + {#name: name, #getter: getter, #setter: setter}), + returnValueForMissingStub: null); + @override + void postEvent(String? eventKind, Map? eventData) => + super.noSuchMethod(Invocation.method(#postEvent, [eventKind, eventData]), + returnValueForMissingStub: null); + @override + void registerStringServiceExtension( + {String? name, + _i3.AsyncValueGetter? getter, + _i3.AsyncValueSetter? setter}) => + super.noSuchMethod( + Invocation.method(#registerStringServiceExtension, [], + {#name: name, #getter: getter, #setter: setter}), + returnValueForMissingStub: null); + @override + void registerServiceExtension( + {String? name, _i3.ServiceExtensionCallback? callback}) => + super.noSuchMethod( + Invocation.method(#registerServiceExtension, [], + {#name: name, #callback: callback}), + returnValueForMissingStub: null); + @override + _i5.BinaryMessenger createBinaryMessenger() => + (super.noSuchMethod(Invocation.method(#createBinaryMessenger, []), + returnValue: _FakeBinaryMessenger_6()) as _i5.BinaryMessenger); + @override + _i9.Future handleSystemMessage(Object? systemMessage) => (super + .noSuchMethod(Invocation.method(#handleSystemMessage, [systemMessage]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + void initLicenses() => + super.noSuchMethod(Invocation.method(#initLicenses, []), + returnValueForMissingStub: null); + @override + void evict(String? asset) => + super.noSuchMethod(Invocation.method(#evict, [asset]), + returnValueForMissingStub: null); + @override + void readInitialLifecycleStateFromNativeWindow() => super.noSuchMethod( + Invocation.method(#readInitialLifecycleStateFromNativeWindow, []), + returnValueForMissingStub: null); + @override + _i5.RestorationManager createRestorationManager() => + (super.noSuchMethod(Invocation.method(#createRestorationManager, []), + returnValue: _FakeRestorationManager_8()) as _i5.RestorationManager); + @override + void setSystemUiChangeCallback(_i5.SystemUiChangeCallback? callback) => super + .noSuchMethod(Invocation.method(#setSystemUiChangeCallback, [callback]), + returnValueForMissingStub: null); + @override + void addTimingsCallback(_i4.TimingsCallback? callback) => + super.noSuchMethod(Invocation.method(#addTimingsCallback, [callback]), + returnValueForMissingStub: null); + @override + void removeTimingsCallback(_i4.TimingsCallback? callback) => + super.noSuchMethod(Invocation.method(#removeTimingsCallback, [callback]), + returnValueForMissingStub: null); + @override + _i9.Future scheduleTask( + _i11.TaskCallback? task, _i11.Priority? priority, + {String? debugLabel, _i13.Flow? flow}) => + (super.noSuchMethod( + Invocation.method(#scheduleTask, [task, priority], + {#debugLabel: debugLabel, #flow: flow}), + returnValue: Future.value(null)) as _i9.Future); + @override + bool handleEventLoopCallback() => + (super.noSuchMethod(Invocation.method(#handleEventLoopCallback, []), + returnValue: false) as bool); + @override + int scheduleFrameCallback(_i11.FrameCallback? callback, + {bool? rescheduling = false}) => + (super.noSuchMethod( + Invocation.method(#scheduleFrameCallback, [callback], + {#rescheduling: rescheduling}), + returnValue: 0) as int); + @override + void cancelFrameCallbackWithId(int? id) => + super.noSuchMethod(Invocation.method(#cancelFrameCallbackWithId, [id]), + returnValueForMissingStub: null); + @override + bool debugAssertNoTransientCallbacks(String? reason) => (super.noSuchMethod( + Invocation.method(#debugAssertNoTransientCallbacks, [reason]), + returnValue: false) as bool); + @override + void addPersistentFrameCallback(_i11.FrameCallback? callback) => super + .noSuchMethod(Invocation.method(#addPersistentFrameCallback, [callback]), + returnValueForMissingStub: null); + @override + void addPostFrameCallback(_i11.FrameCallback? callback) => + super.noSuchMethod(Invocation.method(#addPostFrameCallback, [callback]), + returnValueForMissingStub: null); + @override + void ensureFrameCallbacksRegistered() => + super.noSuchMethod(Invocation.method(#ensureFrameCallbacksRegistered, []), + returnValueForMissingStub: null); + @override + void ensureVisualUpdate() => + super.noSuchMethod(Invocation.method(#ensureVisualUpdate, []), + returnValueForMissingStub: null); + @override + void scheduleFrame() => + super.noSuchMethod(Invocation.method(#scheduleFrame, []), + returnValueForMissingStub: null); + @override + void scheduleForcedFrame() => + super.noSuchMethod(Invocation.method(#scheduleForcedFrame, []), + returnValueForMissingStub: null); + @override + void scheduleWarmUpFrame() => + super.noSuchMethod(Invocation.method(#scheduleWarmUpFrame, []), + returnValueForMissingStub: null); + @override + void resetEpoch() => super.noSuchMethod(Invocation.method(#resetEpoch, []), + returnValueForMissingStub: null); + @override + void handleBeginFrame(Duration? rawTimeStamp) => + super.noSuchMethod(Invocation.method(#handleBeginFrame, [rawTimeStamp]), + returnValueForMissingStub: null); + @override + void handleDrawFrame() => + super.noSuchMethod(Invocation.method(#handleDrawFrame, []), + returnValueForMissingStub: null); + @override + void cancelPointer(int? pointer) => + super.noSuchMethod(Invocation.method(#cancelPointer, [pointer]), + returnValueForMissingStub: null); + @override + void handlePointerEvent(_i6.PointerEvent? event) => + super.noSuchMethod(Invocation.method(#handlePointerEvent, [event]), + returnValueForMissingStub: null); + @override + void hitTest(_i6.HitTestResult? result, _i4.Offset? position) => + super.noSuchMethod(Invocation.method(#hitTest, [result, position]), + returnValueForMissingStub: null); + @override + void dispatchEvent( + _i6.PointerEvent? event, _i6.HitTestResult? hitTestResult) => + super.noSuchMethod( + Invocation.method(#dispatchEvent, [event, hitTestResult]), + returnValueForMissingStub: null); + @override + void handleEvent(_i6.PointerEvent? event, _i6.HitTestEntry? entry) => + super.noSuchMethod(Invocation.method(#handleEvent, [event, entry]), + returnValueForMissingStub: null); + @override + void resetGestureBinding() => + super.noSuchMethod(Invocation.method(#resetGestureBinding, []), + returnValueForMissingStub: null); + @override + void initRenderView() => + super.noSuchMethod(Invocation.method(#initRenderView, []), + returnValueForMissingStub: null); + @override + _i7.ViewConfiguration createViewConfiguration() => + (super.noSuchMethod(Invocation.method(#createViewConfiguration, []), + returnValue: _FakeViewConfiguration_16()) as _i7.ViewConfiguration); + @override + void initMouseTracker([_i7.MouseTracker? tracker]) => + super.noSuchMethod(Invocation.method(#initMouseTracker, [tracker]), + returnValueForMissingStub: null); + @override + void setSemanticsEnabled(bool? enabled) => + super.noSuchMethod(Invocation.method(#setSemanticsEnabled, [enabled]), + returnValueForMissingStub: null); + @override + void deferFirstFrame() => + super.noSuchMethod(Invocation.method(#deferFirstFrame, []), + returnValueForMissingStub: null); + @override + void allowFirstFrame() => + super.noSuchMethod(Invocation.method(#allowFirstFrame, []), + returnValueForMissingStub: null); + @override + void resetFirstFrameSent() => + super.noSuchMethod(Invocation.method(#resetFirstFrameSent, []), + returnValueForMissingStub: null); + @override + _i4.SemanticsUpdateBuilder createSemanticsUpdateBuilder() => + (super.noSuchMethod(Invocation.method(#createSemanticsUpdateBuilder, []), + returnValue: _FakeSemanticsUpdateBuilder_17()) + as _i4.SemanticsUpdateBuilder); +} From bfac8cd96df6a847d971a73dd716913074ee9b29 Mon Sep 17 00:00:00 2001 From: ahmed alaa <154802748+ahmedAlaaInstabug@users.noreply.github.com> Date: Wed, 6 Aug 2025 12:03:55 +0300 Subject: [PATCH 61/84] fix: format --- .../instabug_screen_render_manager_test_mocks.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/utils/screen_render/instabug_screen_render_manager_test_mocks.dart b/test/utils/screen_render/instabug_screen_render_manager_test_mocks.dart index 5c2bba6c4..856450dd4 100644 --- a/test/utils/screen_render/instabug_screen_render_manager_test_mocks.dart +++ b/test/utils/screen_render/instabug_screen_render_manager_test_mocks.dart @@ -41,8 +41,8 @@ class _FakeSingletonFlutterWindow_2 extends _i1.Fake class _FakePlatformDispatcher_3 extends _i1.Fake implements _i4.PlatformDispatcher {} -class _FakeHardwareKeyboard_4 extends _i1.Fake implements _i5.HardwareKeyboard { -} +class _FakeHardwareKeyboard_4 extends _i1.Fake + implements _i5.HardwareKeyboard {} class _FakeKeyEventManager_5 extends _i1.Fake implements _i5.KeyEventManager {} From cfc0c01aef988f33a3ebf5a51dcb1798469ae26d Mon Sep 17 00:00:00 2001 From: Andrew Amin Date: Sun, 10 Aug 2025 18:09:20 +0300 Subject: [PATCH 62/84] chore: update android dependency --- android/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/build.gradle b/android/build.gradle index 32428f00e..9f27f88e1 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -52,7 +52,7 @@ android { } dependencies { - api 'com.instabug.library:instabug:15.0.2.7046628-SNAPSHOT' + api 'com.instabug.library:instabug:15.0.2.7085294-SNAPSHOT' testImplementation 'junit:junit:4.13.2' testImplementation "org.mockito:mockito-inline:3.12.1" testImplementation "io.mockk:mockk:1.13.13" From db428b4d7fc3ad9483fca1e90c1d6d2b04833335 Mon Sep 17 00:00:00 2001 From: Andrew Amin Date: Tue, 12 Aug 2025 14:39:25 +0300 Subject: [PATCH 63/84] chore: add report nonfatal beside exception logs --- example/ios/Runner.xcodeproj/project.pbxproj | 8 +- example/pubspec.lock | 189 +++-- lib/src/modules/apm.dart | 2 + .../instabug_screen_render_manager.dart | 114 ++- .../instabug_screen_render_manager_test.dart | 208 ++++- ...abug_screen_render_manager_test_mocks.dart | 743 ------------------ 6 files changed, 347 insertions(+), 917 deletions(-) delete mode 100644 test/utils/screen_render/instabug_screen_render_manager_test_mocks.dart diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj index d32f983fc..548562ea4 100644 --- a/example/ios/Runner.xcodeproj/project.pbxproj +++ b/example/ios/Runner.xcodeproj/project.pbxproj @@ -389,7 +389,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build\n"; }; A19F33D3063ED99B3A6581AC /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; @@ -559,7 +559,7 @@ "$(PROJECT_DIR)/Flutter", ); INFOPLIST_FILE = Runner/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 15.6; + IPHONEOS_DEPLOYMENT_TARGET = 14.4; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -697,7 +697,7 @@ "$(PROJECT_DIR)/Flutter", ); INFOPLIST_FILE = Runner/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 15.6; + IPHONEOS_DEPLOYMENT_TARGET = 14.4; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -729,7 +729,7 @@ "$(PROJECT_DIR)/Flutter", ); INFOPLIST_FILE = Runner/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 15.6; + IPHONEOS_DEPLOYMENT_TARGET = 14.4; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", diff --git a/example/pubspec.lock b/example/pubspec.lock index ed56bbe53..1221be412 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -1,76 +1,62 @@ # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: - archive: - dependency: transitive - description: - name: archive - url: "https://pub.dartlang.org" - source: hosted - version: "3.1.6" async: dependency: transitive description: name: async - url: "https://pub.dartlang.org" + sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb" + url: "https://pub.dev" source: hosted - version: "2.8.2" + version: "2.13.0" boolean_selector: dependency: transitive description: name: boolean_selector - url: "https://pub.dartlang.org" + sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.2" characters: dependency: transitive description: name: characters - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.0" - charcode: - dependency: transitive - description: - name: charcode - url: "https://pub.dartlang.org" + sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 + url: "https://pub.dev" source: hosted - version: "1.3.1" + version: "1.4.0" clock: dependency: transitive description: name: clock - url: "https://pub.dartlang.org" + sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b + url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.1.2" collection: dependency: transitive description: name: collection - url: "https://pub.dartlang.org" + sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" + url: "https://pub.dev" source: hosted - version: "1.15.0" - crypto: - dependency: transitive - description: - name: crypto - url: "https://pub.dartlang.org" - source: hosted - version: "3.0.1" + version: "1.19.1" fake_async: dependency: transitive description: name: fake_async - url: "https://pub.dartlang.org" + sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" + url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.3.3" file: dependency: transitive description: name: file - url: "https://pub.dartlang.org" + sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 + url: "https://pub.dev" source: hosted - version: "6.1.2" + version: "7.0.1" flutter: dependency: "direct main" description: flutter @@ -85,7 +71,8 @@ packages: dependency: "direct dev" description: name: flutter_lints - url: "https://pub.dartlang.org" + sha256: b543301ad291598523947dc534aaddc5aaad597b709d2426d3a0e0d44c5cb493 + url: "https://pub.dev" source: hosted version: "1.0.4" flutter_test: @@ -102,16 +89,18 @@ packages: dependency: "direct main" description: name: http - url: "https://pub.dartlang.org" + sha256: "5895291c13fa8a3bd82e76d5627f69e0d85ca6a30dcac95c4ea19a5d555879c2" + url: "https://pub.dev" source: hosted - version: "0.13.5" + version: "0.13.6" http_parser: dependency: transitive description: name: http_parser - url: "https://pub.dartlang.org" + sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571" + url: "https://pub.dev" source: hosted - version: "4.0.2" + version: "4.1.2" instabug_flutter: dependency: "direct main" description: @@ -123,139 +112,183 @@ packages: dependency: "direct main" description: name: instabug_http_client - url: "https://pub.dartlang.org" + sha256: a38bed979f549ffe85efa46c46ca743cbfab95a51295b60f143f249b71655231 + url: "https://pub.dev" source: hosted version: "2.6.0" + leak_tracker: + dependency: transitive + description: + name: leak_tracker + sha256: "6bb818ecbdffe216e81182c2f0714a2e62b593f4a4f13098713ff1685dfb6ab0" + url: "https://pub.dev" + source: hosted + version: "10.0.9" + leak_tracker_flutter_testing: + dependency: transitive + description: + name: leak_tracker_flutter_testing + sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573 + url: "https://pub.dev" + source: hosted + version: "3.0.9" + leak_tracker_testing: + dependency: transitive + description: + name: leak_tracker_testing + sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" + url: "https://pub.dev" + source: hosted + version: "3.0.1" lints: dependency: transitive description: name: lints - url: "https://pub.dartlang.org" + sha256: a2c3d198cb5ea2e179926622d433331d8b58374ab8f29cdda6e863bd62fd369c + url: "https://pub.dev" source: hosted version: "1.0.1" matcher: dependency: transitive description: name: matcher - url: "https://pub.dartlang.org" + sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 + url: "https://pub.dev" source: hosted - version: "0.12.11" + version: "0.12.17" material_color_utilities: dependency: transitive description: name: material_color_utilities - url: "https://pub.dartlang.org" + sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec + url: "https://pub.dev" source: hosted - version: "0.1.3" + version: "0.11.1" meta: dependency: transitive description: name: meta - url: "https://pub.dartlang.org" + sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c + url: "https://pub.dev" source: hosted - version: "1.7.0" + version: "1.16.0" path: dependency: transitive description: name: path - url: "https://pub.dartlang.org" + sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" + url: "https://pub.dev" source: hosted - version: "1.8.0" + version: "1.9.1" platform: dependency: transitive description: name: platform - url: "https://pub.dartlang.org" + sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984" + url: "https://pub.dev" source: hosted - version: "3.1.0" + version: "3.1.6" process: dependency: transitive description: name: process - url: "https://pub.dartlang.org" + sha256: "107d8be718f120bbba9dcd1e95e3bd325b1b4a4f07db64154635ba03f2567a0d" + url: "https://pub.dev" source: hosted - version: "4.2.4" + version: "5.0.3" sky_engine: dependency: transitive description: flutter source: sdk - version: "0.0.99" + version: "0.0.0" source_span: dependency: transitive description: name: source_span - url: "https://pub.dartlang.org" + sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c" + url: "https://pub.dev" source: hosted - version: "1.8.1" + version: "1.10.1" stack_trace: dependency: transitive description: name: stack_trace - url: "https://pub.dartlang.org" + sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" + url: "https://pub.dev" source: hosted - version: "1.10.0" + version: "1.12.1" stream_channel: dependency: transitive description: name: stream_channel - url: "https://pub.dartlang.org" + sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.4" string_scanner: dependency: transitive description: name: string_scanner - url: "https://pub.dartlang.org" + sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" + url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.4.1" sync_http: dependency: transitive description: name: sync_http - url: "https://pub.dartlang.org" + sha256: "7f0cd72eca000d2e026bcd6f990b81d0ca06022ef4e32fb257b30d3d1014a961" + url: "https://pub.dev" source: hosted - version: "0.3.0" + version: "0.3.1" term_glyph: dependency: transitive description: name: term_glyph - url: "https://pub.dartlang.org" + sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" + url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.2.2" test_api: dependency: transitive description: name: test_api - url: "https://pub.dartlang.org" + sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd + url: "https://pub.dev" source: hosted - version: "0.4.8" + version: "0.7.4" typed_data: dependency: transitive description: name: typed_data - url: "https://pub.dartlang.org" + sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 + url: "https://pub.dev" source: hosted - version: "1.3.0" + version: "1.4.0" vector_math: dependency: transitive description: name: vector_math - url: "https://pub.dartlang.org" + sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.4" vm_service: dependency: transitive description: name: vm_service - url: "https://pub.dartlang.org" + sha256: ddfa8d30d89985b96407efce8acbdd124701f96741f2d981ca860662f1c0dc02 + url: "https://pub.dev" source: hosted - version: "7.5.0" + version: "15.0.0" webdriver: dependency: transitive description: name: webdriver - url: "https://pub.dartlang.org" + sha256: "2f3a14ca026957870cfd9c635b83507e0e51d8091568e90129fbf805aba7cade" + url: "https://pub.dev" source: hosted - version: "3.0.0" + version: "3.1.0" sdks: - dart: ">=2.14.0 <3.0.0" + dart: ">=3.7.0-0 <4.0.0" + flutter: ">=3.18.0-18.0.pre.54" diff --git a/lib/src/modules/apm.dart b/lib/src/modules/apm.dart index 09b69ed68..31936e870 100644 --- a/lib/src/modules/apm.dart +++ b/lib/src/modules/apm.dart @@ -365,6 +365,7 @@ class APM { /// /// Returns: /// A `Future` is being returned. + @internal static Future endScreenRenderForAutoUiTrace( InstabugScreenRenderData data, ) { @@ -381,6 +382,7 @@ class APM { /// /// Returns: /// A `Future` is being returned. + @internal static Future endScreenRenderForCustomUiTrace( InstabugScreenRenderData data, ) { diff --git a/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart b/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart index 3a9ff003d..5bff74279 100644 --- a/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart +++ b/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart @@ -3,6 +3,7 @@ import 'dart:developer' show log; import 'dart:ui' show TimingsCallback, FrameTiming, FramePhase; import 'package:flutter/widgets.dart'; +import 'package:instabug_flutter/instabug_flutter.dart' show CrashReporting; import 'package:instabug_flutter/src/models/instabug_frame_data.dart'; import 'package:instabug_flutter/src/models/instabug_screen_render_data.dart'; import 'package:instabug_flutter/src/modules/apm.dart'; @@ -123,19 +124,15 @@ class InstabugScreenRenderManager { int traceId, [ UiTraceType type = UiTraceType.auto, ]) { - try { - // Return if frameTimingListener not attached - if (frameCollectorIsNotActive) return; + // Return if frameTimingListener not attached + if (frameCollectorIsNotActive) return; - if (type == UiTraceType.custom) { - _screenRenderForCustomUiTrace.traceId = traceId; - } + if (type == UiTraceType.custom) { + _screenRenderForCustomUiTrace.traceId = traceId; + } - if (type == UiTraceType.auto) { - _screenRenderForAutoUiTrace.traceId = traceId; - } - } catch (error, stackTrace) { - _logExceptionErrorAndStackTrace(error, stackTrace); + if (type == UiTraceType.auto) { + _screenRenderForAutoUiTrace.traceId = traceId; } } @@ -143,59 +140,49 @@ class InstabugScreenRenderManager { void endScreenRenderCollector([ UiTraceType type = UiTraceType.auto, ]) { - try { - // Return if frameTimingListener not attached - // log("frameCollectorIsNotActive $frameCollectorIsNotActive"); - if (frameCollectorIsNotActive) return; - - //Save the memory cached data to be sent to native side - if (_delayedFrames.isNotEmpty) { - _saveCollectedData(); - _resetCachedFrameData(); - } + // Return if frameTimingListener not attached + if (frameCollectorIsNotActive) return; - //Sync the captured screen render data of the Custom UI trace if the collector was active - if (type == UiTraceType.custom && - _screenRenderForCustomUiTrace.isActive) { - _reportScreenRenderForCustomUiTrace(_screenRenderForCustomUiTrace); - _screenRenderForCustomUiTrace.clear(); - } + //Save the memory cached data to be sent to native side + if (_delayedFrames.isNotEmpty) { + _saveCollectedData(); + _resetCachedFrameData(); + } - //Sync the captured screen render data of the Auto UI trace if the collector was active - if (type == UiTraceType.auto && _screenRenderForAutoUiTrace.isActive) { - _reportScreenRenderForAutoUiTrace(_screenRenderForAutoUiTrace); - _screenRenderForAutoUiTrace.clear(); - } - } catch (error, stackTrace) { - _logExceptionErrorAndStackTrace(error, stackTrace); + //Sync the captured screen render data of the Custom UI trace if the collector was active + if (type == UiTraceType.custom && _screenRenderForCustomUiTrace.isActive) { + _reportScreenRenderForCustomUiTrace(_screenRenderForCustomUiTrace); + _screenRenderForCustomUiTrace.clear(); + } + + //Sync the captured screen render data of the Auto UI trace if the collector was active + if (type == UiTraceType.auto && _screenRenderForAutoUiTrace.isActive) { + _reportScreenRenderForAutoUiTrace(_screenRenderForAutoUiTrace); + _screenRenderForAutoUiTrace.clear(); } } /// Stop screen render collector and sync the captured data. @internal void stopScreenRenderCollector() { - try { - // Return if frameTimingListener not attached - if (frameCollectorIsNotActive) return; + // Return if frameTimingListener not attached + if (frameCollectorIsNotActive) return; - if (_delayedFrames.isNotEmpty) { - _saveCollectedData(); - _resetCachedFrameData(); - } + if (_delayedFrames.isNotEmpty) { + _saveCollectedData(); + _resetCachedFrameData(); + } - // Sync Screen Render data for custom ui trace if exists - if (_screenRenderForCustomUiTrace.isActive) { - _reportScreenRenderForCustomUiTrace(_screenRenderForCustomUiTrace); - _screenRenderForCustomUiTrace.clear(); - } + // Sync Screen Render data for custom ui trace if exists + if (_screenRenderForCustomUiTrace.isActive) { + _reportScreenRenderForCustomUiTrace(_screenRenderForCustomUiTrace); + _screenRenderForCustomUiTrace.clear(); + } - // Sync Screen Render data for auto ui trace if exists - if (_screenRenderForAutoUiTrace.isActive) { - _reportScreenRenderForAutoUiTrace(_screenRenderForAutoUiTrace); - _screenRenderForAutoUiTrace.clear(); - } - } catch (error, stackTrace) { - _logExceptionErrorAndStackTrace(error, stackTrace); + // Sync Screen Render data for auto ui trace if exists + if (_screenRenderForAutoUiTrace.isActive) { + _reportScreenRenderForAutoUiTrace(_screenRenderForAutoUiTrace); + _screenRenderForAutoUiTrace.clear(); } } @@ -204,11 +191,15 @@ class InstabugScreenRenderManager { /// Dispose InstabugScreenRenderManager by removing timings callback and cashed data. void dispose() { - _resetCachedFrameData(); - _removeFrameTimings(); - _removeWidgetBindingObserver(); - _widgetsBinding = null; - screenRenderEnabled = false; + try { + _resetCachedFrameData(); + _removeFrameTimings(); + _removeWidgetBindingObserver(); + _widgetsBinding = null; + screenRenderEnabled = false; + } catch (error, stackTrace) { + _logExceptionErrorAndStackTrace(error, stackTrace); + } } /// --------------------------- private methods --------------------- @@ -409,11 +400,18 @@ class InstabugScreenRenderManager { /// @nodoc void _logExceptionErrorAndStackTrace(Object error, StackTrace stackTrace) { + //Log the crash details to the user. InstabugLogger.I.e( '[Error]:$error \n' '[StackTrace]: $stackTrace', tag: tag, ); + + //Report nonfatal for the crash details. + CrashReporting.reportHandledCrash( + error, + stackTrace, + ); } /// @nodoc diff --git a/test/utils/screen_render/instabug_screen_render_manager_test.dart b/test/utils/screen_render/instabug_screen_render_manager_test.dart index 22a1a710f..cd11ecfab 100644 --- a/test/utils/screen_render/instabug_screen_render_manager_test.dart +++ b/test/utils/screen_render/instabug_screen_render_manager_test.dart @@ -1,12 +1,26 @@ +import 'dart:ui' show FrameTiming; + +import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:instabug_flutter/instabug_flutter.dart'; +import 'package:instabug_flutter/src/generated/apm.api.g.dart'; +import 'package:instabug_flutter/src/generated/crash_reporting.api.g.dart'; import 'package:instabug_flutter/src/models/instabug_frame_data.dart'; import 'package:instabug_flutter/src/models/instabug_screen_render_data.dart'; +import 'package:instabug_flutter/src/utils/instabug_logger.dart'; import 'package:instabug_flutter/src/utils/screen_rendering/instabug_screen_render_manager.dart'; +import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; -import 'instabug_screen_render_manager_test_mocks.dart'; +import 'instabug_screen_render_manager_test.mocks.dart'; +@GenerateMocks([ + WidgetsBinding, + FrameTiming, + ApmHostApi, + CrashReportingHostApi, + InstabugLogger, +]) void main() { TestWidgetsFlutterBinding.ensureInitialized(); @@ -45,38 +59,6 @@ void main() { }); }); - // group('_initStaticValues', () { - // - // test('should initialize _timingsCallback', () async { - // await manager.callInitStaticValues(); - // expect(manager.timingsCallback, isNotNull); - // }); - // - // test('should initialize _slowFrameThresholdMs with value from _getSlowFrameThresholdMs', () async { - // // Patch the getter to return a known value - // manager.slowFrameThresholdMs = 0.0; - // manager.getSlowFrameThresholdMsFuture = () async => 42.0; - // await manager.callInitStaticValues(); - // expect(manager.slowFrameThresholdMs, 42.0); - // }); - // - // test('should initialize _screenRenderForAutoUiTrace and _screenRenderForCustomUiTrace as empty InstabugScreenRenderData', () async { - // await manager.callInitStaticValues(); - // expect(manager.screenRenderForAutoUiTrace, isA()); - // expect(manager.screenRenderForAutoUiTrace.frameData, isEmpty); - // expect(manager.screenRenderForCustomUiTrace, isA()); - // expect(manager.screenRenderForCustomUiTrace.frameData, isEmpty); - // }); - // - // test('should set _epochOffset on first timing in _timingsCallback', () async { - // await manager.callInitStaticValues(); - // final mockFrameTiming = MockFrameTiming(); - // manager.epochOffset = null; - // manager.timingsCallback([mockFrameTiming]); - // expect(manager.epochOffset, isNotNull); - // }); - // }); - group('startScreenRenderCollectorForTraceId()', () { test('should not attach timing listener if it is attached', () async { manager.startScreenRenderCollectorForTraceId(1); @@ -268,7 +250,7 @@ void main() { }); }); - group('endScreenRenderCollectorForCustomUiTrace()', () { + group('endScreenRenderCollector()', () { setUp(() { manager.screenRenderForAutoUiTrace.clear(); manager.screenRenderForCustomUiTrace.clear(); @@ -465,4 +447,162 @@ void main() { verifyNever(mApmHost.endScreenRenderForCustomUiTrace(any)); }); }); + + group('InstabugScreenRenderManager() error handling', () { + late InstabugScreenRenderManager realManager; + late MockInstabugLogger mInstabugLogger; + late MockApmHostApi mApmHostForErrorTest; + late MockWidgetsBinding mWidgetBindingForErrorTest; + late MockCrashReportingHostApi mCrashReportingHost; + + setUp(() { + realManager = InstabugScreenRenderManager.init(); // Use real instance + mInstabugLogger = MockInstabugLogger(); + mApmHostForErrorTest = MockApmHostApi(); + mWidgetBindingForErrorTest = MockWidgetsBinding(); + mCrashReportingHost = MockCrashReportingHostApi(); + + InstabugScreenRenderManager.setInstance(realManager); + InstabugLogger.setInstance(mInstabugLogger); + APM.$setHostApi(mApmHostForErrorTest); + + // Mock CrashReporting host to prevent platform channel calls + CrashReporting.$setHostApi(mCrashReportingHost); + }); + + test('should log error and stack trace when init() encounters an exception', + () async { + const error = 'Test error in getDeviceRefreshRateAndTolerance'; + final exception = Exception(error); + + when(mApmHostForErrorTest.getDeviceRefreshRateAndTolerance()) + .thenThrow(exception); + + await realManager.init(mWidgetBindingForErrorTest); + + final capturedLog = verify( + mInstabugLogger.e( + captureAny, + tag: InstabugScreenRenderManager.tag, + ), + ).captured.single as String; + + expect(capturedLog, contains('[Error]:$exception')); + expect(capturedLog, contains('[StackTrace]:')); + + // Verify that non-fatal crash reporting was called + verify( + mCrashReportingHost.sendNonFatalError( + any, // jsonCrash + any, // userAttributes + any, // fingerprint + any, // nonFatalExceptionLevel + ), + ).called(1); + }); + + test( + 'should log error and stack trace when _reportScreenRenderForAutoUiTrace() encounters an exception', + () async { + const error = 'Test error in endScreenRenderForAutoUiTrace'; + final exception = Exception(error); + + // First initialize the manager properly + when(mApmHostForErrorTest.getDeviceRefreshRateAndTolerance()) + .thenAnswer((_) async => [60.0, 10000.0]); + + await realManager.init(mWidgetBindingForErrorTest); + + final frameTestData = InstabugScreenRenderData( + traceId: 123, + frameData: [ + InstabugFrameData(10000, 200), + InstabugFrameData(20000, 1000), + ], + frozenFramesTotalDurationMicro: 1000, + slowFramesTotalDurationMicro: 200, + ); + + when(mApmHostForErrorTest.endScreenRenderForAutoUiTrace(any)) + .thenThrow(exception); + + // Start the collector and add frame data + realManager.startScreenRenderCollectorForTraceId(123); + realManager.setFrameData(frameTestData); + // End the collector which should trigger the error + realManager.endScreenRenderCollector(); + + final capturedLog = verify( + mInstabugLogger.e( + captureAny, + tag: InstabugScreenRenderManager.tag, + ), + ).captured.single as String; + + expect(capturedLog, contains('[Error]:$exception')); + expect(capturedLog, contains('[StackTrace]:')); + + // Verify that non-fatal crash reporting was called + verify( + mCrashReportingHost.sendNonFatalError( + any, // jsonCrash + any, // userAttributes + any, // fingerprint + any, // nonFatalExceptionLevel + ), + ).called(1); + }); + + test( + 'should log error and stack trace when _reportScreenRenderForCustomUiTrace() encounters an exception', + () async { + const error = 'Test error in endScreenRenderForCustomUiTrace'; + final exception = Exception(error); + + // First initialize the manager properly + when(mApmHostForErrorTest.getDeviceRefreshRateAndTolerance()) + .thenAnswer((_) async => [60.0, 10000.0]); + + await realManager.init(mWidgetBindingForErrorTest); + + final frameTestData = InstabugScreenRenderData( + traceId: 456, + frameData: [ + InstabugFrameData(15000, 300), + InstabugFrameData(25000, 1200), + ], + frozenFramesTotalDurationMicro: 1200, + slowFramesTotalDurationMicro: 300, + ); + + when(mApmHostForErrorTest.endScreenRenderForCustomUiTrace(any)) + .thenThrow(exception); + + // Start the collector and add frame data + realManager.startScreenRenderCollectorForTraceId(456, UiTraceType.custom); + realManager.setFrameData(frameTestData); + // End the collector which should trigger the error + realManager.endScreenRenderCollector(UiTraceType.custom); + + final capturedLog = verify( + mInstabugLogger.e( + captureAny, + tag: InstabugScreenRenderManager.tag, + ), + ).captured.single as String; + + expect(capturedLog, contains('[Error]:$exception')); + expect(capturedLog, contains('[StackTrace]:')); + + // Verify that non-fatal crash reporting was called + verify( + mCrashReportingHost.sendNonFatalError( + any, // jsonCrash + any, // userAttributes + any, // fingerprint + any, // nonFatalExceptionLevel + ), + ).called(1); + }); + }); } diff --git a/test/utils/screen_render/instabug_screen_render_manager_test_mocks.dart b/test/utils/screen_render/instabug_screen_render_manager_test_mocks.dart deleted file mode 100644 index 856450dd4..000000000 --- a/test/utils/screen_render/instabug_screen_render_manager_test_mocks.dart +++ /dev/null @@ -1,743 +0,0 @@ -// Mocks generated by Mockito 5.2.0 from annotations -// in instabug_flutter/example/ios/.symlinks/plugins/instabug_flutter/test/utils/screen_render/instabug_screen_render_manager_test.dart. -// Do not manually edit this file. - -import 'dart:async' as _i9; -import 'dart:developer' as _i13; -import 'dart:ui' as _i4; - -import 'package:flutter/foundation.dart' as _i3; -import 'package:flutter/gestures.dart' as _i6; -import 'package:flutter/rendering.dart' as _i7; -import 'package:flutter/scheduler.dart' as _i11; -import 'package:flutter/services.dart' as _i5; -import 'package:flutter/src/widgets/binding.dart' as _i10; -import 'package:flutter/src/widgets/focus_manager.dart' as _i2; -import 'package:flutter/src/widgets/framework.dart' as _i12; -import 'package:instabug_flutter/src/generated/apm.api.g.dart' as _i8; -import 'package:mockito/mockito.dart' as _i1; - -// ignore_for_file: type=lint -// ignore_for_file: avoid_redundant_argument_values -// ignore_for_file: avoid_setters_without_getters -// ignore_for_file: comment_references -// ignore_for_file: implementation_imports -// ignore_for_file: invalid_use_of_visible_for_testing_member -// ignore_for_file: prefer_const_constructors -// ignore_for_file: unnecessary_parenthesis -// ignore_for_file: camel_case_types - -class _FakeDuration_0 extends _i1.Fake implements Duration {} - -class _FakeFocusManager_1 extends _i1.Fake implements _i2.FocusManager { - @override - String toString({_i3.DiagnosticLevel? minLevel = _i3.DiagnosticLevel.info}) => - super.toString(); -} - -class _FakeSingletonFlutterWindow_2 extends _i1.Fake - implements _i4.SingletonFlutterWindow {} - -class _FakePlatformDispatcher_3 extends _i1.Fake - implements _i4.PlatformDispatcher {} - -class _FakeHardwareKeyboard_4 extends _i1.Fake - implements _i5.HardwareKeyboard {} - -class _FakeKeyEventManager_5 extends _i1.Fake implements _i5.KeyEventManager {} - -class _FakeBinaryMessenger_6 extends _i1.Fake implements _i5.BinaryMessenger {} - -class _FakeChannelBuffers_7 extends _i1.Fake implements _i4.ChannelBuffers {} - -class _FakeRestorationManager_8 extends _i1.Fake - implements _i5.RestorationManager {} - -class _FakePointerRouter_9 extends _i1.Fake implements _i6.PointerRouter {} - -class _FakeGestureArenaManager_10 extends _i1.Fake - implements _i6.GestureArenaManager {} - -class _FakePointerSignalResolver_11 extends _i1.Fake - implements _i6.PointerSignalResolver {} - -class _FakeMouseTracker_12 extends _i1.Fake implements _i7.MouseTracker {} - -class _FakePipelineOwner_13 extends _i1.Fake implements _i7.PipelineOwner {} - -class _FakeRenderView_14 extends _i1.Fake implements _i7.RenderView { - @override - String toString({_i3.DiagnosticLevel? minLevel = _i3.DiagnosticLevel.info}) => - super.toString(); -} - -class _FakeAccessibilityFeatures_15 extends _i1.Fake - implements _i4.AccessibilityFeatures {} - -class _FakeViewConfiguration_16 extends _i1.Fake - implements _i7.ViewConfiguration {} - -class _FakeSemanticsUpdateBuilder_17 extends _i1.Fake - implements _i4.SemanticsUpdateBuilder {} - -/// A class which mocks [ApmHostApi]. -/// -/// See the documentation for Mockito's code generation for more information. -class MockApmHostApi extends _i1.Mock implements _i8.ApmHostApi { - MockApmHostApi() { - _i1.throwOnMissingStub(this); - } - - @override - _i9.Future setEnabled(bool? arg_isEnabled) => - (super.noSuchMethod(Invocation.method(#setEnabled, [arg_isEnabled]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - _i9.Future isEnabled() => - (super.noSuchMethod(Invocation.method(#isEnabled, []), - returnValue: Future.value(false)) as _i9.Future); - @override - _i9.Future setScreenLoadingEnabled(bool? arg_isEnabled) => - (super.noSuchMethod( - Invocation.method(#setScreenLoadingEnabled, [arg_isEnabled]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - _i9.Future isScreenLoadingEnabled() => - (super.noSuchMethod(Invocation.method(#isScreenLoadingEnabled, []), - returnValue: Future.value(false)) as _i9.Future); - @override - _i9.Future setColdAppLaunchEnabled(bool? arg_isEnabled) => - (super.noSuchMethod( - Invocation.method(#setColdAppLaunchEnabled, [arg_isEnabled]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - _i9.Future setAutoUITraceEnabled(bool? arg_isEnabled) => (super - .noSuchMethod(Invocation.method(#setAutoUITraceEnabled, [arg_isEnabled]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - _i9.Future startFlow(String? arg_name) => - (super.noSuchMethod(Invocation.method(#startFlow, [arg_name]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - _i9.Future setFlowAttribute( - String? arg_name, String? arg_key, String? arg_value) => - (super.noSuchMethod( - Invocation.method(#setFlowAttribute, [arg_name, arg_key, arg_value]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - _i9.Future endFlow(String? arg_name) => - (super.noSuchMethod(Invocation.method(#endFlow, [arg_name]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - _i9.Future startUITrace(String? arg_name) => - (super.noSuchMethod(Invocation.method(#startUITrace, [arg_name]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - _i9.Future endUITrace() => - (super.noSuchMethod(Invocation.method(#endUITrace, []), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - _i9.Future endAppLaunch() => - (super.noSuchMethod(Invocation.method(#endAppLaunch, []), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - _i9.Future networkLogAndroid(Map? arg_data) => - (super.noSuchMethod(Invocation.method(#networkLogAndroid, [arg_data]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - _i9.Future startCpUiTrace( - String? arg_screenName, int? arg_microTimeStamp, int? arg_traceId) => - (super.noSuchMethod( - Invocation.method(#startCpUiTrace, - [arg_screenName, arg_microTimeStamp, arg_traceId]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - _i9.Future reportScreenLoadingCP(int? arg_startTimeStampMicro, - int? arg_durationMicro, int? arg_uiTraceId) => - (super.noSuchMethod( - Invocation.method(#reportScreenLoadingCP, - [arg_startTimeStampMicro, arg_durationMicro, arg_uiTraceId]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - _i9.Future endScreenLoadingCP( - int? arg_timeStampMicro, int? arg_uiTraceId) => - (super.noSuchMethod( - Invocation.method( - #endScreenLoadingCP, [arg_timeStampMicro, arg_uiTraceId]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - _i9.Future isEndScreenLoadingEnabled() => - (super.noSuchMethod(Invocation.method(#isEndScreenLoadingEnabled, []), - returnValue: Future.value(false)) as _i9.Future); - @override - _i9.Future isScreenRenderEnabled() => - (super.noSuchMethod(Invocation.method(#isScreenRenderEnabled, []), - returnValue: Future.value(false)) as _i9.Future); - @override - _i9.Future> getDeviceRefreshRateAndTolerance() => - (super.noSuchMethod( - Invocation.method(#getDeviceRefreshRateAndTolerance, []), - returnValue: Future>.value([])) - as _i9.Future>); - @override - _i9.Future setScreenRenderEnabled(bool? arg_isEnabled) => (super - .noSuchMethod(Invocation.method(#setScreenRenderEnabled, [arg_isEnabled]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - _i9.Future endScreenRenderForAutoUiTrace( - Map? arg_data) => - (super.noSuchMethod( - Invocation.method(#endScreenRenderForAutoUiTrace, [arg_data]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - _i9.Future endScreenRenderForCustomUiTrace( - Map? arg_data) => - (super.noSuchMethod( - Invocation.method(#endScreenRenderForCustomUiTrace, [arg_data]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); -} - -/// A class which mocks [FrameTiming]. -/// -/// See the documentation for Mockito's code generation for more information. -class MockFrameTiming extends _i1.Mock implements _i4.FrameTiming { - MockFrameTiming() { - _i1.throwOnMissingStub(this); - } - - @override - Duration get buildDuration => - (super.noSuchMethod(Invocation.getter(#buildDuration), - returnValue: _FakeDuration_0()) as Duration); - @override - Duration get rasterDuration => - (super.noSuchMethod(Invocation.getter(#rasterDuration), - returnValue: _FakeDuration_0()) as Duration); - @override - Duration get vsyncOverhead => - (super.noSuchMethod(Invocation.getter(#vsyncOverhead), - returnValue: _FakeDuration_0()) as Duration); - @override - Duration get totalSpan => (super.noSuchMethod(Invocation.getter(#totalSpan), - returnValue: _FakeDuration_0()) as Duration); - @override - int get layerCacheCount => - (super.noSuchMethod(Invocation.getter(#layerCacheCount), returnValue: 0) - as int); - @override - int get layerCacheBytes => - (super.noSuchMethod(Invocation.getter(#layerCacheBytes), returnValue: 0) - as int); - @override - double get layerCacheMegabytes => - (super.noSuchMethod(Invocation.getter(#layerCacheMegabytes), - returnValue: 0.0) as double); - @override - int get pictureCacheCount => - (super.noSuchMethod(Invocation.getter(#pictureCacheCount), returnValue: 0) - as int); - @override - int get pictureCacheBytes => - (super.noSuchMethod(Invocation.getter(#pictureCacheBytes), returnValue: 0) - as int); - @override - double get pictureCacheMegabytes => - (super.noSuchMethod(Invocation.getter(#pictureCacheMegabytes), - returnValue: 0.0) as double); - @override - int get frameNumber => - (super.noSuchMethod(Invocation.getter(#frameNumber), returnValue: 0) - as int); - @override - int timestampInMicroseconds(_i4.FramePhase? phase) => - (super.noSuchMethod(Invocation.method(#timestampInMicroseconds, [phase]), - returnValue: 0) as int); -} - -/// A class which mocks [WidgetsBinding]. -/// -/// See the documentation for Mockito's code generation for more information. -class MockWidgetsBinding extends _i1.Mock implements _i10.WidgetsBinding { - MockWidgetsBinding() { - _i1.throwOnMissingStub(this); - } - - @override - bool get debugBuildingDirtyElements => - (super.noSuchMethod(Invocation.getter(#debugBuildingDirtyElements), - returnValue: false) as bool); - @override - set debugBuildingDirtyElements(bool? _debugBuildingDirtyElements) => - super.noSuchMethod( - Invocation.setter( - #debugBuildingDirtyElements, _debugBuildingDirtyElements), - returnValueForMissingStub: null); - @override - _i2.FocusManager get focusManager => - (super.noSuchMethod(Invocation.getter(#focusManager), - returnValue: _FakeFocusManager_1()) as _i2.FocusManager); - @override - bool get firstFrameRasterized => - (super.noSuchMethod(Invocation.getter(#firstFrameRasterized), - returnValue: false) as bool); - @override - _i9.Future get waitUntilFirstFrameRasterized => - (super.noSuchMethod(Invocation.getter(#waitUntilFirstFrameRasterized), - returnValue: Future.value()) as _i9.Future); - @override - bool get debugDidSendFirstFrameEvent => - (super.noSuchMethod(Invocation.getter(#debugDidSendFirstFrameEvent), - returnValue: false) as bool); - @override - bool get framesEnabled => - (super.noSuchMethod(Invocation.getter(#framesEnabled), returnValue: false) - as bool); - @override - bool get isRootWidgetAttached => - (super.noSuchMethod(Invocation.getter(#isRootWidgetAttached), - returnValue: false) as bool); - @override - _i4.SingletonFlutterWindow get window => - (super.noSuchMethod(Invocation.getter(#window), - returnValue: _FakeSingletonFlutterWindow_2()) - as _i4.SingletonFlutterWindow); - @override - _i4.PlatformDispatcher get platformDispatcher => - (super.noSuchMethod(Invocation.getter(#platformDispatcher), - returnValue: _FakePlatformDispatcher_3()) as _i4.PlatformDispatcher); - @override - bool get locked => - (super.noSuchMethod(Invocation.getter(#locked), returnValue: false) - as bool); - @override - _i5.HardwareKeyboard get keyboard => - (super.noSuchMethod(Invocation.getter(#keyboard), - returnValue: _FakeHardwareKeyboard_4()) as _i5.HardwareKeyboard); - @override - _i5.KeyEventManager get keyEventManager => - (super.noSuchMethod(Invocation.getter(#keyEventManager), - returnValue: _FakeKeyEventManager_5()) as _i5.KeyEventManager); - @override - _i5.BinaryMessenger get defaultBinaryMessenger => - (super.noSuchMethod(Invocation.getter(#defaultBinaryMessenger), - returnValue: _FakeBinaryMessenger_6()) as _i5.BinaryMessenger); - @override - _i4.ChannelBuffers get channelBuffers => - (super.noSuchMethod(Invocation.getter(#channelBuffers), - returnValue: _FakeChannelBuffers_7()) as _i4.ChannelBuffers); - @override - _i5.RestorationManager get restorationManager => - (super.noSuchMethod(Invocation.getter(#restorationManager), - returnValue: _FakeRestorationManager_8()) as _i5.RestorationManager); - @override - _i11.SchedulingStrategy get schedulingStrategy => - (super.noSuchMethod(Invocation.getter(#schedulingStrategy), - returnValue: ({int? priority, _i11.SchedulerBinding? scheduler}) => - false) as _i11.SchedulingStrategy); - @override - set schedulingStrategy(_i11.SchedulingStrategy? _schedulingStrategy) => super - .noSuchMethod(Invocation.setter(#schedulingStrategy, _schedulingStrategy), - returnValueForMissingStub: null); - @override - int get transientCallbackCount => - (super.noSuchMethod(Invocation.getter(#transientCallbackCount), - returnValue: 0) as int); - @override - _i9.Future get endOfFrame => - (super.noSuchMethod(Invocation.getter(#endOfFrame), - returnValue: Future.value()) as _i9.Future); - @override - bool get hasScheduledFrame => - (super.noSuchMethod(Invocation.getter(#hasScheduledFrame), - returnValue: false) as bool); - @override - _i11.SchedulerPhase get schedulerPhase => - (super.noSuchMethod(Invocation.getter(#schedulerPhase), - returnValue: _i11.SchedulerPhase.idle) as _i11.SchedulerPhase); - @override - Duration get currentFrameTimeStamp => - (super.noSuchMethod(Invocation.getter(#currentFrameTimeStamp), - returnValue: _FakeDuration_0()) as Duration); - @override - Duration get currentSystemFrameTimeStamp => - (super.noSuchMethod(Invocation.getter(#currentSystemFrameTimeStamp), - returnValue: _FakeDuration_0()) as Duration); - @override - _i6.PointerRouter get pointerRouter => - (super.noSuchMethod(Invocation.getter(#pointerRouter), - returnValue: _FakePointerRouter_9()) as _i6.PointerRouter); - @override - _i6.GestureArenaManager get gestureArena => (super.noSuchMethod( - Invocation.getter(#gestureArena), - returnValue: _FakeGestureArenaManager_10()) as _i6.GestureArenaManager); - @override - _i6.PointerSignalResolver get pointerSignalResolver => - (super.noSuchMethod(Invocation.getter(#pointerSignalResolver), - returnValue: _FakePointerSignalResolver_11()) - as _i6.PointerSignalResolver); - @override - bool get resamplingEnabled => - (super.noSuchMethod(Invocation.getter(#resamplingEnabled), - returnValue: false) as bool); - @override - set resamplingEnabled(bool? _resamplingEnabled) => super.noSuchMethod( - Invocation.setter(#resamplingEnabled, _resamplingEnabled), - returnValueForMissingStub: null); - @override - Duration get samplingOffset => - (super.noSuchMethod(Invocation.getter(#samplingOffset), - returnValue: _FakeDuration_0()) as Duration); - @override - set samplingOffset(Duration? _samplingOffset) => - super.noSuchMethod(Invocation.setter(#samplingOffset, _samplingOffset), - returnValueForMissingStub: null); - @override - _i7.MouseTracker get mouseTracker => - (super.noSuchMethod(Invocation.getter(#mouseTracker), - returnValue: _FakeMouseTracker_12()) as _i7.MouseTracker); - @override - _i7.PipelineOwner get pipelineOwner => - (super.noSuchMethod(Invocation.getter(#pipelineOwner), - returnValue: _FakePipelineOwner_13()) as _i7.PipelineOwner); - @override - _i7.RenderView get renderView => - (super.noSuchMethod(Invocation.getter(#renderView), - returnValue: _FakeRenderView_14()) as _i7.RenderView); - @override - set renderView(_i7.RenderView? value) => - super.noSuchMethod(Invocation.setter(#renderView, value), - returnValueForMissingStub: null); - @override - bool get sendFramesToEngine => - (super.noSuchMethod(Invocation.getter(#sendFramesToEngine), - returnValue: false) as bool); - @override - _i4.AccessibilityFeatures get accessibilityFeatures => - (super.noSuchMethod(Invocation.getter(#accessibilityFeatures), - returnValue: _FakeAccessibilityFeatures_15()) - as _i4.AccessibilityFeatures); - @override - bool get disableAnimations => - (super.noSuchMethod(Invocation.getter(#disableAnimations), - returnValue: false) as bool); - @override - void initInstances() => - super.noSuchMethod(Invocation.method(#initInstances, []), - returnValueForMissingStub: null); - @override - void initServiceExtensions() => - super.noSuchMethod(Invocation.method(#initServiceExtensions, []), - returnValueForMissingStub: null); - @override - void addObserver(_i10.WidgetsBindingObserver? observer) => - super.noSuchMethod(Invocation.method(#addObserver, [observer]), - returnValueForMissingStub: null); - @override - bool removeObserver(_i10.WidgetsBindingObserver? observer) => - (super.noSuchMethod(Invocation.method(#removeObserver, [observer]), - returnValue: false) as bool); - @override - void handleMetricsChanged() => - super.noSuchMethod(Invocation.method(#handleMetricsChanged, []), - returnValueForMissingStub: null); - @override - void handleTextScaleFactorChanged() => - super.noSuchMethod(Invocation.method(#handleTextScaleFactorChanged, []), - returnValueForMissingStub: null); - @override - void handlePlatformBrightnessChanged() => super.noSuchMethod( - Invocation.method(#handlePlatformBrightnessChanged, []), - returnValueForMissingStub: null); - @override - void handleAccessibilityFeaturesChanged() => super.noSuchMethod( - Invocation.method(#handleAccessibilityFeaturesChanged, []), - returnValueForMissingStub: null); - @override - void handleLocaleChanged() => - super.noSuchMethod(Invocation.method(#handleLocaleChanged, []), - returnValueForMissingStub: null); - @override - void dispatchLocalesChanged(List<_i4.Locale>? locales) => - super.noSuchMethod(Invocation.method(#dispatchLocalesChanged, [locales]), - returnValueForMissingStub: null); - @override - void dispatchAccessibilityFeaturesChanged() => super.noSuchMethod( - Invocation.method(#dispatchAccessibilityFeaturesChanged, []), - returnValueForMissingStub: null); - @override - _i9.Future handlePopRoute() => - (super.noSuchMethod(Invocation.method(#handlePopRoute, []), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - _i9.Future handlePushRoute(String? route) => - (super.noSuchMethod(Invocation.method(#handlePushRoute, [route]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - void handleAppLifecycleStateChanged(_i4.AppLifecycleState? state) => super - .noSuchMethod(Invocation.method(#handleAppLifecycleStateChanged, [state]), - returnValueForMissingStub: null); - @override - void handleMemoryPressure() => - super.noSuchMethod(Invocation.method(#handleMemoryPressure, []), - returnValueForMissingStub: null); - @override - void drawFrame() => super.noSuchMethod(Invocation.method(#drawFrame, []), - returnValueForMissingStub: null); - @override - void scheduleAttachRootWidget(_i12.Widget? rootWidget) => super.noSuchMethod( - Invocation.method(#scheduleAttachRootWidget, [rootWidget]), - returnValueForMissingStub: null); - @override - void attachRootWidget(_i12.Widget? rootWidget) => - super.noSuchMethod(Invocation.method(#attachRootWidget, [rootWidget]), - returnValueForMissingStub: null); - @override - _i9.Future performReassemble() => - (super.noSuchMethod(Invocation.method(#performReassemble, []), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - _i4.Locale? computePlatformResolvedLocale( - List<_i4.Locale>? supportedLocales) => - (super.noSuchMethod(Invocation.method( - #computePlatformResolvedLocale, [supportedLocales])) as _i4.Locale?); - @override - _i9.Future lockEvents(_i9.Future Function()? callback) => - (super.noSuchMethod(Invocation.method(#lockEvents, [callback]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - void unlocked() => super.noSuchMethod(Invocation.method(#unlocked, []), - returnValueForMissingStub: null); - @override - _i9.Future reassembleApplication() => - (super.noSuchMethod(Invocation.method(#reassembleApplication, []), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - void registerSignalServiceExtension( - {String? name, _i3.AsyncCallback? callback}) => - super.noSuchMethod( - Invocation.method(#registerSignalServiceExtension, [], - {#name: name, #callback: callback}), - returnValueForMissingStub: null); - @override - void registerBoolServiceExtension( - {String? name, - _i3.AsyncValueGetter? getter, - _i3.AsyncValueSetter? setter}) => - super.noSuchMethod( - Invocation.method(#registerBoolServiceExtension, [], - {#name: name, #getter: getter, #setter: setter}), - returnValueForMissingStub: null); - @override - void registerNumericServiceExtension( - {String? name, - _i3.AsyncValueGetter? getter, - _i3.AsyncValueSetter? setter}) => - super.noSuchMethod( - Invocation.method(#registerNumericServiceExtension, [], - {#name: name, #getter: getter, #setter: setter}), - returnValueForMissingStub: null); - @override - void postEvent(String? eventKind, Map? eventData) => - super.noSuchMethod(Invocation.method(#postEvent, [eventKind, eventData]), - returnValueForMissingStub: null); - @override - void registerStringServiceExtension( - {String? name, - _i3.AsyncValueGetter? getter, - _i3.AsyncValueSetter? setter}) => - super.noSuchMethod( - Invocation.method(#registerStringServiceExtension, [], - {#name: name, #getter: getter, #setter: setter}), - returnValueForMissingStub: null); - @override - void registerServiceExtension( - {String? name, _i3.ServiceExtensionCallback? callback}) => - super.noSuchMethod( - Invocation.method(#registerServiceExtension, [], - {#name: name, #callback: callback}), - returnValueForMissingStub: null); - @override - _i5.BinaryMessenger createBinaryMessenger() => - (super.noSuchMethod(Invocation.method(#createBinaryMessenger, []), - returnValue: _FakeBinaryMessenger_6()) as _i5.BinaryMessenger); - @override - _i9.Future handleSystemMessage(Object? systemMessage) => (super - .noSuchMethod(Invocation.method(#handleSystemMessage, [systemMessage]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i9.Future); - @override - void initLicenses() => - super.noSuchMethod(Invocation.method(#initLicenses, []), - returnValueForMissingStub: null); - @override - void evict(String? asset) => - super.noSuchMethod(Invocation.method(#evict, [asset]), - returnValueForMissingStub: null); - @override - void readInitialLifecycleStateFromNativeWindow() => super.noSuchMethod( - Invocation.method(#readInitialLifecycleStateFromNativeWindow, []), - returnValueForMissingStub: null); - @override - _i5.RestorationManager createRestorationManager() => - (super.noSuchMethod(Invocation.method(#createRestorationManager, []), - returnValue: _FakeRestorationManager_8()) as _i5.RestorationManager); - @override - void setSystemUiChangeCallback(_i5.SystemUiChangeCallback? callback) => super - .noSuchMethod(Invocation.method(#setSystemUiChangeCallback, [callback]), - returnValueForMissingStub: null); - @override - void addTimingsCallback(_i4.TimingsCallback? callback) => - super.noSuchMethod(Invocation.method(#addTimingsCallback, [callback]), - returnValueForMissingStub: null); - @override - void removeTimingsCallback(_i4.TimingsCallback? callback) => - super.noSuchMethod(Invocation.method(#removeTimingsCallback, [callback]), - returnValueForMissingStub: null); - @override - _i9.Future scheduleTask( - _i11.TaskCallback? task, _i11.Priority? priority, - {String? debugLabel, _i13.Flow? flow}) => - (super.noSuchMethod( - Invocation.method(#scheduleTask, [task, priority], - {#debugLabel: debugLabel, #flow: flow}), - returnValue: Future.value(null)) as _i9.Future); - @override - bool handleEventLoopCallback() => - (super.noSuchMethod(Invocation.method(#handleEventLoopCallback, []), - returnValue: false) as bool); - @override - int scheduleFrameCallback(_i11.FrameCallback? callback, - {bool? rescheduling = false}) => - (super.noSuchMethod( - Invocation.method(#scheduleFrameCallback, [callback], - {#rescheduling: rescheduling}), - returnValue: 0) as int); - @override - void cancelFrameCallbackWithId(int? id) => - super.noSuchMethod(Invocation.method(#cancelFrameCallbackWithId, [id]), - returnValueForMissingStub: null); - @override - bool debugAssertNoTransientCallbacks(String? reason) => (super.noSuchMethod( - Invocation.method(#debugAssertNoTransientCallbacks, [reason]), - returnValue: false) as bool); - @override - void addPersistentFrameCallback(_i11.FrameCallback? callback) => super - .noSuchMethod(Invocation.method(#addPersistentFrameCallback, [callback]), - returnValueForMissingStub: null); - @override - void addPostFrameCallback(_i11.FrameCallback? callback) => - super.noSuchMethod(Invocation.method(#addPostFrameCallback, [callback]), - returnValueForMissingStub: null); - @override - void ensureFrameCallbacksRegistered() => - super.noSuchMethod(Invocation.method(#ensureFrameCallbacksRegistered, []), - returnValueForMissingStub: null); - @override - void ensureVisualUpdate() => - super.noSuchMethod(Invocation.method(#ensureVisualUpdate, []), - returnValueForMissingStub: null); - @override - void scheduleFrame() => - super.noSuchMethod(Invocation.method(#scheduleFrame, []), - returnValueForMissingStub: null); - @override - void scheduleForcedFrame() => - super.noSuchMethod(Invocation.method(#scheduleForcedFrame, []), - returnValueForMissingStub: null); - @override - void scheduleWarmUpFrame() => - super.noSuchMethod(Invocation.method(#scheduleWarmUpFrame, []), - returnValueForMissingStub: null); - @override - void resetEpoch() => super.noSuchMethod(Invocation.method(#resetEpoch, []), - returnValueForMissingStub: null); - @override - void handleBeginFrame(Duration? rawTimeStamp) => - super.noSuchMethod(Invocation.method(#handleBeginFrame, [rawTimeStamp]), - returnValueForMissingStub: null); - @override - void handleDrawFrame() => - super.noSuchMethod(Invocation.method(#handleDrawFrame, []), - returnValueForMissingStub: null); - @override - void cancelPointer(int? pointer) => - super.noSuchMethod(Invocation.method(#cancelPointer, [pointer]), - returnValueForMissingStub: null); - @override - void handlePointerEvent(_i6.PointerEvent? event) => - super.noSuchMethod(Invocation.method(#handlePointerEvent, [event]), - returnValueForMissingStub: null); - @override - void hitTest(_i6.HitTestResult? result, _i4.Offset? position) => - super.noSuchMethod(Invocation.method(#hitTest, [result, position]), - returnValueForMissingStub: null); - @override - void dispatchEvent( - _i6.PointerEvent? event, _i6.HitTestResult? hitTestResult) => - super.noSuchMethod( - Invocation.method(#dispatchEvent, [event, hitTestResult]), - returnValueForMissingStub: null); - @override - void handleEvent(_i6.PointerEvent? event, _i6.HitTestEntry? entry) => - super.noSuchMethod(Invocation.method(#handleEvent, [event, entry]), - returnValueForMissingStub: null); - @override - void resetGestureBinding() => - super.noSuchMethod(Invocation.method(#resetGestureBinding, []), - returnValueForMissingStub: null); - @override - void initRenderView() => - super.noSuchMethod(Invocation.method(#initRenderView, []), - returnValueForMissingStub: null); - @override - _i7.ViewConfiguration createViewConfiguration() => - (super.noSuchMethod(Invocation.method(#createViewConfiguration, []), - returnValue: _FakeViewConfiguration_16()) as _i7.ViewConfiguration); - @override - void initMouseTracker([_i7.MouseTracker? tracker]) => - super.noSuchMethod(Invocation.method(#initMouseTracker, [tracker]), - returnValueForMissingStub: null); - @override - void setSemanticsEnabled(bool? enabled) => - super.noSuchMethod(Invocation.method(#setSemanticsEnabled, [enabled]), - returnValueForMissingStub: null); - @override - void deferFirstFrame() => - super.noSuchMethod(Invocation.method(#deferFirstFrame, []), - returnValueForMissingStub: null); - @override - void allowFirstFrame() => - super.noSuchMethod(Invocation.method(#allowFirstFrame, []), - returnValueForMissingStub: null); - @override - void resetFirstFrameSent() => - super.noSuchMethod(Invocation.method(#resetFirstFrameSent, []), - returnValueForMissingStub: null); - @override - _i4.SemanticsUpdateBuilder createSemanticsUpdateBuilder() => - (super.noSuchMethod(Invocation.method(#createSemanticsUpdateBuilder, []), - returnValue: _FakeSemanticsUpdateBuilder_17()) - as _i4.SemanticsUpdateBuilder); -} From 72f9bc996e46fbd4de5ee9d79be2a3985c36d4b3 Mon Sep 17 00:00:00 2001 From: Andrew Amin Date: Tue, 12 Aug 2025 16:33:59 +0300 Subject: [PATCH 64/84] chore: adapt instabug_screen_render_manager_test for flutter 2.10.5 --- .../instabug_screen_render_manager_test.dart | 15 +- ...abug_screen_render_manager_test_mocks.dart | 814 ++++++++++++++++++ 2 files changed, 815 insertions(+), 14 deletions(-) create mode 100644 test/utils/screen_render/instabug_screen_render_manager_test_mocks.dart diff --git a/test/utils/screen_render/instabug_screen_render_manager_test.dart b/test/utils/screen_render/instabug_screen_render_manager_test.dart index cd11ecfab..2282b8b80 100644 --- a/test/utils/screen_render/instabug_screen_render_manager_test.dart +++ b/test/utils/screen_render/instabug_screen_render_manager_test.dart @@ -1,26 +1,13 @@ -import 'dart:ui' show FrameTiming; - -import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:instabug_flutter/instabug_flutter.dart'; -import 'package:instabug_flutter/src/generated/apm.api.g.dart'; -import 'package:instabug_flutter/src/generated/crash_reporting.api.g.dart'; import 'package:instabug_flutter/src/models/instabug_frame_data.dart'; import 'package:instabug_flutter/src/models/instabug_screen_render_data.dart'; import 'package:instabug_flutter/src/utils/instabug_logger.dart'; import 'package:instabug_flutter/src/utils/screen_rendering/instabug_screen_render_manager.dart'; -import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; -import 'instabug_screen_render_manager_test.mocks.dart'; +import 'instabug_screen_render_manager_test_mocks.dart'; -@GenerateMocks([ - WidgetsBinding, - FrameTiming, - ApmHostApi, - CrashReportingHostApi, - InstabugLogger, -]) void main() { TestWidgetsFlutterBinding.ensureInitialized(); diff --git a/test/utils/screen_render/instabug_screen_render_manager_test_mocks.dart b/test/utils/screen_render/instabug_screen_render_manager_test_mocks.dart new file mode 100644 index 000000000..fbb7545dd --- /dev/null +++ b/test/utils/screen_render/instabug_screen_render_manager_test_mocks.dart @@ -0,0 +1,814 @@ +// Mocks generated by Mockito 5.2.0 from annotations +// in instabug_flutter/example/ios/.symlinks/plugins/instabug_flutter/test/utils/screen_render/instabug_screen_render_manager_test.dart. +// Do not manually edit this file. + +import 'dart:async' as _i8; +import 'dart:developer' as _i12; +import 'dart:ui' as _i4; + +import 'package:flutter/foundation.dart' as _i11; +import 'package:flutter/gestures.dart' as _i6; +import 'package:flutter/rendering.dart' as _i3; +import 'package:flutter/scheduler.dart' as _i9; +import 'package:flutter/services.dart' as _i5; +import 'package:flutter/src/widgets/binding.dart' as _i7; +import 'package:flutter/src/widgets/focus_manager.dart' as _i2; +import 'package:flutter/src/widgets/framework.dart' as _i10; +import 'package:instabug_flutter/instabug_flutter.dart' as _i16; +import 'package:instabug_flutter/src/generated/apm.api.g.dart' as _i13; +import 'package:instabug_flutter/src/generated/crash_reporting.api.g.dart' + as _i14; +import 'package:instabug_flutter/src/utils/instabug_logger.dart' as _i15; +import 'package:mockito/mockito.dart' as _i1; + +// ignore_for_file: type=lint +// ignore_for_file: avoid_redundant_argument_values +// ignore_for_file: avoid_setters_without_getters +// ignore_for_file: comment_references +// ignore_for_file: implementation_imports +// ignore_for_file: invalid_use_of_visible_for_testing_member +// ignore_for_file: prefer_const_constructors +// ignore_for_file: unnecessary_parenthesis +// ignore_for_file: camel_case_types + +class _FakeFocusManager_0 extends _i1.Fake implements _i2.FocusManager { + @override + String toString({_i3.DiagnosticLevel? minLevel = _i3.DiagnosticLevel.info}) => + super.toString(); +} + +class _FakeSingletonFlutterWindow_1 extends _i1.Fake + implements _i4.SingletonFlutterWindow {} + +class _FakePlatformDispatcher_2 extends _i1.Fake + implements _i4.PlatformDispatcher {} + +class _FakeHardwareKeyboard_3 extends _i1.Fake + implements _i5.HardwareKeyboard {} + +class _FakeKeyEventManager_4 extends _i1.Fake implements _i5.KeyEventManager {} + +class _FakeBinaryMessenger_5 extends _i1.Fake implements _i5.BinaryMessenger {} + +class _FakeChannelBuffers_6 extends _i1.Fake implements _i4.ChannelBuffers {} + +class _FakeRestorationManager_7 extends _i1.Fake + implements _i5.RestorationManager {} + +class _FakeDuration_8 extends _i1.Fake implements Duration {} + +class _FakePointerRouter_9 extends _i1.Fake implements _i6.PointerRouter {} + +class _FakeGestureArenaManager_10 extends _i1.Fake + implements _i6.GestureArenaManager {} + +class _FakePointerSignalResolver_11 extends _i1.Fake + implements _i6.PointerSignalResolver {} + +class _FakeMouseTracker_12 extends _i1.Fake implements _i3.MouseTracker {} + +class _FakePipelineOwner_13 extends _i1.Fake implements _i3.PipelineOwner {} + +class _FakeRenderView_14 extends _i1.Fake implements _i3.RenderView { + @override + String toString({_i3.DiagnosticLevel? minLevel = _i3.DiagnosticLevel.info}) => + super.toString(); +} + +class _FakeAccessibilityFeatures_15 extends _i1.Fake + implements _i4.AccessibilityFeatures {} + +class _FakeViewConfiguration_16 extends _i1.Fake + implements _i3.ViewConfiguration {} + +class _FakeSemanticsUpdateBuilder_17 extends _i1.Fake + implements _i4.SemanticsUpdateBuilder {} + +/// A class which mocks [WidgetsBinding]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockWidgetsBinding extends _i1.Mock implements _i7.WidgetsBinding { + MockWidgetsBinding() { + _i1.throwOnMissingStub(this); + } + + @override + bool get debugBuildingDirtyElements => + (super.noSuchMethod(Invocation.getter(#debugBuildingDirtyElements), + returnValue: false) as bool); + @override + set debugBuildingDirtyElements(bool? _debugBuildingDirtyElements) => + super.noSuchMethod( + Invocation.setter( + #debugBuildingDirtyElements, _debugBuildingDirtyElements), + returnValueForMissingStub: null); + @override + _i2.FocusManager get focusManager => + (super.noSuchMethod(Invocation.getter(#focusManager), + returnValue: _FakeFocusManager_0()) as _i2.FocusManager); + @override + bool get firstFrameRasterized => + (super.noSuchMethod(Invocation.getter(#firstFrameRasterized), + returnValue: false) as bool); + @override + _i8.Future get waitUntilFirstFrameRasterized => + (super.noSuchMethod(Invocation.getter(#waitUntilFirstFrameRasterized), + returnValue: Future.value()) as _i8.Future); + @override + bool get debugDidSendFirstFrameEvent => + (super.noSuchMethod(Invocation.getter(#debugDidSendFirstFrameEvent), + returnValue: false) as bool); + @override + bool get framesEnabled => + (super.noSuchMethod(Invocation.getter(#framesEnabled), returnValue: false) + as bool); + @override + bool get isRootWidgetAttached => + (super.noSuchMethod(Invocation.getter(#isRootWidgetAttached), + returnValue: false) as bool); + @override + _i4.SingletonFlutterWindow get window => + (super.noSuchMethod(Invocation.getter(#window), + returnValue: _FakeSingletonFlutterWindow_1()) + as _i4.SingletonFlutterWindow); + @override + _i4.PlatformDispatcher get platformDispatcher => + (super.noSuchMethod(Invocation.getter(#platformDispatcher), + returnValue: _FakePlatformDispatcher_2()) as _i4.PlatformDispatcher); + @override + bool get locked => + (super.noSuchMethod(Invocation.getter(#locked), returnValue: false) + as bool); + @override + _i5.HardwareKeyboard get keyboard => + (super.noSuchMethod(Invocation.getter(#keyboard), + returnValue: _FakeHardwareKeyboard_3()) as _i5.HardwareKeyboard); + @override + _i5.KeyEventManager get keyEventManager => + (super.noSuchMethod(Invocation.getter(#keyEventManager), + returnValue: _FakeKeyEventManager_4()) as _i5.KeyEventManager); + @override + _i5.BinaryMessenger get defaultBinaryMessenger => + (super.noSuchMethod(Invocation.getter(#defaultBinaryMessenger), + returnValue: _FakeBinaryMessenger_5()) as _i5.BinaryMessenger); + @override + _i4.ChannelBuffers get channelBuffers => + (super.noSuchMethod(Invocation.getter(#channelBuffers), + returnValue: _FakeChannelBuffers_6()) as _i4.ChannelBuffers); + @override + _i5.RestorationManager get restorationManager => + (super.noSuchMethod(Invocation.getter(#restorationManager), + returnValue: _FakeRestorationManager_7()) as _i5.RestorationManager); + @override + _i9.SchedulingStrategy get schedulingStrategy => + (super.noSuchMethod(Invocation.getter(#schedulingStrategy), + returnValue: ({int? priority, _i9.SchedulerBinding? scheduler}) => + false) as _i9.SchedulingStrategy); + @override + set schedulingStrategy(_i9.SchedulingStrategy? _schedulingStrategy) => super + .noSuchMethod(Invocation.setter(#schedulingStrategy, _schedulingStrategy), + returnValueForMissingStub: null); + @override + int get transientCallbackCount => + (super.noSuchMethod(Invocation.getter(#transientCallbackCount), + returnValue: 0) as int); + @override + _i8.Future get endOfFrame => + (super.noSuchMethod(Invocation.getter(#endOfFrame), + returnValue: Future.value()) as _i8.Future); + @override + bool get hasScheduledFrame => + (super.noSuchMethod(Invocation.getter(#hasScheduledFrame), + returnValue: false) as bool); + @override + _i9.SchedulerPhase get schedulerPhase => + (super.noSuchMethod(Invocation.getter(#schedulerPhase), + returnValue: _i9.SchedulerPhase.idle) as _i9.SchedulerPhase); + @override + Duration get currentFrameTimeStamp => + (super.noSuchMethod(Invocation.getter(#currentFrameTimeStamp), + returnValue: _FakeDuration_8()) as Duration); + @override + Duration get currentSystemFrameTimeStamp => + (super.noSuchMethod(Invocation.getter(#currentSystemFrameTimeStamp), + returnValue: _FakeDuration_8()) as Duration); + @override + _i6.PointerRouter get pointerRouter => + (super.noSuchMethod(Invocation.getter(#pointerRouter), + returnValue: _FakePointerRouter_9()) as _i6.PointerRouter); + @override + _i6.GestureArenaManager get gestureArena => (super.noSuchMethod( + Invocation.getter(#gestureArena), + returnValue: _FakeGestureArenaManager_10()) as _i6.GestureArenaManager); + @override + _i6.PointerSignalResolver get pointerSignalResolver => + (super.noSuchMethod(Invocation.getter(#pointerSignalResolver), + returnValue: _FakePointerSignalResolver_11()) + as _i6.PointerSignalResolver); + @override + bool get resamplingEnabled => + (super.noSuchMethod(Invocation.getter(#resamplingEnabled), + returnValue: false) as bool); + @override + set resamplingEnabled(bool? _resamplingEnabled) => super.noSuchMethod( + Invocation.setter(#resamplingEnabled, _resamplingEnabled), + returnValueForMissingStub: null); + @override + Duration get samplingOffset => + (super.noSuchMethod(Invocation.getter(#samplingOffset), + returnValue: _FakeDuration_8()) as Duration); + @override + set samplingOffset(Duration? _samplingOffset) => + super.noSuchMethod(Invocation.setter(#samplingOffset, _samplingOffset), + returnValueForMissingStub: null); + @override + _i3.MouseTracker get mouseTracker => + (super.noSuchMethod(Invocation.getter(#mouseTracker), + returnValue: _FakeMouseTracker_12()) as _i3.MouseTracker); + @override + _i3.PipelineOwner get pipelineOwner => + (super.noSuchMethod(Invocation.getter(#pipelineOwner), + returnValue: _FakePipelineOwner_13()) as _i3.PipelineOwner); + @override + _i3.RenderView get renderView => + (super.noSuchMethod(Invocation.getter(#renderView), + returnValue: _FakeRenderView_14()) as _i3.RenderView); + @override + set renderView(_i3.RenderView? value) => + super.noSuchMethod(Invocation.setter(#renderView, value), + returnValueForMissingStub: null); + @override + bool get sendFramesToEngine => + (super.noSuchMethod(Invocation.getter(#sendFramesToEngine), + returnValue: false) as bool); + @override + _i4.AccessibilityFeatures get accessibilityFeatures => + (super.noSuchMethod(Invocation.getter(#accessibilityFeatures), + returnValue: _FakeAccessibilityFeatures_15()) + as _i4.AccessibilityFeatures); + @override + bool get disableAnimations => + (super.noSuchMethod(Invocation.getter(#disableAnimations), + returnValue: false) as bool); + @override + void initInstances() => + super.noSuchMethod(Invocation.method(#initInstances, []), + returnValueForMissingStub: null); + @override + void initServiceExtensions() => + super.noSuchMethod(Invocation.method(#initServiceExtensions, []), + returnValueForMissingStub: null); + @override + void addObserver(_i7.WidgetsBindingObserver? observer) => + super.noSuchMethod(Invocation.method(#addObserver, [observer]), + returnValueForMissingStub: null); + @override + bool removeObserver(_i7.WidgetsBindingObserver? observer) => + (super.noSuchMethod(Invocation.method(#removeObserver, [observer]), + returnValue: false) as bool); + @override + void handleMetricsChanged() => + super.noSuchMethod(Invocation.method(#handleMetricsChanged, []), + returnValueForMissingStub: null); + @override + void handleTextScaleFactorChanged() => + super.noSuchMethod(Invocation.method(#handleTextScaleFactorChanged, []), + returnValueForMissingStub: null); + @override + void handlePlatformBrightnessChanged() => super.noSuchMethod( + Invocation.method(#handlePlatformBrightnessChanged, []), + returnValueForMissingStub: null); + @override + void handleAccessibilityFeaturesChanged() => super.noSuchMethod( + Invocation.method(#handleAccessibilityFeaturesChanged, []), + returnValueForMissingStub: null); + @override + void handleLocaleChanged() => + super.noSuchMethod(Invocation.method(#handleLocaleChanged, []), + returnValueForMissingStub: null); + @override + void dispatchLocalesChanged(List<_i4.Locale>? locales) => + super.noSuchMethod(Invocation.method(#dispatchLocalesChanged, [locales]), + returnValueForMissingStub: null); + @override + void dispatchAccessibilityFeaturesChanged() => super.noSuchMethod( + Invocation.method(#dispatchAccessibilityFeaturesChanged, []), + returnValueForMissingStub: null); + @override + _i8.Future handlePopRoute() => + (super.noSuchMethod(Invocation.method(#handlePopRoute, []), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i8.Future); + @override + _i8.Future handlePushRoute(String? route) => + (super.noSuchMethod(Invocation.method(#handlePushRoute, [route]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i8.Future); + @override + void handleAppLifecycleStateChanged(_i4.AppLifecycleState? state) => super + .noSuchMethod(Invocation.method(#handleAppLifecycleStateChanged, [state]), + returnValueForMissingStub: null); + @override + void handleMemoryPressure() => + super.noSuchMethod(Invocation.method(#handleMemoryPressure, []), + returnValueForMissingStub: null); + @override + void drawFrame() => super.noSuchMethod(Invocation.method(#drawFrame, []), + returnValueForMissingStub: null); + @override + void scheduleAttachRootWidget(_i10.Widget? rootWidget) => super.noSuchMethod( + Invocation.method(#scheduleAttachRootWidget, [rootWidget]), + returnValueForMissingStub: null); + @override + void attachRootWidget(_i10.Widget? rootWidget) => + super.noSuchMethod(Invocation.method(#attachRootWidget, [rootWidget]), + returnValueForMissingStub: null); + @override + _i8.Future performReassemble() => + (super.noSuchMethod(Invocation.method(#performReassemble, []), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i8.Future); + @override + _i4.Locale? computePlatformResolvedLocale( + List<_i4.Locale>? supportedLocales) => + (super.noSuchMethod(Invocation.method( + #computePlatformResolvedLocale, [supportedLocales])) as _i4.Locale?); + @override + _i8.Future lockEvents(_i8.Future Function()? callback) => + (super.noSuchMethod(Invocation.method(#lockEvents, [callback]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i8.Future); + @override + void unlocked() => super.noSuchMethod(Invocation.method(#unlocked, []), + returnValueForMissingStub: null); + @override + _i8.Future reassembleApplication() => + (super.noSuchMethod(Invocation.method(#reassembleApplication, []), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i8.Future); + @override + void registerSignalServiceExtension( + {String? name, _i11.AsyncCallback? callback}) => + super.noSuchMethod( + Invocation.method(#registerSignalServiceExtension, [], + {#name: name, #callback: callback}), + returnValueForMissingStub: null); + @override + void registerBoolServiceExtension( + {String? name, + _i11.AsyncValueGetter? getter, + _i11.AsyncValueSetter? setter}) => + super.noSuchMethod( + Invocation.method(#registerBoolServiceExtension, [], + {#name: name, #getter: getter, #setter: setter}), + returnValueForMissingStub: null); + @override + void registerNumericServiceExtension( + {String? name, + _i11.AsyncValueGetter? getter, + _i11.AsyncValueSetter? setter}) => + super.noSuchMethod( + Invocation.method(#registerNumericServiceExtension, [], + {#name: name, #getter: getter, #setter: setter}), + returnValueForMissingStub: null); + @override + void postEvent(String? eventKind, Map? eventData) => + super.noSuchMethod(Invocation.method(#postEvent, [eventKind, eventData]), + returnValueForMissingStub: null); + @override + void registerStringServiceExtension( + {String? name, + _i11.AsyncValueGetter? getter, + _i11.AsyncValueSetter? setter}) => + super.noSuchMethod( + Invocation.method(#registerStringServiceExtension, [], + {#name: name, #getter: getter, #setter: setter}), + returnValueForMissingStub: null); + @override + void registerServiceExtension( + {String? name, _i11.ServiceExtensionCallback? callback}) => + super.noSuchMethod( + Invocation.method(#registerServiceExtension, [], + {#name: name, #callback: callback}), + returnValueForMissingStub: null); + @override + _i5.BinaryMessenger createBinaryMessenger() => + (super.noSuchMethod(Invocation.method(#createBinaryMessenger, []), + returnValue: _FakeBinaryMessenger_5()) as _i5.BinaryMessenger); + @override + _i8.Future handleSystemMessage(Object? systemMessage) => (super + .noSuchMethod(Invocation.method(#handleSystemMessage, [systemMessage]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i8.Future); + @override + void initLicenses() => + super.noSuchMethod(Invocation.method(#initLicenses, []), + returnValueForMissingStub: null); + @override + void evict(String? asset) => + super.noSuchMethod(Invocation.method(#evict, [asset]), + returnValueForMissingStub: null); + @override + void readInitialLifecycleStateFromNativeWindow() => super.noSuchMethod( + Invocation.method(#readInitialLifecycleStateFromNativeWindow, []), + returnValueForMissingStub: null); + @override + _i5.RestorationManager createRestorationManager() => + (super.noSuchMethod(Invocation.method(#createRestorationManager, []), + returnValue: _FakeRestorationManager_7()) as _i5.RestorationManager); + @override + void setSystemUiChangeCallback(_i5.SystemUiChangeCallback? callback) => super + .noSuchMethod(Invocation.method(#setSystemUiChangeCallback, [callback]), + returnValueForMissingStub: null); + @override + void addTimingsCallback(_i4.TimingsCallback? callback) => + super.noSuchMethod(Invocation.method(#addTimingsCallback, [callback]), + returnValueForMissingStub: null); + @override + void removeTimingsCallback(_i4.TimingsCallback? callback) => + super.noSuchMethod(Invocation.method(#removeTimingsCallback, [callback]), + returnValueForMissingStub: null); + @override + _i8.Future scheduleTask( + _i9.TaskCallback? task, _i9.Priority? priority, + {String? debugLabel, _i12.Flow? flow}) => + (super.noSuchMethod( + Invocation.method(#scheduleTask, [task, priority], + {#debugLabel: debugLabel, #flow: flow}), + returnValue: Future.value(null)) as _i8.Future); + @override + bool handleEventLoopCallback() => + (super.noSuchMethod(Invocation.method(#handleEventLoopCallback, []), + returnValue: false) as bool); + @override + int scheduleFrameCallback(_i9.FrameCallback? callback, + {bool? rescheduling = false}) => + (super.noSuchMethod( + Invocation.method(#scheduleFrameCallback, [callback], + {#rescheduling: rescheduling}), + returnValue: 0) as int); + @override + void cancelFrameCallbackWithId(int? id) => + super.noSuchMethod(Invocation.method(#cancelFrameCallbackWithId, [id]), + returnValueForMissingStub: null); + @override + bool debugAssertNoTransientCallbacks(String? reason) => (super.noSuchMethod( + Invocation.method(#debugAssertNoTransientCallbacks, [reason]), + returnValue: false) as bool); + @override + void addPersistentFrameCallback(_i9.FrameCallback? callback) => super + .noSuchMethod(Invocation.method(#addPersistentFrameCallback, [callback]), + returnValueForMissingStub: null); + @override + void addPostFrameCallback(_i9.FrameCallback? callback) => + super.noSuchMethod(Invocation.method(#addPostFrameCallback, [callback]), + returnValueForMissingStub: null); + @override + void ensureFrameCallbacksRegistered() => + super.noSuchMethod(Invocation.method(#ensureFrameCallbacksRegistered, []), + returnValueForMissingStub: null); + @override + void ensureVisualUpdate() => + super.noSuchMethod(Invocation.method(#ensureVisualUpdate, []), + returnValueForMissingStub: null); + @override + void scheduleFrame() => + super.noSuchMethod(Invocation.method(#scheduleFrame, []), + returnValueForMissingStub: null); + @override + void scheduleForcedFrame() => + super.noSuchMethod(Invocation.method(#scheduleForcedFrame, []), + returnValueForMissingStub: null); + @override + void scheduleWarmUpFrame() => + super.noSuchMethod(Invocation.method(#scheduleWarmUpFrame, []), + returnValueForMissingStub: null); + @override + void resetEpoch() => super.noSuchMethod(Invocation.method(#resetEpoch, []), + returnValueForMissingStub: null); + @override + void handleBeginFrame(Duration? rawTimeStamp) => + super.noSuchMethod(Invocation.method(#handleBeginFrame, [rawTimeStamp]), + returnValueForMissingStub: null); + @override + void handleDrawFrame() => + super.noSuchMethod(Invocation.method(#handleDrawFrame, []), + returnValueForMissingStub: null); + @override + void cancelPointer(int? pointer) => + super.noSuchMethod(Invocation.method(#cancelPointer, [pointer]), + returnValueForMissingStub: null); + @override + void handlePointerEvent(_i3.PointerEvent? event) => + super.noSuchMethod(Invocation.method(#handlePointerEvent, [event]), + returnValueForMissingStub: null); + @override + void hitTest(_i3.HitTestResult? result, _i4.Offset? position) => + super.noSuchMethod(Invocation.method(#hitTest, [result, position]), + returnValueForMissingStub: null); + @override + void dispatchEvent( + _i3.PointerEvent? event, _i3.HitTestResult? hitTestResult) => + super.noSuchMethod( + Invocation.method(#dispatchEvent, [event, hitTestResult]), + returnValueForMissingStub: null); + @override + void handleEvent(_i3.PointerEvent? event, _i3.HitTestEntry? entry) => + super.noSuchMethod(Invocation.method(#handleEvent, [event, entry]), + returnValueForMissingStub: null); + @override + void resetGestureBinding() => + super.noSuchMethod(Invocation.method(#resetGestureBinding, []), + returnValueForMissingStub: null); + @override + void initRenderView() => + super.noSuchMethod(Invocation.method(#initRenderView, []), + returnValueForMissingStub: null); + @override + _i3.ViewConfiguration createViewConfiguration() => + (super.noSuchMethod(Invocation.method(#createViewConfiguration, []), + returnValue: _FakeViewConfiguration_16()) as _i3.ViewConfiguration); + @override + void initMouseTracker([_i3.MouseTracker? tracker]) => + super.noSuchMethod(Invocation.method(#initMouseTracker, [tracker]), + returnValueForMissingStub: null); + @override + void setSemanticsEnabled(bool? enabled) => + super.noSuchMethod(Invocation.method(#setSemanticsEnabled, [enabled]), + returnValueForMissingStub: null); + @override + void deferFirstFrame() => + super.noSuchMethod(Invocation.method(#deferFirstFrame, []), + returnValueForMissingStub: null); + @override + void allowFirstFrame() => + super.noSuchMethod(Invocation.method(#allowFirstFrame, []), + returnValueForMissingStub: null); + @override + void resetFirstFrameSent() => + super.noSuchMethod(Invocation.method(#resetFirstFrameSent, []), + returnValueForMissingStub: null); + @override + _i4.SemanticsUpdateBuilder createSemanticsUpdateBuilder() => + (super.noSuchMethod(Invocation.method(#createSemanticsUpdateBuilder, []), + returnValue: _FakeSemanticsUpdateBuilder_17()) + as _i4.SemanticsUpdateBuilder); +} + +/// A class which mocks [FrameTiming]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockFrameTiming extends _i1.Mock implements _i4.FrameTiming { + MockFrameTiming() { + _i1.throwOnMissingStub(this); + } + + @override + Duration get buildDuration => + (super.noSuchMethod(Invocation.getter(#buildDuration), + returnValue: _FakeDuration_8()) as Duration); + @override + Duration get rasterDuration => + (super.noSuchMethod(Invocation.getter(#rasterDuration), + returnValue: _FakeDuration_8()) as Duration); + @override + Duration get vsyncOverhead => + (super.noSuchMethod(Invocation.getter(#vsyncOverhead), + returnValue: _FakeDuration_8()) as Duration); + @override + Duration get totalSpan => (super.noSuchMethod(Invocation.getter(#totalSpan), + returnValue: _FakeDuration_8()) as Duration); + @override + int get layerCacheCount => + (super.noSuchMethod(Invocation.getter(#layerCacheCount), returnValue: 0) + as int); + @override + int get layerCacheBytes => + (super.noSuchMethod(Invocation.getter(#layerCacheBytes), returnValue: 0) + as int); + @override + double get layerCacheMegabytes => + (super.noSuchMethod(Invocation.getter(#layerCacheMegabytes), + returnValue: 0.0) as double); + @override + int get pictureCacheCount => + (super.noSuchMethod(Invocation.getter(#pictureCacheCount), returnValue: 0) + as int); + @override + int get pictureCacheBytes => + (super.noSuchMethod(Invocation.getter(#pictureCacheBytes), returnValue: 0) + as int); + @override + double get pictureCacheMegabytes => + (super.noSuchMethod(Invocation.getter(#pictureCacheMegabytes), + returnValue: 0.0) as double); + @override + int get frameNumber => + (super.noSuchMethod(Invocation.getter(#frameNumber), returnValue: 0) + as int); + @override + int timestampInMicroseconds(_i4.FramePhase? phase) => + (super.noSuchMethod(Invocation.method(#timestampInMicroseconds, [phase]), + returnValue: 0) as int); +} + +/// A class which mocks [ApmHostApi]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockApmHostApi extends _i1.Mock implements _i13.ApmHostApi { + MockApmHostApi() { + _i1.throwOnMissingStub(this); + } + + @override + _i8.Future setEnabled(bool? arg_isEnabled) => + (super.noSuchMethod(Invocation.method(#setEnabled, [arg_isEnabled]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i8.Future); + @override + _i8.Future isEnabled() => + (super.noSuchMethod(Invocation.method(#isEnabled, []), + returnValue: Future.value(false)) as _i8.Future); + @override + _i8.Future setScreenLoadingEnabled(bool? arg_isEnabled) => + (super.noSuchMethod( + Invocation.method(#setScreenLoadingEnabled, [arg_isEnabled]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i8.Future); + @override + _i8.Future isScreenLoadingEnabled() => + (super.noSuchMethod(Invocation.method(#isScreenLoadingEnabled, []), + returnValue: Future.value(false)) as _i8.Future); + @override + _i8.Future setColdAppLaunchEnabled(bool? arg_isEnabled) => + (super.noSuchMethod( + Invocation.method(#setColdAppLaunchEnabled, [arg_isEnabled]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i8.Future); + @override + _i8.Future setAutoUITraceEnabled(bool? arg_isEnabled) => (super + .noSuchMethod(Invocation.method(#setAutoUITraceEnabled, [arg_isEnabled]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i8.Future); + @override + _i8.Future startFlow(String? arg_name) => + (super.noSuchMethod(Invocation.method(#startFlow, [arg_name]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i8.Future); + @override + _i8.Future setFlowAttribute( + String? arg_name, String? arg_key, String? arg_value) => + (super.noSuchMethod( + Invocation.method(#setFlowAttribute, [arg_name, arg_key, arg_value]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i8.Future); + @override + _i8.Future endFlow(String? arg_name) => + (super.noSuchMethod(Invocation.method(#endFlow, [arg_name]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i8.Future); + @override + _i8.Future startUITrace(String? arg_name) => + (super.noSuchMethod(Invocation.method(#startUITrace, [arg_name]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i8.Future); + @override + _i8.Future endUITrace() => + (super.noSuchMethod(Invocation.method(#endUITrace, []), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i8.Future); + @override + _i8.Future endAppLaunch() => + (super.noSuchMethod(Invocation.method(#endAppLaunch, []), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i8.Future); + @override + _i8.Future networkLogAndroid(Map? arg_data) => + (super.noSuchMethod(Invocation.method(#networkLogAndroid, [arg_data]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i8.Future); + @override + _i8.Future startCpUiTrace( + String? arg_screenName, int? arg_microTimeStamp, int? arg_traceId) => + (super.noSuchMethod( + Invocation.method(#startCpUiTrace, + [arg_screenName, arg_microTimeStamp, arg_traceId]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i8.Future); + @override + _i8.Future reportScreenLoadingCP(int? arg_startTimeStampMicro, + int? arg_durationMicro, int? arg_uiTraceId) => + (super.noSuchMethod( + Invocation.method(#reportScreenLoadingCP, + [arg_startTimeStampMicro, arg_durationMicro, arg_uiTraceId]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i8.Future); + @override + _i8.Future endScreenLoadingCP( + int? arg_timeStampMicro, int? arg_uiTraceId) => + (super.noSuchMethod( + Invocation.method( + #endScreenLoadingCP, [arg_timeStampMicro, arg_uiTraceId]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i8.Future); + @override + _i8.Future isEndScreenLoadingEnabled() => + (super.noSuchMethod(Invocation.method(#isEndScreenLoadingEnabled, []), + returnValue: Future.value(false)) as _i8.Future); + @override + _i8.Future isScreenRenderEnabled() => + (super.noSuchMethod(Invocation.method(#isScreenRenderEnabled, []), + returnValue: Future.value(false)) as _i8.Future); + @override + _i8.Future> getDeviceRefreshRateAndTolerance() => + (super.noSuchMethod( + Invocation.method(#getDeviceRefreshRateAndTolerance, []), + returnValue: Future>.value([])) + as _i8.Future>); + @override + _i8.Future setScreenRenderEnabled(bool? arg_isEnabled) => (super + .noSuchMethod(Invocation.method(#setScreenRenderEnabled, [arg_isEnabled]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i8.Future); + @override + _i8.Future endScreenRenderForAutoUiTrace( + Map? arg_data) => + (super.noSuchMethod( + Invocation.method(#endScreenRenderForAutoUiTrace, [arg_data]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i8.Future); + @override + _i8.Future endScreenRenderForCustomUiTrace( + Map? arg_data) => + (super.noSuchMethod( + Invocation.method(#endScreenRenderForCustomUiTrace, [arg_data]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i8.Future); +} + +/// A class which mocks [CrashReportingHostApi]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockCrashReportingHostApi extends _i1.Mock + implements _i14.CrashReportingHostApi { + MockCrashReportingHostApi() { + _i1.throwOnMissingStub(this); + } + + @override + _i8.Future setEnabled(bool? arg_isEnabled) => + (super.noSuchMethod(Invocation.method(#setEnabled, [arg_isEnabled]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i8.Future); + @override + _i8.Future send(String? arg_jsonCrash, bool? arg_isHandled) => (super + .noSuchMethod(Invocation.method(#send, [arg_jsonCrash, arg_isHandled]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i8.Future); + @override + _i8.Future sendNonFatalError( + String? arg_jsonCrash, + Map? arg_userAttributes, + String? arg_fingerprint, + String? arg_nonFatalExceptionLevel) => + (super.noSuchMethod( + Invocation.method(#sendNonFatalError, [ + arg_jsonCrash, + arg_userAttributes, + arg_fingerprint, + arg_nonFatalExceptionLevel + ]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i8.Future); +} + +/// A class which mocks [InstabugLogger]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockInstabugLogger extends _i1.Mock implements _i15.InstabugLogger { + MockInstabugLogger() { + _i1.throwOnMissingStub(this); + } + + @override + set logLevel(_i16.LogLevel? level) => + super.noSuchMethod(Invocation.setter(#logLevel, level), + returnValueForMissingStub: null); + @override + void log(String? message, {_i16.LogLevel? level, String? tag = r''}) => + super.noSuchMethod( + Invocation.method(#log, [message], {#level: level, #tag: tag}), + returnValueForMissingStub: null); + @override + void e(String? message, {String? tag = r''}) => + super.noSuchMethod(Invocation.method(#e, [message], {#tag: tag}), + returnValueForMissingStub: null); + @override + void d(String? message, {String? tag = r''}) => + super.noSuchMethod(Invocation.method(#d, [message], {#tag: tag}), + returnValueForMissingStub: null); + @override + void v(String? message, {String? tag = r''}) => + super.noSuchMethod(Invocation.method(#v, [message], {#tag: tag}), + returnValueForMissingStub: null); +} From 7244bcc59e09729dd50d239c5a7b9d4faa3f3d83 Mon Sep 17 00:00:00 2001 From: Andrew Amin Date: Tue, 12 Aug 2025 17:05:42 +0300 Subject: [PATCH 65/84] chore: remove logs --- lib/src/utils/instabug_navigator_observer.dart | 2 -- .../instabug_screen_render_manager.dart | 15 --------------- 2 files changed, 17 deletions(-) diff --git a/lib/src/utils/instabug_navigator_observer.dart b/lib/src/utils/instabug_navigator_observer.dart index b20b56b89..8272c66ab 100644 --- a/lib/src/utils/instabug_navigator_observer.dart +++ b/lib/src/utils/instabug_navigator_observer.dart @@ -1,5 +1,4 @@ import 'dart:async'; -import 'dart:developer'; import 'package:flutter/material.dart'; import 'package:instabug_flutter/instabug_flutter.dart'; @@ -69,7 +68,6 @@ class InstabugNavigatorObserver extends NavigatorObserver { FutureOr _startScreenRenderCollector(int? uiTraceId) async { final isScreenRenderEnabled = await FlagsConfig.screenRendering.isEnabled(); - log("isScreenRenderEnabled $isScreenRenderEnabled", name: "Andrew"); await _checkForScreenRenderInitialization(isScreenRenderEnabled); if (uiTraceId != null && isScreenRenderEnabled) { InstabugScreenRenderManager.I diff --git a/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart b/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart index 5bff74279..718c9b473 100644 --- a/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart +++ b/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart @@ -1,5 +1,4 @@ import 'dart:async'; -import 'dart:developer' show log; import 'dart:ui' show TimingsCallback, FrameTiming, FramePhase; import 'package:flutter/widgets.dart'; @@ -41,8 +40,6 @@ class InstabugScreenRenderManager { /// Default frozen frame threshold in milliseconds (700ms) final _frozenFrameThresholdMs = 700; - // final _microsecondsPerMillisecond = 1000; - InstabugScreenRenderManager._(); static InstabugScreenRenderManager _instance = @@ -304,10 +301,6 @@ class InstabugScreenRenderManager { /// Save Slow/Frozen Frames data void _onDelayedFrameDetected(int startTime, int durationInMicroseconds) { - log( - "${durationInMicroseconds >= 700000 ? "🚨Frozen" : "⚠️Slow"} Frame Detected (startTime: $startTime, duration: $durationInMicroseconds µs)", - name: tag, - ); _delayedFrames.add( InstabugFrameData( startTime, @@ -324,10 +317,6 @@ class InstabugScreenRenderManager { ) async { try { screenRenderData.saveEndTime(); - log( - "reportScreenRenderForCustomUiTrace $screenRenderData", - name: tag, - ); await APM.endScreenRenderForCustomUiTrace(screenRenderData); return true; } catch (error, stackTrace) { @@ -345,10 +334,6 @@ class InstabugScreenRenderManager { try { // Save the end time for the running ui trace, it's only needed in Android SDK. screenRenderData.saveEndTime(); - log( - "reportScreenRenderForAutoUiTrace $screenRenderData", - name: tag, - ); await APM.endScreenRenderForAutoUiTrace(screenRenderData); return true; From cb85eda8961fbb9d983e6d1c625b0facf8ddd7cf Mon Sep 17 00:00:00 2001 From: ahmed alaa <154802748+ahmedAlaaInstabug@users.noreply.github.com> Date: Wed, 13 Aug 2025 12:07:15 +0300 Subject: [PATCH 66/84] feat: support app variant (#585) * feat: app variant * feat: app variant * feat: app variant * feat: app variant --- CHANGELOG.md | 2 + .../instabug/flutter/modules/InstabugApi.java | 44 ++++++++++++++----- .../com/instabug/flutter/InstabugApiTest.java | 14 +++++- example/ios/InstabugTests/InstabugApiTests.m | 9 +++- example/ios/Podfile | 1 - example/lib/main.dart | 8 ++-- ios/Classes/Modules/InstabugApi.m | 19 +++++++- lib/src/modules/instabug.dart | 11 +++++ pigeons/instabug.api.dart | 32 +++++++++++++- test/instabug_test.dart | 2 +- 10 files changed, 119 insertions(+), 23 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9cb867f5c..c45d3e5a9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ ### Added +- Add support for App variant. ([#585](https://github.com/Instabug/Instabug-Flutter/pull/585)) + - Add support for xCode 16. ([#574](https://github.com/Instabug/Instabug-Flutter/pull/574)) - Add support for BugReporting user consents. ([#573](https://github.com/Instabug/Instabug-Flutter/pull/573)) diff --git a/android/src/main/java/com/instabug/flutter/modules/InstabugApi.java b/android/src/main/java/com/instabug/flutter/modules/InstabugApi.java index edfde055a..35455237d 100644 --- a/android/src/main/java/com/instabug/flutter/modules/InstabugApi.java +++ b/android/src/main/java/com/instabug/flutter/modules/InstabugApi.java @@ -6,9 +6,11 @@ import android.graphics.BitmapFactory; import android.net.Uri; import android.util.Log; + import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; + import com.instabug.flutter.generated.InstabugPigeon; import com.instabug.flutter.util.ArgsRegistry; import com.instabug.flutter.util.Reflection; @@ -30,9 +32,11 @@ import com.instabug.library.invocation.InstabugInvocationEvent; import com.instabug.library.model.NetworkLog; import com.instabug.library.ui.onboarding.WelcomeMessage; + import io.flutter.FlutterInjector; import io.flutter.embedding.engine.loader.FlutterLoader; import io.flutter.plugin.common.BinaryMessenger; + import org.jetbrains.annotations.NotNull; import org.json.JSONObject; @@ -102,10 +106,12 @@ public Boolean isEnabled() { @NotNull @Override - public Boolean isBuilt() { return Instabug.isBuilt(); } + public Boolean isBuilt() { + return Instabug.isBuilt(); + } @Override - public void init(@NonNull String token, @NonNull List invocationEvents, @NonNull String debugLogsLevel) { + public void init(@NonNull String token, @NonNull List invocationEvents, @NonNull String debugLogsLevel, @Nullable String appVariant) { setCurrentPlatform(); InstabugInvocationEvent[] invocationEventsArray = new InstabugInvocationEvent[invocationEvents.size()]; @@ -116,11 +122,14 @@ public void init(@NonNull String token, @NonNull List invocationEvents, final Application application = (Application) context; final int parsedLogLevel = ArgsRegistry.sdkLogLevels.get(debugLogsLevel); - - new Instabug.Builder(application, token) + Instabug.Builder builder = new Instabug.Builder(application, token) .setInvocationEvents(invocationEventsArray) - .setSdkDebugLogsLevel(parsedLogLevel) - .build(); + .setSdkDebugLogsLevel(parsedLogLevel); + if (appVariant != null) { + builder.setAppVariant(appVariant); + } + + builder.build(); Instabug.setScreenshotProvider(screenshotProvider); } @@ -146,6 +155,17 @@ public void setUserData(@NonNull String data) { Instabug.setUserData(data); } + @Override + public void setAppVariant(@NonNull String appVariant) { + try { + Instabug.setAppVariant(appVariant); + + } catch (Exception e) { + e.printStackTrace(); + } + + } + @Override public void logUserEvent(@NonNull String name) { Instabug.logUserEvent(name); @@ -500,13 +520,13 @@ public void willRedirectToStore() { Instabug.willRedirectToStore(); } - + @Override public void setNetworkLogBodyEnabled(@NonNull Boolean isEnabled) { - try { - Instabug.setNetworkLogBodyEnabled(isEnabled); - } catch (Exception e) { - e.printStackTrace(); - } + try { + Instabug.setNetworkLogBodyEnabled(isEnabled); + } catch (Exception e) { + e.printStackTrace(); + } } } diff --git a/android/src/test/java/com/instabug/flutter/InstabugApiTest.java b/android/src/test/java/com/instabug/flutter/InstabugApiTest.java index 97b9cdf7b..7efb8e425 100644 --- a/android/src/test/java/com/instabug/flutter/InstabugApiTest.java +++ b/android/src/test/java/com/instabug/flutter/InstabugApiTest.java @@ -132,6 +132,8 @@ public void testSetCurrentPlatform() { @Test public void testSdkInit() { String token = "app-token"; + String appVariant = "app-variant"; + List invocationEvents = Collections.singletonList("InvocationEvent.floatingButton"); String logLevel = "LogLevel.error"; @@ -143,7 +145,7 @@ public void testSdkInit() { when(mock.setSdkDebugLogsLevel(anyInt())).thenReturn(mock); }); - api.init(token, invocationEvents, logLevel); + api.init(token, invocationEvents, logLevel,appVariant); Instabug.Builder builder = mInstabugBuilder.constructed().get(0); @@ -155,6 +157,8 @@ public void testSdkInit() { ); verify(builder).setInvocationEvents(InstabugInvocationEvent.FLOATING_BUTTON); verify(builder).setSdkDebugLogsLevel(LogLevel.ERROR); + verify(builder).setAppVariant(appVariant); + verify(builder).build(); // Sets screenshot provider @@ -652,6 +656,14 @@ public void testSetNetworkLogBodyEnabled() { mInstabug.verify(() -> Instabug.setNetworkLogBodyEnabled(true)); } + @Test + public void testSetAppVariant() { + String appVariant = "app-variant"; + api.setAppVariant(appVariant); + + mInstabug.verify(() -> Instabug.setAppVariant(appVariant)); + } + @Test public void testSetNetworkLogBodyDisabled() { api.setNetworkLogBodyEnabled(false); diff --git a/example/ios/InstabugTests/InstabugApiTests.m b/example/ios/InstabugTests/InstabugApiTests.m index 9f2c04373..3cbcc13f0 100644 --- a/example/ios/InstabugTests/InstabugApiTests.m +++ b/example/ios/InstabugTests/InstabugApiTests.m @@ -38,15 +38,22 @@ - (void)testSetEnabled { - (void)testInit { NSString *token = @"app-token"; + NSString *appVariant = @"app-variant"; + NSArray *invocationEvents = @[@"InvocationEvent.floatingButton", @"InvocationEvent.screenshot"]; NSString *logLevel = @"LogLevel.error"; FlutterError *error; - [self.api initToken:token invocationEvents:invocationEvents debugLogsLevel:logLevel error:&error]; + [self.api initToken:token invocationEvents:invocationEvents debugLogsLevel:logLevel appVariant:appVariant error:&error]; OCMVerify([self.mInstabug setCurrentPlatform:IBGPlatformFlutter]); + OCMVerify([self.mInstabug setSdkDebugLogsLevel:IBGSDKDebugLogsLevelError]); + OCMVerify([self.mInstabug startWithToken:token invocationEvents:(IBGInvocationEventFloatingButton | IBGInvocationEventScreenshot)]); + + XCTAssertEqual(Instabug.appVariant, appVariant); + } - (void)testShow { diff --git a/example/ios/Podfile b/example/ios/Podfile index 00756a1dd..bf8d827c6 100644 --- a/example/ios/Podfile +++ b/example/ios/Podfile @@ -30,7 +30,6 @@ target 'Runner' do use_frameworks! use_modular_headers! - flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) end diff --git a/example/lib/main.dart b/example/lib/main.dart index 91b0a67e7..1052d42c8 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -48,10 +48,10 @@ void main() { WidgetsFlutterBinding.ensureInitialized(); Instabug.init( - token: 'ed6f659591566da19b67857e1b9d40ab', - invocationEvents: [InvocationEvent.floatingButton], - debugLogsLevel: LogLevel.verbose, - ); + token: 'ed6f659591566da19b67857e1b9d40ab', + invocationEvents: [InvocationEvent.floatingButton], + debugLogsLevel: LogLevel.verbose, + appVariant: 'variant 1'); FlutterError.onError = (FlutterErrorDetails details) { Zone.current.handleUncaughtError(details.exception, details.stack!); diff --git a/ios/Classes/Modules/InstabugApi.m b/ios/Classes/Modules/InstabugApi.m index 3bdc465f0..edced7a05 100644 --- a/ios/Classes/Modules/InstabugApi.m +++ b/ios/Classes/Modules/InstabugApi.m @@ -29,7 +29,13 @@ - (nullable NSNumber *)isEnabledWithError:(FlutterError * _Nullable __autoreleas return @(Instabug.enabled); } -- (void)initToken:(NSString *)token invocationEvents:(NSArray *)invocationEvents debugLogsLevel:(NSString *)debugLogsLevel error:(FlutterError *_Nullable *_Nonnull)error { +- (void)initToken:(nonnull NSString *)token invocationEvents:(nonnull NSArray *)invocationEvents debugLogsLevel:(nonnull NSString *)debugLogsLevel appVariant:(nullable NSString *)appVariant error:(FlutterError * _Nullable __autoreleasing * _Nonnull)error { + + if(appVariant != nil){ + Instabug.appVariant = appVariant; + } + + SEL setPrivateApiSEL = NSSelectorFromString(@"setCurrentPlatform:"); if ([[Instabug class] respondsToSelector:setPrivateApiSEL]) { NSInteger *platformID = IBGPlatformFlutter; @@ -45,7 +51,8 @@ - (void)initToken:(NSString *)token invocationEvents:(NSArray *)invo [IBGNetworkLogger disableAutomaticCapturingOfNetworkLogs]; IBGInvocationEvent resolvedEvents = 0; - + + for (NSString *event in invocationEvents) { resolvedEvents |= (ArgsRegistry.invocationEvents[event]).integerValue; } @@ -396,4 +403,12 @@ - (void)setNetworkLogBodyEnabledIsEnabled:(NSNumber *)isEnabled IBGNetworkLogger.logBodyEnabled = [isEnabled boolValue]; } + +- (void)setAppVariantAppVariant:(nonnull NSString *)appVariant error:(FlutterError * _Nullable __autoreleasing * _Nonnull)error { + + Instabug.appVariant = appVariant; + +} + + @end diff --git a/lib/src/modules/instabug.dart b/lib/src/modules/instabug.dart index 6bba8ed1f..80726fd7e 100644 --- a/lib/src/modules/instabug.dart +++ b/lib/src/modules/instabug.dart @@ -11,6 +11,7 @@ import 'dart:typed_data'; import 'dart:ui'; import 'package:flutter/material.dart'; + // to maintain supported versions prior to Flutter 3.3 // ignore: unused_import import 'package:flutter/services.dart'; @@ -179,10 +180,12 @@ class Instabug { /// The [token] that identifies the app, you can find it on your dashboard. /// The [invocationEvents] are the events that invoke the SDK's UI. /// The [debugLogsLevel] used to debug Instabug's SDK. + /// The [appVariant] used to set current App variant name. static Future init({ required String token, required List invocationEvents, LogLevel debugLogsLevel = LogLevel.error, + String? appVariant, }) async { $setup(); InstabugLogger.I.logLevel = debugLogsLevel; @@ -190,6 +193,7 @@ class Instabug { token, invocationEvents.mapToString(), debugLogsLevel.toString(), + appVariant, ); return FeatureFlagsManager().registerW3CFlagsListener(); } @@ -482,4 +486,11 @@ class Instabug { static Future willRedirectToStore() async { return _host.willRedirectToStore(); } + + /// This property sets the `appVariant` string to be included in all network requests. + /// It should be set before calling [init] method. + /// [appVariant] used to set current App variant name + static Future setAppVariant(String appVariant) async { + return _host.setAppVariant(appVariant); + } } diff --git a/pigeons/instabug.api.dart b/pigeons/instabug.api.dart index 275306987..6502409cc 100644 --- a/pigeons/instabug.api.dart +++ b/pigeons/instabug.api.dart @@ -12,39 +12,65 @@ abstract class FeatureFlagsFlutterApi { @HostApi() abstract class InstabugHostApi { void setEnabled(bool isEnabled); + bool isEnabled(); + bool isBuilt(); - void init(String token, List invocationEvents, String debugLogsLevel); + + void init( + String token, + List invocationEvents, + String debugLogsLevel, + String? appVariant, + ); void show(); + void showWelcomeMessageWithMode(String mode); void identifyUser(String email, String? name, String? userId); + void setUserData(String data); + + void setAppVariant(String appVariant); + void logUserEvent(String name); + void logOut(); void setLocale(String locale); + void setColorTheme(String theme); + void setWelcomeMessageMode(String mode); + void setPrimaryColor(int color); + void setSessionProfilerEnabled(bool enabled); + void setValueForStringWithKey(String value, String key); void appendTags(List tags); + void resetTags(); @async List? getTags(); void addExperiments(List experiments); + void removeExperiments(List experiments); + void clearAllExperiments(); + void addFeatureFlags(Map featureFlagsMap); + void removeFeatureFlags(List featureFlags); + void removeAllFeatureFlags(); void setUserAttribute(String value, String key); + void removeUserAttribute(String key); @async @@ -58,13 +84,17 @@ abstract class InstabugHostApi { String? crashMode, String? sessionReplayMode, ); + void reportScreenChange(String screenName); void setCustomBrandingImage(String light, String dark); + void setFont(String font); void addFileAttachmentWithURL(String filePath, String fileName); + void addFileAttachmentWithData(Uint8List data, String fileName); + void clearFileAttachments(); void networkLog(Map data); diff --git a/test/instabug_test.dart b/test/instabug_test.dart index e2fd7d298..b6f891221 100644 --- a/test/instabug_test.dart +++ b/test/instabug_test.dart @@ -84,7 +84,7 @@ void main() { ); verify( - mHost.init(token, events.mapToString(), LogLevel.error.toString()), + mHost.init(token, events.mapToString(), LogLevel.error.toString(), null), ).called(1); }); From f9d6d61385f6c152c8ac1722b3ab43c81d93ddb4 Mon Sep 17 00:00:00 2001 From: AyaMahmoud148 Date: Wed, 13 Aug 2025 17:21:50 +0300 Subject: [PATCH 67/84] feat: support advanced UI customization (#599) * feat: support advanced UI customization * chore: add change log * fix: delete setFullScreen * fix: linting * fix: unit test * fix: linting * fix: resolve comments * fix: add full screen function * fix: ios tests * fix: ios tests * chore: remove deprecated apis (#614) * feat: support advanced UI customization * chore: add change log * fix: delete setFullScreen * fix: linting * fix: unit test * fix: linting * fix: resolve comments * chore: remove deprecated apis * chore: add changelog * fix: setTheme calling * fix: formatte * fix: formate * fix: formatting * fix: ios tests * fix: ios tests * fix: e2e tests * fix: formate analyze * fix: e2e ios testing * fix: format --------- Co-authored-by: ahmed alaa <154802748+ahmedAlaaInstabug@users.noreply.github.com> --------- Co-authored-by: ahmed alaa <154802748+ahmedAlaaInstabug@users.noreply.github.com> --- CHANGELOG.md | 14 +- .../com/instabug/flutter/modules/ApmApi.java | 74 +------ .../flutter/modules/BugReportingApi.java | 2 +- .../instabug/flutter/modules/InstabugApi.java | 179 ++++++++++++++-- .../java/com/instabug/flutter/ApmApiTest.java | 57 ----- .../instabug/flutter/BugReportingApiTest.java | 2 +- .../com/instabug/flutter/InstabugApiTest.java | 98 ++++++--- .../InstabugExampleMethodCallHandler.kt | 28 +++ example/ios/InstabugTests/ApmApiTests.m | 67 ------ .../ios/InstabugTests/BugReportingApiTests.m | 4 +- example/ios/InstabugTests/InstabugApiTests.m | 65 +++--- example/lib/main.dart | 2 - .../lib/src/components/traces_content.dart | 157 -------------- ...stabug_flutter_example_method_channel.dart | 17 ++ example/lib/src/screens/apm_page.dart | 2 - example/lib/src/screens/my_home_page.dart | 8 +- example/pubspec.yaml | 4 + ios/Classes/Modules/ApmApi.m | 38 ---- ios/Classes/Modules/BugReportingApi.m | 5 +- ios/Classes/Modules/InstabugApi.m | 194 ++++++++++++++++-- lib/instabug_flutter.dart | 2 +- lib/src/models/theme_config.dart | 121 +++++++++++ lib/src/models/trace.dart | 44 ---- lib/src/modules/apm.dart | 54 ----- lib/src/modules/instabug.dart | 72 ++++--- pigeons/apm.api.dart | 9 - pigeons/instabug.api.dart | 9 +- test/apm_test.dart | 42 ---- test/instabug_test.dart | 71 +++---- test/trace_test.dart | 46 ----- 30 files changed, 725 insertions(+), 762 deletions(-) delete mode 100644 example/lib/src/components/traces_content.dart create mode 100644 lib/src/models/theme_config.dart delete mode 100644 lib/src/models/trace.dart delete mode 100644 test/trace_test.dart diff --git a/CHANGELOG.md b/CHANGELOG.md index c45d3e5a9..0555125f6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,11 +1,23 @@ # Changelog -## [15.0.2](https://github.com/Instabug/Instabug-Flutter/compare/v14.3.0...15.0.2) (Jul 7, 2025) +## [Unreleased](https://github.com/Instabug/Instabug-Flutter/compare/v15.0.2...dev) ### Added +- Add support for Advanced UI customization with comprehensive theming capabilities ([#599](https://github.com/Instabug/Instabug-Flutter/pull/599)) +- - Add support for App variant. ([#585](https://github.com/Instabug/Instabug-Flutter/pull/585)) +### Changed + +- **BREAKING** Remove deprecated APIs ([#614](https://github.com/Instabug/Instabug-Flutter/pull/614)). See migration guide for more details. + + +## [15.0.2](https://github.com/Instabug/Instabug-Flutter/compare/v14.3.0...15.0.2) (Jul 7, 2025) + +### Added + + - Add support for xCode 16. ([#574](https://github.com/Instabug/Instabug-Flutter/pull/574)) - Add support for BugReporting user consents. ([#573](https://github.com/Instabug/Instabug-Flutter/pull/573)) diff --git a/android/src/main/java/com/instabug/flutter/modules/ApmApi.java b/android/src/main/java/com/instabug/flutter/modules/ApmApi.java index 607c569a4..b5ce437da 100644 --- a/android/src/main/java/com/instabug/flutter/modules/ApmApi.java +++ b/android/src/main/java/com/instabug/flutter/modules/ApmApi.java @@ -9,7 +9,6 @@ import com.instabug.apm.InternalAPM; import com.instabug.apm.configuration.cp.APMFeature; import com.instabug.apm.configuration.cp.FeatureAvailabilityCallback; -import com.instabug.apm.model.ExecutionTrace; import com.instabug.apm.networking.APMNetworkLogger; import com.instabug.apm.networkinterception.cp.APMCPNetworkLog; import com.instabug.flutter.generated.ApmPigeon; @@ -26,7 +25,6 @@ public class ApmApi implements ApmPigeon.ApmHostApi { private final String TAG = ApmApi.class.getName(); - private final HashMap traces = new HashMap<>(); public static void init(BinaryMessenger messenger) { final ApmApi api = new ApmApi(); @@ -98,45 +96,7 @@ public void setAutoUITraceEnabled(@NonNull Boolean isEnabled) { * * @deprecated see {@link #startFlow} */ - @Override - public void startExecutionTrace(@NonNull String id, @NonNull String name, ApmPigeon.Result result) { - ThreadManager.runOnBackground( - new Runnable() { - @Override - public void run() { - try { - ExecutionTrace trace = APM.startExecutionTrace(name); - if (trace != null) { - traces.put(id, trace); - - ThreadManager.runOnMainThread(new Runnable() { - @Override - public void run() { - result.success(id); - } - }); - } else { - ThreadManager.runOnMainThread(new Runnable() { - @Override - public void run() { - result.success(null); - } - }); - } - } catch (Exception e) { - e.printStackTrace(); - - ThreadManager.runOnMainThread(new Runnable() { - @Override - public void run() { - result.success(null); - } - }); - } - } - } - ); - } + /** * Starts an AppFlow with the specified name. @@ -201,39 +161,7 @@ public void endFlow(@NonNull String name) { } } - /** - * Adds a new attribute to trace - * - * @param id String id of the trace. - * @param key attribute key - * @param value attribute value. Null to remove attribute - * - * @deprecated see {@link #setFlowAttribute} - */ - @Override - public void setExecutionTraceAttribute(@NonNull String id, @NonNull String key, @NonNull String value) { - try { - traces.get(id).setAttribute(key, value); - } catch (Exception e) { - e.printStackTrace(); - } - } - /** - * Ends a trace - * - * @param id string id of the trace. - * - * @deprecated see {@link #endFlow} - */ - @Override - public void endExecutionTrace(@NonNull String id) { - try { - traces.get(id).end(); - } catch (Exception e) { - e.printStackTrace(); - } - } /** * Starts a UI trace. diff --git a/android/src/main/java/com/instabug/flutter/modules/BugReportingApi.java b/android/src/main/java/com/instabug/flutter/modules/BugReportingApi.java index f3236bb4e..c845de0c1 100644 --- a/android/src/main/java/com/instabug/flutter/modules/BugReportingApi.java +++ b/android/src/main/java/com/instabug/flutter/modules/BugReportingApi.java @@ -184,7 +184,7 @@ public void setCommentMinimumCharacterCount(@NonNull Long limit, @Nullable List< reportTypesArray[i] = ArgsRegistry.reportTypes.get(key); } } - BugReporting.setCommentMinimumCharacterCount(limit.intValue(), reportTypesArray); + BugReporting.setCommentMinimumCharacterCountForBugReportType(limit.intValue(), reportTypesArray); } @Override diff --git a/android/src/main/java/com/instabug/flutter/modules/InstabugApi.java b/android/src/main/java/com/instabug/flutter/modules/InstabugApi.java index 35455237d..0afbbd975 100644 --- a/android/src/main/java/com/instabug/flutter/modules/InstabugApi.java +++ b/android/src/main/java/com/instabug/flutter/modules/InstabugApi.java @@ -5,6 +5,7 @@ import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.net.Uri; +import android.graphics.Typeface; import android.util.Log; import androidx.annotation.NonNull; @@ -196,7 +197,6 @@ public void setWelcomeMessageMode(@NonNull String mode) { @Override public void setPrimaryColor(@NonNull Long color) { - Instabug.setPrimaryColor(color.intValue()); } @Override @@ -248,20 +248,7 @@ public void run() { ); } - @Override - public void addExperiments(@NonNull List experiments) { - Instabug.addExperiments(experiments); - } - @Override - public void removeExperiments(@NonNull List experiments) { - Instabug.removeExperiments(experiments); - } - - @Override - public void clearAllExperiments() { - Instabug.clearAllExperiments(); - } @Override public void addFeatureFlags(@NonNull Map featureFlags) { @@ -529,4 +516,168 @@ public void setNetworkLogBodyEnabled(@NonNull Boolean isEnabled) { e.printStackTrace(); } } + + @Override + public void setTheme(@NonNull Map themeConfig) { + try { + Log.d(TAG, "setTheme called with config: " + themeConfig.toString()); + + com.instabug.library.model.IBGTheme.Builder builder = new com.instabug.library.model.IBGTheme.Builder(); + + if (themeConfig.containsKey("primaryColor")) { + builder.setPrimaryColor(getColor(themeConfig, "primaryColor")); + } + if (themeConfig.containsKey("secondaryTextColor")) { + builder.setSecondaryTextColor(getColor(themeConfig, "secondaryTextColor")); + } + if (themeConfig.containsKey("primaryTextColor")) { + builder.setPrimaryTextColor(getColor(themeConfig, "primaryTextColor")); + } + if (themeConfig.containsKey("titleTextColor")) { + builder.setTitleTextColor(getColor(themeConfig, "titleTextColor")); + } + if (themeConfig.containsKey("backgroundColor")) { + builder.setBackgroundColor(getColor(themeConfig, "backgroundColor")); + } + + if (themeConfig.containsKey("primaryTextStyle")) { + builder.setPrimaryTextStyle(getTextStyle(themeConfig, "primaryTextStyle")); + } + if (themeConfig.containsKey("secondaryTextStyle")) { + builder.setSecondaryTextStyle(getTextStyle(themeConfig, "secondaryTextStyle")); + } + if (themeConfig.containsKey("ctaTextStyle")) { + builder.setCtaTextStyle(getTextStyle(themeConfig, "ctaTextStyle")); + } + + setFontIfPresent(themeConfig, builder, "primaryFontPath", "primaryFontAsset", "primary"); + setFontIfPresent(themeConfig, builder, "secondaryFontPath", "secondaryFontAsset", "secondary"); + setFontIfPresent(themeConfig, builder, "ctaFontPath", "ctaFontAsset", "CTA"); + + com.instabug.library.model.IBGTheme theme = builder.build(); + Instabug.setTheme(theme); + Log.d(TAG, "Theme applied successfully"); + + } catch (Exception e) { + Log.e(TAG, "Error in setTheme: " + e.getMessage()); + e.printStackTrace(); + } + } + + + + /** + * Retrieves a color value from the Map. + * + * @param map The Map object. + * @param key The key to look for. + * @return The parsed color as an integer, or black if missing or invalid. + */ + private int getColor(Map map, String key) { + try { + if (map != null && map.containsKey(key) && map.get(key) != null) { + String colorString = (String) map.get(key); + return android.graphics.Color.parseColor(colorString); + } + } catch (Exception e) { + e.printStackTrace(); + } + return android.graphics.Color.BLACK; + } + + /** + * Retrieves a text style from the Map. + * + * @param map The Map object. + * @param key The key to look for. + * @return The corresponding Typeface style, or Typeface.NORMAL if missing or invalid. + */ + private int getTextStyle(Map map, String key) { + try { + if (map != null && map.containsKey(key) && map.get(key) != null) { + String style = (String) map.get(key); + switch (style.toLowerCase()) { + case "bold": + return Typeface.BOLD; + case "italic": + return Typeface.ITALIC; + case "bold_italic": + return Typeface.BOLD_ITALIC; + case "normal": + default: + return Typeface.NORMAL; + } + } + } catch (Exception e) { + e.printStackTrace(); + } + return Typeface.NORMAL; + } + + /** + * Sets a font on the theme builder if the font configuration is present in the theme config. + * + * @param themeConfig The theme configuration map + * @param builder The theme builder + * @param fileKey The key for font file path + * @param assetKey The key for font asset path + * @param fontType The type of font (for logging purposes) + */ + private void setFontIfPresent(Map themeConfig, com.instabug.library.model.IBGTheme.Builder builder, + String fileKey, String assetKey, String fontType) { + if (themeConfig.containsKey(fileKey) || themeConfig.containsKey(assetKey)) { + Typeface typeface = getTypeface(themeConfig, fileKey, assetKey); + if (typeface != null) { + switch (fontType) { + case "primary": + builder.setPrimaryTextFont(typeface); + break; + case "secondary": + builder.setSecondaryTextFont(typeface); + break; + case "CTA": + builder.setCtaTextFont(typeface); + break; + } + } + } + } + + private Typeface getTypeface(Map map, String fileKey, String assetKey) { + String fontName = null; + + if (assetKey != null && map.containsKey(assetKey) && map.get(assetKey) != null) { + fontName = (String) map.get(assetKey); + } else if (fileKey != null && map.containsKey(fileKey) && map.get(fileKey) != null) { + fontName = (String) map.get(fileKey); + } + + if (fontName == null) { + return Typeface.DEFAULT; + } + + try { + String assetPath = "fonts/" + fontName; + return Typeface.createFromAsset(context.getAssets(), assetPath); + } catch (Exception e) { + try { + return Typeface.create(fontName, Typeface.NORMAL); + } catch (Exception e2) { + return Typeface.DEFAULT; + } + } + } + /** + * Enables or disables displaying in full-screen mode, hiding the status and navigation bars. + * @param isEnabled A boolean to enable/disable setFullscreen. + */ + @Override + public void setFullscreen(@NonNull final Boolean isEnabled) { + try { + Instabug.setFullscreen(isEnabled); + } catch (Exception e) { + e.printStackTrace(); + } + } + } diff --git a/android/src/test/java/com/instabug/flutter/ApmApiTest.java b/android/src/test/java/com/instabug/flutter/ApmApiTest.java index 725d3bd98..39728c20c 100644 --- a/android/src/test/java/com/instabug/flutter/ApmApiTest.java +++ b/android/src/test/java/com/instabug/flutter/ApmApiTest.java @@ -17,7 +17,6 @@ import com.instabug.apm.InternalAPM; import com.instabug.apm.configuration.cp.APMFeature; import com.instabug.apm.configuration.cp.FeatureAvailabilityCallback; -import com.instabug.apm.model.ExecutionTrace; import com.instabug.apm.networking.APMNetworkLogger; import com.instabug.flutter.generated.ApmPigeon; import com.instabug.flutter.modules.ApmApi; @@ -68,16 +67,6 @@ public void cleanUp() { GlobalMocks.close(); } - private ExecutionTrace mockTrace(String id) { - String name = "trace-name"; - ExecutionTrace mTrace = mock(ExecutionTrace.class); - - mAPM.when(() -> APM.startExecutionTrace(name)).thenReturn(mTrace); - - api.startExecutionTrace(id, name, makeResult()); - - return mTrace; - } @Test public void testInit() { @@ -115,53 +104,7 @@ public void testSetAutoUITraceEnabled() { mAPM.verify(() -> APM.setAutoUITraceEnabled(isEnabled)); } - @Test - public void testStartExecutionTraceWhenTraceNotNull() { - String expectedId = "trace-id"; - String name = "trace-name"; - ApmPigeon.Result result = makeResult((String actualId) -> assertEquals(expectedId, actualId)); - - mAPM.when(() -> APM.startExecutionTrace(name)).thenReturn(new ExecutionTrace(name)); - - api.startExecutionTrace(expectedId, name, result); - - mAPM.verify(() -> APM.startExecutionTrace(name)); - } - - @Test - public void testStartExecutionTraceWhenTraceIsNull() { - String id = "trace-id"; - String name = "trace-name"; - ApmPigeon.Result result = makeResult(Assert::assertNull); - - mAPM.when(() -> APM.startExecutionTrace(name)).thenReturn(null); - - api.startExecutionTrace(id, name, result); - - mAPM.verify(() -> APM.startExecutionTrace(name)); - } - - @Test - public void testSetExecutionTraceAttribute() { - String id = "trace-id"; - String key = "is_premium"; - String value = "true"; - ExecutionTrace mTrace = mockTrace(id); - - api.setExecutionTraceAttribute(id, key, value); - - verify(mTrace).setAttribute(key, value); - } - - @Test - public void testEndExecutionTrace() { - String id = "trace-id"; - ExecutionTrace mTrace = mockTrace(id); - - api.endExecutionTrace(id); - verify(mTrace).end(); - } @Test public void testStartFlow() { diff --git a/android/src/test/java/com/instabug/flutter/BugReportingApiTest.java b/android/src/test/java/com/instabug/flutter/BugReportingApiTest.java index 6d22e26b8..50722762f 100644 --- a/android/src/test/java/com/instabug/flutter/BugReportingApiTest.java +++ b/android/src/test/java/com/instabug/flutter/BugReportingApiTest.java @@ -192,7 +192,7 @@ public void testSetCommentMinimumCharacterCount() { api.setCommentMinimumCharacterCount(limit, reportTypes); - mBugReporting.verify(() -> BugReporting.setCommentMinimumCharacterCount(limit.intValue(), BugReporting.ReportType.BUG, BugReporting.ReportType.QUESTION)); + mBugReporting.verify(() -> BugReporting.setCommentMinimumCharacterCountForBugReportType(limit.intValue(), BugReporting.ReportType.BUG, BugReporting.ReportType.QUESTION)); } @Test diff --git a/android/src/test/java/com/instabug/flutter/InstabugApiTest.java b/android/src/test/java/com/instabug/flutter/InstabugApiTest.java index 7efb8e425..8e9999e52 100644 --- a/android/src/test/java/com/instabug/flutter/InstabugApiTest.java +++ b/android/src/test/java/com/instabug/flutter/InstabugApiTest.java @@ -80,6 +80,8 @@ import org.mockito.verification.VerificationMode; import org.mockito.verification.VerificationMode; +import android.graphics.Typeface; + public class InstabugApiTest { private final Callable screenshotProvider = () -> mock(Bitmap.class); private final Application mContext = mock(Application.class); @@ -280,13 +282,7 @@ public void testSetWelcomeMessageMode() { @Test public void testSetPrimaryColor() { - Long color = 0xFF0000L; - - api.setPrimaryColor(color); - - mInstabug.verify(() -> Instabug.setPrimaryColor(0xFF0000)); } - @Test public void testSetSessionProfilerEnabledGivenTrue() { Boolean isEnabled = true; @@ -350,30 +346,7 @@ public void testGetTags() { mInstabug.verify(Instabug::getTags); } - @Test - public void testAddExperiments() { - List experiments = Arrays.asList("premium", "star"); - - api.addExperiments(experiments); - - mInstabug.verify(() -> Instabug.addExperiments(experiments)); - } - - @Test - public void testRemoveExperiments() { - List experiments = Arrays.asList("premium", "star"); - - api.removeExperiments(experiments); - - mInstabug.verify(() -> Instabug.removeExperiments(experiments)); - } - - @Test - public void testClearAllExperiments() { - api.clearAllExperiments(); - mInstabug.verify(Instabug::clearAllExperiments); - } @Test public void testAddFeatureFlags() { @@ -670,4 +643,71 @@ public void testSetNetworkLogBodyDisabled() { mInstabug.verify(() -> Instabug.setNetworkLogBodyEnabled(false)); } + + @Test + public void testSetThemeWithAllProperties() { + Map themeConfig = new HashMap<>(); + themeConfig.put("primaryColor", "#FF6B6B"); + themeConfig.put("backgroundColor", "#FFFFFF"); + themeConfig.put("titleTextColor", "#000000"); + themeConfig.put("primaryTextColor", "#333333"); + themeConfig.put("secondaryTextColor", "#666666"); + themeConfig.put("primaryTextStyle", "bold"); + themeConfig.put("secondaryTextStyle", "italic"); + themeConfig.put("ctaTextStyle", "bold_italic"); + themeConfig.put("primaryFontAsset", "assets/fonts/CustomFont-Regular.ttf"); + themeConfig.put("secondaryFontAsset", "assets/fonts/CustomFont-Bold.ttf"); + themeConfig.put("ctaFontAsset", "assets/fonts/CustomFont-Italic.ttf"); + + MockedConstruction mThemeBuilder = + mockConstruction(com.instabug.library.model.IBGTheme.Builder.class, (mock, context) -> { + when(mock.setPrimaryColor(anyInt())).thenReturn(mock); + when(mock.setBackgroundColor(anyInt())).thenReturn(mock); + when(mock.setTitleTextColor(anyInt())).thenReturn(mock); + when(mock.setPrimaryTextColor(anyInt())).thenReturn(mock); + when(mock.setSecondaryTextColor(anyInt())).thenReturn(mock); + when(mock.setPrimaryTextStyle(anyInt())).thenReturn(mock); + when(mock.setSecondaryTextStyle(anyInt())).thenReturn(mock); + when(mock.setCtaTextStyle(anyInt())).thenReturn(mock); + when(mock.setPrimaryTextFont(any(Typeface.class))).thenReturn(mock); + when(mock.setSecondaryTextFont(any(Typeface.class))).thenReturn(mock); + when(mock.setCtaTextFont(any(Typeface.class))).thenReturn(mock); + when(mock.build()).thenReturn(mock(com.instabug.library.model.IBGTheme.class)); + }); + + api.setTheme(themeConfig); + + com.instabug.library.model.IBGTheme.Builder builder = mThemeBuilder.constructed().get(0); + + verify(builder).setPrimaryColor(anyInt()); + verify(builder).setBackgroundColor(anyInt()); + verify(builder).setTitleTextColor(anyInt()); + verify(builder).setPrimaryTextColor(anyInt()); + verify(builder).setSecondaryTextColor(anyInt()); + verify(builder).setPrimaryTextStyle(Typeface.BOLD); + verify(builder).setSecondaryTextStyle(Typeface.ITALIC); + verify(builder).setCtaTextStyle(Typeface.BOLD_ITALIC); + + mInstabug.verify(() -> Instabug.setTheme(any(com.instabug.library.model.IBGTheme.class))); + } + + @Test + public void testSetFullscreen() { + boolean isEnabled = true; + + api.setFullscreen(isEnabled); + + mInstabug.verify(() -> Instabug.setFullscreen(isEnabled)); + } + + @Test + public void testSetFullscreenDisabled() { + boolean isEnabled = false; + + api.setFullscreen(isEnabled); + + mInstabug.verify(() -> Instabug.setFullscreen(isEnabled)); + } + + } diff --git a/example/android/app/src/main/kotlin/com/example/InstabugSample/InstabugExampleMethodCallHandler.kt b/example/android/app/src/main/kotlin/com/example/InstabugSample/InstabugExampleMethodCallHandler.kt index 17a7d35c6..f6fb0fc03 100644 --- a/example/android/app/src/main/kotlin/com/example/InstabugSample/InstabugExampleMethodCallHandler.kt +++ b/example/android/app/src/main/kotlin/com/example/InstabugSample/InstabugExampleMethodCallHandler.kt @@ -37,6 +37,12 @@ class InstabugExampleMethodCallHandler : MethodChannel.MethodCallHandler { sendOOM() result.success(null) } + SET_FULLSCREEN -> { + val isEnabled = call.arguments as? Map<*, *> + val enabled = isEnabled?.get("isEnabled") as? Boolean ?: false + setFullscreen(enabled) + result.success(null) + } else -> { Log.e(TAG, "onMethodCall for ${call.method} is not implemented") result.notImplemented() @@ -55,6 +61,7 @@ class InstabugExampleMethodCallHandler : MethodChannel.MethodCallHandler { const val SEND_NATIVE_FATAL_HANG = "sendNativeFatalHang" const val SEND_ANR = "sendAnr" const val SEND_OOM = "sendOom" + const val SET_FULLSCREEN = "setFullscreen" } private fun sendNativeNonFatal(exceptionObject: String?) { @@ -125,4 +132,25 @@ class InstabugExampleMethodCallHandler : MethodChannel.MethodCallHandler { return randomString.toString() } + private fun setFullscreen(enabled: Boolean) { + try { + + try { + val instabugClass = Class.forName("com.instabug.library.Instabug") + val setFullscreenMethod = instabugClass.getMethod("setFullscreen", Boolean::class.java) + setFullscreenMethod.invoke(null, enabled) + } catch (e: ClassNotFoundException) { + throw e + } catch (e: NoSuchMethodException) { + throw e + } catch (e: Exception) { + throw e + } + + } catch (e: Exception) { + e.printStackTrace() + + } + } + } diff --git a/example/ios/InstabugTests/ApmApiTests.m b/example/ios/InstabugTests/ApmApiTests.m index bdb710ac7..3be2288d2 100644 --- a/example/ios/InstabugTests/ApmApiTests.m +++ b/example/ios/InstabugTests/ApmApiTests.m @@ -19,16 +19,6 @@ - (void)setUp { self.api = [[ApmApi alloc] init]; } -- (IBGExecutionTrace *)mockTraceWithId:(NSString *)traceId { - NSString* name = @"trace-name"; - IBGExecutionTrace *mTrace = OCMClassMock([IBGExecutionTrace class]); - - OCMStub([self.mAPM startExecutionTraceWithName:name]).andReturn(mTrace); - - [self.api startExecutionTraceId:traceId name:name completion:^(NSString * _Nullable _, FlutterError * _Nullable __) {}]; - - return mTrace; -} - (void)testSetEnabled { NSNumber *isEnabled = @1; @@ -116,63 +106,6 @@ - (void)testSetAutoUITraceEnabled { OCMVerify([self.mAPM setAutoUITraceEnabled:YES]); } -- (void)testStartExecutionTraceWhenTraceNotNil { - NSString *expectedId = @"trace-id"; - NSString *name = @"trace-name"; - XCTestExpectation *expectation = [self expectationWithDescription:@"Call completion handler"]; - - IBGExecutionTrace *mTrace = OCMClassMock([IBGExecutionTrace class]); - OCMStub([self.mAPM startExecutionTraceWithName:name]).andReturn(mTrace); - - [self.api startExecutionTraceId:expectedId name:name completion:^(NSString *actualId, FlutterError *error) { - [expectation fulfill]; - XCTAssertEqual(actualId, expectedId); - XCTAssertNil(error); - }]; - - OCMVerify([self.mAPM startExecutionTraceWithName:name]); - [self waitForExpectations:@[expectation] timeout:5.0]; -} - -- (void)testStartExecutionTraceWhenTraceIsNil { - NSString *traceId = @"trace-id"; - NSString *name = @"trace-name"; - XCTestExpectation *expectation = [self expectationWithDescription:@"Call completion handler"]; - - OCMStub([self.mAPM startExecutionTraceWithName:name]).andReturn(nil); - - [self.api startExecutionTraceId:traceId name:name completion:^(NSString *actualId, FlutterError *error) { - [expectation fulfill]; - XCTAssertNil(actualId); - XCTAssertNil(error); - }]; - - OCMVerify([self.mAPM startExecutionTraceWithName:name]); - [self waitForExpectations:@[expectation] timeout:5.0]; -} - - -- (void)testSetExecutionTraceAttribute { - NSString *traceId = @"trace-id"; - NSString *key = @"is_premium"; - NSString *value = @"true"; - FlutterError *error; - id mTrace = [self mockTraceWithId:traceId]; - - [self.api setExecutionTraceAttributeId:traceId key:key value:value error:&error]; - - OCMVerify([mTrace setAttributeWithKey:key value:value]); -} - -- (void)testEndExecutionTrace { - NSString *traceId = @"trace-id"; - FlutterError *error; - IBGExecutionTrace *mTrace = [self mockTraceWithId:traceId]; - - [self.api endExecutionTraceId:traceId error:&error]; - - OCMVerify([mTrace end]); -} - (void) testStartFlow { NSString* appFlowName = @"app-flow-name"; diff --git a/example/ios/InstabugTests/BugReportingApiTests.m b/example/ios/InstabugTests/BugReportingApiTests.m index e01df21d2..5b6954d59 100644 --- a/example/ios/InstabugTests/BugReportingApiTests.m +++ b/example/ios/InstabugTests/BugReportingApiTests.m @@ -162,7 +162,7 @@ - (void)testSetCommentMinimumCharacterCountGivenReportTypes { [self.api setCommentMinimumCharacterCountLimit:limit reportTypes:reportTypes error:&error]; - OCMVerify([self.mBugReporting setCommentMinimumCharacterCountForReportTypes:IBGBugReportingReportTypeBug | IBGBugReportingReportTypeQuestion withLimit:limit.intValue]); + OCMVerify([self.mBugReporting setCommentMinimumCharacterCount:limit.intValue forBugReportType:IBGBugReportingReportTypeBug | IBGBugReportingReportTypeQuestion]); } - (void)testSetCommentMinimumCharacterCountGivenNoReportTypes { @@ -172,7 +172,7 @@ - (void)testSetCommentMinimumCharacterCountGivenNoReportTypes { [self.api setCommentMinimumCharacterCountLimit:limit reportTypes:reportTypes error:&error]; - OCMVerify([self.mBugReporting setCommentMinimumCharacterCountForReportTypes:IBGBugReportingReportTypeBug | IBGBugReportingReportTypeFeedback | IBGBugReportingReportTypeQuestion withLimit:limit.intValue]); + OCMVerify([self.mBugReporting setCommentMinimumCharacterCount:limit.intValue forBugReportType:IBGBugReportingReportTypeBug | IBGBugReportingReportTypeFeedback | IBGBugReportingReportTypeQuestion]); } - (void)testAddUserConsentWithKey { NSString *key = @"testKey"; diff --git a/example/ios/InstabugTests/InstabugApiTests.m b/example/ios/InstabugTests/InstabugApiTests.m index 3cbcc13f0..3e1abf332 100644 --- a/example/ios/InstabugTests/InstabugApiTests.m +++ b/example/ios/InstabugTests/InstabugApiTests.m @@ -51,7 +51,7 @@ - (void)testInit { OCMVerify([self.mInstabug setSdkDebugLogsLevel:IBGSDKDebugLogsLevelError]); OCMVerify([self.mInstabug startWithToken:token invocationEvents:(IBGInvocationEventFloatingButton | IBGInvocationEventScreenshot)]); - + XCTAssertEqual(Instabug.appVariant, appVariant); } @@ -207,31 +207,6 @@ - (void)testGetTags { [self waitForExpectations:@[expectation] timeout:5.0]; } -- (void)testAddExperiments { - NSArray *experiments = @[@"premium", @"star"]; - FlutterError *error; - - [self.api addExperimentsExperiments:experiments error:&error]; - - OCMVerify([self.mInstabug addExperiments:experiments]); -} - -- (void)testRemoveExperiments { - NSArray *experiments = @[@"premium", @"star"]; - FlutterError *error; - - [self.api removeExperimentsExperiments:experiments error:&error]; - - OCMVerify([self.mInstabug removeExperiments:experiments]); -} - -- (void)testClearAllExperiments { - FlutterError *error; - - [self.api clearAllExperimentsWithError:&error]; - - OCMVerify([self.mInstabug clearAllExperiments]); -} - (void)testAddFeatureFlags { NSDictionary *featureFlagsMap = @{ @"key13" : @"value1", @"key2" : @"value2"}; @@ -618,4 +593,42 @@ - (void)testisW3CFeatureFlagsEnabled { } +- (void)testSetThemeWithAllProperties { + NSDictionary *themeConfig = @{ + @"primaryColor": @"#FF6B6B", + @"backgroundColor": @"#FFFFFF", + @"titleTextColor": @"#000000", + @"primaryTextColor": @"#333333", + @"secondaryTextColor": @"#666666", + @"callToActionTextColor": @"#FF6B6B", + @"primaryFontPath": @"assets/fonts/CustomFont-Regular.ttf", + @"secondaryFontPath": @"assets/fonts/CustomFont-Bold.ttf", + @"ctaFontPath": @"assets/fonts/CustomFont-Italic.ttf" + }; + + id mockTheme = OCMClassMock([IBGTheme class]); + OCMStub([mockTheme primaryColor]).andReturn([UIColor redColor]); + OCMStub([mockTheme backgroundColor]).andReturn([UIColor whiteColor]); + OCMStub([mockTheme titleTextColor]).andReturn([UIColor blackColor]); + OCMStub([mockTheme primaryTextColor]).andReturn([UIColor darkGrayColor]); + OCMStub([mockTheme secondaryTextColor]).andReturn([UIColor grayColor]); + OCMStub([mockTheme callToActionTextColor]).andReturn([UIColor redColor]); + + FlutterError *error; + + [self.api setThemeThemeConfig:themeConfig error:&error]; + + OCMVerify([self.mInstabug setTheme:[OCMArg isNotNil]]); +} + +- (void)testSetFullscreen { + NSNumber *isEnabled = @1; + FlutterError *error; + + [self.api setFullscreenIsEnabled:isEnabled error:&error]; + + // Since this is an empty implementation, we just verify the method can be called without error + XCTAssertNil(error); +} + @end diff --git a/example/lib/main.dart b/example/lib/main.dart index 1052d42c8..bccdbfc68 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -38,8 +38,6 @@ part 'src/components/network_content.dart'; part 'src/components/page.dart'; -part 'src/components/traces_content.dart'; - part 'src/components/flows_content.dart'; void main() { diff --git a/example/lib/src/components/traces_content.dart b/example/lib/src/components/traces_content.dart deleted file mode 100644 index 888460d43..000000000 --- a/example/lib/src/components/traces_content.dart +++ /dev/null @@ -1,157 +0,0 @@ -part of '../../main.dart'; - -class TracesContent extends StatefulWidget { - const TracesContent({Key? key}) : super(key: key); - - @override - State createState() => _TracesContentState(); -} - -class _TracesContentState extends State { - final traceNameController = TextEditingController(); - final traceKeyAttributeController = TextEditingController(); - final traceValueAttributeController = TextEditingController(); - - bool? didTraceEnd; - - Trace? trace; - - @override - Widget build(BuildContext context) { - final textTheme = Theme.of(context).textTheme; - return Column( - children: [ - InstabugTextField( - label: 'Trace name', - labelStyle: textTheme.labelMedium, - controller: traceNameController, - ), - SizedBox.fromSize( - size: const Size.fromHeight(10.0), - ), - Row( - children: [ - Flexible( - flex: 5, - child: InstabugButton.smallFontSize( - text: 'Start Trace', - onPressed: () => _startTrace(traceNameController.text), - margin: const EdgeInsetsDirectional.only( - start: 20.0, - end: 10.0, - ), - ), - ), - Flexible( - flex: 5, - child: InstabugButton.smallFontSize( - text: 'Start Trace With Delay', - onPressed: () => _startTrace( - traceNameController.text, - delayInMilliseconds: 5000, - ), - margin: const EdgeInsetsDirectional.only( - start: 10.0, - end: 20.0, - ), - ), - ), - ], - ), - Row( - children: [ - Flexible( - flex: 5, - child: InstabugTextField( - label: 'Trace Key Attribute', - controller: traceKeyAttributeController, - labelStyle: textTheme.labelMedium, - margin: const EdgeInsetsDirectional.only( - end: 10.0, - start: 20.0, - ), - ), - ), - Flexible( - flex: 5, - child: InstabugTextField( - label: 'Trace Value Attribute', - labelStyle: textTheme.labelMedium, - controller: traceValueAttributeController, - margin: const EdgeInsetsDirectional.only( - start: 10.0, - end: 20.0, - ), - ), - ), - ], - ), - SizedBox.fromSize( - size: const Size.fromHeight(10.0), - ), - InstabugButton( - text: 'Set Trace Attribute', - onPressed: () => _setTraceAttribute( - trace, - traceKeyAttribute: traceKeyAttributeController.text, - traceValueAttribute: traceValueAttributeController.text, - ), - ), - InstabugButton( - text: 'End Trace', - onPressed: () => _endTrace(), - ), - ], - ); - } - - void _startTrace( - String traceName, { - int delayInMilliseconds = 0, - }) { - if (traceName.trim().isNotEmpty) { - log('_startTrace — traceName: $traceName, delay in Milliseconds: $delayInMilliseconds'); - log('traceName: $traceName'); - Future.delayed( - Duration(milliseconds: delayInMilliseconds), - () => APM - .startExecutionTrace(traceName) - .then((value) => trace = value)); - } else { - log('startTrace - Please enter a trace name'); - } - } - - void _endTrace() { - if (didTraceEnd == true) { - log('_endTrace — Please, start a new trace before setting attributes.'); - } - if (trace == null) { - log('_endTrace — Please, start a trace before ending it.'); - } - log('_endTrace — ending Trace.'); - trace?.end(); - didTraceEnd = true; - } - - void _setTraceAttribute( - Trace? trace, { - required String traceKeyAttribute, - required String traceValueAttribute, - }) { - if (trace == null) { - log('_setTraceAttribute — Please, start a trace before setting attributes.'); - } - if (didTraceEnd == true) { - log('_setTraceAttribute — Please, start a new trace before setting attributes.'); - } - if (traceKeyAttribute.trim().isEmpty) { - log('_setTraceAttribute — Please, fill the trace key attribute input before settings attributes.'); - } - if (traceValueAttribute.trim().isEmpty) { - log('_setTraceAttribute — Please, fill the trace value attribute input before settings attributes.'); - } - log('_setTraceAttribute — setting attributes -> key: $traceKeyAttribute, value: $traceValueAttribute.'); - trace?.setAttribute(traceKeyAttribute, traceValueAttribute); - } -} diff --git a/example/lib/src/native/instabug_flutter_example_method_channel.dart b/example/lib/src/native/instabug_flutter_example_method_channel.dart index 9507cc403..118097dc3 100644 --- a/example/lib/src/native/instabug_flutter_example_method_channel.dart +++ b/example/lib/src/native/instabug_flutter_example_method_channel.dart @@ -54,6 +54,22 @@ class InstabugFlutterExampleMethodChannel { log("Failed to send out of memory: '${e.message}'.", name: _tag); } } + + static Future setFullscreen(bool isEnabled) async { + if (!Platform.isAndroid) { + return; + } + + try { + await _channel.invokeMethod(Constants.setFullscreenMethodName, { + 'isEnabled': isEnabled, + }); + } on PlatformException catch (e) { + log("Failed to set fullscreen: '${e.message}'.", name: _tag); + } catch (e) { + log("Unexpected error setting fullscreen: '$e'.", name: _tag); + } + } } class Constants { @@ -65,4 +81,5 @@ class Constants { static const sendNativeFatalHangMethodName = "sendNativeFatalHang"; static const sendAnrMethodName = "sendAnr"; static const sendOomMethodName = "sendOom"; + static const setFullscreenMethodName = "setFullscreen"; } diff --git a/example/lib/src/screens/apm_page.dart b/example/lib/src/screens/apm_page.dart index 798e906fa..d4ad53ca6 100644 --- a/example/lib/src/screens/apm_page.dart +++ b/example/lib/src/screens/apm_page.dart @@ -36,8 +36,6 @@ class _ApmPageState extends State { ), const SectionTitle('Network'), const NetworkContent(), - const SectionTitle('Traces'), - const TracesContent(), const SectionTitle('Flows'), const FlowsContent(), const SectionTitle('Screen Loading'), diff --git a/example/lib/src/screens/my_home_page.dart b/example/lib/src/screens/my_home_page.dart index 404d79cdd..5f7d50a88 100644 --- a/example/lib/src/screens/my_home_page.dart +++ b/example/lib/src/screens/my_home_page.dart @@ -114,10 +114,10 @@ class _MyHomePageState extends State { BugReporting.setInvocationEvents([invocationEvent]); } - void changePrimaryColor() { - String text = 'FF' + primaryColorController.text.replaceAll('#', ''); - Color color = Color(int.parse(text, radix: 16)); - Instabug.setPrimaryColor(color); + void changePrimaryColor() async { + String text = primaryColorController.text.replaceAll('#', ''); + await Instabug.setTheme(ThemeConfig(primaryColor: '#$text')); + await Future.delayed(const Duration(milliseconds: 500)); } void setColorTheme(ColorTheme colorTheme) { diff --git a/example/pubspec.yaml b/example/pubspec.yaml index fe72aaa2d..dfd49f2aa 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -51,6 +51,7 @@ flutter: # To add assets to your application, add an assets section, like this: # assets: + # - assets/fonts/ # - images/a_dot_burr.jpeg # - images/a_dot_ham.jpeg @@ -66,6 +67,9 @@ flutter: # list giving the asset and other descriptors for the font. For # example: # fonts: + # - family: ManufacturingConsent + # fonts: + # - asset: assets/fonts/ManufacturingConsent-Regular.ttf # - family: Schyler # fonts: # - asset: fonts/Schyler-Regular.ttf diff --git a/ios/Classes/Modules/ApmApi.m b/ios/Classes/Modules/ApmApi.m index c6295ce67..a8c5c1bd3 100644 --- a/ios/Classes/Modules/ApmApi.m +++ b/ios/Classes/Modules/ApmApi.m @@ -70,44 +70,6 @@ - (void)setAutoUITraceEnabledIsEnabled:(NSNumber *)isEnabled error:(FlutterError IBGAPM.autoUITraceEnabled = [isEnabled boolValue]; } -// This method is responsible for starting an execution trace -// with a given `id` and `name`. -// -// Deprecated - see [startFlowName, setFlowAttributeName & endFlowName]. -- (void)startExecutionTraceId:(NSString *)id name:(NSString *)name completion:(void(^)(NSString *_Nullable, FlutterError *_Nullable))completion { - IBGExecutionTrace *trace = [IBGAPM startExecutionTraceWithName:name]; - - if (trace != nil) { - [traces setObject:trace forKey:id]; - return completion(id, nil); - } else { - return completion(nil, nil); - } -} - -// This method is responsible for setting an attribute for a specific -// execution trace identified by the provided `id`. -// -// Deprecated - see [startFlowName, setFlowAttributeName & endFlowName]. -- (void)setExecutionTraceAttributeId:(NSString *)id key:(NSString *)key value:(NSString *)value error:(FlutterError *_Nullable *_Nonnull)error { - IBGExecutionTrace *trace = [traces objectForKey:id]; - - if (trace != nil) { - [trace setAttributeWithKey:key value:value]; - } -} - -// This method `endExecutionTraceId` is responsible for ending an execution trace identified by the -// provided `id`. -// -// Deprecated - see [startFlowName, setFlowAttributeName & endFlowName]. -- (void)endExecutionTraceId:(NSString *)id error:(FlutterError *_Nullable *_Nonnull)error { - IBGExecutionTrace *trace = [traces objectForKey:id]; - - if (trace != nil) { - [trace end]; - } -} // This method is responsible for starting a flow with the given `name`. This functionality is used to // track and monitor the performance of specific flows within the application. diff --git a/ios/Classes/Modules/BugReportingApi.m b/ios/Classes/Modules/BugReportingApi.m index bb97810b8..7a92a9563 100644 --- a/ios/Classes/Modules/BugReportingApi.m +++ b/ios/Classes/Modules/BugReportingApi.m @@ -151,8 +151,7 @@ - (void)setDisclaimerTextText:(NSString *)text error:(FlutterError *_Nullable *_ } - (void)setCommentMinimumCharacterCountLimit:(NSNumber *)limit reportTypes:(nullable NSArray *)reportTypes error:(FlutterError *_Nullable *_Nonnull)error { - IBGBugReportingReportType resolvedTypes = 0; - + IBGBugReportingType resolvedTypes = 0; if (![reportTypes count]) { resolvedTypes = (ArgsRegistry.reportTypes[@"ReportType.bug"]).integerValue | (ArgsRegistry.reportTypes[@"ReportType.feedback"]).integerValue | (ArgsRegistry.reportTypes[@"ReportType.question"]).integerValue; } @@ -162,7 +161,7 @@ - (void)setCommentMinimumCharacterCountLimit:(NSNumber *)limit reportTypes:(null } } - [IBGBugReporting setCommentMinimumCharacterCountForReportTypes:resolvedTypes withLimit:limit.intValue]; + [IBGBugReporting setCommentMinimumCharacterCount:[limit integerValue] forBugReportType:resolvedTypes]; } - (void)addUserConsentsKey:(NSString *)key diff --git a/ios/Classes/Modules/InstabugApi.m b/ios/Classes/Modules/InstabugApi.m index edced7a05..84f574b58 100644 --- a/ios/Classes/Modules/InstabugApi.m +++ b/ios/Classes/Modules/InstabugApi.m @@ -14,7 +14,9 @@ extern void InitInstabugApi(id messenger) { InstabugHostApiSetup(messenger, api); } -@implementation InstabugApi +@implementation InstabugApi { + NSMutableSet *_registeredFonts; +} - (void)setEnabledIsEnabled:(NSNumber *)isEnabled error:(FlutterError *_Nullable *_Nonnull)error { Instabug.enabled = [isEnabled boolValue]; @@ -30,12 +32,12 @@ - (nullable NSNumber *)isEnabledWithError:(FlutterError * _Nullable __autoreleas } - (void)initToken:(nonnull NSString *)token invocationEvents:(nonnull NSArray *)invocationEvents debugLogsLevel:(nonnull NSString *)debugLogsLevel appVariant:(nullable NSString *)appVariant error:(FlutterError * _Nullable __autoreleasing * _Nonnull)error { - + if(appVariant != nil){ Instabug.appVariant = appVariant; } - + SEL setPrivateApiSEL = NSSelectorFromString(@"setCurrentPlatform:"); if ([[Instabug class] respondsToSelector:setPrivateApiSEL]) { NSInteger *platformID = IBGPlatformFlutter; @@ -51,8 +53,8 @@ - (void)initToken:(nonnull NSString *)token invocationEvents:(nonnull NSArray * _Nullable, completion([Instabug getTags], nil); } -- (void)addExperimentsExperiments:(NSArray *)experiments error:(FlutterError *_Nullable *_Nonnull)error { - [Instabug addExperiments:experiments]; -} -- (void)removeExperimentsExperiments:(NSArray *)experiments error:(FlutterError *_Nullable *_Nonnull)error { - [Instabug removeExperiments:experiments]; -} - -- (void)clearAllExperimentsWithError:(FlutterError *_Nullable *_Nonnull)error { - [Instabug clearAllExperiments]; -} - (void)setUserAttributeValue:(NSString *)value key:(NSString *)key error:(FlutterError *_Nullable *_Nonnull)error { [Instabug setUserAttribute:value withKey:key]; @@ -404,11 +396,181 @@ - (void)setNetworkLogBodyEnabledIsEnabled:(NSNumber *)isEnabled } -- (void)setAppVariantAppVariant:(nonnull NSString *)appVariant error:(FlutterError * _Nullable __autoreleasing * _Nonnull)error { +- (void)setAppVariantAppVariant:(nonnull NSString *)appVariant error:(FlutterError * _Nullable __autoreleasing * _Nonnull)error { Instabug.appVariant = appVariant; } +- (void)setThemeThemeConfig:(NSDictionary *)themeConfig error:(FlutterError *_Nullable *_Nonnull)error { + IBGTheme *theme = [[IBGTheme alloc] init]; + + NSDictionary *colorMapping = @{ + @"primaryColor": ^(UIColor *color) { theme.primaryColor = color; }, + @"backgroundColor": ^(UIColor *color) { theme.backgroundColor = color; }, + @"titleTextColor": ^(UIColor *color) { theme.titleTextColor = color; }, + @"subtitleTextColor": ^(UIColor *color) { theme.subtitleTextColor = color; }, + @"primaryTextColor": ^(UIColor *color) { theme.primaryTextColor = color; }, + @"secondaryTextColor": ^(UIColor *color) { theme.secondaryTextColor = color; }, + @"callToActionTextColor": ^(UIColor *color) { theme.callToActionTextColor = color; }, + @"headerBackgroundColor": ^(UIColor *color) { theme.headerBackgroundColor = color; }, + @"footerBackgroundColor": ^(UIColor *color) { theme.footerBackgroundColor = color; }, + @"rowBackgroundColor": ^(UIColor *color) { theme.rowBackgroundColor = color; }, + @"selectedRowBackgroundColor": ^(UIColor *color) { theme.selectedRowBackgroundColor = color; }, + @"rowSeparatorColor": ^(UIColor *color) { theme.rowSeparatorColor = color; } + }; + + for (NSString *key in colorMapping) { + if (themeConfig[key]) { + NSString *colorString = themeConfig[key]; + UIColor *color = [self colorFromHexString:colorString]; + if (color) { + void (^setter)(UIColor *) = colorMapping[key]; + setter(color); + } + } + } + + [self setFontIfPresent:themeConfig[@"primaryFontPath"] ?: themeConfig[@"primaryFontAsset"] forTheme:theme type:@"primary"]; + [self setFontIfPresent:themeConfig[@"secondaryFontPath"] ?: themeConfig[@"secondaryFontAsset"] forTheme:theme type:@"secondary"]; + [self setFontIfPresent:themeConfig[@"ctaFontPath"] ?: themeConfig[@"ctaFontAsset"] forTheme:theme type:@"cta"]; + + Instabug.theme = theme; +} + +- (void)setFontIfPresent:(NSString *)fontPath forTheme:(IBGTheme *)theme type:(NSString *)type { + if (!fontPath || fontPath.length == 0 || !theme || !type) return; + + if (!_registeredFonts) { + _registeredFonts = [NSMutableSet set]; + } + + // Check if font is already registered + if ([_registeredFonts containsObject:fontPath]) { + UIFont *font = [UIFont fontWithName:fontPath size:UIFont.systemFontSize]; + if (font) { + [self setFont:font forTheme:theme type:type]; + } + return; + } + + // Try to load font from system fonts first + UIFont *font = [UIFont fontWithName:fontPath size:UIFont.systemFontSize]; + if (font) { + [_registeredFonts addObject:fontPath]; + [self setFont:font forTheme:theme type:type]; + return; + } + + // Try to load font from bundle + font = [self loadFontFromPath:fontPath]; + if (font) { + [_registeredFonts addObject:fontPath]; + [self setFont:font forTheme:theme type:type]; + } +} + +- (UIFont *)loadFontFromPath:(NSString *)fontPath { + NSString *fontFileName = [fontPath stringByDeletingPathExtension]; + NSArray *fontExtensions = @[@"ttf", @"otf", @"woff", @"woff2"]; + + // Find font file in bundle + NSString *fontFilePath = nil; + for (NSString *extension in fontExtensions) { + fontFilePath = [[NSBundle mainBundle] pathForResource:fontFileName ofType:extension]; + if (fontFilePath) break; + } + + if (!fontFilePath) { + return nil; + } + + // Load font data + NSData *fontData = [NSData dataWithContentsOfFile:fontFilePath]; + if (!fontData) { + return nil; + } + + // Create data provider + CGDataProviderRef provider = CGDataProviderCreateWithCFData((__bridge CFDataRef)fontData); + if (!provider) { + return nil; + } + + // Create CG font + CGFontRef cgFont = CGFontCreateWithDataProvider(provider); + CGDataProviderRelease(provider); + + if (!cgFont) { + return nil; + } + + // Register font + CFErrorRef error = NULL; + BOOL registered = CTFontManagerRegisterGraphicsFont(cgFont, &error); + + if (!registered) { + if (error) { + CFStringRef description = CFErrorCopyDescription(error); + CFRelease(description); + CFRelease(error); + } + CGFontRelease(cgFont); + return nil; + } + + // Get PostScript name and create UIFont + NSString *postScriptName = (__bridge_transfer NSString *)CGFontCopyPostScriptName(cgFont); + CGFontRelease(cgFont); + + if (!postScriptName) { + return nil; + } + + return [UIFont fontWithName:postScriptName size:UIFont.systemFontSize]; +} + +- (void)setFont:(UIFont *)font forTheme:(IBGTheme *)theme type:(NSString *)type { + if (!font || !theme || !type) return; + + if ([type isEqualToString:@"primary"]) { + theme.primaryTextFont = font; + } else if ([type isEqualToString:@"secondary"]) { + theme.secondaryTextFont = font; + } else if ([type isEqualToString:@"cta"]) { + theme.callToActionTextFont = font; + } +} + +- (UIColor *)colorFromHexString:(NSString *)hexString { + NSString *cleanString = [hexString stringByReplacingOccurrencesOfString:@"#" withString:@""]; + + if (cleanString.length == 6) { + unsigned int rgbValue = 0; + NSScanner *scanner = [NSScanner scannerWithString:cleanString]; + [scanner scanHexInt:&rgbValue]; + + return [UIColor colorWithRed:((rgbValue & 0xFF0000) >> 16) / 255.0 + green:((rgbValue & 0xFF00) >> 8) / 255.0 + blue:(rgbValue & 0xFF) / 255.0 + alpha:1.0]; + } else if (cleanString.length == 8) { + unsigned int rgbaValue = 0; + NSScanner *scanner = [NSScanner scannerWithString:cleanString]; + [scanner scanHexInt:&rgbaValue]; + + return [UIColor colorWithRed:((rgbaValue & 0xFF000000) >> 24) / 255.0 + green:((rgbaValue & 0xFF0000) >> 16) / 255.0 + blue:((rgbaValue & 0xFF00) >> 8) / 255.0 + alpha:(rgbaValue & 0xFF) / 255.0]; + } + + return [UIColor blackColor]; +} + +- (void)setFullscreenIsEnabled:(NSNumber *)isEnabled error:(FlutterError *_Nullable *_Nonnull)error { + // Empty implementation as requested +} + @end diff --git a/lib/instabug_flutter.dart b/lib/instabug_flutter.dart index e38545897..2cc2e8eca 100644 --- a/lib/instabug_flutter.dart +++ b/lib/instabug_flutter.dart @@ -3,7 +3,7 @@ export 'src/models/crash_data.dart'; export 'src/models/exception_data.dart'; export 'src/models/feature_flag.dart'; export 'src/models/network_data.dart'; -export 'src/models/trace.dart'; +export 'src/models/theme_config.dart'; export 'src/models/w3c_header.dart'; // Modules diff --git a/lib/src/models/theme_config.dart b/lib/src/models/theme_config.dart new file mode 100644 index 000000000..ea3a6754e --- /dev/null +++ b/lib/src/models/theme_config.dart @@ -0,0 +1,121 @@ +class ThemeConfig { + /// Primary color for UI elements indicating interactivity or call to action. + final String? primaryColor; + + /// Background color for the main UI. + final String? backgroundColor; + + /// Color for title text elements. + final String? titleTextColor; + + /// Color for subtitle text elements. + final String? subtitleTextColor; + + /// Color for primary text elements. + final String? primaryTextColor; + + /// Color for secondary text elements. + final String? secondaryTextColor; + + /// Color for call-to-action text elements. + final String? callToActionTextColor; + + /// Background color for header elements. + final String? headerBackgroundColor; + + /// Background color for footer elements. + final String? footerBackgroundColor; + + /// Background color for row elements. + final String? rowBackgroundColor; + + /// Background color for selected row elements. + final String? selectedRowBackgroundColor; + + /// Color for row separator lines. + final String? rowSeparatorColor; + + /// Text style for primary text (Android only). + final String? primaryTextStyle; + + /// Text style for secondary text (Android only). + final String? secondaryTextStyle; + + /// Text style for title text (Android only). + final String? titleTextStyle; + + /// Text style for call-to-action text (Android only). + final String? ctaTextStyle; + + /// Path to primary font file. + final String? primaryFontPath; + + /// Asset path to primary font file. + final String? primaryFontAsset; + + /// Path to secondary font file. + final String? secondaryFontPath; + + /// Asset path to secondary font file. + final String? secondaryFontAsset; + + /// Path to call-to-action font file. + final String? ctaFontPath; + + /// Asset path to call-to-action font file. + final String? ctaFontAsset; + + const ThemeConfig({ + this.primaryColor, + this.backgroundColor, + this.titleTextColor, + this.subtitleTextColor, + this.primaryTextColor, + this.secondaryTextColor, + this.callToActionTextColor, + this.headerBackgroundColor, + this.footerBackgroundColor, + this.rowBackgroundColor, + this.selectedRowBackgroundColor, + this.rowSeparatorColor, + this.primaryTextStyle, + this.secondaryTextStyle, + this.titleTextStyle, + this.ctaTextStyle, + this.primaryFontPath, + this.primaryFontAsset, + this.secondaryFontPath, + this.secondaryFontAsset, + this.ctaFontPath, + this.ctaFontAsset, + }); + + Map toMap() { + return Map.fromEntries( + [ + MapEntry('primaryColor', primaryColor), + MapEntry('backgroundColor', backgroundColor), + MapEntry('titleTextColor', titleTextColor), + MapEntry('subtitleTextColor', subtitleTextColor), + MapEntry('primaryTextColor', primaryTextColor), + MapEntry('secondaryTextColor', secondaryTextColor), + MapEntry('callToActionTextColor', callToActionTextColor), + MapEntry('headerBackgroundColor', headerBackgroundColor), + MapEntry('footerBackgroundColor', footerBackgroundColor), + MapEntry('rowBackgroundColor', rowBackgroundColor), + MapEntry('selectedRowBackgroundColor', selectedRowBackgroundColor), + MapEntry('rowSeparatorColor', rowSeparatorColor), + MapEntry('primaryTextStyle', primaryTextStyle), + MapEntry('secondaryTextStyle', secondaryTextStyle), + MapEntry('titleTextStyle', titleTextStyle), + MapEntry('ctaTextStyle', ctaTextStyle), + MapEntry('primaryFontPath', primaryFontPath), + MapEntry('primaryFontAsset', primaryFontAsset), + MapEntry('secondaryFontPath', secondaryFontPath), + MapEntry('secondaryFontAsset', secondaryFontAsset), + MapEntry('ctaFontPath', ctaFontPath), + MapEntry('ctaFontAsset', ctaFontAsset), + ].where((entry) => entry.value != null), + ); + } +} diff --git a/lib/src/models/trace.dart b/lib/src/models/trace.dart deleted file mode 100644 index bf267640b..000000000 --- a/lib/src/models/trace.dart +++ /dev/null @@ -1,44 +0,0 @@ -import 'package:instabug_flutter/src/modules/apm.dart'; - -class Trace { - Trace({ - required this.id, - required this.name, - }); - - final String id; - final String name; - final Map attributes = {}; - - /// Sets attribute of execution trace. - /// [String] id of the trace. - /// [String] key of attribute. - /// [String] value of attribute. - /// - /// Please migrate to the App Flows APIs: [APM.startFlow], [APM.setFlowAttribute], and [APM.endFlow]. - @Deprecated( - 'Please migrate to the App Flows APIs: APM.startAppFlow, APM.endFlow, and APM.setFlowAttribute. This feature was deprecated in v13.0.0', - ) - void setAttribute(String key, String value) { - APM.setExecutionTraceAttribute(id, key, value); - attributes[key] = value; - } - - /// Ends Execution Trace - /// - /// Please migrate to the App Flows APIs: [APM.startFlow], [APM.setFlowAttribute], and [APM.endFlow]. - @Deprecated( - 'Please migrate to the App Flows APIs: APM.startAppFlow, APM.endFlow, and APM.setFlowAttribute. This feature was deprecated in v13.0.0', - ) - void end() { - APM.endExecutionTrace(id); - } - - Map toJson() { - return { - 'id': id, - 'name': name, - 'attributes': attributes, - }; - } -} diff --git a/lib/src/modules/apm.dart b/lib/src/modules/apm.dart index a9f6e0a7c..970c9330e 100644 --- a/lib/src/modules/apm.dart +++ b/lib/src/modules/apm.dart @@ -5,9 +5,7 @@ import 'dart:async'; import 'package:flutter/widgets.dart' show WidgetBuilder; import 'package:instabug_flutter/src/generated/apm.api.g.dart'; import 'package:instabug_flutter/src/models/network_data.dart'; -import 'package:instabug_flutter/src/models/trace.dart'; import 'package:instabug_flutter/src/utils/ibg_build_info.dart'; -import 'package:instabug_flutter/src/utils/ibg_date_time.dart'; import 'package:instabug_flutter/src/utils/instabug_logger.dart'; import 'package:instabug_flutter/src/utils/screen_loading/screen_loading_manager.dart'; import 'package:meta/meta.dart'; @@ -72,58 +70,6 @@ class APM { return _host.setColdAppLaunchEnabled(isEnabled); } - /// Starts an execution trace. - /// [String] name of the trace. - /// - /// Please migrate to the App Flows APIs: [startFlow], [setFlowAttribute], and [endFlow]. - @Deprecated( - 'Please migrate to the App Flows APIs: APM.startAppFlow, APM.endFlow, and APM.setFlowAttribute. This feature was deprecated in v13.0.0', - ) - static Future startExecutionTrace(String name) async { - final id = IBGDateTime.instance.now(); - final traceId = await _host.startExecutionTrace(id.toString(), name); - - if (traceId == null) { - return Future.error( - "Execution trace $name wasn't created. Please make sure to enable APM first by following " - 'the instructions at this link: https://docs.instabug.com/reference#enable-or-disable-apm', - ); - } - - return Trace( - id: traceId, - name: name, - ); - } - - /// Sets attribute of an execution trace. - /// [String] id of the trace. - /// [String] key of attribute. - /// [String] value of attribute. - /// - /// Please migrate to the App Flows APIs: [startFlow], [setFlowAttribute], and [endFlow]. - @Deprecated( - 'Please migrate to the App Flows APIs: APM.startAppFlow, APM.endFlow, and APM.setFlowAttribute. This feature was deprecated in v13.0.0', - ) - static Future setExecutionTraceAttribute( - String id, - String key, - String value, - ) async { - return _host.setExecutionTraceAttribute(id, key, value); - } - - /// Ends an execution trace. - /// [String] id of the trace. - /// - /// Please migrate to the App Flows APIs: [startFlow], [setFlowAttribute], and [endFlow]. - @Deprecated( - 'Please migrate to the App Flows APIs: APM.startAppFlow, APM.endFlow, and APM.setFlowAttribute. This feature was deprecated in v13.0.0', - ) - static Future endExecutionTrace(String id) async { - return _host.endExecutionTrace(id); - } - /// Starts an AppFlow with the given [name]. /// /// The [name] must not be an empty string. It should be unique and not exceed 150 characters, diff --git a/lib/src/modules/instabug.dart b/lib/src/modules/instabug.dart index 80726fd7e..b0073b42a 100644 --- a/lib/src/modules/instabug.dart +++ b/lib/src/modules/instabug.dart @@ -262,31 +262,6 @@ class Instabug { return tags?.cast(); } - /// Adds experiments to the next report. - @Deprecated( - 'Please migrate to the new feature flags APIs: Instabug.addFeatureFlags.', - ) - static Future addExperiments(List experiments) async { - return _host.addExperiments(experiments); - } - - /// Removes certain experiments from the next report. - @Deprecated( - 'Please migrate to the new feature flags APIs: Instabug.removeFeatureFlags.', - ) - static Future removeExperiments(List experiments) async { - return _host.removeExperiments(experiments); - } - - /// Clears all experiments from the next report. - - @Deprecated( - 'Please migrate to the new feature flags APIs: Instabug.clearAllFeatureFlags.', - ) - static Future clearAllExperiments() async { - return _host.clearAllExperiments(); - } - /// Adds feature flags to the next report. static Future addFeatureFlags(List featureFlags) async { final map = {}; @@ -362,8 +337,13 @@ class Instabug { /// Sets the primary color of the SDK's UI. /// Sets the color of UI elements indicating interactivity or call to action. /// [color] primaryColor A color to set the UI elements of the SDK to. + /// + /// Note: This API is deprecated. Please use `Instabug.setTheme` instead. + @Deprecated( + 'This API is deprecated. Please use Instabug.setTheme instead.', + ) static Future setPrimaryColor(Color color) async { - return _host.setPrimaryColor(color.value); + await setTheme(ThemeConfig(primaryColor: color.toString())); } /// Adds specific user data that you need to be added to the reports @@ -493,4 +473,44 @@ class Instabug { static Future setAppVariant(String appVariant) async { return _host.setAppVariant(appVariant); } + + /// Sets a custom theme for Instabug UI elements. + /// + /// @param theme - Configuration object containing theme properties + /// + /// Example: + /// ```dart + /// + /// Instabug.setTheme(ThemeConfig( + /// primaryColor: '#FF6B6B', + /// secondaryTextColor: '#666666', + /// primaryTextColor: '#333333', + /// titleTextColor: '#000000', + /// backgroundColor: '#FFFFFF', + /// primaryTextStyle: 'bold', + /// secondaryTextStyle: 'normal', + /// titleTextStyle: 'bold', + /// ctaTextStyle: 'bold', + /// primaryFontPath: '/data/user/0/com.yourapp/files/fonts/YourFont.ttf', + /// secondaryFontPath: '/data/user/0/com.yourapp/files/fonts/YourFont.ttf', + /// ctaFontPath: '/data/user/0/com.yourapp/files/fonts/YourFont.ttf', + /// primaryFontAsset: 'fonts/YourFont.ttf', + /// secondaryFontAsset: 'fonts/YourFont.ttf' + /// )); + /// ``` + static Future setTheme(ThemeConfig themeConfig) async { + return _host.setTheme(themeConfig.toMap()); + } + + /// Sets the fullscreen mode for Instabug UI. + /// + /// [isFullscreen] - Whether to enable fullscreen mode or not. + /// + /// Example: + /// ```dart + /// Instabug.setFullscreen(true); + /// ``` + static Future setFullscreen(bool isEnabled) async { + return _host.setFullscreen(isEnabled); + } } diff --git a/pigeons/apm.api.dart b/pigeons/apm.api.dart index 84fe9eb8e..25beca00e 100644 --- a/pigeons/apm.api.dart +++ b/pigeons/apm.api.dart @@ -11,18 +11,9 @@ abstract class ApmHostApi { void setColdAppLaunchEnabled(bool isEnabled); void setAutoUITraceEnabled(bool isEnabled); - @async - String? startExecutionTrace(String id, String name); - void startFlow(String name); void setFlowAttribute(String name, String key, String? value); void endFlow(String name); - void setExecutionTraceAttribute( - String id, - String key, - String value, - ); - void endExecutionTrace(String id); void startUITrace(String name); void endUITrace(); void endAppLaunch(); diff --git a/pigeons/instabug.api.dart b/pigeons/instabug.api.dart index 6502409cc..aa91aec11 100644 --- a/pigeons/instabug.api.dart +++ b/pigeons/instabug.api.dart @@ -57,12 +57,6 @@ abstract class InstabugHostApi { @async List? getTags(); - void addExperiments(List experiments); - - void removeExperiments(List experiments); - - void clearAllExperiments(); - void addFeatureFlags(Map featureFlagsMap); void removeFeatureFlags(List featureFlags); @@ -106,4 +100,7 @@ abstract class InstabugHostApi { void willRedirectToStore(); void setNetworkLogBodyEnabled(bool isEnabled); + + void setTheme(Map themeConfig); + void setFullscreen(bool isEnabled); } diff --git a/test/apm_test.dart b/test/apm_test.dart index c801926f3..16cc2f26d 100644 --- a/test/apm_test.dart +++ b/test/apm_test.dart @@ -86,48 +86,6 @@ void main() { ).called(1); }); - test('[startExecutionTrace] should call host method', () async { - final id = DateTime.now(); - const name = "trace"; - - when(mDateTime.now()).thenAnswer((_) => id); - when(mHost.startExecutionTrace(id.toString(), name)) - .thenAnswer((_) async => id.toString()); - - // ignore: deprecated_member_use_from_same_package - final trace = await APM.startExecutionTrace(name); - - expect(trace.id, id.toString()); - - verify( - mHost.startExecutionTrace(id.toString(), name), - ).called(1); - }); - - test('[setExecutionTraceAttribute] should call host method', () async { - final id = DateTime.now().toString(); - const key = "attr-key"; - const attribute = "Trace Attribute"; - - // ignore: deprecated_member_use_from_same_package - await APM.setExecutionTraceAttribute(id, key, attribute); - - verify( - mHost.setExecutionTraceAttribute(id, key, attribute), - ).called(1); - }); - - test('[endExecutionTrace] should call host method', () async { - final id = DateTime.now().toString(); - - // ignore: deprecated_member_use_from_same_package - await APM.endExecutionTrace(id); - - verify( - mHost.endExecutionTrace(id), - ).called(1); - }); - test('[startFlow] should call host method', () async { const flowName = "flow-name"; await APM.startFlow(flowName); diff --git a/test/instabug_test.dart b/test/instabug_test.dart index b6f891221..37ce0d538 100644 --- a/test/instabug_test.dart +++ b/test/instabug_test.dart @@ -197,16 +197,6 @@ void main() { ).called(1); }); - test('[setPrimaryColor] should call host method', () async { - const color = Color(0x00000000); - - await Instabug.setPrimaryColor(color); - - verify( - mHost.setPrimaryColor(color.value), - ).called(1); - }); - test('[setSessionProfilerEnabled] should call host method', () async { const enabled = true; @@ -258,37 +248,6 @@ void main() { ).called(1); }); - test('[addExperiments] should call host method', () async { - const experiments = ["exp-1", "exp-2"]; - - // ignore: deprecated_member_use_from_same_package - await Instabug.addExperiments(experiments); - - verify( - mHost.addExperiments(experiments), - ).called(1); - }); - - test('[removeExperiments] should call host method', () async { - const experiments = ["exp-1", "exp-2"]; - - // ignore: deprecated_member_use_from_same_package - await Instabug.removeExperiments(experiments); - - verify( - mHost.removeExperiments(experiments), - ).called(1); - }); - - test('[clearAllExperiments] should call host method', () async { - // ignore: deprecated_member_use_from_same_package - await Instabug.clearAllExperiments(); - - verify( - mHost.clearAllExperiments(), - ).called(1); - }); - test('[addFeatureFlags] should call host method', () async { await Instabug.addFeatureFlags([ FeatureFlag(name: 'name1', variant: 'variant1'), @@ -474,4 +433,34 @@ void main() { mHost.willRedirectToStore(), ).called(1); }); + + test('[setFullscreen] should call host method', () async { + const isEnabled = true; + + await Instabug.setFullscreen(isEnabled); + + verify( + mHost.setFullscreen(isEnabled), + ).called(1); + }); + + test('[setFullscreen] should call host method with false', () async { + const isEnabled = false; + + await Instabug.setFullscreen(isEnabled); + + verify( + mHost.setFullscreen(isEnabled), + ).called(1); + }); + + test('[setTheme] should call host method with theme config', () async { + const themeConfig = ThemeConfig(primaryColor: '#FF0000'); + + await Instabug.setTheme(themeConfig); + + verify( + mHost.setTheme(themeConfig.toMap()), + ).called(1); + }); } diff --git a/test/trace_test.dart b/test/trace_test.dart deleted file mode 100644 index 2415420be..000000000 --- a/test/trace_test.dart +++ /dev/null @@ -1,46 +0,0 @@ -import 'package:flutter/widgets.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:instabug_flutter/instabug_flutter.dart'; -import 'package:instabug_flutter/src/generated/apm.api.g.dart'; -import 'package:mockito/annotations.dart'; -import 'package:mockito/mockito.dart'; - -import 'trace_test.mocks.dart'; - -@GenerateMocks([ - ApmHostApi, -]) -void main() { - TestWidgetsFlutterBinding.ensureInitialized(); - WidgetsFlutterBinding.ensureInitialized(); - - final mHost = MockApmHostApi(); - final trace = Trace( - id: "trace", - name: "Execution Trace", - ); - - setUpAll(() { - APM.$setHostApi(mHost); - }); - - test('[end] should call host method', () async { - // ignore: deprecated_member_use_from_same_package - trace.end(); - - verify( - mHost.endExecutionTrace(trace.id), - ).called(1); - }); - - test('[setAttribute] should call host method', () async { - const key = "attr-key"; - const attribute = "Trace Attribute"; - // ignore: deprecated_member_use_from_same_package - trace.setAttribute(key, attribute); - - verify( - mHost.setExecutionTraceAttribute(trace.id, key, attribute), - ).called(1); - }); -} From 364fa4575bd140cdf9880684cefbe001b3c441ec Mon Sep 17 00:00:00 2001 From: Andrew Amin Date: Thu, 14 Aug 2025 12:32:44 +0300 Subject: [PATCH 68/84] chore: update iOS custom pods --- example/ios/Podfile | 2 +- ios/instabug_flutter.podspec | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/example/ios/Podfile b/example/ios/Podfile index bbb7ad1f7..ed931ce33 100644 --- a/example/ios/Podfile +++ b/example/ios/Podfile @@ -30,7 +30,7 @@ target 'Runner' do use_frameworks! use_modular_headers! - pod 'Instabug', :podspec => 'https://ios-releases.instabug.com/custom/faeture-screen_rendering-release/15.1.24/Instabug.podspec' + pod 'Instabug', :podspec => 'https://ios-releases.instabug.com/custom/faeture-screen_rendering-release/15.1.29/Instabug.podspec' flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) end diff --git a/ios/instabug_flutter.podspec b/ios/instabug_flutter.podspec index 20348234e..608a5b261 100644 --- a/ios/instabug_flutter.podspec +++ b/ios/instabug_flutter.podspec @@ -17,6 +17,6 @@ Pod::Spec.new do |s| s.pod_target_xcconfig = { 'OTHER_LDFLAGS' => '-framework "Flutter" -framework "InstabugSDK"'} s.dependency 'Flutter' - s.dependency 'Instabug', '15.1.24' + s.dependency 'Instabug', '15.1.29' end From 3b90e9fb9fe22a315846a7438098b187d3fa8c0a Mon Sep 17 00:00:00 2001 From: Andrew Amin Date: Thu, 14 Aug 2025 15:15:47 +0300 Subject: [PATCH 69/84] chore: update the public api name --- lib/src/modules/apm.dart | 2 +- test/apm_test.dart | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/src/modules/apm.dart b/lib/src/modules/apm.dart index 31936e870..e323f6902 100644 --- a/lib/src/modules/apm.dart +++ b/lib/src/modules/apm.dart @@ -345,7 +345,7 @@ class APM { /// /// Returns: /// A Future is being returned. - static Future setScreenRenderEnabled(bool isEnabled) async { + static Future setScreenRenderingEnabled(bool isEnabled) async { return _host.setScreenRenderEnabled(isEnabled).then((_) async { if (isEnabled) { await InstabugScreenRenderManager.I.init(WidgetsBinding.instance); diff --git a/test/apm_test.dart b/test/apm_test.dart index 3ca288f68..4b16f4501 100644 --- a/test/apm_test.dart +++ b/test/apm_test.dart @@ -244,7 +244,7 @@ void main() { test("[setScreenRenderEnabled] should call host method", () async { const isEnabled = false; - await APM.setScreenRenderEnabled(isEnabled); + await APM.setScreenRenderingEnabled(isEnabled); verify(mHost.setScreenRenderEnabled(isEnabled)).called(1); }); @@ -252,7 +252,7 @@ void main() { "[setScreenRenderEnabled] should call [init()] screen render collector, is the feature is enabled", () async { const isEnabled = true; - await APM.setScreenRenderEnabled(isEnabled); + await APM.setScreenRenderingEnabled(isEnabled); verify(mScreenRenderManager.init(any)).called(1); verifyNoMoreInteractions(mScreenRenderManager); }); @@ -261,7 +261,7 @@ void main() { "[setScreenRenderEnabled] should call [remove()] screen render collector, is the feature is enabled", () async { const isEnabled = false; - await APM.setScreenRenderEnabled(isEnabled); + await APM.setScreenRenderingEnabled(isEnabled); verify(mScreenRenderManager.dispose()).called(1); verifyNoMoreInteractions(mScreenRenderManager); }); From e1d73f268b7f0b4cde493a26ef0bfe76f6697c06 Mon Sep 17 00:00:00 2001 From: Andrew Amin Date: Thu, 14 Aug 2025 15:54:52 +0300 Subject: [PATCH 70/84] chore: fix main.dart --- example/lib/main.dart | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index fa332490c..f035fc60b 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -44,11 +44,10 @@ void main() { Instabug.init( token: 'ed6f659591566da19b67857e1b9d40ab', - // token: '4d75635ae06e5afb4360c04cfcf1987c', invocationEvents: [InvocationEvent.floatingButton], debugLogsLevel: LogLevel.verbose, ).then((_) { - // APM.setScreenRenderEnabled(false); + APM.setScreenRenderingEnabled(true); }); FlutterError.onError = (FlutterErrorDetails details) { From f7b505e8f3de730ac1c28f98af2c59f738830a32 Mon Sep 17 00:00:00 2001 From: Andrew Amin Date: Sun, 17 Aug 2025 11:29:24 +0300 Subject: [PATCH 71/84] chore: fix screen_render_switch.dart --- example/lib/src/components/screen_render_switch.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/lib/src/components/screen_render_switch.dart b/example/lib/src/components/screen_render_switch.dart index d5c6d9e18..53238d807 100644 --- a/example/lib/src/components/screen_render_switch.dart +++ b/example/lib/src/components/screen_render_switch.dart @@ -28,7 +28,7 @@ class _ScreenRenderSwitchState extends State { } void onScreenRenderChanged(BuildContext context, bool value) { - APM.setScreenRenderEnabled(value); + APM.setScreenRenderingEnabled(value); showSnackBar(context, "Screen Render is ${value ? "enabled" : "disabled"}"); setState(() => isEnabled = value); } From a646dda61b0a846593af88aecc4fe3cdbb3c771d Mon Sep 17 00:00:00 2001 From: Andrew Amin Date: Sun, 17 Aug 2025 18:28:31 +0300 Subject: [PATCH 72/84] chore: fix store SR logic for custom ui traces --- android/build.gradle | 2 +- example/ios/Podfile.lock | 14 +++++++------- example/lib/main.dart | 10 +++++----- lib/src/modules/apm.dart | 13 ++++++++----- 4 files changed, 21 insertions(+), 18 deletions(-) diff --git a/android/build.gradle b/android/build.gradle index 9f27f88e1..cef6bc5f9 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -52,7 +52,7 @@ android { } dependencies { - api 'com.instabug.library:instabug:15.0.2.7085294-SNAPSHOT' + api 'com.instabug.library:instabug:15.0.2.7140337-SNAPSHOT' testImplementation 'junit:junit:4.13.2' testImplementation "org.mockito:mockito-inline:3.12.1" testImplementation "io.mockk:mockk:1.13.13" diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index 53dc15ace..0db0443b3 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -1,14 +1,14 @@ PODS: - Flutter (1.0.0) - - Instabug (15.1.24) + - Instabug (15.1.29) - instabug_flutter (14.3.0): - Flutter - - Instabug (= 15.1.24) + - Instabug (= 15.1.29) - OCMock (3.6) DEPENDENCIES: - Flutter (from `Flutter`) - - Instabug (from `https://ios-releases.instabug.com/custom/faeture-screen_rendering-release/15.1.24/Instabug.podspec`) + - Instabug (from `https://ios-releases.instabug.com/custom/faeture-screen_rendering-release/15.1.29/Instabug.podspec`) - instabug_flutter (from `.symlinks/plugins/instabug_flutter/ios`) - OCMock (= 3.6) @@ -20,16 +20,16 @@ EXTERNAL SOURCES: Flutter: :path: Flutter Instabug: - :podspec: https://ios-releases.instabug.com/custom/faeture-screen_rendering-release/15.1.24/Instabug.podspec + :podspec: https://ios-releases.instabug.com/custom/faeture-screen_rendering-release/15.1.29/Instabug.podspec instabug_flutter: :path: ".symlinks/plugins/instabug_flutter/ios" SPEC CHECKSUMS: Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 - Instabug: 81ff406348f7a9784ad2c681c94279a0ad3fcab7 - instabug_flutter: 7aeb6ad19cf4c388aef8955c3aad12ee5373adab + Instabug: c2ddabc44a1f425615fedba6331a7d1e8805e413 + instabug_flutter: 30227104e2ba5857bcd7794dc21e353bdb691f3e OCMock: 5ea90566be239f179ba766fd9fbae5885040b992 -PODFILE CHECKSUM: fb14c1a442ef94a558e4e301f3ea6ba54be132dd +PODFILE CHECKSUM: 8194fdeb7c217898e3faaeed21926a5fc586751d COCOAPODS: 1.15.2 diff --git a/example/lib/main.dart b/example/lib/main.dart index f035fc60b..6b4c7d1ee 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -39,16 +39,16 @@ part 'src/screens/screen_render_page.dart'; void main() { runZonedGuarded( - () { + () async { WidgetsFlutterBinding.ensureInitialized(); - Instabug.init( + await Instabug.init( token: 'ed6f659591566da19b67857e1b9d40ab', invocationEvents: [InvocationEvent.floatingButton], debugLogsLevel: LogLevel.verbose, - ).then((_) { - APM.setScreenRenderingEnabled(true); - }); + ); + + APM.setScreenRenderingEnabled(true); FlutterError.onError = (FlutterErrorDetails details) { Zone.current.handleUncaughtError(details.exception, details.stack!); diff --git a/lib/src/modules/apm.dart b/lib/src/modules/apm.dart index e323f6902..58bc0541e 100644 --- a/lib/src/modules/apm.dart +++ b/lib/src/modules/apm.dart @@ -138,13 +138,16 @@ class APM { /// Returns: /// The method is returning a `Future`. static Future startUITrace(String name) async { + final isScreenRenderingEnabled = + await FlagsConfig.screenRendering.isEnabled(); + if (isScreenRenderingEnabled) { + InstabugScreenRenderManager.I + .endScreenRenderCollector(UiTraceType.custom); + } return _host.startUITrace(name).then( - (_) async { + (_) { // Start screen render collector for custom ui trace if enabled. - if (await FlagsConfig.screenRendering.isEnabled()) { - InstabugScreenRenderManager.I - .endScreenRenderCollector(UiTraceType.custom); - + if (isScreenRenderingEnabled) { InstabugScreenRenderManager.I .startScreenRenderCollectorForTraceId(0, UiTraceType.custom); } From ab3bb29df34b38b7db3458cb597ebebd9fd4793d Mon Sep 17 00:00:00 2001 From: Andrew Amin Date: Sun, 17 Aug 2025 19:15:58 +0300 Subject: [PATCH 73/84] chore: rebase dev branch and resolve conflict --- example/lib/main.dart | 52 ++++++++++++++++++++--------------------- test/instabug_test.dart | 2 +- 2 files changed, 26 insertions(+), 28 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index bccdbfc68..9552c647e 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -1,44 +1,39 @@ import 'dart:async'; +import 'dart:convert'; import 'dart:developer'; import 'dart:io'; -import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:instabug_flutter/instabug_flutter.dart'; -import 'package:instabug_flutter_example/src/components/apm_switch.dart'; -import 'package:instabug_http_client/instabug_http_client.dart'; +import 'package:instabug_flutter/src/utils/screen_loading/screen_loading_manager.dart'; import 'package:instabug_flutter_example/src/app_routes.dart'; +import 'package:instabug_flutter_example/src/utils/show_messages.dart'; import 'package:instabug_flutter_example/src/widget/nested_view.dart'; +import 'package:instabug_http_client/instabug_http_client.dart'; import 'src/native/instabug_flutter_example_method_channel.dart'; import 'src/widget/instabug_button.dart'; import 'src/widget/instabug_clipboard_input.dart'; import 'src/widget/instabug_text_field.dart'; -import 'package:instabug_flutter/src/utils/screen_loading/screen_loading_manager.dart'; - import 'src/widget/section_title.dart'; -part 'src/screens/crashes_page.dart'; - -part 'src/screens/complex_page.dart'; - -part 'src/screens/apm_page.dart'; - -part 'src/screens/screen_capture_premature_extension_page.dart'; - -part 'src/screens/screen_loading_page.dart'; - -part 'src/screens/my_home_page.dart'; - +part 'src/components/animated_box.dart'; +part 'src/components/apm_switch.dart'; part 'src/components/fatal_crashes_content.dart'; - -part 'src/components/non_fatal_crashes_content.dart'; - +part 'src/components/flows_content.dart'; part 'src/components/network_content.dart'; - +part 'src/components/non_fatal_crashes_content.dart'; part 'src/components/page.dart'; - -part 'src/components/flows_content.dart'; +part 'src/components/screen_render.dart'; +part 'src/components/screen_render_switch.dart'; +part 'src/components/ui_traces_content.dart'; +part 'src/screens/apm_page.dart'; +part 'src/screens/complex_page.dart'; +part 'src/screens/crashes_page.dart'; +part 'src/screens/my_home_page.dart'; +part 'src/screens/screen_capture_premature_extension_page.dart'; +part 'src/screens/screen_loading_page.dart'; +part 'src/screens/screen_render_page.dart'; void main() { runZonedGuarded( @@ -46,10 +41,13 @@ void main() { WidgetsFlutterBinding.ensureInitialized(); Instabug.init( - token: 'ed6f659591566da19b67857e1b9d40ab', - invocationEvents: [InvocationEvent.floatingButton], - debugLogsLevel: LogLevel.verbose, - appVariant: 'variant 1'); + token: 'ed6f659591566da19b67857e1b9d40ab', + invocationEvents: [InvocationEvent.floatingButton], + debugLogsLevel: LogLevel.verbose, + appVariant: 'variant 1', + ).then((_) { + APM.setScreenRenderingEnabled(true); + }); FlutterError.onError = (FlutterErrorDetails details) { Zone.current.handleUncaughtError(details.exception, details.stack!); diff --git a/test/instabug_test.dart b/test/instabug_test.dart index b66a36e95..d87208202 100644 --- a/test/instabug_test.dart +++ b/test/instabug_test.dart @@ -85,7 +85,7 @@ void main() { ); //disable the feature flag for screen render feature in order to skip its checking. - when(mApmHost.isScreenRenderingEnabled()).thenAnswer((_) async => false); + when(mApmHost.isScreenRenderEnabled()).thenAnswer((_) async => false); await Instabug.init( token: token, From 96298dc5d78ba500d377f8f9755744e91d09d250 Mon Sep 17 00:00:00 2001 From: Andrew Amin Date: Mon, 18 Aug 2025 10:06:13 +0300 Subject: [PATCH 74/84] chore: update native android dependency --- android/build.gradle | 2 +- lib/src/utils/screen_loading/screen_loading_manager.dart | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/android/build.gradle b/android/build.gradle index cef6bc5f9..102714f6a 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -52,7 +52,7 @@ android { } dependencies { - api 'com.instabug.library:instabug:15.0.2.7140337-SNAPSHOT' + api 'com.instabug.library:instabug:15.0.2.7140934-SNAPSHOT' testImplementation 'junit:junit:4.13.2' testImplementation "org.mockito:mockito-inline:3.12.1" testImplementation "io.mockk:mockk:1.13.13" diff --git a/lib/src/utils/screen_loading/screen_loading_manager.dart b/lib/src/utils/screen_loading/screen_loading_manager.dart index fce8884b4..ca42af359 100644 --- a/lib/src/utils/screen_loading/screen_loading_manager.dart +++ b/lib/src/utils/screen_loading/screen_loading_manager.dart @@ -148,6 +148,9 @@ class ScreenLoadingManager { try { resetDidStartScreenLoading(); + final isSDKBuilt = + await _checkInstabugSDKBuilt("APM.InstabugCaptureScreenLoading"); + if (!isSDKBuilt) return null; // TODO: On Android, FlagsConfig.apm.isEnabled isn't implemented correctly // so we skip the isApmEnabled check on Android and only check on iOS. // This is a temporary fix until we implement the isEnabled check correctly. From ba7a535df7a399f151819abeb595bbd535cf617d Mon Sep 17 00:00:00 2001 From: Andrew Amin Date: Tue, 19 Aug 2025 22:04:19 +0300 Subject: [PATCH 75/84] fix: dropping SR data for customUiTrace when disable AutoUiTrace --- android/build.gradle | 2 +- .../com/instabug/flutter/modules/ApmApi.java | 14 + .../java/com/instabug/flutter/ApmApiTest.java | 22 + example/ios/InstabugTests/ApmApiTests.m | 16 + example/ios/Podfile | 2 +- example/ios/Podfile.lock | 14 +- example/lib/main.dart | 11 +- ios/Classes/Modules/ApmApi.m | 7 + ios/Classes/Modules/InstabugApi.m | 2 +- ios/instabug_flutter.podspec | 2 +- lib/src/modules/apm.dart | 35 +- .../utils/instabug_navigator_observer.dart | 21 +- .../screen_loading_manager.dart | 13 +- .../instabug_screen_render_manager.dart | 40 +- .../instabug_widget_binding_observer.dart | 8 +- lib/src/utils/ui_trace/flags_config.dart | 2 + pigeons/apm.api.dart | 3 + test/apm_test.dart | 15 +- .../screen_loading_manager_test.dart | 9 +- .../instabug_screen_render_manager_test.dart | 15 +- ...abug_screen_render_manager_test_mocks.dart | 814 ------------------ 21 files changed, 189 insertions(+), 878 deletions(-) delete mode 100644 test/utils/screen_render/instabug_screen_render_manager_test_mocks.dart diff --git a/android/build.gradle b/android/build.gradle index 102714f6a..92b3a865e 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -52,7 +52,7 @@ android { } dependencies { - api 'com.instabug.library:instabug:15.0.2.7140934-SNAPSHOT' + api 'com.instabug.library:instabug:15.0.2.7160278-SNAPSHOT' testImplementation 'junit:junit:4.13.2' testImplementation "org.mockito:mockito-inline:3.12.1" testImplementation "io.mockk:mockk:1.13.13" diff --git a/android/src/main/java/com/instabug/flutter/modules/ApmApi.java b/android/src/main/java/com/instabug/flutter/modules/ApmApi.java index ab1f0dd86..fb58834e6 100644 --- a/android/src/main/java/com/instabug/flutter/modules/ApmApi.java +++ b/android/src/main/java/com/instabug/flutter/modules/ApmApi.java @@ -374,6 +374,20 @@ public void isEndScreenLoadingEnabled(@NonNull ApmPigeon.Result result) isScreenLoadingEnabled(result); } + @Override + public void isAutoUiTraceEnabled(@NonNull ApmPigeon.Result result) { + try { + InternalAPM._isFeatureEnabledCP(APMFeature.UI_TRACE, "InstabugCaptureScreenLoading", new FeatureAvailabilityCallback() { + @Override + public void invoke(boolean isFeatureAvailable) { + result.success(isFeatureAvailable); + } + }); + } catch (Exception e) { + e.printStackTrace(); + } + } + @Override public void isEnabled(@NonNull ApmPigeon.Result result) { try { diff --git a/android/src/test/java/com/instabug/flutter/ApmApiTest.java b/android/src/test/java/com/instabug/flutter/ApmApiTest.java index d7bacc450..81b9d2584 100644 --- a/android/src/test/java/com/instabug/flutter/ApmApiTest.java +++ b/android/src/test/java/com/instabug/flutter/ApmApiTest.java @@ -328,6 +328,28 @@ public void testSetScreenLoadingMonitoringEnabled() { mAPM.verify(() -> APM.setScreenLoadingEnabled(isEnabled)); } + @Test + public void testIsAutoUiTraceEnabled() { + + boolean expected = true; + ApmPigeon.Result result = spy(makeResult((actual) -> assertEquals(expected, actual))); + + mInternalApmStatic.when(() -> InternalAPM._isFeatureEnabledCP(any(), any(), any())).thenAnswer( + invocation -> { + FeatureAvailabilityCallback callback = (FeatureAvailabilityCallback) invocation.getArguments()[2]; + callback.invoke(expected); + return null; + }); + + + api.isScreenRenderEnabled(result); + + mInternalApmStatic.verify(() -> InternalAPM._isFeatureEnabledCP(any(), any(), any())); + mInternalApmStatic.verifyNoMoreInteractions(); + + verify(result).success(expected); + } + @Test public void testIsScreenRenderEnabled() { diff --git a/example/ios/InstabugTests/ApmApiTests.m b/example/ios/InstabugTests/ApmApiTests.m index e18643bf7..6d8ea2a33 100644 --- a/example/ios/InstabugTests/ApmApiTests.m +++ b/example/ios/InstabugTests/ApmApiTests.m @@ -199,6 +199,22 @@ - (void)testEndScreenLoading { OCMVerify([self.mAPM endScreenLoadingCPWithEndTimestampMUS:endScreenLoadingCPWithEndTimestampMUS]); } +- (void)testIsAutoUiTraceEnabled { + XCTestExpectation *expectation = [self expectationWithDescription:@"Call completion handler"]; + + BOOL isAutoUiTraceEnabled = YES; + OCMStub([self.mAPM autoUITraceEnabled]).andReturn(isAutoUiTraceEnabled); + + [self.api isAutoUiTraceEnabledWithCompletion:^(NSNumber *isEnabledNumber, FlutterError *error) { + [expectation fulfill]; + + XCTAssertEqualObjects(isEnabledNumber, @(isAutoUiTraceEnabled)); + XCTAssertNil(error); + }]; + + [self waitForExpectations:@[expectation] timeout:5.0]; +} + - (void)testIsScreenRenderEnabled { XCTestExpectation *expectation = [self expectationWithDescription:@"Call completion handler"]; diff --git a/example/ios/Podfile b/example/ios/Podfile index ed931ce33..1768d6c13 100644 --- a/example/ios/Podfile +++ b/example/ios/Podfile @@ -30,7 +30,7 @@ target 'Runner' do use_frameworks! use_modular_headers! - pod 'Instabug', :podspec => 'https://ios-releases.instabug.com/custom/faeture-screen_rendering-release/15.1.29/Instabug.podspec' + pod 'Instabug', :podspec => 'https://ios-releases.instabug.com/custom/faeture-screen_rendering-release/15.1.31/Instabug.podspec' flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) end diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index 0db0443b3..648043285 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -1,14 +1,14 @@ PODS: - Flutter (1.0.0) - - Instabug (15.1.29) + - Instabug (15.1.31) - instabug_flutter (14.3.0): - Flutter - - Instabug (= 15.1.29) + - Instabug (= 15.1.31) - OCMock (3.6) DEPENDENCIES: - Flutter (from `Flutter`) - - Instabug (from `https://ios-releases.instabug.com/custom/faeture-screen_rendering-release/15.1.29/Instabug.podspec`) + - Instabug (from `https://ios-releases.instabug.com/custom/faeture-screen_rendering-release/15.1.31/Instabug.podspec`) - instabug_flutter (from `.symlinks/plugins/instabug_flutter/ios`) - OCMock (= 3.6) @@ -20,16 +20,16 @@ EXTERNAL SOURCES: Flutter: :path: Flutter Instabug: - :podspec: https://ios-releases.instabug.com/custom/faeture-screen_rendering-release/15.1.29/Instabug.podspec + :podspec: https://ios-releases.instabug.com/custom/faeture-screen_rendering-release/15.1.31/Instabug.podspec instabug_flutter: :path: ".symlinks/plugins/instabug_flutter/ios" SPEC CHECKSUMS: Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 - Instabug: c2ddabc44a1f425615fedba6331a7d1e8805e413 - instabug_flutter: 30227104e2ba5857bcd7794dc21e353bdb691f3e + Instabug: 447d3f5a9f1c83120235437e08c9a51aaa8f8605 + instabug_flutter: 65aa2dee3036a3c7c8feff8e898c9547239a891d OCMock: 5ea90566be239f179ba766fd9fbae5885040b992 -PODFILE CHECKSUM: 8194fdeb7c217898e3faaeed21926a5fc586751d +PODFILE CHECKSUM: c5b98f57c27da87950775c360d20aaedd3216b8d COCOAPODS: 1.15.2 diff --git a/example/lib/main.dart b/example/lib/main.dart index 9552c647e..6979ec702 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -37,18 +37,17 @@ part 'src/screens/screen_render_page.dart'; void main() { runZonedGuarded( - () { + () async { WidgetsFlutterBinding.ensureInitialized(); - Instabug.init( + await Instabug.init( token: 'ed6f659591566da19b67857e1b9d40ab', invocationEvents: [InvocationEvent.floatingButton], debugLogsLevel: LogLevel.verbose, appVariant: 'variant 1', - ).then((_) { - APM.setScreenRenderingEnabled(true); - }); - + ); + APM.setScreenRenderingEnabled(true); + APM.setAutoUITraceEnabled(false); FlutterError.onError = (FlutterErrorDetails details) { Zone.current.handleUncaughtError(details.exception, details.stack!); }; diff --git a/ios/Classes/Modules/ApmApi.m b/ios/Classes/Modules/ApmApi.m index b4d6bd161..ac16b84da 100644 --- a/ios/Classes/Modules/ApmApi.m +++ b/ios/Classes/Modules/ApmApi.m @@ -218,6 +218,13 @@ - (void)getDeviceRefreshRateAndToleranceWithCompletion:(nonnull void (^)(NSArray } } +- (void)isAutoUiTraceEnabledWithCompletion:(nonnull void (^)(NSNumber * _Nullable, FlutterError * _Nullable))completion { + BOOL isAutoUiTraceIsEnabled = IBGAPM.autoUITraceEnabled && IBGAPM.enabled; + NSNumber *isEnabledNumber = @(isAutoUiTraceIsEnabled); + completion(isEnabledNumber, nil); +} + + diff --git a/ios/Classes/Modules/InstabugApi.m b/ios/Classes/Modules/InstabugApi.m index 84f574b58..813173c9d 100644 --- a/ios/Classes/Modules/InstabugApi.m +++ b/ios/Classes/Modules/InstabugApi.m @@ -106,7 +106,7 @@ - (void)setWelcomeMessageModeMode:(NSString *)mode error:(FlutterError *_Nullabl } - (void)setPrimaryColorColor:(NSNumber *)color error:(FlutterError *_Nullable *_Nonnull)error { - Instabug.tintColor = UIColorFromRGB([color longValue]); +// Instabug.tintColor = UIColorFromRGB([color longValue]); } - (void)setSessionProfilerEnabledEnabled:(NSNumber *)enabled error:(FlutterError *_Nullable *_Nonnull)error { diff --git a/ios/instabug_flutter.podspec b/ios/instabug_flutter.podspec index 608a5b261..f216fdaf0 100644 --- a/ios/instabug_flutter.podspec +++ b/ios/instabug_flutter.podspec @@ -17,6 +17,6 @@ Pod::Spec.new do |s| s.pod_target_xcconfig = { 'OTHER_LDFLAGS' => '-framework "Flutter" -framework "InstabugSDK"'} s.dependency 'Flutter' - s.dependency 'Instabug', '15.1.29' + s.dependency 'Instabug', '15.1.31' end diff --git a/lib/src/modules/apm.dart b/lib/src/modules/apm.dart index 58bc0541e..1ce12d413 100644 --- a/lib/src/modules/apm.dart +++ b/lib/src/modules/apm.dart @@ -1,8 +1,9 @@ // ignore_for_file: avoid_classes_with_only_static_members import 'dart:async'; +import 'dart:developer'; -import 'package:flutter/widgets.dart' show WidgetBuilder, WidgetsBinding; +import 'package:flutter/widgets.dart' show WidgetBuilder; import 'package:instabug_flutter/src/generated/apm.api.g.dart'; import 'package:instabug_flutter/src/models/instabug_screen_render_data.dart'; import 'package:instabug_flutter/src/models/network_data.dart'; @@ -140,6 +141,11 @@ class APM { static Future startUITrace(String name) async { final isScreenRenderingEnabled = await FlagsConfig.screenRendering.isEnabled(); + log("startUITrace: isScreenRenderEnabled: $isScreenRenderingEnabled"); + await InstabugScreenRenderManager.I + .checkForScreenRenderInitialization(isScreenRenderingEnabled); + + // Ends the active custom ui trace before starting new one. if (isScreenRenderingEnabled) { InstabugScreenRenderManager.I .endScreenRenderCollector(UiTraceType.custom); @@ -162,8 +168,15 @@ class APM { static Future endUITrace() async { // End screen render collector for custom ui trace if enabled. if (InstabugScreenRenderManager.I.screenRenderEnabled) { - return InstabugScreenRenderManager.I + InstabugScreenRenderManager.I .endScreenRenderCollector(UiTraceType.custom); + + final isAutoUiTraceEnabled = await FlagsConfig.uiTrace.isEnabled(); + + // dispose the InstabugScreenRenderManager if AutoUiTrace is disabled. + if (!isAutoUiTraceEnabled) InstabugScreenRenderManager.I.dispose(); + + return; } return _host.endUITrace(); @@ -316,6 +329,16 @@ class APM { return ScreenLoadingManager.wrapRoutes(routes, exclude: exclude); } + /// Returns a Future indicating whether the auto + /// ui trace is enabled. + /// + /// Returns: + /// A Future is being returned. + @internal + static Future isAutoUiTraceEnabled() async { + return _host.isAutoUiTraceEnabled(); + } + /// Returns a Future indicating whether the screen /// render is enabled. /// @@ -349,13 +372,7 @@ class APM { /// Returns: /// A Future is being returned. static Future setScreenRenderingEnabled(bool isEnabled) async { - return _host.setScreenRenderEnabled(isEnabled).then((_) async { - if (isEnabled) { - await InstabugScreenRenderManager.I.init(WidgetsBinding.instance); - } else { - InstabugScreenRenderManager.I.dispose(); - } - }); + return _host.setScreenRenderEnabled(isEnabled); } /// Ends screen rendering for diff --git a/lib/src/utils/instabug_navigator_observer.dart b/lib/src/utils/instabug_navigator_observer.dart index 8272c66ab..f10dce436 100644 --- a/lib/src/utils/instabug_navigator_observer.dart +++ b/lib/src/utils/instabug_navigator_observer.dart @@ -1,4 +1,5 @@ import 'dart:async'; +import 'dart:developer'; import 'package:flutter/material.dart'; import 'package:instabug_flutter/instabug_flutter.dart'; @@ -67,23 +68,15 @@ class InstabugNavigatorObserver extends NavigatorObserver { } FutureOr _startScreenRenderCollector(int? uiTraceId) async { + if (uiTraceId == null) return; final isScreenRenderEnabled = await FlagsConfig.screenRendering.isEnabled(); - await _checkForScreenRenderInitialization(isScreenRenderEnabled); - if (uiTraceId != null && isScreenRenderEnabled) { + log("isScreenRenderEnabled: $isScreenRenderEnabled"); + + await InstabugScreenRenderManager.I + .checkForScreenRenderInitialization(isScreenRenderEnabled); + if (isScreenRenderEnabled) { InstabugScreenRenderManager.I .startScreenRenderCollectorForTraceId(uiTraceId); } } - - Future _checkForScreenRenderInitialization(bool isScreenRender) async { - if (isScreenRender) { - if (!InstabugScreenRenderManager.I.screenRenderEnabled) { - await InstabugScreenRenderManager.I.init(WidgetsBinding.instance); - } - } else { - if (InstabugScreenRenderManager.I.screenRenderEnabled) { - InstabugScreenRenderManager.I.dispose(); - } - } - } } diff --git a/lib/src/utils/screen_loading/screen_loading_manager.dart b/lib/src/utils/screen_loading/screen_loading_manager.dart index ca42af359..9a2747622 100644 --- a/lib/src/utils/screen_loading/screen_loading_manager.dart +++ b/lib/src/utils/screen_loading/screen_loading_manager.dart @@ -149,14 +149,13 @@ class ScreenLoadingManager { resetDidStartScreenLoading(); final isSDKBuilt = - await _checkInstabugSDKBuilt("APM.InstabugCaptureScreenLoading"); + await _checkInstabugSDKBuilt("APM.InstabugCaptureScreenLoading"); + if (!isSDKBuilt) return null; - // TODO: On Android, FlagsConfig.apm.isEnabled isn't implemented correctly - // so we skip the isApmEnabled check on Android and only check on iOS. - // This is a temporary fix until we implement the isEnabled check correctly. - // We need to fix this in the future. - final isApmEnabled = await FlagsConfig.apm.isEnabled(); - if (!isApmEnabled && IBGBuildInfo.I.isIOS) { + + final isAutoUiTraceEnabled = await FlagsConfig.uiTrace.isEnabled(); + + if (!isAutoUiTraceEnabled) { InstabugLogger.I.e( 'APM is disabled, skipping starting the UI trace for screen: $screenName.\n' 'Please refer to the documentation for how to enable APM on your app: ' diff --git a/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart b/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart index 718c9b473..8114d349e 100644 --- a/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart +++ b/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart @@ -1,4 +1,5 @@ import 'dart:async'; +import 'dart:developer'; import 'dart:ui' show TimingsCallback, FrameTiming, FramePhase; import 'package:flutter/widgets.dart'; @@ -122,7 +123,7 @@ class InstabugScreenRenderManager { UiTraceType type = UiTraceType.auto, ]) { // Return if frameTimingListener not attached - if (frameCollectorIsNotActive) return; + if (_frameCollectorIsNotActive) return; if (type == UiTraceType.custom) { _screenRenderForCustomUiTrace.traceId = traceId; @@ -138,7 +139,7 @@ class InstabugScreenRenderManager { UiTraceType type = UiTraceType.auto, ]) { // Return if frameTimingListener not attached - if (frameCollectorIsNotActive) return; + if (_frameCollectorIsNotActive) return; //Save the memory cached data to be sent to native side if (_delayedFrames.isNotEmpty) { @@ -163,7 +164,7 @@ class InstabugScreenRenderManager { @internal void stopScreenRenderCollector() { // Return if frameTimingListener not attached - if (frameCollectorIsNotActive) return; + if (_frameCollectorIsNotActive) return; if (_delayedFrames.isNotEmpty) { _saveCollectedData(); @@ -183,10 +184,23 @@ class InstabugScreenRenderManager { } } - bool get frameCollectorIsNotActive => - !screenRenderEnabled || !_isTimingsListenerAttached; + @internal + Future checkForScreenRenderInitialization( + bool isScreenRenderEnabledFromBackend, + ) async { + if (isScreenRenderEnabledFromBackend) { + if (!screenRenderEnabled) { + await init(WidgetsBinding.instance); + } + } else { + if (screenRenderEnabled) { + dispose(); + } + } + } /// Dispose InstabugScreenRenderManager by removing timings callback and cashed data. + @internal void dispose() { try { _resetCachedFrameData(); @@ -194,6 +208,7 @@ class InstabugScreenRenderManager { _removeWidgetBindingObserver(); _widgetsBinding = null; screenRenderEnabled = false; + _epochOffset = null; } catch (error, stackTrace) { _logExceptionErrorAndStackTrace(error, stackTrace); } @@ -211,6 +226,9 @@ class InstabugScreenRenderManager { bool get _isTotalTimeLarge => _totalTimeMs >= _frozenFrameThresholdMs; + bool get _frameCollectorIsNotActive => + !screenRenderEnabled || !_isTimingsListenerAttached; + /// Calculate the target time for the frame to be drawn in milliseconds based on the device refresh rate. double _targetMsPerFrame(double displayRefreshRate) => 1 / displayRefreshRate * 1000; @@ -301,6 +319,10 @@ class InstabugScreenRenderManager { /// Save Slow/Frozen Frames data void _onDelayedFrameDetected(int startTime, int durationInMicroseconds) { + log( + "${durationInMicroseconds >= 700000 ? "🚨Frozen" : "⚠️Slow"} Frame Detected (startTime: $startTime, duration: $durationInMicroseconds µs)", + name: tag, + ); _delayedFrames.add( InstabugFrameData( startTime, @@ -317,6 +339,10 @@ class InstabugScreenRenderManager { ) async { try { screenRenderData.saveEndTime(); + log( + "reportScreenRenderForCustomUiTrace $screenRenderData", + name: tag, + ); await APM.endScreenRenderForCustomUiTrace(screenRenderData); return true; } catch (error, stackTrace) { @@ -334,6 +360,10 @@ class InstabugScreenRenderManager { try { // Save the end time for the running ui trace, it's only needed in Android SDK. screenRenderData.saveEndTime(); + log( + "reportScreenRenderForAutoUiTrace $screenRenderData", + name: tag, + ); await APM.endScreenRenderForAutoUiTrace(screenRenderData); return true; diff --git a/lib/src/utils/screen_rendering/instabug_widget_binding_observer.dart b/lib/src/utils/screen_rendering/instabug_widget_binding_observer.dart index 3c18b1642..d454309c1 100644 --- a/lib/src/utils/screen_rendering/instabug_widget_binding_observer.dart +++ b/lib/src/utils/screen_rendering/instabug_widget_binding_observer.dart @@ -36,7 +36,10 @@ class InstabugWidgetsBindingObserver extends WidgetsBindingObserver { .then((uiTraceId) { if (uiTraceId != null && InstabugScreenRenderManager.I.screenRenderEnabled) { + //End any active ScreenRenderCollector before starting a new one (Safe garde condition). InstabugScreenRenderManager.I.endScreenRenderCollector(); + + //Start new ScreenRenderCollector. InstabugScreenRenderManager.I .startScreenRenderCollectorForTraceId(uiTraceId); } @@ -49,11 +52,10 @@ class InstabugWidgetsBindingObserver extends WidgetsBindingObserver { } } - void _handleDetachedState() { + Future _handleDetachedState() async { if (InstabugScreenRenderManager.I.screenRenderEnabled) { - InstabugScreenRenderManager.I.stopScreenRenderCollector(); + dispose(); } - dispose(); } void _handleDefaultState() { diff --git a/lib/src/utils/ui_trace/flags_config.dart b/lib/src/utils/ui_trace/flags_config.dart index 92a899b15..bc447b70b 100644 --- a/lib/src/utils/ui_trace/flags_config.dart +++ b/lib/src/utils/ui_trace/flags_config.dart @@ -13,6 +13,8 @@ extension FeatureExtensions on FlagsConfig { switch (this) { case FlagsConfig.apm: return APM.isEnabled(); + case FlagsConfig.uiTrace: + return APM.isAutoUiTraceEnabled(); case FlagsConfig.screenLoading: return APM.isScreenLoadingEnabled(); case FlagsConfig.endScreenLoading: diff --git a/pigeons/apm.api.dart b/pigeons/apm.api.dart index eb7201792..5d7bc1ea7 100644 --- a/pigeons/apm.api.dart +++ b/pigeons/apm.api.dart @@ -32,6 +32,9 @@ abstract class ApmHostApi { @async bool isEndScreenLoadingEnabled(); + @async + bool isAutoUiTraceEnabled(); + @async bool isScreenRenderEnabled(); diff --git a/test/apm_test.dart b/test/apm_test.dart index 4b16f4501..90df62787 100644 --- a/test/apm_test.dart +++ b/test/apm_test.dart @@ -89,6 +89,12 @@ void main() { ).called(1); }); + test("[isAutoUiTraceEnabled] should call host method", () async { + when(mHost.isAutoUiTraceEnabled()).thenAnswer((_) async => true); + await APM.isAutoUiTraceEnabled(); + verify(mHost.isAutoUiTraceEnabled()); + }); + test('[startFlow] should call host method', () async { const flowName = "flow-name"; await APM.startFlow(flowName); @@ -226,6 +232,7 @@ void main() { }); tearDown(() { reset(mScreenRenderManager); + reset(mHost); }); test("[isScreenRenderEnabled] should call host method", () async { when(mHost.isScreenRenderEnabled()).thenAnswer((_) async => true); @@ -242,8 +249,9 @@ void main() { verify(mHost.getDeviceRefreshRateAndTolerance()).called(1); }); - test("[setScreenRenderEnabled] should call host method", () async { + test("[setScreenRenderingEnabled] should call host method", () async { const isEnabled = false; + when(mScreenRenderManager.screenRenderEnabled).thenReturn(false); await APM.setScreenRenderingEnabled(isEnabled); verify(mHost.setScreenRenderEnabled(isEnabled)).called(1); }); @@ -252,6 +260,7 @@ void main() { "[setScreenRenderEnabled] should call [init()] screen render collector, is the feature is enabled", () async { const isEnabled = true; + when(mHost.isScreenRenderEnabled()).thenAnswer((_) async => true); await APM.setScreenRenderingEnabled(isEnabled); verify(mScreenRenderManager.init(any)).called(1); verifyNoMoreInteractions(mScreenRenderManager); @@ -261,9 +270,10 @@ void main() { "[setScreenRenderEnabled] should call [remove()] screen render collector, is the feature is enabled", () async { const isEnabled = false; + when(mScreenRenderManager.screenRenderEnabled).thenReturn(true); await APM.setScreenRenderingEnabled(isEnabled); verify(mScreenRenderManager.dispose()).called(1); - verifyNoMoreInteractions(mScreenRenderManager); + verify(mScreenRenderManager.screenRenderEnabled).called(1); }); test( @@ -306,6 +316,7 @@ void main() { "[endUITrace] should stop screen render collector with, if screen render feature is enabled", () async { when(mHost.isScreenRenderEnabled()).thenAnswer((_) async => true); + when(mHost.isAutoUiTraceEnabled()).thenAnswer((_) async => true); when(mScreenRenderManager.screenRenderEnabled).thenReturn(true); await APM.endUITrace(); diff --git a/test/utils/screen_loading/screen_loading_manager_test.dart b/test/utils/screen_loading/screen_loading_manager_test.dart index 6b5c954f3..1d8598948 100644 --- a/test/utils/screen_loading/screen_loading_manager_test.dart +++ b/test/utils/screen_loading/screen_loading_manager_test.dart @@ -171,8 +171,7 @@ void main() { test('[startUiTrace] with APM disabled on iOS Platform should Log error', () async { mScreenLoadingManager.currentUiTrace = uiTrace; - when(FlagsConfig.apm.isEnabled()).thenAnswer((_) async => false); - when(IBGBuildInfo.I.isIOS).thenReturn(true); + when(FlagsConfig.uiTrace.isEnabled()).thenAnswer((_) async => false); await ScreenLoadingManager.I.startUiTrace(screenName); @@ -192,8 +191,7 @@ void main() { test( '[startUiTrace] with APM enabled on android Platform should call `APM.startCpUiTrace and set UiTrace', () async { - when(FlagsConfig.apm.isEnabled()).thenAnswer((_) async => true); - when(IBGBuildInfo.I.isIOS).thenReturn(false); + when(FlagsConfig.uiTrace.isEnabled()).thenAnswer((_) async => true); await ScreenLoadingManager.I.startUiTrace(screenName); @@ -217,8 +215,7 @@ void main() { test( '[startUiTrace] with APM enabled should create a UI trace with the matching screen name', () async { - when(FlagsConfig.apm.isEnabled()).thenAnswer((_) async => true); - when(IBGBuildInfo.I.isIOS).thenReturn(false); + when(FlagsConfig.uiTrace.isEnabled()).thenAnswer((_) async => true); when( RouteMatcher.I.match( routePath: anyNamed('routePath'), diff --git a/test/utils/screen_render/instabug_screen_render_manager_test.dart b/test/utils/screen_render/instabug_screen_render_manager_test.dart index 2282b8b80..918dfa168 100644 --- a/test/utils/screen_render/instabug_screen_render_manager_test.dart +++ b/test/utils/screen_render/instabug_screen_render_manager_test.dart @@ -1,13 +1,26 @@ +import 'dart:ui' show FrameTiming; + +import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:instabug_flutter/instabug_flutter.dart'; +import 'package:instabug_flutter/src/generated/apm.api.g.dart'; +import 'package:instabug_flutter/src/generated/crash_reporting.api.g.dart'; import 'package:instabug_flutter/src/models/instabug_frame_data.dart'; import 'package:instabug_flutter/src/models/instabug_screen_render_data.dart'; import 'package:instabug_flutter/src/utils/instabug_logger.dart'; import 'package:instabug_flutter/src/utils/screen_rendering/instabug_screen_render_manager.dart'; +import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; -import 'instabug_screen_render_manager_test_mocks.dart'; +import 'instabug_screen_render_manager_test.mocks.dart'; +@GenerateMocks([ + ApmHostApi, + WidgetsBinding, + FrameTiming, + CrashReportingHostApi, + InstabugLogger, +]) void main() { TestWidgetsFlutterBinding.ensureInitialized(); diff --git a/test/utils/screen_render/instabug_screen_render_manager_test_mocks.dart b/test/utils/screen_render/instabug_screen_render_manager_test_mocks.dart deleted file mode 100644 index fbb7545dd..000000000 --- a/test/utils/screen_render/instabug_screen_render_manager_test_mocks.dart +++ /dev/null @@ -1,814 +0,0 @@ -// Mocks generated by Mockito 5.2.0 from annotations -// in instabug_flutter/example/ios/.symlinks/plugins/instabug_flutter/test/utils/screen_render/instabug_screen_render_manager_test.dart. -// Do not manually edit this file. - -import 'dart:async' as _i8; -import 'dart:developer' as _i12; -import 'dart:ui' as _i4; - -import 'package:flutter/foundation.dart' as _i11; -import 'package:flutter/gestures.dart' as _i6; -import 'package:flutter/rendering.dart' as _i3; -import 'package:flutter/scheduler.dart' as _i9; -import 'package:flutter/services.dart' as _i5; -import 'package:flutter/src/widgets/binding.dart' as _i7; -import 'package:flutter/src/widgets/focus_manager.dart' as _i2; -import 'package:flutter/src/widgets/framework.dart' as _i10; -import 'package:instabug_flutter/instabug_flutter.dart' as _i16; -import 'package:instabug_flutter/src/generated/apm.api.g.dart' as _i13; -import 'package:instabug_flutter/src/generated/crash_reporting.api.g.dart' - as _i14; -import 'package:instabug_flutter/src/utils/instabug_logger.dart' as _i15; -import 'package:mockito/mockito.dart' as _i1; - -// ignore_for_file: type=lint -// ignore_for_file: avoid_redundant_argument_values -// ignore_for_file: avoid_setters_without_getters -// ignore_for_file: comment_references -// ignore_for_file: implementation_imports -// ignore_for_file: invalid_use_of_visible_for_testing_member -// ignore_for_file: prefer_const_constructors -// ignore_for_file: unnecessary_parenthesis -// ignore_for_file: camel_case_types - -class _FakeFocusManager_0 extends _i1.Fake implements _i2.FocusManager { - @override - String toString({_i3.DiagnosticLevel? minLevel = _i3.DiagnosticLevel.info}) => - super.toString(); -} - -class _FakeSingletonFlutterWindow_1 extends _i1.Fake - implements _i4.SingletonFlutterWindow {} - -class _FakePlatformDispatcher_2 extends _i1.Fake - implements _i4.PlatformDispatcher {} - -class _FakeHardwareKeyboard_3 extends _i1.Fake - implements _i5.HardwareKeyboard {} - -class _FakeKeyEventManager_4 extends _i1.Fake implements _i5.KeyEventManager {} - -class _FakeBinaryMessenger_5 extends _i1.Fake implements _i5.BinaryMessenger {} - -class _FakeChannelBuffers_6 extends _i1.Fake implements _i4.ChannelBuffers {} - -class _FakeRestorationManager_7 extends _i1.Fake - implements _i5.RestorationManager {} - -class _FakeDuration_8 extends _i1.Fake implements Duration {} - -class _FakePointerRouter_9 extends _i1.Fake implements _i6.PointerRouter {} - -class _FakeGestureArenaManager_10 extends _i1.Fake - implements _i6.GestureArenaManager {} - -class _FakePointerSignalResolver_11 extends _i1.Fake - implements _i6.PointerSignalResolver {} - -class _FakeMouseTracker_12 extends _i1.Fake implements _i3.MouseTracker {} - -class _FakePipelineOwner_13 extends _i1.Fake implements _i3.PipelineOwner {} - -class _FakeRenderView_14 extends _i1.Fake implements _i3.RenderView { - @override - String toString({_i3.DiagnosticLevel? minLevel = _i3.DiagnosticLevel.info}) => - super.toString(); -} - -class _FakeAccessibilityFeatures_15 extends _i1.Fake - implements _i4.AccessibilityFeatures {} - -class _FakeViewConfiguration_16 extends _i1.Fake - implements _i3.ViewConfiguration {} - -class _FakeSemanticsUpdateBuilder_17 extends _i1.Fake - implements _i4.SemanticsUpdateBuilder {} - -/// A class which mocks [WidgetsBinding]. -/// -/// See the documentation for Mockito's code generation for more information. -class MockWidgetsBinding extends _i1.Mock implements _i7.WidgetsBinding { - MockWidgetsBinding() { - _i1.throwOnMissingStub(this); - } - - @override - bool get debugBuildingDirtyElements => - (super.noSuchMethod(Invocation.getter(#debugBuildingDirtyElements), - returnValue: false) as bool); - @override - set debugBuildingDirtyElements(bool? _debugBuildingDirtyElements) => - super.noSuchMethod( - Invocation.setter( - #debugBuildingDirtyElements, _debugBuildingDirtyElements), - returnValueForMissingStub: null); - @override - _i2.FocusManager get focusManager => - (super.noSuchMethod(Invocation.getter(#focusManager), - returnValue: _FakeFocusManager_0()) as _i2.FocusManager); - @override - bool get firstFrameRasterized => - (super.noSuchMethod(Invocation.getter(#firstFrameRasterized), - returnValue: false) as bool); - @override - _i8.Future get waitUntilFirstFrameRasterized => - (super.noSuchMethod(Invocation.getter(#waitUntilFirstFrameRasterized), - returnValue: Future.value()) as _i8.Future); - @override - bool get debugDidSendFirstFrameEvent => - (super.noSuchMethod(Invocation.getter(#debugDidSendFirstFrameEvent), - returnValue: false) as bool); - @override - bool get framesEnabled => - (super.noSuchMethod(Invocation.getter(#framesEnabled), returnValue: false) - as bool); - @override - bool get isRootWidgetAttached => - (super.noSuchMethod(Invocation.getter(#isRootWidgetAttached), - returnValue: false) as bool); - @override - _i4.SingletonFlutterWindow get window => - (super.noSuchMethod(Invocation.getter(#window), - returnValue: _FakeSingletonFlutterWindow_1()) - as _i4.SingletonFlutterWindow); - @override - _i4.PlatformDispatcher get platformDispatcher => - (super.noSuchMethod(Invocation.getter(#platformDispatcher), - returnValue: _FakePlatformDispatcher_2()) as _i4.PlatformDispatcher); - @override - bool get locked => - (super.noSuchMethod(Invocation.getter(#locked), returnValue: false) - as bool); - @override - _i5.HardwareKeyboard get keyboard => - (super.noSuchMethod(Invocation.getter(#keyboard), - returnValue: _FakeHardwareKeyboard_3()) as _i5.HardwareKeyboard); - @override - _i5.KeyEventManager get keyEventManager => - (super.noSuchMethod(Invocation.getter(#keyEventManager), - returnValue: _FakeKeyEventManager_4()) as _i5.KeyEventManager); - @override - _i5.BinaryMessenger get defaultBinaryMessenger => - (super.noSuchMethod(Invocation.getter(#defaultBinaryMessenger), - returnValue: _FakeBinaryMessenger_5()) as _i5.BinaryMessenger); - @override - _i4.ChannelBuffers get channelBuffers => - (super.noSuchMethod(Invocation.getter(#channelBuffers), - returnValue: _FakeChannelBuffers_6()) as _i4.ChannelBuffers); - @override - _i5.RestorationManager get restorationManager => - (super.noSuchMethod(Invocation.getter(#restorationManager), - returnValue: _FakeRestorationManager_7()) as _i5.RestorationManager); - @override - _i9.SchedulingStrategy get schedulingStrategy => - (super.noSuchMethod(Invocation.getter(#schedulingStrategy), - returnValue: ({int? priority, _i9.SchedulerBinding? scheduler}) => - false) as _i9.SchedulingStrategy); - @override - set schedulingStrategy(_i9.SchedulingStrategy? _schedulingStrategy) => super - .noSuchMethod(Invocation.setter(#schedulingStrategy, _schedulingStrategy), - returnValueForMissingStub: null); - @override - int get transientCallbackCount => - (super.noSuchMethod(Invocation.getter(#transientCallbackCount), - returnValue: 0) as int); - @override - _i8.Future get endOfFrame => - (super.noSuchMethod(Invocation.getter(#endOfFrame), - returnValue: Future.value()) as _i8.Future); - @override - bool get hasScheduledFrame => - (super.noSuchMethod(Invocation.getter(#hasScheduledFrame), - returnValue: false) as bool); - @override - _i9.SchedulerPhase get schedulerPhase => - (super.noSuchMethod(Invocation.getter(#schedulerPhase), - returnValue: _i9.SchedulerPhase.idle) as _i9.SchedulerPhase); - @override - Duration get currentFrameTimeStamp => - (super.noSuchMethod(Invocation.getter(#currentFrameTimeStamp), - returnValue: _FakeDuration_8()) as Duration); - @override - Duration get currentSystemFrameTimeStamp => - (super.noSuchMethod(Invocation.getter(#currentSystemFrameTimeStamp), - returnValue: _FakeDuration_8()) as Duration); - @override - _i6.PointerRouter get pointerRouter => - (super.noSuchMethod(Invocation.getter(#pointerRouter), - returnValue: _FakePointerRouter_9()) as _i6.PointerRouter); - @override - _i6.GestureArenaManager get gestureArena => (super.noSuchMethod( - Invocation.getter(#gestureArena), - returnValue: _FakeGestureArenaManager_10()) as _i6.GestureArenaManager); - @override - _i6.PointerSignalResolver get pointerSignalResolver => - (super.noSuchMethod(Invocation.getter(#pointerSignalResolver), - returnValue: _FakePointerSignalResolver_11()) - as _i6.PointerSignalResolver); - @override - bool get resamplingEnabled => - (super.noSuchMethod(Invocation.getter(#resamplingEnabled), - returnValue: false) as bool); - @override - set resamplingEnabled(bool? _resamplingEnabled) => super.noSuchMethod( - Invocation.setter(#resamplingEnabled, _resamplingEnabled), - returnValueForMissingStub: null); - @override - Duration get samplingOffset => - (super.noSuchMethod(Invocation.getter(#samplingOffset), - returnValue: _FakeDuration_8()) as Duration); - @override - set samplingOffset(Duration? _samplingOffset) => - super.noSuchMethod(Invocation.setter(#samplingOffset, _samplingOffset), - returnValueForMissingStub: null); - @override - _i3.MouseTracker get mouseTracker => - (super.noSuchMethod(Invocation.getter(#mouseTracker), - returnValue: _FakeMouseTracker_12()) as _i3.MouseTracker); - @override - _i3.PipelineOwner get pipelineOwner => - (super.noSuchMethod(Invocation.getter(#pipelineOwner), - returnValue: _FakePipelineOwner_13()) as _i3.PipelineOwner); - @override - _i3.RenderView get renderView => - (super.noSuchMethod(Invocation.getter(#renderView), - returnValue: _FakeRenderView_14()) as _i3.RenderView); - @override - set renderView(_i3.RenderView? value) => - super.noSuchMethod(Invocation.setter(#renderView, value), - returnValueForMissingStub: null); - @override - bool get sendFramesToEngine => - (super.noSuchMethod(Invocation.getter(#sendFramesToEngine), - returnValue: false) as bool); - @override - _i4.AccessibilityFeatures get accessibilityFeatures => - (super.noSuchMethod(Invocation.getter(#accessibilityFeatures), - returnValue: _FakeAccessibilityFeatures_15()) - as _i4.AccessibilityFeatures); - @override - bool get disableAnimations => - (super.noSuchMethod(Invocation.getter(#disableAnimations), - returnValue: false) as bool); - @override - void initInstances() => - super.noSuchMethod(Invocation.method(#initInstances, []), - returnValueForMissingStub: null); - @override - void initServiceExtensions() => - super.noSuchMethod(Invocation.method(#initServiceExtensions, []), - returnValueForMissingStub: null); - @override - void addObserver(_i7.WidgetsBindingObserver? observer) => - super.noSuchMethod(Invocation.method(#addObserver, [observer]), - returnValueForMissingStub: null); - @override - bool removeObserver(_i7.WidgetsBindingObserver? observer) => - (super.noSuchMethod(Invocation.method(#removeObserver, [observer]), - returnValue: false) as bool); - @override - void handleMetricsChanged() => - super.noSuchMethod(Invocation.method(#handleMetricsChanged, []), - returnValueForMissingStub: null); - @override - void handleTextScaleFactorChanged() => - super.noSuchMethod(Invocation.method(#handleTextScaleFactorChanged, []), - returnValueForMissingStub: null); - @override - void handlePlatformBrightnessChanged() => super.noSuchMethod( - Invocation.method(#handlePlatformBrightnessChanged, []), - returnValueForMissingStub: null); - @override - void handleAccessibilityFeaturesChanged() => super.noSuchMethod( - Invocation.method(#handleAccessibilityFeaturesChanged, []), - returnValueForMissingStub: null); - @override - void handleLocaleChanged() => - super.noSuchMethod(Invocation.method(#handleLocaleChanged, []), - returnValueForMissingStub: null); - @override - void dispatchLocalesChanged(List<_i4.Locale>? locales) => - super.noSuchMethod(Invocation.method(#dispatchLocalesChanged, [locales]), - returnValueForMissingStub: null); - @override - void dispatchAccessibilityFeaturesChanged() => super.noSuchMethod( - Invocation.method(#dispatchAccessibilityFeaturesChanged, []), - returnValueForMissingStub: null); - @override - _i8.Future handlePopRoute() => - (super.noSuchMethod(Invocation.method(#handlePopRoute, []), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i8.Future); - @override - _i8.Future handlePushRoute(String? route) => - (super.noSuchMethod(Invocation.method(#handlePushRoute, [route]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i8.Future); - @override - void handleAppLifecycleStateChanged(_i4.AppLifecycleState? state) => super - .noSuchMethod(Invocation.method(#handleAppLifecycleStateChanged, [state]), - returnValueForMissingStub: null); - @override - void handleMemoryPressure() => - super.noSuchMethod(Invocation.method(#handleMemoryPressure, []), - returnValueForMissingStub: null); - @override - void drawFrame() => super.noSuchMethod(Invocation.method(#drawFrame, []), - returnValueForMissingStub: null); - @override - void scheduleAttachRootWidget(_i10.Widget? rootWidget) => super.noSuchMethod( - Invocation.method(#scheduleAttachRootWidget, [rootWidget]), - returnValueForMissingStub: null); - @override - void attachRootWidget(_i10.Widget? rootWidget) => - super.noSuchMethod(Invocation.method(#attachRootWidget, [rootWidget]), - returnValueForMissingStub: null); - @override - _i8.Future performReassemble() => - (super.noSuchMethod(Invocation.method(#performReassemble, []), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i8.Future); - @override - _i4.Locale? computePlatformResolvedLocale( - List<_i4.Locale>? supportedLocales) => - (super.noSuchMethod(Invocation.method( - #computePlatformResolvedLocale, [supportedLocales])) as _i4.Locale?); - @override - _i8.Future lockEvents(_i8.Future Function()? callback) => - (super.noSuchMethod(Invocation.method(#lockEvents, [callback]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i8.Future); - @override - void unlocked() => super.noSuchMethod(Invocation.method(#unlocked, []), - returnValueForMissingStub: null); - @override - _i8.Future reassembleApplication() => - (super.noSuchMethod(Invocation.method(#reassembleApplication, []), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i8.Future); - @override - void registerSignalServiceExtension( - {String? name, _i11.AsyncCallback? callback}) => - super.noSuchMethod( - Invocation.method(#registerSignalServiceExtension, [], - {#name: name, #callback: callback}), - returnValueForMissingStub: null); - @override - void registerBoolServiceExtension( - {String? name, - _i11.AsyncValueGetter? getter, - _i11.AsyncValueSetter? setter}) => - super.noSuchMethod( - Invocation.method(#registerBoolServiceExtension, [], - {#name: name, #getter: getter, #setter: setter}), - returnValueForMissingStub: null); - @override - void registerNumericServiceExtension( - {String? name, - _i11.AsyncValueGetter? getter, - _i11.AsyncValueSetter? setter}) => - super.noSuchMethod( - Invocation.method(#registerNumericServiceExtension, [], - {#name: name, #getter: getter, #setter: setter}), - returnValueForMissingStub: null); - @override - void postEvent(String? eventKind, Map? eventData) => - super.noSuchMethod(Invocation.method(#postEvent, [eventKind, eventData]), - returnValueForMissingStub: null); - @override - void registerStringServiceExtension( - {String? name, - _i11.AsyncValueGetter? getter, - _i11.AsyncValueSetter? setter}) => - super.noSuchMethod( - Invocation.method(#registerStringServiceExtension, [], - {#name: name, #getter: getter, #setter: setter}), - returnValueForMissingStub: null); - @override - void registerServiceExtension( - {String? name, _i11.ServiceExtensionCallback? callback}) => - super.noSuchMethod( - Invocation.method(#registerServiceExtension, [], - {#name: name, #callback: callback}), - returnValueForMissingStub: null); - @override - _i5.BinaryMessenger createBinaryMessenger() => - (super.noSuchMethod(Invocation.method(#createBinaryMessenger, []), - returnValue: _FakeBinaryMessenger_5()) as _i5.BinaryMessenger); - @override - _i8.Future handleSystemMessage(Object? systemMessage) => (super - .noSuchMethod(Invocation.method(#handleSystemMessage, [systemMessage]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i8.Future); - @override - void initLicenses() => - super.noSuchMethod(Invocation.method(#initLicenses, []), - returnValueForMissingStub: null); - @override - void evict(String? asset) => - super.noSuchMethod(Invocation.method(#evict, [asset]), - returnValueForMissingStub: null); - @override - void readInitialLifecycleStateFromNativeWindow() => super.noSuchMethod( - Invocation.method(#readInitialLifecycleStateFromNativeWindow, []), - returnValueForMissingStub: null); - @override - _i5.RestorationManager createRestorationManager() => - (super.noSuchMethod(Invocation.method(#createRestorationManager, []), - returnValue: _FakeRestorationManager_7()) as _i5.RestorationManager); - @override - void setSystemUiChangeCallback(_i5.SystemUiChangeCallback? callback) => super - .noSuchMethod(Invocation.method(#setSystemUiChangeCallback, [callback]), - returnValueForMissingStub: null); - @override - void addTimingsCallback(_i4.TimingsCallback? callback) => - super.noSuchMethod(Invocation.method(#addTimingsCallback, [callback]), - returnValueForMissingStub: null); - @override - void removeTimingsCallback(_i4.TimingsCallback? callback) => - super.noSuchMethod(Invocation.method(#removeTimingsCallback, [callback]), - returnValueForMissingStub: null); - @override - _i8.Future scheduleTask( - _i9.TaskCallback? task, _i9.Priority? priority, - {String? debugLabel, _i12.Flow? flow}) => - (super.noSuchMethod( - Invocation.method(#scheduleTask, [task, priority], - {#debugLabel: debugLabel, #flow: flow}), - returnValue: Future.value(null)) as _i8.Future); - @override - bool handleEventLoopCallback() => - (super.noSuchMethod(Invocation.method(#handleEventLoopCallback, []), - returnValue: false) as bool); - @override - int scheduleFrameCallback(_i9.FrameCallback? callback, - {bool? rescheduling = false}) => - (super.noSuchMethod( - Invocation.method(#scheduleFrameCallback, [callback], - {#rescheduling: rescheduling}), - returnValue: 0) as int); - @override - void cancelFrameCallbackWithId(int? id) => - super.noSuchMethod(Invocation.method(#cancelFrameCallbackWithId, [id]), - returnValueForMissingStub: null); - @override - bool debugAssertNoTransientCallbacks(String? reason) => (super.noSuchMethod( - Invocation.method(#debugAssertNoTransientCallbacks, [reason]), - returnValue: false) as bool); - @override - void addPersistentFrameCallback(_i9.FrameCallback? callback) => super - .noSuchMethod(Invocation.method(#addPersistentFrameCallback, [callback]), - returnValueForMissingStub: null); - @override - void addPostFrameCallback(_i9.FrameCallback? callback) => - super.noSuchMethod(Invocation.method(#addPostFrameCallback, [callback]), - returnValueForMissingStub: null); - @override - void ensureFrameCallbacksRegistered() => - super.noSuchMethod(Invocation.method(#ensureFrameCallbacksRegistered, []), - returnValueForMissingStub: null); - @override - void ensureVisualUpdate() => - super.noSuchMethod(Invocation.method(#ensureVisualUpdate, []), - returnValueForMissingStub: null); - @override - void scheduleFrame() => - super.noSuchMethod(Invocation.method(#scheduleFrame, []), - returnValueForMissingStub: null); - @override - void scheduleForcedFrame() => - super.noSuchMethod(Invocation.method(#scheduleForcedFrame, []), - returnValueForMissingStub: null); - @override - void scheduleWarmUpFrame() => - super.noSuchMethod(Invocation.method(#scheduleWarmUpFrame, []), - returnValueForMissingStub: null); - @override - void resetEpoch() => super.noSuchMethod(Invocation.method(#resetEpoch, []), - returnValueForMissingStub: null); - @override - void handleBeginFrame(Duration? rawTimeStamp) => - super.noSuchMethod(Invocation.method(#handleBeginFrame, [rawTimeStamp]), - returnValueForMissingStub: null); - @override - void handleDrawFrame() => - super.noSuchMethod(Invocation.method(#handleDrawFrame, []), - returnValueForMissingStub: null); - @override - void cancelPointer(int? pointer) => - super.noSuchMethod(Invocation.method(#cancelPointer, [pointer]), - returnValueForMissingStub: null); - @override - void handlePointerEvent(_i3.PointerEvent? event) => - super.noSuchMethod(Invocation.method(#handlePointerEvent, [event]), - returnValueForMissingStub: null); - @override - void hitTest(_i3.HitTestResult? result, _i4.Offset? position) => - super.noSuchMethod(Invocation.method(#hitTest, [result, position]), - returnValueForMissingStub: null); - @override - void dispatchEvent( - _i3.PointerEvent? event, _i3.HitTestResult? hitTestResult) => - super.noSuchMethod( - Invocation.method(#dispatchEvent, [event, hitTestResult]), - returnValueForMissingStub: null); - @override - void handleEvent(_i3.PointerEvent? event, _i3.HitTestEntry? entry) => - super.noSuchMethod(Invocation.method(#handleEvent, [event, entry]), - returnValueForMissingStub: null); - @override - void resetGestureBinding() => - super.noSuchMethod(Invocation.method(#resetGestureBinding, []), - returnValueForMissingStub: null); - @override - void initRenderView() => - super.noSuchMethod(Invocation.method(#initRenderView, []), - returnValueForMissingStub: null); - @override - _i3.ViewConfiguration createViewConfiguration() => - (super.noSuchMethod(Invocation.method(#createViewConfiguration, []), - returnValue: _FakeViewConfiguration_16()) as _i3.ViewConfiguration); - @override - void initMouseTracker([_i3.MouseTracker? tracker]) => - super.noSuchMethod(Invocation.method(#initMouseTracker, [tracker]), - returnValueForMissingStub: null); - @override - void setSemanticsEnabled(bool? enabled) => - super.noSuchMethod(Invocation.method(#setSemanticsEnabled, [enabled]), - returnValueForMissingStub: null); - @override - void deferFirstFrame() => - super.noSuchMethod(Invocation.method(#deferFirstFrame, []), - returnValueForMissingStub: null); - @override - void allowFirstFrame() => - super.noSuchMethod(Invocation.method(#allowFirstFrame, []), - returnValueForMissingStub: null); - @override - void resetFirstFrameSent() => - super.noSuchMethod(Invocation.method(#resetFirstFrameSent, []), - returnValueForMissingStub: null); - @override - _i4.SemanticsUpdateBuilder createSemanticsUpdateBuilder() => - (super.noSuchMethod(Invocation.method(#createSemanticsUpdateBuilder, []), - returnValue: _FakeSemanticsUpdateBuilder_17()) - as _i4.SemanticsUpdateBuilder); -} - -/// A class which mocks [FrameTiming]. -/// -/// See the documentation for Mockito's code generation for more information. -class MockFrameTiming extends _i1.Mock implements _i4.FrameTiming { - MockFrameTiming() { - _i1.throwOnMissingStub(this); - } - - @override - Duration get buildDuration => - (super.noSuchMethod(Invocation.getter(#buildDuration), - returnValue: _FakeDuration_8()) as Duration); - @override - Duration get rasterDuration => - (super.noSuchMethod(Invocation.getter(#rasterDuration), - returnValue: _FakeDuration_8()) as Duration); - @override - Duration get vsyncOverhead => - (super.noSuchMethod(Invocation.getter(#vsyncOverhead), - returnValue: _FakeDuration_8()) as Duration); - @override - Duration get totalSpan => (super.noSuchMethod(Invocation.getter(#totalSpan), - returnValue: _FakeDuration_8()) as Duration); - @override - int get layerCacheCount => - (super.noSuchMethod(Invocation.getter(#layerCacheCount), returnValue: 0) - as int); - @override - int get layerCacheBytes => - (super.noSuchMethod(Invocation.getter(#layerCacheBytes), returnValue: 0) - as int); - @override - double get layerCacheMegabytes => - (super.noSuchMethod(Invocation.getter(#layerCacheMegabytes), - returnValue: 0.0) as double); - @override - int get pictureCacheCount => - (super.noSuchMethod(Invocation.getter(#pictureCacheCount), returnValue: 0) - as int); - @override - int get pictureCacheBytes => - (super.noSuchMethod(Invocation.getter(#pictureCacheBytes), returnValue: 0) - as int); - @override - double get pictureCacheMegabytes => - (super.noSuchMethod(Invocation.getter(#pictureCacheMegabytes), - returnValue: 0.0) as double); - @override - int get frameNumber => - (super.noSuchMethod(Invocation.getter(#frameNumber), returnValue: 0) - as int); - @override - int timestampInMicroseconds(_i4.FramePhase? phase) => - (super.noSuchMethod(Invocation.method(#timestampInMicroseconds, [phase]), - returnValue: 0) as int); -} - -/// A class which mocks [ApmHostApi]. -/// -/// See the documentation for Mockito's code generation for more information. -class MockApmHostApi extends _i1.Mock implements _i13.ApmHostApi { - MockApmHostApi() { - _i1.throwOnMissingStub(this); - } - - @override - _i8.Future setEnabled(bool? arg_isEnabled) => - (super.noSuchMethod(Invocation.method(#setEnabled, [arg_isEnabled]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i8.Future); - @override - _i8.Future isEnabled() => - (super.noSuchMethod(Invocation.method(#isEnabled, []), - returnValue: Future.value(false)) as _i8.Future); - @override - _i8.Future setScreenLoadingEnabled(bool? arg_isEnabled) => - (super.noSuchMethod( - Invocation.method(#setScreenLoadingEnabled, [arg_isEnabled]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i8.Future); - @override - _i8.Future isScreenLoadingEnabled() => - (super.noSuchMethod(Invocation.method(#isScreenLoadingEnabled, []), - returnValue: Future.value(false)) as _i8.Future); - @override - _i8.Future setColdAppLaunchEnabled(bool? arg_isEnabled) => - (super.noSuchMethod( - Invocation.method(#setColdAppLaunchEnabled, [arg_isEnabled]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i8.Future); - @override - _i8.Future setAutoUITraceEnabled(bool? arg_isEnabled) => (super - .noSuchMethod(Invocation.method(#setAutoUITraceEnabled, [arg_isEnabled]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i8.Future); - @override - _i8.Future startFlow(String? arg_name) => - (super.noSuchMethod(Invocation.method(#startFlow, [arg_name]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i8.Future); - @override - _i8.Future setFlowAttribute( - String? arg_name, String? arg_key, String? arg_value) => - (super.noSuchMethod( - Invocation.method(#setFlowAttribute, [arg_name, arg_key, arg_value]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i8.Future); - @override - _i8.Future endFlow(String? arg_name) => - (super.noSuchMethod(Invocation.method(#endFlow, [arg_name]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i8.Future); - @override - _i8.Future startUITrace(String? arg_name) => - (super.noSuchMethod(Invocation.method(#startUITrace, [arg_name]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i8.Future); - @override - _i8.Future endUITrace() => - (super.noSuchMethod(Invocation.method(#endUITrace, []), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i8.Future); - @override - _i8.Future endAppLaunch() => - (super.noSuchMethod(Invocation.method(#endAppLaunch, []), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i8.Future); - @override - _i8.Future networkLogAndroid(Map? arg_data) => - (super.noSuchMethod(Invocation.method(#networkLogAndroid, [arg_data]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i8.Future); - @override - _i8.Future startCpUiTrace( - String? arg_screenName, int? arg_microTimeStamp, int? arg_traceId) => - (super.noSuchMethod( - Invocation.method(#startCpUiTrace, - [arg_screenName, arg_microTimeStamp, arg_traceId]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i8.Future); - @override - _i8.Future reportScreenLoadingCP(int? arg_startTimeStampMicro, - int? arg_durationMicro, int? arg_uiTraceId) => - (super.noSuchMethod( - Invocation.method(#reportScreenLoadingCP, - [arg_startTimeStampMicro, arg_durationMicro, arg_uiTraceId]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i8.Future); - @override - _i8.Future endScreenLoadingCP( - int? arg_timeStampMicro, int? arg_uiTraceId) => - (super.noSuchMethod( - Invocation.method( - #endScreenLoadingCP, [arg_timeStampMicro, arg_uiTraceId]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i8.Future); - @override - _i8.Future isEndScreenLoadingEnabled() => - (super.noSuchMethod(Invocation.method(#isEndScreenLoadingEnabled, []), - returnValue: Future.value(false)) as _i8.Future); - @override - _i8.Future isScreenRenderEnabled() => - (super.noSuchMethod(Invocation.method(#isScreenRenderEnabled, []), - returnValue: Future.value(false)) as _i8.Future); - @override - _i8.Future> getDeviceRefreshRateAndTolerance() => - (super.noSuchMethod( - Invocation.method(#getDeviceRefreshRateAndTolerance, []), - returnValue: Future>.value([])) - as _i8.Future>); - @override - _i8.Future setScreenRenderEnabled(bool? arg_isEnabled) => (super - .noSuchMethod(Invocation.method(#setScreenRenderEnabled, [arg_isEnabled]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i8.Future); - @override - _i8.Future endScreenRenderForAutoUiTrace( - Map? arg_data) => - (super.noSuchMethod( - Invocation.method(#endScreenRenderForAutoUiTrace, [arg_data]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i8.Future); - @override - _i8.Future endScreenRenderForCustomUiTrace( - Map? arg_data) => - (super.noSuchMethod( - Invocation.method(#endScreenRenderForCustomUiTrace, [arg_data]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i8.Future); -} - -/// A class which mocks [CrashReportingHostApi]. -/// -/// See the documentation for Mockito's code generation for more information. -class MockCrashReportingHostApi extends _i1.Mock - implements _i14.CrashReportingHostApi { - MockCrashReportingHostApi() { - _i1.throwOnMissingStub(this); - } - - @override - _i8.Future setEnabled(bool? arg_isEnabled) => - (super.noSuchMethod(Invocation.method(#setEnabled, [arg_isEnabled]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i8.Future); - @override - _i8.Future send(String? arg_jsonCrash, bool? arg_isHandled) => (super - .noSuchMethod(Invocation.method(#send, [arg_jsonCrash, arg_isHandled]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i8.Future); - @override - _i8.Future sendNonFatalError( - String? arg_jsonCrash, - Map? arg_userAttributes, - String? arg_fingerprint, - String? arg_nonFatalExceptionLevel) => - (super.noSuchMethod( - Invocation.method(#sendNonFatalError, [ - arg_jsonCrash, - arg_userAttributes, - arg_fingerprint, - arg_nonFatalExceptionLevel - ]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i8.Future); -} - -/// A class which mocks [InstabugLogger]. -/// -/// See the documentation for Mockito's code generation for more information. -class MockInstabugLogger extends _i1.Mock implements _i15.InstabugLogger { - MockInstabugLogger() { - _i1.throwOnMissingStub(this); - } - - @override - set logLevel(_i16.LogLevel? level) => - super.noSuchMethod(Invocation.setter(#logLevel, level), - returnValueForMissingStub: null); - @override - void log(String? message, {_i16.LogLevel? level, String? tag = r''}) => - super.noSuchMethod( - Invocation.method(#log, [message], {#level: level, #tag: tag}), - returnValueForMissingStub: null); - @override - void e(String? message, {String? tag = r''}) => - super.noSuchMethod(Invocation.method(#e, [message], {#tag: tag}), - returnValueForMissingStub: null); - @override - void d(String? message, {String? tag = r''}) => - super.noSuchMethod(Invocation.method(#d, [message], {#tag: tag}), - returnValueForMissingStub: null); - @override - void v(String? message, {String? tag = r''}) => - super.noSuchMethod(Invocation.method(#v, [message], {#tag: tag}), - returnValueForMissingStub: null); -} From 3695b62a6099533df27cc4e9aa20bf1a91ffcb7c Mon Sep 17 00:00:00 2001 From: Andrew Amin Date: Wed, 20 Aug 2025 12:02:12 +0300 Subject: [PATCH 76/84] fix: android back button drop the active traces --- .../flutter/InstabugFlutterPlugin.java | 66 +++++++++++++- .../com/instabug/flutter/modules/ApmApi.java | 17 ---- example/lib/main.dart | 2 +- lib/src/modules/instabug.dart | 22 +++++ .../instabug_widget_binding_observer.dart | 89 ++++++++++++------- pigeons/instabug.api.dart | 5 ++ test/apm_test.dart | 14 +-- test/instabug_test.dart | 15 ++++ ...instabug_widget_binding_observer_test.dart | 5 +- 9 files changed, 170 insertions(+), 65 deletions(-) diff --git a/android/src/main/java/com/instabug/flutter/InstabugFlutterPlugin.java b/android/src/main/java/com/instabug/flutter/InstabugFlutterPlugin.java index 3a51a4051..ec6a022d2 100644 --- a/android/src/main/java/com/instabug/flutter/InstabugFlutterPlugin.java +++ b/android/src/main/java/com/instabug/flutter/InstabugFlutterPlugin.java @@ -23,23 +23,35 @@ import com.instabug.flutter.modules.SurveysApi; import java.util.concurrent.Callable; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; import io.flutter.embedding.engine.plugins.FlutterPlugin; import io.flutter.embedding.engine.plugins.activity.ActivityAware; import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding; +import io.flutter.embedding.engine.plugins.lifecycle.HiddenLifecycleReference; import io.flutter.embedding.engine.renderer.FlutterRenderer; import io.flutter.plugin.common.BinaryMessenger; +import androidx.lifecycle.Lifecycle; +import androidx.lifecycle.LifecycleEventObserver; +import androidx.lifecycle.LifecycleOwner; +import com.instabug.flutter.generated.InstabugPigeon; -public class InstabugFlutterPlugin implements FlutterPlugin, ActivityAware { - private static final String TAG = InstabugFlutterPlugin.class.getName(); +public class InstabugFlutterPlugin implements FlutterPlugin, ActivityAware, LifecycleEventObserver { + private static final String TAG = "Andrew"; @SuppressLint("StaticFieldLeak") private static Activity activity; + + private InstabugPigeon.InstabugFlutterApi instabugFlutterApi; + private Lifecycle lifecycle; + final CountDownLatch latch = new CountDownLatch(1); @Override public void onAttachedToEngine(@NonNull FlutterPluginBinding binding) { register(binding.getApplicationContext(), binding.getBinaryMessenger(), (FlutterRenderer) binding.getTextureRegistry()); + instabugFlutterApi = new InstabugPigeon.InstabugFlutterApi(binding.getBinaryMessenger()); } @Override @@ -50,23 +62,73 @@ public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) { @Override public void onAttachedToActivity(@NonNull ActivityPluginBinding binding) { activity = binding.getActivity(); + + // Register lifecycle observer if available + if (binding.getLifecycle() instanceof HiddenLifecycleReference) { + lifecycle = ((HiddenLifecycleReference) binding.getLifecycle()).getLifecycle(); + lifecycle.addObserver(this); + } } @Override public void onDetachedFromActivityForConfigChanges() { + Log.d(TAG, "onDetachedFromActivityForConfigChanges"); + + if (lifecycle != null) { + lifecycle.removeObserver(this); + } activity = null; } @Override public void onReattachedToActivityForConfigChanges(@NonNull ActivityPluginBinding binding) { activity = binding.getActivity(); + + // Re-register lifecycle observer if available + if (binding.getLifecycle() instanceof HiddenLifecycleReference) { + lifecycle = ((HiddenLifecycleReference) binding.getLifecycle()).getLifecycle(); + lifecycle.addObserver(this); + } } @Override public void onDetachedFromActivity() { + Log.d(TAG, "onDetachedFromActivity"); + if (lifecycle != null) { + lifecycle.removeObserver(this); + lifecycle = null; + } activity = null; } + @Override + public void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event) { + if (event == Lifecycle.Event.ON_PAUSE) { + Log.d(TAG, "ON_PAUSE"); + handleOnDestroy(); + } + } + + private void handleOnDestroy() { + Log.d(TAG, "handleOnDestroy"); + + if (instabugFlutterApi != null) { + instabugFlutterApi.dispose(new InstabugPigeon.InstabugFlutterApi.Reply() { + @Override + public void reply(Void reply) { + Log.d(TAG, "Screen render cleanup dispose called successfully"); + latch.countDown(); + } + }); + } + try { + // Wait up to 2 seconds to avoid ANR + latch.await(2, TimeUnit.SECONDS); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + private static void register(Context context, BinaryMessenger messenger, FlutterRenderer renderer) { final Callable screenshotProvider = new Callable() { @Override diff --git a/android/src/main/java/com/instabug/flutter/modules/ApmApi.java b/android/src/main/java/com/instabug/flutter/modules/ApmApi.java index fb58834e6..23b11b3fe 100644 --- a/android/src/main/java/com/instabug/flutter/modules/ApmApi.java +++ b/android/src/main/java/com/instabug/flutter/modules/ApmApi.java @@ -93,23 +93,6 @@ public void setAutoUITraceEnabled(@NonNull Boolean isEnabled) { } } - /** - * Starts an execution trace and handles the result - * using callbacks. - * - * @param id The `id` parameter is a non-null String that represents the identifier of the execution - * trace. - * @param name The `name` parameter in the `startExecutionTrace` method represents the name of the - * execution trace that will be started. It is used as a reference to identify the trace during - * execution monitoring. - * @param result The `result` parameter in the `startExecutionTrace` method is an instance of - * `ApmPigeon.Result`. This parameter is used to provide the result of the execution trace - * operation back to the caller. The `success` method of the `result` object is called with the - * - * @deprecated see {@link #startFlow} - */ - - /** * Starts an AppFlow with the specified name. *
diff --git a/example/lib/main.dart b/example/lib/main.dart index 6979ec702..5946f75c1 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -47,7 +47,7 @@ void main() { appVariant: 'variant 1', ); APM.setScreenRenderingEnabled(true); - APM.setAutoUITraceEnabled(false); + // APM.setAutoUITraceEnabled(false); FlutterError.onError = (FlutterErrorDetails details) { Zone.current.handleUncaughtError(details.exception, details.stack!); }; diff --git a/lib/src/modules/instabug.dart b/lib/src/modules/instabug.dart index b0073b42a..ee98afaa0 100644 --- a/lib/src/modules/instabug.dart +++ b/lib/src/modules/instabug.dart @@ -22,6 +22,7 @@ import 'package:instabug_flutter/src/utils/feature_flags_manager.dart'; import 'package:instabug_flutter/src/utils/ibg_build_info.dart'; import 'package:instabug_flutter/src/utils/instabug_logger.dart'; import 'package:instabug_flutter/src/utils/screen_name_masker.dart'; +import 'package:instabug_flutter/src/utils/screen_rendering/instabug_widget_binding_observer.dart'; import 'package:meta/meta.dart'; enum InvocationEvent { @@ -136,6 +137,25 @@ enum CustomTextPlaceHolderKey { enum ReproStepsMode { enabled, disabled, enabledWithNoScreenshots } +/// Disposal manager for handling Android onDestroy lifecycle events +class _InstabugDisposalManager implements InstabugFlutterApi { + _InstabugDisposalManager._(); + + static final _InstabugDisposalManager _instance = + _InstabugDisposalManager._(); + + static _InstabugDisposalManager get instance => _instance; + + @override + void dispose() { + // Call the InstabugWidgetsBindingObserver dispose method when Android onDestroy is triggered + InstabugLogger.I.d( + 'Android onDestroy called - disposing screen render resources', + tag: 'InstabugDisposal'); + InstabugWidgetsBindingObserver.dispose(); + } +} + class Instabug { static var _host = InstabugHostApi(); @@ -154,6 +174,8 @@ class Instabug { BugReporting.$setup(); Replies.$setup(); Surveys.$setup(); + // Set up InstabugFlutterApi for Android onDestroy disposal + InstabugFlutterApi.setup(_InstabugDisposalManager.instance); } /// @nodoc diff --git a/lib/src/utils/screen_rendering/instabug_widget_binding_observer.dart b/lib/src/utils/screen_rendering/instabug_widget_binding_observer.dart index d454309c1..349d39bf2 100644 --- a/lib/src/utils/screen_rendering/instabug_widget_binding_observer.dart +++ b/lib/src/utils/screen_rendering/instabug_widget_binding_observer.dart @@ -1,7 +1,9 @@ import 'package:flutter/widgets.dart'; +import 'package:instabug_flutter/src/utils/instabug_logger.dart'; import 'package:instabug_flutter/src/utils/screen_loading/screen_loading_manager.dart'; import 'package:instabug_flutter/src/utils/screen_name_masker.dart'; import 'package:instabug_flutter/src/utils/screen_rendering/instabug_screen_render_manager.dart'; +import 'package:instabug_flutter/src/utils/ui_trace/flags_config.dart'; import 'package:meta/meta.dart'; class InstabugWidgetsBindingObserver extends WidgetsBindingObserver { @@ -19,45 +21,69 @@ class InstabugWidgetsBindingObserver extends WidgetsBindingObserver { /// Logging tag for debugging purposes. static const tag = "InstabugWidgetsBindingObserver"; + /// Disposes all screen render resources. + /// This method is safe to call multiple times and from external sources + /// such as Android onDestroy lifecycle events. static void dispose() { - // Always call dispose to ensure proper cleanup with tracking flags - // The dispose method is safe to call multiple times due to state tracking - InstabugScreenRenderManager.I.dispose(); + try { + //Save the screen rendering data for the active traces Auto|Custom. + InstabugScreenRenderManager.I.stopScreenRenderCollector(); + + // Always call dispose to ensure proper cleanup with tracking flags + // The dispose method is safe to call multiple times due to state tracking + InstabugScreenRenderManager.I.dispose(); + + InstabugLogger.I + .d('Screen render resources disposed successfully', tag: tag); + } catch (error, stackTrace) { + InstabugLogger.I.e( + 'Error during screen render disposal: $error\nStackTrace: $stackTrace', + tag: tag, + ); + } } void _handleResumedState() { final lastUiTrace = ScreenLoadingManager.I.currentUiTrace; - if (lastUiTrace == null) { - return; - } + + if (lastUiTrace == null) return; + final maskedScreenName = ScreenNameMasker.I.mask(lastUiTrace.screenName); + ScreenLoadingManager.I .startUiTrace(maskedScreenName, lastUiTrace.screenName) - .then((uiTraceId) { - if (uiTraceId != null && - InstabugScreenRenderManager.I.screenRenderEnabled) { - //End any active ScreenRenderCollector before starting a new one (Safe garde condition). - InstabugScreenRenderManager.I.endScreenRenderCollector(); - - //Start new ScreenRenderCollector. - InstabugScreenRenderManager.I - .startScreenRenderCollectorForTraceId(uiTraceId); - } - }); - } + .then((uiTraceId) async { + if (uiTraceId == null) return; - void _handlePausedState() { - if (InstabugScreenRenderManager.I.screenRenderEnabled) { - InstabugScreenRenderManager.I.stopScreenRenderCollector(); - } - } + final isScreenRenderEnabled = + await FlagsConfig.screenRendering.isEnabled(); - Future _handleDetachedState() async { - if (InstabugScreenRenderManager.I.screenRenderEnabled) { - dispose(); - } + if (!isScreenRenderEnabled) return; + + await InstabugScreenRenderManager.I + .checkForScreenRenderInitialization(isScreenRenderEnabled); + + //End any active ScreenRenderCollector before starting a new one (Safe garde condition). + InstabugScreenRenderManager.I.endScreenRenderCollector(); + + //Start new ScreenRenderCollector. + InstabugScreenRenderManager.I + .startScreenRenderCollectorForTraceId(uiTraceId); + }); } + // void _handlePausedState() { + // if (InstabugScreenRenderManager.I.screenRenderEnabled) { + // InstabugScreenRenderManager.I.stopScreenRenderCollector(); + // } + // } + // + // Future _handleDetachedState() async { + // if (InstabugScreenRenderManager.I.screenRenderEnabled) { + // dispose(); + // } + // } + // void _handleDefaultState() { // Added for lint warnings } @@ -68,12 +94,9 @@ class InstabugWidgetsBindingObserver extends WidgetsBindingObserver { case AppLifecycleState.resumed: _handleResumedState(); break; - case AppLifecycleState.paused: - _handlePausedState(); - break; - case AppLifecycleState.detached: - _handleDetachedState(); - break; + // case AppLifecycleState.paused: + // _handlePausedState(); + // break; default: _handleDefaultState(); } diff --git a/pigeons/instabug.api.dart b/pigeons/instabug.api.dart index aa91aec11..eede56de7 100644 --- a/pigeons/instabug.api.dart +++ b/pigeons/instabug.api.dart @@ -9,6 +9,11 @@ abstract class FeatureFlagsFlutterApi { ); } +@FlutterApi() +abstract class InstabugFlutterApi { + void dispose(); +} + @HostApi() abstract class InstabugHostApi { void setEnabled(bool isEnabled); diff --git a/test/apm_test.dart b/test/apm_test.dart index 90df62787..7a9e78230 100644 --- a/test/apm_test.dart +++ b/test/apm_test.dart @@ -256,24 +256,18 @@ void main() { verify(mHost.setScreenRenderEnabled(isEnabled)).called(1); }); - test( - "[setScreenRenderEnabled] should call [init()] screen render collector, is the feature is enabled", + test("[setScreenRenderEnabled] should call host method when enabled", () async { const isEnabled = true; - when(mHost.isScreenRenderEnabled()).thenAnswer((_) async => true); await APM.setScreenRenderingEnabled(isEnabled); - verify(mScreenRenderManager.init(any)).called(1); - verifyNoMoreInteractions(mScreenRenderManager); + verify(mHost.setScreenRenderEnabled(isEnabled)).called(1); }); - test( - "[setScreenRenderEnabled] should call [remove()] screen render collector, is the feature is enabled", + test("[setScreenRenderEnabled] should call host method when disabled", () async { const isEnabled = false; - when(mScreenRenderManager.screenRenderEnabled).thenReturn(true); await APM.setScreenRenderingEnabled(isEnabled); - verify(mScreenRenderManager.dispose()).called(1); - verify(mScreenRenderManager.screenRenderEnabled).called(1); + verify(mHost.setScreenRenderEnabled(isEnabled)).called(1); }); test( diff --git a/test/instabug_test.dart b/test/instabug_test.dart index d87208202..29dc5889f 100644 --- a/test/instabug_test.dart +++ b/test/instabug_test.dart @@ -472,4 +472,19 @@ void main() { mHost.setTheme(themeConfig.toMap()), ).called(1); }); + + group('Disposal Manager', () { + test( + 'InstabugFlutterApi dispose should call widget binding observer dispose', + () { + // Test that the FlutterApi setup and dispose functionality works + // This verifies that when Android calls dispose(), it properly cleans up resources + expect(() { + // Get the InstabugFlutterApi setup that was configured in Instabug.$setup() + // The actual dispose call will be tested in integration tests + // Here we just verify the setup doesn't crash + Instabug.$setup(); + }, returnsNormally); + }); + }); } diff --git a/test/utils/screen_render/instabug_widget_binding_observer_test.dart b/test/utils/screen_render/instabug_widget_binding_observer_test.dart index b97d312a0..77e0198d4 100644 --- a/test/utils/screen_render/instabug_widget_binding_observer_test.dart +++ b/test/utils/screen_render/instabug_widget_binding_observer_test.dart @@ -73,13 +73,14 @@ void main() { verify(mockRenderManager.stopScreenRenderCollector()).called(1); }); - test('handles AppLifecycleState.detached and stops render collector', () { + test('handles AppLifecycleState.detached and disposes render resources', + () { when(mockRenderManager.screenRenderEnabled).thenReturn(true); InstabugWidgetsBindingObserver.I .didChangeAppLifecycleState(AppLifecycleState.detached); - verify(mockRenderManager.stopScreenRenderCollector()).called(1); + verify(mockRenderManager.dispose()).called(1); }); test('handles AppLifecycleState.inactive with no action', () { From 4dac2aea481102e7caf0c57f23ce3df8853c3539 Mon Sep 17 00:00:00 2001 From: Andrew Amin Date: Wed, 20 Aug 2025 12:27:12 +0300 Subject: [PATCH 77/84] remove logs & run mockito on FLT 2.10.5 --- example/pubspec.lock | 189 ++-- .../utils/instabug_navigator_observer.dart | 2 - .../instabug_screen_render_manager.dart | 13 - test/apm_test.dart | 20 - .../instabug_screen_render_manager_test.dart | 15 +- ...abug_screen_render_manager_test_mocks.dart | 818 ++++++++++++++++++ ...instabug_widget_binding_observer_test.dart | 9 - 7 files changed, 897 insertions(+), 169 deletions(-) create mode 100644 test/utils/screen_render/instabug_screen_render_manager_test_mocks.dart diff --git a/example/pubspec.lock b/example/pubspec.lock index 1221be412..ed56bbe53 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -1,62 +1,76 @@ # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: + archive: + dependency: transitive + description: + name: archive + url: "https://pub.dartlang.org" + source: hosted + version: "3.1.6" async: dependency: transitive description: name: async - sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb" - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "2.13.0" + version: "2.8.2" boolean_selector: dependency: transitive description: name: boolean_selector - sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "2.1.2" + version: "2.1.0" characters: dependency: transitive description: name: characters - sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 - url: "https://pub.dev" + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.0" + charcode: + dependency: transitive + description: + name: charcode + url: "https://pub.dartlang.org" source: hosted - version: "1.4.0" + version: "1.3.1" clock: dependency: transitive description: name: clock - sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "1.1.2" + version: "1.1.0" collection: dependency: transitive description: name: collection - sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "1.19.1" + version: "1.15.0" + crypto: + dependency: transitive + description: + name: crypto + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.1" fake_async: dependency: transitive description: name: fake_async - sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "1.3.3" + version: "1.2.0" file: dependency: transitive description: name: file - sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "7.0.1" + version: "6.1.2" flutter: dependency: "direct main" description: flutter @@ -71,8 +85,7 @@ packages: dependency: "direct dev" description: name: flutter_lints - sha256: b543301ad291598523947dc534aaddc5aaad597b709d2426d3a0e0d44c5cb493 - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted version: "1.0.4" flutter_test: @@ -89,18 +102,16 @@ packages: dependency: "direct main" description: name: http - sha256: "5895291c13fa8a3bd82e76d5627f69e0d85ca6a30dcac95c4ea19a5d555879c2" - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "0.13.6" + version: "0.13.5" http_parser: dependency: transitive description: name: http_parser - sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571" - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "4.1.2" + version: "4.0.2" instabug_flutter: dependency: "direct main" description: @@ -112,183 +123,139 @@ packages: dependency: "direct main" description: name: instabug_http_client - sha256: a38bed979f549ffe85efa46c46ca743cbfab95a51295b60f143f249b71655231 - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted version: "2.6.0" - leak_tracker: - dependency: transitive - description: - name: leak_tracker - sha256: "6bb818ecbdffe216e81182c2f0714a2e62b593f4a4f13098713ff1685dfb6ab0" - url: "https://pub.dev" - source: hosted - version: "10.0.9" - leak_tracker_flutter_testing: - dependency: transitive - description: - name: leak_tracker_flutter_testing - sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573 - url: "https://pub.dev" - source: hosted - version: "3.0.9" - leak_tracker_testing: - dependency: transitive - description: - name: leak_tracker_testing - sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" - url: "https://pub.dev" - source: hosted - version: "3.0.1" lints: dependency: transitive description: name: lints - sha256: a2c3d198cb5ea2e179926622d433331d8b58374ab8f29cdda6e863bd62fd369c - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted version: "1.0.1" matcher: dependency: transitive description: name: matcher - sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "0.12.17" + version: "0.12.11" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "0.11.1" + version: "0.1.3" meta: dependency: transitive description: name: meta - sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "1.16.0" + version: "1.7.0" path: dependency: transitive description: name: path - sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "1.9.1" + version: "1.8.0" platform: dependency: transitive description: name: platform - sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984" - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "3.1.6" + version: "3.1.0" process: dependency: transitive description: name: process - sha256: "107d8be718f120bbba9dcd1e95e3bd325b1b4a4f07db64154635ba03f2567a0d" - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "5.0.3" + version: "4.2.4" sky_engine: dependency: transitive description: flutter source: sdk - version: "0.0.0" + version: "0.0.99" source_span: dependency: transitive description: name: source_span - sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c" - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "1.10.1" + version: "1.8.1" stack_trace: dependency: transitive description: name: stack_trace - sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "1.12.1" + version: "1.10.0" stream_channel: dependency: transitive description: name: stream_channel - sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "2.1.4" + version: "2.1.0" string_scanner: dependency: transitive description: name: string_scanner - sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "1.4.1" + version: "1.1.0" sync_http: dependency: transitive description: name: sync_http - sha256: "7f0cd72eca000d2e026bcd6f990b81d0ca06022ef4e32fb257b30d3d1014a961" - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "0.3.1" + version: "0.3.0" term_glyph: dependency: transitive description: name: term_glyph - sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "1.2.2" + version: "1.2.0" test_api: dependency: transitive description: name: test_api - sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "0.7.4" + version: "0.4.8" typed_data: dependency: transitive description: name: typed_data - sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "1.4.0" + version: "1.3.0" vector_math: dependency: transitive description: name: vector_math - sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "2.1.4" + version: "2.1.1" vm_service: dependency: transitive description: name: vm_service - sha256: ddfa8d30d89985b96407efce8acbdd124701f96741f2d981ca860662f1c0dc02 - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "15.0.0" + version: "7.5.0" webdriver: dependency: transitive description: name: webdriver - sha256: "2f3a14ca026957870cfd9c635b83507e0e51d8091568e90129fbf805aba7cade" - url: "https://pub.dev" + url: "https://pub.dartlang.org" source: hosted - version: "3.1.0" + version: "3.0.0" sdks: - dart: ">=3.7.0-0 <4.0.0" - flutter: ">=3.18.0-18.0.pre.54" + dart: ">=2.14.0 <3.0.0" diff --git a/lib/src/utils/instabug_navigator_observer.dart b/lib/src/utils/instabug_navigator_observer.dart index f10dce436..d10c59e6c 100644 --- a/lib/src/utils/instabug_navigator_observer.dart +++ b/lib/src/utils/instabug_navigator_observer.dart @@ -1,5 +1,4 @@ import 'dart:async'; -import 'dart:developer'; import 'package:flutter/material.dart'; import 'package:instabug_flutter/instabug_flutter.dart'; @@ -70,7 +69,6 @@ class InstabugNavigatorObserver extends NavigatorObserver { FutureOr _startScreenRenderCollector(int? uiTraceId) async { if (uiTraceId == null) return; final isScreenRenderEnabled = await FlagsConfig.screenRendering.isEnabled(); - log("isScreenRenderEnabled: $isScreenRenderEnabled"); await InstabugScreenRenderManager.I .checkForScreenRenderInitialization(isScreenRenderEnabled); diff --git a/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart b/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart index 8114d349e..4beb720af 100644 --- a/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart +++ b/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart @@ -1,5 +1,4 @@ import 'dart:async'; -import 'dart:developer'; import 'dart:ui' show TimingsCallback, FrameTiming, FramePhase; import 'package:flutter/widgets.dart'; @@ -319,10 +318,6 @@ class InstabugScreenRenderManager { /// Save Slow/Frozen Frames data void _onDelayedFrameDetected(int startTime, int durationInMicroseconds) { - log( - "${durationInMicroseconds >= 700000 ? "🚨Frozen" : "⚠️Slow"} Frame Detected (startTime: $startTime, duration: $durationInMicroseconds µs)", - name: tag, - ); _delayedFrames.add( InstabugFrameData( startTime, @@ -339,10 +334,6 @@ class InstabugScreenRenderManager { ) async { try { screenRenderData.saveEndTime(); - log( - "reportScreenRenderForCustomUiTrace $screenRenderData", - name: tag, - ); await APM.endScreenRenderForCustomUiTrace(screenRenderData); return true; } catch (error, stackTrace) { @@ -360,10 +351,6 @@ class InstabugScreenRenderManager { try { // Save the end time for the running ui trace, it's only needed in Android SDK. screenRenderData.saveEndTime(); - log( - "reportScreenRenderForAutoUiTrace $screenRenderData", - name: tag, - ); await APM.endScreenRenderForAutoUiTrace(screenRenderData); return true; diff --git a/test/apm_test.dart b/test/apm_test.dart index 90df62787..36a40ba27 100644 --- a/test/apm_test.dart +++ b/test/apm_test.dart @@ -256,26 +256,6 @@ void main() { verify(mHost.setScreenRenderEnabled(isEnabled)).called(1); }); - test( - "[setScreenRenderEnabled] should call [init()] screen render collector, is the feature is enabled", - () async { - const isEnabled = true; - when(mHost.isScreenRenderEnabled()).thenAnswer((_) async => true); - await APM.setScreenRenderingEnabled(isEnabled); - verify(mScreenRenderManager.init(any)).called(1); - verifyNoMoreInteractions(mScreenRenderManager); - }); - - test( - "[setScreenRenderEnabled] should call [remove()] screen render collector, is the feature is enabled", - () async { - const isEnabled = false; - when(mScreenRenderManager.screenRenderEnabled).thenReturn(true); - await APM.setScreenRenderingEnabled(isEnabled); - verify(mScreenRenderManager.dispose()).called(1); - verify(mScreenRenderManager.screenRenderEnabled).called(1); - }); - test( "[startUITrace] should start screen render collector with right params, if screen render feature is enabled", () async { diff --git a/test/utils/screen_render/instabug_screen_render_manager_test.dart b/test/utils/screen_render/instabug_screen_render_manager_test.dart index 918dfa168..2282b8b80 100644 --- a/test/utils/screen_render/instabug_screen_render_manager_test.dart +++ b/test/utils/screen_render/instabug_screen_render_manager_test.dart @@ -1,26 +1,13 @@ -import 'dart:ui' show FrameTiming; - -import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:instabug_flutter/instabug_flutter.dart'; -import 'package:instabug_flutter/src/generated/apm.api.g.dart'; -import 'package:instabug_flutter/src/generated/crash_reporting.api.g.dart'; import 'package:instabug_flutter/src/models/instabug_frame_data.dart'; import 'package:instabug_flutter/src/models/instabug_screen_render_data.dart'; import 'package:instabug_flutter/src/utils/instabug_logger.dart'; import 'package:instabug_flutter/src/utils/screen_rendering/instabug_screen_render_manager.dart'; -import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; -import 'instabug_screen_render_manager_test.mocks.dart'; +import 'instabug_screen_render_manager_test_mocks.dart'; -@GenerateMocks([ - ApmHostApi, - WidgetsBinding, - FrameTiming, - CrashReportingHostApi, - InstabugLogger, -]) void main() { TestWidgetsFlutterBinding.ensureInitialized(); diff --git a/test/utils/screen_render/instabug_screen_render_manager_test_mocks.dart b/test/utils/screen_render/instabug_screen_render_manager_test_mocks.dart new file mode 100644 index 000000000..3928266e0 --- /dev/null +++ b/test/utils/screen_render/instabug_screen_render_manager_test_mocks.dart @@ -0,0 +1,818 @@ +// Mocks generated by Mockito 5.2.0 from annotations +// in instabug_flutter/example/ios/.symlinks/plugins/instabug_flutter/test/utils/screen_render/instabug_screen_render_manager_test.dart. +// Do not manually edit this file. + +import 'dart:async' as _i9; +import 'dart:developer' as _i13; +import 'dart:ui' as _i4; + +import 'package:flutter/foundation.dart' as _i3; +import 'package:flutter/gestures.dart' as _i6; +import 'package:flutter/rendering.dart' as _i7; +import 'package:flutter/scheduler.dart' as _i11; +import 'package:flutter/services.dart' as _i5; +import 'package:flutter/src/widgets/binding.dart' as _i10; +import 'package:flutter/src/widgets/focus_manager.dart' as _i2; +import 'package:flutter/src/widgets/framework.dart' as _i12; +import 'package:instabug_flutter/instabug_flutter.dart' as _i16; +import 'package:instabug_flutter/src/generated/apm.api.g.dart' as _i8; +import 'package:instabug_flutter/src/generated/crash_reporting.api.g.dart' + as _i14; +import 'package:instabug_flutter/src/utils/instabug_logger.dart' as _i15; +import 'package:mockito/mockito.dart' as _i1; + +// ignore_for_file: type=lint +// ignore_for_file: avoid_redundant_argument_values +// ignore_for_file: avoid_setters_without_getters +// ignore_for_file: comment_references +// ignore_for_file: implementation_imports +// ignore_for_file: invalid_use_of_visible_for_testing_member +// ignore_for_file: prefer_const_constructors +// ignore_for_file: unnecessary_parenthesis +// ignore_for_file: camel_case_types + +class _FakeFocusManager_0 extends _i1.Fake implements _i2.FocusManager { + @override + String toString({_i3.DiagnosticLevel? minLevel = _i3.DiagnosticLevel.info}) => + super.toString(); +} + +class _FakeSingletonFlutterWindow_1 extends _i1.Fake + implements _i4.SingletonFlutterWindow {} + +class _FakePlatformDispatcher_2 extends _i1.Fake + implements _i4.PlatformDispatcher {} + +class _FakeHardwareKeyboard_3 extends _i1.Fake + implements _i5.HardwareKeyboard {} + +class _FakeKeyEventManager_4 extends _i1.Fake implements _i5.KeyEventManager {} + +class _FakeBinaryMessenger_5 extends _i1.Fake implements _i5.BinaryMessenger {} + +class _FakeChannelBuffers_6 extends _i1.Fake implements _i4.ChannelBuffers {} + +class _FakeRestorationManager_7 extends _i1.Fake + implements _i5.RestorationManager {} + +class _FakeDuration_8 extends _i1.Fake implements Duration {} + +class _FakePointerRouter_9 extends _i1.Fake implements _i6.PointerRouter {} + +class _FakeGestureArenaManager_10 extends _i1.Fake + implements _i6.GestureArenaManager {} + +class _FakePointerSignalResolver_11 extends _i1.Fake + implements _i6.PointerSignalResolver {} + +class _FakeMouseTracker_12 extends _i1.Fake implements _i7.MouseTracker {} + +class _FakePipelineOwner_13 extends _i1.Fake implements _i7.PipelineOwner {} + +class _FakeRenderView_14 extends _i1.Fake implements _i7.RenderView { + @override + String toString({_i3.DiagnosticLevel? minLevel = _i3.DiagnosticLevel.info}) => + super.toString(); +} + +class _FakeAccessibilityFeatures_15 extends _i1.Fake + implements _i4.AccessibilityFeatures {} + +class _FakeViewConfiguration_16 extends _i1.Fake + implements _i7.ViewConfiguration {} + +class _FakeSemanticsUpdateBuilder_17 extends _i1.Fake + implements _i4.SemanticsUpdateBuilder {} + +/// A class which mocks [ApmHostApi]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockApmHostApi extends _i1.Mock implements _i8.ApmHostApi { + MockApmHostApi() { + _i1.throwOnMissingStub(this); + } + + @override + _i9.Future setEnabled(bool? arg_isEnabled) => + (super.noSuchMethod(Invocation.method(#setEnabled, [arg_isEnabled]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future isEnabled() => + (super.noSuchMethod(Invocation.method(#isEnabled, []), + returnValue: Future.value(false)) as _i9.Future); + @override + _i9.Future setScreenLoadingEnabled(bool? arg_isEnabled) => + (super.noSuchMethod( + Invocation.method(#setScreenLoadingEnabled, [arg_isEnabled]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future isScreenLoadingEnabled() => + (super.noSuchMethod(Invocation.method(#isScreenLoadingEnabled, []), + returnValue: Future.value(false)) as _i9.Future); + @override + _i9.Future setColdAppLaunchEnabled(bool? arg_isEnabled) => + (super.noSuchMethod( + Invocation.method(#setColdAppLaunchEnabled, [arg_isEnabled]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future setAutoUITraceEnabled(bool? arg_isEnabled) => (super + .noSuchMethod(Invocation.method(#setAutoUITraceEnabled, [arg_isEnabled]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future startFlow(String? arg_name) => + (super.noSuchMethod(Invocation.method(#startFlow, [arg_name]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future setFlowAttribute( + String? arg_name, String? arg_key, String? arg_value) => + (super.noSuchMethod( + Invocation.method(#setFlowAttribute, [arg_name, arg_key, arg_value]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future endFlow(String? arg_name) => + (super.noSuchMethod(Invocation.method(#endFlow, [arg_name]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future startUITrace(String? arg_name) => + (super.noSuchMethod(Invocation.method(#startUITrace, [arg_name]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future endUITrace() => + (super.noSuchMethod(Invocation.method(#endUITrace, []), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future endAppLaunch() => + (super.noSuchMethod(Invocation.method(#endAppLaunch, []), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future networkLogAndroid(Map? arg_data) => + (super.noSuchMethod(Invocation.method(#networkLogAndroid, [arg_data]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future startCpUiTrace( + String? arg_screenName, int? arg_microTimeStamp, int? arg_traceId) => + (super.noSuchMethod( + Invocation.method(#startCpUiTrace, + [arg_screenName, arg_microTimeStamp, arg_traceId]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future reportScreenLoadingCP(int? arg_startTimeStampMicro, + int? arg_durationMicro, int? arg_uiTraceId) => + (super.noSuchMethod( + Invocation.method(#reportScreenLoadingCP, + [arg_startTimeStampMicro, arg_durationMicro, arg_uiTraceId]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future endScreenLoadingCP( + int? arg_timeStampMicro, int? arg_uiTraceId) => + (super.noSuchMethod( + Invocation.method( + #endScreenLoadingCP, [arg_timeStampMicro, arg_uiTraceId]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future isEndScreenLoadingEnabled() => + (super.noSuchMethod(Invocation.method(#isEndScreenLoadingEnabled, []), + returnValue: Future.value(false)) as _i9.Future); + @override + _i9.Future isAutoUiTraceEnabled() => + (super.noSuchMethod(Invocation.method(#isAutoUiTraceEnabled, []), + returnValue: Future.value(false)) as _i9.Future); + @override + _i9.Future isScreenRenderEnabled() => + (super.noSuchMethod(Invocation.method(#isScreenRenderEnabled, []), + returnValue: Future.value(false)) as _i9.Future); + @override + _i9.Future> getDeviceRefreshRateAndTolerance() => + (super.noSuchMethod( + Invocation.method(#getDeviceRefreshRateAndTolerance, []), + returnValue: Future>.value([])) + as _i9.Future>); + @override + _i9.Future setScreenRenderEnabled(bool? arg_isEnabled) => (super + .noSuchMethod(Invocation.method(#setScreenRenderEnabled, [arg_isEnabled]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future endScreenRenderForAutoUiTrace( + Map? arg_data) => + (super.noSuchMethod( + Invocation.method(#endScreenRenderForAutoUiTrace, [arg_data]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future endScreenRenderForCustomUiTrace( + Map? arg_data) => + (super.noSuchMethod( + Invocation.method(#endScreenRenderForCustomUiTrace, [arg_data]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); +} + +/// A class which mocks [WidgetsBinding]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockWidgetsBinding extends _i1.Mock implements _i10.WidgetsBinding { + MockWidgetsBinding() { + _i1.throwOnMissingStub(this); + } + + @override + bool get debugBuildingDirtyElements => + (super.noSuchMethod(Invocation.getter(#debugBuildingDirtyElements), + returnValue: false) as bool); + @override + set debugBuildingDirtyElements(bool? _debugBuildingDirtyElements) => + super.noSuchMethod( + Invocation.setter( + #debugBuildingDirtyElements, _debugBuildingDirtyElements), + returnValueForMissingStub: null); + @override + _i2.FocusManager get focusManager => + (super.noSuchMethod(Invocation.getter(#focusManager), + returnValue: _FakeFocusManager_0()) as _i2.FocusManager); + @override + bool get firstFrameRasterized => + (super.noSuchMethod(Invocation.getter(#firstFrameRasterized), + returnValue: false) as bool); + @override + _i9.Future get waitUntilFirstFrameRasterized => + (super.noSuchMethod(Invocation.getter(#waitUntilFirstFrameRasterized), + returnValue: Future.value()) as _i9.Future); + @override + bool get debugDidSendFirstFrameEvent => + (super.noSuchMethod(Invocation.getter(#debugDidSendFirstFrameEvent), + returnValue: false) as bool); + @override + bool get framesEnabled => + (super.noSuchMethod(Invocation.getter(#framesEnabled), returnValue: false) + as bool); + @override + bool get isRootWidgetAttached => + (super.noSuchMethod(Invocation.getter(#isRootWidgetAttached), + returnValue: false) as bool); + @override + _i4.SingletonFlutterWindow get window => + (super.noSuchMethod(Invocation.getter(#window), + returnValue: _FakeSingletonFlutterWindow_1()) + as _i4.SingletonFlutterWindow); + @override + _i4.PlatformDispatcher get platformDispatcher => + (super.noSuchMethod(Invocation.getter(#platformDispatcher), + returnValue: _FakePlatformDispatcher_2()) as _i4.PlatformDispatcher); + @override + bool get locked => + (super.noSuchMethod(Invocation.getter(#locked), returnValue: false) + as bool); + @override + _i5.HardwareKeyboard get keyboard => + (super.noSuchMethod(Invocation.getter(#keyboard), + returnValue: _FakeHardwareKeyboard_3()) as _i5.HardwareKeyboard); + @override + _i5.KeyEventManager get keyEventManager => + (super.noSuchMethod(Invocation.getter(#keyEventManager), + returnValue: _FakeKeyEventManager_4()) as _i5.KeyEventManager); + @override + _i5.BinaryMessenger get defaultBinaryMessenger => + (super.noSuchMethod(Invocation.getter(#defaultBinaryMessenger), + returnValue: _FakeBinaryMessenger_5()) as _i5.BinaryMessenger); + @override + _i4.ChannelBuffers get channelBuffers => + (super.noSuchMethod(Invocation.getter(#channelBuffers), + returnValue: _FakeChannelBuffers_6()) as _i4.ChannelBuffers); + @override + _i5.RestorationManager get restorationManager => + (super.noSuchMethod(Invocation.getter(#restorationManager), + returnValue: _FakeRestorationManager_7()) as _i5.RestorationManager); + @override + _i11.SchedulingStrategy get schedulingStrategy => + (super.noSuchMethod(Invocation.getter(#schedulingStrategy), + returnValue: ({int? priority, _i11.SchedulerBinding? scheduler}) => + false) as _i11.SchedulingStrategy); + @override + set schedulingStrategy(_i11.SchedulingStrategy? _schedulingStrategy) => super + .noSuchMethod(Invocation.setter(#schedulingStrategy, _schedulingStrategy), + returnValueForMissingStub: null); + @override + int get transientCallbackCount => + (super.noSuchMethod(Invocation.getter(#transientCallbackCount), + returnValue: 0) as int); + @override + _i9.Future get endOfFrame => + (super.noSuchMethod(Invocation.getter(#endOfFrame), + returnValue: Future.value()) as _i9.Future); + @override + bool get hasScheduledFrame => + (super.noSuchMethod(Invocation.getter(#hasScheduledFrame), + returnValue: false) as bool); + @override + _i11.SchedulerPhase get schedulerPhase => + (super.noSuchMethod(Invocation.getter(#schedulerPhase), + returnValue: _i11.SchedulerPhase.idle) as _i11.SchedulerPhase); + @override + Duration get currentFrameTimeStamp => + (super.noSuchMethod(Invocation.getter(#currentFrameTimeStamp), + returnValue: _FakeDuration_8()) as Duration); + @override + Duration get currentSystemFrameTimeStamp => + (super.noSuchMethod(Invocation.getter(#currentSystemFrameTimeStamp), + returnValue: _FakeDuration_8()) as Duration); + @override + _i6.PointerRouter get pointerRouter => + (super.noSuchMethod(Invocation.getter(#pointerRouter), + returnValue: _FakePointerRouter_9()) as _i6.PointerRouter); + @override + _i6.GestureArenaManager get gestureArena => (super.noSuchMethod( + Invocation.getter(#gestureArena), + returnValue: _FakeGestureArenaManager_10()) as _i6.GestureArenaManager); + @override + _i6.PointerSignalResolver get pointerSignalResolver => + (super.noSuchMethod(Invocation.getter(#pointerSignalResolver), + returnValue: _FakePointerSignalResolver_11()) + as _i6.PointerSignalResolver); + @override + bool get resamplingEnabled => + (super.noSuchMethod(Invocation.getter(#resamplingEnabled), + returnValue: false) as bool); + @override + set resamplingEnabled(bool? _resamplingEnabled) => super.noSuchMethod( + Invocation.setter(#resamplingEnabled, _resamplingEnabled), + returnValueForMissingStub: null); + @override + Duration get samplingOffset => + (super.noSuchMethod(Invocation.getter(#samplingOffset), + returnValue: _FakeDuration_8()) as Duration); + @override + set samplingOffset(Duration? _samplingOffset) => + super.noSuchMethod(Invocation.setter(#samplingOffset, _samplingOffset), + returnValueForMissingStub: null); + @override + _i7.MouseTracker get mouseTracker => + (super.noSuchMethod(Invocation.getter(#mouseTracker), + returnValue: _FakeMouseTracker_12()) as _i7.MouseTracker); + @override + _i7.PipelineOwner get pipelineOwner => + (super.noSuchMethod(Invocation.getter(#pipelineOwner), + returnValue: _FakePipelineOwner_13()) as _i7.PipelineOwner); + @override + _i7.RenderView get renderView => + (super.noSuchMethod(Invocation.getter(#renderView), + returnValue: _FakeRenderView_14()) as _i7.RenderView); + @override + set renderView(_i7.RenderView? value) => + super.noSuchMethod(Invocation.setter(#renderView, value), + returnValueForMissingStub: null); + @override + bool get sendFramesToEngine => + (super.noSuchMethod(Invocation.getter(#sendFramesToEngine), + returnValue: false) as bool); + @override + _i4.AccessibilityFeatures get accessibilityFeatures => + (super.noSuchMethod(Invocation.getter(#accessibilityFeatures), + returnValue: _FakeAccessibilityFeatures_15()) + as _i4.AccessibilityFeatures); + @override + bool get disableAnimations => + (super.noSuchMethod(Invocation.getter(#disableAnimations), + returnValue: false) as bool); + @override + void initInstances() => + super.noSuchMethod(Invocation.method(#initInstances, []), + returnValueForMissingStub: null); + @override + void initServiceExtensions() => + super.noSuchMethod(Invocation.method(#initServiceExtensions, []), + returnValueForMissingStub: null); + @override + void addObserver(_i10.WidgetsBindingObserver? observer) => + super.noSuchMethod(Invocation.method(#addObserver, [observer]), + returnValueForMissingStub: null); + @override + bool removeObserver(_i10.WidgetsBindingObserver? observer) => + (super.noSuchMethod(Invocation.method(#removeObserver, [observer]), + returnValue: false) as bool); + @override + void handleMetricsChanged() => + super.noSuchMethod(Invocation.method(#handleMetricsChanged, []), + returnValueForMissingStub: null); + @override + void handleTextScaleFactorChanged() => + super.noSuchMethod(Invocation.method(#handleTextScaleFactorChanged, []), + returnValueForMissingStub: null); + @override + void handlePlatformBrightnessChanged() => super.noSuchMethod( + Invocation.method(#handlePlatformBrightnessChanged, []), + returnValueForMissingStub: null); + @override + void handleAccessibilityFeaturesChanged() => super.noSuchMethod( + Invocation.method(#handleAccessibilityFeaturesChanged, []), + returnValueForMissingStub: null); + @override + void handleLocaleChanged() => + super.noSuchMethod(Invocation.method(#handleLocaleChanged, []), + returnValueForMissingStub: null); + @override + void dispatchLocalesChanged(List<_i4.Locale>? locales) => + super.noSuchMethod(Invocation.method(#dispatchLocalesChanged, [locales]), + returnValueForMissingStub: null); + @override + void dispatchAccessibilityFeaturesChanged() => super.noSuchMethod( + Invocation.method(#dispatchAccessibilityFeaturesChanged, []), + returnValueForMissingStub: null); + @override + _i9.Future handlePopRoute() => + (super.noSuchMethod(Invocation.method(#handlePopRoute, []), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future handlePushRoute(String? route) => + (super.noSuchMethod(Invocation.method(#handlePushRoute, [route]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + void handleAppLifecycleStateChanged(_i4.AppLifecycleState? state) => super + .noSuchMethod(Invocation.method(#handleAppLifecycleStateChanged, [state]), + returnValueForMissingStub: null); + @override + void handleMemoryPressure() => + super.noSuchMethod(Invocation.method(#handleMemoryPressure, []), + returnValueForMissingStub: null); + @override + void drawFrame() => super.noSuchMethod(Invocation.method(#drawFrame, []), + returnValueForMissingStub: null); + @override + void scheduleAttachRootWidget(_i12.Widget? rootWidget) => super.noSuchMethod( + Invocation.method(#scheduleAttachRootWidget, [rootWidget]), + returnValueForMissingStub: null); + @override + void attachRootWidget(_i12.Widget? rootWidget) => + super.noSuchMethod(Invocation.method(#attachRootWidget, [rootWidget]), + returnValueForMissingStub: null); + @override + _i9.Future performReassemble() => + (super.noSuchMethod(Invocation.method(#performReassemble, []), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i4.Locale? computePlatformResolvedLocale( + List<_i4.Locale>? supportedLocales) => + (super.noSuchMethod(Invocation.method( + #computePlatformResolvedLocale, [supportedLocales])) as _i4.Locale?); + @override + _i9.Future lockEvents(_i9.Future Function()? callback) => + (super.noSuchMethod(Invocation.method(#lockEvents, [callback]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + void unlocked() => super.noSuchMethod(Invocation.method(#unlocked, []), + returnValueForMissingStub: null); + @override + _i9.Future reassembleApplication() => + (super.noSuchMethod(Invocation.method(#reassembleApplication, []), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + void registerSignalServiceExtension( + {String? name, _i3.AsyncCallback? callback}) => + super.noSuchMethod( + Invocation.method(#registerSignalServiceExtension, [], + {#name: name, #callback: callback}), + returnValueForMissingStub: null); + @override + void registerBoolServiceExtension( + {String? name, + _i3.AsyncValueGetter? getter, + _i3.AsyncValueSetter? setter}) => + super.noSuchMethod( + Invocation.method(#registerBoolServiceExtension, [], + {#name: name, #getter: getter, #setter: setter}), + returnValueForMissingStub: null); + @override + void registerNumericServiceExtension( + {String? name, + _i3.AsyncValueGetter? getter, + _i3.AsyncValueSetter? setter}) => + super.noSuchMethod( + Invocation.method(#registerNumericServiceExtension, [], + {#name: name, #getter: getter, #setter: setter}), + returnValueForMissingStub: null); + @override + void postEvent(String? eventKind, Map? eventData) => + super.noSuchMethod(Invocation.method(#postEvent, [eventKind, eventData]), + returnValueForMissingStub: null); + @override + void registerStringServiceExtension( + {String? name, + _i3.AsyncValueGetter? getter, + _i3.AsyncValueSetter? setter}) => + super.noSuchMethod( + Invocation.method(#registerStringServiceExtension, [], + {#name: name, #getter: getter, #setter: setter}), + returnValueForMissingStub: null); + @override + void registerServiceExtension( + {String? name, _i3.ServiceExtensionCallback? callback}) => + super.noSuchMethod( + Invocation.method(#registerServiceExtension, [], + {#name: name, #callback: callback}), + returnValueForMissingStub: null); + @override + _i5.BinaryMessenger createBinaryMessenger() => + (super.noSuchMethod(Invocation.method(#createBinaryMessenger, []), + returnValue: _FakeBinaryMessenger_5()) as _i5.BinaryMessenger); + @override + _i9.Future handleSystemMessage(Object? systemMessage) => (super + .noSuchMethod(Invocation.method(#handleSystemMessage, [systemMessage]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + void initLicenses() => + super.noSuchMethod(Invocation.method(#initLicenses, []), + returnValueForMissingStub: null); + @override + void evict(String? asset) => + super.noSuchMethod(Invocation.method(#evict, [asset]), + returnValueForMissingStub: null); + @override + void readInitialLifecycleStateFromNativeWindow() => super.noSuchMethod( + Invocation.method(#readInitialLifecycleStateFromNativeWindow, []), + returnValueForMissingStub: null); + @override + _i5.RestorationManager createRestorationManager() => + (super.noSuchMethod(Invocation.method(#createRestorationManager, []), + returnValue: _FakeRestorationManager_7()) as _i5.RestorationManager); + @override + void setSystemUiChangeCallback(_i5.SystemUiChangeCallback? callback) => super + .noSuchMethod(Invocation.method(#setSystemUiChangeCallback, [callback]), + returnValueForMissingStub: null); + @override + void addTimingsCallback(_i4.TimingsCallback? callback) => + super.noSuchMethod(Invocation.method(#addTimingsCallback, [callback]), + returnValueForMissingStub: null); + @override + void removeTimingsCallback(_i4.TimingsCallback? callback) => + super.noSuchMethod(Invocation.method(#removeTimingsCallback, [callback]), + returnValueForMissingStub: null); + @override + _i9.Future scheduleTask( + _i11.TaskCallback? task, _i11.Priority? priority, + {String? debugLabel, _i13.Flow? flow}) => + (super.noSuchMethod( + Invocation.method(#scheduleTask, [task, priority], + {#debugLabel: debugLabel, #flow: flow}), + returnValue: Future.value(null)) as _i9.Future); + @override + bool handleEventLoopCallback() => + (super.noSuchMethod(Invocation.method(#handleEventLoopCallback, []), + returnValue: false) as bool); + @override + int scheduleFrameCallback(_i11.FrameCallback? callback, + {bool? rescheduling = false}) => + (super.noSuchMethod( + Invocation.method(#scheduleFrameCallback, [callback], + {#rescheduling: rescheduling}), + returnValue: 0) as int); + @override + void cancelFrameCallbackWithId(int? id) => + super.noSuchMethod(Invocation.method(#cancelFrameCallbackWithId, [id]), + returnValueForMissingStub: null); + @override + bool debugAssertNoTransientCallbacks(String? reason) => (super.noSuchMethod( + Invocation.method(#debugAssertNoTransientCallbacks, [reason]), + returnValue: false) as bool); + @override + void addPersistentFrameCallback(_i11.FrameCallback? callback) => super + .noSuchMethod(Invocation.method(#addPersistentFrameCallback, [callback]), + returnValueForMissingStub: null); + @override + void addPostFrameCallback(_i11.FrameCallback? callback) => + super.noSuchMethod(Invocation.method(#addPostFrameCallback, [callback]), + returnValueForMissingStub: null); + @override + void ensureFrameCallbacksRegistered() => + super.noSuchMethod(Invocation.method(#ensureFrameCallbacksRegistered, []), + returnValueForMissingStub: null); + @override + void ensureVisualUpdate() => + super.noSuchMethod(Invocation.method(#ensureVisualUpdate, []), + returnValueForMissingStub: null); + @override + void scheduleFrame() => + super.noSuchMethod(Invocation.method(#scheduleFrame, []), + returnValueForMissingStub: null); + @override + void scheduleForcedFrame() => + super.noSuchMethod(Invocation.method(#scheduleForcedFrame, []), + returnValueForMissingStub: null); + @override + void scheduleWarmUpFrame() => + super.noSuchMethod(Invocation.method(#scheduleWarmUpFrame, []), + returnValueForMissingStub: null); + @override + void resetEpoch() => super.noSuchMethod(Invocation.method(#resetEpoch, []), + returnValueForMissingStub: null); + @override + void handleBeginFrame(Duration? rawTimeStamp) => + super.noSuchMethod(Invocation.method(#handleBeginFrame, [rawTimeStamp]), + returnValueForMissingStub: null); + @override + void handleDrawFrame() => + super.noSuchMethod(Invocation.method(#handleDrawFrame, []), + returnValueForMissingStub: null); + @override + void cancelPointer(int? pointer) => + super.noSuchMethod(Invocation.method(#cancelPointer, [pointer]), + returnValueForMissingStub: null); + @override + void handlePointerEvent(_i6.PointerEvent? event) => + super.noSuchMethod(Invocation.method(#handlePointerEvent, [event]), + returnValueForMissingStub: null); + @override + void hitTest(_i6.HitTestResult? result, _i4.Offset? position) => + super.noSuchMethod(Invocation.method(#hitTest, [result, position]), + returnValueForMissingStub: null); + @override + void dispatchEvent( + _i6.PointerEvent? event, _i6.HitTestResult? hitTestResult) => + super.noSuchMethod( + Invocation.method(#dispatchEvent, [event, hitTestResult]), + returnValueForMissingStub: null); + @override + void handleEvent(_i6.PointerEvent? event, _i6.HitTestEntry? entry) => + super.noSuchMethod(Invocation.method(#handleEvent, [event, entry]), + returnValueForMissingStub: null); + @override + void resetGestureBinding() => + super.noSuchMethod(Invocation.method(#resetGestureBinding, []), + returnValueForMissingStub: null); + @override + void initRenderView() => + super.noSuchMethod(Invocation.method(#initRenderView, []), + returnValueForMissingStub: null); + @override + _i7.ViewConfiguration createViewConfiguration() => + (super.noSuchMethod(Invocation.method(#createViewConfiguration, []), + returnValue: _FakeViewConfiguration_16()) as _i7.ViewConfiguration); + @override + void initMouseTracker([_i7.MouseTracker? tracker]) => + super.noSuchMethod(Invocation.method(#initMouseTracker, [tracker]), + returnValueForMissingStub: null); + @override + void setSemanticsEnabled(bool? enabled) => + super.noSuchMethod(Invocation.method(#setSemanticsEnabled, [enabled]), + returnValueForMissingStub: null); + @override + void deferFirstFrame() => + super.noSuchMethod(Invocation.method(#deferFirstFrame, []), + returnValueForMissingStub: null); + @override + void allowFirstFrame() => + super.noSuchMethod(Invocation.method(#allowFirstFrame, []), + returnValueForMissingStub: null); + @override + void resetFirstFrameSent() => + super.noSuchMethod(Invocation.method(#resetFirstFrameSent, []), + returnValueForMissingStub: null); + @override + _i4.SemanticsUpdateBuilder createSemanticsUpdateBuilder() => + (super.noSuchMethod(Invocation.method(#createSemanticsUpdateBuilder, []), + returnValue: _FakeSemanticsUpdateBuilder_17()) + as _i4.SemanticsUpdateBuilder); +} + +/// A class which mocks [FrameTiming]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockFrameTiming extends _i1.Mock implements _i4.FrameTiming { + MockFrameTiming() { + _i1.throwOnMissingStub(this); + } + + @override + Duration get buildDuration => + (super.noSuchMethod(Invocation.getter(#buildDuration), + returnValue: _FakeDuration_8()) as Duration); + @override + Duration get rasterDuration => + (super.noSuchMethod(Invocation.getter(#rasterDuration), + returnValue: _FakeDuration_8()) as Duration); + @override + Duration get vsyncOverhead => + (super.noSuchMethod(Invocation.getter(#vsyncOverhead), + returnValue: _FakeDuration_8()) as Duration); + @override + Duration get totalSpan => (super.noSuchMethod(Invocation.getter(#totalSpan), + returnValue: _FakeDuration_8()) as Duration); + @override + int get layerCacheCount => + (super.noSuchMethod(Invocation.getter(#layerCacheCount), returnValue: 0) + as int); + @override + int get layerCacheBytes => + (super.noSuchMethod(Invocation.getter(#layerCacheBytes), returnValue: 0) + as int); + @override + double get layerCacheMegabytes => + (super.noSuchMethod(Invocation.getter(#layerCacheMegabytes), + returnValue: 0.0) as double); + @override + int get pictureCacheCount => + (super.noSuchMethod(Invocation.getter(#pictureCacheCount), returnValue: 0) + as int); + @override + int get pictureCacheBytes => + (super.noSuchMethod(Invocation.getter(#pictureCacheBytes), returnValue: 0) + as int); + @override + double get pictureCacheMegabytes => + (super.noSuchMethod(Invocation.getter(#pictureCacheMegabytes), + returnValue: 0.0) as double); + @override + int get frameNumber => + (super.noSuchMethod(Invocation.getter(#frameNumber), returnValue: 0) + as int); + @override + int timestampInMicroseconds(_i4.FramePhase? phase) => + (super.noSuchMethod(Invocation.method(#timestampInMicroseconds, [phase]), + returnValue: 0) as int); +} + +/// A class which mocks [CrashReportingHostApi]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockCrashReportingHostApi extends _i1.Mock + implements _i14.CrashReportingHostApi { + MockCrashReportingHostApi() { + _i1.throwOnMissingStub(this); + } + + @override + _i9.Future setEnabled(bool? arg_isEnabled) => + (super.noSuchMethod(Invocation.method(#setEnabled, [arg_isEnabled]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future send(String? arg_jsonCrash, bool? arg_isHandled) => (super + .noSuchMethod(Invocation.method(#send, [arg_jsonCrash, arg_isHandled]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override + _i9.Future sendNonFatalError( + String? arg_jsonCrash, + Map? arg_userAttributes, + String? arg_fingerprint, + String? arg_nonFatalExceptionLevel) => + (super.noSuchMethod( + Invocation.method(#sendNonFatalError, [ + arg_jsonCrash, + arg_userAttributes, + arg_fingerprint, + arg_nonFatalExceptionLevel + ]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); +} + +/// A class which mocks [InstabugLogger]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockInstabugLogger extends _i1.Mock implements _i15.InstabugLogger { + MockInstabugLogger() { + _i1.throwOnMissingStub(this); + } + + @override + set logLevel(_i16.LogLevel? level) => + super.noSuchMethod(Invocation.setter(#logLevel, level), + returnValueForMissingStub: null); + @override + void log(String? message, {_i16.LogLevel? level, String? tag = r''}) => + super.noSuchMethod( + Invocation.method(#log, [message], {#level: level, #tag: tag}), + returnValueForMissingStub: null); + @override + void e(String? message, {String? tag = r''}) => + super.noSuchMethod(Invocation.method(#e, [message], {#tag: tag}), + returnValueForMissingStub: null); + @override + void d(String? message, {String? tag = r''}) => + super.noSuchMethod(Invocation.method(#d, [message], {#tag: tag}), + returnValueForMissingStub: null); + @override + void v(String? message, {String? tag = r''}) => + super.noSuchMethod(Invocation.method(#v, [message], {#tag: tag}), + returnValueForMissingStub: null); +} diff --git a/test/utils/screen_render/instabug_widget_binding_observer_test.dart b/test/utils/screen_render/instabug_widget_binding_observer_test.dart index b97d312a0..d3117c7ca 100644 --- a/test/utils/screen_render/instabug_widget_binding_observer_test.dart +++ b/test/utils/screen_render/instabug_widget_binding_observer_test.dart @@ -73,15 +73,6 @@ void main() { verify(mockRenderManager.stopScreenRenderCollector()).called(1); }); - test('handles AppLifecycleState.detached and stops render collector', () { - when(mockRenderManager.screenRenderEnabled).thenReturn(true); - - InstabugWidgetsBindingObserver.I - .didChangeAppLifecycleState(AppLifecycleState.detached); - - verify(mockRenderManager.stopScreenRenderCollector()).called(1); - }); - test('handles AppLifecycleState.inactive with no action', () { // Just ensure it doesn't crash expect( From 8a3a98c674ee73afd96e7ebf24b8a64b9fc71271 Mon Sep 17 00:00:00 2001 From: Andrew Amin Date: Wed, 20 Aug 2025 12:29:35 +0300 Subject: [PATCH 78/84] remove unnecessary native unit test --- example/ios/InstabugTests/ApmApiTests.m | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/example/ios/InstabugTests/ApmApiTests.m b/example/ios/InstabugTests/ApmApiTests.m index 6d8ea2a33..75572d958 100644 --- a/example/ios/InstabugTests/ApmApiTests.m +++ b/example/ios/InstabugTests/ApmApiTests.m @@ -199,21 +199,6 @@ - (void)testEndScreenLoading { OCMVerify([self.mAPM endScreenLoadingCPWithEndTimestampMUS:endScreenLoadingCPWithEndTimestampMUS]); } -- (void)testIsAutoUiTraceEnabled { - XCTestExpectation *expectation = [self expectationWithDescription:@"Call completion handler"]; - - BOOL isAutoUiTraceEnabled = YES; - OCMStub([self.mAPM autoUITraceEnabled]).andReturn(isAutoUiTraceEnabled); - - [self.api isAutoUiTraceEnabledWithCompletion:^(NSNumber *isEnabledNumber, FlutterError *error) { - [expectation fulfill]; - - XCTAssertEqualObjects(isEnabledNumber, @(isAutoUiTraceEnabled)); - XCTAssertNil(error); - }]; - - [self waitForExpectations:@[expectation] timeout:5.0]; -} - (void)testIsScreenRenderEnabled { XCTestExpectation *expectation = [self expectationWithDescription:@"Call completion handler"]; From 6b7d480e13461eb9d1d06b85dfa04b03d0d3739e Mon Sep 17 00:00:00 2001 From: Andrew Amin Date: Wed, 20 Aug 2025 15:16:00 +0300 Subject: [PATCH 79/84] fix android back button --- .../flutter/InstabugFlutterPlugin.java | 37 +++------- lib/src/modules/instabug.dart | 8 +-- .../utils/instabug_navigator_observer.dart | 2 +- .../instabug_screen_render_manager.dart | 4 ++ .../instabug_widget_binding_observer.dart | 67 ++++++++++--------- ...instabug_widget_binding_observer_test.dart | 23 +------ 6 files changed, 55 insertions(+), 86 deletions(-) diff --git a/android/src/main/java/com/instabug/flutter/InstabugFlutterPlugin.java b/android/src/main/java/com/instabug/flutter/InstabugFlutterPlugin.java index ec6a022d2..d399fb834 100644 --- a/android/src/main/java/com/instabug/flutter/InstabugFlutterPlugin.java +++ b/android/src/main/java/com/instabug/flutter/InstabugFlutterPlugin.java @@ -11,7 +11,11 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.lifecycle.Lifecycle; +import androidx.lifecycle.LifecycleEventObserver; +import androidx.lifecycle.LifecycleOwner; +import com.instabug.flutter.generated.InstabugPigeon; import com.instabug.flutter.modules.ApmApi; import com.instabug.flutter.modules.BugReportingApi; import com.instabug.flutter.modules.CrashReportingApi; @@ -23,8 +27,6 @@ import com.instabug.flutter.modules.SurveysApi; import java.util.concurrent.Callable; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; import io.flutter.embedding.engine.plugins.FlutterPlugin; import io.flutter.embedding.engine.plugins.activity.ActivityAware; @@ -32,21 +34,15 @@ import io.flutter.embedding.engine.plugins.lifecycle.HiddenLifecycleReference; import io.flutter.embedding.engine.renderer.FlutterRenderer; import io.flutter.plugin.common.BinaryMessenger; -import androidx.lifecycle.Lifecycle; -import androidx.lifecycle.LifecycleEventObserver; -import androidx.lifecycle.LifecycleOwner; -import com.instabug.flutter.generated.InstabugPigeon; public class InstabugFlutterPlugin implements FlutterPlugin, ActivityAware, LifecycleEventObserver { private static final String TAG = "Andrew"; @SuppressLint("StaticFieldLeak") private static Activity activity; - + private InstabugPigeon.InstabugFlutterApi instabugFlutterApi; private Lifecycle lifecycle; - final CountDownLatch latch = new CountDownLatch(1); - @Override public void onAttachedToEngine(@NonNull FlutterPluginBinding binding) { @@ -62,7 +58,7 @@ public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) { @Override public void onAttachedToActivity(@NonNull ActivityPluginBinding binding) { activity = binding.getActivity(); - + // Register lifecycle observer if available if (binding.getLifecycle() instanceof HiddenLifecycleReference) { lifecycle = ((HiddenLifecycleReference) binding.getLifecycle()).getLifecycle(); @@ -72,8 +68,6 @@ public void onAttachedToActivity(@NonNull ActivityPluginBinding binding) { @Override public void onDetachedFromActivityForConfigChanges() { - Log.d(TAG, "onDetachedFromActivityForConfigChanges"); - if (lifecycle != null) { lifecycle.removeObserver(this); } @@ -83,7 +77,7 @@ public void onDetachedFromActivityForConfigChanges() { @Override public void onReattachedToActivityForConfigChanges(@NonNull ActivityPluginBinding binding) { activity = binding.getActivity(); - + // Re-register lifecycle observer if available if (binding.getLifecycle() instanceof HiddenLifecycleReference) { lifecycle = ((HiddenLifecycleReference) binding.getLifecycle()).getLifecycle(); @@ -93,7 +87,6 @@ public void onReattachedToActivityForConfigChanges(@NonNull ActivityPluginBindin @Override public void onDetachedFromActivity() { - Log.d(TAG, "onDetachedFromActivity"); if (lifecycle != null) { lifecycle.removeObserver(this); lifecycle = null; @@ -104,29 +97,19 @@ public void onDetachedFromActivity() { @Override public void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event) { if (event == Lifecycle.Event.ON_PAUSE) { - Log.d(TAG, "ON_PAUSE"); - handleOnDestroy(); + handleOnPause(); } } - - private void handleOnDestroy() { - Log.d(TAG, "handleOnDestroy"); + private void handleOnPause() { if (instabugFlutterApi != null) { instabugFlutterApi.dispose(new InstabugPigeon.InstabugFlutterApi.Reply() { @Override public void reply(Void reply) { Log.d(TAG, "Screen render cleanup dispose called successfully"); - latch.countDown(); } }); } - try { - // Wait up to 2 seconds to avoid ANR - latch.await(2, TimeUnit.SECONDS); - } catch (InterruptedException e) { - e.printStackTrace(); - } } private static void register(Context context, BinaryMessenger messenger, FlutterRenderer renderer) { @@ -139,7 +122,7 @@ public Bitmap call() { Callable refreshRateProvider = new Callable() { @Override - public Float call(){ + public Float call() { return getRefreshRate(); } }; diff --git a/lib/src/modules/instabug.dart b/lib/src/modules/instabug.dart index ee98afaa0..7dc40873a 100644 --- a/lib/src/modules/instabug.dart +++ b/lib/src/modules/instabug.dart @@ -137,7 +137,7 @@ enum CustomTextPlaceHolderKey { enum ReproStepsMode { enabled, disabled, enabledWithNoScreenshots } -/// Disposal manager for handling Android onDestroy lifecycle events +/// Disposal manager for handling Android lifecycle events class _InstabugDisposalManager implements InstabugFlutterApi { _InstabugDisposalManager._(); @@ -148,10 +148,8 @@ class _InstabugDisposalManager implements InstabugFlutterApi { @override void dispose() { - // Call the InstabugWidgetsBindingObserver dispose method when Android onDestroy is triggered - InstabugLogger.I.d( - 'Android onDestroy called - disposing screen render resources', - tag: 'InstabugDisposal'); + // Call the InstabugWidgetsBindingObserver dispose method when Android onPause is triggered + // to overcome calling onActivityDestroy() from android side before sending the data to it. InstabugWidgetsBindingObserver.dispose(); } } diff --git a/lib/src/utils/instabug_navigator_observer.dart b/lib/src/utils/instabug_navigator_observer.dart index f10dce436..878741457 100644 --- a/lib/src/utils/instabug_navigator_observer.dart +++ b/lib/src/utils/instabug_navigator_observer.dart @@ -70,7 +70,7 @@ class InstabugNavigatorObserver extends NavigatorObserver { FutureOr _startScreenRenderCollector(int? uiTraceId) async { if (uiTraceId == null) return; final isScreenRenderEnabled = await FlagsConfig.screenRendering.isEnabled(); - log("isScreenRenderEnabled: $isScreenRenderEnabled"); + log("isScreenRenderEnabled: $isScreenRenderEnabled" , name: "ScreenRenderManager"); await InstabugScreenRenderManager.I .checkForScreenRenderInitialization(isScreenRenderEnabled); diff --git a/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart b/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart index 8114d349e..586d685dc 100644 --- a/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart +++ b/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart @@ -59,6 +59,7 @@ class InstabugScreenRenderManager { @internal Future init(WidgetsBinding? widgetBinding) async { try { + log("init" , name: tag); // passing WidgetsBinding? (nullable) for flutter versions prior than 3.x if (!screenRenderEnabled && widgetBinding != null) { _widgetsBinding = widgetBinding; @@ -122,6 +123,7 @@ class InstabugScreenRenderManager { int traceId, [ UiTraceType type = UiTraceType.auto, ]) { + log("startScreenRenderCollectorForTraceId" , name: tag); // Return if frameTimingListener not attached if (_frameCollectorIsNotActive) return; @@ -138,6 +140,7 @@ class InstabugScreenRenderManager { void endScreenRenderCollector([ UiTraceType type = UiTraceType.auto, ]) { + log("endScreenRenderCollector" , name: tag); // Return if frameTimingListener not attached if (_frameCollectorIsNotActive) return; @@ -203,6 +206,7 @@ class InstabugScreenRenderManager { @internal void dispose() { try { + log("dispose" , name: tag); _resetCachedFrameData(); _removeFrameTimings(); _removeWidgetBindingObserver(); diff --git a/lib/src/utils/screen_rendering/instabug_widget_binding_observer.dart b/lib/src/utils/screen_rendering/instabug_widget_binding_observer.dart index 349d39bf2..01b1968b3 100644 --- a/lib/src/utils/screen_rendering/instabug_widget_binding_observer.dart +++ b/lib/src/utils/screen_rendering/instabug_widget_binding_observer.dart @@ -1,5 +1,7 @@ +import 'dart:developer'; + import 'package:flutter/widgets.dart'; -import 'package:instabug_flutter/src/utils/instabug_logger.dart'; +import 'package:instabug_flutter/src/utils/ibg_build_info.dart'; import 'package:instabug_flutter/src/utils/screen_loading/screen_loading_manager.dart'; import 'package:instabug_flutter/src/utils/screen_name_masker.dart'; import 'package:instabug_flutter/src/utils/screen_rendering/instabug_screen_render_manager.dart'; @@ -22,25 +24,12 @@ class InstabugWidgetsBindingObserver extends WidgetsBindingObserver { static const tag = "InstabugWidgetsBindingObserver"; /// Disposes all screen render resources. - /// This method is safe to call multiple times and from external sources - /// such as Android onDestroy lifecycle events. static void dispose() { - try { - //Save the screen rendering data for the active traces Auto|Custom. - InstabugScreenRenderManager.I.stopScreenRenderCollector(); + //Save the screen rendering data for the active traces Auto|Custom. + InstabugScreenRenderManager.I.stopScreenRenderCollector(); - // Always call dispose to ensure proper cleanup with tracking flags - // The dispose method is safe to call multiple times due to state tracking - InstabugScreenRenderManager.I.dispose(); - - InstabugLogger.I - .d('Screen render resources disposed successfully', tag: tag); - } catch (error, stackTrace) { - InstabugLogger.I.e( - 'Error during screen render disposal: $error\nStackTrace: $stackTrace', - tag: tag, - ); - } + // The dispose method is safe to call multiple times due to state tracking + InstabugScreenRenderManager.I.dispose(); } void _handleResumedState() { @@ -72,18 +61,27 @@ class InstabugWidgetsBindingObserver extends WidgetsBindingObserver { }); } - // void _handlePausedState() { - // if (InstabugScreenRenderManager.I.screenRenderEnabled) { - // InstabugScreenRenderManager.I.stopScreenRenderCollector(); - // } - // } - // - // Future _handleDetachedState() async { - // if (InstabugScreenRenderManager.I.screenRenderEnabled) { - // dispose(); - // } - // } - // + void _handlePausedState() { + // Only handles iOS platform because in android we use pigeon @FlutterApi(). + // To overcome the onActivityDestroy() before sending the data to the android side. + if (InstabugScreenRenderManager.I.screenRenderEnabled && + IBGBuildInfo.I.isIOS) { + log("_handlePausedState" , name: "andrew"); + InstabugScreenRenderManager.I.stopScreenRenderCollector(); + } + } + + Future _handleDetachedState() async { + // Only handles iOS platform because in android we use pigeon @FlutterApi(). + // To overcome the onActivityDestroy() before sending the data to the android side. + if (InstabugScreenRenderManager.I.screenRenderEnabled && + IBGBuildInfo.I.isIOS) { + log("_handleDetachedState" , name: "andrew"); + + dispose(); + } + } + void _handleDefaultState() { // Added for lint warnings } @@ -94,9 +92,12 @@ class InstabugWidgetsBindingObserver extends WidgetsBindingObserver { case AppLifecycleState.resumed: _handleResumedState(); break; - // case AppLifecycleState.paused: - // _handlePausedState(); - // break; + case AppLifecycleState.paused: + _handlePausedState(); + break; + case AppLifecycleState.detached: + _handleDetachedState(); + break; default: _handleDefaultState(); } diff --git a/test/utils/screen_render/instabug_widget_binding_observer_test.dart b/test/utils/screen_render/instabug_widget_binding_observer_test.dart index 77e0198d4..ebaff9b62 100644 --- a/test/utils/screen_render/instabug_widget_binding_observer_test.dart +++ b/test/utils/screen_render/instabug_widget_binding_observer_test.dart @@ -1,5 +1,6 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:instabug_flutter/src/generated/apm.api.g.dart'; import 'package:instabug_flutter/src/utils/screen_loading/screen_loading_manager.dart'; import 'package:instabug_flutter/src/utils/screen_name_masker.dart'; import 'package:instabug_flutter/src/utils/screen_rendering/instabug_screen_render_manager.dart'; @@ -15,6 +16,7 @@ import 'instabug_widget_binding_observer_test.mocks.dart'; ScreenLoadingManager, ScreenNameMasker, UiTrace, + ApmHostApi, ]) void main() { late MockInstabugScreenRenderManager mockRenderManager; @@ -51,7 +53,7 @@ void main() { when(mockLoadingManager.startUiTrace("MaskedHome", "HomeScreen")) .thenAnswer((_) async => 123); when(mockRenderManager.screenRenderEnabled).thenReturn(true); - + // when() InstabugWidgetsBindingObserver.I .didChangeAppLifecycleState(AppLifecycleState.resumed); @@ -64,25 +66,6 @@ void main() { .called(1); }); - test('handles AppLifecycleState.paused and stops render collector', () { - when(mockRenderManager.screenRenderEnabled).thenReturn(true); - - InstabugWidgetsBindingObserver.I - .didChangeAppLifecycleState(AppLifecycleState.paused); - - verify(mockRenderManager.stopScreenRenderCollector()).called(1); - }); - - test('handles AppLifecycleState.detached and disposes render resources', - () { - when(mockRenderManager.screenRenderEnabled).thenReturn(true); - - InstabugWidgetsBindingObserver.I - .didChangeAppLifecycleState(AppLifecycleState.detached); - - verify(mockRenderManager.dispose()).called(1); - }); - test('handles AppLifecycleState.inactive with no action', () { // Just ensure it doesn't crash expect( From 565bdb2c31cf4694df8be6e5405f35572ba3e59c Mon Sep 17 00:00:00 2001 From: Andrew Amin Date: Wed, 20 Aug 2025 16:41:16 +0300 Subject: [PATCH 80/84] update iOS pods --- example/ios/Podfile | 2 +- example/ios/Podfile.lock | 14 +++++++------- ios/instabug_flutter.podspec | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/example/ios/Podfile b/example/ios/Podfile index 1768d6c13..410f49b97 100644 --- a/example/ios/Podfile +++ b/example/ios/Podfile @@ -30,7 +30,7 @@ target 'Runner' do use_frameworks! use_modular_headers! - pod 'Instabug', :podspec => 'https://ios-releases.instabug.com/custom/faeture-screen_rendering-release/15.1.31/Instabug.podspec' + pod 'Instabug', :podspec => 'https://ios-releases.instabug.com/custom/faeture-screen_rendering-release/15.1.32/Instabug.podspec' flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) end diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index 648043285..14c2a7b68 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -1,14 +1,14 @@ PODS: - Flutter (1.0.0) - - Instabug (15.1.31) + - Instabug (15.1.32) - instabug_flutter (14.3.0): - Flutter - - Instabug (= 15.1.31) + - Instabug (= 15.1.32) - OCMock (3.6) DEPENDENCIES: - Flutter (from `Flutter`) - - Instabug (from `https://ios-releases.instabug.com/custom/faeture-screen_rendering-release/15.1.31/Instabug.podspec`) + - Instabug (from `https://ios-releases.instabug.com/custom/faeture-screen_rendering-release/15.1.32/Instabug.podspec`) - instabug_flutter (from `.symlinks/plugins/instabug_flutter/ios`) - OCMock (= 3.6) @@ -20,16 +20,16 @@ EXTERNAL SOURCES: Flutter: :path: Flutter Instabug: - :podspec: https://ios-releases.instabug.com/custom/faeture-screen_rendering-release/15.1.31/Instabug.podspec + :podspec: https://ios-releases.instabug.com/custom/faeture-screen_rendering-release/15.1.32/Instabug.podspec instabug_flutter: :path: ".symlinks/plugins/instabug_flutter/ios" SPEC CHECKSUMS: Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 - Instabug: 447d3f5a9f1c83120235437e08c9a51aaa8f8605 - instabug_flutter: 65aa2dee3036a3c7c8feff8e898c9547239a891d + Instabug: ee379b2694fa1dd3951526e5a34782bac886102e + instabug_flutter: 33230b1cc57be3b343b4d30f6dfdd03f9bf43599 OCMock: 5ea90566be239f179ba766fd9fbae5885040b992 -PODFILE CHECKSUM: c5b98f57c27da87950775c360d20aaedd3216b8d +PODFILE CHECKSUM: 41b206566c390a4111f60619beb4e420eba98359 COCOAPODS: 1.15.2 diff --git a/ios/instabug_flutter.podspec b/ios/instabug_flutter.podspec index f216fdaf0..2cf55fcdd 100644 --- a/ios/instabug_flutter.podspec +++ b/ios/instabug_flutter.podspec @@ -17,6 +17,6 @@ Pod::Spec.new do |s| s.pod_target_xcconfig = { 'OTHER_LDFLAGS' => '-framework "Flutter" -framework "InstabugSDK"'} s.dependency 'Flutter' - s.dependency 'Instabug', '15.1.31' + s.dependency 'Instabug', '15.1.32' end From ff28d2371f56f8492466a6c1d781d63eaa197994 Mon Sep 17 00:00:00 2001 From: Andrew Amin Date: Wed, 20 Aug 2025 17:13:22 +0300 Subject: [PATCH 81/84] resolve conflicts and remove logs --- lib/src/modules/apm.dart | 2 -- .../instabug_screen_render_manager.dart | 4 ---- .../instabug_widget_binding_observer.dart | 5 ----- test/instabug_test.dart | 15 +++++++++------ ...instabug_widget_binding_observer_test.dart | 19 ++++++++++++++++++- 5 files changed, 27 insertions(+), 18 deletions(-) diff --git a/lib/src/modules/apm.dart b/lib/src/modules/apm.dart index 1ce12d413..3d28a0379 100644 --- a/lib/src/modules/apm.dart +++ b/lib/src/modules/apm.dart @@ -1,7 +1,6 @@ // ignore_for_file: avoid_classes_with_only_static_members import 'dart:async'; -import 'dart:developer'; import 'package:flutter/widgets.dart' show WidgetBuilder; import 'package:instabug_flutter/src/generated/apm.api.g.dart'; @@ -141,7 +140,6 @@ class APM { static Future startUITrace(String name) async { final isScreenRenderingEnabled = await FlagsConfig.screenRendering.isEnabled(); - log("startUITrace: isScreenRenderEnabled: $isScreenRenderingEnabled"); await InstabugScreenRenderManager.I .checkForScreenRenderInitialization(isScreenRenderingEnabled); diff --git a/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart b/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart index 4b122103f..4beb720af 100644 --- a/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart +++ b/lib/src/utils/screen_rendering/instabug_screen_render_manager.dart @@ -58,7 +58,6 @@ class InstabugScreenRenderManager { @internal Future init(WidgetsBinding? widgetBinding) async { try { - log("init" , name: tag); // passing WidgetsBinding? (nullable) for flutter versions prior than 3.x if (!screenRenderEnabled && widgetBinding != null) { _widgetsBinding = widgetBinding; @@ -122,7 +121,6 @@ class InstabugScreenRenderManager { int traceId, [ UiTraceType type = UiTraceType.auto, ]) { - log("startScreenRenderCollectorForTraceId" , name: tag); // Return if frameTimingListener not attached if (_frameCollectorIsNotActive) return; @@ -139,7 +137,6 @@ class InstabugScreenRenderManager { void endScreenRenderCollector([ UiTraceType type = UiTraceType.auto, ]) { - log("endScreenRenderCollector" , name: tag); // Return if frameTimingListener not attached if (_frameCollectorIsNotActive) return; @@ -205,7 +202,6 @@ class InstabugScreenRenderManager { @internal void dispose() { try { - log("dispose" , name: tag); _resetCachedFrameData(); _removeFrameTimings(); _removeWidgetBindingObserver(); diff --git a/lib/src/utils/screen_rendering/instabug_widget_binding_observer.dart b/lib/src/utils/screen_rendering/instabug_widget_binding_observer.dart index 01b1968b3..a085cf011 100644 --- a/lib/src/utils/screen_rendering/instabug_widget_binding_observer.dart +++ b/lib/src/utils/screen_rendering/instabug_widget_binding_observer.dart @@ -1,5 +1,3 @@ -import 'dart:developer'; - import 'package:flutter/widgets.dart'; import 'package:instabug_flutter/src/utils/ibg_build_info.dart'; import 'package:instabug_flutter/src/utils/screen_loading/screen_loading_manager.dart'; @@ -66,7 +64,6 @@ class InstabugWidgetsBindingObserver extends WidgetsBindingObserver { // To overcome the onActivityDestroy() before sending the data to the android side. if (InstabugScreenRenderManager.I.screenRenderEnabled && IBGBuildInfo.I.isIOS) { - log("_handlePausedState" , name: "andrew"); InstabugScreenRenderManager.I.stopScreenRenderCollector(); } } @@ -76,8 +73,6 @@ class InstabugWidgetsBindingObserver extends WidgetsBindingObserver { // To overcome the onActivityDestroy() before sending the data to the android side. if (InstabugScreenRenderManager.I.screenRenderEnabled && IBGBuildInfo.I.isIOS) { - log("_handleDetachedState" , name: "andrew"); - dispose(); } } diff --git a/test/instabug_test.dart b/test/instabug_test.dart index 29dc5889f..5e5041a3c 100644 --- a/test/instabug_test.dart +++ b/test/instabug_test.dart @@ -479,12 +479,15 @@ void main() { () { // Test that the FlutterApi setup and dispose functionality works // This verifies that when Android calls dispose(), it properly cleans up resources - expect(() { - // Get the InstabugFlutterApi setup that was configured in Instabug.$setup() - // The actual dispose call will be tested in integration tests - // Here we just verify the setup doesn't crash - Instabug.$setup(); - }, returnsNormally); + expect( + () { + // Get the InstabugFlutterApi setup that was configured in Instabug.$setup() + // The actual dispose call will be tested in integration tests + // Here we just verify the setup doesn't crash + Instabug.$setup(); + }, + returnsNormally, + ); }); }); } diff --git a/test/utils/screen_render/instabug_widget_binding_observer_test.dart b/test/utils/screen_render/instabug_widget_binding_observer_test.dart index d3117c7ca..e11852ac2 100644 --- a/test/utils/screen_render/instabug_widget_binding_observer_test.dart +++ b/test/utils/screen_render/instabug_widget_binding_observer_test.dart @@ -1,5 +1,8 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:instabug_flutter/instabug_flutter.dart' show APM; +import 'package:instabug_flutter/src/generated/apm.api.g.dart'; +import 'package:instabug_flutter/src/utils/ibg_build_info.dart'; import 'package:instabug_flutter/src/utils/screen_loading/screen_loading_manager.dart'; import 'package:instabug_flutter/src/utils/screen_name_masker.dart'; import 'package:instabug_flutter/src/utils/screen_rendering/instabug_screen_render_manager.dart'; @@ -15,6 +18,8 @@ import 'instabug_widget_binding_observer_test.mocks.dart'; ScreenLoadingManager, ScreenNameMasker, UiTrace, + ApmHostApi, + IBGBuildInfo, ]) void main() { late MockInstabugScreenRenderManager mockRenderManager; @@ -37,6 +42,13 @@ void main() { }); group('InstabugWidgetsBindingObserver', () { + final mApmHost = MockApmHostApi(); + final mIBGBuildInfo = MockIBGBuildInfo(); + setUp(() { + APM.$setHostApi(mApmHost); + IBGBuildInfo.setInstance(mIBGBuildInfo); + }); + test('returns the singleton instance', () { final instance = InstabugWidgetsBindingObserver.instance; final shorthand = InstabugWidgetsBindingObserver.I; @@ -52,6 +64,8 @@ void main() { .thenAnswer((_) async => 123); when(mockRenderManager.screenRenderEnabled).thenReturn(true); + when(mApmHost.isScreenRenderEnabled()).thenAnswer((_) async => true); + InstabugWidgetsBindingObserver.I .didChangeAppLifecycleState(AppLifecycleState.resumed); @@ -64,8 +78,11 @@ void main() { .called(1); }); - test('handles AppLifecycleState.paused and stops render collector', () { + test( + 'handles AppLifecycleState.paused and stops render collector for iOS platform', + () { when(mockRenderManager.screenRenderEnabled).thenReturn(true); + when(mIBGBuildInfo.isIOS).thenReturn(true); InstabugWidgetsBindingObserver.I .didChangeAppLifecycleState(AppLifecycleState.paused); From 7b6f48b6d0d7f34cceac9975bbe3da69eeb3ed16 Mon Sep 17 00:00:00 2001 From: Andrew Amin Date: Wed, 20 Aug 2025 21:49:03 +0300 Subject: [PATCH 82/84] remove static testing log --- .../main/java/com/instabug/flutter/InstabugFlutterPlugin.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/src/main/java/com/instabug/flutter/InstabugFlutterPlugin.java b/android/src/main/java/com/instabug/flutter/InstabugFlutterPlugin.java index d399fb834..2488e8147 100644 --- a/android/src/main/java/com/instabug/flutter/InstabugFlutterPlugin.java +++ b/android/src/main/java/com/instabug/flutter/InstabugFlutterPlugin.java @@ -36,7 +36,7 @@ import io.flutter.plugin.common.BinaryMessenger; public class InstabugFlutterPlugin implements FlutterPlugin, ActivityAware, LifecycleEventObserver { - private static final String TAG = "Andrew"; + private static final String TAG = InstabugFlutterPlugin.class.getName(); @SuppressLint("StaticFieldLeak") private static Activity activity; From 19226b148627a6abf8e77924eaa970d803f5b2ed Mon Sep 17 00:00:00 2001 From: Andrew Amin Date: Thu, 21 Aug 2025 11:29:37 +0300 Subject: [PATCH 83/84] update android snapshot --- android/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/build.gradle b/android/build.gradle index 92b3a865e..4c0f175d1 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -52,7 +52,7 @@ android { } dependencies { - api 'com.instabug.library:instabug:15.0.2.7160278-SNAPSHOT' + api 'com.instabug.library:instabug:16.0.0.6893269-SNAPSHOT' testImplementation 'junit:junit:4.13.2' testImplementation "org.mockito:mockito-inline:3.12.1" testImplementation "io.mockk:mockk:1.13.13" From 89c5dcf3e0a51a7996f3311be1d1cd07e3dbe81a Mon Sep 17 00:00:00 2001 From: Andrew Amin Date: Thu, 21 Aug 2025 13:17:41 +0300 Subject: [PATCH 84/84] update android snapshot --- android/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/build.gradle b/android/build.gradle index 4c0f175d1..e569ea981 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -52,7 +52,7 @@ android { } dependencies { - api 'com.instabug.library:instabug:16.0.0.6893269-SNAPSHOT' + api 'com.instabug.library:instabug:16.0.0.6893868-SNAPSHOT' testImplementation 'junit:junit:4.13.2' testImplementation "org.mockito:mockito-inline:3.12.1" testImplementation "io.mockk:mockk:1.13.13"