blob: 8d8e16bf783e6a036da2921565c686560be28dc9 [file] [log] [blame]
// Copyright 2018 The Fuchsia 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 'package:fidl/fidl.dart' show InterfaceRequest, InterfaceHandle;
import 'package:fidl_fuchsia_modular/fidl_async.dart'
show
SessionShellPresentationProvider,
SessionShellPresentationProviderBinding,
FocusWatcher,
StoryVisualStateWatcherProxy,
FocusWatcherBinding,
FocusProviderProxy,
StoryVisualStateWatcher,
StoryVisualState,
FocusInfo,
SessionShellContext;
import 'package:fidl_fuchsia_ui_policy/fidl_async.dart' show Presentation;
import 'package:fuchsia_modular/lifecycle.dart';
import 'package:fuchsia_services/services.dart';
/// Manages which Stories have focus and thus can receive input events from the
/// presenter.
class SessionShellServices {
/// The session shell
final SessionShellContext sessionShellContext;
/// The binding for the [SessionShellPresentationProvider] service implemented
/// by [SessionShellImpl].
final _bindings = <SessionShellPresentationProviderBinding>[];
/// Binding for the [FocusProvider] proxy.
final _focusProviderProxy = FocusProviderProxy();
/// Mapping of story id to [StoryVisualStateWatcher] handle.
final _visualStateWatchers = <String, StoryVisualStateWatcherProxy>{};
/// Binding for [FocusWatcher] implemented by this SessionShell.
final _focusWatcherBinding = FocusWatcherBinding();
String _lastFocusedStoryId;
// Holds the [Lifecycle] reference to expose the service.
Lifecycle _lifecycle;
/// Constructor.
SessionShellServices({this.sessionShellContext});
/// Advertises the session shell as a [Lifecycle] and
/// [SessionShellPresentationProvider] to the rest of the system via
/// the [StartupContext].
void advertise() {
sessionShellContext.getFocusProvider(_focusProviderProxy.ctrl.request());
_focusProviderProxy
.watch(_focusWatcherBinding.wrap(_FocusWatcherImpl(this)));
_lifecycle ??= Lifecycle();
StartupContext.fromStartupInfo().outgoing.addPublicService(
(InterfaceRequest<SessionShellPresentationProvider> request) =>
_bindings.add(
SessionShellPresentationProviderBinding()
..bind(_SessionShellPresentationProviderImpl(this), request),
),
SessionShellPresentationProvider.$serviceName,
);
}
void _removeWatcher(String storyId) => _visualStateWatchers.remove(storyId);
void _setWatcher(String storyId, StoryVisualStateWatcherProxy watcher) =>
_visualStateWatchers[storyId] = watcher;
void _notifyWatchers() {
for (final entry in _visualStateWatchers.entries) {
entry.value.onVisualStateChange(
entry.key == _lastFocusedStoryId
? StoryVisualState.maximized
: StoryVisualState.minimized,
);
}
}
}
class _SessionShellPresentationProviderImpl
extends SessionShellPresentationProvider {
final SessionShellServices _sessionShellServices;
_SessionShellPresentationProviderImpl(this._sessionShellServices);
@override
Future<void> getPresentation(
String storyId,
InterfaceRequest<Presentation> request,
) =>
_sessionShellServices.sessionShellContext.getPresentation(request);
@override
Future<void> watchVisualState(
String storyId,
InterfaceHandle<StoryVisualStateWatcher> watcherHandle,
) async {
final watcherProxy = StoryVisualStateWatcherProxy();
try {
watcherProxy.ctrl.bind(watcherHandle);
} on Exception {
_sessionShellServices._removeWatcher(storyId);
}
_sessionShellServices
.._setWatcher(storyId, watcherProxy)
.._notifyWatchers();
}
}
class _FocusWatcherImpl extends FocusWatcher {
final SessionShellServices _sessionShellServices;
_FocusWatcherImpl(this._sessionShellServices);
@override
Future<void> onFocusChange(FocusInfo focusInfo) async {
_sessionShellServices
.._lastFocusedStoryId = focusInfo.focusedStoryId
.._notifyWatchers();
}
}