Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(949)

Side by Side Diff: chrome/browser/ui/views/extensions/disabled_extensions_view.cc

Issue 11189094: Implement sideload wipeout for Extensions. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 8 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
Property Changes:
Added: svn:eol-style
+ LF
OLDNEW
(Empty)
1 // Copyright (c) 2012 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/ui/views/extensions/disabled_extensions_view.h"
6
7 #include "base/metrics/histogram.h"
8 #include "base/string_number_conversions.h"
9 #include "base/utf_string_conversions.h"
10 #include "chrome/browser/extensions/extension_service.h"
11 #include "chrome/browser/extensions/extension_system.h"
12 #include "chrome/browser/ui/browser.h"
13 #include "chrome/browser/ui/singleton_tabs.h"
14 #include "chrome/common/extensions/feature_switch.h"
15 #include "chrome/common/url_constants.h"
16 #include "content/public/browser/user_metrics.h"
17 #include "grit/generated_resources.h"
18 #include "grit/locale_settings.h"
19 #include "grit/theme_resources.h"
20 #include "ui/base/accessibility/accessible_view_state.h"
21 #include "ui/base/l10n/l10n_util.h"
22 #include "ui/base/resource/resource_bundle.h"
23 #include "ui/views/controls/button/text_button.h"
24 #include "ui/views/controls/label.h"
25 #include "ui/views/controls/image_view.h"
26 #include "ui/views/controls/link.h"
27 #include "ui/views/layout/grid_layout.h"
28 #include "ui/views/layout/layout_constants.h"
29 #include "ui/views/widget/widget.h"
30
31 using content::UserMetricsAction;
32
33 namespace {
34
35 // Layout constants.
36 const int kColumnPadding = 4;
37 const int kExtensionListPadding = 20;
38 const int kImagePadding = 7;
39 const int kLeftColumnPadding = 3;
40 const int kInset = 2;
41 const int kHeadlineMessagePadding = 4;
42 const int kHeadlineRowPadding = 10;
43 const int kMessageBubblePadding = 11;
44
45 // How many extensions to show in the bubble (max).
46 const int kMaxExtensionsToShow = 7;
47
48 } // namespace
49
50 ////////////////////////////////////////////////////////////////////////////////
51 // DisabledExtensionsView
52
53 // static
54 bool DisabledExtensionsView::MaybeShow(Browser* browser,
55 views::View* anchor_view) {
56 #if !defined(OS_WIN)
57 // We are targeting registry-installed extensions, which is Windows-specific,
58 // and extensions marked internal and not from the web store, which are mostly
59 // problematic on Windows.
60 return false;
61 #endif
62
63 if (!extensions::FeatureSwitch::sideload_wipeout()->IsEnabled())
64 return false;
65
66 static bool done_showing_ui = false;
67 if (done_showing_ui)
68 return false; // Only show the bubble once per launch.
69
70 // Fetch all disabled extensions.
71 ExtensionService* extension_service =
72 extensions::ExtensionSystem::Get(
73 browser->profile())->extension_service();
74 scoped_ptr<const ExtensionSet> wiped_out(
75 extension_service->GetWipedOutExtensions());
76 if (wiped_out->size()) {
77 DisabledExtensionsView* bubble_delegate =
78 new DisabledExtensionsView(
79 anchor_view, browser, wiped_out.release());
80 views::BubbleDelegateView::CreateBubble(bubble_delegate);
81 bubble_delegate->StartFade(true);
82
83 done_showing_ui = true;
84 return true;
85 }
86
87 return false;
88 }
89
90 DisabledExtensionsView::DisabledExtensionsView(
91 views::View* anchor_view,
92 Browser* browser,
93 const ExtensionSet* wiped_out)
94 : BubbleDelegateView(anchor_view, views::BubbleBorder::TOP_RIGHT),
95 browser_(browser),
96 wiped_out_(wiped_out),
97 headline_(NULL),
98 learn_more_(NULL),
99 settings_button_(NULL),
100 dismiss_button_(NULL) {
101 set_close_on_deactivate(false);
102 set_move_with_anchor(true);
103
104 UMA_HISTOGRAM_COUNTS_100("DisabledExtension.SideloadWipeoutCount",
105 wiped_out->size());
106 }
107
108 DisabledExtensionsView::~DisabledExtensionsView() {
109 }
110
111 void DisabledExtensionsView::ButtonPressed(views::Button* sender,
112 const ui::Event& event) {
113 if (sender == settings_button_) {
114 content::RecordAction(
115 UserMetricsAction("DisabledExtension_SettingsButton"));
116 browser_->OpenURL(
117 content::OpenURLParams(GURL(chrome::kChromeUIExtensionsURL),
118 content::Referrer(),
119 NEW_FOREGROUND_TAB,
120 content::PAGE_TRANSITION_LINK,
121 false));
122
123 } else if (sender == dismiss_button_) {
124 content::RecordAction(UserMetricsAction("DisabledExtension_Dismiss"));
125 // No action required. Close will happen below.
126 } else {
127 NOTREACHED();
128 }
129
130 GetWidget()->Close();
131 }
132
133 void DisabledExtensionsView::LinkClicked(
134 views::Link* source, int event_flags) {
135 content::RecordAction(UserMetricsAction("DisabledExtension_LearnMore"));
136 browser_->OpenURL(
137 content::OpenURLParams(GURL(chrome::kSideloadWipeoutHelpURL),
138 content::Referrer(),
139 NEW_FOREGROUND_TAB,
140 content::PAGE_TRANSITION_LINK,
141 false));
142
143 GetWidget()->Close();
144 }
145
146 void DisabledExtensionsView::GetAccessibleState(
147 ui::AccessibleViewState* state) {
148 state->role = ui::AccessibilityTypes::ROLE_ALERT;
149 }
150
151 void DisabledExtensionsView::ViewHierarchyChanged(
152 bool is_add, View* parent, View* child) {
153 if (is_add && child == this) {
154 GetWidget()->NotifyAccessibilityEvent(
155 this, ui::AccessibilityTypes::EVENT_ALERT, true);
156 }
157 }
158
159 void DisabledExtensionsView::Init() {
160 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
161
162 views::GridLayout* layout = views::GridLayout::CreatePanel(this);
163 layout->SetInsets(kInset, kInset, kInset, kInset);
164 SetLayoutManager(layout);
165
166 const int headline_column_set_id = 0;
167 views::ColumnSet* top_columns = layout->AddColumnSet(headline_column_set_id);
168 top_columns->AddColumn(views::GridLayout::LEADING, views::GridLayout::CENTER,
169 0, views::GridLayout::USE_PREF, 0, 0);
170 top_columns->AddPaddingColumn(0, kImagePadding);
171 top_columns->AddColumn(views::GridLayout::LEADING, views::GridLayout::CENTER,
172 0, views::GridLayout::USE_PREF, 0, 0);
173 top_columns->AddPaddingColumn(1, 0);
174 layout->StartRow(0, headline_column_set_id);
175
176 views::ImageView* image = new views::ImageView();
177 const gfx::ImageSkia* puzzle_piece =
178 rb.GetImageSkiaNamed(IDR_EXTENSIONS_PUZZLE_PIECE);
179 image->SetImage(puzzle_piece);
180 layout->AddView(image);
181 int left_padding_column = puzzle_piece->width() + kLeftColumnPadding;
182
183 headline_ = new views::Label();
184 headline_->SetFont(rb.GetFont(ui::ResourceBundle::MediumFont));
185 headline_->SetText(l10n_util::GetStringUTF16(
186 IDS_OPTIONS_SIDELOAD_WIPEOUT_BUBBLE_HEADLINE));
187 layout->AddView(headline_);
188
189 layout->AddPaddingRow(0, kHeadlineRowPadding);
190
191 const int text_column_set_id = 1;
192 views::ColumnSet* upper_columns = layout->AddColumnSet(text_column_set_id);
193 upper_columns->AddPaddingColumn(0, left_padding_column);
194 upper_columns->AddPaddingColumn(0, kColumnPadding);
195 upper_columns->AddColumn(
196 views::GridLayout::LEADING, views::GridLayout::LEADING,
197 0, views::GridLayout::USE_PREF, 0, 0);
198 layout->StartRow(0, text_column_set_id);
199
200 views::Label* message = new views::Label();
201 message->SetMultiLine(true);
202 message->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
203 message->SetText(
204 l10n_util::GetStringUTF16(IDS_OPTIONS_SIDELOAD_WIPEOUT_WHAT_HAPPENED));
205 message->SizeToFit(views::Widget::GetLocalizedContentsWidth(
206 IDS_DISABLED_EXTENSIONS_BUBBLE_WIDTH_CHARS));
207 layout->AddView(message);
208
209 const int extension_list_column_set_id = 2;
210 views::ColumnSet* middle_columns =
211 layout->AddColumnSet(extension_list_column_set_id);
212 middle_columns->AddPaddingColumn(0, left_padding_column);
213 middle_columns->AddPaddingColumn(0, kExtensionListPadding);
214 middle_columns->AddColumn(
215 views::GridLayout::LEADING, views::GridLayout::CENTER,
216 0, views::GridLayout::USE_PREF, 0, 0);
217
218 layout->StartRowWithPadding(0, extension_list_column_set_id,
219 0, kHeadlineMessagePadding);
220 views::Label* extensions = new views::Label();
221 extensions->SetMultiLine(true);
222 extensions->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
223 extensions->SetFont(extensions->font().DeriveFont(0, gfx::Font::ITALIC));
224
225 std::vector<string16> extension_list;
226 int count = 0;
227 for (ExtensionSet::const_iterator iter = wiped_out_->begin();
228 iter != wiped_out_->end() && count < kMaxExtensionsToShow; ++iter) {
229 const extensions::Extension* extension = *iter;
230 extension_list.push_back(ASCIIToUTF16("- ") +
231 UTF8ToUTF16(extension->name()));
232 count++;
233 }
234
235 if (count == kMaxExtensionsToShow) {
236 string16 difference =
237 base::IntToString16(wiped_out_->size() - kMaxExtensionsToShow);
238 extension_list.push_back(ASCIIToUTF16("- ") +
239 l10n_util::GetStringFUTF16(IDS_OPTIONS_SIDELOAD_WIPEOUT_OVERFLOW,
240 difference));
241 }
242
243 extensions->SetText(JoinString(extension_list, ASCIIToUTF16("\n")));
244 extensions->SizeToFit(views::Widget::GetLocalizedContentsWidth(
245 IDS_DISABLED_EXTENSIONS_BUBBLE_WIDTH_CHARS));
246 layout->AddView(extensions);
247
248 layout->StartRowWithPadding(
249 0, text_column_set_id, 0, kHeadlineMessagePadding);
250 views::Label* recourse = new views::Label();
251 recourse->SetMultiLine(true);
252 recourse->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
253 recourse->SetText(
254 l10n_util::GetStringUTF16(IDS_OPTIONS_SIDELOAD_WIPEOUT_RECOURSE));
255 recourse->SizeToFit(views::Widget::GetLocalizedContentsWidth(
256 IDS_DISABLED_EXTENSIONS_BUBBLE_WIDTH_CHARS));
257 layout->AddView(recourse);
258
259 const int action_row_column_set_id = 3;
260 views::ColumnSet* bottom_columns =
261 layout->AddColumnSet(action_row_column_set_id);
262 bottom_columns->AddPaddingColumn(0, left_padding_column);
263 bottom_columns->AddPaddingColumn(0, kColumnPadding);
264 bottom_columns->AddColumn(views::GridLayout::LEADING,
265 views::GridLayout::CENTER, 0, views::GridLayout::USE_PREF, 0, 0);
266 bottom_columns->AddPaddingColumn(1, views::kRelatedButtonHSpacing);
267 bottom_columns->AddColumn(views::GridLayout::TRAILING,
268 views::GridLayout::CENTER, 0, views::GridLayout::USE_PREF, 0, 0);
269 bottom_columns->AddPaddingColumn(0, views::kRelatedButtonHSpacing);
270 bottom_columns->AddColumn(views::GridLayout::TRAILING,
271 views::GridLayout::CENTER, 0, views::GridLayout::USE_PREF, 0, 0);
272 layout->StartRowWithPadding(0, action_row_column_set_id,
273 0, kMessageBubblePadding);
274
275 learn_more_ = new views::Link(l10n_util::GetStringUTF16(IDS_LEARN_MORE));
276 learn_more_->set_listener(this);
277 layout->AddView(learn_more_);
278
279 settings_button_ = new views::NativeTextButton(this,
280 l10n_util::GetStringUTF16(IDS_OPTIONS_SIDELOAD_WIPEOUT_SETTINGS));
281 settings_button_->SetIsDefault(true);
282 layout->AddView(settings_button_);
283 dismiss_button_ = new views::NativeTextButton(this,
284 l10n_util::GetStringUTF16(IDS_OPTIONS_SIDELOAD_WIPEOUT_DISMISS));
285 dismiss_button_->SetFont(
286 dismiss_button_->font().DeriveFont(0, gfx::Font::BOLD));
287 layout->AddView(dismiss_button_);
288
289 content::RecordAction(
290 UserMetricsAction("DisabledExtensionNotificationShown"));
291 }
OLDNEW
« no previous file with comments | « chrome/browser/ui/views/extensions/disabled_extensions_view.h ('k') | chrome/browser/ui/views/toolbar_view.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698