| 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 |