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

Side by Side Diff: ui/app_list/views/app_list_view.cc

Issue 2802903003: Implementation of a full screen app list and re-alphabetized switches (Closed)
Patch Set: Addressed comments, added my tests to the filter, and refactored! Created 3 years, 8 months 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
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "ui/app_list/views/app_list_view.h" 5 #include "ui/app_list/views/app_list_view.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 8
9 #include "base/command_line.h" 9 #include "base/command_line.h"
10 #include "base/macros.h" 10 #include "base/macros.h"
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after
117 bool GetHitTestMask(aura::Window* window, gfx::Path* mask) const override { 117 bool GetHitTestMask(aura::Window* window, gfx::Path* mask) const override {
118 mask->addRect(gfx::RectToSkRect(search_box_->GetContentsBounds())); 118 mask->addRect(gfx::RectToSkRect(search_box_->GetContentsBounds()));
119 return true; 119 return true;
120 } 120 }
121 121
122 views::View* search_box_; 122 views::View* search_box_;
123 123
124 DISALLOW_COPY_AND_ASSIGN(SearchBoxWindowTargeter); 124 DISALLOW_COPY_AND_ASSIGN(SearchBoxWindowTargeter);
125 }; 125 };
126 126
127 // Returns whether the fullscreen app list has been enabled via cmd line switch.
128 bool IsFullscreenAppListEnabled() {
129 return base::CommandLine::ForCurrentProcess()->HasSwitch(
130 switches::kEnableFullscreenAppList);
131 }
132
127 } // namespace 133 } // namespace
128 134
129 // An animation observer to hide the view at the end of the animation. 135 // An animation observer to hide the view at the end of the animation.
130 class HideViewAnimationObserver : public ui::ImplicitAnimationObserver { 136 class HideViewAnimationObserver : public ui::ImplicitAnimationObserver {
131 public: 137 public:
132 HideViewAnimationObserver() 138 HideViewAnimationObserver() : frame_(NULL), target_(NULL) {}
133 : frame_(NULL),
134 target_(NULL) {
135 }
136 139
137 ~HideViewAnimationObserver() override { 140 ~HideViewAnimationObserver() override {
138 if (target_) 141 if (target_)
139 StopObservingImplicitAnimations(); 142 StopObservingImplicitAnimations();
140 } 143 }
141 144
142 void SetTarget(views::View* target) { 145 void SetTarget(views::View* target) {
143 if (target_) 146 if (target_)
144 StopObservingImplicitAnimations(); 147 StopObservingImplicitAnimations();
145 target_ = target; 148 target_ = target;
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
183 delegate_->GetSpeechUI()->AddObserver(this); 186 delegate_->GetSpeechUI()->AddObserver(this);
184 } 187 }
185 188
186 AppListView::~AppListView() { 189 AppListView::~AppListView() {
187 delegate_->GetSpeechUI()->RemoveObserver(this); 190 delegate_->GetSpeechUI()->RemoveObserver(this);
188 animation_observer_.reset(); 191 animation_observer_.reset();
189 // Remove child views first to ensure no remaining dependencies on delegate_. 192 // Remove child views first to ensure no remaining dependencies on delegate_.
190 RemoveAllChildViews(true); 193 RemoveAllChildViews(true);
191 } 194 }
192 195
193 void AppListView::InitAsBubble(gfx::NativeView parent, int initial_apps_page) { 196 void AppListView::Initialize(gfx::NativeView parent,
197 int initial_apps_page,
198 const gfx::Rect& display_work_area_bounds) {
199 base::Time start_time = base::Time::Now();
200 InitContents(parent, initial_apps_page);
201 AddAccelerator(ui::Accelerator(ui::VKEY_ESCAPE, ui::EF_NONE));
202 set_color(kContentsBackgroundColor);
203
204 if (IsFullscreenAppListEnabled()) {
205 InitializeFullscreen(parent, initial_apps_page,
206 display_work_area_bounds);
vadimt 2017/04/20 20:21:35 indentation....
sky 2017/04/20 21:08:45 I think if you run git cl format it'll fix all the
newcomer 2017/04/21 19:51:22 I gave it a shot!
207 } else {
208 InitializeBubble(parent, initial_apps_page);
209 }
210
211 InitChildWidgets();
212 AddChildView(overlay_view_);
213 if (delegate_)
214 delegate_->ViewInitialized();
215 UMA_HISTOGRAM_TIMES("Apps.AppListCreationTime",
216 base::Time::Now() - start_time);
217 }
218
219 void AppListView::Initialize(gfx::NativeView parent,
220 int initial_apps_page){
194 base::Time start_time = base::Time::Now(); 221 base::Time start_time = base::Time::Now();
195 222
196 InitContents(parent, initial_apps_page); 223 InitContents(parent, initial_apps_page);
197
198 AddAccelerator(ui::Accelerator(ui::VKEY_ESCAPE, ui::EF_NONE)); 224 AddAccelerator(ui::Accelerator(ui::VKEY_ESCAPE, ui::EF_NONE));
199 set_margins(gfx::Insets());
200 set_parent_window(parent);
201 set_close_on_deactivate(false);
202 set_shadow(views::BubbleBorder::NO_ASSETS);
203 set_color(kContentsBackgroundColor); 225 set_color(kContentsBackgroundColor);
204 // This creates the app list widget. (Before this, child widgets cannot be 226 InitializeBubble(parent, initial_apps_page);
205 // created.)
206 views::BubbleDialogDelegateView::CreateBubble(this);
207
208 SetBubbleArrow(views::BubbleBorder::FLOAT);
209 // We can now create the internal widgets.
210 InitChildWidgets(); 227 InitChildWidgets();
211
212 aura::Window* window = GetWidget()->GetNativeWindow();
213 window->SetEventTargeter(base::MakeUnique<views::BubbleWindowTargeter>(this));
214
215 const int kOverlayCornerRadius =
216 GetBubbleFrameView()->bubble_border()->GetBorderCornerRadius();
217 overlay_view_ = new AppListOverlayView(kOverlayCornerRadius);
218 overlay_view_->SetBoundsRect(GetContentsBounds());
219 AddChildView(overlay_view_); 228 AddChildView(overlay_view_);
220 229
221 if (delegate_) 230 if (delegate_)
222 delegate_->ViewInitialized(); 231 delegate_->ViewInitialized();
223 232
224 UMA_HISTOGRAM_TIMES("Apps.AppListCreationTime", 233 UMA_HISTOGRAM_TIMES("Apps.AppListCreationTime",
225 base::Time::Now() - start_time); 234 base::Time::Now() - start_time);
226 } 235 }
227 236
228 void AppListView::SetBubbleArrow(views::BubbleBorder::Arrow arrow) { 237 void AppListView::SetBubbleArrow(views::BubbleBorder::Arrow arrow) {
229 GetBubbleFrameView()->bubble_border()->set_arrow(arrow); 238 GetBubbleFrameView()->bubble_border()->set_arrow(arrow);
230 SizeToContents(); // Recalcuates with new border. 239 SizeToContents(); // Recalcuates with new border.
231 GetBubbleFrameView()->SchedulePaint(); 240 GetBubbleFrameView()->SchedulePaint();
232 } 241 }
233 242
234 void AppListView::SetAnchorPoint(const gfx::Point& anchor_point) { 243 void AppListView::MaybeSetAnchorPoint(const gfx::Point& anchor_point) {
235 SetAnchorRect(gfx::Rect(anchor_point, gfx::Size())); 244 // if the AppListView is a bubble
245 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
246 app_list::switches::kEnableFullscreenAppList)) {
247 SetAnchorRect(gfx::Rect(anchor_point, gfx::Size()));
248 }
236 } 249 }
237 250
238 void AppListView::SetDragAndDropHostOfCurrentAppList( 251 void AppListView::SetDragAndDropHostOfCurrentAppList(
239 ApplicationDragAndDropHost* drag_and_drop_host) { 252 ApplicationDragAndDropHost* drag_and_drop_host) {
240 app_list_main_view_->SetDragAndDropHostOfCurrentAppList(drag_and_drop_host); 253 app_list_main_view_->SetDragAndDropHostOfCurrentAppList(drag_and_drop_host);
241 } 254 }
242 255
243 void AppListView::ShowWhenReady() { 256 void AppListView::ShowWhenReady() {
244 app_list_main_view_->ShowAppListWhenReady(); 257 app_list_main_view_->ShowAppListWhenReady();
245 } 258 }
246 259
247 void AppListView::CloseAppList() { 260 void AppListView::CloseAppList() {
248 app_list_main_view_->Close(); 261 app_list_main_view_->Close();
249 delegate_->Dismiss(); 262 delegate_->Dismiss();
250 } 263 }
251 264
252 void AppListView::UpdateBounds() { 265 void AppListView::UpdateBounds() {
253 SizeToContents(); 266 // if the AppListView is a bubble
267 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
268 app_list::switches::kEnableFullscreenAppList)) {
269 SizeToContents();
270 }
254 } 271 }
255 272
256 void AppListView::SetAppListOverlayVisible(bool visible) { 273 void AppListView::SetAppListOverlayVisible(bool visible) {
257 DCHECK(overlay_view_); 274 DCHECK(overlay_view_);
258 275
259 // Display the overlay immediately so we can begin the animation. 276 // Display the overlay immediately so we can begin the animation.
260 overlay_view_->SetVisible(true); 277 overlay_view_->SetVisible(true);
261 278
262 ui::ScopedLayerAnimationSettings settings( 279 ui::ScopedLayerAnimationSettings settings(
263 overlay_view_->layer()->GetAnimator()); 280 overlay_view_->layer()->GetAnimator());
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
297 } 314 }
298 315
299 void AppListView::OnPaint(gfx::Canvas* canvas) { 316 void AppListView::OnPaint(gfx::Canvas* canvas) {
300 views::BubbleDialogDelegateView::OnPaint(canvas); 317 views::BubbleDialogDelegateView::OnPaint(canvas);
301 if (!next_paint_callback_.is_null()) { 318 if (!next_paint_callback_.is_null()) {
302 next_paint_callback_.Run(); 319 next_paint_callback_.Run();
303 next_paint_callback_.Reset(); 320 next_paint_callback_.Reset();
304 } 321 }
305 } 322 }
306 323
324 const char* AppListView::GetClassName() const {
325 return "AppListView";
326 }
327
307 bool AppListView::ShouldHandleSystemCommands() const { 328 bool AppListView::ShouldHandleSystemCommands() const {
308 return true; 329 return true;
309 } 330 }
310 331
311 bool AppListView::ShouldDescendIntoChildForEventHandling( 332 bool AppListView::ShouldDescendIntoChildForEventHandling(
312 gfx::NativeView child, 333 gfx::NativeView child,
313 const gfx::Point& location) { 334 const gfx::Point& location) {
314 // While on the start page, don't descend into the custom launcher page. Since 335 // While on the start page, don't descend into the custom launcher page. Since
315 // the only valid action is to open it. 336 // the only valid action is to open it.
316 ContentsView* contents_view = app_list_main_view_->contents_view(); 337 ContentsView* contents_view = app_list_main_view_->contents_view();
(...skipping 19 matching lines...) Expand all
336 // crbug.com/441028 are fixed. 357 // crbug.com/441028 are fixed.
337 tracked_objects::ScopedTracker tracking_profile( 358 tracked_objects::ScopedTracker tracking_profile(
338 FROM_HERE_WITH_EXPLICIT_FUNCTION( 359 FROM_HERE_WITH_EXPLICIT_FUNCTION(
339 "440224, 441028 AppListView::InitContents")); 360 "440224, 441028 AppListView::InitContents"));
340 361
341 app_list_main_view_ = new AppListMainView(delegate_); 362 app_list_main_view_ = new AppListMainView(delegate_);
342 AddChildView(app_list_main_view_); 363 AddChildView(app_list_main_view_);
343 app_list_main_view_->SetPaintToLayer(); 364 app_list_main_view_->SetPaintToLayer();
344 app_list_main_view_->layer()->SetFillsBoundsOpaquely(false); 365 app_list_main_view_->layer()->SetFillsBoundsOpaquely(false);
345 app_list_main_view_->layer()->SetMasksToBounds(true); 366 app_list_main_view_->layer()->SetMasksToBounds(true);
346
347 // This will be added to the |search_box_widget_| after the app list widget is 367 // This will be added to the |search_box_widget_| after the app list widget is
348 // initialized. 368 // initialized.
349 search_box_view_ = new SearchBoxView(app_list_main_view_, delegate_); 369 search_box_view_ = new SearchBoxView(app_list_main_view_, delegate_);
350 search_box_view_->SetPaintToLayer(); 370 search_box_view_->SetPaintToLayer();
351 search_box_view_->layer()->SetFillsBoundsOpaquely(false); 371 search_box_view_->layer()->SetFillsBoundsOpaquely(false);
352 search_box_view_->layer()->SetMasksToBounds(true); 372 search_box_view_->layer()->SetMasksToBounds(true);
353 373
354 // TODO(vadimt): Remove ScopedTracker below once crbug.com/440224 and 374 // TODO(vadimt): Remove ScopedTracker below once crbug.com/440224 and
355 // crbug.com/441028 are fixed. 375 // crbug.com/441028 are fixed.
356 tracked_objects::ScopedTracker tracking_profile1( 376 tracked_objects::ScopedTracker tracking_profile1(
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
403 GetWidget()->GetFocusTraversable()); 423 GetWidget()->GetFocusTraversable());
404 424
405 // Mouse events on the search box shadow should not be captured. 425 // Mouse events on the search box shadow should not be captured.
406 aura::Window* window = search_box_widget_->GetNativeWindow(); 426 aura::Window* window = search_box_widget_->GetNativeWindow();
407 window->SetEventTargeter( 427 window->SetEventTargeter(
408 base::MakeUnique<SearchBoxWindowTargeter>(search_box_view_)); 428 base::MakeUnique<SearchBoxWindowTargeter>(search_box_view_));
409 429
410 app_list_main_view_->contents_view()->Layout(); 430 app_list_main_view_->contents_view()->Layout();
411 } 431 }
412 432
413 void AppListView::OnBeforeBubbleWidgetInit( 433 void AppListView::InitializeFullscreen(
414 views::Widget::InitParams* params, 434 gfx::NativeView parent,
415 views::Widget* widget) const { 435 int initial_apps_page,
436 const gfx::Rect& display_work_area_bounds) {
437
438 views::Widget* widget = new views::Widget;
439 views::Widget::InitParams app_list_overlay_view_params(
440 views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
441
442 app_list_overlay_view_params.parent = parent;
443 app_list_overlay_view_params.delegate = this;
444
445 widget->Init(app_list_overlay_view_params);
446 widget->SetBounds(display_work_area_bounds);
447 widget->GetLayer()->SetFillsBoundsOpaquely(false);
448 widget->GetLayer()->SetBackgroundBlur(10);
449
450 overlay_view_ = new AppListOverlayView(0 /* no corners */);
451 }
452
453 void AppListView::InitializeBubble(gfx::NativeView parent,
454 int initial_apps_page) {
455 set_margins(gfx::Insets());
456 set_parent_window(parent);
457 set_close_on_deactivate(false);
458 set_shadow(views::BubbleBorder::NO_ASSETS);
459
460
461 // This creates the app list widget. (Before this, child widgets cannot be
462 // created.)
463 views::BubbleDialogDelegateView::CreateBubble(this);
464
465 SetBubbleArrow(views::BubbleBorder::FLOAT);
466 // We can now create the internal widgets.
467
468 aura::Window* window = GetWidget()->GetNativeWindow();
469 window->SetEventTargeter(base::MakeUnique<views::BubbleWindowTargeter>(this));
470
471 const int kOverlayCornerRadius =
472 GetBubbleFrameView()->bubble_border()->GetBorderCornerRadius();
473 overlay_view_ = new AppListOverlayView(kOverlayCornerRadius);
474 overlay_view_->SetBoundsRect(GetContentsBounds());
475 }
476
477 void AppListView::OnBeforeBubbleWidgetInit(views::Widget::InitParams* params,
478 views::Widget* widget) const {
416 if (!params->native_widget) { 479 if (!params->native_widget) {
417 views::ViewsDelegate* views_delegate = views::ViewsDelegate::GetInstance(); 480 views::ViewsDelegate* views_delegate = views::ViewsDelegate::GetInstance();
418 if (views_delegate && !views_delegate->native_widget_factory().is_null()) { 481 if (views_delegate && !views_delegate->native_widget_factory().is_null()) {
419 params->native_widget = 482 params->native_widget =
420 views_delegate->native_widget_factory().Run(*params, widget); 483 views_delegate->native_widget_factory().Run(*params, widget);
421 } 484 }
422 } 485 }
423 // Apply a WM-provided shadow (see ui/wm/core/). 486 // Apply a WM-provided shadow (see ui/wm/core/).
424 params->shadow_type = views::Widget::InitParams::SHADOW_TYPE_DROP; 487 params->shadow_type = views::Widget::InitParams::SHADOW_TYPE_DROP;
425 params->shadow_elevation = wm::ShadowElevation::LARGE; 488 params->shadow_elevation = wm::ShadowElevation::LARGE;
426 } 489 }
427 490
428 int AppListView::GetDialogButtons() const { 491 int AppListView::GetDialogButtons() const {
429 return ui::DIALOG_BUTTON_NONE; 492 return ui::DIALOG_BUTTON_NONE;
430 } 493 }
431 494
432 views::View* AppListView::GetInitiallyFocusedView() { 495 views::View* AppListView::GetInitiallyFocusedView() {
433 return app_list_main_view_->search_box_view()->search_box(); 496 return app_list_main_view_->search_box_view()->search_box();
434 } 497 }
435 498
436 bool AppListView::WidgetHasHitTestMask() const { 499 bool AppListView::WidgetHasHitTestMask() const {
437 return GetBubbleFrameView() != nullptr; 500 return GetBubbleFrameView() != nullptr;
438 } 501 }
439 502
440 void AppListView::GetWidgetHitTestMask(gfx::Path* mask) const { 503 void AppListView::GetWidgetHitTestMask(gfx::Path* mask) const {
441 DCHECK(mask); 504 DCHECK(mask);
442 DCHECK(GetBubbleFrameView()); 505 DCHECK(GetBubbleFrameView());
443 506
444 mask->addRect(gfx::RectToSkRect( 507 mask->addRect(gfx::RectToSkRect(GetBubbleFrameView()->GetContentsBounds()));
445 GetBubbleFrameView()->GetContentsBounds()));
446 } 508 }
447 509
448 bool AppListView::AcceleratorPressed(const ui::Accelerator& accelerator) { 510 bool AppListView::AcceleratorPressed(const ui::Accelerator& accelerator) {
449 DCHECK_EQ(ui::VKEY_ESCAPE, accelerator.key_code()); 511 DCHECK_EQ(ui::VKEY_ESCAPE, accelerator.key_code());
450 512
451 // If the ContentsView does not handle the back action, then this is the 513 // If the ContentsView does not handle the back action, then this is the
452 // top level, so we close the app list. 514 // top level, so we close the app list.
453 if (!app_list_main_view_->contents_view()->Back()) { 515 if (!app_list_main_view_->contents_view()->Back()) {
454 GetWidget()->Deactivate(); 516 GetWidget()->Deactivate();
455 CloseAppList(); 517 CloseAppList();
(...skipping 12 matching lines...) Expand all
468 centered_bounds.ClampToCenteredSize(gfx::Size( 530 centered_bounds.ClampToCenteredSize(gfx::Size(
469 app_list_main_view_->contents_view()->GetDefaultContentsBounds().width(), 531 app_list_main_view_->contents_view()->GetDefaultContentsBounds().width(),
470 contents_bounds.height())); 532 contents_bounds.height()));
471 533
472 app_list_main_view_->SetBoundsRect(centered_bounds); 534 app_list_main_view_->SetBoundsRect(centered_bounds);
473 535
474 if (speech_view_) { 536 if (speech_view_) {
475 gfx::Rect speech_bounds = centered_bounds; 537 gfx::Rect speech_bounds = centered_bounds;
476 int preferred_height = speech_view_->GetPreferredSize().height(); 538 int preferred_height = speech_view_->GetPreferredSize().height();
477 speech_bounds.Inset(kSpeechUIMargin, kSpeechUIMargin); 539 speech_bounds.Inset(kSpeechUIMargin, kSpeechUIMargin);
478 speech_bounds.set_height(std::min(speech_bounds.height(), 540 speech_bounds.set_height(
479 preferred_height)); 541 std::min(speech_bounds.height(), preferred_height));
480 speech_bounds.Inset(-speech_view_->GetInsets()); 542 speech_bounds.Inset(-speech_view_->GetInsets());
481 speech_view_->SetBoundsRect(speech_bounds); 543 speech_view_->SetBoundsRect(speech_bounds);
482 } 544 }
483 } 545 }
484 546
485 void AppListView::SchedulePaintInRect(const gfx::Rect& rect) { 547 void AppListView::SchedulePaintInRect(const gfx::Rect& rect) {
486 BubbleDialogDelegateView::SchedulePaintInRect(rect); 548 BubbleDialogDelegateView::SchedulePaintInRect(rect);
487 if (GetBubbleFrameView()) 549 if (GetBubbleFrameView())
488 GetBubbleFrameView()->SchedulePaint(); 550 GetBubbleFrameView()->SchedulePaint();
489 } 551 }
(...skipping 25 matching lines...) Expand all
515 new_state == SPEECH_RECOGNITION_NETWORK_ERROR); 577 new_state == SPEECH_RECOGNITION_NETWORK_ERROR);
516 // No change for this class. 578 // No change for this class.
517 if (speech_view_->visible() == will_appear) 579 if (speech_view_->visible() == will_appear)
518 return; 580 return;
519 581
520 if (will_appear) 582 if (will_appear)
521 speech_view_->Reset(); 583 speech_view_->Reset();
522 584
523 animation_observer_->set_frame(GetBubbleFrameView()); 585 animation_observer_->set_frame(GetBubbleFrameView());
524 gfx::Transform speech_transform; 586 gfx::Transform speech_transform;
525 speech_transform.Translate( 587 speech_transform.Translate(0, SkFloatToMScalar(kSpeechUIAppearingPosition));
526 0, SkFloatToMScalar(kSpeechUIAppearingPosition));
527 if (will_appear) 588 if (will_appear)
528 speech_view_->layer()->SetTransform(speech_transform); 589 speech_view_->layer()->SetTransform(speech_transform);
529 590
530 { 591 {
531 ui::ScopedLayerAnimationSettings main_settings( 592 ui::ScopedLayerAnimationSettings main_settings(
532 app_list_main_view_->layer()->GetAnimator()); 593 app_list_main_view_->layer()->GetAnimator());
533 if (will_appear) { 594 if (will_appear) {
534 animation_observer_->SetTarget(app_list_main_view_); 595 animation_observer_->SetTarget(app_list_main_view_);
535 main_settings.AddObserver(animation_observer_.get()); 596 main_settings.AddObserver(animation_observer_.get());
536 } 597 }
(...skipping 30 matching lines...) Expand all
567 app_list_main_view_->SetVisible(true); 628 app_list_main_view_->SetVisible(true);
568 // Refocus the search box. However, if the app list widget does not have 629 // Refocus the search box. However, if the app list widget does not have
569 // focus, it means another window has already taken focus, and we *must not* 630 // focus, it means another window has already taken focus, and we *must not*
570 // focus the search box (or we would steal focus back into the app list). 631 // focus the search box (or we would steal focus back into the app list).
571 if (GetWidget()->IsActive()) 632 if (GetWidget()->IsActive())
572 search_box_view_->search_box()->RequestFocus(); 633 search_box_view_->search_box()->RequestFocus();
573 } 634 }
574 } 635 }
575 636
576 } // namespace app_list 637 } // namespace app_list
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698