ScreenCapture for Android phase1, part II

The capture part has been landed in cl https://codereview.chromium.org/2125973002/.
This cl is to implement the control part in chrome/ and content/. The document
is here, https://goo.gl/QNH29g.
This cl proposes a pemission design on Android, including permission info bar
and head up notification, which will show up each time at starting screen capture
and user can check/stop the capture without leaving current page.
And all of these is behind a flag as an experimental feature.

BUG=487935

Review-Url: https://codereview.chromium.org/2123863004
Cr-Commit-Position: refs/heads/master@{#420679}
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 3a8b094..7fbd69b 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -3247,6 +3247,8 @@
       "media/protected_media_identifier_infobar_delegate_android.h",
       "media/webrtc/media_stream_infobar_delegate_android.cc",
       "media/webrtc/media_stream_infobar_delegate_android.h",
+      "media/webrtc/screen_capture_infobar_delegate_android.cc",
+      "media/webrtc/screen_capture_infobar_delegate_android.h",
       "metrics/android_metrics_provider.cc",
       "metrics/android_metrics_provider.h",
       "metrics/page_load_metrics_provider.cc",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 93ba8597..bc92340c 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -729,6 +729,9 @@
     {"enable-osk-overscroll", IDS_FLAGS_ENABLE_OSK_OVERSCROLL_NAME,
      IDS_FLAGS_ENABLE_OSK_OVERSCROLL_DESCRIPTION, kOsAndroid,
      SINGLE_VALUE_TYPE(switches::kEnableOSKOverscroll)},
+    {"enable-usermedia-screen-capturing", IDS_FLAGS_MEDIA_SCREEN_CAPTURE_NAME,
+     IDS_FLAGS_MEDIA_SCREEN_CAPTURE_DESCRIPTION, kOsAndroid,
+     FEATURE_VALUE_TYPE(chrome::android::kUserMediaScreenCapturing)},
 #endif
   // Native client is compiled out when DISABLE_NACL is defined.
 #if !defined(DISABLE_NACL)
diff --git a/chrome/browser/android/chrome_feature_list.cc b/chrome/browser/android/chrome_feature_list.cc
index faba55055..d48ebc2 100644
--- a/chrome/browser/android/chrome_feature_list.cc
+++ b/chrome/browser/android/chrome_feature_list.cc
@@ -64,6 +64,9 @@
 const base::Feature kAllBookmarksFeature{"AllBookmarks",
                                          base::FEATURE_ENABLED_BY_DEFAULT};
 
+const base::Feature kAndroidPayIntegrationV1{"AndroidPayIntegrationV1",
+                                             base::FEATURE_ENABLED_BY_DEFAULT};
+
 const base::Feature kDownloadsUiFeature{"DownloadsUi",
                                          base::FEATURE_DISABLED_BY_DEFAULT};
 
@@ -79,9 +82,6 @@
 const base::Feature kNTPFakeOmniboxTextFeature{
     "NTPFakeOmniboxText", base::FEATURE_DISABLED_BY_DEFAULT};
 
-const base::Feature kAndroidPayIntegrationV1{"AndroidPayIntegrationV1",
-                                             base::FEATURE_ENABLED_BY_DEFAULT};
-
 const base::Feature kPhysicalWebFeature{"PhysicalWeb",
                                         base::FEATURE_ENABLED_BY_DEFAULT};
 
@@ -100,9 +100,11 @@
 const base::Feature kSpecialLocaleWrapper{"SpecialLocaleWrapper",
                                           base::FEATURE_ENABLED_BY_DEFAULT};
 
-const base::Feature kTabReparenting {
-  "TabReparenting", base::FEATURE_ENABLED_BY_DEFAULT
-};
+const base::Feature kTabReparenting{"TabReparenting",
+                                    base::FEATURE_ENABLED_BY_DEFAULT};
+
+const base::Feature kUserMediaScreenCapturing{
+    "UserMediaScreenCapturing", base::FEATURE_DISABLED_BY_DEFAULT};
 
 static jboolean IsEnabled(JNIEnv* env,
                           const JavaParamRef<jclass>& clazz,
diff --git a/chrome/browser/android/chrome_feature_list.h b/chrome/browser/android/chrome_feature_list.h
index 17ebb4b..9e70a63 100644
--- a/chrome/browser/android/chrome_feature_list.h
+++ b/chrome/browser/android/chrome_feature_list.h
@@ -13,8 +13,8 @@
 namespace android {
 
 extern const base::Feature kAllBookmarksFeature;
-extern const base::Feature kDownloadsUiFeature;
 extern const base::Feature kAndroidPayIntegrationV1;
+extern const base::Feature kDownloadsUiFeature;
 extern const base::Feature kImportantSitesInCBD;
 extern const base::Feature kNTPMaterialDesign;
 extern const base::Feature kNTPOfflinePagesFeature;
@@ -26,6 +26,7 @@
 extern const base::Feature kSpecialLocaleFeature;
 extern const base::Feature kSpecialLocaleWrapper;
 extern const base::Feature kTabReparenting;
+extern const base::Feature kUserMediaScreenCapturing;
 
 bool RegisterChromeFeatureListJni(JNIEnv* env);
 
diff --git a/chrome/browser/android/tab_web_contents_delegate_android.cc b/chrome/browser/android/tab_web_contents_delegate_android.cc
index 52704a0..03c84d7 100644
--- a/chrome/browser/android/tab_web_contents_delegate_android.cc
+++ b/chrome/browser/android/tab_web_contents_delegate_android.cc
@@ -449,8 +449,8 @@
   content::WebContents* web_contents =
       content::WebContents::FromJavaWebContents(java_web_contents);
   scoped_refptr<MediaStreamCaptureIndicator> indicator =
-      MediaCaptureDevicesDispatcher::GetInstance()->
-          GetMediaStreamCaptureIndicator();
+      MediaCaptureDevicesDispatcher::GetInstance()
+          ->GetMediaStreamCaptureIndicator();
   return indicator->IsCapturingAudio(web_contents);
 }
 
@@ -460,7 +460,29 @@
   content::WebContents* web_contents =
       content::WebContents::FromJavaWebContents(java_web_contents);
   scoped_refptr<MediaStreamCaptureIndicator> indicator =
-      MediaCaptureDevicesDispatcher::GetInstance()->
-          GetMediaStreamCaptureIndicator();
+      MediaCaptureDevicesDispatcher::GetInstance()
+          ->GetMediaStreamCaptureIndicator();
   return indicator->IsCapturingVideo(web_contents);
 }
+
+jboolean IsCapturingScreen(JNIEnv* env,
+                           const JavaParamRef<jclass>& clazz,
+                           const JavaParamRef<jobject>& java_web_contents) {
+  content::WebContents* web_contents =
+      content::WebContents::FromJavaWebContents(java_web_contents);
+  scoped_refptr<MediaStreamCaptureIndicator> indicator =
+      MediaCaptureDevicesDispatcher::GetInstance()
+          ->GetMediaStreamCaptureIndicator();
+  return indicator->IsBeingMirrored(web_contents);
+}
+
+void NotifyStopped(JNIEnv* env,
+                   const JavaParamRef<jclass>& clazz,
+                   const JavaParamRef<jobject>& java_web_contents) {
+  content::WebContents* web_contents =
+      content::WebContents::FromJavaWebContents(java_web_contents);
+  scoped_refptr<MediaStreamCaptureIndicator> indicator =
+      MediaCaptureDevicesDispatcher::GetInstance()
+          ->GetMediaStreamCaptureIndicator();
+  indicator->NotifyStopped(web_contents);
+}
diff --git a/chrome/browser/media/webrtc/media_stream_capture_indicator.cc b/chrome/browser/media/webrtc/media_stream_capture_indicator.cc
index 105b6212..9e80983 100644
--- a/chrome/browser/media/webrtc/media_stream_capture_indicator.cc
+++ b/chrome/browser/media/webrtc/media_stream_capture_indicator.cc
@@ -114,11 +114,15 @@
       const content::MediaStreamDevices& devices);
 
   // Increment ref-counts up based on the type of each device provided.
-  void AddDevices(const content::MediaStreamDevices& devices);
+  void AddDevices(const content::MediaStreamDevices& devices,
+                  const base::Closure& close_callback);
 
   // Decrement ref-counts up based on the type of each device provided.
   void RemoveDevices(const content::MediaStreamDevices& devices);
 
+  // Helper to call |stop_callback_|.
+  void NotifyStopped();
+
  private:
   // content::WebContentsObserver overrides.
   void WebContentsDestroyed() override {
@@ -130,6 +134,7 @@
   int video_ref_count_;
   int mirroring_ref_count_;
 
+  base::Closure stop_callback_;
   base::WeakPtrFactory<WebContentsDeviceUsage> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(WebContentsDeviceUsage);
@@ -161,7 +166,7 @@
     DCHECK(!started_);
     started_ = true;
     if (device_usage_.get())
-      device_usage_->AddDevices(devices_);
+      device_usage_->AddDevices(devices_, close_callback);
     return 0;
   }
 
@@ -179,11 +184,11 @@
 }
 
 void MediaStreamCaptureIndicator::WebContentsDeviceUsage::AddDevices(
-    const content::MediaStreamDevices& devices) {
+    const content::MediaStreamDevices& devices,
+    const base::Closure& close_callback) {
   for (content::MediaStreamDevices::const_iterator it = devices.begin();
        it != devices.end(); ++it) {
-    if (it->type == content::MEDIA_TAB_AUDIO_CAPTURE ||
-        it->type == content::MEDIA_TAB_VIDEO_CAPTURE) {
+    if (content::IsScreenCaptureMediaType(it->type)) {
       ++mirroring_ref_count_;
     } else if (content::IsAudioInputMediaType(it->type)) {
       ++audio_ref_count_;
@@ -194,8 +199,10 @@
     }
   }
 
-  if (web_contents())
+  if (web_contents()) {
+    stop_callback_ = close_callback;
     web_contents()->NotifyNavigationStateChanged(content::INVALIDATE_TYPE_TAB);
+  }
 
   indicator_->UpdateNotificationUserInterface();
 }
@@ -204,8 +211,7 @@
     const content::MediaStreamDevices& devices) {
   for (content::MediaStreamDevices::const_iterator it = devices.begin();
        it != devices.end(); ++it) {
-    if (it->type == content::MEDIA_TAB_AUDIO_CAPTURE ||
-        it->type == content::MEDIA_TAB_VIDEO_CAPTURE) {
+    if (IsScreenCaptureMediaType(it->type)) {
       --mirroring_ref_count_;
     } else if (content::IsAudioInputMediaType(it->type)) {
       --audio_ref_count_;
@@ -224,6 +230,14 @@
   indicator_->UpdateNotificationUserInterface();
 }
 
+void MediaStreamCaptureIndicator::WebContentsDeviceUsage::NotifyStopped() {
+  if (!stop_callback_.is_null()) {
+    base::Closure callback = stop_callback_;
+    stop_callback_.Reset();
+    callback.Run();
+  }
+}
+
 MediaStreamCaptureIndicator::MediaStreamCaptureIndicator()
     : status_icon_(NULL),
       mic_image_(NULL),
@@ -297,6 +311,15 @@
   return usage && usage->IsMirroring();
 }
 
+void MediaStreamCaptureIndicator::NotifyStopped(
+    content::WebContents* web_contents) const {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+  WebContentsDeviceUsage* usage = usage_map_.get(web_contents);
+  DCHECK(usage);
+  usage->NotifyStopped();
+}
+
 void MediaStreamCaptureIndicator::UnregisterWebContents(
     WebContents* web_contents) {
   usage_map_.erase(web_contents);
diff --git a/chrome/browser/media/webrtc/media_stream_capture_indicator.h b/chrome/browser/media/webrtc/media_stream_capture_indicator.h
index 296d7d8..d68cd04 100644
--- a/chrome/browser/media/webrtc/media_stream_capture_indicator.h
+++ b/chrome/browser/media/webrtc/media_stream_capture_indicator.h
@@ -55,6 +55,9 @@
   // of media for remote broadcast).
   bool IsBeingMirrored(content::WebContents* web_contents) const;
 
+  // Called when STOP button in media capture notification is clicked.
+  void NotifyStopped(content::WebContents* web_contents) const;
+
  private:
   class UIDelegate;
   class WebContentsDeviceUsage;
diff --git a/chrome/browser/media/webrtc/media_stream_devices_controller_browsertest.cc b/chrome/browser/media/webrtc/media_stream_devices_controller_browsertest.cc
index 36dd8f6..2d95084d 100644
--- a/chrome/browser/media/webrtc/media_stream_devices_controller_browsertest.cc
+++ b/chrome/browser/media/webrtc/media_stream_devices_controller_browsertest.cc
@@ -109,17 +109,13 @@
 
   // Checks whether the devices returned in OnMediaStreamResponse contains a
   // microphone and/or camera device.
-  bool DevicesContains(bool needs_mic, bool needs_cam) {
-    bool has_mic = false;
-    bool has_cam = false;
+  bool CheckDevicesListContains(content::MediaStreamType type) {
     for (const auto& device : media_stream_devices_) {
-      if (device.type == content::MEDIA_DEVICE_AUDIO_CAPTURE)
-        has_mic = true;
-      if (device.type == content::MEDIA_DEVICE_VIDEO_CAPTURE)
-        has_cam = true;
+      if (device.type == type) {
+        return true;
+      }
     }
-
-    return needs_mic == has_mic && needs_cam == has_cam;
+    return false;
   }
 
   content::WebContents* GetWebContents() {
@@ -637,8 +633,10 @@
     // Check the media stream result is expected and the devices returned are
     // expected;
     ASSERT_EQ(test.ExpectedMediaStreamResult(), media_stream_result());
-    ASSERT_TRUE(
-        DevicesContains(test.ExpectMicAllowed(), test.ExpectCamAllowed()));
+    ASSERT_EQ(CheckDevicesListContains(content::MEDIA_DEVICE_AUDIO_CAPTURE),
+              test.ExpectMicAllowed());
+    ASSERT_EQ(CheckDevicesListContains(content::MEDIA_DEVICE_VIDEO_CAPTURE),
+              test.ExpectCamAllowed());
   }
 }
 
@@ -655,7 +653,8 @@
   ASSERT_FALSE(controller.IsAskingForVideo());
 
   ASSERT_EQ(content::MEDIA_DEVICE_OK, media_stream_result());
-  ASSERT_TRUE(DevicesContains(false, true));
+  ASSERT_FALSE(CheckDevicesListContains(content::MEDIA_DEVICE_AUDIO_CAPTURE));
+  ASSERT_TRUE(CheckDevicesListContains(content::MEDIA_DEVICE_VIDEO_CAPTURE));
 }
 
 IN_PROC_BROWSER_TEST_F(MediaStreamDevicesControllerTest,
@@ -672,7 +671,8 @@
   // Accept the prompt.
   controller.PermissionGranted();
   ASSERT_EQ(content::MEDIA_DEVICE_OK, media_stream_result());
-  ASSERT_TRUE(DevicesContains(true, true));
+  ASSERT_TRUE(CheckDevicesListContains(content::MEDIA_DEVICE_AUDIO_CAPTURE));
+  ASSERT_TRUE(CheckDevicesListContains(content::MEDIA_DEVICE_VIDEO_CAPTURE));
 
   // Check that re-requesting allows without prompting.
   MediaStreamDevicesController controller2(
@@ -683,7 +683,8 @@
   ASSERT_FALSE(controller2.IsAskingForVideo());
 
   ASSERT_EQ(content::MEDIA_DEVICE_OK, media_stream_result());
-  ASSERT_TRUE(DevicesContains(true, true));
+  ASSERT_TRUE(CheckDevicesListContains(content::MEDIA_DEVICE_AUDIO_CAPTURE));
+  ASSERT_TRUE(CheckDevicesListContains(content::MEDIA_DEVICE_VIDEO_CAPTURE));
 }
 
 // For Pepper request from insecure origin, even if it's ALLOW, it won't be
diff --git a/chrome/browser/media/webrtc/permission_bubble_media_access_handler.cc b/chrome/browser/media/webrtc/permission_bubble_media_access_handler.cc
index 1a9da71e..5b18553 100644
--- a/chrome/browser/media/webrtc/permission_bubble_media_access_handler.cc
+++ b/chrome/browser/media/webrtc/permission_bubble_media_access_handler.cc
@@ -24,7 +24,9 @@
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
+#include "chrome/browser/android/chrome_feature_list.h"
 #include "chrome/browser/media/webrtc/media_stream_infobar_delegate_android.h"
+#include "chrome/browser/media/webrtc/screen_capture_infobar_delegate_android.h"
 #include "chrome/browser/permissions/permission_update_infobar_delegate_android.h"
 #else
 #include "chrome/browser/permissions/permission_request_manager.h"
@@ -77,8 +79,14 @@
 bool PermissionBubbleMediaAccessHandler::SupportsStreamType(
     const content::MediaStreamType type,
     const extensions::Extension* extension) {
+#if BUILDFLAG(ANDROID_JAVA_UI)
+  return type == content::MEDIA_DEVICE_VIDEO_CAPTURE ||
+         type == content::MEDIA_DEVICE_AUDIO_CAPTURE ||
+         type == content::MEDIA_DESKTOP_VIDEO_CAPTURE;
+#else
   return type == content::MEDIA_DEVICE_VIDEO_CAPTURE ||
          type == content::MEDIA_DEVICE_AUDIO_CAPTURE;
+#endif
 }
 
 bool PermissionBubbleMediaAccessHandler::CheckMediaAccessPermission(
@@ -106,6 +114,18 @@
     const extensions::Extension* extension) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
+#if BUILDFLAG(ANDROID_JAVA_UI)
+  if (request.video_type == content::MEDIA_DESKTOP_VIDEO_CAPTURE &&
+      !base::FeatureList::IsEnabled(
+          chrome::android::kUserMediaScreenCapturing)) {
+    // If screen capturing isn't enabled on Android, we'll use "invalid state"
+    // as result, same as on desktop.
+    callback.Run(content::MediaStreamDevices(),
+                 content::MEDIA_DEVICE_INVALID_STATE, nullptr);
+    return;
+  }
+#endif  // BUILDFLAG(ANDROID_JAVA_UI)
+
   RequestsQueue& queue = pending_requests_[web_contents];
   queue.push_back(PendingAccessRequest(request, callback));
 
@@ -128,9 +148,20 @@
 
   DCHECK(!it->second.empty());
 
+  const content::MediaStreamRequest request = it->second.front().request;
+#if BUILDFLAG(ANDROID_JAVA_UI)
+  if (request.video_type == content::MEDIA_DESKTOP_VIDEO_CAPTURE) {
+    ScreenCaptureInfoBarDelegateAndroid::Create(
+        web_contents, request,
+        base::Bind(&PermissionBubbleMediaAccessHandler::OnAccessRequestResponse,
+                   base::Unretained(this), web_contents));
+    return;
+  }
+#endif
+
   std::unique_ptr<MediaStreamDevicesController> controller(
       new MediaStreamDevicesController(
-          web_contents, it->second.front().request,
+          web_contents, request,
           base::Bind(
               &PermissionBubbleMediaAccessHandler::OnAccessRequestResponse,
               base::Unretained(this), web_contents)));
diff --git a/chrome/browser/media/webrtc/screen_capture_infobar_delegate_android.cc b/chrome/browser/media/webrtc/screen_capture_infobar_delegate_android.cc
new file mode 100644
index 0000000..bdbc0be
--- /dev/null
+++ b/chrome/browser/media/webrtc/screen_capture_infobar_delegate_android.cc
@@ -0,0 +1,103 @@
+// 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.
+
+#include "chrome/browser/media/webrtc/screen_capture_infobar_delegate_android.h"
+
+#include "base/callback_helpers.h"
+#include "chrome/browser/infobars/infobar_service.h"
+#include "chrome/browser/media/webrtc/desktop_streams_registry.h"
+#include "chrome/browser/media/webrtc/media_capture_devices_dispatcher.h"
+#include "chrome/browser/media/webrtc/media_stream_capture_indicator.h"
+#include "chrome/grit/generated_resources.h"
+#include "chrome/grit/theme_resources.h"
+#include "components/infobars/core/infobar.h"
+#include "components/url_formatter/elide_url.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/common/media_stream_request.h"
+#include "third_party/webrtc/modules/desktop_capture/desktop_capture_types.h"
+#include "ui/base/l10n/l10n_util.h"
+
+// static
+void ScreenCaptureInfoBarDelegateAndroid::Create(
+    content::WebContents* web_contents,
+    const content::MediaStreamRequest& request,
+    const content::MediaResponseCallback& callback) {
+  InfoBarService* infobar_service =
+      InfoBarService::FromWebContents(web_contents);
+
+  infobar_service->AddInfoBar(infobar_service->CreateConfirmInfoBar(
+      std::unique_ptr<ConfirmInfoBarDelegate>(
+          new ScreenCaptureInfoBarDelegateAndroid(web_contents, request,
+                                                  callback))));
+}
+
+ScreenCaptureInfoBarDelegateAndroid::ScreenCaptureInfoBarDelegateAndroid(
+    content::WebContents* web_contents,
+    const content::MediaStreamRequest& request,
+    const content::MediaResponseCallback& callback)
+    : web_contents_(web_contents), request_(request), callback_(callback) {
+  DCHECK_EQ(content::MEDIA_DESKTOP_VIDEO_CAPTURE, request.video_type);
+}
+
+ScreenCaptureInfoBarDelegateAndroid::~ScreenCaptureInfoBarDelegateAndroid() {
+  if (!callback_.is_null()) {
+    callback_.Run(content::MediaStreamDevices(),
+                  content::MEDIA_DEVICE_FAILED_DUE_TO_SHUTDOWN, nullptr);
+  }
+}
+
+infobars::InfoBarDelegate::InfoBarIdentifier
+ScreenCaptureInfoBarDelegateAndroid::GetIdentifier() const {
+  return SCREEN_CAPTURE_INFOBAR_DELEGATE_ANDROID;
+}
+
+base::string16 ScreenCaptureInfoBarDelegateAndroid::GetMessageText() const {
+  return l10n_util::GetStringFUTF16(
+      IDS_MEDIA_CAPTURE_SCREEN,
+      url_formatter::FormatUrlForSecurityDisplay(request_.security_origin));
+}
+
+int ScreenCaptureInfoBarDelegateAndroid::GetIconId() const {
+  return IDR_INFOBAR_MEDIA_STREAM_SCREEN;
+}
+
+base::string16 ScreenCaptureInfoBarDelegateAndroid::GetButtonLabel(
+    InfoBarButton button) const {
+  return l10n_util::GetStringUTF16((button == BUTTON_OK) ? IDS_PERMISSION_ALLOW
+                                                         : IDS_PERMISSION_DENY);
+}
+
+bool ScreenCaptureInfoBarDelegateAndroid::Accept() {
+  RunCallback(content::MEDIA_DEVICE_OK);
+  return true;
+}
+
+bool ScreenCaptureInfoBarDelegateAndroid::Cancel() {
+  RunCallback(content::MEDIA_DEVICE_PERMISSION_DENIED);
+  return true;
+}
+
+void ScreenCaptureInfoBarDelegateAndroid::InfoBarDismissed() {
+  RunCallback(content::MEDIA_DEVICE_PERMISSION_DISMISSED);
+}
+
+void ScreenCaptureInfoBarDelegateAndroid::RunCallback(
+    content::MediaStreamRequestResult result) {
+  DCHECK(!callback_.is_null());
+
+  content::MediaStreamDevices devices;
+  std::unique_ptr<content::MediaStreamUI> ui;
+  if (result == content::MEDIA_DEVICE_OK) {
+    content::DesktopMediaID screen_id = content::DesktopMediaID(
+        content::DesktopMediaID::TYPE_SCREEN, webrtc::kFullDesktopScreenId);
+    devices.push_back(content::MediaStreamDevice(
+        content::MEDIA_DESKTOP_VIDEO_CAPTURE, screen_id.ToString(), "Screen"));
+
+    ui = MediaCaptureDevicesDispatcher::GetInstance()
+             ->GetMediaStreamCaptureIndicator()
+             ->RegisterMediaStream(web_contents_, devices);
+  }
+
+  base::ResetAndReturn(&callback_).Run(devices, result, std::move(ui));
+}
diff --git a/chrome/browser/media/webrtc/screen_capture_infobar_delegate_android.h b/chrome/browser/media/webrtc/screen_capture_infobar_delegate_android.h
new file mode 100644
index 0000000..9d187c09
--- /dev/null
+++ b/chrome/browser/media/webrtc/screen_capture_infobar_delegate_android.h
@@ -0,0 +1,51 @@
+// 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.
+
+#ifndef CHROME_BROWSER_MEDIA_WEBRTC_SCREEN_CAPTURE_INFOBAR_DELEGATE_ANDROID_H_
+#define CHROME_BROWSER_MEDIA_WEBRTC_SCREEN_CAPTURE_INFOBAR_DELEGATE_ANDROID_H_
+
+#include "chrome/browser/media/media_access_handler.h"
+#include "components/infobars/core/confirm_infobar_delegate.h"
+
+namespace content {
+class WebContents;
+}
+
+// An infobar that allows the user to share their screen with the current page.
+class ScreenCaptureInfoBarDelegateAndroid : public ConfirmInfoBarDelegate {
+ public:
+  // Creates a screen capture infobar and delegate and adds the infobar to the
+  // InfoBarService associated with |web_contents|.
+  static void Create(content::WebContents* web_contents,
+                     const content::MediaStreamRequest& request,
+                     const content::MediaResponseCallback& callback);
+
+ private:
+  ScreenCaptureInfoBarDelegateAndroid(
+      content::WebContents* web_contents,
+      const content::MediaStreamRequest& request,
+      const content::MediaResponseCallback& callback);
+  ~ScreenCaptureInfoBarDelegateAndroid() override;
+
+  // ConfirmInfoBarDelegate:
+  infobars::InfoBarDelegate::InfoBarIdentifier GetIdentifier() const override;
+  base::string16 GetMessageText() const override;
+  int GetIconId() const override;
+  base::string16 GetButtonLabel(InfoBarButton button) const override;
+  bool Accept() override;
+  bool Cancel() override;
+  void InfoBarDismissed() override;
+
+  // Runs |callback_|, passing it the |result|, and (if permission was granted)
+  // the appropriate stream device and UI object for video capture.
+  void RunCallback(content::MediaStreamRequestResult result);
+
+  content::WebContents* web_contents_;
+  const content::MediaStreamRequest request_;
+  content::MediaResponseCallback callback_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScreenCaptureInfoBarDelegateAndroid);
+};
+
+#endif  // CHROME_BROWSER_MEDIA_WEBRTC_SCREEN_CAPTURE_INFOBAR_DELEGATE_ANDROID_H_