blob: cca4a7f74ea623fd71792d42191a238d46feeb45 [file] [log] [blame]
// 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';
import 'package:usage/src/usage_impl_io.dart'; // ignore: implementation_imports
import 'package:usage/usage.dart';
import 'base/context.dart';
import 'base/utils.dart';
import 'globals.dart';
import 'version.dart';
// TODO(devoncarew): We'll want to find a way to send (sanitized) command parameters.
const String _kFlutterUA = 'UA-67589403-6';
class Usage {
/// 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);
bool runningOnCI = false;
// Many CI systems don't do a full git checkout.
if (version.endsWith('/unknown'))
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;
}
/// Returns [Usage] active in the current app context.
static Usage get instance => context[Usage] ?? (context[Usage] = new Usage());
Analytics _analytics;
bool _printedUsage = false;
bool _suppressAnalytics = false;
bool get isFirstRun => _analytics.firstRun;
bool get enabled => _analytics.enabled;
bool get suppressAnalytics => _suppressAnalytics || _analytics.firstRun;
/// Suppress analytics for this session.
set suppressAnalytics(bool value) {
_suppressAnalytics = value;
}
/// Enable or disable reporting analytics.
set enabled(bool value) {
_analytics.enabled = value;
}
void sendCommand(String command) {
if (!suppressAnalytics)
_analytics.sendScreenView(command);
}
void sendEvent(String category, String parameter) {
if (!suppressAnalytics)
_analytics.sendEvent(category, parameter);
}
void sendTiming(String category, String variableName, Duration duration) {
_analytics.sendTiming(variableName, duration.inMilliseconds, category: category);
}
UsageTimer startTimer(String event) {
if (suppressAnalytics)
return new _MockUsageTimer();
else
return new UsageTimer._(event, _analytics.startTimer(event, category: 'flutter'));
}
void sendException(dynamic exception, StackTrace trace) {
if (!suppressAnalytics)
_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));
}
void printUsage() {
if (_printedUsage)
return;
_printedUsage = true;
printStatus('');
printStatus('''
╔════════════════════════════════════════════════════════════════════════════╗
║ 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. ║
╚════════════════════════════════════════════════════════════════════════════╝
''', emphasis: true);
}
}
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() { }
}