15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/wm/app_list_controller.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
77d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "ash/ash_switches.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/launcher/launcher.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/root_window_controller.h"
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ash/shelf/shelf_layout_manager.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/shell.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/shell_delegate.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/shell_window_ids.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/wm/property_util.h"
15bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch#include "base/command_line.h"
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/app_list/app_list_constants.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/app_list/pagination_model.h"
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/app_list/views/app_list_view.h"
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/aura/client/focus_client.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/aura/root_window.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/aura/window.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/events/event.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/compositor/layer.h"
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/compositor/scoped_layer_animation_settings.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/transform_util.h"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/widget/widget.h"
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace ash {
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace internal {
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Duration for show/hide animation in milliseconds.
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kAnimationDurationMs = 200;
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Offset in pixels to animation away/towards the launcher.
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kAnimationOffset = 8;
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The maximum shift in pixels when over-scroll happens.
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kMaxOverScrollShift = 48;
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
42bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch// The alternate shelf style adjusts the bubble to be flush with the shelf
43bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch// when there is no bubble-tip. This is the tip height which needs to be
44bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch// offsetted.
45bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdochconst int kArrowTipHeight = 10;
46bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch
47bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch// The minimal anchor position offset to make sure that the bubble is still on
48bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch// the screen with 8 pixels spacing on the left / right. This constant is a
49bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch// result of minimal bubble arrow sizes and offsets.
50558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdochconst int kMinimalAnchorPositionOffset = 57;
51bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ui::Layer* GetLayer(views::Widget* widget) {
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return widget->GetNativeView()->layer();
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Gets arrow location based on shelf alignment.
57c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)views::BubbleBorder::Arrow GetBubbleArrow(aura::Window* window) {
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(Shell::HasInstance());
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return ShelfLayoutManager::ForLauncher(window)->
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      SelectValueForShelfAlignment(
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          views::BubbleBorder::BOTTOM_CENTER,
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          views::BubbleBorder::LEFT_CENTER,
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          views::BubbleBorder::RIGHT_CENTER,
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          views::BubbleBorder::TOP_CENTER);
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Offset given |rect| towards shelf.
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gfx::Rect OffsetTowardsShelf(const gfx::Rect& rect, views::Widget* widget) {
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(Shell::HasInstance());
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ShelfAlignment shelf_alignment = Shell::GetInstance()->GetShelfAlignment(
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      widget->GetNativeView()->GetRootWindow());
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Rect offseted(rect);
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (shelf_alignment) {
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case SHELF_ALIGNMENT_BOTTOM:
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      offseted.Offset(0, kAnimationOffset);
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case SHELF_ALIGNMENT_LEFT:
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      offseted.Offset(-kAnimationOffset, 0);
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case SHELF_ALIGNMENT_RIGHT:
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      offseted.Offset(kAnimationOffset, 0);
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case SHELF_ALIGNMENT_TOP:
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      offseted.Offset(0, -kAnimationOffset);
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return offseted;
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
91bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch// Using |button_bounds|, determine the anchor so that the bubble gets shown
92bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch// above the shelf (used for the alternate shelf theme).
93bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdochgfx::Point GetAdjustAnchorPositionToShelf(
94bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch    const gfx::Rect& button_bounds, views::Widget* widget) {
95bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  DCHECK(Shell::HasInstance());
96bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  ShelfAlignment shelf_alignment = Shell::GetInstance()->GetShelfAlignment(
97bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch      widget->GetNativeView()->GetRootWindow());
98bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  gfx::Point anchor(button_bounds.CenterPoint());
99bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  switch (shelf_alignment) {
100bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch    case SHELF_ALIGNMENT_TOP:
101bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch    case SHELF_ALIGNMENT_BOTTOM:
102bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch      {
103bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch        if (base::i18n::IsRTL()) {
104bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch          int screen_width = widget->GetWorkAreaBoundsInScreen().width();
105bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch          anchor.set_x(std::min(screen_width - kMinimalAnchorPositionOffset,
106bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch                                anchor.x()));
107bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch        } else {
108bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch          anchor.set_x(std::max(kMinimalAnchorPositionOffset, anchor.x()));
109bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch        }
110bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch        int offset = button_bounds.height() / 2 - kArrowTipHeight;
111bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch        if (shelf_alignment == SHELF_ALIGNMENT_TOP)
112bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch          offset = -offset;
113bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch        anchor.set_y(anchor.y() - offset);
114bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch      }
115bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch      break;
116bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch    case SHELF_ALIGNMENT_LEFT:
117bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch      anchor.set_x(button_bounds.right() - kArrowTipHeight);
118bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch      anchor.set_y(std::max(kMinimalAnchorPositionOffset, anchor.y()));
119bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch      break;
120bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch    case SHELF_ALIGNMENT_RIGHT:
121bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch      anchor.set_x(button_bounds.x() + kArrowTipHeight);
122bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch      anchor.set_y(std::max(kMinimalAnchorPositionOffset, anchor.y()));
123bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch      break;
124bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  }
125bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch
126bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  return anchor;
127bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch}
128bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// AppListController, public:
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AppListController::AppListController()
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : pagination_model_(new app_list::PaginationModel),
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      is_visible_(false),
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      view_(NULL),
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      should_snap_back_(false) {
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Shell::GetInstance()->AddShellObserver(this);
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pagination_model_->AddObserver(this);
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AppListController::~AppListController() {
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Ensures app list view goes before the controller since pagination model
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // lives in the controller and app list view would access it on destruction.
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (view_ && view_->GetWidget())
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    view_->GetWidget()->CloseNow();
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Shell::GetInstance()->RemoveShellObserver(this);
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pagination_model_->RemoveObserver(this);
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AppListController::SetVisible(bool visible, aura::Window* window) {
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (visible == is_visible_)
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  is_visible_ = visible;
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // App list needs to know the new shelf layout in order to calculate its
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // UI layout when AppListView visibility changes.
1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Shell::GetPrimaryRootWindowController()->GetShelfLayoutManager()->
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      UpdateAutoHideState();
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (view_) {
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ScheduleAnimation();
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (is_visible_) {
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // AppListModel and AppListViewDelegate are owned by AppListView. They
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // will be released with AppListView on close.
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    app_list::AppListView* view = new app_list::AppListView(
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        Shell::GetInstance()->delegate()->CreateAppListViewDelegate());
1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    aura::Window* container = GetRootWindowController(window->GetRootWindow())->
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        GetContainer(kShellWindowId_AppListContainer);
173eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    if (ash::switches::UseAlternateShelfLayout()) {
174eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      gfx::Rect applist_button_bounds = Launcher::ForWindow(container)->
175eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          GetAppListButtonView()->GetBoundsInScreen();
176eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      view->InitAsBubble(
177eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          container,
178eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          pagination_model_.get(),
179eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          NULL,
180bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch          GetAdjustAnchorPositionToShelf(applist_button_bounds,
181bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch              Launcher::ForWindow(container)->GetAppListButtonView()->
182bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch                  GetWidget()),
183eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          GetBubbleArrow(container),
184eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          true /* border_accepts_events */);
185bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch      view->SetArrowPaintType(views::BubbleBorder::PAINT_NONE);
186eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    } else {
187eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      view->InitAsBubble(
188eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          container,
189eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          pagination_model_.get(),
190eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          Launcher::ForWindow(container)->GetAppListButtonView(),
191eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          gfx::Point(),
192eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          GetBubbleArrow(container),
193eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          true /* border_accepts_events */);
194eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    }
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SetView(view);
196bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch    // By setting us as DnD recipient, the app list knows that we can
197bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch    // handle items.
198bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch    if (!CommandLine::ForCurrentProcess()->HasSwitch(
199bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch            ash::switches::kAshDisableDragAndDropAppListToLauncher)) {
200bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch      SetDragAndDropHostOfCurrentAppList(
201bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch          Launcher::ForWindow(window)->GetDragAndDropHostForAppList());
202bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch    }
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool AppListController::IsVisible() const {
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return view_ && view_->GetWidget()->IsVisible();
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)aura::Window* AppListController::GetWindow() {
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return is_visible_ && view_ ? view_->GetWidget()->GetNativeWindow() : NULL;
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
214bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch////////////////////////////////////////////////////////////////////////////////
215bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch// AppListController, private:
216bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
217b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)void AppListController::SetDragAndDropHostOfCurrentAppList(
218b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    app_list::ApplicationDragAndDropHost* drag_and_drop_host) {
219b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (view_ && is_visible_)
220b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    view_->SetDragAndDropHostOfCurrentAppList(drag_and_drop_host);
221b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}
222b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AppListController::SetView(app_list::AppListView* view) {
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(view_ == NULL);
2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(is_visible_);
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  view_ = view;
2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  views::Widget* widget = view_->GetWidget();
2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  widget->AddObserver(this);
2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Shell::GetInstance()->AddPreTargetHandler(this);
2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Launcher::ForWindow(widget->GetNativeWindow())->AddIconObserver(this);
2327d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  widget->GetNativeView()->GetRootWindow()->AddObserver(this);
2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  aura::client::GetFocusClient(widget->GetNativeView())->AddObserver(this);
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  view_->ShowWhenReady();
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AppListController::ResetView() {
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!view_)
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  views::Widget* widget = view_->GetWidget();
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  widget->RemoveObserver(this);
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GetLayer(widget)->GetAnimator()->RemoveObserver(this);
2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Shell::GetInstance()->RemovePreTargetHandler(this);
2462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Launcher::ForWindow(widget->GetNativeWindow())->RemoveIconObserver(this);
2477d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  widget->GetNativeView()->GetRootWindow()->RemoveObserver(this);
2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  aura::client::GetFocusClient(widget->GetNativeView())->RemoveObserver(this);
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  view_ = NULL;
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AppListController::ScheduleAnimation() {
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Stop observing previous animation.
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  StopObservingImplicitAnimations();
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  views::Widget* widget = view_->GetWidget();
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ui::Layer* layer = GetLayer(widget);
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  layer->GetAnimator()->StopAnimating();
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Rect target_bounds;
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (is_visible_) {
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    target_bounds = widget->GetWindowBoundsInScreen();
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    widget->SetBounds(OffsetTowardsShelf(target_bounds, widget));
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    target_bounds = OffsetTowardsShelf(widget->GetWindowBoundsInScreen(),
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       widget);
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ui::ScopedLayerAnimationSettings animation(layer->GetAnimator());
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  animation.SetTransitionDuration(
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::TimeDelta::FromMilliseconds(
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          is_visible_ ? 0 : kAnimationDurationMs));
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  animation.AddObserver(this);
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  layer->SetOpacity(is_visible_ ? 1.0 : 0.0);
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  widget->SetBounds(target_bounds);
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AppListController::ProcessLocatedEvent(ui::LocatedEvent* event) {
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the event happened on a menu, then the event should not close the app
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // list.
2822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  aura::Window* target = static_cast<aura::Window*>(event->target());
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (target) {
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RootWindowController* root_controller =
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        GetRootWindowController(target->GetRootWindow());
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (root_controller) {
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      aura::Window* menu_container = root_controller->GetContainer(
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          ash::internal::kShellWindowId_MenuContainer);
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (menu_container->Contains(target))
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return;
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (view_ && is_visible_) {
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    aura::Window* window = view_->GetWidget()->GetNativeView();
2962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    gfx::Point window_local_point(event->root_location());
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    aura::Window::ConvertPointToTarget(window->GetRootWindow(),
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       window,
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       &window_local_point);
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Use HitTest to respect the hit test mask of the bubble.
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!window->HitTest(window_local_point))
3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      SetVisible(false, window);
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AppListController::UpdateBounds() {
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (view_ && is_visible_)
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    view_->UpdateBounds();
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// AppListController, aura::EventFilter implementation:
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AppListController::OnMouseEvent(ui::MouseEvent* event) {
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (event->type() == ui::ET_MOUSE_PRESSED)
3162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ProcessLocatedEvent(event);
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AppListController::OnGestureEvent(ui::GestureEvent* event) {
3202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (event->type() == ui::ET_GESTURE_TAP_DOWN)
3212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ProcessLocatedEvent(event);
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// AppListController,  aura::FocusObserver implementation:
3262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AppListController::OnWindowFocused(aura::Window* gained_focus,
3282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                        aura::Window* lost_focus) {
3292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (gained_focus && view_ && is_visible_) {
3302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    aura::Window* applist_container =
3312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        GetRootWindowController(gained_focus->GetRootWindow())->GetContainer(
3322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            kShellWindowId_AppListContainer);
3332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (gained_focus->parent() != applist_container)
3342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      SetVisible(false, gained_focus);
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
3397d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)// AppListController,  aura::WindowObserver implementation:
3407d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void AppListController::OnWindowBoundsChanged(aura::Window* root,
3417d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                                              const gfx::Rect& old_bounds,
3427d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                                              const gfx::Rect& new_bounds) {
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UpdateBounds();
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// AppListController, ui::ImplicitAnimationObserver implementation:
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AppListController::OnImplicitAnimationsCompleted() {
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (is_visible_ )
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    view_->GetWidget()->Activate();
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    view_->GetWidget()->Close();
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// AppListController, views::WidgetObserver implementation:
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AppListController::OnWidgetDestroying(views::Widget* widget) {
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(view_->GetWidget() == widget);
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (is_visible_)
3622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SetVisible(false, widget->GetNativeView());
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ResetView();
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// AppListController, ShellObserver implementation:
3682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AppListController::OnShelfAlignmentChanged(aura::RootWindow* root_window) {
369c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (view_)
370c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    view_->SetBubbleArrow(GetBubbleArrow(view_->GetWidget()->GetNativeView()));
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// AppListController, LauncherIconObserver implementation:
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AppListController::OnLauncherIconPositionsChanged() {
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UpdateBounds();
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// AppListController, PaginationModelObserver implementation:
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AppListController::TotalPagesChanged() {
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AppListController::SelectedPageChanged(int old_selected,
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                            int new_selected) {
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3907dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid AppListController::TransitionStarted() {
3917dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
3927dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AppListController::TransitionChanged() {
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |view_| could be NULL when app list is closed with a running transition.
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!view_)
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const app_list::PaginationModel::Transition& transition =
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pagination_model_->transition();
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (pagination_model_->is_valid_page(transition.target_page))
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  views::Widget* widget = view_->GetWidget();
4042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ui::LayerAnimator* widget_animator = GetLayer(widget)->GetAnimator();
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!pagination_model_->IsRevertingCurrentTransition()) {
4062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Update cached |view_bounds_| if it is the first over-scroll move and
4072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // widget does not have running animations.
4082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!should_snap_back_ && !widget_animator->is_animating())
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      view_bounds_ = widget->GetWindowBoundsInScreen();
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const int current_page = pagination_model_->selected_page();
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const int dir = transition.target_page > current_page ? -1 : 1;
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const double progress = 1.0 - pow(1.0 - transition.progress, 4);
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const int shift = kMaxOverScrollShift * progress * dir;
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gfx::Rect shifted(view_bounds_);
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    shifted.set_x(shifted.x() + shift);
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    widget->SetBounds(shifted);
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    should_snap_back_ = true;
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (should_snap_back_) {
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    should_snap_back_ = false;
4232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ui::ScopedLayerAnimationSettings animation(widget_animator);
4242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    animation.SetTransitionDuration(base::TimeDelta::FromMilliseconds(
4252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        app_list::kOverscrollPageTransitionDurationMs));
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    widget->SetBounds(view_bounds_);
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace internal
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace ash
432