[settings] Reland: Add settings package.

This is a reland of 6ad59b980460281f26b8f44a99677e8b894322a9

Original change's description:
> [settings] Add settings package.
>
> Allows changing wifi and datetime settings.
> - Add a default proposer to launch settings from Ask bar.
> - Add timezone watcher to update timezone when it changes.
> - Add datetime_settings, display_settings and settings to
>   ermine product dependencies.
>
> Change-Id: I664c4575a2a4506ff211ac9f33b5c246d6965997

Change-Id: If514f4610e02a98d9f59d5d694ca749aec6746fa
diff --git a/bin/datetime_settings/BUILD.gn b/bin/datetime_settings/BUILD.gn
new file mode 100644
index 0000000..90fa71f
--- /dev/null
+++ b/bin/datetime_settings/BUILD.gn
@@ -0,0 +1,31 @@
+# Copyright 2017 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("//topaz/runtime/flutter_runner/flutter_app.gni")
+
+flutter_app("datetime_settings") {
+
+  main_dart = "lib/main.dart"
+
+  manifest = "pubspec.yaml"
+
+  sources = [
+  ]
+
+  meta = [
+    {
+      path = rebase_path("meta/datetime_settings.cmx")
+      dest = "datetime_settings.cmx"
+    },
+  ]
+
+  deps = [
+    "//sdk/fidl/fuchsia.timezone",
+    "//third_party/dart-pkg/git/flutter/packages/flutter",
+    "//topaz/lib/settings:lib.settings",
+    "//topaz/public/dart/fuchsia_logger",
+    "//topaz/public/dart/fuchsia_services",
+    "//topaz/public/dart/widgets:lib.widgets"
+  ]
+}
diff --git a/bin/datetime_settings/OWNERS b/bin/datetime_settings/OWNERS
new file mode 100644
index 0000000..ce2ec43
--- /dev/null
+++ b/bin/datetime_settings/OWNERS
@@ -0,0 +1,3 @@
+ejia@google.com
+brycelee@google.com
+sanjayc@google.com
\ No newline at end of file
diff --git a/bin/datetime_settings/analysis_options.yaml b/bin/datetime_settings/analysis_options.yaml
new file mode 100644
index 0000000..e688f26
--- /dev/null
+++ b/bin/datetime_settings/analysis_options.yaml
@@ -0,0 +1,5 @@
+# Copyright 2017 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.
+
+include: ../analysis_options.yaml
diff --git a/bin/datetime_settings/assets/ic_signal_wifi_0_bar_grey600_48dp.png b/bin/datetime_settings/assets/ic_signal_wifi_0_bar_grey600_48dp.png
new file mode 100644
index 0000000..4e59c6a
--- /dev/null
+++ b/bin/datetime_settings/assets/ic_signal_wifi_0_bar_grey600_48dp.png
Binary files differ
diff --git a/bin/datetime_settings/assets/ic_signal_wifi_1_bar_grey600_48dp.png b/bin/datetime_settings/assets/ic_signal_wifi_1_bar_grey600_48dp.png
new file mode 100644
index 0000000..36c2cca
--- /dev/null
+++ b/bin/datetime_settings/assets/ic_signal_wifi_1_bar_grey600_48dp.png
Binary files differ
diff --git a/bin/datetime_settings/assets/ic_signal_wifi_1_bar_lock_grey600_48dp.png b/bin/datetime_settings/assets/ic_signal_wifi_1_bar_lock_grey600_48dp.png
new file mode 100644
index 0000000..35e3881
--- /dev/null
+++ b/bin/datetime_settings/assets/ic_signal_wifi_1_bar_lock_grey600_48dp.png
Binary files differ
diff --git a/bin/datetime_settings/assets/ic_signal_wifi_2_bar_grey600_48dp.png b/bin/datetime_settings/assets/ic_signal_wifi_2_bar_grey600_48dp.png
new file mode 100644
index 0000000..9cf549d
--- /dev/null
+++ b/bin/datetime_settings/assets/ic_signal_wifi_2_bar_grey600_48dp.png
Binary files differ
diff --git a/bin/datetime_settings/assets/ic_signal_wifi_2_bar_lock_grey600_48dp.png b/bin/datetime_settings/assets/ic_signal_wifi_2_bar_lock_grey600_48dp.png
new file mode 100644
index 0000000..8b5f3e6
--- /dev/null
+++ b/bin/datetime_settings/assets/ic_signal_wifi_2_bar_lock_grey600_48dp.png
Binary files differ
diff --git a/bin/datetime_settings/assets/ic_signal_wifi_3_bar_grey600_48dp.png b/bin/datetime_settings/assets/ic_signal_wifi_3_bar_grey600_48dp.png
new file mode 100644
index 0000000..eb55802
--- /dev/null
+++ b/bin/datetime_settings/assets/ic_signal_wifi_3_bar_grey600_48dp.png
Binary files differ
diff --git a/bin/datetime_settings/assets/ic_signal_wifi_3_bar_lock_grey600_48dp.png b/bin/datetime_settings/assets/ic_signal_wifi_3_bar_lock_grey600_48dp.png
new file mode 100644
index 0000000..2f37f9a
--- /dev/null
+++ b/bin/datetime_settings/assets/ic_signal_wifi_3_bar_lock_grey600_48dp.png
Binary files differ
diff --git a/bin/datetime_settings/assets/ic_signal_wifi_4_bar_grey600_48dp.png b/bin/datetime_settings/assets/ic_signal_wifi_4_bar_grey600_48dp.png
new file mode 100644
index 0000000..3941290
--- /dev/null
+++ b/bin/datetime_settings/assets/ic_signal_wifi_4_bar_grey600_48dp.png
Binary files differ
diff --git a/bin/datetime_settings/assets/ic_signal_wifi_4_bar_lock_grey600_48dp.png b/bin/datetime_settings/assets/ic_signal_wifi_4_bar_lock_grey600_48dp.png
new file mode 100644
index 0000000..63661cc
--- /dev/null
+++ b/bin/datetime_settings/assets/ic_signal_wifi_4_bar_lock_grey600_48dp.png
Binary files differ
diff --git a/bin/datetime_settings/lib/main.dart b/bin/datetime_settings/lib/main.dart
new file mode 100644
index 0000000..3296e45
--- /dev/null
+++ b/bin/datetime_settings/lib/main.dart
@@ -0,0 +1,40 @@
+// Copyright 2019 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:flutter/material.dart';
+
+import 'package:fidl_fuchsia_timezone/fidl_async.dart' show TimezoneProxy;
+import 'package:fuchsia_logger/logger.dart' show setupLogger;
+import 'package:fuchsia_services/services.dart' show StartupContext;
+import 'package:lib.settings/timezone_picker.dart';
+
+/// Main entry point to the datetime settings module.
+Future<void> main() async {
+  setupLogger(name: 'datetime_settings');
+
+  final timezone = TimezoneProxy();
+  StartupContext.fromStartupInfo().incoming.connectToService(timezone);
+  final currentTimezone = ValueNotifier<String>(await timezone.getTimezoneId());
+
+  Widget app = MaterialApp(
+    home: Container(
+      child: Container(
+        color: Colors.white,
+        child: AnimatedBuilder(
+            animation: currentTimezone,
+            builder: (context, child) {
+              return TimezonePicker(
+                onTap: (tz) {
+                  timezone.setTimezone(tz);
+                  currentTimezone.value = tz;
+                },
+                currentTimezoneId: currentTimezone.value,
+              );
+            }),
+      ),
+    ),
+  );
+
+  runApp(app);
+}
diff --git a/bin/datetime_settings/meta/datetime_settings.cmx b/bin/datetime_settings/meta/datetime_settings.cmx
new file mode 100644
index 0000000..cced215
--- /dev/null
+++ b/bin/datetime_settings/meta/datetime_settings.cmx
@@ -0,0 +1,37 @@
+{
+    "program": {
+        "data": "data/datetime_settings"
+    },
+    "sandbox": {
+        "services": [
+            "fuchsia.fonts.Provider",
+            "fuchsia.modular.Clipboard",
+            "fuchsia.modular.ContextWriter",
+            "fuchsia.logger.LogSink",
+            "fuchsia.sys.Environment",
+            "fuchsia.timezone.Timezone",
+            "fuchsia.ui.input.ImeService",
+            "fuchsia.ui.policy.Presenter",
+            "fuchsia.ui.scenic.Scenic",
+            "fuchsia.wlan.service.Wlan"
+        ],
+        "system": [ "data" ]
+    },
+    "facets": {
+        "fuchsia.module": {
+            "@version": 2,
+            "suggestion_headline": "Date-Time Settings",
+            "intent_filters": [
+                {
+                    "action": "com.fuchsia.settings.datetime.show",
+                    "parameters": [
+                        {
+                        "name": "status",
+                        "type": "com.fuchsia.status"
+                        }
+                    ]
+                }
+            ]
+        }
+    }
+}
diff --git a/bin/datetime_settings/pubspec.yaml b/bin/datetime_settings/pubspec.yaml
new file mode 100644
index 0000000..8b2b91e
--- /dev/null
+++ b/bin/datetime_settings/pubspec.yaml
@@ -0,0 +1,16 @@
+# Copyright 2017 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.
+
+name: wifi_settings
+flutter:
+  assets:
+    - assets/ic_signal_wifi_0_bar_grey600_48dp.png
+    - assets/ic_signal_wifi_1_bar_lock_grey600_48dp.png
+    - assets/ic_signal_wifi_1_bar_grey600_48dp.png
+    - assets/ic_signal_wifi_2_bar_lock_grey600_48dp.png
+    - assets/ic_signal_wifi_2_bar_grey600_48dp.png
+    - assets/ic_signal_wifi_3_bar_lock_grey600_48dp.png
+    - assets/ic_signal_wifi_3_bar_grey600_48dp.png
+    - assets/ic_signal_wifi_4_bar_lock_grey600_48dp.png
+    - assets/ic_signal_wifi_4_bar_grey600_48dp.png
\ No newline at end of file
diff --git a/bin/settings/BUILD.gn b/bin/settings/BUILD.gn
new file mode 100644
index 0000000..7ffd535
--- /dev/null
+++ b/bin/settings/BUILD.gn
@@ -0,0 +1,63 @@
+# 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("//build/package.gni")
+import("//topaz/runtime/dart/flutter_test.gni")
+import("//topaz/runtime/flutter_runner/flutter_app.gni")
+
+flutter_app("settings") {
+
+  main_dart = "lib/main.dart"
+
+  package_name = "settings"
+
+  manifest = "pubspec.yaml"
+
+  meta = [
+    {
+      path = rebase_path("meta/settings.cmx")
+      dest = "settings.cmx"
+    },
+  ]
+
+  sources = [
+    "src/models/settings_model.dart",
+    "src/widgets/all_settings.dart",
+  ]
+
+  deps = [
+    "//sdk/fidl/fuchsia.modular",
+    "//sdk/fidl/fuchsia.timezone",
+    "//sdk/fidl/fuchsia.ui.views",
+    "//sdk/fidl/fuchsia.wlan.service",
+    "//third_party/dart-pkg/git/flutter/packages/flutter_test",
+    "//third_party/dart-pkg/git/flutter/packages/flutter",
+    "//third_party/dart-pkg/pub/meta",
+    "//topaz/lib/settings:lib.settings",
+    "//topaz/public/dart/fuchsia_logger",
+    "//topaz/public/dart/fuchsia_modular",
+    "//topaz/public/dart/fuchsia_scenic_flutter",
+    "//topaz/public/dart/fuchsia_services",
+    "//topaz/public/dart/widgets:lib.widgets",
+  ]
+}
+
+flutter_test("settings_tests") {
+  sources = [
+    "settings_model_test.dart",
+  ]
+
+  deps = [
+    ":settings_dart_library",
+    "//third_party/dart-pkg/pub/test",
+  ]
+}
+
+group("tests") {
+  testonly = true
+
+  deps = [
+    ":settings_tests",
+  ]
+}
diff --git a/bin/settings/README.md b/bin/settings/README.md
new file mode 100644
index 0000000..1970c2e
--- /dev/null
+++ b/bin/settings/README.md
@@ -0,0 +1,6 @@
+# settings
+
+Used by the Session Shell as the settings story.
+
+This app will serve as the settings story for Session Shells.
+
diff --git a/bin/settings/analysis_options.yaml b/bin/settings/analysis_options.yaml
new file mode 100644
index 0000000..9d84659
--- /dev/null
+++ b/bin/settings/analysis_options.yaml
@@ -0,0 +1,5 @@
+# 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.
+
+include: ../../tools/analysis_options.yaml
diff --git a/bin/settings/lib/main.dart b/bin/settings/lib/main.dart
new file mode 100644
index 0000000..0a2c34d
--- /dev/null
+++ b/bin/settings/lib/main.dart
@@ -0,0 +1,77 @@
+// 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 'dart:async';
+import 'dart:developer' show Timeline;
+
+import 'package:flutter/material.dart';
+import 'package:fuchsia_logger/logger.dart';
+
+import 'src/models/settings_model.dart';
+import 'src/widgets/all_settings.dart';
+
+/// Main function of settings.
+Future<Null> main() async {
+  setupLogger(name: 'settings');
+  Timeline.instantSync('settings starting');
+
+  SettingsModel settingsModel = SettingsModel();
+
+  Widget app = MaterialApp(
+    home: AllSettings(),
+    routes: <String, WidgetBuilder>{
+      '/wifi': (BuildContext context) => _buildModule(
+            'Wi-Fi',
+            () => settingsModel.wifiModule,
+          ),
+      '/datetime': (BuildContext context) => _buildModule(
+            'Date & Time',
+            () => settingsModel.datetimeModule,
+          ),
+      '/display': (BuildContext context) => _buildModule(
+            'Display',
+            () => settingsModel.displayModule,
+          ),
+      '/accessibility': (BuildContext context) => _buildModule(
+            'Accessibility',
+            () => settingsModel.accessibilitySettingsModule,
+          ),
+      '/experiments': (BuildContext context) => _buildModule(
+            'Experiments',
+            () => settingsModel.experimentsModule,
+          ),
+      '/system': (BuildContext context) => _buildModule(
+            'System',
+            () => settingsModel.deviceSettingsModule,
+          ),
+      '/licenses': (BuildContext context) => LicensePage()
+    },
+  );
+
+  app = ScopedModel<SettingsModel>(
+    model: settingsModel,
+    child: app,
+  );
+
+  runApp(app);
+
+  Timeline.instantSync('settings started');
+}
+
+// Returns the [Scaffold] widget for the root view of the module.
+Widget _buildModule(String title, Widget getModView()) {
+  return ScopedModelDescendant<SettingsModel>(
+    builder: (
+      BuildContext context,
+      Widget child,
+      SettingsModel settingsModel,
+    ) =>
+        Scaffold(
+          appBar: AppBar(
+            title: Text(title),
+          ),
+          body: getModView(),
+        ),
+  );
+}
diff --git a/bin/settings/lib/src/models/settings_model.dart b/bin/settings/lib/src/models/settings_model.dart
new file mode 100644
index 0000000..3b453fc
--- /dev/null
+++ b/bin/settings/lib/src/models/settings_model.dart
@@ -0,0 +1,222 @@
+// 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 'dart:async';
+import 'dart:io';
+
+import 'package:intl/intl.dart';
+import 'package:fidl_fuchsia_ui_views/fidl_async.dart';
+import 'package:fuchsia_logger/logger.dart';
+import 'package:lib.settings/device_info.dart';
+import 'package:lib.widgets/model.dart';
+import 'package:fuchsia_modular/module.dart';
+import 'package:fuchsia_scenic_flutter/child_view.dart' show ChildView;
+import 'package:fuchsia_scenic_flutter/child_view_connection.dart';
+
+import 'settings_status.dart';
+
+export 'package:lib.widgets/model.dart'
+    show ScopedModel, Model, ScopedModelDescendant;
+
+/// Model for settings view.
+class SettingsModel extends Model {
+  String _networkAddresses;
+
+  SettingsStatus _settingsStatus;
+
+  // Wi-Fi module.
+  _CachedModule _wifiModule;
+
+  // Datetime module.
+  _CachedModule _datetimeModule;
+
+  // Display module.
+  _CachedModule _displayModule;
+
+  // Accessibility module.
+  _CachedModule _accessibilityModule;
+
+  // Experiments module.
+  _CachedModule _experimentsModule;
+
+  /// Module for general device settings, including update.
+  _CachedModule _deviceSettingsModule;
+
+  DateTime _testDeviceSourceDate;
+
+  /// Constructor.
+  SettingsModel() {
+    initialize();
+  }
+
+  // Exposed for testing.
+  void initialize() {
+    // Explicitly ignore intents
+    Module().registerIntentHandler(NoopIntentHandler());
+    _settingsStatus = SettingsStatus()..addListener(notifyListeners);
+    _setNetworkAddresses();
+  }
+
+  /// Fetches and sets the addresses of all network interfaces delimited by space.
+  Future<void> _setNetworkAddresses() async {
+    var interfaces = await NetworkInterface.list();
+    _networkAddresses = interfaces
+        .expand((NetworkInterface interface) => interface.addresses)
+        .map((InternetAddress address) => address.address)
+        .join(' ');
+    notifyListeners();
+  }
+
+  /// Returns the addresses of all network interfaces delimited by space.
+  String get networkAddresses {
+    return _networkAddresses;
+  }
+
+  /// Returns the hostname of the running device.
+  String get hostname => Platform.localHostname;
+
+  /// Returns the build info, if build info file is found on the system image.
+  String get buildInfo {
+    final DateTime buildTimeStamp = _testDeviceSourceDate != null
+        ? _testDeviceSourceDate
+        : DeviceInfo.getSourceDate();
+
+    if (buildTimeStamp != null) {
+      final builtAt =
+          DateFormat('H:mm', 'en_US').format(buildTimeStamp).toLowerCase();
+      final builtOn =
+          DateFormat('MMM dd, yyyy', 'en_US').format(buildTimeStamp);
+      // The time zone is hardcoded because DateFormat and DateTime currently doesn't
+      // support time zones.
+      return 'Built at $builtAt UTC on $builtOn';
+    } else {
+      log.warning('Last built time doesn\'t exist!');
+    }
+    return null;
+  }
+
+  /// Returns the wifi status.
+  String get wifiStatus => _settingsStatus.wifiStatus;
+
+  /// Returns the [EmbeddedModule] for Wi-Fi.
+  ChildView get wifiModule {
+    if (_wifiModule == null) {
+      _embedSetting(
+        name: 'wifi_settings',
+        title: 'Wi-Fi',
+      ).then((_CachedModule module) {
+        _wifiModule = module;
+        notifyListeners();
+      });
+    }
+    return _wifiModule?.childView;
+  }
+
+  /// Returns the datetime status.
+  String get datetimeStatus => _settingsStatus.timezoneStatus;
+
+  /// Returns the [EmbeddedModule] for Date & Time.
+  ChildView get datetimeModule {
+    if (_datetimeModule == null) {
+      _embedSetting(
+        name: 'datetime_settings',
+        title: 'Date & Time',
+      ).then((_CachedModule module) {
+        _datetimeModule = module;
+        notifyListeners();
+      });
+    }
+    return _datetimeModule?.childView;
+  }
+
+  /// Returns the [EmbeddedModule] for Experiments.
+  ChildView get experimentsModule {
+    if (_experimentsModule == null) {
+      _embedSetting(
+        name: 'experiments_setting',
+        title: 'Experiments',
+      ).then((_CachedModule module) {
+        _experimentsModule = module;
+        notifyListeners();
+      });
+    }
+    return _experimentsModule?.childView;
+  }
+
+  /// Returns the [EmbeddedModule] for Display.
+  ChildView get displayModule {
+    if (_displayModule == null) {
+      _embedSetting(
+        name: 'display_settings',
+        title: 'Display',
+      ).then((_CachedModule module) {
+        _displayModule = module;
+        notifyListeners();
+      });
+    }
+    return _displayModule?.childView;
+  }
+
+  /// Returns the [EmbeddedModule] for accessibility settings.
+  ChildView get accessibilitySettingsModule {
+    if (_accessibilityModule == null) {
+      _embedSetting(
+        name: 'accessibility_settings',
+        title: 'Accessibility',
+      ).then((_CachedModule module) {
+        _accessibilityModule = module;
+        notifyListeners();
+      });
+    }
+    return _accessibilityModule?.childView;
+  }
+
+  /// Returns the [EmbeddedModule] for device settings.
+  ChildView get deviceSettingsModule {
+    if (_deviceSettingsModule == null) {
+      _embedSetting(
+        name: 'device_settings',
+        title: 'System',
+      ).then((_CachedModule module) {
+        _deviceSettingsModule = module;
+        notifyListeners();
+      });
+    }
+    return _deviceSettingsModule?.childView;
+  }
+
+  Future<_CachedModule> _embedSetting({
+    String name,
+    String title,
+  }) {
+    final intent = Intent(
+      action: '',
+      handler: 'fuchsia-pkg://fuchsia.com/$name#meta/$name.cmx',
+    );
+    return Module()
+        .embedModule(name: title, intent: intent)
+        .then((m) => _CachedModule(m));
+  }
+
+  set testDeviceSourceDate(DateTime testDeviceSourceDate) =>
+      _testDeviceSourceDate = testDeviceSourceDate;
+}
+
+/// A helper class which holds a reference to the [EmbeddedModule]
+/// and creates the [childView] on demand.
+class _CachedModule {
+  final EmbeddedModule _embeddedModule;
+  ChildView _childView;
+
+  /// Returns an instance of the [ChildView] for this module.
+  ChildView get childView {
+    return _childView ??= _makeChildView();
+  }
+
+  _CachedModule(this._embeddedModule);
+
+  ChildView _makeChildView() => ChildView(
+      connection: ChildViewConnection(
+          ViewHolderToken(value: _embeddedModule.viewHolderToken.value)));
+}
diff --git a/bin/settings/lib/src/models/settings_status.dart b/bin/settings/lib/src/models/settings_status.dart
new file mode 100644
index 0000000..7bfbc49
--- /dev/null
+++ b/bin/settings/lib/src/models/settings_status.dart
@@ -0,0 +1,96 @@
+// 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 'dart:async';
+
+import 'package:fidl_fuchsia_timezone/fidl_async.dart' as tz;
+import 'package:fidl_fuchsia_wlan_service/fidl_async.dart' as wlan;
+import 'package:flutter/foundation.dart';
+import 'package:fuchsia_services/services.dart';
+
+// Interval for scanning in seconds.
+const _statusUpdateInterval = 6;
+
+/// Class that listens to and sends out status shown in the all_settings view.
+class SettingsStatus extends ChangeNotifier {
+  final ValueNotifier<String> _wifiStatus = ValueNotifier<String>('');
+  final ValueNotifier<String> _timezoneStatus = ValueNotifier<String>('');
+
+  final wlan.WlanProxy _wlanProxy = wlan.WlanProxy();
+  final tz.TimezoneProxy _timezoneProxy = tz.TimezoneProxy();
+  final tz.TimezoneWatcherBinding _timezoneWatcherBinding =
+      tz.TimezoneWatcherBinding();
+
+  Timer _wlanUpdateTimer;
+  SettingsStatus() {
+    _wifiStatus.addListener(notifyListeners);
+    _timezoneStatus.addListener(notifyListeners);
+
+    _listenToWifiStatus();
+    _listenToTimezoneStatus();
+  }
+
+  String get timezoneStatus => _timezoneStatus.value;
+
+  String get wifiStatus => _wifiStatus.value;
+
+  /// Stop any updating timers
+  void stop() {
+    _wlanUpdateTimer.cancel();
+  }
+
+  String _extractTimezoneStatus(String timezoneId) => '$timezoneId';
+
+  String _extractWifiStatus(wlan.WlanStatus status) {
+    switch (status.state) {
+      case wlan.State.associated:
+        return 'Connected to ${status.currentAp.ssid}';
+      case wlan.State.associating:
+      case wlan.State.joining:
+      case wlan.State.bss:
+      case wlan.State.querying:
+      case wlan.State.authenticating:
+        return 'Connecting';
+      case wlan.State.scanning:
+        return 'Disconnected';
+      default:
+        return 'Unknown';
+    }
+  }
+
+  void _listenToTimezoneStatus() async {
+    StartupContext.fromStartupInfo().incoming.connectToService(_timezoneProxy);
+
+    _timezoneStatus.value =
+        _extractTimezoneStatus(await _timezoneProxy.getTimezoneId());
+
+    await _timezoneProxy
+        .watch(_timezoneWatcherBinding.wrap(_TimezoneWatcherImpl(this)));
+  }
+
+  void _listenToWifiStatus() async {
+    StartupContext.fromStartupInfo().incoming.connectToService(_wlanProxy);
+
+    _wifiStatus.value = _extractWifiStatus(await _wlanProxy.status());
+
+    _wlanUpdateTimer =
+        Timer.periodic(Duration(seconds: _statusUpdateInterval), (_) async {
+      _wifiStatus.value = _extractWifiStatus(await _wlanProxy.status());
+    });
+  }
+
+  void _onChangeTimezone(String tz) {
+    _timezoneStatus.value = _extractTimezoneStatus(tz);
+  }
+}
+
+class _TimezoneWatcherImpl extends tz.TimezoneWatcher {
+  final SettingsStatus status;
+  _TimezoneWatcherImpl(this.status);
+
+  @override
+  Future<void> onTimezoneOffsetChange(String timezoneId) async {
+    status._onChangeTimezone(timezoneId);
+  }
+}
diff --git a/bin/settings/lib/src/widgets/all_settings.dart b/bin/settings/lib/src/widgets/all_settings.dart
new file mode 100644
index 0000000..654637c
--- /dev/null
+++ b/bin/settings/lib/src/widgets/all_settings.dart
@@ -0,0 +1,75 @@
+// 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:flutter/material.dart';
+import 'package:lib.widgets/model.dart';
+
+import '../models/settings_model.dart';
+
+/// Main view that shows all settings.
+class AllSettings extends StatelessWidget {
+  @override
+  Widget build(BuildContext context) {
+    return ScopedModelDescendant<SettingsModel>(
+      builder: (
+        BuildContext context,
+        Widget child,
+        SettingsModel settingsModel,
+      ) =>
+          Scaffold(
+            appBar: AppBar(
+              title: Text('All Settings'),
+            ),
+            body: ListView(
+              physics: BouncingScrollPhysics(),
+              children: <Widget>[
+                ListTile(
+                  leading: Icon(Icons.wifi),
+                  title: Text('Wi-Fi'),
+                  subtitle: Text(settingsModel.wifiStatus),
+                  onTap: () => Navigator.of(context).pushNamed('/wifi'),
+                ),
+                ListTile(
+                  leading: Icon(Icons.schedule),
+                  title: Text('Date & time'),
+                  subtitle: Text(settingsModel.datetimeStatus),
+                  onTap: () => Navigator.of(context).pushNamed('/datetime'),
+                ),
+                ListTile(
+                  leading: Icon(Icons.settings_brightness),
+                  title: Text('Display'),
+                  onTap: () => Navigator.of(context).pushNamed('/display'),
+                ),
+                ListTile(
+                  leading: Icon(Icons.accessibility),
+                  title: Text('Accessibility'),
+                  onTap: () =>
+                      Navigator.of(context).pushNamed('/accessibility'),
+                ),
+                ListTile(
+                  leading: Icon(Icons.touch_app),
+                  title: Text('Experiments'),
+                  onTap: () => Navigator.of(context).pushNamed('/experiments'),
+                ),
+                ListTile(
+                  leading: Icon(Icons.info_outline),
+                  title: Text('System'),
+                  subtitle: Text(
+                    '${settingsModel.hostname} '
+                        '${settingsModel.networkAddresses} '
+                        '${settingsModel.buildInfo}',
+                  ),
+                  onTap: () => Navigator.of(context).pushNamed('/system'),
+                ),
+                ListTile(
+                  leading: Icon(Icons.copyright),
+                  title: Text('Show Open Source Licenses'),
+                  onTap: () => Navigator.of(context).pushNamed('/licenses'),
+                ),
+              ],
+            ),
+          ),
+    );
+  }
+}
diff --git a/bin/settings/meta/settings.cmx b/bin/settings/meta/settings.cmx
new file mode 100644
index 0000000..4c87f6a
--- /dev/null
+++ b/bin/settings/meta/settings.cmx
@@ -0,0 +1,23 @@
+{
+    "program": {
+        "data": "data/settings"
+    },
+    "sandbox": {
+        "features": [ "build-info" ],
+        "services": [
+            "fuchsia.cobalt.LoggerFactory",
+            "fuchsia.fonts.Provider",
+            "fuchsia.logger.LogSink",
+            "fuchsia.modular.Clipboard",
+            "fuchsia.modular.ContextWriter",
+            "fuchsia.modular.ModuleContext",
+            "fuchsia.sys.Environment",
+            "fuchsia.timezone.Timezone",
+            "fuchsia.ui.input.ImeService",
+            "fuchsia.ui.policy.Presenter",
+            "fuchsia.ui.scenic.Scenic",
+            "fuchsia.wlan.service.Wlan"
+        ],
+        "system": [ "data" ]
+    }
+}
diff --git a/bin/settings/pubspec.yaml b/bin/settings/pubspec.yaml
new file mode 100644
index 0000000..2fa4436
--- /dev/null
+++ b/bin/settings/pubspec.yaml
@@ -0,0 +1,4 @@
+# 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.
+name: settings
diff --git a/bin/settings/test/settings_model_test.dart b/bin/settings/test/settings_model_test.dart
new file mode 100644
index 0000000..ea21b45
--- /dev/null
+++ b/bin/settings/test/settings_model_test.dart
@@ -0,0 +1,22 @@
+// 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:settings/src/models/settings_model.dart'; // ignore: implementation_imports
+import 'package:test/test.dart';
+
+class TestSettingsModel extends SettingsModel {
+  @override
+  void initialize() {}
+}
+
+void main() {
+  TestSettingsModel _settingsModel = TestSettingsModel();
+
+  test('test buildInfo', () {
+    final DateTime testDate = DateTime.utc(2006, 10, 6, 13, 20, 0);
+    _settingsModel.testDeviceSourceDate = testDate;
+    expect(
+        _settingsModel.buildInfo, equals('Built at 13:20 UTC on Oct 06, 2006'));
+  });
+}
diff --git a/packages/prod/BUILD.gn b/packages/prod/BUILD.gn
index 0eb5474..13e3392 100644
--- a/packages/prod/BUILD.gn
+++ b/packages/prod/BUILD.gn
@@ -54,6 +54,7 @@
     "//topaz/packages/prod:dart_jit_product_runner",
     "//topaz/packages/prod:dart_jit_runner",
     "//topaz/packages/prod:dart_runner",
+    "//topaz/packages/prod:datetime_settings",
     "//topaz/packages/prod:device_settings",
     "//topaz/packages/prod:display_settings",
     "//topaz/packages/prod:ermine",
@@ -66,6 +67,7 @@
     "//topaz/packages/prod:latin-ime",
     "//topaz/packages/prod:modules_index",
     "//topaz/packages/prod:mondrian",
+    "//topaz/packages/prod:settings",
     "//topaz/packages/prod:skottie_viewer",
     "//topaz/packages/prod:system_dashboard",
     "//topaz/packages/prod:term",
@@ -91,6 +93,20 @@
   ]
 }
 
+group("datetime_settings") {
+  testonly = true
+  public_deps = [
+    "//topaz/bin/datetime_settings",
+  ]
+}
+
+group("settings") {
+  testonly = true
+  public_deps = [
+    "//topaz/bin/settings",
+  ]
+}
+
 group("wifi_settings") {
   testonly = true
   public_deps = [
@@ -253,8 +269,11 @@
     "//topaz/packages/prod:chromium",
     "//topaz/packages/prod:dart_jit_runner",
     "//topaz/packages/prod:dart_jit_product_runner",
+    "//topaz/packages/prod:datetime_settings",
+    "//topaz/packages/prod:display_settings",
     "//topaz/packages/prod:google_auth_provider",
     "//topaz/packages/prod:mondrian",
+    "//topaz/packages/prod:settings",
     "//topaz/packages/prod:userpicker_base_shell",
     "//topaz/packages/prod:wifi_settings",
     "//topaz/shell/ermine:ermine",
diff --git a/packages/tests/BUILD.gn b/packages/tests/BUILD.gn
index 75a7fb1..6c8a36b 100644
--- a/packages/tests/BUILD.gn
+++ b/packages/tests/BUILD.gn
@@ -22,6 +22,7 @@
   testonly = true
   public_deps = [
     "//topaz/bin/dart_fidl_json/test:dart_fidl_json_test($host_toolchain)",
+    "//topaz/bin/settings:settings_tests($host_toolchain)",
     "//topaz/examples/test/flutter_widget_test($host_toolchain)",
     "//topaz/lib/keyboard/flutter:keyboard_test($host_toolchain)",
     "//topaz/lib/setui/common:lib_setui_common_test($host_toolchain)",
diff --git a/shell/ermine/BUILD.gn b/shell/ermine/BUILD.gn
index 144314d..62fdb76 100644
--- a/shell/ermine/BUILD.gn
+++ b/shell/ermine/BUILD.gn
@@ -32,6 +32,7 @@
     "main.dart",
     "src/models/app_model.dart",
     "src/models/ermine_service_provider.dart",
+    "src/models/default_proposer.dart",
     "src/models/package_proposer.dart",
     "src/models/story_manager.dart",
     "src/models/story_model.dart",
diff --git a/shell/ermine/lib/src/models/app_model.dart b/shell/ermine/lib/src/models/app_model.dart
index 31c8e8c..c9d9a78 100644
--- a/shell/ermine/lib/src/models/app_model.dart
+++ b/shell/ermine/lib/src/models/app_model.dart
@@ -41,6 +41,7 @@
 import '../utils/elevations.dart';
 import '../utils/key_chord_listener.dart' show KeyChordListener;
 import '../utils/session_shell_services.dart' show SessionShellServices;
+import 'default_proposer.dart' show DefaultProposer;
 import 'ermine_service_provider.dart' show ErmineServiceProvider;
 import 'package_proposer.dart' show PackageProposer;
 import 'story_manager.dart'
@@ -64,6 +65,7 @@
   final _componentControllerProxy = ComponentControllerProxy();
   final _suggestionProvider = SuggestionProviderProxy();
   final _ask = AskBarProxy();
+  final _defaultProposer = DefaultProposer();
   final _packageProposer = PackageProposer();
   final _webProposer = WebProposer();
 
@@ -88,6 +90,7 @@
         .incoming
         .connectToService(_componentContext);
     StartupContext.fromStartupInfo().incoming.connectToService(_puppetMaster);
+    _defaultProposer.start();
     _packageProposer.start();
     _webProposer.start();
 
@@ -200,6 +203,7 @@
     _sessionShellContext.logout();
     storyManager.stop();
     _pointerEventsListener.stop();
+    _defaultProposer.stop();
     _packageProposer.stop();
     _webProposer.stop();
 
diff --git a/shell/ermine/lib/src/models/default_proposer.dart b/shell/ermine/lib/src/models/default_proposer.dart
new file mode 100644
index 0000000..53ffef1
--- /dev/null
+++ b/shell/ermine/lib/src/models/default_proposer.dart
@@ -0,0 +1,77 @@
+// 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 'dart:async';
+
+import 'package:fidl_fuchsia_modular/fidl_async.dart'
+    show
+        AddMod,
+        IntelligenceServicesProxy,
+        ProposalPublisherProxy,
+        QueryHandler,
+        QueryHandlerBinding,
+        QueryResponse,
+        SetFocusState,
+        StoryCommand,
+        SurfaceRelation,
+        UserInput;
+import 'package:fuchsia_modular/module.dart';
+import 'package:fuchsia_modular/proposal.dart';
+import 'package:fuchsia_services/services.dart';
+
+/// Proposes suggestions when no query is entered.
+class DefaultProposer extends QueryHandler {
+  final _proposalPublisherProxy = ProposalPublisherProxy();
+  final _queryHandlerBinding = QueryHandlerBinding();
+
+  /// Starts the proposal process.
+  void start() {
+    final intelligenceServicesProxy = IntelligenceServicesProxy();
+    StartupContext.fromStartupInfo()
+        .incoming
+        .connectToService(intelligenceServicesProxy);
+    intelligenceServicesProxy
+      ..getProposalPublisher(_proposalPublisherProxy.ctrl.request())
+      ..registerQueryHandler(
+        _queryHandlerBinding.wrap(this),
+      );
+    intelligenceServicesProxy.ctrl.close();
+  }
+
+  /// Stops the proposal process.
+  void stop() {
+    _proposalPublisherProxy.ctrl.close();
+    _queryHandlerBinding.close();
+  }
+
+  @override
+  Future<QueryResponse> onQuery(UserInput input) async {
+    List<Proposal> proposals = <Proposal>[];
+    if (input.text.isEmpty) {
+      // Open settings.
+      proposals = await Future.wait([_createPackageProposal('settings')]);
+    }
+
+    return QueryResponse(proposals: proposals);
+  }
+
+  Future<Proposal> _createPackageProposal(String package) async {
+    final packageUrl = 'fuchsia-pkg://fuchsia.com/$package#meta/$package.cmx';
+    final AddMod addMod = AddMod(
+      intent: Intent(action: '', handler: packageUrl),
+      surfaceParentModName: [],
+      modName: [packageUrl],
+      surfaceRelation: SurfaceRelation(),
+    );
+    return Proposal(
+      id: 'open_$package',
+      headline: 'open $package',
+      confidence: 0.9,
+      details: package,
+    )
+      ..addStoryCommand(StoryCommand.withAddMod(addMod))
+      ..addStoryCommand(
+          StoryCommand.withSetFocusState(SetFocusState(focused: true)));
+  }
+}
diff --git a/shell/ermine/lib/src/modules/ask_model.dart b/shell/ermine/lib/src/modules/ask_model.dart
index 117d8a6..775108d 100644
--- a/shell/ermine/lib/src/modules/ask_model.dart
+++ b/shell/ermine/lib/src/modules/ask_model.dart
@@ -100,6 +100,7 @@
       ..jump(0.8)
       ..target = 1.0;
     controller.clear();
+    onQuery('');
   }
 
   void hide() {
@@ -163,10 +164,6 @@
   }
 
   void onQuery(String query) {
-    if (query?.isEmpty ?? true) {
-      return;
-    }
-
     _suggestions = <Suggestion>[];
 
     final queryListenerBinding = QueryListenerBinding();