summaryrefslogtreecommitdiffstats
path: root/chrome/browser/extensions/extension_install_prompt_experiment.cc
blob: 475cae1f5d262697fa81958398b79ae78c4cd96b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/basictypes.h"
#include "base/logging.h"
#include "base/metrics/field_trial.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
#include "base/strings/stringprintf.h"
#include "chrome/browser/extensions/extension_install_prompt_experiment.h"
#include "grit/generated_resources.h"
#include "ui/base/l10n/l10n_util.h"

namespace {

const char kExperimentName[] = "ExtensionPermissionDialog";
const char kGroupPrefix[] = "Group";

// Flags for groups. Not all combinations make sense.
// Refer to the UI screens at http://goo.gl/f2KzPj for those that do.
enum GroupFlag {
  // No changes (Control group).
  NONE = 0,
  // Indicates that the experiment is text only. A text only experiment
  // only adds an explanation text at the bottom of the permission dialog and
  // modifies the text on accept/cancel buttons.
  TEXT_ONLY = 1 << 0,
  // Indicates that the experiment shows inline explanations for permissions.
  INLINE_EXPLANATIONS = 1 << 1,
  // Indicates that the experiment highlights permission text color.
  SHOULD_HIGHLIGHT_TEXT = 1 << 2,
  // Indicates that the experiment highlights permission text background.
  SHOULD_HIGHLIGHT_BACKGROUND = 1 << 3,
  // Indicates that the experiment highlights all permissions.
  SHOULD_HIGHLIGHT_ALL_PERMISSIONS = 1 << 4,
  // Indicates that the experiment puts a "show details" link in the UI.
  SHOULD_SHOW_DETAILS_LINK = 1 << 5,
  // Indicates that the experiment hides the permissions by default and the list
  // can be expanded.
  EXPANDABLE_PERMISSION_LIST = 1 << 6,
  // Indicates that the experiment shows checkboxes for each permission.
  SHOULD_SHOW_CHECKBOXES = 1 << 7
};

// Flags for the actual experiment groups. These flags define what kind of
// UI changes each experiment group does. An experiment group may change
// multiple aspects of the extension install dialog  (e.g. one of the groups
// show a details link and inline explanations for permissions). The control
// group doesn't change the UI. Text only groups add a text warning to the UI,
// with the text changing depending on the group number. Groups with inline
// explanations show detailed explanations for a subset of permissions. Some
// groups highlight the foreground or the background of permission texts.
// The flags reflect the UI screens at http://goo.gl/f2KzPj.
const unsigned int kGroupFlags[] = {
  // Control group doesn't change the UI.
  NONE,
  // Adds "Do you trust this extension to use these privileges safely" text.
  TEXT_ONLY,
  // Adds "Extension can be malicious" text.
  TEXT_ONLY,
  // Adds "Are you sure you want to install" text.
  TEXT_ONLY,
  // Adds "Make sure these privileges make sense for this extension" text.
  TEXT_ONLY,
  // Adds "Do you trust this extension to perform these actions" text.
  TEXT_ONLY,
  // Adds inline explanations displayed by default.
  INLINE_EXPLANATIONS,
  // Adds expandable inline explanations with a "Show Details" link.
  SHOULD_SHOW_DETAILS_LINK | INLINE_EXPLANATIONS,
  // Adds expandable permission list with a "Show Permissions" link.
  SHOULD_SHOW_DETAILS_LINK | EXPANDABLE_PERMISSION_LIST,
  // Highlights text for risky permissions.
  SHOULD_HIGHLIGHT_TEXT,
  // Highlights background for risky permissions.
  SHOULD_HIGHLIGHT_BACKGROUND,
  // Highlights background for all permissions
  SHOULD_HIGHLIGHT_BACKGROUND | SHOULD_HIGHLIGHT_ALL_PERMISSIONS,
  // Displays checkboxes for all permissions.
  SHOULD_SHOW_CHECKBOXES
};

const size_t kGroupCount = arraysize(kGroupFlags);

// Parameters for text only experiments.
const struct TextParams {
  int text_id;
  int ok_text_id;
  int cancel_text_id;
} kTextParams[] = {
  {
    IDS_EXTENSION_PROMPT_EXPERIMENT_EXPLANATION1,
    IDS_EXTENSION_PROMPT_EXPERIMENT_INSTALL_BUTTON_TRUST,
    IDS_CANCEL,
  },
  {
    IDS_EXTENSION_PROMPT_EXPERIMENT_EXPLANATION2,
    IDS_EXTENSION_PROMPT_EXPERIMENT_INSTALL_BUTTON_YES,
    IDS_EXTENSION_PROMPT_EXPERIMENT_INSTALL_BUTTON_NOPE
  },
  {
    IDS_EXTENSION_PROMPT_EXPERIMENT_EXPLANATION3,
    IDS_EXTENSION_PROMPT_EXPERIMENT_INSTALL_BUTTON_SURE,
    IDS_EXTENSION_PROMPT_EXPERIMENT_INSTALL_BUTTON_NOPE
  },
  {
    IDS_EXTENSION_PROMPT_EXPERIMENT_EXPLANATION4,
    IDS_EXTENSION_PROMPT_INSTALL_BUTTON,
    IDS_CANCEL
  },
  {
    IDS_EXTENSION_PROMPT_EXPERIMENT_EXPLANATION5,
    IDS_EXTENSION_PROMPT_EXPERIMENT_INSTALL_BUTTON_TRUST2,
    IDS_EXTENSION_PROMPT_EXPERIMENT_INSTALL_BUTTON_NOPE
  }
};

// Permission warnings in this list have inline explanation texts.
const struct PermissionExplanations {
  int warning_msg_id;
  int extra_explanation_id;
} kPermissionExplanations[] = {
  {
    IDS_EXTENSION_PROMPT_WARNING_FULL_ACCESS,
    IDS_EXTENSION_PROMPT_WARNING_FULL_ACCESS_EXPLANATION
  },
  {
    IDS_EXTENSION_PROMPT_WARNING_ALL_HOSTS,
    IDS_EXTENSION_PROMPT_WARNING_ALL_HOSTS_EXPLANATION
  }
};

// Permission warnings in this list are going to be highlighted.
// Note that the matching is done by string comparison, so this list must not
// contain any dynamic strings (e.g. permission for 3 hosts with the host list).
const int kHighlightedWarnings[] = {
  IDS_EXTENSION_PROMPT_WARNING_FULL_ACCESS,
  IDS_EXTENSION_PROMPT_WARNING_ALL_HOSTS,
  IDS_EXTENSION_PROMPT_WARNING_BOOKMARKS,
  IDS_EXTENSION_PROMPT_WARNING_CONTENT_SETTINGS,
  IDS_EXTENSION_PROMPT_WARNING_HISTORY_WRITE,
  IDS_EXTENSION_PROMPT_WARNING_INPUT,
  IDS_EXTENSION_PROMPT_WARNING_MANAGEMENT,
  IDS_EXTENSION_PROMPT_WARNING_HISTORY_READ,
  IDS_EXTENSION_PROMPT_WARNING_DEBUGGER
};

bool IsImportantWarning(const base::string16& message) {
  for (size_t i = 0; i < arraysize(kHighlightedWarnings); ++i) {
    if (message == l10n_util::GetStringUTF16(kHighlightedWarnings[i]))
      return true;
  }
  return false;
}

}  // namespace

ExtensionInstallPromptExperiment::ExtensionInstallPromptExperiment(
    unsigned int group_id, unsigned int flags)
    : group_id_(group_id),
      flags_(flags) {
}

ExtensionInstallPromptExperiment::~ExtensionInstallPromptExperiment() {
}

// static
ExtensionInstallPromptExperiment*
    ExtensionInstallPromptExperiment::ControlGroup() {
  return new ExtensionInstallPromptExperiment(0, kGroupFlags[0]);
}

// static
ExtensionInstallPromptExperiment*
    ExtensionInstallPromptExperiment::Find() {
  base::FieldTrial* trial = base::FieldTrialList::Find(kExperimentName);
  // Default is control group.
  unsigned int group_id = 0;
  if (trial) {
    std::vector<std::string> tokens;
    base::SplitString(trial->group_name().c_str(), '_', &tokens);
    if (tokens.size() == 2 && tokens[0] == kGroupPrefix) {
      base::StringToUint(tokens[1], &group_id);
      if (group_id >= kGroupCount)
        group_id = 0;
    }
  }
  return new ExtensionInstallPromptExperiment(group_id, kGroupFlags[group_id]);
}

base::string16 ExtensionInstallPromptExperiment::GetExplanationText() const {
  DCHECK(group_id_ > 0 && group_id_ - 1 < arraysize(kTextParams));
  return l10n_util::GetStringUTF16(kTextParams[group_id_ - 1].text_id);
}

base::string16 ExtensionInstallPromptExperiment::GetOkButtonText() const {
  DCHECK(group_id_ > 0 && group_id_ - 1 < arraysize(kTextParams));
  return l10n_util::GetStringUTF16(kTextParams[group_id_ - 1].ok_text_id);
}

base::string16 ExtensionInstallPromptExperiment::GetCancelButtonText() const {
  DCHECK(group_id_ > 0 && group_id_ - 1 < arraysize(kTextParams));
  return l10n_util::GetStringUTF16(kTextParams[group_id_ - 1].cancel_text_id);
}

bool ExtensionInstallPromptExperiment::text_only() const {
  return (flags_ & TEXT_ONLY) != 0;
}

bool ExtensionInstallPromptExperiment::ShouldHighlightText(
    const base::string16& message) const {
  return (flags_ & SHOULD_HIGHLIGHT_TEXT) != 0 && IsImportantWarning(message);
}

bool ExtensionInstallPromptExperiment::ShouldHighlightBackground(
    const base::string16& message) const {
  return (flags_ & SHOULD_HIGHLIGHT_BACKGROUND) != 0 &&
      ((flags_ & SHOULD_HIGHLIGHT_ALL_PERMISSIONS) != 0 ||
      IsImportantWarning(message));
}

bool ExtensionInstallPromptExperiment::show_details_link() const {
  return (flags_ & SHOULD_SHOW_DETAILS_LINK) != 0;
}

bool ExtensionInstallPromptExperiment::show_checkboxes() const {
  return (flags_ & SHOULD_SHOW_CHECKBOXES) != 0;
}

bool ExtensionInstallPromptExperiment::should_show_expandable_permission_list()
    const {
  return (flags_ & EXPANDABLE_PERMISSION_LIST) != 0;
}

bool ExtensionInstallPromptExperiment::should_show_inline_explanations() const {
  return (flags_ & INLINE_EXPLANATIONS) != 0;
}

base::string16 ExtensionInstallPromptExperiment::GetInlineExplanation(
    const base::string16& message) const {
  for (size_t i = 0; i < arraysize(kPermissionExplanations); ++i) {
    if (message == l10n_util::GetStringUTF16(
        kPermissionExplanations[i].warning_msg_id)) {
      return l10n_util::GetStringUTF16(
          kPermissionExplanations[i].extra_explanation_id);
    }
  }
  return base::string16();
}