Add an infobar if a session is being controlled by an automated test.

This infobar is only displayed if the browser is launched with the
--enable-automation switch. It also disables the developer mode extensions
warning bubble.

Design doc: https://docs.google.com/document/d/1JYj9K61UyxIYavR8_HATYIglR9T_rDwAtLLsD3fbDQg/edit

BUG=chromedriver:1625
TEST=launch with and without --enable-automation, and check for presence of automation infobar

Review-Url: https://codereview.chromium.org/2564973002
Cr-Commit-Position: refs/heads/master@{#450257}
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 96fd3fa4..b374e173 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -14780,6 +14780,11 @@
     <message name="IDS_FLAGS_ENABLE_MIDI_MANAGER_DYNAMIC_INSTANTIATION_DESCRIPTION" desc="Description for the flag to enable MIDIManager dynamic instantiation" translateable="false">
       Enable MIDIManager dynamic instantiation for Web MIDI.
     </message>
+
+    <!-- Automation info bar -->
+    <message name="IDS_CONTROLLED_BY_AUTOMATION" desc="Message shown when the browser session is being controlled by an automated test.">
+      Chrome is being controlled by automated test software.
+    </message>
   </messages>
  </release>
 </grit>
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 0700868..c32974bd 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -814,6 +814,8 @@
       "signin_view_controller_delegate.h",
       "singleton_tabs.cc",
       "singleton_tabs.h",
+      "startup/automation_infobar_delegate.cc",
+      "startup/automation_infobar_delegate.h",
       "startup/bad_flags_prompt.cc",
       "startup/bad_flags_prompt.h",
       "startup/google_api_keys_infobar_delegate.cc",
diff --git a/chrome/browser/ui/extensions/extension_message_bubble_factory.cc b/chrome/browser/ui/extensions/extension_message_bubble_factory.cc
index ddbfadf..384fcae 100644
--- a/chrome/browser/ui/extensions/extension_message_bubble_factory.cc
+++ b/chrome/browser/ui/extensions/extension_message_bubble_factory.cc
@@ -20,6 +20,7 @@
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/startup/startup_browser_creator.h"
 #include "chrome/common/channel_info.h"
+#include "chrome/common/chrome_switches.h"
 #include "components/version_info/version_info.h"
 #include "extensions/common/feature_switch.h"
 
@@ -84,6 +85,14 @@
   if (extensions::FeatureSwitch::force_dev_mode_highlighting()->IsEnabled())
     return true;
 
+  // If an automated test is controlling the browser, we don't show the dev mode
+  // bubble because it interferes with focus. This isn't a security concern
+  // because we'll instead show an (even scarier) infobar. See also
+  // AutomationInfoBarDelegate.
+  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+  if (command_line->HasSwitch(switches::kEnableAutomation))
+    return false;
+
 #if defined(OS_WIN)
   if (chrome::GetChannel() >= version_info::Channel::BETA)
     return true;
diff --git a/chrome/browser/ui/startup/automation_infobar_delegate.cc b/chrome/browser/ui/startup/automation_infobar_delegate.cc
new file mode 100644
index 0000000..c7da2cd
--- /dev/null
+++ b/chrome/browser/ui/startup/automation_infobar_delegate.cc
@@ -0,0 +1,41 @@
+// Copyright 2017 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.
+
+#include "chrome/browser/ui/startup/automation_infobar_delegate.h"
+
+#include "chrome/browser/devtools/global_confirm_info_bar.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/grit/generated_resources.h"
+#include "components/infobars/core/infobar.h"
+#include "components/strings/grit/components_strings.h"
+#include "ui/base/l10n/l10n_util.h"
+
+// static
+void AutomationInfoBarDelegate::Create() {
+  std::unique_ptr<ConfirmInfoBarDelegate> delegate(
+      new AutomationInfoBarDelegate());
+  GlobalConfirmInfoBar::Show(std::move(delegate));
+}
+
+AutomationInfoBarDelegate::AutomationInfoBarDelegate() {}
+
+AutomationInfoBarDelegate::~AutomationInfoBarDelegate() {}
+
+infobars::InfoBarDelegate::InfoBarIdentifier
+AutomationInfoBarDelegate::GetIdentifier() const {
+  return AUTOMATION_INFOBAR_DELEGATE;
+}
+
+bool AutomationInfoBarDelegate::ShouldExpire(
+    const NavigationDetails& details) const {
+  return false;
+}
+
+base::string16 AutomationInfoBarDelegate::GetMessageText() const {
+  return l10n_util::GetStringUTF16(IDS_CONTROLLED_BY_AUTOMATION);
+}
+
+int AutomationInfoBarDelegate::GetButtons() const {
+  return BUTTON_NONE;
+}
diff --git a/chrome/browser/ui/startup/automation_infobar_delegate.h b/chrome/browser/ui/startup/automation_infobar_delegate.h
new file mode 100644
index 0000000..bf60e2f4
--- /dev/null
+++ b/chrome/browser/ui/startup/automation_infobar_delegate.h
@@ -0,0 +1,33 @@
+// Copyright 2017 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.
+
+#ifndef CHROME_BROWSER_UI_STARTUP_AUTOMATION_INFOBAR_DELEGATE_H_
+#define CHROME_BROWSER_UI_STARTUP_AUTOMATION_INFOBAR_DELEGATE_H_
+
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "base/strings/string16.h"
+#include "components/infobars/core/confirm_infobar_delegate.h"
+#include "ui/gfx/vector_icons_public.h"
+#include "url/gurl.h"
+
+// An infobar to inform users if their browser is being controlled by an
+// automated test.
+class AutomationInfoBarDelegate : public ConfirmInfoBarDelegate {
+ public:
+  static void Create();
+
+ private:
+  AutomationInfoBarDelegate();
+  ~AutomationInfoBarDelegate() override;
+
+  infobars::InfoBarDelegate::InfoBarIdentifier GetIdentifier() const override;
+  bool ShouldExpire(const NavigationDetails& details) const override;
+  base::string16 GetMessageText() const override;
+  int GetButtons() const override;
+
+  DISALLOW_COPY_AND_ASSIGN(AutomationInfoBarDelegate);
+};
+
+#endif  // CHROME_BROWSER_UI_STARTUP_AUTOMATION_INFOBAR_DELEGATE_H_
diff --git a/chrome/browser/ui/startup/startup_browser_creator_impl.cc b/chrome/browser/ui/startup/startup_browser_creator_impl.cc
index 237ccc7..bd234d54 100644
--- a/chrome/browser/ui/startup/startup_browser_creator_impl.cc
+++ b/chrome/browser/ui/startup/startup_browser_creator_impl.cc
@@ -66,6 +66,7 @@
 #include "chrome/browser/ui/extensions/app_launch_params.h"
 #include "chrome/browser/ui/extensions/application_launch.h"
 #include "chrome/browser/ui/session_crashed_bubble.h"
+#include "chrome/browser/ui/startup/automation_infobar_delegate.h"
 #include "chrome/browser/ui/startup/bad_flags_prompt.h"
 #include "chrome/browser/ui/startup/default_browser_prompt.h"
 #include "chrome/browser/ui/startup/google_api_keys_infobar_delegate.h"
@@ -816,11 +817,19 @@
 #endif
   }
 
+  if (command_line_.HasSwitch(switches::kEnableAutomation))
+    AutomationInfoBarDelegate::Create();
+
   // The below info bars are only added to the first profile which is launched.
   // Other profiles might be restoring the browsing sessions asynchronously,
   // so we cannot add the info bars to the focused tabs here.
+  //
+  // These info bars are not shown when the browser is being controlled by
+  // automated tests, so that they don't interfere with tests that assume no
+  // info bars.
   if (is_process_startup == chrome::startup::IS_PROCESS_STARTUP &&
-      !command_line_.HasSwitch(switches::kTestType)) {
+      !command_line_.HasSwitch(switches::kTestType) &&
+      !command_line_.HasSwitch(switches::kEnableAutomation)) {
     chrome::ShowBadFlagsPrompt(browser);
     GoogleApiKeysInfoBarDelegate::Create(InfoBarService::FromWebContents(
         browser->tab_strip_model()->GetActiveWebContents()));
diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc
index 73bc421..b0d7e66 100644
--- a/chrome/common/chrome_switches.cc
+++ b/chrome/common/chrome_switches.cc
@@ -304,6 +304,9 @@
 const char kEnableAudioDebugRecordingsFromExtension[] =
     "enable-audio-debug-recordings-from-extension";
 
+// Inform users that their browser is being controlled by an automated test.
+const char kEnableAutomation[] = "enable-automation";
+
 // Enables the benchmarking extensions.
 const char kEnableBenchmarking[]            = "enable-benchmarking";
 
diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h
index df69b26..49b9680 100644
--- a/chrome/common/chrome_switches.h
+++ b/chrome/common/chrome_switches.h
@@ -102,6 +102,7 @@
 extern const char kEasyUnlockAppPath[];
 extern const char kEnableAddToShelf[];
 extern const char kEnableAudioDebugRecordingsFromExtension[];
+extern const char kEnableAutomation[];
 extern const char kEnableBenchmarking[];
 extern const char kEnableBookmarkUndo[];
 extern const char kEnableClearBrowsingDataCounters[];
diff --git a/chrome/test/chromedriver/chrome_launcher.cc b/chrome/test/chromedriver/chrome_launcher.cc
index b66294a5..224d609 100644
--- a/chrome/test/chromedriver/chrome_launcher.cc
+++ b/chrome/test/chromedriver/chrome_launcher.cc
@@ -62,32 +62,29 @@
 namespace {
 
 const char* const kCommonSwitches[] = {
-  "disable-infobars",
-  "disable-popup-blocking",
-  "ignore-certificate-errors",
-  "metrics-recording-only",
+    "disable-popup-blocking", "enable-automation", "ignore-certificate-errors",
+    "metrics-recording-only",
 };
 
 const char* const kDesktopSwitches[] = {
-  "disable-hang-monitor",
-  "disable-prompt-on-repost",
-  "disable-sync",
-  "no-first-run",
-  "disable-background-networking",
-  "disable-web-resources",
-  "safebrowsing-disable-auto-update",
-  "disable-client-side-phishing-detection",
-  "disable-default-apps",
-  "enable-logging",
-  "log-level=0",
-  "password-store=basic",
-  "use-mock-keychain",
-  "test-type=webdriver",
+    "disable-hang-monitor",
+    "disable-prompt-on-repost",
+    "disable-sync",
+    "no-first-run",
+    "disable-background-networking",
+    "disable-web-resources",
+    "safebrowsing-disable-auto-update",
+    "disable-client-side-phishing-detection",
+    "disable-default-apps",
+    "enable-logging",
+    "log-level=0",
+    "password-store=basic",
+    "use-mock-keychain",
+    "test-type=webdriver",
 };
 
 const char* const kAndroidSwitches[] = {
-  "disable-fre",
-  "enable-remote-debugging",
+    "disable-fre", "enable-remote-debugging",
 };
 
 #if defined(OS_LINUX)
diff --git a/components/infobars/core/infobar_delegate.h b/components/infobars/core/infobar_delegate.h
index 03fdf1e..6b476a64 100644
--- a/components/infobars/core/infobar_delegate.h
+++ b/components/infobars/core/infobar_delegate.h
@@ -144,6 +144,7 @@
     GROUPED_PERMISSION_INFOBAR_DELEGATE_ANDROID = 70,
     OFFLINE_PAGE_INFOBAR_DELEGATE = 71,
     SEARCH_GEOLOCATION_DISCLOSURE_INFOBAR_DELEGATE = 72,
+    AUTOMATION_INFOBAR_DELEGATE = 73,
   };
 
   // Describes navigation events, used to decide whether infobars should be
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index bf14c0a..8d6ded6 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -94529,6 +94529,7 @@
   <int value="70" label="GROUPED_PERMISSION_INFOBAR_DELEGATE_ANDROID"/>
   <int value="71" label="OFFLINE_PAGE_INFOBAR_DELEGATE"/>
   <int value="72" label="SEARCH_GEOLOCATION_DISCLOSURE_INFOBAR_DELEGATE"/>
+  <int value="73" label="AUTOMATION_INFOBAR_DELEGATE"/>
 </enum>
 
 <enum name="InfoBarResponse" type="int">