|
@@ -1,7 +1,7 @@
|
|
|
|
+import "dart:async";
|
|
import "dart:io";
|
|
import "dart:io";
|
|
|
|
|
|
import "package:battery_info/battery_info_plugin.dart";
|
|
import "package:battery_info/battery_info_plugin.dart";
|
|
-import "package:battery_info/enums/charging_status.dart";
|
|
|
|
import "package:battery_info/model/android_battery_info.dart";
|
|
import "package:battery_info/model/android_battery_info.dart";
|
|
import "package:logging/logging.dart";
|
|
import "package:logging/logging.dart";
|
|
import "package:photos/core/event_bus.dart";
|
|
import "package:photos/core/event_bus.dart";
|
|
@@ -17,35 +17,70 @@ class MachineLearningController {
|
|
|
|
|
|
static const kMaximumTemperature = 36; // 36 degree celsius
|
|
static const kMaximumTemperature = 36; // 36 degree celsius
|
|
static const kMinimumBatteryLevel = 20; // 20%
|
|
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() {
|
|
void init() {
|
|
if (Platform.isAndroid) {
|
|
if (Platform.isAndroid) {
|
|
|
|
+ _startInteractionTimer(timeout: kInitialInteractionTimeout);
|
|
BatteryInfoPlugin()
|
|
BatteryInfoPlugin()
|
|
.androidBatteryInfoStream
|
|
.androidBatteryInfoStream
|
|
.listen((AndroidBatteryInfo? batteryInfo) {
|
|
.listen((AndroidBatteryInfo? batteryInfo) {
|
|
- _logger.info("Battery info: ${batteryInfo!.toJson()}");
|
|
|
|
- if (_shouldRunMachineLearning(batteryInfo)) {
|
|
|
|
- Bus.instance.fire(MachineLearningControlEvent(true));
|
|
|
|
- } else {
|
|
|
|
- Bus.instance.fire(MachineLearningControlEvent(false));
|
|
|
|
- }
|
|
|
|
|
|
+ _onBatteryStateUpdate(batteryInfo);
|
|
});
|
|
});
|
|
|
|
+ } else {
|
|
|
|
+ // Always run Machine Learning on iOS
|
|
|
|
+ Bus.instance.fire(MachineLearningControlEvent(true));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- void onUserInteractionEvent(bool isUserInteracting) {
|
|
|
|
- Bus.instance.fire(MachineLearningControlEvent(!isUserInteracting));
|
|
|
|
|
|
+ void onUserInteraction() {
|
|
|
|
+ _logger.info("User is interacting with the app");
|
|
|
|
+ _isUserInteracting = true;
|
|
|
|
+ _fireControlEvent();
|
|
|
|
+ _resetTimer();
|
|
}
|
|
}
|
|
|
|
|
|
- bool _shouldRunMachineLearning(AndroidBatteryInfo info) {
|
|
|
|
- if (info.chargingStatus == ChargingStatus.Charging ||
|
|
|
|
- info.chargingStatus == ChargingStatus.Full) {
|
|
|
|
- return _isAcceptableTemperature(
|
|
|
|
- info.temperature ?? kMaximumTemperature,
|
|
|
|
|
|
+ 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) &&
|
|
return _hasSufficientBattery(info.batteryLevel ?? kMinimumBatteryLevel) &&
|
|
- _isAcceptableTemperature(info.temperature ?? kMaximumTemperature);
|
|
|
|
|
|
+ _isAcceptableTemperature(info.temperature ?? kMaximumTemperature) &&
|
|
|
|
+ _isBatteryHealthy(info.health ?? "");
|
|
}
|
|
}
|
|
|
|
|
|
bool _hasSufficientBattery(int batteryLevel) {
|
|
bool _hasSufficientBattery(int batteryLevel) {
|
|
@@ -55,4 +90,8 @@ class MachineLearningController {
|
|
bool _isAcceptableTemperature(int temperature) {
|
|
bool _isAcceptableTemperature(int temperature) {
|
|
return temperature <= kMaximumTemperature;
|
|
return temperature <= kMaximumTemperature;
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ bool _isBatteryHealthy(String health) {
|
|
|
|
+ return !kUnhealthyStates.contains(health);
|
|
|
|
+ }
|
|
}
|
|
}
|