Chromium Code Reviews| Index: chrome/browser/ui/passwords/password_bubble_experiment.cc |
| diff --git a/chrome/browser/ui/passwords/password_bubble_experiment.cc b/chrome/browser/ui/passwords/password_bubble_experiment.cc |
| index 276a038e6a4e20cef8503e302217bc8bb390dbad..dc1bcc1312fb1065fb33beab4a873392d6f481e7 100644 |
| --- a/chrome/browser/ui/passwords/password_bubble_experiment.cc |
| +++ b/chrome/browser/ui/passwords/password_bubble_experiment.cc |
| @@ -6,9 +6,7 @@ |
| #include "base/metrics/field_trial.h" |
| #include "base/prefs/pref_service.h" |
| -#include "base/rand_util.h" |
| #include "base/strings/string_number_conversions.h" |
| -#include "base/time/time.h" |
| #include "chrome/common/pref_names.h" |
| #include "components/pref_registry/pref_registry_syncable.h" |
| #include "components/variations/variations_associated_data.h" |
| @@ -16,190 +14,44 @@ |
| namespace password_bubble_experiment { |
| namespace { |
| -bool IsNegativeEvent(password_manager::metrics_util::UIDismissalReason reason) { |
| - return (reason == password_manager::metrics_util::NO_DIRECT_INTERACTION || |
| - reason == password_manager::metrics_util::CLICKED_NOPE || |
| - reason == password_manager::metrics_util::CLICKED_NEVER); |
| -} |
| - |
| -// "TimeSpan" experiment ----------------------------------------------------- |
| - |
| -bool ExtractTimeSpanParams(base::TimeDelta* time_delta, int* nopes_limit) { |
| - std::map<std::string, std::string> params; |
| - bool retrieved = variations::GetVariationParams(kExperimentName, ¶ms); |
| - if (!retrieved) |
| - return false; |
| - int days = 0; |
| - if (!base::StringToInt(params[kParamTimeSpan], &days) || |
| - !base::StringToInt(params[kParamTimeSpanNopeThreshold], nopes_limit)) |
| - return false; |
| - *time_delta = base::TimeDelta::FromDays(days); |
| - return true; |
| -} |
| - |
| -bool OverwriteTimeSpanPrefsIfNeeded(PrefService* prefs, |
| - base::TimeDelta time_span) { |
| - base::Time beginning = base::Time::FromInternalValue( |
| - prefs->GetInt64(prefs::kPasswordBubbleTimeStamp)); |
| - base::Time now = base::Time::Now(); |
| - if (beginning + time_span < now) { |
| - prefs->SetInt64(prefs::kPasswordBubbleTimeStamp, now.ToInternalValue()); |
| - prefs->SetInteger(prefs::kPasswordBubbleNopesCount, 0); |
| - return true; |
| - } |
| - return false; |
| -} |
| - |
| -// If user dismisses the bubble >= kParamTimeSpanNopeThreshold times during |
| -// kParamTimeSpan days then the bubble isn't shown until the end of this time |
| -// span. |
| -bool ShouldShowBubbleTimeSpanExperiment(PrefService* prefs) { |
| - base::TimeDelta time_span; |
| - int nopes_limit = 0; |
| - if (!ExtractTimeSpanParams(&time_span, &nopes_limit)) { |
| - VLOG(2) << "Can't read parameters for " |
| - << kExperimentName << " experiment"; |
| - return true; |
| - } |
| - // Check if the new time span has started. |
| - if (OverwriteTimeSpanPrefsIfNeeded(prefs, time_span)) |
| - return true; |
| - int current_nopes = prefs->GetInteger(prefs::kPasswordBubbleNopesCount); |
| - return current_nopes < nopes_limit; |
| -} |
| - |
| -// Increase the "Nope" counter in prefs and start a new time span if needed. |
| -void UpdateTimeSpanPrefs( |
| - PrefService* prefs, |
| - password_manager::metrics_util::UIDismissalReason reason) { |
| - if (!IsNegativeEvent(reason)) |
| - return; |
| - base::TimeDelta time_span; |
| - int nopes_limit = 0; |
| - if (!ExtractTimeSpanParams(&time_span, &nopes_limit)) { |
| - VLOG(2) << "Can't read parameters for " |
| - << kExperimentName << " experiment"; |
| - return; |
| - } |
| - OverwriteTimeSpanPrefsIfNeeded(prefs, time_span); |
| - int current_nopes = prefs->GetInteger(prefs::kPasswordBubbleNopesCount); |
| - prefs->SetInteger(prefs::kPasswordBubbleNopesCount, current_nopes + 1); |
| -} |
| - |
| -// "Probability" experiment -------------------------------------------------- |
| - |
| -bool ExtractProbabilityParams(unsigned* history_length, unsigned* saves) { |
| - std::map<std::string, std::string> params; |
| - bool retrieved = variations::GetVariationParams(kExperimentName, ¶ms); |
| - if (!retrieved) |
| - return false; |
| - return base::StringToUint(params[kParamProbabilityInteractionsCount], |
| - history_length) && |
| - base::StringToUint(params[kParamProbabilityFakeSaves], saves); |
| -} |
| - |
| -std::vector<int> ReadInteractionHistory(PrefService* prefs) { |
| - std::vector<int> interactions; |
| - const base::ListValue* list = |
| - prefs->GetList(prefs::kPasswordBubbleLastInteractions); |
| - if (!list) |
| - return interactions; |
| - for (const base::Value* value : *list) { |
| - int out_value; |
| - if (value->GetAsInteger(&out_value)) |
| - interactions.push_back(out_value); |
| - } |
| - return interactions; |
| -} |
| - |
| -// We keep the history of last kParamProbabilityInteractionsCount interactions |
| -// with the bubble. We implicitly add kParamProbabilityFakeSaves "Save" clicks. |
| -// If there are x "Save" clicks among those kParamProbabilityInteractionsCount |
| -// then the bubble is shown with probability (x + kParamProbabilityFakeSaves)/ |
| -// (kParamProbabilityInteractionsCount + kParamProbabilityFakeSaves). |
| -bool ShouldShowBubbleProbabilityExperiment(PrefService* prefs) { |
| - unsigned history_length = 0, fake_saves = 0; |
| - if (!ExtractProbabilityParams(&history_length, &fake_saves)) { |
| - VLOG(2) << "Can't read parameters for " |
| - << kExperimentName << " experiment"; |
| - return true; |
| - } |
| - std::vector<int> interactions = ReadInteractionHistory(prefs); |
| - unsigned real_saves = |
| - std::count(interactions.begin(), interactions.end(), |
| - password_manager::metrics_util::CLICKED_SAVE); |
| - return (interactions.size() + fake_saves) * base::RandDouble() <= |
| - real_saves + fake_saves; |
| -} |
| - |
| -void UpdateProbabilityPrefs( |
| - PrefService* prefs, |
| - password_manager::metrics_util::UIDismissalReason reason) { |
| - if (!IsNegativeEvent(reason) && |
| - reason != password_manager::metrics_util::CLICKED_SAVE) |
| - return; |
| - unsigned history_length = 0, fake_saves = 0; |
| - if (!ExtractProbabilityParams(&history_length, &fake_saves)) { |
| - VLOG(2) << "Can't read parameters for " |
| - << kExperimentName << " experiment"; |
| - return; |
| - } |
| - std::vector<int> interactions = ReadInteractionHistory(prefs); |
| - interactions.push_back(reason); |
| - size_t history_beginning = interactions.size() > history_length ? |
| - interactions.size() - history_length : 0; |
| - base::ListValue value; |
| - for (size_t i = history_beginning; i < interactions.size(); ++i) |
| - value.AppendInteger(interactions[i]); |
| - prefs->Set(prefs::kPasswordBubbleLastInteractions, value); |
| +// Return the number of consecutive times the user clicked "Not now" in the |
| +// "Save password" bubble. |
| +int GetCurrentNopesCount(PrefService* prefs) { |
| + return prefs->GetInteger(prefs::kPasswordBubbleNopesCount); |
| } |
| } // namespace |
| const char kExperimentName[] = "PasswordBubbleAlgorithm"; |
| -const char kGroupTimeSpanBased[] = "TimeSpan"; |
| -const char kGroupProbabilityBased[] = "Probability"; |
| -const char kParamProbabilityFakeSaves[] = "saves_count"; |
| -const char kParamProbabilityInteractionsCount[] = "last_interactions_count"; |
| -const char kParamTimeSpan[] = "time_span"; |
| -const char kParamTimeSpanNopeThreshold[] = "nope_threshold"; |
| +const char kParamNopeThreshold[] = "consecutive_nope_threshold"; |
| void RegisterPrefs(user_prefs::PrefRegistrySyncable* registry) { |
| - registry->RegisterInt64Pref( |
| - prefs::kPasswordBubbleTimeStamp, |
| - 0, |
| - user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); |
| registry->RegisterIntegerPref( |
| prefs::kPasswordBubbleNopesCount, |
| 0, |
| user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); |
| - registry->RegisterListPref( |
| - prefs::kPasswordBubbleLastInteractions, |
| - user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); |
| } |
| -bool ShouldShowBubble(PrefService* prefs) { |
| +bool ShouldShowNeverForThisSiteDefault(PrefService* prefs) { |
| if (!base::FieldTrialList::TrialExists(kExperimentName)) |
| - return true; |
| - std::string group_name = |
| - base::FieldTrialList::FindFullName(kExperimentName); |
| - |
| - if (group_name == kGroupTimeSpanBased) { |
| - return ShouldShowBubbleTimeSpanExperiment(prefs); |
| - } |
| - if (group_name == kGroupProbabilityBased) { |
| - return ShouldShowBubbleProbabilityExperiment(prefs); |
| - } |
| + return false; |
| + std::string param = |
| + variations::GetVariationParamValue(kExperimentName, kParamNopeThreshold); |
| - // The "Show Always" should be the default case. |
| - return true; |
| + int threshold = 0; |
| + return base::StringToInt(param, &threshold) && |
| + GetCurrentNopesCount(prefs) >= threshold; |
| } |
| void RecordBubbleClosed( |
| PrefService* prefs, |
| password_manager::metrics_util::UIDismissalReason reason) { |
| - UpdateTimeSpanPrefs(prefs, reason); |
| - UpdateProbabilityPrefs(prefs, reason); |
| + int nopes_count = GetCurrentNopesCount(prefs); |
| + if (reason == password_manager::metrics_util::CLICKED_NOPE) |
| + nopes_count++; |
| + else |
| + nopes_count = 0; |
|
vabr (Chromium)
2015/03/24 09:09:04
I'm not sure why clicking "Never" or just abandoni
vasilii
2015/03/24 10:30:53
The case of NO_DIRECT_INTERACTION was discussed wi
vabr (Chromium)
2015/03/24 10:40:59
Fair enough for NO_DIRECT_INTERACTION. To be clear
vasilii
2015/03/24 11:00:04
I changed the algorithm and the test.
|
| + prefs->SetInteger(prefs::kPasswordBubbleNopesCount, nopes_count); |
| } |
| } // namespace password_bubble_experiment |