machine_learning_controller.dart 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. import "dart:async";
  2. import "dart:io";
  3. import "package:battery_info/battery_info_plugin.dart";
  4. import "package:battery_info/model/android_battery_info.dart";
  5. import "package:battery_info/model/iso_battery_info.dart";
  6. import "package:flutter/foundation.dart" show kDebugMode;
  7. import "package:logging/logging.dart";
  8. import "package:photos/core/event_bus.dart";
  9. import "package:photos/events/machine_learning_control_event.dart";
  10. class MachineLearningController {
  11. MachineLearningController._privateConstructor();
  12. static final MachineLearningController instance =
  13. MachineLearningController._privateConstructor();
  14. final _logger = Logger("MachineLearningController");
  15. static const kMaximumTemperature = 42; // 42 degree celsius
  16. static const kMinimumBatteryLevel = 20; // 20%
  17. static const kDefaultInteractionTimeout =
  18. kDebugMode ? Duration(seconds: 3) : Duration(seconds: 5);
  19. static const kUnhealthyStates = ["over_heat", "over_voltage", "dead"];
  20. bool _isDeviceHealthy = true;
  21. bool _isUserInteracting = true;
  22. bool _canRunML = false;
  23. late Timer _userInteractionTimer;
  24. bool get isDeviceHealthy => _isDeviceHealthy;
  25. void init() {
  26. if (Platform.isAndroid) {
  27. _startInteractionTimer();
  28. BatteryInfoPlugin()
  29. .androidBatteryInfoStream
  30. .listen((AndroidBatteryInfo? batteryInfo) {
  31. _onAndroidBatteryStateUpdate(batteryInfo);
  32. });
  33. }
  34. if (Platform.isIOS) {
  35. BatteryInfoPlugin()
  36. .iosBatteryInfoStream
  37. .listen((IosBatteryInfo? batteryInfo) {
  38. _oniOSBatteryStateUpdate(batteryInfo);
  39. });
  40. }
  41. _fireControlEvent();
  42. }
  43. void onUserInteraction() {
  44. if (Platform.isIOS) {
  45. return;
  46. }
  47. if (!_isUserInteracting) {
  48. _logger.info("User is interacting with the app");
  49. _isUserInteracting = true;
  50. _fireControlEvent();
  51. }
  52. _resetTimer();
  53. }
  54. void _fireControlEvent() {
  55. final shouldRunML =
  56. _isDeviceHealthy && (Platform.isAndroid ? !_isUserInteracting : true);
  57. if (shouldRunML != _canRunML) {
  58. _canRunML = shouldRunML;
  59. _logger.info(
  60. "Firing event with $shouldRunML, device health: $_isDeviceHealthy and user interaction: $_isUserInteracting",
  61. );
  62. Bus.instance.fire(MachineLearningControlEvent(shouldRunML));
  63. }
  64. }
  65. void _startInteractionTimer({Duration timeout = kDefaultInteractionTimeout}) {
  66. _userInteractionTimer = Timer(timeout, () {
  67. _logger.info("User is not interacting with the app");
  68. _isUserInteracting = false;
  69. _fireControlEvent();
  70. });
  71. }
  72. void _resetTimer() {
  73. _userInteractionTimer.cancel();
  74. _startInteractionTimer();
  75. }
  76. void _onAndroidBatteryStateUpdate(AndroidBatteryInfo? batteryInfo) {
  77. _logger.info("Battery info: ${batteryInfo!.toJson()}");
  78. _isDeviceHealthy = _computeIsAndroidDeviceHealthy(batteryInfo);
  79. _fireControlEvent();
  80. }
  81. void _oniOSBatteryStateUpdate(IosBatteryInfo? batteryInfo) {
  82. _logger.info("Battery info: ${batteryInfo!.toJson()}");
  83. _isDeviceHealthy = _computeIsiOSDeviceHealthy(batteryInfo);
  84. _fireControlEvent();
  85. }
  86. bool _computeIsAndroidDeviceHealthy(AndroidBatteryInfo info) {
  87. return _hasSufficientBattery(info.batteryLevel ?? kMinimumBatteryLevel) &&
  88. _isAcceptableTemperature(info.temperature ?? kMaximumTemperature) &&
  89. _isBatteryHealthy(info.health ?? "");
  90. }
  91. bool _computeIsiOSDeviceHealthy(IosBatteryInfo info) {
  92. return _hasSufficientBattery(info.batteryLevel ?? kMinimumBatteryLevel);
  93. }
  94. bool _hasSufficientBattery(int batteryLevel) {
  95. return batteryLevel >= kMinimumBatteryLevel;
  96. }
  97. bool _isAcceptableTemperature(int temperature) {
  98. return temperature <= kMaximumTemperature;
  99. }
  100. bool _isBatteryHealthy(String health) {
  101. return !kUnhealthyStates.contains(health);
  102. }
  103. }