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.
5 #include "athena/home/public/home_card.h"
10 #include "athena/common/container_priorities.h"
11 #include "athena/env/public/athena_env.h"
12 #include "athena/home/app_list_view_delegate.h"
13 #include "athena/home/athena_start_page_view.h"
14 #include "athena/home/home_card_constants.h"
15 #include "athena/home/home_card_gesture_manager.h"
16 #include "athena/home/minimized_home.h"
17 #include "athena/home/public/app_model_builder.h"
18 #include "athena/input/public/accelerator_manager.h"
19 #include "athena/screen/public/screen_manager.h"
20 #include "athena/wm/public/window_manager.h"
21 #include "athena/wm/public/window_manager_observer.h"
22 #include "ui/app_list/search_provider.h"
23 #include "ui/app_list/views/app_list_main_view.h"
24 #include "ui/app_list/views/contents_view.h"
25 #include "ui/aura/layout_manager.h"
26 #include "ui/aura/window.h"
27 #include "ui/compositor/layer.h"
28 #include "ui/compositor/layer_owner.h"
29 #include "ui/compositor/scoped_layer_animation_settings.h"
30 #include "ui/views/layout/fill_layout.h"
31 #include "ui/views/widget/widget.h"
32 #include "ui/views/widget/widget_delegate.h"
33 #include "ui/wm/core/shadow_types.h"
34 #include "ui/wm/core/visibility_controller.h"
35 #include "ui/wm/public/activation_change_observer.h"
36 #include "ui/wm/public/activation_client.h"
41 HomeCard
* instance
= NULL
;
43 gfx::Rect
GetBoundsForState(const gfx::Rect
& screen_bounds
,
44 HomeCard::State state
) {
46 case HomeCard::HIDDEN
:
49 case HomeCard::VISIBLE_CENTERED
:
52 // Do not change the home_card's size, only changes the top position
53 // instead, because size change causes unnecessary re-layouts.
54 case HomeCard::VISIBLE_BOTTOM
:
56 screen_bounds
.bottom() - kHomeCardHeight
,
57 screen_bounds
.width(),
58 screen_bounds
.height());
59 case HomeCard::VISIBLE_MINIMIZED
:
61 screen_bounds
.bottom() - kHomeCardMinimizedHeight
,
62 screen_bounds
.width(),
63 screen_bounds
.height());
70 // Makes sure the homecard is center-aligned horizontally and bottom-aligned
72 class HomeCardLayoutManager
: public aura::LayoutManager
{
74 HomeCardLayoutManager()
76 minimized_layer_(NULL
) {}
78 virtual ~HomeCardLayoutManager() {}
80 void Layout(bool animate
) {
81 // |home_card| could be detached from the root window (e.g. when it is being
83 if (!home_card_
|| !home_card_
->IsVisible() || !home_card_
->GetRootWindow())
86 scoped_ptr
<ui::ScopedLayerAnimationSettings
> settings
;
88 settings
.reset(new ui::ScopedLayerAnimationSettings(
89 home_card_
->layer()->GetAnimator()));
90 settings
->SetTweenType(gfx::Tween::EASE_IN_OUT
);
92 SetChildBoundsDirect(home_card_
, GetBoundsForState(
93 home_card_
->GetRootWindow()->bounds(), HomeCard::Get()->GetState()));
96 void SetMinimizedLayer(ui::Layer
* minimized_layer
) {
97 minimized_layer_
= minimized_layer
;
98 UpdateMinimizedHomeBounds();
102 void UpdateMinimizedHomeBounds() {
103 gfx::Rect minimized_bounds
= minimized_layer_
->parent()->bounds();
104 minimized_bounds
.set_y(
105 minimized_bounds
.bottom() - kHomeCardMinimizedHeight
);
106 minimized_bounds
.set_height(kHomeCardMinimizedHeight
);
107 minimized_layer_
->SetBounds(minimized_bounds
);
110 // aura::LayoutManager:
111 virtual void OnWindowResized() OVERRIDE
{
113 UpdateMinimizedHomeBounds();
115 virtual void OnWindowAddedToLayout(aura::Window
* child
) OVERRIDE
{
121 virtual void OnWillRemoveWindowFromLayout(aura::Window
* child
) OVERRIDE
{
122 if (home_card_
== child
)
125 virtual void OnWindowRemovedFromLayout(aura::Window
* child
) OVERRIDE
{
128 virtual void OnChildWindowVisibilityChanged(aura::Window
* child
,
129 bool visible
) OVERRIDE
{
132 virtual void SetChildBounds(aura::Window
* child
,
133 const gfx::Rect
& requested_bounds
) OVERRIDE
{
134 SetChildBoundsDirect(child
, requested_bounds
);
137 aura::Window
* home_card_
;
138 ui::Layer
* minimized_layer_
;
140 DISALLOW_COPY_AND_ASSIGN(HomeCardLayoutManager
);
143 // The container view of home card contents of each state.
144 class HomeCardView
: public views::WidgetDelegateView
{
146 HomeCardView(app_list::AppListViewDelegate
* view_delegate
,
147 aura::Window
* container
,
148 HomeCardGestureManager::Delegate
* gesture_delegate
)
149 : gesture_delegate_(gesture_delegate
) {
150 SetLayoutManager(new views::FillLayout());
151 // Ideally AppListMainView should be used here and have AthenaStartPageView
152 // as its child view, so that custom pages and apps grid are available in
154 // TODO(mukai): make it so after the detailed UI has been fixed.
155 main_view_
= new AthenaStartPageView(view_delegate
);
156 AddChildView(main_view_
);
159 void SetStateProgress(HomeCard::State from_state
,
160 HomeCard::State to_state
,
162 if (from_state
== HomeCard::VISIBLE_CENTERED
)
163 main_view_
->SetLayoutState(1.0f
- progress
);
164 else if (to_state
== HomeCard::VISIBLE_CENTERED
)
165 main_view_
->SetLayoutState(progress
);
170 void SetState(HomeCard::State state
) {
171 if (state
== HomeCard::VISIBLE_CENTERED
)
172 main_view_
->RequestFocusOnSearchBox();
174 GetWidget()->GetFocusManager()->ClearFocus();
175 wm::SetShadowType(GetWidget()->GetNativeView(),
176 state
== HomeCard::VISIBLE_MINIMIZED
?
177 wm::SHADOW_TYPE_NONE
:
178 wm::SHADOW_TYPE_RECTANGULAR
);
179 main_view_
->SetLayoutState(
180 (state
== HomeCard::VISIBLE_CENTERED
) ? 1.0f
: 0.0f
);
183 void SetStateWithAnimation(HomeCard::State state
) {
184 if (state
== HomeCard::VISIBLE_MINIMIZED
)
187 main_view_
->SetLayoutStateWithAnimation(
188 (state
== HomeCard::VISIBLE_CENTERED
) ? 1.0f
: 0.0f
);
191 void ClearGesture() {
192 gesture_manager_
.reset();
196 virtual void OnGestureEvent(ui::GestureEvent
* event
) OVERRIDE
{
197 if (!gesture_manager_
&&
198 event
->type() == ui::ET_GESTURE_SCROLL_BEGIN
) {
199 gesture_manager_
.reset(new HomeCardGestureManager(
201 GetWidget()->GetNativeWindow()->GetRootWindow()->bounds()));
204 if (gesture_manager_
)
205 gesture_manager_
->ProcessGestureEvent(event
);
207 virtual bool OnMousePressed(const ui::MouseEvent
& event
) OVERRIDE
{
208 if (HomeCard::Get()->GetState() == HomeCard::VISIBLE_MINIMIZED
&&
209 event
.IsLeftMouseButton() && event
.GetClickCount() == 1) {
210 athena::WindowManager::GetInstance()->ToggleOverview();
217 // views::WidgetDelegate:
218 virtual views::View
* GetContentsView() OVERRIDE
{
222 AthenaStartPageView
* main_view_
;
223 scoped_ptr
<HomeCardGestureManager
> gesture_manager_
;
224 HomeCardGestureManager::Delegate
* gesture_delegate_
;
226 DISALLOW_COPY_AND_ASSIGN(HomeCardView
);
229 class HomeCardImpl
: public HomeCard
,
230 public AcceleratorHandler
,
231 public HomeCardGestureManager::Delegate
,
232 public WindowManagerObserver
,
233 public aura::client::ActivationChangeObserver
{
235 explicit HomeCardImpl(AppModelBuilder
* model_builder
);
236 virtual ~HomeCardImpl();
242 COMMAND_SHOW_HOME_CARD
,
244 void InstallAccelerators();
245 void UpdateMinimizedHomeBounds();
247 // Overridden from HomeCard:
248 virtual void SetState(State state
) OVERRIDE
;
249 virtual State
GetState() OVERRIDE
;
250 virtual void RegisterSearchProvider(
251 app_list::SearchProvider
* search_provider
) OVERRIDE
;
252 virtual void UpdateVirtualKeyboardBounds(
253 const gfx::Rect
& bounds
) OVERRIDE
;
255 // AcceleratorHandler:
256 virtual bool IsCommandEnabled(int command_id
) const OVERRIDE
{ return true; }
257 virtual bool OnAcceleratorFired(int command_id
,
258 const ui::Accelerator
& accelerator
) OVERRIDE
;
260 // HomeCardGestureManager::Delegate:
261 virtual void OnGestureEnded(State final_state
) OVERRIDE
;
262 virtual void OnGestureProgressed(
263 State from_state
, State to_state
, float progress
) OVERRIDE
;
265 // WindowManagerObserver:
266 virtual void OnOverviewModeEnter() OVERRIDE
;
267 virtual void OnOverviewModeExit() OVERRIDE
;
268 virtual void OnActivityOrderHasChanged() OVERRIDE
;
270 // aura::client::ActivationChangeObserver:
271 virtual void OnWindowActivated(aura::Window
* gained_active
,
272 aura::Window
* lost_active
) OVERRIDE
;
274 scoped_ptr
<AppModelBuilder
> model_builder_
;
276 HomeCard::State state_
;
278 // original_state_ is the state which the home card should go back to after
279 // the virtual keyboard is hidden.
280 HomeCard::State original_state_
;
282 views::Widget
* home_card_widget_
;
283 HomeCardView
* home_card_view_
;
284 scoped_ptr
<AppListViewDelegate
> view_delegate_
;
285 HomeCardLayoutManager
* layout_manager_
;
286 aura::client::ActivationClient
* activation_client_
; // Not owned
287 scoped_ptr
<ui::LayerOwner
> minimized_home_
;
289 // Right now HomeCard allows only one search provider.
290 // TODO(mukai): port app-list's SearchController and Mixer.
291 scoped_ptr
<app_list::SearchProvider
> search_provider_
;
293 DISALLOW_COPY_AND_ASSIGN(HomeCardImpl
);
296 HomeCardImpl::HomeCardImpl(AppModelBuilder
* model_builder
)
297 : model_builder_(model_builder
),
299 original_state_(VISIBLE_MINIMIZED
),
300 home_card_widget_(NULL
),
301 home_card_view_(NULL
),
302 layout_manager_(NULL
),
303 activation_client_(NULL
) {
306 WindowManager::GetInstance()->AddObserver(this);
309 HomeCardImpl::~HomeCardImpl() {
311 WindowManager::GetInstance()->RemoveObserver(this);
312 if (activation_client_
)
313 activation_client_
->RemoveObserver(this);
314 home_card_widget_
->CloseNow();
316 // Reset the view delegate first as it access search provider during
318 view_delegate_
.reset();
319 search_provider_
.reset();
323 void HomeCardImpl::Init() {
324 InstallAccelerators();
325 ScreenManager::ContainerParams
params("HomeCardContainer", CP_HOME_CARD
);
326 params
.can_activate_children
= true;
327 aura::Window
* container
= ScreenManager::Get()->CreateContainer(params
);
328 layout_manager_
= new HomeCardLayoutManager();
330 container
->SetLayoutManager(layout_manager_
);
331 wm::SetChildWindowVisibilityChangesAnimated(container
);
333 view_delegate_
.reset(new AppListViewDelegate(model_builder_
.get()));
334 if (search_provider_
)
335 view_delegate_
->RegisterSearchProvider(search_provider_
.get());
337 home_card_view_
= new HomeCardView(view_delegate_
.get(), container
, this);
338 home_card_widget_
= new views::Widget();
339 views::Widget::InitParams
widget_params(
340 views::Widget::InitParams::TYPE_WINDOW_FRAMELESS
);
341 widget_params
.parent
= container
;
342 widget_params
.delegate
= home_card_view_
;
343 widget_params
.opacity
= views::Widget::InitParams::TRANSLUCENT_WINDOW
;
344 home_card_widget_
->Init(widget_params
);
346 minimized_home_
= CreateMinimizedHome();
347 container
->layer()->Add(minimized_home_
->layer());
348 container
->layer()->StackAtTop(minimized_home_
->layer());
349 layout_manager_
->SetMinimizedLayer(minimized_home_
->layer());
351 SetState(VISIBLE_MINIMIZED
);
352 home_card_view_
->Layout();
355 aura::client::GetActivationClient(container
->GetRootWindow());
356 if (activation_client_
)
357 activation_client_
->AddObserver(this);
359 AthenaEnv::Get()->SetDisplayWorkAreaInsets(
360 gfx::Insets(0, 0, kHomeCardMinimizedHeight
, 0));
363 void HomeCardImpl::InstallAccelerators() {
364 const AcceleratorData accelerator_data
[] = {
365 {TRIGGER_ON_PRESS
, ui::VKEY_L
, ui::EF_CONTROL_DOWN
,
366 COMMAND_SHOW_HOME_CARD
, AF_NONE
},
368 AcceleratorManager::Get()->RegisterAccelerators(
369 accelerator_data
, arraysize(accelerator_data
), this);
372 void HomeCardImpl::SetState(HomeCard::State state
) {
376 // Update |state_| before changing the visibility of the widgets, so that
377 // LayoutManager callbacks get the correct state.
378 HomeCard::State old_state
= state_
;
380 original_state_
= state
;
382 if (old_state
== VISIBLE_MINIMIZED
||
383 state_
== VISIBLE_MINIMIZED
) {
384 minimized_home_
->layer()->SetVisible(true);
386 ui::ScopedLayerAnimationSettings
settings(
387 minimized_home_
->layer()->GetAnimator());
388 minimized_home_
->layer()->SetVisible(state_
== VISIBLE_MINIMIZED
);
389 minimized_home_
->layer()->SetOpacity(
390 state_
== VISIBLE_MINIMIZED
? 1.0f
: 0.0f
);
393 if (state_
== HIDDEN
) {
394 home_card_widget_
->Hide();
396 if (state_
== VISIBLE_CENTERED
)
397 home_card_widget_
->Show();
399 home_card_widget_
->ShowInactive();
400 home_card_view_
->SetStateWithAnimation(state
);
401 layout_manager_
->Layout(true);
405 HomeCard::State
HomeCardImpl::GetState() {
409 void HomeCardImpl::RegisterSearchProvider(
410 app_list::SearchProvider
* search_provider
) {
411 DCHECK(!search_provider_
);
412 search_provider_
.reset(search_provider
);
413 view_delegate_
->RegisterSearchProvider(search_provider_
.get());
416 void HomeCardImpl::UpdateVirtualKeyboardBounds(
417 const gfx::Rect
& bounds
) {
418 if (state_
== VISIBLE_MINIMIZED
&& !bounds
.IsEmpty()) {
420 original_state_
= VISIBLE_MINIMIZED
;
421 } else if (state_
== VISIBLE_BOTTOM
&& !bounds
.IsEmpty()) {
422 SetState(VISIBLE_CENTERED
);
423 original_state_
= VISIBLE_BOTTOM
;
424 } else if (state_
!= original_state_
&& bounds
.IsEmpty()) {
425 SetState(original_state_
);
429 bool HomeCardImpl::OnAcceleratorFired(int command_id
,
430 const ui::Accelerator
& accelerator
) {
431 DCHECK_EQ(COMMAND_SHOW_HOME_CARD
, command_id
);
433 if (state_
== VISIBLE_CENTERED
&& original_state_
!= VISIBLE_BOTTOM
)
434 SetState(VISIBLE_MINIMIZED
);
435 else if (state_
== VISIBLE_MINIMIZED
)
436 SetState(VISIBLE_CENTERED
);
440 void HomeCardImpl::OnGestureEnded(State final_state
) {
441 home_card_view_
->ClearGesture();
442 if (state_
!= final_state
&&
443 (state_
== VISIBLE_MINIMIZED
|| final_state
== VISIBLE_MINIMIZED
)) {
444 SetState(final_state
);
445 WindowManager::GetInstance()->ToggleOverview();
447 state_
= final_state
;
448 home_card_view_
->SetStateWithAnimation(state_
);
449 layout_manager_
->Layout(true);
453 void HomeCardImpl::OnGestureProgressed(
454 State from_state
, State to_state
, float progress
) {
455 if (from_state
== VISIBLE_MINIMIZED
|| to_state
== VISIBLE_MINIMIZED
) {
456 minimized_home_
->layer()->SetVisible(true);
458 (from_state
== VISIBLE_MINIMIZED
) ? 1.0f
- progress
: progress
;
459 minimized_home_
->layer()->SetOpacity(opacity
);
461 gfx::Rect screen_bounds
=
462 home_card_widget_
->GetNativeWindow()->GetRootWindow()->bounds();
463 home_card_widget_
->SetBounds(gfx::Tween::RectValueBetween(
465 GetBoundsForState(screen_bounds
, from_state
),
466 GetBoundsForState(screen_bounds
, to_state
)));
468 home_card_view_
->SetStateProgress(from_state
, to_state
, progress
);
470 // TODO(mukai): signals the update to the window manager so that it shows the
471 // intermediate visual state of overview mode.
474 void HomeCardImpl::OnOverviewModeEnter() {
475 if (state_
== VISIBLE_MINIMIZED
)
476 SetState(VISIBLE_BOTTOM
);
479 void HomeCardImpl::OnOverviewModeExit() {
480 SetState(VISIBLE_MINIMIZED
);
483 void HomeCardImpl::OnActivityOrderHasChanged() {
486 void HomeCardImpl::OnWindowActivated(aura::Window
* gained_active
,
487 aura::Window
* lost_active
) {
488 if (state_
!= HIDDEN
&&
489 gained_active
!= home_card_widget_
->GetNativeWindow()) {
490 SetState(VISIBLE_MINIMIZED
);
497 HomeCard
* HomeCard::Create(AppModelBuilder
* model_builder
) {
498 (new HomeCardImpl(model_builder
))->Init();
504 void HomeCard::Shutdown() {
511 HomeCard
* HomeCard::Get() {
516 } // namespace athena