Commit c7b2eef8 authored by Evan Stade's avatar Evan Stade Committed by Commit Bot

WebLayer: componentize Android C++ app modal jsdialog code

TBR=avi@chromium.org

Bug: 1025256
Change-Id: I2cdc1c86559e3c9217326a452563946fcff149ea
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1972137Reviewed-by: default avatarEvan Stade <estade@chromium.org>
Reviewed-by: default avatarTheresa  <twellington@chromium.org>
Commit-Queue: Evan Stade <estade@chromium.org>
Cr-Commit-Position: refs/heads/master@{#727011}
parent 8f0096c5
...@@ -654,6 +654,8 @@ jumbo_static_library("ui") { ...@@ -654,6 +654,8 @@ jumbo_static_library("ui") {
"android/autofill/credit_card_scanner_view_android.h", "android/autofill/credit_card_scanner_view_android.h",
"android/chrome_http_auth_handler.cc", "android/chrome_http_auth_handler.cc",
"android/chrome_http_auth_handler.h", "android/chrome_http_auth_handler.h",
"android/chrome_javascript_app_modal_dialog_android.cc",
"android/chrome_javascript_app_modal_dialog_android.h",
"android/color_chooser_dialog_android.cc", "android/color_chooser_dialog_android.cc",
"android/content_settings/ads_blocked_infobar_delegate.cc", "android/content_settings/ads_blocked_infobar_delegate.cc",
"android/content_settings/ads_blocked_infobar_delegate.h", "android/content_settings/ads_blocked_infobar_delegate.h",
...@@ -715,8 +717,6 @@ jumbo_static_library("ui") { ...@@ -715,8 +717,6 @@ jumbo_static_library("ui") {
"android/infobars/translate_compact_infobar.h", "android/infobars/translate_compact_infobar.h",
"android/infobars/update_password_infobar.cc", "android/infobars/update_password_infobar.cc",
"android/infobars/update_password_infobar.h", "android/infobars/update_password_infobar.h",
"android/javascript_app_modal_dialog_android.cc",
"android/javascript_app_modal_dialog_android.h",
"android/javascript_dialog_android.cc", "android/javascript_dialog_android.cc",
"android/javascript_dialog_android.h", "android/javascript_dialog_android.h",
"android/login_handler_android.cc", "android/login_handler_android.cc",
......
// Copyright 2019 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/android/chrome_javascript_app_modal_dialog_android.h"
#include "base/android/jni_android.h"
#include "chrome/browser/android/tab_android.h"
#include "chrome/browser/ui/javascript_dialogs/chrome_javascript_native_app_modal_dialog_factory.h"
#include "components/app_modal/javascript_app_modal_dialog.h"
#include "components/app_modal/javascript_dialog_manager.h"
#include "components/app_modal/javascript_native_dialog_factory.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_delegate.h"
void ChromeJavascriptAppModalDialogAndroid::ShowAppModalDialog() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
TabAndroid* tab = TabAndroid::FromWebContents(dialog()->web_contents());
if (!tab) {
CancelAppModalDialog();
return;
}
DoShowAppModalDialog(tab->IsUserInteractable());
}
ChromeJavascriptAppModalDialogAndroid::
~ChromeJavascriptAppModalDialogAndroid() = default;
namespace {
class ChromeJavaScriptNativeDialogAndroidFactory
: public app_modal::JavaScriptNativeDialogFactory {
public:
ChromeJavaScriptNativeDialogAndroidFactory() = default;
~ChromeJavaScriptNativeDialogAndroidFactory() override = default;
private:
app_modal::NativeAppModalDialog* CreateNativeJavaScriptDialog(
app_modal::JavaScriptAppModalDialog* dialog) override {
dialog->web_contents()->GetDelegate()->ActivateContents(
dialog->web_contents());
return new ChromeJavascriptAppModalDialogAndroid(
base::android::AttachCurrentThread(), dialog,
dialog->web_contents()->GetTopLevelNativeWindow());
}
DISALLOW_COPY_AND_ASSIGN(ChromeJavaScriptNativeDialogAndroidFactory);
};
} // namespace
void InstallChromeJavaScriptNativeAppModalDialogFactory() {
app_modal::JavaScriptDialogManager::GetInstance()->SetNativeDialogFactory(
base::WrapUnique(new ChromeJavaScriptNativeDialogAndroidFactory));
}
// Copyright 2019 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_ANDROID_CHROME_JAVASCRIPT_APP_MODAL_DIALOG_ANDROID_H_
#define CHROME_BROWSER_UI_ANDROID_CHROME_JAVASCRIPT_APP_MODAL_DIALOG_ANDROID_H_
#include <memory>
#include "base/macros.h"
#include "components/app_modal/android/javascript_app_modal_dialog_android.h"
class ChromeJavascriptAppModalDialogAndroid
: public app_modal::JavascriptAppModalDialogAndroid {
public:
using JavascriptAppModalDialogAndroid::JavascriptAppModalDialogAndroid;
// NativeAppModalDialog:
void ShowAppModalDialog() override;
protected:
~ChromeJavascriptAppModalDialogAndroid() override;
private:
DISALLOW_COPY_AND_ASSIGN(ChromeJavascriptAppModalDialogAndroid);
};
#endif // CHROME_BROWSER_UI_ANDROID_CHROME_JAVASCRIPT_APP_MODAL_DIALOG_ANDROID_H_
...@@ -41,6 +41,18 @@ static_library("app_modal") { ...@@ -41,6 +41,18 @@ static_library("app_modal") {
deps += [ "//ui/views" ] deps += [ "//ui/views" ]
} }
if (is_android) {
sources += [
"android/javascript_app_modal_dialog_android.cc",
"android/javascript_app_modal_dialog_android.h",
]
deps += [
"//components/app_modal/android:jni_headers",
"//ui/android",
]
}
} }
source_set("unit_tests") { source_set("unit_tests") {
......
...@@ -9,6 +9,7 @@ import android.content.Context; ...@@ -9,6 +9,7 @@ import android.content.Context;
import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting;
import org.chromium.base.annotations.CalledByNative; import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.annotations.JNINamespace;
import org.chromium.base.annotations.NativeMethods; import org.chromium.base.annotations.NativeMethods;
import org.chromium.ui.base.WindowAndroid; import org.chromium.ui.base.WindowAndroid;
import org.chromium.ui.modaldialog.DialogDismissalCause; import org.chromium.ui.modaldialog.DialogDismissalCause;
...@@ -18,6 +19,7 @@ import org.chromium.ui.modaldialog.ModalDialogManager; ...@@ -18,6 +19,7 @@ import org.chromium.ui.modaldialog.ModalDialogManager;
* A dialog shown via JavaScript. This can be an alert dialog, a prompt dialog, a confirm dialog, * A dialog shown via JavaScript. This can be an alert dialog, a prompt dialog, a confirm dialog,
* or an onbeforeunload dialog. * or an onbeforeunload dialog.
*/ */
@JNINamespace("app_modal")
public class JavascriptAppModalDialog extends JavascriptModalDialog { public class JavascriptAppModalDialog extends JavascriptModalDialog {
private long mNativeDialogPointer; private long mNativeDialogPointer;
......
...@@ -2,15 +2,13 @@ ...@@ -2,15 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#include "chrome/browser/ui/android/javascript_app_modal_dialog_android.h" #include "components/app_modal/android/javascript_app_modal_dialog_android.h"
#include "base/android/jni_android.h" #include "base/android/jni_android.h"
#include "base/android/jni_string.h" #include "base/android/jni_string.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/memory/ptr_util.h" #include "base/memory/ptr_util.h"
#include "base/metrics/histogram_macros.h" #include "base/metrics/histogram_macros.h"
#include "chrome/browser/android/tab_android.h"
#include "chrome/browser/ui/javascript_dialogs/chrome_javascript_native_app_modal_dialog_factory.h"
#include "components/app_modal/android/jni_headers/JavascriptAppModalDialog_jni.h" #include "components/app_modal/android/jni_headers/JavascriptAppModalDialog_jni.h"
#include "components/app_modal/app_modal_dialog_queue.h" #include "components/app_modal/app_modal_dialog_queue.h"
#include "components/app_modal/javascript_app_modal_dialog.h" #include "components/app_modal/javascript_app_modal_dialog.h"
...@@ -28,24 +26,73 @@ using base::android::JavaParamRef; ...@@ -28,24 +26,73 @@ using base::android::JavaParamRef;
using base::android::ScopedJavaGlobalRef; using base::android::ScopedJavaGlobalRef;
using base::android::ScopedJavaLocalRef; using base::android::ScopedJavaLocalRef;
namespace app_modal {
JavascriptAppModalDialogAndroid::JavascriptAppModalDialogAndroid( JavascriptAppModalDialogAndroid::JavascriptAppModalDialogAndroid(
JNIEnv* env, JNIEnv* env,
app_modal::JavaScriptAppModalDialog* dialog, app_modal::JavaScriptAppModalDialog* dialog,
gfx::NativeWindow parent) gfx::NativeWindow parent)
: dialog_(dialog), : dialog_(dialog),
parent_jobject_weak_ref_(env, parent->GetJavaObject().obj()) { parent_jobject_weak_ref_(env, parent->GetJavaObject().obj()) {}
}
void JavascriptAppModalDialogAndroid::ShowAppModalDialog() { void JavascriptAppModalDialogAndroid::ShowAppModalDialog() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI); DoShowAppModalDialog(true);
}
void JavascriptAppModalDialogAndroid::ActivateAppModalDialog() {
ShowAppModalDialog();
}
void JavascriptAppModalDialogAndroid::CloseAppModalDialog() {
CancelAppModalDialog();
}
void JavascriptAppModalDialogAndroid::AcceptAppModalDialog() {
base::string16 prompt_text;
dialog_->OnAccept(prompt_text, false);
delete this;
}
void JavascriptAppModalDialogAndroid::DidAcceptAppModalDialog(
JNIEnv* env,
const JavaParamRef<jobject>&,
const JavaParamRef<jstring>& prompt,
bool should_suppress_js_dialogs) {
base::string16 prompt_text =
base::android::ConvertJavaStringToUTF16(env, prompt);
dialog_->OnAccept(prompt_text, should_suppress_js_dialogs);
delete this;
}
void JavascriptAppModalDialogAndroid::CancelAppModalDialog() {
dialog_->OnCancel(false);
delete this;
}
bool JavascriptAppModalDialogAndroid::IsShowing() const {
return true;
}
void JavascriptAppModalDialogAndroid::DidCancelAppModalDialog(
JNIEnv* env,
const JavaParamRef<jobject>&,
bool should_suppress_js_dialogs) {
dialog_->OnCancel(should_suppress_js_dialogs);
delete this;
}
const ScopedJavaGlobalRef<jobject>&
JavascriptAppModalDialogAndroid::GetDialogObject() const {
return dialog_jobject_;
}
void JavascriptAppModalDialogAndroid::DoShowAppModalDialog(
bool is_web_contents_foremost) {
JNIEnv* env = AttachCurrentThread(); JNIEnv* env = AttachCurrentThread();
// Keep a strong ref to the parent window while we make the call to java to // Keep a strong ref to the parent window while we make the call to java to
// display the dialog. // display the dialog.
ScopedJavaLocalRef<jobject> parent_jobj = parent_jobject_weak_ref_.get(env); ScopedJavaLocalRef<jobject> parent_jobj = parent_jobject_weak_ref_.get(env);
if (parent_jobj.is_null()) {
TabAndroid* tab = TabAndroid::FromWebContents(dialog_->web_contents());
if (parent_jobj.is_null() || !tab) {
CancelAppModalDialog(); CancelAppModalDialog();
return; return;
} }
...@@ -56,10 +103,10 @@ void JavascriptAppModalDialogAndroid::ShowAppModalDialog() { ...@@ -56,10 +103,10 @@ void JavascriptAppModalDialogAndroid::ShowAppModalDialog() {
ScopedJavaLocalRef<jstring> message = ScopedJavaLocalRef<jstring> message =
ConvertUTF16ToJavaString(env, dialog_->message_text()); ConvertUTF16ToJavaString(env, dialog_->message_text());
bool foremost = tab->IsUserInteractable();
switch (dialog_->javascript_dialog_type()) { switch (dialog_->javascript_dialog_type()) {
case content::JAVASCRIPT_DIALOG_TYPE_ALERT: { case content::JAVASCRIPT_DIALOG_TYPE_ALERT: {
UMA_HISTOGRAM_BOOLEAN("JSDialogs.IsForemost.Alert", foremost); UMA_HISTOGRAM_BOOLEAN("JSDialogs.IsForemost.Alert",
is_web_contents_foremost);
dialog_object = Java_JavascriptAppModalDialog_createAlertDialog( dialog_object = Java_JavascriptAppModalDialog_createAlertDialog(
env, title, message, dialog_->display_suppress_checkbox()); env, title, message, dialog_->display_suppress_checkbox());
break; break;
...@@ -70,14 +117,16 @@ void JavascriptAppModalDialogAndroid::ShowAppModalDialog() { ...@@ -70,14 +117,16 @@ void JavascriptAppModalDialogAndroid::ShowAppModalDialog() {
env, title, message, dialog_->is_reload(), env, title, message, dialog_->is_reload(),
dialog_->display_suppress_checkbox()); dialog_->display_suppress_checkbox());
} else { } else {
UMA_HISTOGRAM_BOOLEAN("JSDialogs.IsForemost.Confirm", foremost); UMA_HISTOGRAM_BOOLEAN("JSDialogs.IsForemost.Confirm",
is_web_contents_foremost);
dialog_object = Java_JavascriptAppModalDialog_createConfirmDialog( dialog_object = Java_JavascriptAppModalDialog_createConfirmDialog(
env, title, message, dialog_->display_suppress_checkbox()); env, title, message, dialog_->display_suppress_checkbox());
} }
break; break;
} }
case content::JAVASCRIPT_DIALOG_TYPE_PROMPT: { case content::JAVASCRIPT_DIALOG_TYPE_PROMPT: {
UMA_HISTOGRAM_BOOLEAN("JSDialogs.IsForemost.Prompt", foremost); UMA_HISTOGRAM_BOOLEAN("JSDialogs.IsForemost.Prompt",
is_web_contents_foremost);
ScopedJavaLocalRef<jstring> default_prompt_text = ScopedJavaLocalRef<jstring> default_prompt_text =
ConvertUTF16ToJavaString(env, dialog_->default_prompt_text()); ConvertUTF16ToJavaString(env, dialog_->default_prompt_text());
dialog_object = Java_JavascriptAppModalDialog_createPromptDialog( dialog_object = Java_JavascriptAppModalDialog_createPromptDialog(
...@@ -96,51 +145,14 @@ void JavascriptAppModalDialogAndroid::ShowAppModalDialog() { ...@@ -96,51 +145,14 @@ void JavascriptAppModalDialogAndroid::ShowAppModalDialog() {
env, dialog_object, parent_jobj, reinterpret_cast<intptr_t>(this)); env, dialog_object, parent_jobj, reinterpret_cast<intptr_t>(this));
} }
void JavascriptAppModalDialogAndroid::ActivateAppModalDialog() { JavascriptAppModalDialogAndroid::~JavascriptAppModalDialogAndroid() {
ShowAppModalDialog(); // In case the dialog is still displaying, tell it to close itself.
} // This can happen if you trigger a dialog but close the Tab before it's
// shown, and then accept the dialog.
void JavascriptAppModalDialogAndroid::CloseAppModalDialog() { if (!dialog_jobject_.is_null()) {
CancelAppModalDialog(); JNIEnv* env = AttachCurrentThread();
} Java_JavascriptAppModalDialog_dismiss(env, dialog_jobject_);
}
void JavascriptAppModalDialogAndroid::AcceptAppModalDialog() {
base::string16 prompt_text;
dialog_->OnAccept(prompt_text, false);
delete this;
}
void JavascriptAppModalDialogAndroid::DidAcceptAppModalDialog(
JNIEnv* env,
const JavaParamRef<jobject>&,
const JavaParamRef<jstring>& prompt,
bool should_suppress_js_dialogs) {
base::string16 prompt_text =
base::android::ConvertJavaStringToUTF16(env, prompt);
dialog_->OnAccept(prompt_text, should_suppress_js_dialogs);
delete this;
}
void JavascriptAppModalDialogAndroid::CancelAppModalDialog() {
dialog_->OnCancel(false);
delete this;
}
bool JavascriptAppModalDialogAndroid::IsShowing() const {
return true;
}
void JavascriptAppModalDialogAndroid::DidCancelAppModalDialog(
JNIEnv* env,
const JavaParamRef<jobject>&,
bool should_suppress_js_dialogs) {
dialog_->OnCancel(should_suppress_js_dialogs);
delete this;
}
const ScopedJavaGlobalRef<jobject>&
JavascriptAppModalDialogAndroid::GetDialogObject() const {
return dialog_jobject_;
} }
// static // static
...@@ -156,40 +168,4 @@ ScopedJavaLocalRef<jobject> JNI_JavascriptAppModalDialog_GetCurrentModalDialog( ...@@ -156,40 +168,4 @@ ScopedJavaLocalRef<jobject> JNI_JavascriptAppModalDialog_GetCurrentModalDialog(
return ScopedJavaLocalRef<jobject>(js_dialog->GetDialogObject()); return ScopedJavaLocalRef<jobject>(js_dialog->GetDialogObject());
} }
JavascriptAppModalDialogAndroid::~JavascriptAppModalDialogAndroid() { } // namespace app_modal
// In case the dialog is still displaying, tell it to close itself.
// This can happen if you trigger a dialog but close the Tab before it's
// shown, and then accept the dialog.
if (!dialog_jobject_.is_null()) {
JNIEnv* env = AttachCurrentThread();
Java_JavascriptAppModalDialog_dismiss(env, dialog_jobject_);
}
}
namespace {
class ChromeJavaScriptNativeDialogAndroidFactory
: public app_modal::JavaScriptNativeDialogFactory {
public:
ChromeJavaScriptNativeDialogAndroidFactory() {}
~ChromeJavaScriptNativeDialogAndroidFactory() override {}
private:
app_modal::NativeAppModalDialog* CreateNativeJavaScriptDialog(
app_modal::JavaScriptAppModalDialog* dialog) override {
dialog->web_contents()->GetDelegate()->ActivateContents(
dialog->web_contents());
return new JavascriptAppModalDialogAndroid(
base::android::AttachCurrentThread(),
dialog, dialog->web_contents()->GetTopLevelNativeWindow());
}
DISALLOW_COPY_AND_ASSIGN(ChromeJavaScriptNativeDialogAndroidFactory);
};
} // namespace
void InstallChromeJavaScriptNativeAppModalDialogFactory() {
app_modal::JavaScriptDialogManager::GetInstance()->SetNativeDialogFactory(
base::WrapUnique(new ChromeJavaScriptNativeDialogAndroidFactory));
}
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#ifndef CHROME_BROWSER_UI_ANDROID_JAVASCRIPT_APP_MODAL_DIALOG_ANDROID_H_ #ifndef COMPONENTS_APP_MODAL_ANDROID_JAVASCRIPT_APP_MODAL_DIALOG_ANDROID_H_
#define CHROME_BROWSER_UI_ANDROID_JAVASCRIPT_APP_MODAL_DIALOG_ANDROID_H_ #define COMPONENTS_APP_MODAL_ANDROID_JAVASCRIPT_APP_MODAL_DIALOG_ANDROID_H_
#include <memory> #include <memory>
...@@ -14,16 +14,14 @@ ...@@ -14,16 +14,14 @@
#include "ui/gfx/native_widget_types.h" #include "ui/gfx/native_widget_types.h"
namespace app_modal { namespace app_modal {
class JavaScriptAppModalDialog; class JavaScriptAppModalDialog;
}
class JavascriptAppModalDialogAndroid class JavascriptAppModalDialogAndroid : public NativeAppModalDialog {
: public app_modal::NativeAppModalDialog {
public: public:
JavascriptAppModalDialogAndroid( JavascriptAppModalDialogAndroid(JNIEnv* env,
JNIEnv* env, JavaScriptAppModalDialog* dialog,
app_modal::JavaScriptAppModalDialog* dialog, gfx::NativeWindow parent);
gfx::NativeWindow parent);
// NativeAppModalDialog: // NativeAppModalDialog:
void ShowAppModalDialog() override; void ShowAppModalDialog() override;
...@@ -45,16 +43,21 @@ class JavascriptAppModalDialogAndroid ...@@ -45,16 +43,21 @@ class JavascriptAppModalDialogAndroid
const base::android::ScopedJavaGlobalRef<jobject>& GetDialogObject() const; const base::android::ScopedJavaGlobalRef<jobject>& GetDialogObject() const;
private: protected:
// The object deletes itself. void DoShowAppModalDialog(bool is_web_contents_foremost);
JavaScriptAppModalDialog* dialog() { return dialog_.get(); }
~JavascriptAppModalDialogAndroid() override; ~JavascriptAppModalDialogAndroid() override;
std::unique_ptr<app_modal::JavaScriptAppModalDialog> dialog_; private:
std::unique_ptr<JavaScriptAppModalDialog> dialog_;
base::android::ScopedJavaGlobalRef<jobject> dialog_jobject_; base::android::ScopedJavaGlobalRef<jobject> dialog_jobject_;
JavaObjectWeakGlobalRef parent_jobject_weak_ref_; JavaObjectWeakGlobalRef parent_jobject_weak_ref_;
DISALLOW_COPY_AND_ASSIGN(JavascriptAppModalDialogAndroid); DISALLOW_COPY_AND_ASSIGN(JavascriptAppModalDialogAndroid);
}; };
} // namespace app_modal
#endif // CHROME_BROWSER_UI_ANDROID_JAVASCRIPT_APP_MODAL_DIALOG_ANDROID_H_ #endif // COMPONENTS_APP_MODAL_ANDROID_JAVASCRIPT_APP_MODAL_DIALOG_ANDROID_H_
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment