Unverified Commit 6e252772 authored by Todd Volkert's avatar Todd Volkert Committed by GitHub

Add support for system alert sound (#62086)

* Add SystemSoundType.alert (supported in the engine in flutter/engine#19970)
* Play system alert sound when user tries to dismiss a non-dismissable modal
  barrier
parent 7782845e
...@@ -9,9 +9,19 @@ import 'dart:async'; ...@@ -9,9 +9,19 @@ import 'dart:async';
import 'system_channels.dart'; import 'system_channels.dart';
/// A sound provided by the system. /// A sound provided by the system.
///
/// These sounds may be played with [SystemSound.play].
enum SystemSoundType { enum SystemSoundType {
/// A short indication that a button was pressed. /// A short indication that a button was pressed.
click, click,
/// A short system alert sound indicating the need for user attention.
///
/// Desktop platforms are the only platforms that support a system alert
/// sound, so on mobile platforms (Android, iOS), this will be ignored. The
/// web platform does not support playing any sounds, so this will be
/// ignored on the web as well.
alert,
} }
/// Provides access to the library of short system specific sounds for common /// Provides access to the library of short system specific sounds for common
...@@ -24,6 +34,9 @@ class SystemSound { ...@@ -24,6 +34,9 @@ class SystemSound {
/// Play the specified system sound. If that sound is not present on the /// Play the specified system sound. If that sound is not present on the
/// system, the call is ignored. /// system, the call is ignored.
///
/// The web platform currently does not support playing sounds, so this call
/// will yield no behavior on that platform.
static Future<void> play(SystemSoundType type) async { static Future<void> play(SystemSoundType type) async {
await SystemChannels.platform.invokeMethod<void>( await SystemChannels.platform.invokeMethod<void>(
'SystemSound.play', 'SystemSound.play',
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart'; import 'package:flutter/gestures.dart';
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
import 'basic.dart'; import 'basic.dart';
import 'container.dart'; import 'container.dart';
...@@ -103,6 +104,8 @@ class ModalBarrier extends StatelessWidget { ...@@ -103,6 +104,8 @@ class ModalBarrier extends StatelessWidget {
onDismiss: () { onDismiss: () {
if (dismissible) if (dismissible)
Navigator.maybePop(context); Navigator.maybePop(context);
else
SystemSound.play(SystemSoundType.alert);
}, },
child: Semantics( child: Semantics(
label: semanticsDismissible ? semanticsLabel : null, label: semanticsDismissible ? semanticsLabel : null,
......
...@@ -8,6 +8,7 @@ import 'package:flutter_test/flutter_test.dart'; ...@@ -8,6 +8,7 @@ import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:flutter/gestures.dart' show kSecondaryButton, PointerDeviceKind; import 'package:flutter/gestures.dart' show kSecondaryButton, PointerDeviceKind;
...@@ -165,6 +166,32 @@ void main() { ...@@ -165,6 +166,32 @@ void main() {
hovered = false; hovered = false;
}); });
testWidgets('ModalBarrier plays system alert sound when user tries to dismiss it', (WidgetTester tester) async {
final List<String> playedSystemSounds = <String>[];
try {
SystemChannels.platform.setMockMethodCallHandler((MethodCall methodCall) async {
if (methodCall.method == 'SystemSound.play')
playedSystemSounds.add(methodCall.arguments as String);
});
final Widget subject = Stack(
textDirection: TextDirection.ltr,
children: <Widget>[
tapTarget,
const ModalBarrier(dismissible: false),
],
);
await tester.pumpWidget(subject);
await tester.tap(find.text('target'));
await tester.pumpWidget(subject);
} finally {
SystemChannels.platform.setMockMethodCallHandler(null);
}
expect(playedSystemSounds, hasLength(1));
expect(playedSystemSounds[0], SystemSoundType.alert.toString());
});
testWidgets('ModalBarrier pops the Navigator when dismissed by primary tap', (WidgetTester tester) async { testWidgets('ModalBarrier pops the Navigator when dismissed by primary tap', (WidgetTester tester) async {
final Map<String, WidgetBuilder> routes = <String, WidgetBuilder>{ final Map<String, WidgetBuilder> routes = <String, WidgetBuilder>{
'/': (BuildContext context) => const FirstWidget(), '/': (BuildContext context) => const FirstWidget(),
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment