OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/ui/javascript_dialogs/javascript_dialog_tab_helper.h" | 5 #include "chrome/browser/ui/javascript_dialogs/javascript_dialog_tab_helper.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/callback.h" | 8 #include "base/callback.h" |
9 #include "base/feature_list.h" | 9 #include "base/feature_list.h" |
10 #include "base/metrics/histogram_macros.h" | 10 #include "base/metrics/histogram_macros.h" |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
49 // That will clear the callback inside of JavaScriptDialog, and start the | 49 // That will clear the callback inside of JavaScriptDialog, and start the |
50 // JavaScriptDialog on its own path of destruction. CloseDialog() then calls | 50 // JavaScriptDialog on its own path of destruction. CloseDialog() then calls |
51 // ClearDialogInfo() which removes observers. | 51 // ClearDialogInfo() which removes observers. |
52 // | 52 // |
53 // If closing is initiated by the JavaScriptDialog, which is a self-deleting | 53 // If closing is initiated by the JavaScriptDialog, which is a self-deleting |
54 // object, then it will make its callback. The callback will have been wrapped | 54 // object, then it will make its callback. The callback will have been wrapped |
55 // within JavaScriptDialogTabHelper::RunJavaScriptDialog() to be a call to | 55 // within JavaScriptDialogTabHelper::RunJavaScriptDialog() to be a call to |
56 // JavaScriptDialogTabHelper::OnDialogClosed(), which, after doing the callback, | 56 // JavaScriptDialogTabHelper::OnDialogClosed(), which, after doing the callback, |
57 // again calls ClearDialogInfo() to remove observers. | 57 // again calls ClearDialogInfo() to remove observers. |
58 | 58 |
| 59 enum class JavaScriptDialogTabHelper::DismissalCause { |
| 60 // This is used for a UMA histogram. Please never alter existing values, only |
| 61 // append new ones. |
| 62 TAB_HELPER_DESTROYED = 0, |
| 63 SUBSEQUENT_DIALOG_SHOWN = 1, |
| 64 HANDLE_DIALOG_CALLED = 2, |
| 65 CANCEL_DIALOGS_CALLED = 3, |
| 66 TAB_HIDDEN = 4, |
| 67 BROWSER_SWITCHED = 5, |
| 68 DIALOG_BUTTON_CLICKED = 6, |
| 69 MAX, |
| 70 }; |
| 71 |
59 JavaScriptDialogTabHelper::JavaScriptDialogTabHelper( | 72 JavaScriptDialogTabHelper::JavaScriptDialogTabHelper( |
60 content::WebContents* web_contents) | 73 content::WebContents* web_contents) |
61 : content::WebContentsObserver(web_contents) { | 74 : content::WebContentsObserver(web_contents) { |
62 } | 75 } |
63 | 76 |
64 JavaScriptDialogTabHelper::~JavaScriptDialogTabHelper() { | 77 JavaScriptDialogTabHelper::~JavaScriptDialogTabHelper() { |
65 if (dialog_) | 78 if (dialog_) { |
66 CloseDialog(true /*suppress_callback*/, false, base::string16()); | 79 CloseDialog(true /*suppress_callback*/, false, base::string16(), |
| 80 DismissalCause::TAB_HELPER_DESTROYED); |
| 81 } |
67 } | 82 } |
68 | 83 |
69 void JavaScriptDialogTabHelper::SetDialogShownCallbackForTesting( | 84 void JavaScriptDialogTabHelper::SetDialogShownCallbackForTesting( |
70 base::Closure callback) { | 85 base::Closure callback) { |
71 dialog_shown_ = callback; | 86 dialog_shown_ = callback; |
72 } | 87 } |
73 | 88 |
74 void JavaScriptDialogTabHelper::RunJavaScriptDialog( | 89 void JavaScriptDialogTabHelper::RunJavaScriptDialog( |
75 content::WebContents* alerting_web_contents, | 90 content::WebContents* alerting_web_contents, |
76 const GURL& origin_url, | 91 const GURL& origin_url, |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
124 "A window.prompt() dialog generated by this page was suppressed " | 139 "A window.prompt() dialog generated by this page was suppressed " |
125 "because this page is not the active tab of the front window. " | 140 "because this page is not the active tab of the front window. " |
126 "Please make sure your dialogs are triggered by user interactions " | 141 "Please make sure your dialogs are triggered by user interactions " |
127 "to avoid this situation. " | 142 "to avoid this situation. " |
128 "https://www.chromestatus.com/feature/5637107137642496"); | 143 "https://www.chromestatus.com/feature/5637107137642496"); |
129 return; | 144 return; |
130 } | 145 } |
131 | 146 |
132 if (dialog_) { | 147 if (dialog_) { |
133 // There's already a dialog up; clear it out. | 148 // There's already a dialog up; clear it out. |
134 CloseDialog(false, false, base::string16()); | 149 CloseDialog(false, false, base::string16(), |
| 150 DismissalCause::SUBSEQUENT_DIALOG_SHOWN); |
135 } | 151 } |
136 | 152 |
137 base::string16 title = | 153 base::string16 title = |
138 AppModalDialogManager()->GetTitle(alerting_web_contents, origin_url); | 154 AppModalDialogManager()->GetTitle(alerting_web_contents, origin_url); |
139 dialog_callback_ = callback; | 155 dialog_callback_ = callback; |
| 156 message_type_ = message_type; |
140 dialog_ = JavaScriptDialog::Create( | 157 dialog_ = JavaScriptDialog::Create( |
141 parent_web_contents, alerting_web_contents, title, message_type, | 158 parent_web_contents, alerting_web_contents, title, message_type, |
142 message_text, default_prompt_text, | 159 message_text, default_prompt_text, |
143 base::Bind(&JavaScriptDialogTabHelper::OnDialogClosed, | 160 base::Bind(&JavaScriptDialogTabHelper::OnDialogClosed, |
144 base::Unretained(this), callback)); | 161 base::Unretained(this), callback)); |
145 | 162 |
146 BrowserList::AddObserver(this); | 163 BrowserList::AddObserver(this); |
147 | 164 |
148 // Message suppression is something that we don't give the user a checkbox | 165 // Message suppression is something that we don't give the user a checkbox |
149 // for any more. It was useful back in the day when dialogs were app-modal | 166 // for any more. It was useful back in the day when dialogs were app-modal |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
206 web_contents, is_reload, | 223 web_contents, is_reload, |
207 base::Bind(&SaveUnloadUmaStats, engagement_score, callback)); | 224 base::Bind(&SaveUnloadUmaStats, engagement_score, callback)); |
208 } | 225 } |
209 | 226 |
210 bool JavaScriptDialogTabHelper::HandleJavaScriptDialog( | 227 bool JavaScriptDialogTabHelper::HandleJavaScriptDialog( |
211 content::WebContents* web_contents, | 228 content::WebContents* web_contents, |
212 bool accept, | 229 bool accept, |
213 const base::string16* prompt_override) { | 230 const base::string16* prompt_override) { |
214 if (dialog_) { | 231 if (dialog_) { |
215 CloseDialog(false /*suppress_callback*/, accept, | 232 CloseDialog(false /*suppress_callback*/, accept, |
216 prompt_override ? *prompt_override : base::string16()); | 233 prompt_override ? *prompt_override : base::string16(), |
| 234 DismissalCause::HANDLE_DIALOG_CALLED); |
217 return true; | 235 return true; |
218 } | 236 } |
219 | 237 |
220 // Handle any app-modal dialogs being run by the app-modal dialog system. | 238 // Handle any app-modal dialogs being run by the app-modal dialog system. |
221 return AppModalDialogManager()->HandleJavaScriptDialog(web_contents, accept, | 239 return AppModalDialogManager()->HandleJavaScriptDialog(web_contents, accept, |
222 prompt_override); | 240 prompt_override); |
223 } | 241 } |
224 | 242 |
225 void JavaScriptDialogTabHelper::CancelDialogs( | 243 void JavaScriptDialogTabHelper::CancelDialogs( |
226 content::WebContents* web_contents, | 244 content::WebContents* web_contents, |
227 bool suppress_callbacks, | 245 bool suppress_callbacks, |
228 bool reset_state) { | 246 bool reset_state) { |
229 if (dialog_) | 247 if (dialog_) |
230 CloseDialog(suppress_callbacks, false, base::string16()); | 248 CloseDialog(suppress_callbacks, false, base::string16(), |
| 249 DismissalCause::CANCEL_DIALOGS_CALLED); |
231 | 250 |
232 // Cancel any app-modal dialogs being run by the app-modal dialog system. | 251 // Cancel any app-modal dialogs being run by the app-modal dialog system. |
233 return AppModalDialogManager()->CancelDialogs( | 252 return AppModalDialogManager()->CancelDialogs( |
234 web_contents, suppress_callbacks, reset_state); | 253 web_contents, suppress_callbacks, reset_state); |
235 } | 254 } |
236 | 255 |
237 void JavaScriptDialogTabHelper::WasHidden() { | 256 void JavaScriptDialogTabHelper::WasHidden() { |
238 if (dialog_) | 257 if (dialog_) { |
239 CloseDialog(false, false, base::string16()); | 258 CloseDialog(false, false, base::string16(), DismissalCause::TAB_HIDDEN); |
| 259 } |
240 } | 260 } |
241 | 261 |
242 void JavaScriptDialogTabHelper::OnBrowserSetLastActive(Browser* browser) { | 262 void JavaScriptDialogTabHelper::OnBrowserSetLastActive(Browser* browser) { |
243 if (dialog_ && !IsWebContentsForemost(web_contents())) | 263 if (dialog_ && !IsWebContentsForemost(web_contents())) { |
244 CloseDialog(false, false, base::string16()); | 264 CloseDialog(false, false, base::string16(), |
| 265 DismissalCause::BROWSER_SWITCHED); |
| 266 } |
| 267 } |
| 268 |
| 269 void JavaScriptDialogTabHelper::LogDialogDismissalCause( |
| 270 JavaScriptDialogTabHelper::DismissalCause cause) { |
| 271 switch (message_type_) { |
| 272 case content::JAVASCRIPT_MESSAGE_TYPE_ALERT: |
| 273 UMA_HISTOGRAM_ENUMERATION("JSDialogs.DismissalCause.Alert", |
| 274 static_cast<int>(cause), |
| 275 static_cast<int>(DismissalCause::MAX)); |
| 276 break; |
| 277 case content::JAVASCRIPT_MESSAGE_TYPE_CONFIRM: |
| 278 UMA_HISTOGRAM_ENUMERATION("JSDialogs.DismissalCause.Confirm", |
| 279 static_cast<int>(cause), |
| 280 static_cast<int>(DismissalCause::MAX)); |
| 281 break; |
| 282 case content::JAVASCRIPT_MESSAGE_TYPE_PROMPT: |
| 283 UMA_HISTOGRAM_ENUMERATION("JSDialogs.DismissalCause.Prompt", |
| 284 static_cast<int>(cause), |
| 285 static_cast<int>(DismissalCause::MAX)); |
| 286 break; |
| 287 } |
245 } | 288 } |
246 | 289 |
247 void JavaScriptDialogTabHelper::OnDialogClosed( | 290 void JavaScriptDialogTabHelper::OnDialogClosed( |
248 DialogClosedCallback callback, | 291 DialogClosedCallback callback, |
249 bool success, | 292 bool success, |
250 const base::string16& user_input) { | 293 const base::string16& user_input) { |
| 294 LogDialogDismissalCause(DismissalCause::DIALOG_BUTTON_CLICKED); |
251 callback.Run(success, user_input); | 295 callback.Run(success, user_input); |
252 | 296 |
253 ClearDialogInfo(); | 297 ClearDialogInfo(); |
254 } | 298 } |
255 | 299 |
256 void JavaScriptDialogTabHelper::CloseDialog(bool suppress_callback, | 300 void JavaScriptDialogTabHelper::CloseDialog(bool suppress_callback, |
257 bool success, | 301 bool success, |
258 const base::string16& user_input) { | 302 const base::string16& user_input, |
| 303 DismissalCause cause) { |
259 DCHECK(dialog_); | 304 DCHECK(dialog_); |
| 305 LogDialogDismissalCause(cause); |
260 | 306 |
261 dialog_->CloseDialogWithoutCallback(); | 307 dialog_->CloseDialogWithoutCallback(); |
262 if (!suppress_callback) | 308 if (!suppress_callback) |
263 dialog_callback_.Run(success, user_input); | 309 dialog_callback_.Run(success, user_input); |
264 | 310 |
265 ClearDialogInfo(); | 311 ClearDialogInfo(); |
266 } | 312 } |
267 | 313 |
268 void JavaScriptDialogTabHelper::ClearDialogInfo() { | 314 void JavaScriptDialogTabHelper::ClearDialogInfo() { |
269 dialog_.reset(); | 315 dialog_.reset(); |
270 dialog_callback_.Reset(); | 316 dialog_callback_.Reset(); |
271 BrowserList::RemoveObserver(this); | 317 BrowserList::RemoveObserver(this); |
272 } | 318 } |
OLD | NEW |