e2f5936a51ac168d7c9143da574c2d91f9c2ab97
[platform/framework/web/crosswalk.git] / src / athena / home / home_card_impl.cc
1 // Copyright 2014 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 "athena/home/public/home_card.h"
6
7 #include <cmath>
8 #include <limits>
9
10 #include "athena/common/container_priorities.h"
11 #include "athena/home/app_list_view_delegate.h"
12 #include "athena/home/athena_start_page_view.h"
13 #include "athena/home/minimized_home.h"
14 #include "athena/home/public/app_model_builder.h"
15 #include "athena/input/public/accelerator_manager.h"
16 #include "athena/screen/public/screen_manager.h"
17 #include "athena/wm/public/window_manager.h"
18 #include "athena/wm/public/window_manager_observer.h"
19 #include "base/bind.h"
20 #include "base/memory/weak_ptr.h"
21 #include "ui/app_list/search_provider.h"
22 #include "ui/app_list/views/app_list_main_view.h"
23 #include "ui/app_list/views/contents_view.h"
24 #include "ui/aura/layout_manager.h"
25 #include "ui/aura/window.h"
26 #include "ui/compositor/closure_animation_observer.h"
27 #include "ui/compositor/scoped_layer_animation_settings.h"
28 #include "ui/views/background.h"
29 #include "ui/views/layout/box_layout.h"
30 #include "ui/views/widget/widget.h"
31 #include "ui/views/widget/widget_delegate.h"
32 #include "ui/wm/core/shadow_types.h"
33 #include "ui/wm/core/visibility_controller.h"
34 #include "ui/wm/core/window_animations.h"
35 #include "ui/wm/public/activation_change_observer.h"
36 #include "ui/wm/public/activation_client.h"
37
38 namespace athena {
39 namespace {
40
41 HomeCard* instance = NULL;
42 const int kHomeCardHeight = 100;
43 const int kHomeCardMinimizedHeight = 6;
44
45 gfx::Rect GetBoundsForState(const gfx::Rect& screen_bounds,
46                             HomeCard::State state) {
47   switch (state) {
48     case HomeCard::HIDDEN:
49       break;
50
51     case HomeCard::VISIBLE_CENTERED:
52       return screen_bounds;
53
54     case HomeCard::VISIBLE_BOTTOM:
55       return gfx::Rect(0,
56                        screen_bounds.bottom() - kHomeCardHeight,
57                        screen_bounds.width(),
58                        kHomeCardHeight);
59     case HomeCard::VISIBLE_MINIMIZED:
60       return gfx::Rect(0,
61                        screen_bounds.bottom() - kHomeCardMinimizedHeight,
62                        screen_bounds.width(),
63                        kHomeCardMinimizedHeight);
64   }
65
66   NOTREACHED();
67   return gfx::Rect();
68 }
69
70 // Makes sure the homecard is center-aligned horizontally and bottom-aligned
71 // vertically.
72 class HomeCardLayoutManager : public aura::LayoutManager {
73  public:
74   class Delegate {
75    public:
76     virtual ~Delegate() {}
77
78     virtual HomeCard::State GetState() = 0;
79     virtual aura::Window* GetNativeWindow() = 0;
80   };
81
82   explicit HomeCardLayoutManager(Delegate* delegate)
83       : delegate_(delegate) {}
84
85   virtual ~HomeCardLayoutManager() {}
86
87   void Layout() {
88     aura::Window* home_card = delegate_->GetNativeWindow();
89     // |home_card| could be detached from the root window (e.g. when it is being
90     // destroyed).
91     if (!home_card || !home_card->GetRootWindow())
92       return;
93
94     {
95       ui::ScopedLayerAnimationSettings settings(
96           home_card->layer()->GetAnimator());
97       settings.SetTweenType(gfx::Tween::EASE_IN_OUT);
98       SetChildBoundsDirect(home_card, GetBoundsForState(
99           home_card->GetRootWindow()->bounds(), delegate_->GetState()));
100     }
101   }
102
103  private:
104   // aura::LayoutManager:
105   virtual void OnWindowResized() OVERRIDE { Layout(); }
106   virtual void OnWindowAddedToLayout(aura::Window* child) OVERRIDE { Layout(); }
107   virtual void OnWillRemoveWindowFromLayout(aura::Window* child) OVERRIDE {}
108   virtual void OnWindowRemovedFromLayout(aura::Window* child) OVERRIDE {
109     Layout();
110   }
111   virtual void OnChildWindowVisibilityChanged(aura::Window* child,
112                                               bool visible) OVERRIDE {
113     Layout();
114   }
115   virtual void SetChildBounds(aura::Window* child,
116                               const gfx::Rect& requested_bounds) OVERRIDE {
117     SetChildBoundsDirect(child, requested_bounds);
118   }
119
120   Delegate* delegate_;
121
122   DISALLOW_COPY_AND_ASSIGN(HomeCardLayoutManager);
123 };
124
125 class HomeCardGestureManager {
126  public:
127   class Delegate {
128    public:
129     // Called when the gesture has ended. The state of the home card will
130     // end up with |final_state|.
131     virtual void OnGestureEnded(HomeCard::State final_state) = 0;
132
133     // Called when the gesture position is updated so that |delegate| should
134     // update the visual. The arguments represent the state of the current
135     // gesture position is switching from |from_state| to |to_state|, and
136     // the level of the progress is at |progress|, which is 0 to 1.
137     // |from_state| and |to_state| could be same. For example, if the user moves
138     // the finger down to the bottom of the screen, both states are MINIMIZED.
139     // In that case |progress| is 0.
140     virtual void OnGestureProgressed(
141         HomeCard::State from_state,
142         HomeCard::State to_state,
143         float progress) = 0;
144   };
145
146   HomeCardGestureManager(Delegate* delegate,
147                          const gfx::Rect& screen_bounds)
148       : delegate_(delegate),
149         last_state_(HomeCard::Get()->GetState()),
150         y_offset_(0),
151         last_estimated_top_(0),
152         screen_bounds_(screen_bounds) {}
153
154   void ProcessGestureEvent(ui::GestureEvent* event) {
155     switch (event->type()) {
156       case ui::ET_GESTURE_SCROLL_BEGIN:
157         y_offset_ = event->location().y();
158         event->SetHandled();
159         break;
160       case ui::ET_GESTURE_SCROLL_END:
161         event->SetHandled();
162         delegate_->OnGestureEnded(GetClosestState());
163         break;
164       case ui::ET_GESTURE_SCROLL_UPDATE:
165         UpdateScrollState(*event);
166         break;
167       case ui::ET_SCROLL_FLING_START: {
168         const ui::GestureEventDetails& details = event->details();
169         const float kFlingCompletionVelocity = 100.0f;
170         if (::fabs(details.velocity_y()) > kFlingCompletionVelocity) {
171           int step = (details.velocity_y() > 0) ? 1 : -1;
172           int new_state = static_cast<int>(last_state_) + step;
173           if (new_state >= HomeCard::VISIBLE_CENTERED &&
174               new_state <= HomeCard::VISIBLE_MINIMIZED) {
175             last_state_ = static_cast<HomeCard::State>(new_state);
176           }
177           delegate_->OnGestureEnded(last_state_);
178         }
179         break;
180       }
181       default:
182         // do nothing.
183         break;
184     }
185   }
186
187  private:
188   HomeCard::State GetClosestState() {
189     // The top position of the bounds for one smaller state than the current
190     // one.
191     int smaller_top = -1;
192     for (int i = HomeCard::VISIBLE_MINIMIZED;
193          i >= HomeCard::VISIBLE_CENTERED; --i) {
194       HomeCard::State state = static_cast<HomeCard::State>(i);
195       int top = GetBoundsForState(screen_bounds_, state).y();
196       if (last_estimated_top_ == top) {
197         return state;
198       } else if (last_estimated_top_ > top) {
199         if (smaller_top < 0)
200           return state;
201
202         if (smaller_top - last_estimated_top_ > (smaller_top - top) / 5) {
203           return state;
204         } else {
205           return static_cast<HomeCard::State>(i + 1);
206         }
207       }
208       smaller_top = top;
209     }
210
211     NOTREACHED();
212     return last_state_;
213   }
214
215   void UpdateScrollState(const ui::GestureEvent& event) {
216     last_estimated_top_ = event.root_location().y() - y_offset_;
217
218     // The bounds which is at one smaller state than the current one.
219     gfx::Rect smaller_bounds;
220
221     for (int i = HomeCard::VISIBLE_MINIMIZED;
222          i >= HomeCard::VISIBLE_CENTERED; --i) {
223       HomeCard::State state = static_cast<HomeCard::State>(i);
224       const gfx::Rect bounds = GetBoundsForState(screen_bounds_, state);
225       if (last_estimated_top_ == bounds.y()) {
226         delegate_->OnGestureProgressed(last_state_, state, 1.0f);
227         last_state_ = state;
228         return;
229       } else if (last_estimated_top_ > bounds.y()) {
230         if (smaller_bounds.IsEmpty()) {
231           // Smaller than minimized -- returning the minimized bounds.
232           delegate_->OnGestureProgressed(last_state_, state, 1.0f);
233         } else {
234           // The finger is between two states.
235           float progress =
236               static_cast<float>((smaller_bounds.y() - last_estimated_top_)) /
237               (smaller_bounds.y() - bounds.y());
238           if (last_state_ == state) {
239             if (event.details().scroll_y() > 0) {
240               state = static_cast<HomeCard::State>(state + 1);
241               progress = 1.0f - progress;
242             } else {
243               last_state_ = static_cast<HomeCard::State>(last_state_ + 1);
244             }
245           }
246           delegate_->OnGestureProgressed(last_state_, state, progress);
247         }
248         last_state_ = state;
249         return;
250       }
251       smaller_bounds = bounds;
252     }
253     NOTREACHED();
254   }
255
256   Delegate* delegate_;
257   HomeCard::State last_state_;
258
259   // The offset from the top edge of the home card and the initial position of
260   // gesture.
261   int y_offset_;
262
263   // The estimated top edge of the home card after the last touch event.
264   int last_estimated_top_;
265
266   // The bounds of the screen to compute the home card bounds.
267   gfx::Rect screen_bounds_;
268
269   DISALLOW_COPY_AND_ASSIGN(HomeCardGestureManager);
270 };
271
272 // The container view of home card contents of each state.
273 class HomeCardView : public views::WidgetDelegateView {
274  public:
275   HomeCardView(app_list::AppListViewDelegate* view_delegate,
276                aura::Window* container,
277                HomeCardGestureManager::Delegate* gesture_delegate)
278       : gesture_delegate_(gesture_delegate),
279         weak_factory_(this) {
280     bottom_view_ = new AthenaStartPageView(view_delegate);
281     AddChildView(bottom_view_);
282     bottom_view_->SetPaintToLayer(true);
283     bottom_view_->layer()->SetFillsBoundsOpaquely(false);
284
285     main_view_ = new app_list::AppListMainView(
286         view_delegate, 0 /* initial_apps_page */, container);
287     AddChildView(main_view_);
288     main_view_->set_background(
289         views::Background::CreateSolidBackground(SK_ColorWHITE));
290     main_view_->SetPaintToLayer(true);
291
292     minimized_view_ = CreateMinimizedHome();
293     minimized_view_->SetPaintToLayer(true);
294     AddChildView(minimized_view_);
295   }
296
297   void SetStateProgress(HomeCard::State from_state,
298                         HomeCard::State to_state,
299                         float progress) {
300     if (from_state == HomeCard::VISIBLE_BOTTOM &&
301         to_state == HomeCard::VISIBLE_MINIMIZED) {
302       SetStateProgress(to_state, from_state, 1.0 - progress);
303       return;
304     }
305
306     // View from minimized to bottom.
307     if (from_state == HomeCard::VISIBLE_MINIMIZED &&
308         to_state == HomeCard::VISIBLE_BOTTOM) {
309       bottom_view_->SetVisible(true);
310       minimized_view_->SetVisible(true);
311       minimized_view_->layer()->SetOpacity(1.0f - progress);
312       return;
313     }
314
315     SetState(to_state);
316   }
317
318   void SetState(HomeCard::State state) {
319     bottom_view_->SetVisible(state == HomeCard::VISIBLE_BOTTOM);
320     main_view_->SetVisible(state == HomeCard::VISIBLE_CENTERED);
321     minimized_view_->SetVisible(state == HomeCard::VISIBLE_MINIMIZED);
322     if (minimized_view_->visible())
323       minimized_view_->layer()->SetOpacity(1.0f);
324     if (state == HomeCard::VISIBLE_CENTERED) {
325       app_list::ContentsView* contents_view = main_view_->contents_view();
326       contents_view->SetActivePage(contents_view->GetPageIndexForNamedPage(
327           app_list::ContentsView::NAMED_PAGE_START));
328     }
329     wm::SetShadowType(GetWidget()->GetNativeView(),
330                       state == HomeCard::VISIBLE_MINIMIZED ?
331                       wm::SHADOW_TYPE_NONE :
332                       wm::SHADOW_TYPE_RECTANGULAR);
333   }
334
335   void SetStateWithAnimation(HomeCard::State from_state,
336                              HomeCard::State to_state) {
337     if ((from_state == HomeCard::VISIBLE_MINIMIZED &&
338          to_state == HomeCard::VISIBLE_BOTTOM) ||
339         (from_state == HomeCard::VISIBLE_BOTTOM &&
340          to_state == HomeCard::VISIBLE_MINIMIZED)) {
341       minimized_view_->SetVisible(true);
342       bottom_view_->SetVisible(true);
343       {
344         ui::ScopedLayerAnimationSettings settings(
345             minimized_view_->layer()->GetAnimator());
346         settings.SetTweenType(gfx::Tween::EASE_IN_OUT);
347         settings.AddObserver(new ui::ClosureAnimationObserver(
348             base::Bind(&HomeCardView::SetState,
349                        weak_factory_.GetWeakPtr(),
350                        to_state)));
351         minimized_view_->layer()->SetOpacity(
352             (to_state == HomeCard::VISIBLE_MINIMIZED) ? 1.0f : 0.0f);
353       }
354     } else {
355       // TODO(mukai): Take care of other transition.
356       SetState(to_state);
357     }
358   }
359
360   void ClearGesture() {
361     gesture_manager_.reset();
362   }
363
364   // views::View:
365   virtual void Layout() OVERRIDE {
366     for (int i = 0; i < child_count(); ++i) {
367       views::View* child = child_at(i);
368       if (child->visible()) {
369         if (child == minimized_view_) {
370           gfx::Rect minimized_bounds = bounds();
371           minimized_bounds.set_y(
372               minimized_bounds.bottom() - kHomeCardMinimizedHeight);
373           minimized_bounds.set_height(kHomeCardMinimizedHeight);
374           child->SetBoundsRect(minimized_bounds);
375         } else {
376           child->SetBoundsRect(bounds());
377         }
378       }
379     }
380   }
381   virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE {
382     if (!gesture_manager_ &&
383         event->type() == ui::ET_GESTURE_SCROLL_BEGIN) {
384       gesture_manager_.reset(new HomeCardGestureManager(
385           gesture_delegate_,
386           GetWidget()->GetNativeWindow()->GetRootWindow()->bounds()));
387     }
388
389     if (gesture_manager_)
390       gesture_manager_->ProcessGestureEvent(event);
391   }
392
393  private:
394   // views::WidgetDelegate:
395   virtual views::View* GetContentsView() OVERRIDE {
396     return this;
397   }
398
399   app_list::AppListMainView* main_view_;
400   views::View* bottom_view_;
401   views::View* minimized_view_;
402   scoped_ptr<HomeCardGestureManager> gesture_manager_;
403   HomeCardGestureManager::Delegate* gesture_delegate_;
404   base::WeakPtrFactory<HomeCardView> weak_factory_;
405
406   DISALLOW_COPY_AND_ASSIGN(HomeCardView);
407 };
408
409 class HomeCardImpl : public HomeCard,
410                      public AcceleratorHandler,
411                      public HomeCardLayoutManager::Delegate,
412                      public HomeCardGestureManager::Delegate,
413                      public WindowManagerObserver,
414                      public aura::client::ActivationChangeObserver {
415  public:
416   explicit HomeCardImpl(AppModelBuilder* model_builder);
417   virtual ~HomeCardImpl();
418
419   void Init();
420
421  private:
422   enum Command {
423     COMMAND_SHOW_HOME_CARD,
424   };
425   void InstallAccelerators();
426
427   // Overridden from HomeCard:
428   virtual void SetState(State state) OVERRIDE;
429   virtual State GetState() OVERRIDE;
430   virtual void RegisterSearchProvider(
431       app_list::SearchProvider* search_provider) OVERRIDE;
432   virtual void UpdateVirtualKeyboardBounds(
433       const gfx::Rect& bounds) OVERRIDE;
434
435   // AcceleratorHandler:
436   virtual bool IsCommandEnabled(int command_id) const OVERRIDE { return true; }
437   virtual bool OnAcceleratorFired(int command_id,
438                                   const ui::Accelerator& accelerator) OVERRIDE;
439
440   // HomeCardLayoutManager::Delegate:
441   virtual aura::Window* GetNativeWindow() OVERRIDE;
442
443   // HomeCardGestureManager::Delegate:
444   virtual void OnGestureEnded(State final_state) OVERRIDE;
445   virtual void OnGestureProgressed(
446       State from_state, State to_state, float progress) OVERRIDE;
447
448   // WindowManagerObserver:
449   virtual void OnOverviewModeEnter() OVERRIDE;
450   virtual void OnOverviewModeExit() OVERRIDE;
451
452   // aura::client::ActivationChangeObserver:
453   virtual void OnWindowActivated(aura::Window* gained_active,
454                                  aura::Window* lost_active) OVERRIDE;
455
456   scoped_ptr<AppModelBuilder> model_builder_;
457
458   HomeCard::State state_;
459
460   // original_state_ is the state which the home card should go back to after
461   // the virtual keyboard is hidden.
462   HomeCard::State original_state_;
463
464   views::Widget* home_card_widget_;
465   HomeCardView* home_card_view_;
466   scoped_ptr<AppListViewDelegate> view_delegate_;
467   HomeCardLayoutManager* layout_manager_;
468   aura::client::ActivationClient* activation_client_;  // Not owned
469
470   // Right now HomeCard allows only one search provider.
471   // TODO(mukai): port app-list's SearchController and Mixer.
472   scoped_ptr<app_list::SearchProvider> search_provider_;
473
474   DISALLOW_COPY_AND_ASSIGN(HomeCardImpl);
475 };
476
477 HomeCardImpl::HomeCardImpl(AppModelBuilder* model_builder)
478     : model_builder_(model_builder),
479       state_(HIDDEN),
480       original_state_(VISIBLE_MINIMIZED),
481       home_card_widget_(NULL),
482       home_card_view_(NULL),
483       layout_manager_(NULL),
484       activation_client_(NULL) {
485   DCHECK(!instance);
486   instance = this;
487   WindowManager::GetInstance()->AddObserver(this);
488 }
489
490 HomeCardImpl::~HomeCardImpl() {
491   DCHECK(instance);
492   WindowManager::GetInstance()->RemoveObserver(this);
493   if (activation_client_)
494     activation_client_->RemoveObserver(this);
495   home_card_widget_->CloseNow();
496   instance = NULL;
497 }
498
499 void HomeCardImpl::Init() {
500   InstallAccelerators();
501   ScreenManager::ContainerParams params("HomeCardContainer", CP_HOME_CARD);
502   params.can_activate_children = true;
503   aura::Window* container = ScreenManager::Get()->CreateContainer(params);
504   layout_manager_ = new HomeCardLayoutManager(this);
505
506   container->SetLayoutManager(layout_manager_);
507   wm::SetChildWindowVisibilityChangesAnimated(container);
508
509   view_delegate_.reset(new AppListViewDelegate(model_builder_.get()));
510   if (search_provider_)
511     view_delegate_->RegisterSearchProvider(search_provider_.get());
512
513   home_card_view_ = new HomeCardView(view_delegate_.get(), container, this);
514   home_card_widget_ = new views::Widget();
515   views::Widget::InitParams widget_params(
516       views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
517   widget_params.parent = container;
518   widget_params.delegate = home_card_view_;
519   widget_params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
520   home_card_widget_->Init(widget_params);
521
522   SetState(VISIBLE_MINIMIZED);
523   home_card_view_->Layout();
524
525   activation_client_ =
526       aura::client::GetActivationClient(container->GetRootWindow());
527   if (activation_client_)
528     activation_client_->AddObserver(this);
529 }
530
531 void HomeCardImpl::InstallAccelerators() {
532   const AcceleratorData accelerator_data[] = {
533       {TRIGGER_ON_PRESS, ui::VKEY_L, ui::EF_CONTROL_DOWN,
534        COMMAND_SHOW_HOME_CARD, AF_NONE},
535   };
536   AcceleratorManager::Get()->RegisterAccelerators(
537       accelerator_data, arraysize(accelerator_data), this);
538 }
539
540 void HomeCardImpl::SetState(HomeCard::State state) {
541   if (state_ == state)
542     return;
543
544   // Update |state_| before changing the visibility of the widgets, so that
545   // LayoutManager callbacks get the correct state.
546   HomeCard::State old_state = state_;
547   state_ = state;
548   original_state_ = state;
549   if (state_ == HIDDEN) {
550     home_card_widget_->Hide();
551   } else {
552     if (state_ == VISIBLE_CENTERED)
553       home_card_widget_->Show();
554     else
555       home_card_widget_->ShowInactive();
556     home_card_view_->SetStateWithAnimation(old_state, state);
557     layout_manager_->Layout();
558   }
559 }
560
561 HomeCard::State HomeCardImpl::GetState() {
562   return state_;
563 }
564
565 void HomeCardImpl::RegisterSearchProvider(
566     app_list::SearchProvider* search_provider) {
567   DCHECK(!search_provider_);
568   search_provider_.reset(search_provider);
569   view_delegate_->RegisterSearchProvider(search_provider_.get());
570 }
571
572 void HomeCardImpl::UpdateVirtualKeyboardBounds(
573     const gfx::Rect& bounds) {
574   if (state_ == VISIBLE_MINIMIZED && !bounds.IsEmpty()) {
575     SetState(HIDDEN);
576     original_state_ = VISIBLE_MINIMIZED;
577   } else if (state_ == VISIBLE_BOTTOM && !bounds.IsEmpty()) {
578     SetState(VISIBLE_CENTERED);
579     original_state_ = VISIBLE_BOTTOM;
580   } else if (state_ != original_state_ && bounds.IsEmpty()) {
581     SetState(original_state_);
582   }
583 }
584
585 bool HomeCardImpl::OnAcceleratorFired(int command_id,
586                                       const ui::Accelerator& accelerator) {
587   DCHECK_EQ(COMMAND_SHOW_HOME_CARD, command_id);
588
589   if (state_ == VISIBLE_CENTERED && original_state_ != VISIBLE_BOTTOM)
590     SetState(VISIBLE_MINIMIZED);
591   else if (state_ == VISIBLE_MINIMIZED)
592     SetState(VISIBLE_CENTERED);
593   return true;
594 }
595
596 aura::Window* HomeCardImpl::GetNativeWindow() {
597   if (state_ == HIDDEN)
598     return NULL;
599
600   return home_card_widget_ ? home_card_widget_->GetNativeWindow() : NULL;
601 }
602
603 void HomeCardImpl::OnGestureEnded(State final_state) {
604   home_card_view_->ClearGesture();
605   if (state_ != final_state &&
606       (state_ == VISIBLE_MINIMIZED || final_state == VISIBLE_MINIMIZED)) {
607     WindowManager::GetInstance()->ToggleOverview();
608   } else {
609     HomeCard::State old_state = state_;
610     state_ = final_state;
611     home_card_view_->SetStateWithAnimation(old_state, final_state);
612     layout_manager_->Layout();
613   }
614 }
615
616 void HomeCardImpl::OnGestureProgressed(
617     State from_state, State to_state, float progress) {
618   home_card_view_->SetStateProgress(from_state, to_state, progress);
619
620   gfx::Rect screen_bounds =
621       home_card_widget_->GetNativeWindow()->GetRootWindow()->bounds();
622   home_card_widget_->SetBounds(gfx::Tween::RectValueBetween(
623       progress,
624       GetBoundsForState(screen_bounds, from_state),
625       GetBoundsForState(screen_bounds, to_state)));
626
627   // TODO(mukai): signals the update to the window manager so that it shows the
628   // intermediate visual state of overview mode.
629 }
630
631 void HomeCardImpl::OnOverviewModeEnter() {
632   SetState(VISIBLE_BOTTOM);
633 }
634
635 void HomeCardImpl::OnOverviewModeExit() {
636   SetState(VISIBLE_MINIMIZED);
637 }
638
639 void HomeCardImpl::OnWindowActivated(aura::Window* gained_active,
640                                      aura::Window* lost_active) {
641   if (state_ != HIDDEN &&
642       gained_active != home_card_widget_->GetNativeWindow()) {
643     SetState(VISIBLE_MINIMIZED);
644   }
645 }
646
647 }  // namespace
648
649 // static
650 HomeCard* HomeCard::Create(AppModelBuilder* model_builder) {
651   (new HomeCardImpl(model_builder))->Init();
652   DCHECK(instance);
653   return instance;
654 }
655
656 // static
657 void HomeCard::Shutdown() {
658   DCHECK(instance);
659   delete instance;
660   instance = NULL;
661 }
662
663 // static
664 HomeCard* HomeCard::Get() {
665   DCHECK(instance);
666   return instance;
667 }
668
669 }  // namespace athena