Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / athena / home / home_card_impl.cc
index e2f5936..3b285fb 100644 (file)
@@ -2,45 +2,39 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "athena/home/public/home_card.h"
+#include "athena/home/home_card_impl.h"
 
 #include <cmath>
 #include <limits>
 
-#include "athena/common/container_priorities.h"
+#include "athena/env/public/athena_env.h"
 #include "athena/home/app_list_view_delegate.h"
 #include "athena/home/athena_start_page_view.h"
+#include "athena/home/home_card_constants.h"
 #include "athena/home/minimized_home.h"
 #include "athena/home/public/app_model_builder.h"
-#include "athena/input/public/accelerator_manager.h"
 #include "athena/screen/public/screen_manager.h"
+#include "athena/util/container_priorities.h"
 #include "athena/wm/public/window_manager.h"
-#include "athena/wm/public/window_manager_observer.h"
-#include "base/bind.h"
-#include "base/memory/weak_ptr.h"
 #include "ui/app_list/search_provider.h"
 #include "ui/app_list/views/app_list_main_view.h"
 #include "ui/app_list/views/contents_view.h"
 #include "ui/aura/layout_manager.h"
 #include "ui/aura/window.h"
-#include "ui/compositor/closure_animation_observer.h"
+#include "ui/compositor/layer.h"
 #include "ui/compositor/scoped_layer_animation_settings.h"
-#include "ui/views/background.h"
-#include "ui/views/layout/box_layout.h"
+#include "ui/gfx/animation/tween.h"
+#include "ui/views/layout/fill_layout.h"
 #include "ui/views/widget/widget.h"
 #include "ui/views/widget/widget_delegate.h"
 #include "ui/wm/core/shadow_types.h"
 #include "ui/wm/core/visibility_controller.h"
-#include "ui/wm/core/window_animations.h"
-#include "ui/wm/public/activation_change_observer.h"
 #include "ui/wm/public/activation_client.h"
 
 namespace athena {
 namespace {
 
 HomeCard* instance = NULL;
-const int kHomeCardHeight = 100;
-const int kHomeCardMinimizedHeight = 6;
 
 gfx::Rect GetBoundsForState(const gfx::Rect& screen_bounds,
                             HomeCard::State state) {
@@ -51,310 +45,137 @@ gfx::Rect GetBoundsForState(const gfx::Rect& screen_bounds,
     case HomeCard::VISIBLE_CENTERED:
       return screen_bounds;
 
+    // Do not change the home_card's size, only changes the top position
+    // instead, because size change causes unnecessary re-layouts.
     case HomeCard::VISIBLE_BOTTOM:
       return gfx::Rect(0,
                        screen_bounds.bottom() - kHomeCardHeight,
                        screen_bounds.width(),
-                       kHomeCardHeight);
+                       screen_bounds.height());
     case HomeCard::VISIBLE_MINIMIZED:
       return gfx::Rect(0,
                        screen_bounds.bottom() - kHomeCardMinimizedHeight,
                        screen_bounds.width(),
-                       kHomeCardMinimizedHeight);
+                       screen_bounds.height());
   }
 
   NOTREACHED();
   return gfx::Rect();
 }
 
+}  // namespace
+
 // Makes sure the homecard is center-aligned horizontally and bottom-aligned
 // vertically.
 class HomeCardLayoutManager : public aura::LayoutManager {
  public:
-  class Delegate {
-   public:
-    virtual ~Delegate() {}
-
-    virtual HomeCard::State GetState() = 0;
-    virtual aura::Window* GetNativeWindow() = 0;
-  };
-
-  explicit HomeCardLayoutManager(Delegate* delegate)
-      : delegate_(delegate) {}
+  HomeCardLayoutManager()
+      : home_card_(NULL),
+        minimized_layer_(NULL) {}
 
   virtual ~HomeCardLayoutManager() {}
 
-  void Layout() {
-    aura::Window* home_card = delegate_->GetNativeWindow();
+  void Layout(bool animate, gfx::Tween::Type tween_type) {
     // |home_card| could be detached from the root window (e.g. when it is being
     // destroyed).
-    if (!home_card || !home_card->GetRootWindow())
+    if (!home_card_ || !home_card_->IsVisible() || !home_card_->GetRootWindow())
       return;
 
-    {
-      ui::ScopedLayerAnimationSettings settings(
-          home_card->layer()->GetAnimator());
-      settings.SetTweenType(gfx::Tween::EASE_IN_OUT);
-      SetChildBoundsDirect(home_card, GetBoundsForState(
-          home_card->GetRootWindow()->bounds(), delegate_->GetState()));
+    scoped_ptr<ui::ScopedLayerAnimationSettings> settings;
+    if (animate) {
+      settings.reset(new ui::ScopedLayerAnimationSettings(
+          home_card_->layer()->GetAnimator()));
+      settings->SetTweenType(tween_type);
     }
+    SetChildBoundsDirect(home_card_, GetBoundsForState(
+        home_card_->GetRootWindow()->bounds(), HomeCard::Get()->GetState()));
+  }
+
+  void SetMinimizedLayer(ui::Layer* minimized_layer) {
+    minimized_layer_ = minimized_layer;
+    UpdateMinimizedHomeBounds();
   }
 
  private:
+  void UpdateMinimizedHomeBounds() {
+    gfx::Rect minimized_bounds = minimized_layer_->parent()->bounds();
+    minimized_bounds.set_y(
+        minimized_bounds.bottom() - kHomeCardMinimizedHeight);
+    minimized_bounds.set_height(kHomeCardMinimizedHeight);
+    minimized_layer_->SetBounds(minimized_bounds);
+  }
+
   // aura::LayoutManager:
-  virtual void OnWindowResized() OVERRIDE { Layout(); }
-  virtual void OnWindowAddedToLayout(aura::Window* child) OVERRIDE { Layout(); }
-  virtual void OnWillRemoveWindowFromLayout(aura::Window* child) OVERRIDE {}
+  virtual void OnWindowResized() OVERRIDE {
+    Layout(false, gfx::Tween::LINEAR);
+    UpdateMinimizedHomeBounds();
+  }
+  virtual void OnWindowAddedToLayout(aura::Window* child) OVERRIDE {
+    if (!home_card_) {
+      home_card_ = child;
+      Layout(false, gfx::Tween::LINEAR);
+    }
+  }
+  virtual void OnWillRemoveWindowFromLayout(aura::Window* child) OVERRIDE {
+    if (home_card_ == child)
+      home_card_ = NULL;
+  }
   virtual void OnWindowRemovedFromLayout(aura::Window* child) OVERRIDE {
-    Layout();
   }
   virtual void OnChildWindowVisibilityChanged(aura::Window* child,
                                               bool visible) OVERRIDE {
-    Layout();
+    if (home_card_ == child)
+      Layout(false, gfx::Tween::LINEAR);
   }
   virtual void SetChildBounds(aura::Window* child,
                               const gfx::Rect& requested_bounds) OVERRIDE {
     SetChildBoundsDirect(child, requested_bounds);
   }
 
-  Delegate* delegate_;
+  aura::Window* home_card_;
+  ui::Layer* minimized_layer_;
 
   DISALLOW_COPY_AND_ASSIGN(HomeCardLayoutManager);
 };
 
-class HomeCardGestureManager {
- public:
-  class Delegate {
-   public:
-    // Called when the gesture has ended. The state of the home card will
-    // end up with |final_state|.
-    virtual void OnGestureEnded(HomeCard::State final_state) = 0;
-
-    // Called when the gesture position is updated so that |delegate| should
-    // update the visual. The arguments represent the state of the current
-    // gesture position is switching from |from_state| to |to_state|, and
-    // the level of the progress is at |progress|, which is 0 to 1.
-    // |from_state| and |to_state| could be same. For example, if the user moves
-    // the finger down to the bottom of the screen, both states are MINIMIZED.
-    // In that case |progress| is 0.
-    virtual void OnGestureProgressed(
-        HomeCard::State from_state,
-        HomeCard::State to_state,
-        float progress) = 0;
-  };
-
-  HomeCardGestureManager(Delegate* delegate,
-                         const gfx::Rect& screen_bounds)
-      : delegate_(delegate),
-        last_state_(HomeCard::Get()->GetState()),
-        y_offset_(0),
-        last_estimated_top_(0),
-        screen_bounds_(screen_bounds) {}
-
-  void ProcessGestureEvent(ui::GestureEvent* event) {
-    switch (event->type()) {
-      case ui::ET_GESTURE_SCROLL_BEGIN:
-        y_offset_ = event->location().y();
-        event->SetHandled();
-        break;
-      case ui::ET_GESTURE_SCROLL_END:
-        event->SetHandled();
-        delegate_->OnGestureEnded(GetClosestState());
-        break;
-      case ui::ET_GESTURE_SCROLL_UPDATE:
-        UpdateScrollState(*event);
-        break;
-      case ui::ET_SCROLL_FLING_START: {
-        const ui::GestureEventDetails& details = event->details();
-        const float kFlingCompletionVelocity = 100.0f;
-        if (::fabs(details.velocity_y()) > kFlingCompletionVelocity) {
-          int step = (details.velocity_y() > 0) ? 1 : -1;
-          int new_state = static_cast<int>(last_state_) + step;
-          if (new_state >= HomeCard::VISIBLE_CENTERED &&
-              new_state <= HomeCard::VISIBLE_MINIMIZED) {
-            last_state_ = static_cast<HomeCard::State>(new_state);
-          }
-          delegate_->OnGestureEnded(last_state_);
-        }
-        break;
-      }
-      default:
-        // do nothing.
-        break;
-    }
-  }
-
- private:
-  HomeCard::State GetClosestState() {
-    // The top position of the bounds for one smaller state than the current
-    // one.
-    int smaller_top = -1;
-    for (int i = HomeCard::VISIBLE_MINIMIZED;
-         i >= HomeCard::VISIBLE_CENTERED; --i) {
-      HomeCard::State state = static_cast<HomeCard::State>(i);
-      int top = GetBoundsForState(screen_bounds_, state).y();
-      if (last_estimated_top_ == top) {
-        return state;
-      } else if (last_estimated_top_ > top) {
-        if (smaller_top < 0)
-          return state;
-
-        if (smaller_top - last_estimated_top_ > (smaller_top - top) / 5) {
-          return state;
-        } else {
-          return static_cast<HomeCard::State>(i + 1);
-        }
-      }
-      smaller_top = top;
-    }
-
-    NOTREACHED();
-    return last_state_;
-  }
-
-  void UpdateScrollState(const ui::GestureEvent& event) {
-    last_estimated_top_ = event.root_location().y() - y_offset_;
-
-    // The bounds which is at one smaller state than the current one.
-    gfx::Rect smaller_bounds;
-
-    for (int i = HomeCard::VISIBLE_MINIMIZED;
-         i >= HomeCard::VISIBLE_CENTERED; --i) {
-      HomeCard::State state = static_cast<HomeCard::State>(i);
-      const gfx::Rect bounds = GetBoundsForState(screen_bounds_, state);
-      if (last_estimated_top_ == bounds.y()) {
-        delegate_->OnGestureProgressed(last_state_, state, 1.0f);
-        last_state_ = state;
-        return;
-      } else if (last_estimated_top_ > bounds.y()) {
-        if (smaller_bounds.IsEmpty()) {
-          // Smaller than minimized -- returning the minimized bounds.
-          delegate_->OnGestureProgressed(last_state_, state, 1.0f);
-        } else {
-          // The finger is between two states.
-          float progress =
-              static_cast<float>((smaller_bounds.y() - last_estimated_top_)) /
-              (smaller_bounds.y() - bounds.y());
-          if (last_state_ == state) {
-            if (event.details().scroll_y() > 0) {
-              state = static_cast<HomeCard::State>(state + 1);
-              progress = 1.0f - progress;
-            } else {
-              last_state_ = static_cast<HomeCard::State>(last_state_ + 1);
-            }
-          }
-          delegate_->OnGestureProgressed(last_state_, state, progress);
-        }
-        last_state_ = state;
-        return;
-      }
-      smaller_bounds = bounds;
-    }
-    NOTREACHED();
-  }
-
-  Delegate* delegate_;
-  HomeCard::State last_state_;
-
-  // The offset from the top edge of the home card and the initial position of
-  // gesture.
-  int y_offset_;
-
-  // The estimated top edge of the home card after the last touch event.
-  int last_estimated_top_;
-
-  // The bounds of the screen to compute the home card bounds.
-  gfx::Rect screen_bounds_;
-
-  DISALLOW_COPY_AND_ASSIGN(HomeCardGestureManager);
-};
-
 // The container view of home card contents of each state.
 class HomeCardView : public views::WidgetDelegateView {
  public:
   HomeCardView(app_list::AppListViewDelegate* view_delegate,
                aura::Window* container,
                HomeCardGestureManager::Delegate* gesture_delegate)
-      : gesture_delegate_(gesture_delegate),
-        weak_factory_(this) {
-    bottom_view_ = new AthenaStartPageView(view_delegate);
-    AddChildView(bottom_view_);
-    bottom_view_->SetPaintToLayer(true);
-    bottom_view_->layer()->SetFillsBoundsOpaquely(false);
-
-    main_view_ = new app_list::AppListMainView(
-        view_delegate, 0 /* initial_apps_page */, container);
+      : gesture_delegate_(gesture_delegate) {
+    SetLayoutManager(new views::FillLayout());
+    // Ideally AppListMainView should be used here and have AthenaStartPageView
+    // as its child view, so that custom pages and apps grid are available in
+    // the home card.
+    // TODO(mukai): make it so after the detailed UI has been fixed.
+    main_view_ = new AthenaStartPageView(view_delegate);
     AddChildView(main_view_);
-    main_view_->set_background(
-        views::Background::CreateSolidBackground(SK_ColorWHITE));
-    main_view_->SetPaintToLayer(true);
-
-    minimized_view_ = CreateMinimizedHome();
-    minimized_view_->SetPaintToLayer(true);
-    AddChildView(minimized_view_);
   }
 
   void SetStateProgress(HomeCard::State from_state,
                         HomeCard::State to_state,
                         float progress) {
-    if (from_state == HomeCard::VISIBLE_BOTTOM &&
-        to_state == HomeCard::VISIBLE_MINIMIZED) {
-      SetStateProgress(to_state, from_state, 1.0 - progress);
-      return;
-    }
-
-    // View from minimized to bottom.
-    if (from_state == HomeCard::VISIBLE_MINIMIZED &&
-        to_state == HomeCard::VISIBLE_BOTTOM) {
-      bottom_view_->SetVisible(true);
-      minimized_view_->SetVisible(true);
-      minimized_view_->layer()->SetOpacity(1.0f - progress);
-      return;
-    }
-
-    SetState(to_state);
+    // TODO(mukai): not clear the focus, but simply close the virtual keyboard.
+    GetFocusManager()->ClearFocus();
+    if (from_state == HomeCard::VISIBLE_CENTERED)
+      main_view_->SetLayoutState(1.0f - progress);
+    else if (to_state == HomeCard::VISIBLE_CENTERED)
+      main_view_->SetLayoutState(progress);
+    UpdateShadow(true);
   }
 
-  void SetState(HomeCard::State state) {
-    bottom_view_->SetVisible(state == HomeCard::VISIBLE_BOTTOM);
-    main_view_->SetVisible(state == HomeCard::VISIBLE_CENTERED);
-    minimized_view_->SetVisible(state == HomeCard::VISIBLE_MINIMIZED);
-    if (minimized_view_->visible())
-      minimized_view_->layer()->SetOpacity(1.0f);
-    if (state == HomeCard::VISIBLE_CENTERED) {
-      app_list::ContentsView* contents_view = main_view_->contents_view();
-      contents_view->SetActivePage(contents_view->GetPageIndexForNamedPage(
-          app_list::ContentsView::NAMED_PAGE_START));
-    }
-    wm::SetShadowType(GetWidget()->GetNativeView(),
-                      state == HomeCard::VISIBLE_MINIMIZED ?
-                      wm::SHADOW_TYPE_NONE :
-                      wm::SHADOW_TYPE_RECTANGULAR);
-  }
+  void SetStateWithAnimation(HomeCard::State state,
+                             gfx::Tween::Type tween_type) {
+    UpdateShadow(state != HomeCard::VISIBLE_MINIMIZED);
+    if (state == HomeCard::VISIBLE_CENTERED)
+      main_view_->RequestFocusOnSearchBox();
+    else
+      GetWidget()->GetFocusManager()->ClearFocus();
 
-  void SetStateWithAnimation(HomeCard::State from_state,
-                             HomeCard::State to_state) {
-    if ((from_state == HomeCard::VISIBLE_MINIMIZED &&
-         to_state == HomeCard::VISIBLE_BOTTOM) ||
-        (from_state == HomeCard::VISIBLE_BOTTOM &&
-         to_state == HomeCard::VISIBLE_MINIMIZED)) {
-      minimized_view_->SetVisible(true);
-      bottom_view_->SetVisible(true);
-      {
-        ui::ScopedLayerAnimationSettings settings(
-            minimized_view_->layer()->GetAnimator());
-        settings.SetTweenType(gfx::Tween::EASE_IN_OUT);
-        settings.AddObserver(new ui::ClosureAnimationObserver(
-            base::Bind(&HomeCardView::SetState,
-                       weak_factory_.GetWeakPtr(),
-                       to_state)));
-        minimized_view_->layer()->SetOpacity(
-            (to_state == HomeCard::VISIBLE_MINIMIZED) ? 1.0f : 0.0f);
-      }
-    } else {
-      // TODO(mukai): Take care of other transition.
-      SetState(to_state);
-    }
+    main_view_->SetLayoutStateWithAnimation(
+        (state == HomeCard::VISIBLE_CENTERED) ? 1.0f : 0.0f, tween_type);
   }
 
   void ClearGesture() {
@@ -362,22 +183,6 @@ class HomeCardView : public views::WidgetDelegateView {
   }
 
   // views::View:
-  virtual void Layout() OVERRIDE {
-    for (int i = 0; i < child_count(); ++i) {
-      views::View* child = child_at(i);
-      if (child->visible()) {
-        if (child == minimized_view_) {
-          gfx::Rect minimized_bounds = bounds();
-          minimized_bounds.set_y(
-              minimized_bounds.bottom() - kHomeCardMinimizedHeight);
-          minimized_bounds.set_height(kHomeCardMinimizedHeight);
-          child->SetBoundsRect(minimized_bounds);
-        } else {
-          child->SetBoundsRect(bounds());
-        }
-      }
-    }
-  }
   virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE {
     if (!gesture_manager_ &&
         event->type() == ui::ET_GESTURE_SCROLL_BEGIN) {
@@ -389,91 +194,34 @@ class HomeCardView : public views::WidgetDelegateView {
     if (gesture_manager_)
       gesture_manager_->ProcessGestureEvent(event);
   }
+  virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE {
+    if (HomeCard::Get()->GetState() == HomeCard::VISIBLE_MINIMIZED &&
+        event.IsLeftMouseButton() && event.GetClickCount() == 1) {
+      athena::WindowManager::Get()->ToggleOverview();
+      return true;
+    }
+    return false;
+  }
 
  private:
+  void UpdateShadow(bool should_show) {
+    wm::SetShadowType(
+        GetWidget()->GetNativeWindow(),
+        should_show ? wm::SHADOW_TYPE_RECTANGULAR : wm::SHADOW_TYPE_NONE);
+  }
+
   // views::WidgetDelegate:
   virtual views::View* GetContentsView() OVERRIDE {
     return this;
   }
 
-  app_list::AppListMainView* main_view_;
-  views::View* bottom_view_;
-  views::View* minimized_view_;
+  AthenaStartPageView* main_view_;
   scoped_ptr<HomeCardGestureManager> gesture_manager_;
   HomeCardGestureManager::Delegate* gesture_delegate_;
-  base::WeakPtrFactory<HomeCardView> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(HomeCardView);
 };
 
-class HomeCardImpl : public HomeCard,
-                     public AcceleratorHandler,
-                     public HomeCardLayoutManager::Delegate,
-                     public HomeCardGestureManager::Delegate,
-                     public WindowManagerObserver,
-                     public aura::client::ActivationChangeObserver {
- public:
-  explicit HomeCardImpl(AppModelBuilder* model_builder);
-  virtual ~HomeCardImpl();
-
-  void Init();
-
- private:
-  enum Command {
-    COMMAND_SHOW_HOME_CARD,
-  };
-  void InstallAccelerators();
-
-  // Overridden from HomeCard:
-  virtual void SetState(State state) OVERRIDE;
-  virtual State GetState() OVERRIDE;
-  virtual void RegisterSearchProvider(
-      app_list::SearchProvider* search_provider) OVERRIDE;
-  virtual void UpdateVirtualKeyboardBounds(
-      const gfx::Rect& bounds) OVERRIDE;
-
-  // AcceleratorHandler:
-  virtual bool IsCommandEnabled(int command_id) const OVERRIDE { return true; }
-  virtual bool OnAcceleratorFired(int command_id,
-                                  const ui::Accelerator& accelerator) OVERRIDE;
-
-  // HomeCardLayoutManager::Delegate:
-  virtual aura::Window* GetNativeWindow() OVERRIDE;
-
-  // HomeCardGestureManager::Delegate:
-  virtual void OnGestureEnded(State final_state) OVERRIDE;
-  virtual void OnGestureProgressed(
-      State from_state, State to_state, float progress) OVERRIDE;
-
-  // WindowManagerObserver:
-  virtual void OnOverviewModeEnter() OVERRIDE;
-  virtual void OnOverviewModeExit() OVERRIDE;
-
-  // aura::client::ActivationChangeObserver:
-  virtual void OnWindowActivated(aura::Window* gained_active,
-                                 aura::Window* lost_active) OVERRIDE;
-
-  scoped_ptr<AppModelBuilder> model_builder_;
-
-  HomeCard::State state_;
-
-  // original_state_ is the state which the home card should go back to after
-  // the virtual keyboard is hidden.
-  HomeCard::State original_state_;
-
-  views::Widget* home_card_widget_;
-  HomeCardView* home_card_view_;
-  scoped_ptr<AppListViewDelegate> view_delegate_;
-  HomeCardLayoutManager* layout_manager_;
-  aura::client::ActivationClient* activation_client_;  // Not owned
-
-  // Right now HomeCard allows only one search provider.
-  // TODO(mukai): port app-list's SearchController and Mixer.
-  scoped_ptr<app_list::SearchProvider> search_provider_;
-
-  DISALLOW_COPY_AND_ASSIGN(HomeCardImpl);
-};
-
 HomeCardImpl::HomeCardImpl(AppModelBuilder* model_builder)
     : model_builder_(model_builder),
       state_(HIDDEN),
@@ -484,15 +232,20 @@ HomeCardImpl::HomeCardImpl(AppModelBuilder* model_builder)
       activation_client_(NULL) {
   DCHECK(!instance);
   instance = this;
-  WindowManager::GetInstance()->AddObserver(this);
+  WindowManager::Get()->AddObserver(this);
 }
 
 HomeCardImpl::~HomeCardImpl() {
   DCHECK(instance);
-  WindowManager::GetInstance()->RemoveObserver(this);
+  WindowManager::Get()->RemoveObserver(this);
   if (activation_client_)
     activation_client_->RemoveObserver(this);
   home_card_widget_->CloseNow();
+
+  // Reset the view delegate first as it access search provider during
+  // shutdown.
+  view_delegate_.reset();
+  search_provider_.reset();
   instance = NULL;
 }
 
@@ -501,7 +254,7 @@ void HomeCardImpl::Init() {
   ScreenManager::ContainerParams params("HomeCardContainer", CP_HOME_CARD);
   params.can_activate_children = true;
   aura::Window* container = ScreenManager::Get()->CreateContainer(params);
-  layout_manager_ = new HomeCardLayoutManager(this);
+  layout_manager_ = new HomeCardLayoutManager();
 
   container->SetLayoutManager(layout_manager_);
   wm::SetChildWindowVisibilityChangesAnimated(container);
@@ -519,6 +272,11 @@ void HomeCardImpl::Init() {
   widget_params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
   home_card_widget_->Init(widget_params);
 
+  minimized_home_ = CreateMinimizedHome();
+  container->layer()->Add(minimized_home_->layer());
+  container->layer()->StackAtTop(minimized_home_->layer());
+  layout_manager_->SetMinimizedLayer(minimized_home_->layer());
+
   SetState(VISIBLE_MINIMIZED);
   home_card_view_->Layout();
 
@@ -526,6 +284,13 @@ void HomeCardImpl::Init() {
       aura::client::GetActivationClient(container->GetRootWindow());
   if (activation_client_)
     activation_client_->AddObserver(this);
+
+  AthenaEnv::Get()->SetDisplayWorkAreaInsets(
+      gfx::Insets(0, 0, kHomeCardMinimizedHeight, 0));
+}
+
+aura::Window* HomeCardImpl::GetHomeCardWindowForTest() const {
+  return home_card_widget_ ? home_card_widget_->GetNativeWindow() : NULL;
 }
 
 void HomeCardImpl::InstallAccelerators() {
@@ -546,15 +311,27 @@ void HomeCardImpl::SetState(HomeCard::State state) {
   HomeCard::State old_state = state_;
   state_ = state;
   original_state_ = state;
+
+  if (old_state == VISIBLE_MINIMIZED ||
+      state_ == VISIBLE_MINIMIZED) {
+    minimized_home_->layer()->SetVisible(true);
+    {
+      ui::ScopedLayerAnimationSettings settings(
+          minimized_home_->layer()->GetAnimator());
+      minimized_home_->layer()->SetVisible(state_ == VISIBLE_MINIMIZED);
+      minimized_home_->layer()->SetOpacity(
+          state_ == VISIBLE_MINIMIZED ? 1.0f : 0.0f);
+    }
+  }
   if (state_ == HIDDEN) {
     home_card_widget_->Hide();
   } else {
-    if (state_ == VISIBLE_CENTERED)
-      home_card_widget_->Show();
-    else
+    if (state_ == VISIBLE_MINIMIZED)
       home_card_widget_->ShowInactive();
-    home_card_view_->SetStateWithAnimation(old_state, state);
-    layout_manager_->Layout();
+    else
+      home_card_widget_->Show();
+    home_card_view_->SetStateWithAnimation(state, gfx::Tween::EASE_IN_OUT);
+    layout_manager_->Layout(true, gfx::Tween::EASE_IN_OUT);
   }
 }
 
@@ -582,6 +359,10 @@ void HomeCardImpl::UpdateVirtualKeyboardBounds(
   }
 }
 
+bool HomeCardImpl::IsCommandEnabled(int command_id) const {
+  return true;
+}
+
 bool HomeCardImpl::OnAcceleratorFired(int command_id,
                                       const ui::Accelerator& accelerator) {
   DCHECK_EQ(COMMAND_SHOW_HOME_CARD, command_id);
@@ -593,30 +374,32 @@ bool HomeCardImpl::OnAcceleratorFired(int command_id,
   return true;
 }
 
-aura::Window* HomeCardImpl::GetNativeWindow() {
-  if (state_ == HIDDEN)
-    return NULL;
-
-  return home_card_widget_ ? home_card_widget_->GetNativeWindow() : NULL;
-}
-
-void HomeCardImpl::OnGestureEnded(State final_state) {
+void HomeCardImpl::OnGestureEnded(State final_state, bool is_fling) {
   home_card_view_->ClearGesture();
   if (state_ != final_state &&
       (state_ == VISIBLE_MINIMIZED || final_state == VISIBLE_MINIMIZED)) {
-    WindowManager::GetInstance()->ToggleOverview();
+    SetState(final_state);
+    WindowManager::Get()->ToggleOverview();
   } else {
-    HomeCard::State old_state = state_;
     state_ = final_state;
-    home_card_view_->SetStateWithAnimation(old_state, final_state);
-    layout_manager_->Layout();
+    // When the animation happens after a fling, EASE_IN_OUT would cause weird
+    // slow-down right after the finger release because of slow-in. Therefore
+    // EASE_OUT is better.
+    gfx::Tween::Type tween_type =
+        is_fling ? gfx::Tween::EASE_OUT : gfx::Tween::EASE_IN_OUT;
+    home_card_view_->SetStateWithAnimation(state_, tween_type);
+    layout_manager_->Layout(true, tween_type);
   }
 }
 
 void HomeCardImpl::OnGestureProgressed(
     State from_state, State to_state, float progress) {
-  home_card_view_->SetStateProgress(from_state, to_state, progress);
-
+  if (from_state == VISIBLE_MINIMIZED || to_state == VISIBLE_MINIMIZED) {
+    minimized_home_->layer()->SetVisible(true);
+    float opacity =
+        (from_state == VISIBLE_MINIMIZED) ? 1.0f - progress : progress;
+    minimized_home_->layer()->SetOpacity(opacity);
+  }
   gfx::Rect screen_bounds =
       home_card_widget_->GetNativeWindow()->GetRootWindow()->bounds();
   home_card_widget_->SetBounds(gfx::Tween::RectValueBetween(
@@ -624,18 +407,27 @@ void HomeCardImpl::OnGestureProgressed(
       GetBoundsForState(screen_bounds, from_state),
       GetBoundsForState(screen_bounds, to_state)));
 
+  home_card_view_->SetStateProgress(from_state, to_state, progress);
+
   // TODO(mukai): signals the update to the window manager so that it shows the
   // intermediate visual state of overview mode.
 }
 
 void HomeCardImpl::OnOverviewModeEnter() {
-  SetState(VISIBLE_BOTTOM);
+  if (state_ == HIDDEN || state_ == VISIBLE_MINIMIZED)
+    SetState(VISIBLE_BOTTOM);
 }
 
 void HomeCardImpl::OnOverviewModeExit() {
   SetState(VISIBLE_MINIMIZED);
 }
 
+void HomeCardImpl::OnSplitViewModeEnter() {
+}
+
+void HomeCardImpl::OnSplitViewModeExit() {
+}
+
 void HomeCardImpl::OnWindowActivated(aura::Window* gained_active,
                                      aura::Window* lost_active) {
   if (state_ != HIDDEN &&
@@ -644,8 +436,6 @@ void HomeCardImpl::OnWindowActivated(aura::Window* gained_active,
   }
 }
 
-}  // namespace
-
 // static
 HomeCard* HomeCard::Create(AppModelBuilder* model_builder) {
   (new HomeCardImpl(model_builder))->Init();