Change default organization name to example.com in project templates (#14116)

diff --git a/packages/flutter_tools/lib/src/project.dart b/packages/flutter_tools/lib/src/project.dart
new file mode 100644
index 0000000..1fd1b4f
--- /dev/null
+++ b/packages/flutter_tools/lib/src/project.dart
@@ -0,0 +1,96 @@
+// Copyright 2018 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 'dart:convert';
+import 'base/file_system.dart';
+
+/// Represents the contents of a Flutter project at the specified [directory].
+class FlutterProject {
+  FlutterProject(this.directory);
+
+  /// The location of this project.
+  final Directory directory;
+
+  /// Asynchronously returns the organization names found in this project as
+  /// part of iOS product bundle identifier, Android application ID, or
+  /// Gradle group ID.
+  Future<Set<String>> organizationNames() async {
+    final List<String> candidates = await Future.wait(<Future<String>>[
+      ios.productBundleIdentifier(),
+      android.applicationId(),
+      android.group(),
+      example.android.applicationId(),
+      example.ios.productBundleIdentifier(),
+    ]);
+    return new Set<String>.from(
+      candidates.map(_organizationNameFromPackageName)
+                .where((String name) => name != null)
+    );
+  }
+
+  String _organizationNameFromPackageName(String packageName) {
+    if (packageName != null && 0 <= packageName.lastIndexOf('.'))
+      return packageName.substring(0, packageName.lastIndexOf('.'));
+    else
+      return null;
+  }
+
+  /// The iOS sub project of this project.
+  IosProject get ios => new IosProject(directory.childDirectory('ios'));
+
+  /// The Android sub project of this project.
+  AndroidProject get android => new AndroidProject(directory.childDirectory('android'));
+
+  /// The example sub project of this (plugin) project.
+  FlutterProject get example => new FlutterProject(directory.childDirectory('example'));
+}
+
+/// Represents the contents of the ios/ folder of a Flutter project.
+class IosProject {
+  static final RegExp _productBundleIdPattern = new RegExp(r'^\s*PRODUCT_BUNDLE_IDENTIFIER\s*=\s*(.*);\s*$');
+  IosProject(this.directory);
+
+  final Directory directory;
+
+  Future<String> productBundleIdentifier() {
+    final File projectFile = directory.childDirectory('Runner.xcodeproj').childFile('project.pbxproj');
+    return _firstMatchInFile(projectFile, _productBundleIdPattern).then((Match match) => match?.group(1));
+  }
+}
+
+/// Represents the contents of the android/ folder of a Flutter project.
+class AndroidProject {
+  static final RegExp _applicationIdPattern = new RegExp('^\\s*applicationId\\s+[\'\"](.*)[\'\"]\\s*\$');
+  static final RegExp _groupPattern = new RegExp('^\\s*group\\s+[\'\"](.*)[\'\"]\\s*\$');
+
+  AndroidProject(this.directory);
+
+  final Directory directory;
+
+  Future<String> applicationId() {
+    final File gradleFile = directory.childDirectory('app').childFile('build.gradle');
+    return _firstMatchInFile(gradleFile, _applicationIdPattern).then((Match match) => match?.group(1));
+  }
+
+  Future<String> group() {
+    final File gradleFile = directory.childFile('build.gradle');
+    return _firstMatchInFile(gradleFile, _groupPattern).then((Match match) => match?.group(1));
+  }
+}
+
+/// Asynchronously returns the first line-based match for [regExp] in [file].
+///
+/// Assumes UTF8 encoding.
+Future<Match> _firstMatchInFile(File file, RegExp regExp) async {
+  if (!await file.exists()) {
+    return null;
+  }
+  return file
+      .openRead()
+      .transform(UTF8.decoder)
+      .transform(const LineSplitter())
+      .map(regExp.firstMatch)
+      .firstWhere((Match match) => match != null, defaultValue: () => null);
+}