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

diff --git a/packages/flutter_tools/lib/src/commands/create.dart b/packages/flutter_tools/lib/src/commands/create.dart
index 142ec29..b4e3283 100644
--- a/packages/flutter_tools/lib/src/commands/create.dart
+++ b/packages/flutter_tools/lib/src/commands/create.dart
@@ -22,6 +22,7 @@
 import '../globals.dart';
 import '../ios/xcodeproj.dart';
 import '../plugins.dart';
+import '../project.dart';
 import '../runner/flutter_command.dart';
 import '../template.dart';
 import '../version.dart';
@@ -65,7 +66,7 @@
     );
     argParser.addOption(
       'org',
-      defaultsTo: 'com.yourcompany',
+      defaultsTo: 'com.example',
       help: 'The organization responsible for your new Flutter project, in reverse domain name notation.\n'
             'This string is used in Java package names and as prefix in the iOS bundle identifier.'
     );
@@ -135,7 +136,18 @@
     // TODO(goderbauer): Work-around for: https://github.com/dart-lang/path/issues/24
     if (fs.path.basename(dirPath) == '.')
       dirPath = fs.path.dirname(dirPath);
-    final String organization = argResults['org'];
+    String organization = argResults['org'];
+    if (!argResults.wasParsed('org')) {
+      final Set<String> existingOrganizations = await new FlutterProject(projectDir).organizationNames();
+      if (existingOrganizations.length == 1) {
+        organization = existingOrganizations.first;
+      } else if (1 < existingOrganizations.length) {
+        throwToolExit(
+          'Ambiguous organization in existing files: $existingOrganizations.\n'
+          'The --org command line argument must be specified to recreate project.'
+        );
+      }
+    }
     final String projectName = fs.path.basename(dirPath);
 
     String error =_validateProjectDir(dirPath, flutterRoot: flutterRoot);
diff --git a/packages/flutter_tools/lib/src/ios/mac.dart b/packages/flutter_tools/lib/src/ios/mac.dart
index 14fa5a3..a5639f7 100644
--- a/packages/flutter_tools/lib/src/ios/mac.dart
+++ b/packages/flutter_tools/lib/src/ios/mac.dart
@@ -393,10 +393,10 @@
   }
   if (result.xcodeBuildExecution != null &&
       result.xcodeBuildExecution.buildForPhysicalDevice &&
-      app.id?.contains('com.yourcompany') ?? false) {
+      app.id?.contains('com.example') ?? false) {
     printError('');
     printError('It appears that your application still contains the default signing identifier.');
-    printError("Try replacing 'com.yourcompany' with your signing id in Xcode:");
+    printError("Try replacing 'com.example' with your signing id in Xcode:");
     printError('  open ios/Runner.xcworkspace');
     return;
   }
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);
+}