OnionSoup: Migrate IPC message handler to Mojo in Android's RendererDateTimePicker

As a first step to moving content/renderer/renderer_date_time_picker to Blink,
this CL migrates IPC message handler to Mojo in RendererDateTimePicker first.
Major changes are as below,

  - Introduce date_time_picker.mojom with DateTimePicker interface.
  - Introduce DateTimeDialogValue struct in date_time_picker.mojom.
  - Move DateTimeSuggestion struct to date_time_picker.mojom.
  - Remove all IPC messages regarding DateTimePicker
    (content::DateTimeSuggestion and ViewHostMsg_DateTimeDialogValue_Params)

The following CL will move the date_time_picker Mojo to Blink.

Bug: 950157
Change-Id: If3c2f7fd2c0e71cd485c0372efbcff0348ffca9e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1564361
Reviewed-by: Dmitry Gozman <[email protected]>
Reviewed-by: Kinuko Yasuda <[email protected]>
Reviewed-by: Kentaro Hara <[email protected]>
Commit-Queue: Gyuyoung Kim <[email protected]>
Cr-Commit-Position: refs/heads/master@{#653861}
diff --git a/content/browser/android/date_time_chooser_android.cc b/content/browser/android/date_time_chooser_android.cc
index 5d0f044..c26d1bf 100644
--- a/content/browser/android/date_time_chooser_android.cc
+++ b/content/browser/android/date_time_chooser_android.cc
@@ -10,8 +10,9 @@
 #include "base/android/jni_string.h"
 #include "base/i18n/char_iterator.h"
 #include "base/i18n/unicodestring.h"
-#include "content/common/date_time_suggestion.h"
-#include "content/common/view_messages.h"
+#include "base/strings/utf_string_conversions.h"
+#include "content/browser/web_contents/web_contents_impl.h"
+#include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_view_host.h"
 #include "jni/DateTimeChooserAndroid_jni.h"
 #include "third_party/icu/source/common/unicode/uchar.h"
@@ -45,62 +46,84 @@
 namespace content {
 
 // DateTimeChooserAndroid implementation
-DateTimeChooserAndroid::DateTimeChooserAndroid()
-  : host_(NULL) {
+DateTimeChooserAndroid::DateTimeChooserAndroid(WebContentsImpl* web_contents)
+    : content::WebContentsObserver(web_contents),
+      date_time_picker_binding_(this) {
+  registry_.AddInterface(
+      base::BindRepeating(&DateTimeChooserAndroid::OnDateTimePickerRequest,
+                          base::Unretained(this)));
 }
 
 DateTimeChooserAndroid::~DateTimeChooserAndroid() {
 }
 
-void DateTimeChooserAndroid::ReplaceDateTime(JNIEnv* env,
-                                             const JavaRef<jobject>&,
-                                             jdouble value) {
-  host_->Send(new ViewMsg_ReplaceDateTime(host_->GetRoutingID(), value));
+void DateTimeChooserAndroid::OnDateTimePickerRequest(
+    mojom::DateTimePickerRequest request) {
+  // Disconnect the previous picker first.
+  date_time_picker_binding_.Close();
+
+  date_time_picker_binding_.Bind(std::move(request));
 }
 
-void DateTimeChooserAndroid::CancelDialog(JNIEnv* env,
-                                          const JavaRef<jobject>&) {
-  host_->Send(new ViewMsg_CancelDateTimeDialog(host_->GetRoutingID()));
-}
-
-void DateTimeChooserAndroid::ShowDialog(
-    gfx::NativeWindow native_window,
-    RenderViewHost* host,
-    ui::TextInputType dialog_type,
-    double dialog_value,
-    double min,
-    double max,
-    double step,
-    const std::vector<DateTimeSuggestion>& suggestions) {
-  host_ = host;
-
+void DateTimeChooserAndroid::OpenDateTimeDialog(
+    mojom::DateTimeDialogValuePtr value,
+    OpenDateTimeDialogCallback callback) {
   JNIEnv* env = AttachCurrentThread();
-  ScopedJavaLocalRef<jobjectArray> suggestions_array;
 
-  if (suggestions.size() > 0) {
-    suggestions_array =
-        Java_DateTimeChooserAndroid_createSuggestionsArray(env,
-                                                           suggestions.size());
-    for (size_t i = 0; i < suggestions.size(); ++i) {
-      const content::DateTimeSuggestion& suggestion = suggestions[i];
+  if (open_date_time_response_callback_) {
+    date_time_picker_binding_.ReportBadMessage(
+        "DateTimeChooserAndroid: Previous picker's binding isn't closed.");
+    return;
+  }
+  open_date_time_response_callback_ = std::move(callback);
+
+  ScopedJavaLocalRef<jobjectArray> suggestions_array;
+  if (value->suggestions.size() > 0) {
+    suggestions_array = Java_DateTimeChooserAndroid_createSuggestionsArray(
+        env, value->suggestions.size());
+    for (size_t i = 0; i < value->suggestions.size(); ++i) {
+      const mojom::DateTimeSuggestionPtr suggestion =
+          std::move(value->suggestions[i]);
       ScopedJavaLocalRef<jstring> localized_value = ConvertUTF16ToJavaString(
-          env, SanitizeSuggestionString(suggestion.localized_value));
+          env, SanitizeSuggestionString(
+                   base::ASCIIToUTF16(suggestion->localized_value)));
       ScopedJavaLocalRef<jstring> label = ConvertUTF16ToJavaString(
-          env, SanitizeSuggestionString(suggestion.label));
+          env, SanitizeSuggestionString(base::ASCIIToUTF16(suggestion->label)));
       Java_DateTimeChooserAndroid_setDateTimeSuggestionAt(
-          env, suggestions_array, i, suggestion.value, localized_value, label);
+          env, suggestions_array, i, suggestion->value, localized_value, label);
     }
   }
 
+  gfx::NativeWindow native_window = web_contents()->GetTopLevelNativeWindow();
+
   if (native_window && !(native_window->GetJavaObject()).is_null()) {
     j_date_time_chooser_.Reset(
         Java_DateTimeChooserAndroid_createDateTimeChooser(
             env, native_window->GetJavaObject(),
-            reinterpret_cast<intptr_t>(this), dialog_type, dialog_value, min,
-            max, step, suggestions_array));
+            reinterpret_cast<intptr_t>(this), value->dialog_type,
+            value->dialog_value, value->minimum, value->maximum, value->step,
+            suggestions_array));
   }
   if (j_date_time_chooser_.is_null())
-    ReplaceDateTime(env, j_date_time_chooser_, dialog_value);
+    std::move(open_date_time_response_callback_).Run(true, value->dialog_value);
+}
+
+void DateTimeChooserAndroid::ReplaceDateTime(JNIEnv* env,
+                                             const JavaRef<jobject>&,
+                                             jdouble value) {
+  std::move(open_date_time_response_callback_).Run(true, value);
+}
+
+void DateTimeChooserAndroid::CancelDialog(JNIEnv* env,
+                                          const JavaRef<jobject>&) {
+  std::move(open_date_time_response_callback_).Run(false, 0.0);
+}
+
+void DateTimeChooserAndroid::OnInterfaceRequestFromFrame(
+    content::RenderFrameHost* render_frame_host,
+    const std::string& interface_name,
+    mojo::ScopedMessagePipeHandle* interface_pipe) {
+  registry_.TryBindInterface(interface_name, interface_pipe);
 }
 
 }  // namespace content
diff --git a/content/browser/android/date_time_chooser_android.h b/content/browser/android/date_time_chooser_android.h
index f5da0e6..1886684 100644
--- a/content/browser/android/date_time_chooser_android.h
+++ b/content/browser/android/date_time_chooser_android.h
@@ -11,33 +11,34 @@
 
 #include "base/android/jni_weak_ref.h"
 #include "base/macros.h"
+#include "content/common/date_time_picker.mojom.h"
+#include "content/public/browser/web_contents_observer.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "services/service_manager/public/cpp/binder_registry.h"
 #include "ui/base/ime/text_input_type.h"
 #include "ui/gfx/native_widget_types.h"
 
 namespace content {
 
-class RenderViewHost;
-struct DateTimeSuggestion;
+class WebContentsImpl;
+class RenderFrameHost;
 
 // Android implementation for DateTimeChooser dialogs.
-class DateTimeChooserAndroid {
+class DateTimeChooserAndroid : public mojom::DateTimePicker,
+                               public WebContentsObserver {
  public:
-  DateTimeChooserAndroid();
-  ~DateTimeChooserAndroid();
+  explicit DateTimeChooserAndroid(WebContentsImpl* web_contents);
+  ~DateTimeChooserAndroid() override;
 
-  // DateTimeChooser implementation:
-  // Shows the dialog. |dialog_value| is the date/time value converted to a
+  void OnDateTimePickerRequest(mojom::DateTimePickerRequest request);
+
+  // content::mojom::DateTimePicker implementation:
+  // Shows the dialog. |value| is the date/time value converted to a
   // number as defined in HTML. (See blink::InputType::parseToNumber())
-  void ShowDialog(gfx::NativeWindow native_window,
-                  RenderViewHost* host,
-                  ui::TextInputType dialog_type,
-                  double dialog_value,
-                  double min,
-                  double max,
-                  double step,
-                  const std::vector<DateTimeSuggestion>& suggestions);
+  void OpenDateTimeDialog(mojom::DateTimeDialogValuePtr value,
+                          OpenDateTimeDialogCallback callback) override;
 
-  // Replaces the current value
+  // Replaces the current value.
   void ReplaceDateTime(JNIEnv* env,
                        const base::android::JavaRef<jobject>&,
                        jdouble value);
@@ -45,11 +46,21 @@
   // Closes the dialog without propagating any changes.
   void CancelDialog(JNIEnv* env, const base::android::JavaRef<jobject>&);
 
+  // WebContentsObserver overrides:
+  void OnInterfaceRequestFromFrame(
+      content::RenderFrameHost* render_frame_host,
+      const std::string& interface_name,
+      mojo::ScopedMessagePipeHandle* interface_pipe) override;
+
  private:
-  RenderViewHost* host_;
+  OpenDateTimeDialogCallback open_date_time_response_callback_;
 
   base::android::ScopedJavaGlobalRef<jobject> j_date_time_chooser_;
 
+  mojo::Binding<mojom::DateTimePicker> date_time_picker_binding_;
+
+  service_manager::BinderRegistry registry_;
+
   DISALLOW_COPY_AND_ASSIGN(DateTimeChooserAndroid);
 };
 
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index d43b70a..12e572a5 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -864,9 +864,6 @@
     IPC_MESSAGE_HANDLER(ViewHostMsg_RequestPpapiBrokerPermission,
                         OnRequestPpapiBrokerPermission)
 #endif
-#if defined(OS_ANDROID)
-    IPC_MESSAGE_HANDLER(ViewHostMsg_OpenDateTimeDialog, OnOpenDateTimeDialog)
-#endif
     IPC_MESSAGE_UNHANDLED(handled = false)
   IPC_END_MESSAGE_MAP()
 
@@ -2105,7 +2102,7 @@
   manifest_manager_host_.reset(new ManifestManagerHost(this));
 
 #if defined(OS_ANDROID)
-  date_time_chooser_.reset(new DateTimeChooserAndroid());
+  date_time_chooser_.reset(new DateTimeChooserAndroid(this));
 #endif
 
   // BrowserPluginGuest::Init needs to be called after this WebContents has
@@ -4834,16 +4831,6 @@
   page_importance_signals_ = signals;
 }
 
-#if defined(OS_ANDROID)
-void WebContentsImpl::OnOpenDateTimeDialog(
-    RenderViewHostImpl* source,
-    const ViewHostMsg_DateTimeDialogValue_Params& value) {
-  date_time_chooser_->ShowDialog(
-      GetTopLevelNativeWindow(), source, value.dialog_type, value.dialog_value,
-      value.minimum, value.maximum, value.step, value.suggestions);
-}
-#endif
-
 void WebContentsImpl::OnDomOperationResponse(RenderFrameHostImpl* source,
                                              const std::string& json_string) {
   // TODO(nick, lukasza): The notification below should probably be updated to
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h
index 12fad99..22085cc 100644
--- a/content/browser/web_contents/web_contents_impl.h
+++ b/content/browser/web_contents/web_contents_impl.h
@@ -74,8 +74,6 @@
 #include "content/public/browser/android/child_process_importance.h"
 #endif
 
-struct ViewHostMsg_DateTimeDialogValue_Params;
-
 namespace service_manager {
 class InterfaceProvider;
 }
@@ -1251,11 +1249,6 @@
                                    const std::string& protocol,
                                    const GURL& url,
                                    bool user_gesture);
-#if defined(OS_ANDROID)
-  void OnOpenDateTimeDialog(
-      RenderViewHostImpl* source,
-      const ViewHostMsg_DateTimeDialogValue_Params& value);
-#endif
   void OnDomOperationResponse(RenderFrameHostImpl* source,
                               const std::string& json_string);
   void OnUpdatePageImportanceSignals(RenderFrameHostImpl* source,