diff --git a/pkgs/unified_analytics/CHANGELOG.md b/pkgs/unified_analytics/CHANGELOG.md index aba5c821..56389af1 100644 --- a/pkgs/unified_analytics/CHANGELOG.md +++ b/pkgs/unified_analytics/CHANGELOG.md @@ -1,3 +1,7 @@ +## 5.8.1 + +- Check devtools config file for legacy opt out status + ## 5.8.0 - Fix template string for consent message diff --git a/pkgs/unified_analytics/lib/src/constants.dart b/pkgs/unified_analytics/lib/src/constants.dart index 24639343..48606f03 100644 --- a/pkgs/unified_analytics/lib/src/constants.dart +++ b/pkgs/unified_analytics/lib/src/constants.dart @@ -82,7 +82,7 @@ const int kLogFileLength = 2500; const String kLogFileName = 'dart-flutter-telemetry.log'; /// The current version of the package, should be in line with pubspec version. -const String kPackageVersion = '5.8.0'; +const String kPackageVersion = '5.8.1'; /// The minimum length for a session. const int kSessionDurationMinutes = 30; diff --git a/pkgs/unified_analytics/lib/src/utils.dart b/pkgs/unified_analytics/lib/src/utils.dart index b94599bc..455eb1e1 100644 --- a/pkgs/unified_analytics/lib/src/utils.dart +++ b/pkgs/unified_analytics/lib/src/utils.dart @@ -137,6 +137,8 @@ Directory? getHomeDirectory(FileSystem fs) { /// Dart: `$HOME/.dart/dartdev.json` /// /// Flutter: `$HOME/.flutter` +/// +/// Devtools: `$HOME/.flutter-devtools/.devtools` bool legacyOptOut({ required FileSystem fs, required Directory home, @@ -144,6 +146,8 @@ bool legacyOptOut({ final dartLegacyConfigFile = fs.file(p.join(home.path, '.dart', 'dartdev.json')); final flutterLegacyConfigFile = fs.file(p.join(home.path, '.flutter')); + final devtoolsLegacyConfigFile = + fs.file(p.join(home.path, '.flutter-devtools', '.devtools')); // Example of what the file looks like for dart // @@ -202,6 +206,38 @@ bool legacyOptOut({ } } + // Example of what the file looks like for devtools + // + // { + // "analyticsEnabled": false, <-- THIS USER HAS OPTED OUT + // "isFirstRun": false, + // "lastReleaseNotesVersion": "2.31.0", + // "2023-Q4": { + // "surveyActionTaken": false, + // "surveyShownCount": 0 + // } + // } + if (devtoolsLegacyConfigFile.existsSync()) { + try { + final devtoolsObj = + jsonDecode(devtoolsLegacyConfigFile.readAsStringSync()) + as Map; + if (devtoolsObj.containsKey('analyticsEnabled') && + devtoolsObj['analyticsEnabled'] == false) { + return true; + } + } on FormatException { + // In the case of an error when parsing the json file, return true + // which will result in the user being opted out of unified_analytics + // + // A corrupted file could mean they opted out previously but for some + // reason, the file was written incorrectly + return true; + } on FileSystemException { + return true; + } + } + return false; } diff --git a/pkgs/unified_analytics/pubspec.yaml b/pkgs/unified_analytics/pubspec.yaml index 85ce4a59..ef8808f6 100644 --- a/pkgs/unified_analytics/pubspec.yaml +++ b/pkgs/unified_analytics/pubspec.yaml @@ -4,7 +4,7 @@ description: >- to Google Analytics. # When updating this, keep the version consistent with the changelog and the # value in lib/src/constants.dart. -version: 5.8.0 +version: 5.8.1 repository: https://github.com/dart-lang/tools/tree/main/pkgs/unified_analytics environment: diff --git a/pkgs/unified_analytics/test/legacy_analytics_test.dart b/pkgs/unified_analytics/test/legacy_analytics_test.dart index 242700a3..6a8d309a 100644 --- a/pkgs/unified_analytics/test/legacy_analytics_test.dart +++ b/pkgs/unified_analytics/test/legacy_analytics_test.dart @@ -102,7 +102,7 @@ void main() { }); test('Honor legacy flutter analytics opt out', () { - // Create the file for the dart legacy opt out + // Create the file for the flutter legacy opt out final flutterLegacyConfigFile = home.childDirectory('.dart').childFile('dartdev.json'); flutterLegacyConfigFile.createSync(recursive: true); @@ -134,7 +134,7 @@ void main() { }); test('Telemetry enabled if legacy flutter analytics is enabled', () { - // Create the file for the dart legacy opt out + // Create the file for the flutter legacy opt out final flutterLegacyConfigFile = home.childDirectory('.dart').childFile('dartdev.json'); flutterLegacyConfigFile.createSync(recursive: true); @@ -165,6 +165,78 @@ void main() { expect(analytics.telemetryEnabled, true); }); + test('Honor legacy devtools analytics opt out', () { + // Create the file for the devtools legacy opt out + final devtoolsLegacyConfigFile = + home.childDirectory('.flutter-devtools').childFile('.devtools'); + devtoolsLegacyConfigFile.createSync(recursive: true); + devtoolsLegacyConfigFile.writeAsStringSync(''' +{ + "analyticsEnabled": false, + "isFirstRun": false, + "lastReleaseNotesVersion": "2.31.0", + "2023-Q4": { + "surveyActionTaken": false, + "surveyShownCount": 0 + } +} +'''); + + // The main analytics instance, other instances can be spawned within tests + // to test how to instances running together work + analytics = Analytics.test( + tool: initialTool, + homeDirectory: home, + measurementId: measurementId, + apiSecret: apiSecret, + flutterChannel: flutterChannel, + toolsMessageVersion: toolsMessageVersion, + toolsMessage: toolsMessage, + flutterVersion: flutterVersion, + dartVersion: dartVersion, + fs: fs, + platform: platform, + ); + + expect(analytics.telemetryEnabled, false); + }); + + test('Telemetry enabled if legacy devtools analytics is enabled', () { + // Create the file for the devtools legacy opt out + final devtoolsLegacyConfigFile = + home.childDirectory('.flutter-devtools').childFile('.devtools'); + devtoolsLegacyConfigFile.createSync(recursive: true); + devtoolsLegacyConfigFile.writeAsStringSync(''' +{ + "analyticsEnabled": true, + "isFirstRun": false, + "lastReleaseNotesVersion": "2.31.0", + "2023-Q4": { + "surveyActionTaken": false, + "surveyShownCount": 0 + } +} +'''); + + // The main analytics instance, other instances can be spawned within tests + // to test how to instances running together work + analytics = Analytics.test( + tool: initialTool, + homeDirectory: home, + measurementId: measurementId, + apiSecret: apiSecret, + flutterChannel: flutterChannel, + toolsMessageVersion: toolsMessageVersion, + toolsMessage: toolsMessage, + flutterVersion: flutterVersion, + dartVersion: dartVersion, + fs: fs, + platform: platform, + ); + + expect(analytics.telemetryEnabled, true); + }); + test('Telemetry disabled if dart config file corrupted', () { // Create the file for the dart legacy opt out with text that // is not valid JSON @@ -199,8 +271,46 @@ NOT VALID JSON expect(analytics.telemetryEnabled, false); }); + test('Telemetry disabled if devtools config file corrupted', () { + // Create the file for the devtools legacy opt out with text that + // is not valid JSON + final devtoolsLegacyConfigFile = + home.childDirectory('.flutter-devtools').childFile('.devtools'); + devtoolsLegacyConfigFile.createSync(recursive: true); + devtoolsLegacyConfigFile.writeAsStringSync(''' +NOT VALID JSON +{ + "analyticsEnabled": true, + "isFirstRun": false, + "lastReleaseNotesVersion": "2.31.0", + "2023-Q4": { + "surveyActionTaken": false, + "surveyShownCount": 0 + } +} +'''); + + // The main analytics instance, other instances can be spawned within tests + // to test how to instances running together work + analytics = Analytics.test( + tool: initialTool, + homeDirectory: home, + measurementId: measurementId, + apiSecret: apiSecret, + flutterChannel: flutterChannel, + toolsMessageVersion: toolsMessageVersion, + toolsMessage: toolsMessage, + flutterVersion: flutterVersion, + dartVersion: dartVersion, + fs: fs, + platform: platform, + ); + + expect(analytics.telemetryEnabled, false); + }); + test('Telemetry disabled if flutter config file corrupted', () { - // Create the file for the dart legacy opt out with text that + // Create the file for the flutter legacy opt out with text that // is not valid JSON final fluttterLegacyConfigFile = home.childDirectory('.dart').childFile('dartdev.json');