usage.dart 4.8 KB
Newer Older
1 2 3 4 5 6
// Copyright 2016 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';

7
import 'package:usage/src/usage_impl_io.dart'; // ignore: implementation_imports
8 9 10
import 'package:usage/usage.dart';

import 'base/context.dart';
11
import 'base/utils.dart';
12
import 'globals.dart';
13
import 'version.dart';
14 15 16

// TODO(devoncarew): We'll want to find a way to send (sanitized) command parameters.

17
const String _kFlutterUA = 'UA-67589403-6';
18 19

class Usage {
20 21 22 23
  /// Create a new Usage instance; [versionOverride] is used for testing.
  Usage({ String settingsName: 'flutter', String versionOverride }) {
    String version = versionOverride ?? FlutterVersion.getVersionString(whitelistBranchName: true);
    _analytics = new AnalyticsIO(_kFlutterUA, settingsName, version);
24 25 26 27

    bool runningOnCI = false;

    // Many CI systems don't do a full git checkout.
28
    if (version.endsWith('/unknown'))
29 30 31 32 33 34 35 36
      runningOnCI = true;

    // Check for common CI systems.
    if (isRunningOnBot)
      runningOnCI = true;

    // If we think we're running on a CI system, default to not sending analytics.
    _analytics.analyticsOpt = runningOnCI ? AnalyticsOpt.optIn : AnalyticsOpt.optOut;
37 38 39 40 41 42 43
  }

  /// Returns [Usage] active in the current app context.
  static Usage get instance => context[Usage] ?? (context[Usage] = new Usage());

  Analytics _analytics;

44
  bool _printedUsage = false;
45
  bool _suppressAnalytics = false;
46

47 48 49 50
  bool get isFirstRun => _analytics.firstRun;

  bool get enabled => _analytics.enabled;

51 52 53 54 55 56 57
  bool get suppressAnalytics => _suppressAnalytics || _analytics.firstRun;

  /// Suppress analytics for this session.
  set suppressAnalytics(bool value) {
    _suppressAnalytics = value;
  }

58 59 60 61 62 63
  /// Enable or disable reporting analytics.
  set enabled(bool value) {
    _analytics.enabled = value;
  }

  void sendCommand(String command) {
64
    if (!suppressAnalytics)
65 66 67 68
      _analytics.sendScreenView(command);
  }

  void sendEvent(String category, String parameter) {
69
    if (!suppressAnalytics)
70 71 72
      _analytics.sendEvent(category, parameter);
  }

73 74 75 76
  void sendTiming(String category, String variableName, Duration duration) {
    _analytics.sendTiming(variableName, duration.inMilliseconds, category: category);
  }

77
  UsageTimer startTimer(String event) {
78
    if (suppressAnalytics)
79 80
      return new _MockUsageTimer();
    else
81
      return new UsageTimer._(event, _analytics.startTimer(event, category: 'flutter'));
82 83 84
  }

  void sendException(dynamic exception, StackTrace trace) {
85
    if (!suppressAnalytics)
86 87 88 89 90 91 92 93 94 95 96 97 98 99
      _analytics.sendException('${exception.runtimeType}; ${sanitizeStacktrace(trace)}');
  }

  /// Fires whenever analytics data is sent over the network; public for testing.
  Stream<Map<String, dynamic>> get onSend => _analytics.onSend;

  /// Returns when the last analytics event has been sent, or after a fixed
  /// (short) delay, whichever is less.
  Future<Null> ensureAnalyticsSent() {
    // TODO(devoncarew): This may delay tool exit and could cause some analytics
    // events to not be reported. Perhaps we could send the analytics pings
    // out-of-process from flutter_tools?
    return _analytics.waitForLastPing(timeout: new Duration(milliseconds: 250));
  }
100 101 102 103 104 105 106 107

  void printUsage() {
    if (_printedUsage)
      return;
    _printedUsage = true;

    printStatus('');
    printStatus('''
Seth Ladd's avatar
Seth Ladd committed
108 109 110 111 112 113 114 115 116 117
  ╔════════════════════════════════════════════════════════════════════════════╗
  ║                 Welcome to Flutter! - https://flutter.io                   ║
  ║                                                                            ║
  ║ The Flutter tool anonymously reports feature usage statistics and basic    ║
  ║ crash reports to Google in order to help Google contribute improvements to ║
  ║ Flutter over time. See Google's privacy policy:                            
   https://www.google.com/intl/en/policies/privacy/                           ║
                                                                              
   Use "flutter config --no-analytics" to disable analytics reporting.        
  ╚════════════════════════════════════════════════════════════════════════════╝
118 119
  ''', emphasis: true);
  }
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
}

class UsageTimer {
  UsageTimer._(this.event, this._timer);

  final String event;
  final AnalyticsTimer _timer;

  void finish() {
    _timer.finish();
  }
}

class _MockUsageTimer implements UsageTimer {
  @override
  String event;
  @override
  AnalyticsTimer _timer;

  @override
  void finish() { }
}