machine_learning_controller.dart 3.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  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:logging/logging.dart";
  6. import "package:photos/core/event_bus.dart";
  7. import "package:photos/events/machine_learning_control_event.dart";
  8. class MachineLearningController {
  9. MachineLearningController._privateConstructor();
  10. static final MachineLearningController instance =
  11. MachineLearningController._privateConstructor();
  12. final _logger = Logger("MachineLearningController");
  13. static const kMaximumTemperature = 36; // 36 degree celsius
  14. static const kMinimumBatteryLevel = 20; // 20%
  15. static const kInitialInteractionTimeout = Duration(seconds: 10);
  16. static const kDefaultInteractionTimeout = Duration(seconds: 5);
  17. static const kUnhealthyStates = ["over_heat", "over_voltage", "dead"];
  18. bool _isDeviceHealthy = true;
  19. bool _isUserInteracting = true;
  20. bool _isRunningML = false;
  21. late Timer _userInteractionTimer;
  22. void init() {
  23. if (Platform.isAndroid) {
  24. _startInteractionTimer(timeout: kInitialInteractionTimeout);
  25. BatteryInfoPlugin()
  26. .androidBatteryInfoStream
  27. .listen((AndroidBatteryInfo? batteryInfo) {
  28. _onBatteryStateUpdate(batteryInfo);
  29. });
  30. } else {
  31. // Always run Machine Learning on iOS
  32. Bus.instance.fire(MachineLearningControlEvent(true));
  33. }
  34. }
  35. void onUserInteraction() {
  36. _logger.info("User is interacting with the app");
  37. _isUserInteracting = true;
  38. _fireControlEvent();
  39. _resetTimer();
  40. }
  41. void _fireControlEvent() {
  42. final shouldRunML = _isDeviceHealthy && !_isUserInteracting;
  43. if (shouldRunML != _isRunningML) {
  44. _isRunningML = shouldRunML;
  45. _logger.info(
  46. "Firing event with device health: $_isDeviceHealthy and user interaction: $_isUserInteracting",
  47. );
  48. Bus.instance.fire(MachineLearningControlEvent(shouldRunML));
  49. }
  50. }
  51. void _startInteractionTimer({Duration timeout = kDefaultInteractionTimeout}) {
  52. _userInteractionTimer = Timer(timeout, () {
  53. _logger.info("User is not interacting with the app");
  54. _isUserInteracting = false;
  55. _fireControlEvent();
  56. });
  57. }
  58. void _resetTimer() {
  59. _userInteractionTimer.cancel();
  60. _startInteractionTimer();
  61. }
  62. void _onBatteryStateUpdate(AndroidBatteryInfo? batteryInfo) {
  63. _logger.info("Battery info: ${batteryInfo!.toJson()}");
  64. _isDeviceHealthy = _computeIsDeviceHealthy(batteryInfo);
  65. _fireControlEvent();
  66. }
  67. bool _computeIsDeviceHealthy(AndroidBatteryInfo info) {
  68. return _hasSufficientBattery(info.batteryLevel ?? kMinimumBatteryLevel) &&
  69. _isAcceptableTemperature(info.temperature ?? kMaximumTemperature) &&
  70. _isBatteryHealthy(info.health ?? "");
  71. }
  72. bool _hasSufficientBattery(int batteryLevel) {
  73. return batteryLevel >= kMinimumBatteryLevel;
  74. }
  75. bool _isAcceptableTemperature(int temperature) {
  76. return temperature <= kMaximumTemperature;
  77. }
  78. bool _isBatteryHealthy(String health) {
  79. return !kUnhealthyStates.contains(health);
  80. }
  81. }