ente/lib/services/machine_learning/machine_learning_controller.dart
2024-02-19 16:03:38 +05:30

98 lines
3 KiB
Dart

import "dart:async";
import "dart:io";
import "package:battery_info/battery_info_plugin.dart";
import "package:battery_info/model/android_battery_info.dart";
import "package:logging/logging.dart";
import "package:photos/core/event_bus.dart";
import "package:photos/events/machine_learning_control_event.dart";
class MachineLearningController {
MachineLearningController._privateConstructor();
static final MachineLearningController instance =
MachineLearningController._privateConstructor();
final _logger = Logger("MachineLearningController");
static const kMaximumTemperature = 42; // 42 degree celsius
static const kMinimumBatteryLevel = 20; // 20%
static const kInitialInteractionTimeout = Duration(seconds: 10);
static const kDefaultInteractionTimeout = Duration(seconds: 5);
static const kUnhealthyStates = ["over_heat", "over_voltage", "dead"];
bool _isDeviceHealthy = true;
bool _isUserInteracting = true;
bool _isRunningML = false;
late Timer _userInteractionTimer;
void init() {
if (Platform.isAndroid) {
_startInteractionTimer(timeout: kInitialInteractionTimeout);
BatteryInfoPlugin()
.androidBatteryInfoStream
.listen((AndroidBatteryInfo? batteryInfo) {
_onBatteryStateUpdate(batteryInfo);
});
} else {
// Always run Machine Learning on iOS
Bus.instance.fire(MachineLearningControlEvent(true));
}
}
void onUserInteraction() {
_logger.info("User is interacting with the app");
_isUserInteracting = true;
_fireControlEvent();
_resetTimer();
}
void _fireControlEvent() {
final shouldRunML = _isDeviceHealthy && !_isUserInteracting;
if (shouldRunML != _isRunningML) {
_isRunningML = shouldRunML;
_logger.info(
"Firing event with device health: $_isDeviceHealthy and user interaction: $_isUserInteracting",
);
Bus.instance.fire(MachineLearningControlEvent(shouldRunML));
}
}
void _startInteractionTimer({Duration timeout = kDefaultInteractionTimeout}) {
_userInteractionTimer = Timer(timeout, () {
_logger.info("User is not interacting with the app");
_isUserInteracting = false;
_fireControlEvent();
});
}
void _resetTimer() {
_userInteractionTimer.cancel();
_startInteractionTimer();
}
void _onBatteryStateUpdate(AndroidBatteryInfo? batteryInfo) {
_logger.info("Battery info: ${batteryInfo!.toJson()}");
_isDeviceHealthy = _computeIsDeviceHealthy(batteryInfo);
_fireControlEvent();
}
bool _computeIsDeviceHealthy(AndroidBatteryInfo info) {
return _hasSufficientBattery(info.batteryLevel ?? kMinimumBatteryLevel) &&
_isAcceptableTemperature(info.temperature ?? kMaximumTemperature) &&
_isBatteryHealthy(info.health ?? "");
}
bool _hasSufficientBattery(int batteryLevel) {
return batteryLevel >= kMinimumBatteryLevel;
}
bool _isAcceptableTemperature(int temperature) {
return temperature <= kMaximumTemperature;
}
bool _isBatteryHealthy(String health) {
return !kUnhealthyStates.contains(health);
}
}