summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
Diffstat (limited to 'chrome')
-rw-r--r--chrome/browser/first_run/try_chrome_dialog_view.cc104
-rw-r--r--chrome/browser/first_run/try_chrome_dialog_view.h33
-rw-r--r--chrome/common/attrition_experiments.h12
-rw-r--r--chrome/installer/util/browser_distribution.h10
-rw-r--r--chrome/installer/util/google_chrome_distribution.cc125
5 files changed, 174 insertions, 110 deletions
diff --git a/chrome/browser/first_run/try_chrome_dialog_view.cc b/chrome/browser/first_run/try_chrome_dialog_view.cc
index 3d74836..be3c7dd 100644
--- a/chrome/browser/first_run/try_chrome_dialog_view.cc
+++ b/chrome/browser/first_run/try_chrome_dialog_view.cc
@@ -18,6 +18,7 @@
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/image/image.h"
+#include "ui/views/controls/button/checkbox.h"
#include "ui/views/controls/button/image_button.h"
#include "ui/views/controls/button/radio_button.h"
#include "ui/views/controls/button/text_button.h"
@@ -32,6 +33,14 @@ namespace {
const wchar_t kHelpCenterUrl[] =
L"https://www.google.com/support/chrome/bin/answer.py?answer=150752";
+enum ButtonTags {
+ BT_NONE,
+ BT_CLOSE_BUTTON,
+ BT_OK_BUTTON,
+ BT_TRY_IT_RADIO,
+ BT_DONT_BUG_RADIO
+};
+
} // namespace
// static
@@ -53,7 +62,8 @@ TryChromeDialogView::TryChromeDialogView(size_t flavor)
try_chrome_(NULL),
kill_chrome_(NULL),
dont_try_chrome_(NULL),
- result_(COUNT) {
+ make_default_(NULL),
+ result_(COUNT) {
}
TryChromeDialogView::~TryChromeDialogView() {
@@ -90,8 +100,8 @@ TryChromeDialogView::Result TryChromeDialogView::ShowModal(
return DIALOG_ERROR;
}
root_view->SetLayoutManager(layout);
-
views::ColumnSet* columns;
+
// First row: [icon][pad][text][button].
columns = layout->AddColumnSet(0);
columns->AddColumn(views::GridLayout::LEADING, views::GridLayout::LEADING, 0,
@@ -102,37 +112,49 @@ TryChromeDialogView::Result TryChromeDialogView::ShowModal(
views::GridLayout::USE_PREF, 0, 0);
columns->AddColumn(views::GridLayout::TRAILING, views::GridLayout::FILL, 1,
views::GridLayout::USE_PREF, 0, 0);
- // Second row: [pad][pad][radio 1].
+
+ // Optional second row: [pad][pad][radio 1].
columns = layout->AddColumnSet(1);
columns->AddPaddingColumn(0, icon_size.width());
columns->AddPaddingColumn(0, views::kRelatedControlHorizontalSpacing);
columns->AddColumn(views::GridLayout::LEADING, views::GridLayout::FILL, 1,
views::GridLayout::USE_PREF, 0, 0);
+
// Third row: [pad][pad][radio 2].
columns = layout->AddColumnSet(2);
columns->AddPaddingColumn(0, icon_size.width());
columns->AddPaddingColumn(0, views::kRelatedControlHorizontalSpacing);
columns->AddColumn(views::GridLayout::LEADING, views::GridLayout::FILL, 1,
views::GridLayout::USE_PREF, 0, 0);
+
// Fourth row: [pad][pad][button][pad][button].
columns = layout->AddColumnSet(3);
columns->AddPaddingColumn(0, icon_size.width());
- columns->AddPaddingColumn(0, views::kRelatedControlHorizontalSpacing);
columns->AddColumn(views::GridLayout::LEADING, views::GridLayout::FILL, 0,
views::GridLayout::USE_PREF, 0, 0);
columns->AddPaddingColumn(0, views::kRelatedButtonHSpacing);
columns->AddColumn(views::GridLayout::LEADING, views::GridLayout::FILL, 0,
views::GridLayout::USE_PREF, 0, 0);
+
// Fifth row: [pad][pad][link].
columns = layout->AddColumnSet(4);
columns->AddPaddingColumn(0, icon_size.width());
columns->AddPaddingColumn(0, views::kRelatedControlHorizontalSpacing);
columns->AddColumn(views::GridLayout::LEADING, views::GridLayout::FILL, 1,
views::GridLayout::USE_PREF, 0, 0);
+
// Optional fourth row: [button].
columns = layout->AddColumnSet(5);
columns->AddColumn(views::GridLayout::CENTER, views::GridLayout::FILL, 1,
views::GridLayout::USE_PREF, 0, 0);
+
+ // Optional fourth row: [pad][pad][checkbox].
+ columns = layout->AddColumnSet(6);
+ columns->AddPaddingColumn(0, icon_size.width());
+ columns->AddPaddingColumn(0,
+ views::kRelatedControlHorizontalSpacing + views::kPanelHorizIndentation);
+ columns->AddColumn(views::GridLayout::LEADING, views::GridLayout::FILL, 1,
+ views::GridLayout::USE_PREF, 0, 0);
// First row views.
layout->StartRow(0, 0);
layout->AddView(icon);
@@ -171,45 +193,59 @@ TryChromeDialogView::Result TryChromeDialogView::ShowModal(
const string16 try_it(l10n_util::GetStringUTF16(IDS_TRY_TOAST_TRY_OPT));
layout->StartRowWithPadding(0, 1, 0, 10);
try_chrome_ = new views::RadioButton(try_it, 1);
- layout->AddView(try_chrome_);
try_chrome_->SetChecked(true);
+ try_chrome_->set_tag(BT_TRY_IT_RADIO);
+ try_chrome_->set_listener(this);
+ layout->AddView(try_chrome_);
- // Third row views.
- layout->StartRow(0, 2);
- if (experiment.compact_bubble) {
- // The compact bubble has, as its second radio button, "Don't bug me".
+ // Decide if the don't bug me is a button or a radio button.
+ bool dont_bug_me_button =
+ experiment.flags & BrowserDistribution::kDontBugMeAsButton ? true : false;
+
+ // Optional third and fourth row views.
+ if (!dont_bug_me_button) {
+ layout->StartRow(0, 1);
const string16 decline(l10n_util::GetStringUTF16(IDS_TRY_TOAST_CANCEL));
dont_try_chrome_ = new views::RadioButton(decline, 1);
+ dont_try_chrome_->set_tag(BT_DONT_BUG_RADIO);
+ dont_try_chrome_->set_listener(this);
layout->AddView(dont_try_chrome_);
- } else {
- // The regular bubble has, as its second radio button, "Uninstall Chrome".
+ }
+ if (experiment.flags & BrowserDistribution::kUninstall) {
+ layout->StartRow(0, 2);
const string16 kill_it(l10n_util::GetStringUTF16(IDS_UNINSTALL_CHROME));
kill_chrome_ = new views::RadioButton(kill_it, 1);
layout->AddView(kill_chrome_);
}
+ if (experiment.flags & BrowserDistribution::kMakeDefault) {
+ layout->StartRow(0, 6);
+ const string16 default_text(
+ l10n_util::GetStringUTF16(IDS_TRY_TOAST_SET_DEFAULT));
+ make_default_ = new views::Checkbox(default_text);
+ gfx::Font font = make_default_->font().DeriveFont(0, gfx::Font::ITALIC);
+ make_default_->SetFont(font);
+ make_default_->SetChecked(true);
+ layout->AddView(make_default_);
+ }
- // Fourth row views.
+ // Button row, the last or next to last depending on the 'why?' link.
const string16 ok_it(l10n_util::GetStringUTF16(IDS_OK));
- const string16 cancel_it(l10n_util::GetStringUTF16(IDS_TRY_TOAST_CANCEL));
- const string16 why_this(l10n_util::GetStringUTF16(IDS_TRY_TOAST_WHY));
views::Button* accept_button = new views::NativeTextButton(this, ok_it);
accept_button->set_tag(BT_OK_BUTTON);
- // The compact bubble uses a centered button column for buttons, since only
- // the OK button appears.
- int column_id_buttons = experiment.compact_bubble ? 5 : 3;
- layout->StartRowWithPadding(0, column_id_buttons, 0, 10);
+ layout->StartRowWithPadding(0, dont_bug_me_button ? 3 : 5, 0, 10);
layout->AddView(accept_button);
- if (!experiment.compact_bubble) {
- // The regular bubble needs a "Don't bug me" as a button, since it is not
- // one of the options for the radio buttons. We also decided to include the
- // "Why am I seeing this?" link for the regular bubble only.
+ if (dont_bug_me_button) {
+ // The bubble needs a "Don't bug me" as a button or as a radio button, this
+ // this the button case.
+ const string16 cancel_it(l10n_util::GetStringUTF16(IDS_TRY_TOAST_CANCEL));
views::Button* cancel_button = new views::NativeTextButton(this, cancel_it);
cancel_button->set_tag(BT_CLOSE_BUTTON);
layout->AddView(cancel_button);
-
- // Fifth row views.
+ }
+ if (experiment.flags & BrowserDistribution::kWhyLink) {
layout->StartRowWithPadding(0, 4, 0, 10);
+ const string16 why_this(l10n_util::GetStringUTF16(IDS_TRY_TOAST_WHY));
views::Link* link = new views::Link(why_this);
link->set_listener(this);
layout->AddView(link);
@@ -269,14 +305,26 @@ void TryChromeDialogView::SetToastRegion(HWND window, int w, int h) {
void TryChromeDialogView::ButtonPressed(views::Button* sender,
const views::Event& event) {
- if (sender->tag() == BT_CLOSE_BUTTON) {
+ if (sender->tag() == BT_DONT_BUG_RADIO) {
+ if (make_default_) {
+ make_default_->SetChecked(false);
+ make_default_->SetState(views::CustomButton::BS_DISABLED);
+ }
+ return;
+ } else if (sender->tag() == BT_TRY_IT_RADIO) {
+ if (make_default_) {
+ make_default_->SetChecked(true);
+ make_default_->SetState(views::CustomButton::BS_NORMAL);
+ }
+ return;
+ } else if (sender->tag() == BT_CLOSE_BUTTON) {
// The user pressed cancel or the [x] button.
result_ = NOT_NOW;
} else if (!try_chrome_) {
// We don't have radio buttons, the user pressed ok.
result_ = TRY_CHROME;
} else {
- // The outcome is according to the selected ratio button.
+ // The outcome is according to the selected radio button.
if (try_chrome_->checked())
result_ = TRY_CHROME;
else if (dont_try_chrome_ && dont_try_chrome_->checked())
@@ -286,6 +334,10 @@ void TryChromeDialogView::ButtonPressed(views::Button* sender,
else
NOTREACHED() << "Unknown radio button selected";
}
+
+ if ((result_ == TRY_CHROME) && make_default_->checked())
+ result_ = TRY_CHROME_AS_DEFAULT;
+
popup_->Close();
MessageLoop::current()->Quit();
}
diff --git a/chrome/browser/first_run/try_chrome_dialog_view.h b/chrome/browser/first_run/try_chrome_dialog_view.h
index 77f90bc..d0a5aa5 100644
--- a/chrome/browser/first_run/try_chrome_dialog_view.h
+++ b/chrome/browser/first_run/try_chrome_dialog_view.h
@@ -19,6 +19,7 @@ class Rect;
namespace views {
class RadioButton;
+class Checkbox;
class Widget;
}
@@ -27,23 +28,32 @@ class Widget;
// resulting actions are up to the caller. One flavor looks like this:
//
// +-----------------------------------------------+
-// | |icon| You stopped using Google Chrome [x] |
-// | |icon| Would you like to: |
-// | [o] Give the new version a try |
+// | |icon| There is a new, safer version [x] |
+// | |icon| of Google Chrome available |
+// | [o] Try it out (already installed) |
// | [ ] Uninstall Google Chrome |
// | [ OK ] [Don't bug me] |
-// | |
// | _why_am_I_seeing this?_ |
// +-----------------------------------------------+
//
+// Another flavor looks like:
+// +-----------------------------------------------+
+// | |icon| There is a new, safer version [x] |
+// | |icon| of Google Chrome available |
+// | [o] Try it out (already installed) |
+// | [ ] Don't bug me |
+// | [ OK ] |
+// +-----------------------------------------------+
+//
class TryChromeDialogView : public views::ButtonListener,
public views::LinkListener {
public:
enum Result {
- TRY_CHROME, // Launch chrome right now.
- NOT_NOW, // Don't launch chrome. Exit now.
- UNINSTALL_CHROME, // Initiate chrome uninstall and exit.
- DIALOG_ERROR, // An error occurred creating the dialog.
+ TRY_CHROME, // Launch chrome right now.
+ TRY_CHROME_AS_DEFAULT, // Launch chrome and make it the default.
+ NOT_NOW, // Don't launch chrome. Exit now.
+ UNINSTALL_CHROME, // Initiate chrome uninstall and exit.
+ DIALOG_ERROR, // An error occurred creating the dialog.
COUNT
};
@@ -59,12 +69,6 @@ class TryChromeDialogView : public views::ButtonListener,
static Result Show(size_t flavor, ProcessSingleton* process_singleton);
private:
- enum ButtonTags {
- BT_NONE,
- BT_CLOSE_BUTTON,
- BT_OK_BUTTON,
- };
-
explicit TryChromeDialogView(size_t flavor);
virtual ~TryChromeDialogView();
@@ -101,6 +105,7 @@ class TryChromeDialogView : public views::ButtonListener,
views::RadioButton* try_chrome_;
views::RadioButton* kill_chrome_;
views::RadioButton* dont_try_chrome_;
+ views::Checkbox* make_default_;
Result result_;
DISALLOW_COPY_AND_ASSIGN(TryChromeDialogView);
diff --git a/chrome/common/attrition_experiments.h b/chrome/common/attrition_experiments.h
index e3dec6b..1404b49 100644
--- a/chrome/common/attrition_experiments.h
+++ b/chrome/common/attrition_experiments.h
@@ -18,18 +18,8 @@ enum Experiment {
kSkype1 = IDS_TRY_TOAST_HEADING_SKYPE,
};
-// This is used to match against locale and brands, and represents any
-// locale/brand.
-const wchar_t kAll[] = L"*";
-
// A comma-separated list of brand codes that are associated with Skype.
-const wchar_t kSkype[] = L"SKPC,SKPG,SKPH,SKPI,SKPL,SKPM,SKPN";
-
-// The brand code for enterprise installations.
-const wchar_t kEnterprise[] = L"GGRV";
-
-// The brand code for showing more compact bubbles (experimental).
-const wchar_t kBrief[] = L"CHMA";
+const wchar_t kSkypeBrandCode[] = L"SKPC,SKPG,SKPH,SKPI,SKPL,SKPM,SKPN";
} // namespace
diff --git a/chrome/installer/util/browser_distribution.h b/chrome/installer/util/browser_distribution.h
index 4f609c9..96360a9 100644
--- a/chrome/installer/util/browser_distribution.h
+++ b/chrome/installer/util/browser_distribution.h
@@ -33,6 +33,14 @@ class BrowserDistribution {
NUM_TYPES
};
+ // Flags to control what to show in the UserExperiment dialog.
+ enum ToastUIflags {
+ kUninstall = 1, // Uninstall radio button.
+ kDontBugMeAsButton = 2, // Don't bug me is a button, not a radio button.
+ kWhyLink = 4, // Has the 'why I am seeing this' link.
+ kMakeDefault = 8 // Has the 'make it default' checkbox.
+ };
+
// A struct for communicating what a UserExperiment contains. In these
// experiments we show toasts to the user if they are inactive for a certain
// amount of time.
@@ -41,7 +49,7 @@ class BrowserDistribution {
// also known as the 'TV' part in 'TV80'.
int flavor; // The flavor index for this experiment.
int heading; // The heading resource ID to use for this experiment.
- bool compact_bubble; // Whether to show the compact heading or not.
+ int flags; // See ToastUIFlags above.
int control_group; // Size of the control group (in percentages). Control
// group is the group that qualifies for the
// experiment but does not participate.
diff --git a/chrome/installer/util/google_chrome_distribution.cc b/chrome/installer/util/google_chrome_distribution.cc
index 80c160f..b340873 100644
--- a/chrome/installer/util/google_chrome_distribution.cc
+++ b/chrome/installer/util/google_chrome_distribution.cc
@@ -60,14 +60,15 @@ const wchar_t kICommandExecuteImplUuid[] =
// The following strings are the possible outcomes of the toast experiment
// as recorded in the |client| field.
-const wchar_t kToastExpControlGroup[] = L"01";
-const wchar_t kToastExpCancelGroup[] = L"02";
-const wchar_t kToastExpUninstallGroup[] = L"04";
-const wchar_t kToastExpTriesOkGroup[] = L"18";
-const wchar_t kToastExpTriesErrorGroup[] = L"28";
-const wchar_t kToastActiveGroup[] = L"40";
-const wchar_t kToastUDDirFailure[] = L"40";
-const wchar_t kToastExpBaseGroup[] = L"80";
+const wchar_t kToastExpControlGroup[] = L"01";
+const wchar_t kToastExpCancelGroup[] = L"02";
+const wchar_t kToastExpUninstallGroup[] = L"04";
+const wchar_t kToastExpTriesOkGroup[] = L"18";
+const wchar_t kToastExpTriesErrorGroup[] = L"28";
+const wchar_t kToastExpTriesOkDefaultGroup[] = L"48";
+const wchar_t kToastActiveGroup[] = L"40";
+const wchar_t kToastUDDirFailure[] = L"40";
+const wchar_t kToastExpBaseGroup[] = L"80";
// Substitute the locale parameter in uninstall URL with whatever
// Google Update tells us is the locale. In case we fail to find
@@ -612,6 +613,10 @@ void SetClient(const string16& experiment_group, bool last_write) {
bool GoogleChromeDistribution::GetExperimentDetails(
UserExperiment* experiment, int flavor) {
+ struct FlavorDetails {
+ int heading_id;
+ int flags;
+ };
// Maximum number of experiment flavors we support.
static const int kMax = 4;
// This struct determines which experiment flavors we show for each locale and
@@ -624,29 +629,37 @@ bool GoogleChromeDistribution::GetExperimentDetails(
// The big experiment in Feb 2011 used SJxx SKxx SLxx SMxx.
// Note: the plugin infobar experiment uses PIxx codes.
using namespace attrition_experiments;
+
static const struct UserExperimentDetails {
const wchar_t* locale; // Locale to show this experiment for (* for all).
const wchar_t* brands; // Brand codes show this experiment for (* for all).
int control_group; // Size of the control group, in percentages.
- const wchar_t prefix1; // The first letter for the experiment code.
- const wchar_t prefix2; // The second letter for the experiment code. This
- // will be incremented by one for each additional
- // experiment flavor beyond the first.
- int flavors; // Numbers of flavors for this experiment. Should
- // always be positive and never exceed the number
- // of headings (below).
- int headings[kMax]; // A list of IDs per experiment. 0 == no heading.
- } kExperimentFlavors[] = {
- // This list should be ordered most-specific rule first (catch-all, like all
- // brands or all locales should be last).
-
- // The experiment with the more compact bubble. This one is a bit special
- // because it is split into two: CAxx is regular style bubble and CBxx is
- // compact style bubble. See |compact_bubble| below.
- {L"en-US", kBrief, 1, L'C', L'A', 2, { kEnUs3, kEnUs3, 0, 0 } },
-
- // Catch-all rules.
- {kAll, kAll, 1, L'B', L'A', 1, {kEnUs3, 0, 0, 0} },
+ const wchar_t* prefix; // The two letter experiment code. The second letter
+ // will be incremented with the flavor.
+ FlavorDetails flavors[kMax];
+ } kExperiments[] = {
+ // The first match from top to bottom is used so this list should be ordered
+ // most-specific rule first.
+ { L"*", L"CHMA", // All locales, CHMA brand.
+ 25, // 25 percent control group.
+ L"ZA", // Experiment is ZAxx, ZBxx, ZCxx, ZDxx etc.
+ // Three flavors.
+ { { IDS_TRY_TOAST_HEADING3, kDontBugMeAsButton | kUninstall | kWhyLink },
+ { IDS_TRY_TOAST_HEADING3, 0 },
+ { IDS_TRY_TOAST_HEADING3, kMakeDefault },
+ { 0, 0 },
+ }
+ },
+ { L"*", L"GGRV", // All locales, GGRV is enterprise.
+ 0, // 0 percent control group.
+ L"EA", // Experiment is EAxx, EBxx, etc.
+ // No flavors means no experiment.
+ { { 0, 0 },
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 }
+ }
+ }
};
string16 locale;
@@ -657,50 +670,36 @@ bool GoogleChromeDistribution::GetExperimentDetails(
string16 brand;
if (!GoogleUpdateSettings::GetBrand(&brand))
brand = ASCIIToWide(""); // Could still be viable for catch-all rules.
- if (brand == kEnterprise)
- return false;
- for (int i = 0; i < arraysize(kExperimentFlavors); ++i) {
- // A maximum of four flavors are supported at the moment.
- CHECK_LE(kExperimentFlavors[i].flavors, kMax);
- CHECK_GT(kExperimentFlavors[i].flavors, 0);
- // Make sure each experiment has valid headings.
- for (int f = 0; f < kMax; ++f) {
- if (f < kExperimentFlavors[i].flavors) {
- CHECK_GT(kExperimentFlavors[i].headings[f], 0);
- } else {
- CHECK_EQ(kExperimentFlavors[i].headings[f], 0);
- }
- }
- // The prefix has to be a valid two letter combo.
- CHECK(kExperimentFlavors[i].prefix1 >= 'A');
- CHECK(kExperimentFlavors[i].prefix2 >= 'A');
- CHECK(kExperimentFlavors[i].prefix2 +
- kExperimentFlavors[i].flavors - 1 <= 'Z');
-
- if (kExperimentFlavors[i].locale != locale &&
- kExperimentFlavors[i].locale != ASCIIToWide("*"))
+ for (int i = 0; i < arraysize(kExperiments); ++i) {
+ if (kExperiments[i].locale != locale &&
+ kExperiments[i].locale != ASCIIToWide("*"))
continue;
std::vector<string16> brand_codes;
- base::SplitString(kExperimentFlavors[i].brands, L',', &brand_codes);
+ base::SplitString(kExperiments[i].brands, L',', &brand_codes);
if (brand_codes.empty())
return false;
for (std::vector<string16>::iterator it = brand_codes.begin();
it != brand_codes.end(); ++it) {
if (*it != brand && *it != L"*")
continue;
-
// We have found our match.
+ const UserExperimentDetails& match = kExperiments[i];
+ // Find out how many flavors we have. Zero means no experiment.
+ int num_flavors = 0;
+ while (match.flavors[num_flavors].heading_id) { ++num_flavors; }
+ if (!num_flavors)
+ return false;
+
if (flavor < 0)
- flavor = base::RandInt(0, kExperimentFlavors[i].flavors - 1);
+ flavor = base::RandInt(0, num_flavors - 1);
experiment->flavor = flavor;
- experiment->heading = kExperimentFlavors[i].headings[flavor];
- experiment->control_group = kExperimentFlavors[i].control_group;
- experiment->prefix.resize(2);
- experiment->prefix[0] = kExperimentFlavors[i].prefix1;
- experiment->prefix[1] = kExperimentFlavors[i].prefix2 + flavor;
- experiment->compact_bubble = (brand == kBrief) && (flavor == 1);
+ experiment->heading = match.flavors[flavor].heading_id;
+ experiment->control_group = match.control_group;
+ const wchar_t prefix[] = { match.prefix[0], match.prefix[1] + flavor, 0 };
+ experiment->prefix = prefix;
+ experiment->flags = match.flavors[flavor].flags;
return true;
}
}
@@ -853,6 +852,16 @@ void GoogleChromeDistribution::InactiveUserToastExperiment(int flavor,
outcome = kToastExpTriesErrorGroup;
};
+ if (outcome == kToastExpTriesOkGroup) {
+ // User tried chrome, but if it had the default group button it belongs
+ // to a different outcome group.
+ UserExperiment experiment;
+ if (GetExperimentDetails(&experiment, flavor)) {
+ outcome = experiment.flags & kMakeDefault ? kToastExpTriesOkDefaultGroup :
+ kToastExpTriesOkGroup;
+ }
+ }
+
// Write to the |client| key for the last time.
SetClient(experiment_group + outcome, true);