1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/ui/android/javascript_app_modal_dialog_android.h"
6
7#include "base/android/jni_android.h"
8#include "base/android/jni_string.h"
9#include "base/strings/utf_string_conversions.h"
10
11#include "chrome/browser/browser_process.h"
12#include "chrome/browser/ui/app_modal_dialogs/app_modal_dialog_queue.h"
13#include "chrome/browser/ui/app_modal_dialogs/javascript_app_modal_dialog.h"
14#include "content/public/browser/browser_thread.h"
15#include "content/public/browser/web_contents.h"
16#include "content/public/common/javascript_message_type.h"
17#include "jni/JavascriptAppModalDialog_jni.h"
18#include "ui/base/android/window_android.h"
19
20using base::android::AttachCurrentThread;
21using base::android::ConvertUTF16ToJavaString;
22using base::android::ScopedJavaGlobalRef;
23using base::android::ScopedJavaLocalRef;
24using content::BrowserThread;
25
26// static
27NativeAppModalDialog* NativeAppModalDialog::CreateNativeJavaScriptPrompt(
28    JavaScriptAppModalDialog* dialog,
29    gfx::NativeWindow parent_window) {
30  return new JavascriptAppModalDialogAndroid(AttachCurrentThread(),
31      dialog, parent_window);
32}
33
34JavascriptAppModalDialogAndroid::JavascriptAppModalDialogAndroid(
35    JNIEnv* env,
36    JavaScriptAppModalDialog* dialog,
37    gfx::NativeWindow parent)
38    : dialog_(dialog),
39      parent_jobject_weak_ref_(env, parent->GetJavaObject().obj()) {
40}
41
42int JavascriptAppModalDialogAndroid::GetAppModalDialogButtons() const {
43  NOTIMPLEMENTED();
44  return 0;
45}
46
47void JavascriptAppModalDialogAndroid::ShowAppModalDialog() {
48  DCHECK_CURRENTLY_ON(BrowserThread::UI);
49
50  JNIEnv* env = AttachCurrentThread();
51  // Keep a strong ref to the parent window while we make the call to java to
52  // display the dialog.
53  ScopedJavaLocalRef<jobject> parent_jobj = parent_jobject_weak_ref_.get(env);
54  if (parent_jobj.is_null()) {
55    CancelAppModalDialog();
56    return;
57  }
58
59  ScopedJavaLocalRef<jobject> dialog_object;
60  ScopedJavaLocalRef<jstring> title =
61      ConvertUTF16ToJavaString(env, dialog_->title());
62  ScopedJavaLocalRef<jstring> message =
63      ConvertUTF16ToJavaString(env, dialog_->message_text());
64
65  switch (dialog_->javascript_message_type()) {
66    case content::JAVASCRIPT_MESSAGE_TYPE_ALERT: {
67      dialog_object = Java_JavascriptAppModalDialog_createAlertDialog(env,
68          title.obj(), message.obj(),
69          dialog_->display_suppress_checkbox());
70      break;
71    }
72    case content::JAVASCRIPT_MESSAGE_TYPE_CONFIRM: {
73      if (dialog_->is_before_unload_dialog()) {
74        dialog_object = Java_JavascriptAppModalDialog_createBeforeUnloadDialog(
75            env, title.obj(), message.obj(), dialog_->is_reload(),
76            dialog_->display_suppress_checkbox());
77      } else {
78        dialog_object = Java_JavascriptAppModalDialog_createConfirmDialog(env,
79            title.obj(), message.obj(),
80            dialog_->display_suppress_checkbox());
81      }
82      break;
83    }
84    case content::JAVASCRIPT_MESSAGE_TYPE_PROMPT: {
85      ScopedJavaLocalRef<jstring> default_prompt_text =
86          ConvertUTF16ToJavaString(env, dialog_->default_prompt_text());
87      dialog_object = Java_JavascriptAppModalDialog_createPromptDialog(env,
88          title.obj(), message.obj(),
89          dialog_->display_suppress_checkbox(), default_prompt_text.obj());
90      break;
91    }
92    default:
93      NOTREACHED();
94  }
95
96  // Keep a ref to the java side object until we get a confirm or cancel.
97  dialog_jobject_.Reset(dialog_object);
98
99  Java_JavascriptAppModalDialog_showJavascriptAppModalDialog(env,
100      dialog_object.obj(), parent_jobj.obj(),
101      reinterpret_cast<intptr_t>(this));
102}
103
104void JavascriptAppModalDialogAndroid::ActivateAppModalDialog() {
105  ShowAppModalDialog();
106}
107
108void JavascriptAppModalDialogAndroid::CloseAppModalDialog() {
109  CancelAppModalDialog();
110}
111
112void JavascriptAppModalDialogAndroid::AcceptAppModalDialog() {
113  base::string16 prompt_text;
114  dialog_->OnAccept(prompt_text, false);
115  delete this;
116}
117
118void JavascriptAppModalDialogAndroid::DidAcceptAppModalDialog(
119    JNIEnv* env, jobject, jstring prompt, bool should_suppress_js_dialogs) {
120  base::string16 prompt_text =
121      base::android::ConvertJavaStringToUTF16(env, prompt);
122  dialog_->OnAccept(prompt_text, should_suppress_js_dialogs);
123  delete this;
124}
125
126void JavascriptAppModalDialogAndroid::CancelAppModalDialog() {
127  dialog_->OnCancel(false);
128  delete this;
129}
130
131void JavascriptAppModalDialogAndroid::DidCancelAppModalDialog(
132    JNIEnv* env, jobject, bool should_suppress_js_dialogs) {
133  dialog_->OnCancel(should_suppress_js_dialogs);
134  delete this;
135}
136
137const ScopedJavaGlobalRef<jobject>&
138    JavascriptAppModalDialogAndroid::GetDialogObject() const {
139  return dialog_jobject_;
140}
141
142// static
143jobject GetCurrentModalDialog(JNIEnv* env, jclass clazz) {
144  AppModalDialog* dialog = AppModalDialogQueue::GetInstance()->active_dialog();
145  if (!dialog || !dialog->native_dialog())
146    return NULL;
147
148  JavascriptAppModalDialogAndroid* js_dialog =
149      static_cast<JavascriptAppModalDialogAndroid*>(dialog->native_dialog());
150  return js_dialog->GetDialogObject().obj();
151}
152
153// static
154bool JavascriptAppModalDialogAndroid::RegisterJavascriptAppModalDialog(
155    JNIEnv* env) {
156  return RegisterNativesImpl(env);
157}
158
159JavascriptAppModalDialogAndroid::~JavascriptAppModalDialogAndroid() {
160  // In case the dialog is still displaying, tell it to close itself.
161  // This can happen if you trigger a dialog but close the Tab before it's
162  // shown, and then accept the dialog.
163  if (!dialog_jobject_.is_null()) {
164    JNIEnv* env = AttachCurrentThread();
165    Java_JavascriptAppModalDialog_dismiss(env, dialog_jobject_.obj());
166  }
167}
168