Add test case for Flutter Issue #27677 as a benchmark. (#34870)

* Add test case for Flutter Issue #27677 as a benchmark.

See https://github.com/flutter/flutter/issues/27677

I got the following results running the test on a Moto E2 which
will help us determine how much we can gain by analyzing the
operations and eliminating unnecessary repaints based on
dirty rectangles/regions.

no blurs       - avg 216.0 fps over 3 samples
blur the group - avg  22.9 fps over 3 samples
blur each txt  - avg   3.4 fps over 3 samples

* Added the new benchmark to be tracked on the dashboard.
diff --git a/dev/benchmarks/macrobenchmarks/lib/common.dart b/dev/benchmarks/macrobenchmarks/lib/common.dart
index 741920d..746d824 100644
--- a/dev/benchmarks/macrobenchmarks/lib/common.dart
+++ b/dev/benchmarks/macrobenchmarks/lib/common.dart
@@ -4,3 +4,4 @@
 
 const String kCullOpacityRouteName = '/cull_opacity';
 const String kCubicBezierRouteName = '/cubic_bezier';
+const String kBackdropFilterRouteName = '/backdrop_filter';
diff --git a/dev/benchmarks/macrobenchmarks/lib/main.dart b/dev/benchmarks/macrobenchmarks/lib/main.dart
index 0b89ba0..5f87dfd 100644
--- a/dev/benchmarks/macrobenchmarks/lib/main.dart
+++ b/dev/benchmarks/macrobenchmarks/lib/main.dart
@@ -5,6 +5,7 @@
 import 'package:flutter/material.dart';
 
 import 'common.dart';
+import 'src/backdrop_filter.dart';
 import 'src/cubic_bezier.dart';
 import 'src/cull_opacity.dart';
 
@@ -22,6 +23,7 @@
         '/': (BuildContext context) => HomePage(),
         kCullOpacityRouteName: (BuildContext context) => CullOpacityPage(),
         kCubicBezierRouteName: (BuildContext context) => CubicBezierPage(),
+        kBackdropFilterRouteName: (BuildContext context) => BackdropFilterPage(),
       },
     );
   }
@@ -48,6 +50,13 @@
               Navigator.pushNamed(context, kCubicBezierRouteName);
             },
           ),
+          RaisedButton(
+            key: const Key(kBackdropFilterRouteName),
+            child: const Text('Backdrop Filter'),
+            onPressed: (){
+              Navigator.pushNamed(context, kBackdropFilterRouteName);
+            },
+          ),
         ],
       ),
     );
diff --git a/dev/benchmarks/macrobenchmarks/lib/src/backdrop_filter.dart b/dev/benchmarks/macrobenchmarks/lib/src/backdrop_filter.dart
new file mode 100644
index 0000000..5e93117
--- /dev/null
+++ b/dev/benchmarks/macrobenchmarks/lib/src/backdrop_filter.dart
@@ -0,0 +1,113 @@
+import 'dart:ui';
+
+import 'package:flutter/material.dart';
+
+class BackdropFilterPage extends StatefulWidget {
+  @override
+  _BackdropFilterPageState createState() => _BackdropFilterPageState();
+}
+
+class _BackdropFilterPageState extends State<BackdropFilterPage> with TickerProviderStateMixin {
+  bool _blurGroup = false;
+  bool _blurTexts = true;
+  AnimationController animation;
+
+  @override
+  void initState() {
+    super.initState();
+    animation = AnimationController(vsync: this, duration: const Duration(seconds: 1));
+    animation.repeat();
+  }
+
+  @override
+  void dispose() {
+    animation.dispose();
+    super.dispose();
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    Widget addBlur(Widget child, bool shouldBlur) {
+      if (shouldBlur) {
+        return ClipRect(
+          child: BackdropFilter(
+            filter: ImageFilter.blur(sigmaX: 5, sigmaY: 5),
+            child: child,
+          ),
+        );
+      } else {
+        return child;
+      }
+    }
+
+    final Widget txt = addBlur(Container(
+      padding: const EdgeInsets.all(5),
+      child: const Text('txt'),
+    ), _blurTexts);
+
+    Widget col(Widget w, int numRows) {
+      return Column(
+          children: List<Widget>.generate(numRows, (int i) => w),
+      );
+    }
+
+    Widget grid(Widget w, int numRows, int numCols) {
+      return Row(
+        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
+        children: List<Widget>.generate(numCols, (int i) => col(w, numRows)),
+      );
+    }
+
+    return Scaffold(
+      backgroundColor: Colors.grey,
+      body: Stack(
+        children: <Widget>[
+          Text('0' * 10000, style: TextStyle(color: Colors.yellow)),
+          Column(
+            mainAxisAlignment: MainAxisAlignment.spaceEvenly,
+            children: <Widget>[
+              Expanded(
+                child: RepaintBoundary(
+                    child: Center(
+                      child: AnimatedBuilder(
+                          animation: animation,
+                          builder: (BuildContext c, Widget w) {
+                            final int val = (animation.value * 255).round();
+                            return Container(
+                                width: 50,
+                                height: 50,
+                                color: Color.fromARGB(255, val, val, val));
+                          }),
+                    )),
+              ),
+              const SizedBox(height: 20),
+              RepaintBoundary(
+                child: addBlur(grid(txt, 17, 5), _blurGroup),
+              ),
+              const SizedBox(height: 20),
+              Container(
+                color: Colors.white,
+                child:Row(
+                  mainAxisAlignment: MainAxisAlignment.center,
+                  children: <Widget>[
+                    const Text('Backdrop per txt:'),
+                    Checkbox(
+                      value: _blurTexts,
+                      onChanged: (bool v) => setState(() { _blurTexts = v; }),
+                    ),
+                    const SizedBox(width: 10),
+                    const Text('Backdrop grid:'),
+                    Checkbox(
+                      value: _blurGroup,
+                      onChanged: (bool v) => setState(() { _blurGroup = v; }),
+                    ),
+                  ],
+                ),
+              ),
+            ],
+          ),
+        ],
+      ),
+    );
+  }
+}
diff --git a/dev/benchmarks/macrobenchmarks/lib/src/cubic_bezier.dart b/dev/benchmarks/macrobenchmarks/lib/src/cubic_bezier.dart
index a14b71c..8237d7e 100644
--- a/dev/benchmarks/macrobenchmarks/lib/src/cubic_bezier.dart
+++ b/dev/benchmarks/macrobenchmarks/lib/src/cubic_bezier.dart
@@ -327,6 +327,12 @@
   }
 
   @override
+  void dispose() {
+    controller.dispose();
+    super.dispose();
+  }
+
+  @override
   Widget build(BuildContext context) {
     return CustomPaint(
         foregroundPainter: BezierPainter(widget.color,
diff --git a/dev/benchmarks/macrobenchmarks/lib/src/cull_opacity.dart b/dev/benchmarks/macrobenchmarks/lib/src/cull_opacity.dart
index c42f2e1..6ee3f57 100644
--- a/dev/benchmarks/macrobenchmarks/lib/src/cull_opacity.dart
+++ b/dev/benchmarks/macrobenchmarks/lib/src/cull_opacity.dart
@@ -21,6 +21,12 @@
   }
 
   @override
+  void dispose() {
+    _controller.dispose();
+    super.dispose();
+  }
+
+  @override
   Widget build(BuildContext context) {
     return Stack(children: List<Widget>.generate(50, (int i) => Positioned(
       left: 0,
diff --git a/dev/benchmarks/macrobenchmarks/test_driver/backdrop_filter_perf.dart b/dev/benchmarks/macrobenchmarks/test_driver/backdrop_filter_perf.dart
new file mode 100644
index 0000000..80361f3
--- /dev/null
+++ b/dev/benchmarks/macrobenchmarks/test_driver/backdrop_filter_perf.dart
@@ -0,0 +1,11 @@
+// Copyright 2019 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 'package:flutter_driver/driver_extension.dart';
+import 'package:macrobenchmarks/main.dart' as app;
+
+void main() {
+  enableFlutterDriverExtension();
+  app.main();
+}
diff --git a/dev/benchmarks/macrobenchmarks/test_driver/backdrop_filter_perf_test.dart b/dev/benchmarks/macrobenchmarks/test_driver/backdrop_filter_perf_test.dart
new file mode 100644
index 0000000..8be26c3
--- /dev/null
+++ b/dev/benchmarks/macrobenchmarks/test_driver/backdrop_filter_perf_test.dart
@@ -0,0 +1,16 @@
+// Copyright 2019 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 'package:macrobenchmarks/common.dart';
+
+import 'util.dart';
+
+void main() {
+  macroPerfTest(
+    'backdrop_filter_perf',
+    kBackdropFilterRouteName,
+    pageDelay: const Duration(seconds: 1),
+    duration: const Duration(seconds: 10),
+  );
+}
diff --git a/dev/devicelab/bin/tasks/backdrop_filter_perf__timeline_summary.dart b/dev/devicelab/bin/tasks/backdrop_filter_perf__timeline_summary.dart
new file mode 100644
index 0000000..4e7a306
--- /dev/null
+++ b/dev/devicelab/bin/tasks/backdrop_filter_perf__timeline_summary.dart
@@ -0,0 +1,14 @@
+// Copyright 2019 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:flutter_devicelab/tasks/perf_tests.dart';
+import 'package:flutter_devicelab/framework/adb.dart';
+import 'package:flutter_devicelab/framework/framework.dart';
+
+Future<void> main() async {
+  deviceOperatingSystem = DeviceOperatingSystem.android;
+  await task(createBackdropFilterPerfTest());
+}
diff --git a/dev/devicelab/lib/tasks/perf_tests.dart b/dev/devicelab/lib/tasks/perf_tests.dart
index 7fa6059..c0afb07 100644
--- a/dev/devicelab/lib/tasks/perf_tests.dart
+++ b/dev/devicelab/lib/tasks/perf_tests.dart
@@ -54,6 +54,14 @@
   ).run;
 }
 
+TaskFunction createBackdropFilterPerfTest() {
+  return PerfTest(
+    '${flutterDirectory.path}/dev/benchmarks/macrobenchmarks',
+    'test_driver/backdrop_filter_perf.dart',
+    'backdrop_filter_perf',
+  ).run;
+}
+
 TaskFunction createFlutterGalleryStartupTest() {
   return StartupTest(
     '${flutterDirectory.path}/examples/flutter_gallery',
diff --git a/dev/devicelab/manifest.yaml b/dev/devicelab/manifest.yaml
index f142262..5ecb300 100644
--- a/dev/devicelab/manifest.yaml
+++ b/dev/devicelab/manifest.yaml
@@ -171,6 +171,13 @@
     stage: devicelab
     required_agent_capabilities: ["mac/android"]
 
+  backdrop_filter_perf__timeline_summary:
+    description: >
+      Measures the runtime performance of backdrop filter blurs on Android.
+    stage: devicelab
+    required_agent_capabilities: ["mac/android"]
+    flaky: true
+
   flavors_test:
     description: >
       Checks that flavored builds work on Android.