main.dart 5 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12
// Copyright 2017 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/material.dart';
import 'package:flutter/scheduler.dart';
import 'package:flutter/services.dart';
import 'package:flutter_driver/driver_extension.dart';

void main() {
  enableFlutterDriverExtension();
13
  debugPrint('Application starting...');
14 15 16 17 18 19 20 21
  runApp(new MyApp());
}

class MyApp extends StatefulWidget {
  @override
  State createState() => new MyAppState();
}

22
const MethodChannel channel = MethodChannel('texture');
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43

enum FrameState { initial, slow, afterSlow, fast, afterFast }

class MyAppState extends State<MyApp> with SingleTickerProviderStateMixin {
  int _widgetBuilds = 0;
  FrameState _state;
  String _summary = '';
  IconData _icon;
  double _flutterFrameRate;

  Future<Null> _summarizeStats() async {
    final double framesProduced = await channel.invokeMethod('getProducedFrameRate');
    final double framesConsumed = await channel.invokeMethod('getConsumedFrameRate');
    _summary = '''
Produced: ${framesProduced.toStringAsFixed(1)}fps
Consumed: ${framesConsumed.toStringAsFixed(1)}fps
Widget builds: $_widgetBuilds''';
  }

  Future<Null> _nextState() async {
    switch (_state) {
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
      case FrameState.initial:
        debugPrint('Starting .5x speed test...');
        _widgetBuilds = 0;
        _summary = 'Producing texture frames at .5x speed...';
        _state = FrameState.slow;
        _icon = Icons.stop;
        channel.invokeMethod('start', _flutterFrameRate ~/ 2);
        break;
      case FrameState.slow:
        debugPrint('Stopping .5x speed test...');
        await channel.invokeMethod('stop');
        await _summarizeStats();
        _icon = Icons.fast_forward;
        _state = FrameState.afterSlow;
        break;
      case FrameState.afterSlow:
        debugPrint('Starting 2x speed test...');
        _widgetBuilds = 0;
        _summary = 'Producing texture frames at 2x speed...';
        _state = FrameState.fast;
        _icon = Icons.stop;
        channel.invokeMethod('start', (_flutterFrameRate * 2).toInt());
        break;
      case FrameState.fast:
        debugPrint('Stopping 2x speed test...');
        await channel.invokeMethod('stop');
        await _summarizeStats();
        _state = FrameState.afterFast;
        _icon = Icons.replay;
        break;
      case FrameState.afterFast:
        debugPrint('Test complete.');
        _summary = 'Press play to start again';
        _state = FrameState.initial;
        _icon = Icons.play_arrow;
        break;
80 81 82 83 84 85 86 87 88 89
    }
    setState(() {});
  }

  @override
  void initState() {
    super.initState();
    _calibrate();
  }

90 91
  static const int calibrationTickCount = 600;

92 93
  /// Measures Flutter's frame rate.
  Future<Null> _calibrate() async {
94 95 96
    debugPrint('Awaiting calm (3 second pause)...');
    await new Future<Null>.delayed(const Duration(milliseconds: 3000));
    debugPrint('Calibrating...');
97 98 99
    DateTime startTime;
    int tickCount = 0;
    Ticker ticker;
100 101 102
    ticker = createTicker((Duration time) {
      tickCount += 1;
      if (tickCount == calibrationTickCount) { // about 10 seconds
103 104 105 106 107
        final Duration elapsed = new DateTime.now().difference(startTime);
        ticker.stop();
        ticker.dispose();
        setState(() {
          _flutterFrameRate = tickCount * 1000 / elapsed.inMilliseconds;
108
          debugPrint('Calibrated: frame rate ${_flutterFrameRate.toStringAsFixed(1)}fps.');
109 110 111
          _summary = '''
Flutter frame rate is ${_flutterFrameRate.toStringAsFixed(1)}fps.
Press play to produce texture frames.''';
112 113 114
          _icon = Icons.play_arrow;
          _state = FrameState.initial;
        });
115 116 117
      } else {
        if ((tickCount % (calibrationTickCount ~/ 20)) == 0)
          debugPrint('Calibrating... ${(100.0 * tickCount / calibrationTickCount).floor()}%');
118 119 120 121 122 123 124 125 126 127 128 129
      }
    });
    ticker.start();
    startTime = new DateTime.now();
    setState(() {
      _summary = 'Calibrating...';
      _icon = null;
    });
  }

  @override
  Widget build(BuildContext context) {
130
    _widgetBuilds += 1;
131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
    return new MaterialApp(
      home: new Scaffold(
        body: new Center(
          child: new Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              new Container(
                width: 300.0,
                height: 200.0,
                child: const Texture(textureId: 0),
              ),
              new Container(
                width: 300.0,
                height: 60.0,
                color: Colors.grey,
                child: new Center(
                  child: new Text(
                    _summary,
                    key: const ValueKey<String>('summary'),
                  ),
                ),
              ),
            ],
          ),
        ),
156
        floatingActionButton: _icon == null ? null : new FloatingActionButton(
157 158 159
          key: const ValueKey<String>('fab'),
          child: new Icon(_icon),
          onPressed: _nextState,
160
        ),
161 162 163 164
      ),
    );
  }
}