pedometer.dart 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. import 'dart:async';
  2. import 'package:flutter/services.dart';
  3. import 'dart:io' show Platform;
  4. const int _stopped = 0, _walking = 1;
  5. class Pedometer {
  6. static const EventChannel _stepDetectionChannel =
  7. const EventChannel('step_detection');
  8. static const EventChannel _stepCountChannel =
  9. const EventChannel('step_count');
  10. static StreamController<PedestrianStatus> _androidPedestrianController =
  11. StreamController.broadcast();
  12. /// Returns one step at a time.
  13. /// Events come every time a step is detected.
  14. static Stream<PedestrianStatus> get pedestrianStatusStream {
  15. Stream<PedestrianStatus> stream = _stepDetectionChannel
  16. .receiveBroadcastStream()
  17. .map((event) => PedestrianStatus._(event));
  18. if (Platform.isAndroid) return _androidStream(stream);
  19. return stream;
  20. }
  21. /// Transformed stream for the Android platform
  22. static Stream<PedestrianStatus> _androidStream(
  23. Stream<PedestrianStatus> stream) {
  24. /// Init a timer and a status
  25. Timer t;
  26. int pedestrianStatus;
  27. /// Listen for events on the original stream
  28. /// Transform these events by using the timer
  29. stream.listen((dynamic e) {
  30. /// If an event is received it means the status is 'walking'
  31. /// If the timer has been started, it should be cancelled
  32. /// to prevent sending out additional 'walking' events
  33. if (t != null) {
  34. t.cancel();
  35. /// If a previous status was either not set yet, or was 'stopped'
  36. /// then a 'walking' event should be emitted.
  37. if (pedestrianStatus == null || pedestrianStatus == _stopped) {
  38. _androidPedestrianController.add(PedestrianStatus._(_walking));
  39. pedestrianStatus = _walking;
  40. }
  41. }
  42. /// After receiving an event, start a timer for 2 seconds, after
  43. /// which a 'stopped' event is emitted. If it manages to go through,
  44. /// it is because no events were received for the 2 second duration
  45. t = Timer(Duration(seconds: 2), () {
  46. _androidPedestrianController.add(PedestrianStatus._(_stopped));
  47. pedestrianStatus = _stopped;
  48. });
  49. });
  50. return _androidPedestrianController.stream;
  51. }
  52. /// Returns the steps taken since last system boot.
  53. /// Events may come with a delay.
  54. static Stream<StepCount> get stepCountStream => _stepCountChannel
  55. .receiveBroadcastStream()
  56. .map((event) => StepCount._(event));
  57. static Stream<int> get stepDetectionStream => _stepDetectionChannel
  58. .receiveBroadcastStream()
  59. .map((event) => event as int);
  60. }
  61. /// A DTO for steps taken containing the number of steps taken.
  62. class StepCount {
  63. DateTime _timeStamp;
  64. int _steps = 0;
  65. StepCount._(dynamic e) {
  66. _steps = e as int;
  67. _timeStamp = DateTime.now();
  68. }
  69. int get steps => _steps;
  70. DateTime get timeStamp => _timeStamp;
  71. @override
  72. String toString() =>
  73. 'Steps taken: $_steps at ${_timeStamp.toIso8601String()}';
  74. }
  75. /// A DTO for steps taken containing a detected step and its corresponding
  76. /// status, i.e. walking, stopped or unknown.
  77. class PedestrianStatus {
  78. static const _WALKING = 'walking';
  79. static const _STOPPED = 'stopped';
  80. static const _UNKNOWN = 'unknown';
  81. static const Map<int, String> _STATUSES = {
  82. _stopped: _STOPPED,
  83. _walking: _WALKING
  84. };
  85. DateTime _timeStamp;
  86. String _status = _UNKNOWN;
  87. PedestrianStatus._(dynamic t) {
  88. int _type = t as int;
  89. _status = _STATUSES[_type];
  90. _timeStamp = DateTime.now();
  91. }
  92. String get status => _status;
  93. DateTime get timeStamp => _timeStamp;
  94. @override
  95. String toString() => 'Status: $_status at ${_timeStamp.toIso8601String()}';
  96. }