system_controller_test.dart 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. import 'package:cardash_launcher/data/models/app_entry.dart';
  2. import 'package:cardash_launcher/data/models/media_playback.dart';
  3. import 'package:cardash_launcher/data/models/update_info.dart';
  4. import 'package:cardash_launcher/data/models/system_status.dart';
  5. import 'package:cardash_launcher/data/services/native_bridge.dart';
  6. import 'package:cardash_launcher/features/home/system_controller.dart';
  7. import 'package:flutter_test/flutter_test.dart';
  8. class _MediaPlatform implements LauncherPlatform {
  9. bool playing = false;
  10. bool applyWrites = false;
  11. MediaPlayback media = const MediaPlayback();
  12. VolumeInfo volume = const VolumeInfo(index: 8, max: 15);
  13. final List<String> keys = [];
  14. final List<int> volumeWrites = [];
  15. @override
  16. Future<List<AppEntry>> listApps() async => const [];
  17. @override
  18. Future<void> launchApp({
  19. required String packageName,
  20. required String activityName,
  21. }) async {}
  22. @override
  23. Future<bool> isDefaultHome() async => true;
  24. @override
  25. Future<bool> requestDefaultHome() async => true;
  26. @override
  27. Future<SystemStatus> getStatus() async => const SystemStatus();
  28. @override
  29. Future<VolumeInfo> getVolume() async => volume;
  30. @override
  31. Future<void> setVolume(int index) async {
  32. volumeWrites.add(index);
  33. if (applyWrites) {
  34. volume = volume.copyWith(index: index);
  35. }
  36. }
  37. @override
  38. Future<bool> isMusicPlaying() async => playing;
  39. @override
  40. Future<bool> sendMediaKey(String action) async {
  41. keys.add(action);
  42. if (action == 'play') playing = true;
  43. if (action == 'pause') playing = false;
  44. return true;
  45. }
  46. @override
  47. Future<MediaPlayback> getMediaState() async => media;
  48. @override
  49. Future<bool> openNotificationAccessSettings() async => true;
  50. @override
  51. Future<void> setKeepScreenOn(bool enabled) async {}
  52. @override
  53. Future<bool> openUrl(String url) async => true;
  54. @override
  55. Future<UpdateInstallResult> downloadAndInstallUpdate(String url) async {
  56. return const UpdateInstallResult(
  57. started: false,
  58. permissionRequired: false,
  59. message: 'not started',
  60. );
  61. }
  62. }
  63. void main() {
  64. test('pause sends the pause key and clears playing state', () async {
  65. final platform = _MediaPlatform()..playing = true;
  66. final controller = SystemController(platform);
  67. await controller.start();
  68. addTearDown(controller.dispose);
  69. expect(controller.isMusicPlaying, isTrue);
  70. await controller.pauseMusic();
  71. expect(platform.keys, contains('pause'));
  72. expect(controller.isMusicPlaying, isFalse);
  73. controller.stop();
  74. });
  75. test('media state supplies the title, progress and playing flag', () async {
  76. final platform = _MediaPlatform()
  77. ..media = const MediaPlayback(
  78. hasAccess: true,
  79. hasSession: true,
  80. playing: true,
  81. title: 'Night Drive',
  82. artist: 'The Dashboard',
  83. durationMs: 240000,
  84. positionMs: 60000,
  85. );
  86. final controller = SystemController(platform);
  87. await controller.start();
  88. addTearDown(controller.dispose);
  89. expect(controller.hasMediaAccess, isTrue);
  90. expect(controller.media.displayTitle, 'Night Drive — The Dashboard');
  91. expect(controller.media.progress, 0.25);
  92. expect(controller.isMusicPlaying, isTrue);
  93. controller.stop();
  94. });
  95. test('play resumes and reports whether audio started', () async {
  96. final platform = _MediaPlatform();
  97. final controller = SystemController(platform);
  98. await controller.start();
  99. addTearDown(controller.dispose);
  100. expect(controller.isMusicPlaying, isFalse);
  101. expect(await controller.playMusic(), isTrue);
  102. expect(platform.keys, contains('play'));
  103. expect(controller.isMusicPlaying, isTrue);
  104. controller.stop();
  105. });
  106. test('fixed car volume ignores software volume changes', () async {
  107. final platform = _MediaPlatform()
  108. ..volume = const VolumeInfo(index: 100, max: 100, fixed: true);
  109. final controller = SystemController(platform);
  110. await controller.start();
  111. addTearDown(controller.dispose);
  112. expect(controller.isVolumeFixed, isTrue);
  113. await controller.setVolume(25);
  114. await controller.toggleMute();
  115. expect(platform.volumeWrites, isEmpty);
  116. expect(controller.volume.index, 100);
  117. controller.stop();
  118. });
  119. test('a rejected volume write keeps the requested level', () async {
  120. final platform = _MediaPlatform()
  121. ..volume = const VolumeInfo(
  122. index: 100,
  123. max: 100,
  124. streams: {'music': 100, 'system': 8},
  125. );
  126. final controller = SystemController(platform);
  127. await controller.start();
  128. addTearDown(controller.dispose);
  129. await controller.setVolume(25);
  130. expect(platform.volumeWrites, contains(25));
  131. expect(controller.volume.index, 25);
  132. expect(controller.volumeUnconfirmed, isFalse);
  133. controller.toggleVolumeDiagnostics();
  134. expect(controller.volumeDiagnostics, contains('25 -> 100'));
  135. expect(controller.volumeDiagnostics, contains('music 100'));
  136. controller.toggleVolumeDiagnostics();
  137. expect(controller.volumeDiagnostics, isNull);
  138. controller.stop();
  139. });
  140. test('a confirmed volume write adopts the car level', () async {
  141. final platform = _MediaPlatform()
  142. ..applyWrites = true
  143. ..volume = const VolumeInfo(index: 8, max: 15);
  144. final controller = SystemController(platform);
  145. await controller.start();
  146. addTearDown(controller.dispose);
  147. await controller.setVolume(3);
  148. expect(platform.volumeWrites, contains(3));
  149. expect(controller.volume.index, 3);
  150. expect(controller.volumeUnconfirmed, isFalse);
  151. controller.stop();
  152. });
  153. }