Commit 870c3619 authored by Adam Barth's avatar Adam Barth

Add ergonomic wrappers for Flutter platform services (#3636)

These wrappers also give us a chance to document what these services do.

Fixes #3164
parent 5497ba18
......@@ -3,7 +3,7 @@
// found in the LICENSE file.
/// System services exposed to Flutter apps.
///
///
/// To use, import `package:flutter/services.dart`.
///
/// For example, this library includes [fetch], which fetches data from the
......@@ -18,8 +18,12 @@ export 'src/services/activity.dart';
export 'src/services/app_messages.dart';
export 'src/services/asset_bundle.dart';
export 'src/services/binding.dart';
export 'src/services/haptic_feedback.dart';
export 'src/services/image_cache.dart';
export 'src/services/image_decoder.dart';
export 'src/services/image_resource.dart';
export 'src/services/keyboard.dart';
export 'src/services/path_provider.dart';
export 'src/services/shell.dart';
export 'src/services/system_chrome.dart';
export 'src/services/system_sound.dart';
......@@ -66,14 +66,14 @@ class _DatePickerState extends State<DatePicker> {
_DatePickerMode _mode = _DatePickerMode.day;
void _handleModeChanged(_DatePickerMode mode) {
userFeedback.performHapticFeedback(HapticFeedbackType.virtualKey);
HapticFeedback.vibrate();
setState(() {
_mode = mode;
});
}
void _handleYearChanged(DateTime dateTime) {
userFeedback.performHapticFeedback(HapticFeedbackType.virtualKey);
HapticFeedback.vibrate();
setState(() {
_mode = _DatePickerMode.day;
});
......@@ -82,7 +82,7 @@ class _DatePickerState extends State<DatePicker> {
}
void _handleDayChanged(DateTime dateTime) {
userFeedback.performHapticFeedback(HapticFeedbackType.virtualKey);
HapticFeedback.vibrate();
if (config.onChanged != null)
config.onChanged(dateTime);
}
......
......@@ -4,7 +4,7 @@
import 'dart:math' as math;
import 'package:flutter/services.dart' show HapticFeedbackType, userFeedback;
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
import 'colors.dart';
......@@ -129,7 +129,7 @@ class _TimePickerState extends State<TimePicker> {
_TimePickerMode _mode = _TimePickerMode.hour;
void _handleModeChanged(_TimePickerMode mode) {
userFeedback.performHapticFeedback(HapticFeedbackType.virtualKey);
HapticFeedback.vibrate();
setState(() {
_mode = mode;
});
......
......@@ -3,13 +3,13 @@
// found in the LICENSE file.
import 'dart:ui';
import 'dart:async';
import 'package:sky_services/activity/activity.mojom.dart';
import 'shell.dart';
export 'package:sky_services/activity/activity.mojom.dart';
export 'package:sky_services/activity/activity.mojom.dart' show Activity, Intent, ComponentName, StringExtra;
// Dart wrapper around Activity mojo service available in Flutter on Android.
//
......@@ -21,7 +21,7 @@ export 'package:sky_services/activity/activity.mojom.dart';
/// Open a document into a new task rooted at the activity launched by
/// this Intent.
///
///
/// See Android's Intent.FLAG_ACTIVITY_NEW_DOCUMENT.
const int NEW_DOCUMENT = 0x00080000; // ignore: constant_identifier_names
......@@ -44,24 +44,6 @@ ActivityProxy _initActivityProxy() {
final ActivityProxy _activityProxy = _initActivityProxy();
final Activity activity = _activityProxy.ptr;
UserFeedbackProxy _initUserFeedbackProxy() {
UserFeedbackProxy proxy = new UserFeedbackProxy.unbound();
_activityProxy.ptr.getUserFeedback(proxy);
return proxy;
}
final UserFeedbackProxy _userFeedbackProxy = _initUserFeedbackProxy();
final UserFeedback userFeedback = _userFeedbackProxy.ptr;
PathServiceProxy _initPathServiceProxy() {
PathServiceProxy proxy = new PathServiceProxy.unbound();
shell.connectToService(null, proxy);
return proxy;
}
final PathServiceProxy _pathServiceProxy = _initPathServiceProxy();
final PathService pathService = _pathServiceProxy.ptr;
Color _cachedPrimaryColor;
String _cachedLabel;
......@@ -81,7 +63,3 @@ void updateTaskDescription({ String label, Color color }) {
_activityProxy.ptr.setTaskDescription(description);
}
Future<String> getAppDataDir() async => (await _pathServiceProxy.ptr.getAppDataDir()).path;
Future<String> getFilesDir() async => (await _pathServiceProxy.ptr.getFilesDir()).path;
Future<String> getCacheDir() async => (await _pathServiceProxy.ptr.getCacheDir()).path;
......@@ -5,30 +5,28 @@
import 'dart:async';
import 'package:mojo/core.dart' as core;
import 'package:sky_services/flutter/platform/app_messages.mojom.dart';
import 'package:sky_services/flutter/platform/app_messages.mojom.dart' as mojom;
import 'shell.dart';
// APIs for exchanging messages with the host application.
ApplicationMessagesProxy _initHostAppMessagesProxy() {
ApplicationMessagesProxy proxy = new ApplicationMessagesProxy.unbound();
mojom.ApplicationMessagesProxy _initHostAppMessagesProxy() {
mojom.ApplicationMessagesProxy proxy = new mojom.ApplicationMessagesProxy.unbound();
shell.connectToViewAssociatedService(proxy);
return proxy;
}
final ApplicationMessagesProxy _hostAppMessagesProxy = _initHostAppMessagesProxy();
final mojom.ApplicationMessagesProxy _hostAppMessagesProxy = _initHostAppMessagesProxy();
typedef Future<String> HostMessageCallback(String message);
typedef Object _SendStringResponseFactory(String response);
class _ApplicationMessagesImpl extends ApplicationMessages {
class _ApplicationMessagesImpl extends mojom.ApplicationMessages {
final Map<String, HostMessageCallback> handlers = <String, HostMessageCallback>{};
_ApplicationMessagesImpl() {
shell.provideService(ApplicationMessages.serviceName,
shell.provideService(mojom.ApplicationMessages.serviceName,
(core.MojoMessagePipeEndpoint endpoint) {
ApplicationMessagesStub stub = new ApplicationMessagesStub.fromEndpoint(endpoint);
mojom.ApplicationMessagesStub stub = new mojom.ApplicationMessagesStub.fromEndpoint(endpoint);
stub.impl = this;
}
);
......@@ -46,6 +44,8 @@ class _ApplicationMessagesImpl extends ApplicationMessages {
final _ApplicationMessagesImpl _appMessages = new _ApplicationMessagesImpl();
/// A service that can be implemented by the host application and the
/// Flutter framework to exchange application-specific messages.
class HostMessages {
/// Send a message to the host application.
static Future<String> sendToHost(String messageName, String message) async {
......
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:async';
import 'package:sky_services/flutter/platform/haptic_feedback.mojom.dart' as mojom;
import 'shell.dart';
mojom.HapticFeedbackProxy _initHapticFeedbackProxy() {
mojom.HapticFeedbackProxy proxy = new mojom.HapticFeedbackProxy.unbound();
shell.connectToViewAssociatedService(proxy);
return proxy;
}
final mojom.HapticFeedbackProxy _hapticFeedbackProxy = _initHapticFeedbackProxy();
/// Allows access to the haptic feedback interface on the device. This API is
/// intentionally terse since it invokes default platform behavior. It is not
/// suitable for use if you require more flexible access to device sensors and
/// peripherals.
class HapticFeedback {
HapticFeedback._();
/// Provides haptic feedback to the user for a short duration.
///
/// Platform Specific Notes:
///
/// * _iOS_: Uses the platform "sound" for vibration (via
/// AudioServicesPlaySystemSound)
/// * _Android_: Uses the platform haptic feedback API that simulates a short
/// a short tap on a virtual keyboard.
///
/// Return Value:
///
/// boolean indicating if the intent to provide haptic feedback to the user
/// was successfully conveyed to the embedder. There may not be any actual
/// feedback if the device does not have a vibrator or one is disabled in
/// system settings.
static Future<bool> vibrate() async {
return (await _hapticFeedbackProxy.ptr.vibrate()).success;
}
}
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:async';
import 'dart:io';
import 'package:sky_services/flutter/platform/path_provider.mojom.dart' as mojom;
import 'shell.dart';
mojom.PathProviderProxy _initPathProviderProxy() {
mojom.PathProviderProxy proxy = new mojom.PathProviderProxy.unbound();
shell.connectToViewAssociatedService(proxy);
return proxy;
}
final mojom.PathProviderProxy _pathProviderProxy = _initPathProviderProxy();
/// Returns commonly used locations on the filesystem.
class PathProvider {
PathProvider._();
/// Path to the temporary directory on the device. Files in this directory
/// may be cleared at any time. This does *not* return a new temporary
/// directory. Instead, the caller is responsible for creating
/// (and cleaning up) files or directories within this directory. This
/// directory is scoped to the calling application.
///
/// Examples:
///
/// * _iOS_: `NSTemporaryDirectory()`
/// * _Android_: `getCacheDir()` on the context.
static Future<Directory> getTemporaryDirectory() async {
return new Directory((await _pathProviderProxy.ptr.temporaryDirectory()).path);
}
/// Path to a directory where the application may place files that are private
/// to the application and will only be cleared when the application itself
/// is deleted.
///
/// Examples:
///
/// * iOS: `NSDocumentsDirectory`
/// * Android: The AppData directory.
static Future<Directory> getApplicationDocumentsDirectory() async {
return new Directory((await _pathProviderProxy.ptr.applicationDocumentsDirectory()).path);
}
}
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:async';
import 'package:sky_services/flutter/platform/system_chrome.mojom.dart' as mojom;
import 'shell.dart';
export 'package:sky_services/flutter/platform/system_chrome.mojom.dart' show DeviceOrientation, SystemUIOverlay;
mojom.SystemChromeProxy _initSystemChromeProxy() {
mojom.SystemChromeProxy proxy = new mojom.SystemChromeProxy.unbound();
shell.connectToViewAssociatedService(proxy);
return proxy;
}
final mojom.SystemChromeProxy _systemChromeProxy = _initSystemChromeProxy();
/// Controls specific aspects of the embedder interface.
class SystemChrome {
SystemChrome._();
/// Specifies the set of orientations the application interface can
/// be displayed in.
///
/// Arguments:
///
/// * `device_orientation_mask`: A mask of `DeviceOrientation` enum values.
/// The value 0 is synonymous with having all options enabled.
///
/// Return Value:
///
/// boolean indicating if the orientation mask is valid and the changes
/// could be conveyed successfully to the embedder.
static Future<bool> setPreferredOrientations(int deviceOrientationMask) async {
return (await _systemChromeProxy.ptr.setPreferredOrientations(deviceOrientationMask)).success;
}
/// Specifies the set of overlays visible on the embedder when the
/// application is running. The embedder may choose to ignore unsupported
/// overlays
///
/// Arguments:
///
/// * `style`: A mask of `SystemUIOverlay` enum values that denotes the overlays
/// to show.
///
/// Return Value:
///
/// boolean indicating if the preference was conveyed successfully to the
/// embedder.
///
/// Platform Specific Notes:
///
/// If the overlay is unsupported on the platform, enabling or disabling
/// that overlay is a no-op and always return true.
static Future<bool> setEnabledSystemUIOverlays(int overlaysMask) async {
return (await _systemChromeProxy.ptr.setEnabledSystemUiOverlays(overlaysMask)).success;
}
}
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:async';
import 'package:sky_services/flutter/platform/system_sound.mojom.dart' as mojom;
import 'shell.dart';
export 'package:sky_services/flutter/platform/system_sound.mojom.dart' show SystemSoundType;
mojom.SystemSoundProxy _initSystemSoundProxy() {
mojom.SystemSoundProxy proxy = new mojom.SystemSoundProxy.unbound();
shell.connectToViewAssociatedService(proxy);
return proxy;
}
final mojom.SystemSoundProxy _systemChromeProxy = _initSystemSoundProxy();
/// Allows easy access to the library of short system specific sounds for
/// common tasks.
class SystemSound {
SystemSound._();
/// Play the specified system sound. If that sound is not present on the
/// system, this method is a no-op and returns `true`.
///
/// Return Value:
///
/// boolean indicating if the intent to play the specified sound was
/// successfully conveyed to the embedder. No sound may actually play if the
/// device is muted or the sound was not available on the platform.
static Future<bool> play(mojom.SystemSoundType type) async {
return (await _systemChromeProxy.ptr.play(type)).success;
}
}
......@@ -217,7 +217,7 @@ class LongPressDraggable<T> extends DraggableBase<T> {
..onStart = (Point position) {
Drag result = onStart(position);
if (result != null)
userFeedback.performHapticFeedback(HapticFeedbackType.virtualKey);
HapticFeedback.vibrate();
return result;
};
}
......
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