1// Copyright 2014 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/password_manager/save_password_infobar_delegate.h"
6
7#include "base/metrics/histogram.h"
8#include "base/strings/utf_string_conversions.h"
9#include "chrome/browser/infobars/infobar_service.h"
10#include "chrome/browser/ui/sync/one_click_signin_helper.h"
11#include "chrome/grit/chromium_strings.h"
12#include "chrome/grit/generated_resources.h"
13#include "components/infobars/core/infobar.h"
14#include "components/password_manager/core/browser/password_form_manager.h"
15#include "components/signin/core/common/profile_management_switches.h"
16#include "content/public/browser/navigation_entry.h"
17#include "content/public/browser/web_contents.h"
18#include "google_apis/gaia/gaia_urls.h"
19#include "grit/theme_resources.h"
20#include "ui/base/l10n/l10n_util.h"
21
22// static
23void SavePasswordInfoBarDelegate::Create(
24    content::WebContents* web_contents,
25    scoped_ptr<password_manager::PasswordFormManager> form_to_save,
26    const std::string& uma_histogram_suffix) {
27#if defined(ENABLE_ONE_CLICK_SIGNIN)
28  // Don't show the password manager infobar if this form is for a google
29  // account and we are going to show the one-click signin infobar.
30  GURL realm(form_to_save->realm());
31  // TODO(mathp): Checking only against associated_username() causes a bug
32  // referenced here: crbug.com/133275
33  // TODO(vabr): The check IsEnableWebBasedSignin is a hack for the time when
34  // OneClickSignin is disabled. http://crbug.com/339804
35  if (((realm == GaiaUrls::GetInstance()->gaia_login_form_realm()) ||
36       (realm == GURL("https://www.google.com/"))) &&
37      switches::IsEnableWebBasedSignin() &&
38      OneClickSigninHelper::CanOffer(
39          web_contents,
40          OneClickSigninHelper::CAN_OFFER_FOR_INTERSTITAL_ONLY,
41          base::UTF16ToUTF8(form_to_save->associated_username()),
42          NULL))
43    return;
44#endif
45
46  InfoBarService::FromWebContents(web_contents)->AddInfoBar(
47      SavePasswordInfoBarDelegate::CreateInfoBar(
48          scoped_ptr<SavePasswordInfoBarDelegate>(
49              new SavePasswordInfoBarDelegate(form_to_save.Pass(),
50                                              uma_histogram_suffix))));
51}
52
53SavePasswordInfoBarDelegate::~SavePasswordInfoBarDelegate() {
54  UMA_HISTOGRAM_ENUMERATION("PasswordManager.InfoBarResponse",
55                            infobar_response_,
56                            password_manager::metrics_util::NUM_RESPONSE_TYPES);
57
58  password_manager::metrics_util::LogUIDismissalReason(infobar_response_);
59
60  // The shortest period for which the prompt needs to live, so that we don't
61  // consider it killed prematurely, as might happen, e.g., if a pre-rendered
62  // page gets swapped in (and the current WebContents is destroyed).
63  const base::TimeDelta kMinimumPromptDisplayTime =
64      base::TimeDelta::FromSeconds(1);
65
66  if (!uma_histogram_suffix_.empty()) {
67    password_manager::metrics_util::LogUMAHistogramEnumeration(
68        "PasswordManager.SavePasswordPromptResponse_" + uma_histogram_suffix_,
69        infobar_response_,
70        password_manager::metrics_util::NUM_RESPONSE_TYPES);
71    password_manager::metrics_util::LogUMAHistogramBoolean(
72        "PasswordManager.SavePasswordPromptDisappearedQuickly_" +
73            uma_histogram_suffix_,
74        timer_.Elapsed() < kMinimumPromptDisplayTime);
75  }
76}
77
78void SavePasswordInfoBarDelegate::SetUseAdditionalPasswordAuthentication(
79    bool use_additional_authentication) {
80  form_to_save_->SetUseAdditionalPasswordAuthentication(
81      use_additional_authentication);
82}
83
84SavePasswordInfoBarDelegate::SavePasswordInfoBarDelegate(
85    scoped_ptr<password_manager::PasswordFormManager> form_to_save,
86    const std::string& uma_histogram_suffix)
87    : ConfirmInfoBarDelegate(),
88      form_to_save_(form_to_save.Pass()),
89      infobar_response_(password_manager::metrics_util::NO_RESPONSE),
90      uma_histogram_suffix_(uma_histogram_suffix) {
91  if (!uma_histogram_suffix_.empty()) {
92    password_manager::metrics_util::LogUMAHistogramBoolean(
93        "PasswordManager.SavePasswordPromptDisplayed_" + uma_histogram_suffix_,
94        true);
95  }
96}
97
98#if !defined(OS_ANDROID)
99// On Android, the save password infobar supports an additional checkbox to
100// require additional authentication before autofilling a saved password.
101// Because of this non-standard UI, the Android version is special cased and
102// constructed in:
103// chrome/browser/ui/android/infobars/save_password_infobar.cc
104
105// static
106scoped_ptr<infobars::InfoBar> SavePasswordInfoBarDelegate::CreateInfoBar(
107    scoped_ptr<SavePasswordInfoBarDelegate> delegate) {
108  return ConfirmInfoBarDelegate::CreateInfoBar(
109      delegate.PassAs<ConfirmInfoBarDelegate>());
110}
111#endif
112
113bool SavePasswordInfoBarDelegate::ShouldExpire(
114    const NavigationDetails& details) const {
115  return !details.is_redirect &&
116         infobars::InfoBarDelegate::ShouldExpire(details);
117}
118
119int SavePasswordInfoBarDelegate::GetIconID() const {
120  return IDR_INFOBAR_SAVE_PASSWORD;
121}
122
123infobars::InfoBarDelegate::Type SavePasswordInfoBarDelegate::GetInfoBarType()
124    const {
125  return PAGE_ACTION_TYPE;
126}
127
128base::string16 SavePasswordInfoBarDelegate::GetMessageText() const {
129  return l10n_util::GetStringUTF16(IDS_PASSWORD_MANAGER_SAVE_PASSWORD_PROMPT);
130}
131
132base::string16 SavePasswordInfoBarDelegate::GetButtonLabel(
133    InfoBarButton button) const {
134  return l10n_util::GetStringUTF16((button == BUTTON_OK) ?
135      IDS_PASSWORD_MANAGER_SAVE_BUTTON : IDS_PASSWORD_MANAGER_BLACKLIST_BUTTON);
136}
137
138bool SavePasswordInfoBarDelegate::Accept() {
139  DCHECK(form_to_save_.get());
140  form_to_save_->Save();
141  infobar_response_ = password_manager::metrics_util::REMEMBER_PASSWORD;
142  return true;
143}
144
145bool SavePasswordInfoBarDelegate::Cancel() {
146  DCHECK(form_to_save_.get());
147  form_to_save_->PermanentlyBlacklist();
148  infobar_response_ = password_manager::metrics_util::NEVER_REMEMBER_PASSWORD;
149  return true;
150}
151
152void SavePasswordInfoBarDelegate::InfoBarDismissed() {
153  DCHECK(form_to_save_.get());
154  infobar_response_ = password_manager::metrics_util::INFOBAR_DISMISSED;
155}
156
157infobars::InfoBarDelegate::InfoBarAutomationType
158SavePasswordInfoBarDelegate::GetInfoBarAutomationType() const {
159  return PASSWORD_INFOBAR;
160}
161