Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / ui / app_list / views / app_list_view.cc
blobcd4dd58110f90aedf9f81e63c71ee37eb2bcaed9
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.
5 #include "ui/app_list/views/app_list_view.h"
7 #include <algorithm>
9 #include "base/command_line.h"
10 #include "base/metrics/histogram.h"
11 #include "base/profiler/scoped_tracker.h"
12 #include "base/strings/string_util.h"
13 #include "base/win/windows_version.h"
14 #include "ui/app_list/app_list_constants.h"
15 #include "ui/app_list/app_list_model.h"
16 #include "ui/app_list/app_list_switches.h"
17 #include "ui/app_list/app_list_view_delegate.h"
18 #include "ui/app_list/speech_ui_model.h"
19 #include "ui/app_list/views/app_list_background.h"
20 #include "ui/app_list/views/app_list_folder_view.h"
21 #include "ui/app_list/views/app_list_main_view.h"
22 #include "ui/app_list/views/app_list_view_observer.h"
23 #include "ui/app_list/views/apps_container_view.h"
24 #include "ui/app_list/views/contents_view.h"
25 #include "ui/app_list/views/custom_launcher_page_view.h"
26 #include "ui/app_list/views/search_box_view.h"
27 #include "ui/app_list/views/speech_view.h"
28 #include "ui/app_list/views/start_page_view.h"
29 #include "ui/base/ui_base_switches.h"
30 #include "ui/compositor/layer.h"
31 #include "ui/compositor/layer_animation_observer.h"
32 #include "ui/compositor/scoped_layer_animation_settings.h"
33 #include "ui/gfx/canvas.h"
34 #include "ui/gfx/geometry/insets.h"
35 #include "ui/gfx/image/image_skia.h"
36 #include "ui/gfx/path.h"
37 #include "ui/gfx/skia_util.h"
38 #include "ui/resources/grit/ui_resources.h"
39 #include "ui/views/bubble/bubble_frame_view.h"
40 #include "ui/views/controls/image_view.h"
41 #include "ui/views/controls/textfield/textfield.h"
42 #include "ui/views/layout/fill_layout.h"
43 #include "ui/views/widget/widget.h"
45 #if defined(USE_AURA)
46 #include "ui/aura/window.h"
47 #include "ui/aura/window_tree_host.h"
48 #include "ui/views/bubble/bubble_window_targeter.h"
49 #include "ui/wm/core/masked_window_targeter.h"
50 #if defined(OS_WIN)
51 #include "ui/base/win/shell.h"
52 #endif
53 #if !defined(OS_CHROMEOS)
54 #include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
55 #endif
56 #endif // defined(USE_AURA)
58 namespace app_list {
60 namespace {
62 // The margin from the edge to the speech UI.
63 const int kSpeechUIMargin = 12;
65 // The vertical position for the appearing animation of the speech UI.
66 const float kSpeechUIAppearingPosition = 12;
68 // The distance between the arrow tip and edge of the anchor view.
69 const int kArrowOffset = 10;
71 // Determines whether the current environment supports shadows bubble borders.
72 bool SupportsShadow() {
73 #if defined(OS_WIN)
74 // Shadows are not supported on Windows without Aero Glass.
75 if (!ui::win::IsAeroGlassEnabled() ||
76 base::CommandLine::ForCurrentProcess()->HasSwitch(
77 ::switches::kDisableDwmComposition)) {
78 return false;
80 #elif defined(OS_LINUX) && !defined(OS_CHROMEOS)
81 // Shadows are not supported on (non-ChromeOS) Linux.
82 return false;
83 #endif
84 return true;
87 // This view forwards the focus to the search box widget by providing it as a
88 // FocusTraversable when a focus search is provided.
89 class SearchBoxFocusHost : public views::View {
90 public:
91 explicit SearchBoxFocusHost(views::Widget* search_box_widget)
92 : search_box_widget_(search_box_widget) {}
94 ~SearchBoxFocusHost() override {}
96 views::FocusTraversable* GetFocusTraversable() override {
97 return search_box_widget_;
100 private:
101 views::Widget* search_box_widget_;
103 DISALLOW_COPY_AND_ASSIGN(SearchBoxFocusHost);
106 // The view for the App List overlay, which appears as a white rounded
107 // rectangle with the given radius.
108 class AppListOverlayView : public views::View {
109 public:
110 explicit AppListOverlayView(int corner_radius)
111 : corner_radius_(corner_radius) {
112 SetPaintToLayer(true);
113 SetVisible(false);
114 layer()->SetOpacity(0.0f);
117 ~AppListOverlayView() override {}
119 // Overridden from views::View:
120 void OnPaint(gfx::Canvas* canvas) override {
121 SkPaint paint;
122 paint.setStyle(SkPaint::kFill_Style);
123 paint.setColor(SK_ColorWHITE);
124 canvas->DrawRoundRect(GetContentsBounds(), corner_radius_, paint);
127 private:
128 const int corner_radius_;
130 DISALLOW_COPY_AND_ASSIGN(AppListOverlayView);
133 #if defined(USE_AURA)
134 // An event targeter for the search box widget which will ignore events that
135 // are on the search box's shadow.
136 class SearchBoxWindowTargeter : public wm::MaskedWindowTargeter {
137 public:
138 explicit SearchBoxWindowTargeter(views::View* search_box)
139 : wm::MaskedWindowTargeter(search_box->GetWidget()->GetNativeWindow()),
140 search_box_(search_box) {}
141 ~SearchBoxWindowTargeter() override {}
143 private:
144 // wm::MaskedWindowTargeter:
145 bool GetHitTestMask(aura::Window* window, gfx::Path* mask) const override {
146 mask->addRect(gfx::RectToSkRect(search_box_->GetContentsBounds()));
147 return true;
150 views::View* search_box_;
152 DISALLOW_COPY_AND_ASSIGN(SearchBoxWindowTargeter);
154 #endif
156 } // namespace
158 // An animation observer to hide the view at the end of the animation.
159 class HideViewAnimationObserver : public ui::ImplicitAnimationObserver {
160 public:
161 HideViewAnimationObserver()
162 : frame_(NULL),
163 target_(NULL) {
166 ~HideViewAnimationObserver() override {
167 if (target_)
168 StopObservingImplicitAnimations();
171 void SetTarget(views::View* target) {
172 if (target_)
173 StopObservingImplicitAnimations();
174 target_ = target;
177 void set_frame(views::BubbleFrameView* frame) { frame_ = frame; }
179 private:
180 // Overridden from ui::ImplicitAnimationObserver:
181 void OnImplicitAnimationsCompleted() override {
182 if (target_) {
183 target_->SetVisible(false);
184 target_ = NULL;
186 // Should update the background by invoking SchedulePaint().
187 if (frame_)
188 frame_->SchedulePaint();
192 views::BubbleFrameView* frame_;
193 views::View* target_;
195 DISALLOW_COPY_AND_ASSIGN(HideViewAnimationObserver);
198 ////////////////////////////////////////////////////////////////////////////////
199 // AppListView:
201 AppListView::AppListView(AppListViewDelegate* delegate)
202 : delegate_(delegate),
203 app_list_main_view_(nullptr),
204 speech_view_(nullptr),
205 search_box_focus_host_(nullptr),
206 search_box_widget_(nullptr),
207 search_box_view_(nullptr),
208 overlay_view_(nullptr),
209 animation_observer_(new HideViewAnimationObserver()) {
210 CHECK(delegate);
212 delegate_->AddObserver(this);
213 delegate_->GetSpeechUI()->AddObserver(this);
216 AppListView::~AppListView() {
217 delegate_->GetSpeechUI()->RemoveObserver(this);
218 delegate_->RemoveObserver(this);
219 animation_observer_.reset();
220 // Remove child views first to ensure no remaining dependencies on delegate_.
221 RemoveAllChildViews(true);
224 void AppListView::InitAsBubbleAttachedToAnchor(
225 gfx::NativeView parent,
226 int initial_apps_page,
227 views::View* anchor,
228 const gfx::Vector2d& anchor_offset,
229 views::BubbleBorder::Arrow arrow,
230 bool border_accepts_events) {
231 SetAnchorView(anchor);
232 InitAsBubbleInternal(
233 parent, initial_apps_page, arrow, border_accepts_events, anchor_offset);
236 void AppListView::InitAsBubbleAtFixedLocation(
237 gfx::NativeView parent,
238 int initial_apps_page,
239 const gfx::Point& anchor_point_in_screen,
240 views::BubbleBorder::Arrow arrow,
241 bool border_accepts_events) {
242 SetAnchorView(NULL);
243 SetAnchorRect(gfx::Rect(anchor_point_in_screen, gfx::Size()));
244 InitAsBubbleInternal(
245 parent, initial_apps_page, arrow, border_accepts_events, gfx::Vector2d());
248 void AppListView::InitAsFramelessWindow(gfx::NativeView parent,
249 int initial_apps_page,
250 gfx::Rect bounds) {
251 InitContents(parent, initial_apps_page);
252 overlay_view_ = new AppListOverlayView(0 /* no corners */);
253 AddChildView(overlay_view_);
255 views::Widget* widget = new views::Widget();
256 views::Widget::InitParams params(
257 views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
258 params.parent = parent;
259 params.delegate = this;
260 widget->Init(params);
261 widget->SetBounds(bounds);
262 // This needs to be set *after* Widget::Init() because BubbleDelegateView sets
263 // its own background at OnNativeThemeChanged(), which is called in
264 // View::AddChildView() which is called at Widget::SetContentsView() to build
265 // the views hierarchy in the widget.
266 set_background(new AppListBackground(0));
268 InitChildWidgets();
271 void AppListView::SetBubbleArrow(views::BubbleBorder::Arrow arrow) {
272 GetBubbleFrameView()->bubble_border()->set_arrow(arrow);
273 SizeToContents(); // Recalcuates with new border.
274 GetBubbleFrameView()->SchedulePaint();
277 void AppListView::SetAnchorPoint(const gfx::Point& anchor_point) {
278 SetAnchorRect(gfx::Rect(anchor_point, gfx::Size()));
281 void AppListView::SetDragAndDropHostOfCurrentAppList(
282 ApplicationDragAndDropHost* drag_and_drop_host) {
283 app_list_main_view_->SetDragAndDropHostOfCurrentAppList(drag_and_drop_host);
286 void AppListView::ShowWhenReady() {
287 app_list_main_view_->ShowAppListWhenReady();
290 void AppListView::Close() {
291 app_list_main_view_->Close();
292 delegate_->Dismiss();
295 void AppListView::UpdateBounds() {
296 SizeToContents();
299 void AppListView::SetAppListOverlayVisible(bool visible) {
300 DCHECK(overlay_view_);
302 // Display the overlay immediately so we can begin the animation.
303 overlay_view_->SetVisible(true);
305 ui::ScopedLayerAnimationSettings settings(
306 overlay_view_->layer()->GetAnimator());
307 settings.SetTweenType(gfx::Tween::LINEAR);
309 // If we're dismissing the overlay, hide the view at the end of the animation.
310 if (!visible) {
311 // Since only one animation is visible at a time, it's safe to re-use
312 // animation_observer_ here.
313 animation_observer_->set_frame(NULL);
314 animation_observer_->SetTarget(overlay_view_);
315 settings.AddObserver(animation_observer_.get());
318 const float kOverlayFadeInMilliseconds = 125;
319 settings.SetTransitionDuration(
320 base::TimeDelta::FromMilliseconds(kOverlayFadeInMilliseconds));
322 const float kOverlayOpacity = 0.75f;
323 overlay_view_->layer()->SetOpacity(visible ? kOverlayOpacity : 0.0f);
324 // Create the illusion that the search box is hidden behind the app list
325 // overlay mask by setting its opacity to the same value, and disabling it.
327 ui::ScopedLayerAnimationSettings settings(
328 search_box_widget_->GetLayer()->GetAnimator());
329 const float kSearchBoxWidgetOpacity = 0.5f;
330 search_box_widget_->GetLayer()->SetOpacity(visible ? kSearchBoxWidgetOpacity
331 : 1.0f);
332 search_box_view_->SetEnabled(!visible);
333 if (!visible)
334 search_box_view_->search_box()->RequestFocus();
338 bool AppListView::ShouldCenterWindow() const {
339 return delegate_->ShouldCenterWindow();
342 gfx::Size AppListView::GetPreferredSize() const {
343 return app_list_main_view_->GetPreferredSize();
346 void AppListView::OnPaint(gfx::Canvas* canvas) {
347 views::BubbleDelegateView::OnPaint(canvas);
348 if (!next_paint_callback_.is_null()) {
349 next_paint_callback_.Run();
350 next_paint_callback_.Reset();
354 void AppListView::OnThemeChanged() {
355 #if defined(OS_WIN)
356 GetWidget()->Close();
357 #endif
360 bool AppListView::ShouldHandleSystemCommands() const {
361 return true;
364 bool AppListView::ShouldDescendIntoChildForEventHandling(
365 gfx::NativeView child,
366 const gfx::Point& location) {
367 // While on the start page, don't descend into the custom launcher page. Since
368 // the only valid action is to open it.
369 ContentsView* contents_view = app_list_main_view_->contents_view();
370 if (contents_view->custom_page_view() &&
371 contents_view->GetActiveState() == AppListModel::STATE_START)
372 return !contents_view->custom_page_view()
373 ->GetCollapsedLauncherPageBounds()
374 .Contains(location);
376 return views::BubbleDelegateView::ShouldDescendIntoChildForEventHandling(
377 child, location);
380 void AppListView::Prerender() {
381 app_list_main_view_->Prerender();
384 void AppListView::OnProfilesChanged() {
385 app_list_main_view_->search_box_view()->InvalidateMenu();
388 void AppListView::OnShutdown() {
389 // Nothing to do on views - the widget will soon be closed, which will tear
390 // everything down.
393 void AppListView::SetProfileByPath(const base::FilePath& profile_path) {
394 delegate_->SetProfileByPath(profile_path);
395 app_list_main_view_->ModelChanged();
398 void AppListView::AddObserver(AppListViewObserver* observer) {
399 observers_.AddObserver(observer);
402 void AppListView::RemoveObserver(AppListViewObserver* observer) {
403 observers_.RemoveObserver(observer);
406 // static
407 void AppListView::SetNextPaintCallback(const base::Closure& callback) {
408 next_paint_callback_ = callback;
411 #if defined(OS_WIN)
412 HWND AppListView::GetHWND() const {
413 gfx::NativeWindow window =
414 GetWidget()->GetTopLevelWidget()->GetNativeWindow();
415 return window->GetHost()->GetAcceleratedWidget();
417 #endif
419 PaginationModel* AppListView::GetAppsPaginationModel() {
420 return app_list_main_view_->contents_view()
421 ->apps_container_view()
422 ->apps_grid_view()
423 ->pagination_model();
426 void AppListView::InitContents(gfx::NativeView parent, int initial_apps_page) {
427 // TODO(vadimt): Remove ScopedTracker below once crbug.com/440224 and
428 // crbug.com/441028 are fixed.
429 tracked_objects::ScopedTracker tracking_profile(
430 FROM_HERE_WITH_EXPLICIT_FUNCTION(
431 "440224, 441028 AppListView::InitContents"));
433 app_list_main_view_ = new AppListMainView(delegate_);
434 AddChildView(app_list_main_view_);
435 app_list_main_view_->SetPaintToLayer(true);
436 app_list_main_view_->SetFillsBoundsOpaquely(false);
437 app_list_main_view_->layer()->SetMasksToBounds(true);
439 // This will be added to the |search_box_widget_| after the app list widget is
440 // initialized.
441 search_box_view_ = new SearchBoxView(app_list_main_view_, delegate_);
442 search_box_view_->SetPaintToLayer(true);
443 search_box_view_->SetFillsBoundsOpaquely(false);
444 search_box_view_->layer()->SetMasksToBounds(true);
446 // TODO(vadimt): Remove ScopedTracker below once crbug.com/440224 and
447 // crbug.com/441028 are fixed.
448 tracked_objects::ScopedTracker tracking_profile1(
449 FROM_HERE_WITH_EXPLICIT_FUNCTION(
450 "440224, 441028 AppListView::InitContents1"));
452 app_list_main_view_->Init(parent, initial_apps_page, search_box_view_);
454 // TODO(vadimt): Remove ScopedTracker below once crbug.com/440224 and
455 // crbug.com/441028 are fixed.
456 tracked_objects::ScopedTracker tracking_profile2(
457 FROM_HERE_WITH_EXPLICIT_FUNCTION(
458 "440224, 441028 AppListView::InitContents2"));
460 // Speech recognition is available only when the start page exists.
461 if (delegate_ && delegate_->IsSpeechRecognitionEnabled()) {
462 speech_view_ = new SpeechView(delegate_);
463 speech_view_->SetVisible(false);
464 speech_view_->SetPaintToLayer(true);
465 speech_view_->SetFillsBoundsOpaquely(false);
466 speech_view_->layer()->SetOpacity(0.0f);
467 AddChildView(speech_view_);
470 OnProfilesChanged();
473 void AppListView::InitChildWidgets() {
474 DCHECK(search_box_view_);
476 // Create the search box widget.
477 views::Widget::InitParams search_box_widget_params(
478 views::Widget::InitParams::TYPE_CONTROL);
479 search_box_widget_params.parent = GetWidget()->GetNativeView();
480 search_box_widget_params.opacity =
481 views::Widget::InitParams::TRANSLUCENT_WINDOW;
483 // Create a widget for the SearchBoxView to live in. This allows the
484 // SearchBoxView to be on top of the custom launcher page's WebContents
485 // (otherwise the search box events will be captured by the WebContents).
486 search_box_widget_ = new views::Widget;
487 search_box_widget_->Init(search_box_widget_params);
488 search_box_widget_->SetContentsView(search_box_view_);
490 // The search box will not naturally receive focus by itself (because it is in
491 // a separate widget). Create this SearchBoxFocusHost in the main widget to
492 // forward the focus search into to the search box.
493 search_box_focus_host_ = new SearchBoxFocusHost(search_box_widget_);
494 AddChildView(search_box_focus_host_);
495 search_box_widget_->SetFocusTraversableParentView(search_box_focus_host_);
496 search_box_widget_->SetFocusTraversableParent(
497 GetWidget()->GetFocusTraversable());
499 #if defined(USE_AURA)
500 // Mouse events on the search box shadow should not be captured.
501 aura::Window* window = search_box_widget_->GetNativeWindow();
502 window->SetEventTargeter(scoped_ptr<ui::EventTargeter>(
503 new SearchBoxWindowTargeter(search_box_view_)));
504 #endif
506 app_list_main_view_->contents_view()->Layout();
509 void AppListView::InitAsBubbleInternal(gfx::NativeView parent,
510 int initial_apps_page,
511 views::BubbleBorder::Arrow arrow,
512 bool border_accepts_events,
513 const gfx::Vector2d& anchor_offset) {
514 base::Time start_time = base::Time::Now();
516 InitContents(parent, initial_apps_page);
518 set_color(kContentsBackgroundColor);
519 set_margins(gfx::Insets());
520 set_parent_window(parent);
521 set_close_on_deactivate(false);
522 set_close_on_esc(false);
523 set_anchor_view_insets(gfx::Insets(kArrowOffset + anchor_offset.y(),
524 kArrowOffset + anchor_offset.x(),
525 kArrowOffset - anchor_offset.y(),
526 kArrowOffset - anchor_offset.x()));
527 set_border_accepts_events(border_accepts_events);
528 set_shadow(SupportsShadow() ? views::BubbleBorder::BIG_SHADOW
529 : views::BubbleBorder::NO_SHADOW_OPAQUE_BORDER);
532 // TODO(tapted): Remove ScopedTracker below once crbug.com/431326 is fixed.
533 tracked_objects::ScopedTracker tracking_profile(
534 FROM_HERE_WITH_EXPLICIT_FUNCTION(
535 "431326 views::BubbleDelegateView::CreateBubble()"));
537 // This creates the app list widget. (Before this, child widgets cannot be
538 // created.)
539 views::BubbleDelegateView::CreateBubble(this);
542 SetBubbleArrow(arrow);
544 // We can now create the internal widgets.
545 InitChildWidgets();
547 #if defined(USE_AURA)
548 aura::Window* window = GetWidget()->GetNativeWindow();
549 window->layer()->SetMasksToBounds(true);
550 GetBubbleFrameView()->set_background(new AppListBackground(
551 GetBubbleFrameView()->bubble_border()->GetBorderCornerRadius()));
552 set_background(NULL);
553 window->SetEventTargeter(scoped_ptr<ui::EventTargeter>(
554 new views::BubbleWindowTargeter(this)));
555 #else
556 set_background(new AppListBackground(
557 GetBubbleFrameView()->bubble_border()->GetBorderCornerRadius()));
559 // On non-aura the bubble has two widgets, and it's possible for the border
560 // to be shown independently in odd situations. Explicitly hide the bubble
561 // widget to ensure that any WM_WINDOWPOSCHANGED messages triggered by the
562 // window manager do not have the SWP_SHOWWINDOW flag set which would cause
563 // the border to be shown. See http://crbug.com/231687 .
564 GetWidget()->Hide();
565 #endif
567 // On platforms that don't support a shadow, the rounded border of the app
568 // list is constructed _inside_ the view, so a rectangular background goes
569 // over the border in the rounded corners. To fix this, give the background a
570 // corner radius 1px smaller than the outer border, so it just reaches but
571 // doesn't cover it.
572 const int kOverlayCornerRadius =
573 GetBubbleFrameView()->bubble_border()->GetBorderCornerRadius();
574 overlay_view_ =
575 new AppListOverlayView(kOverlayCornerRadius - (SupportsShadow() ? 0 : 1));
576 overlay_view_->SetBoundsRect(GetContentsBounds());
577 AddChildView(overlay_view_);
579 if (delegate_)
580 delegate_->ViewInitialized();
582 UMA_HISTOGRAM_TIMES("Apps.AppListCreationTime",
583 base::Time::Now() - start_time);
586 void AppListView::OnBeforeBubbleWidgetInit(
587 views::Widget::InitParams* params,
588 views::Widget* widget) const {
589 #if defined(USE_AURA) && !defined(OS_CHROMEOS)
590 if (delegate_ && delegate_->ForceNativeDesktop())
591 params->native_widget = new views::DesktopNativeWidgetAura(widget);
592 #endif
593 #if defined(OS_WIN)
594 // Windows 7 and higher offer pinning to the taskbar, but we need presence
595 // on the taskbar for the user to be able to pin us. So, show the window on
596 // the taskbar for these versions of Windows.
597 if (base::win::GetVersion() >= base::win::VERSION_WIN7)
598 params->force_show_in_taskbar = true;
599 #elif defined(OS_LINUX)
600 // Set up a custom WM_CLASS for the app launcher window. This allows task
601 // switchers in X11 environments to distinguish it from main browser windows.
602 params->wm_class_name = kAppListWMClass;
603 // Show the window in the taskbar, even though it is a bubble, which would not
604 // normally be shown.
605 params->force_show_in_taskbar = true;
606 #endif
609 views::View* AppListView::GetInitiallyFocusedView() {
610 return app_list_main_view_->search_box_view()->search_box();
613 gfx::ImageSkia AppListView::GetWindowIcon() {
614 if (delegate_)
615 return delegate_->GetWindowIcon();
617 return gfx::ImageSkia();
620 bool AppListView::WidgetHasHitTestMask() const {
621 return GetBubbleFrameView() != nullptr;
624 void AppListView::GetWidgetHitTestMask(gfx::Path* mask) const {
625 DCHECK(mask);
626 DCHECK(GetBubbleFrameView());
628 mask->addRect(gfx::RectToSkRect(
629 GetBubbleFrameView()->GetContentsBounds()));
632 bool AppListView::AcceleratorPressed(const ui::Accelerator& accelerator) {
633 // The accelerator is added by BubbleDelegateView.
634 if (accelerator.key_code() == ui::VKEY_ESCAPE) {
635 if (switches::IsExperimentalAppListEnabled()) {
636 // If the ContentsView does not handle the back action, then this is the
637 // top level, so we close the app list.
638 if (!app_list_main_view_->contents_view()->Back()) {
639 GetWidget()->Deactivate();
640 Close();
642 return true;
645 if (app_list_main_view_->search_box_view()->HasSearch()) {
646 app_list_main_view_->search_box_view()->ClearSearch();
647 } else if (app_list_main_view_->contents_view()
648 ->apps_container_view()
649 ->IsInFolderView()) {
650 app_list_main_view_->contents_view()
651 ->apps_container_view()
652 ->app_list_folder_view()
653 ->CloseFolderPage();
654 return true;
655 } else {
656 GetWidget()->Deactivate();
657 Close();
659 return true;
662 return false;
665 void AppListView::Layout() {
666 const gfx::Rect contents_bounds = GetContentsBounds();
668 // Make sure to layout |app_list_main_view_| and |speech_view_| at the center
669 // of the widget.
670 gfx::Rect centered_bounds = contents_bounds;
671 centered_bounds.ClampToCenteredSize(gfx::Size(
672 app_list_main_view_->contents_view()->GetDefaultContentsBounds().width(),
673 contents_bounds.height()));
675 app_list_main_view_->SetBoundsRect(centered_bounds);
677 if (speech_view_) {
678 gfx::Rect speech_bounds = centered_bounds;
679 int preferred_height = speech_view_->GetPreferredSize().height();
680 speech_bounds.Inset(kSpeechUIMargin, kSpeechUIMargin);
681 speech_bounds.set_height(std::min(speech_bounds.height(),
682 preferred_height));
683 speech_bounds.Inset(-speech_view_->GetInsets());
684 speech_view_->SetBoundsRect(speech_bounds);
688 void AppListView::SchedulePaintInRect(const gfx::Rect& rect) {
689 BubbleDelegateView::SchedulePaintInRect(rect);
690 if (GetBubbleFrameView())
691 GetBubbleFrameView()->SchedulePaint();
694 void AppListView::OnWidgetDestroying(views::Widget* widget) {
695 BubbleDelegateView::OnWidgetDestroying(widget);
696 if (delegate_ && widget == GetWidget())
697 delegate_->ViewClosing();
700 void AppListView::OnWidgetActivationChanged(views::Widget* widget,
701 bool active) {
702 // Do not called inherited function as the bubble delegate auto close
703 // functionality is not used.
704 if (widget == GetWidget())
705 FOR_EACH_OBSERVER(AppListViewObserver, observers_,
706 OnActivationChanged(widget, active));
709 void AppListView::OnWidgetVisibilityChanged(views::Widget* widget,
710 bool visible) {
711 BubbleDelegateView::OnWidgetVisibilityChanged(widget, visible);
713 if (widget != GetWidget())
714 return;
716 if (!visible)
717 app_list_main_view_->ResetForShow();
720 void AppListView::OnSpeechRecognitionStateChanged(
721 SpeechRecognitionState new_state) {
722 if (!speech_view_)
723 return;
725 bool will_appear = (new_state == SPEECH_RECOGNITION_RECOGNIZING ||
726 new_state == SPEECH_RECOGNITION_IN_SPEECH ||
727 new_state == SPEECH_RECOGNITION_NETWORK_ERROR);
728 // No change for this class.
729 if (speech_view_->visible() == will_appear)
730 return;
732 if (will_appear)
733 speech_view_->Reset();
735 animation_observer_->set_frame(GetBubbleFrameView());
736 gfx::Transform speech_transform;
737 speech_transform.Translate(
738 0, SkFloatToMScalar(kSpeechUIAppearingPosition));
739 if (will_appear)
740 speech_view_->layer()->SetTransform(speech_transform);
743 ui::ScopedLayerAnimationSettings main_settings(
744 app_list_main_view_->layer()->GetAnimator());
745 if (will_appear) {
746 animation_observer_->SetTarget(app_list_main_view_);
747 main_settings.AddObserver(animation_observer_.get());
749 app_list_main_view_->layer()->SetOpacity(will_appear ? 0.0f : 1.0f);
753 ui::ScopedLayerAnimationSettings search_box_settings(
754 search_box_widget_->GetLayer()->GetAnimator());
755 search_box_widget_->GetLayer()->SetOpacity(will_appear ? 0.0f : 1.0f);
759 ui::ScopedLayerAnimationSettings speech_settings(
760 speech_view_->layer()->GetAnimator());
761 if (!will_appear) {
762 animation_observer_->SetTarget(speech_view_);
763 speech_settings.AddObserver(animation_observer_.get());
766 speech_view_->layer()->SetOpacity(will_appear ? 1.0f : 0.0f);
767 if (will_appear)
768 speech_view_->layer()->SetTransform(gfx::Transform());
769 else
770 speech_view_->layer()->SetTransform(speech_transform);
773 // Prevent the search box from receiving events when hidden.
774 search_box_view_->SetEnabled(!will_appear);
776 if (will_appear) {
777 speech_view_->SetVisible(true);
778 } else {
779 app_list_main_view_->SetVisible(true);
780 // Refocus the search box. However, if the app list widget does not have
781 // focus, it means another window has already taken focus, and we *must not*
782 // focus the search box (or we would steal focus back into the app list).
783 if (GetWidget()->IsActive())
784 search_box_view_->search_box()->RequestFocus();
788 } // namespace app_list