[ermine] Cache status spec for infrequently updating settings.

Some settings like battery charge does not update frequently. This
results in a missing entry for battery until it is updated. This
change caches the last update received from a status provider and
displays that until the next update.

bug: http://fxb/37803 #done
Change-Id: I2f6ff8936a440c6ac93225b57836af9fb3ebe33c
diff --git a/lib/quickui/lib/quickui.dart b/lib/quickui/lib/quickui.dart
index 218d1c3..0a9c075 100644
--- a/lib/quickui/lib/quickui.dart
+++ b/lib/quickui/lib/quickui.dart
@@ -44,10 +44,10 @@
       update(value);
     }
 
-    final status = _completer.future;
+    final future = _completer.future;
     if (_completer.isCompleted) {
       _completer = Completer<Spec>();
     }
-    return status;
+    return future;
   }
 }
diff --git a/lib/quickui/lib/uistream.dart b/lib/quickui/lib/uistream.dart
index e156b04..92acc28 100644
--- a/lib/quickui/lib/uistream.dart
+++ b/lib/quickui/lib/uistream.dart
@@ -13,6 +13,7 @@
 /// of the request to the underlying [QuickUi] proxy.
 class UiStream {
   final QuickUi _ui;
+  Spec _spec;
   StreamSubscription<Spec> _subscription;
   final _controller = StreamController<Spec>.broadcast();
 
@@ -22,15 +23,20 @@
   /// Returns the [Stream] over [Spec] objects.
   Stream<Spec> get stream => _controller.stream.asBroadcastStream();
 
+  /// Returns the last [Spec] returned from QuickUi server.
+  Spec get spec => _spec;
+
   /// Start listening to the [QuickUi] server.
   void listen() {
     update(null);
   }
 
   /// Send a [Value] to QuickUi server to request a new [Spec].
-  void update(Value value) {
+  void update([Value value]) {
     _subscription?.cancel();
     _subscription = _ui.getSpec(value).asStream().listen((spec) {
+      // Cache the spec until the next returned from the server.
+      _spec = spec;
       if (spec != null) {
         _controller.add(spec);
       }
diff --git a/session_shells/ermine/settings/lib/src/battery.dart b/session_shells/ermine/settings/lib/src/battery.dart
index 1807a46..31c99f9 100644
--- a/session_shells/ermine/settings/lib/src/battery.dart
+++ b/session_shells/ermine/settings/lib/src/battery.dart
@@ -17,8 +17,6 @@
   // Localized strings.
   static String get _title => Strings.battery;
 
-  static const _checkBatteryDuration = Duration(seconds: 1);
-
   BatteryModel model;
 
   Battery({BatteryManagerProxy monitor, BatteryInfoWatcherBinding binding}) {
@@ -27,7 +25,6 @@
       binding: binding,
       onChange: _onChange,
     );
-    Timer.periodic(_checkBatteryDuration, (Timer t) => {_onChange()});
   }
 
   factory Battery.fromStartupContext(StartupContext startupContext) {
diff --git a/session_shells/ermine/shell/lib/src/widgets/status/status.dart b/session_shells/ermine/shell/lib/src/widgets/status/status.dart
index 3e58537..444c3f1 100644
--- a/session_shells/ermine/shell/lib/src/widgets/status/status.dart
+++ b/session_shells/ermine/shell/lib/src/widgets/status/status.dart
@@ -59,6 +59,7 @@
   Widget build(BuildContext context) {
     return StreamBuilder<Spec>(
       stream: uiStream.stream,
+      initialData: uiStream.spec,
       builder: (context, snapshot) {
         if (!snapshot.hasData) {
           return Offstage();
@@ -145,21 +146,7 @@
 
   Widget _buildFromValue(Value value, void Function(Value) update) {
     if (value.$tag == ValueTag.button) {
-      return GestureDetector(
-        onTap: () => update(value),
-        child: Container(
-          height: kItemHeight,
-          color: Colors.white,
-          padding: EdgeInsets.symmetric(vertical: 0, horizontal: 2),
-          child: Text(
-            value.button.label.toUpperCase(),
-            style: TextStyle(
-              color: Colors.black,
-              fontWeight: FontWeight.w400,
-            ),
-          ),
-        ),
-      );
+      return _buildButton(value.button.label, () => update(value));
     }
     if (value.$tag == ValueTag.text) {
       return Text(value.text.text.toUpperCase());
@@ -228,22 +215,22 @@
       ),
     );
   }
+}
 
-  Widget _buildButton(String label, void Function() onTap) {
-    return GestureDetector(
-      onTap: onTap,
-      child: Container(
-        height: kItemHeight,
-        color: Colors.white,
-        padding: EdgeInsets.symmetric(vertical: 0, horizontal: 2),
-        child: Text(
-          label.toUpperCase(),
-          style: TextStyle(
-            color: Colors.black,
-            fontWeight: FontWeight.w400,
-          ),
+Widget _buildButton(String label, void Function() onTap) {
+  return GestureDetector(
+    onTap: onTap,
+    child: Container(
+      height: kItemHeight,
+      color: Colors.white,
+      padding: EdgeInsets.symmetric(vertical: 0, horizontal: 2),
+      child: Text(
+        label.toUpperCase(),
+        style: TextStyle(
+          color: Colors.black,
+          fontWeight: FontWeight.w400,
         ),
       ),
-    );
-  }
+    ),
+  );
 }