OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "ash/app_list/app_list.h" | |
6 | |
7 #include "ash/app_list/app_list_view.h" | |
8 #include "ash/app_list/icon_cache.h" | |
9 #include "ash/ash_switches.h" | |
10 #include "ash/shell.h" | |
11 #include "ash/shell_delegate.h" | |
12 #include "ash/shell_window_ids.h" | |
13 #include "ash/wm/shelf_layout_manager.h" | |
14 #include "ash/wm/window_util.h" | |
15 #include "base/command_line.h" | |
16 #include "ui/aura/event.h" | |
17 #include "ui/aura/root_window.h" | |
18 #include "ui/aura/window.h" | |
19 #include "ui/compositor/layer.h" | |
20 #include "ui/compositor/scoped_layer_animation_settings.h" | |
21 #include "ui/gfx/transform_util.h" | |
22 | |
23 namespace ash { | |
24 namespace internal { | |
25 | |
26 namespace { | |
27 | |
28 const float kContainerAnimationScaleFactor = 1.05f; | |
29 | |
30 // Duration for both default container and app list animation in milliseconds. | |
31 const int kAnimationDurationMs = 130; | |
32 | |
33 // Delayed time of 2nd animation in milliseconds. | |
34 const int kSecondAnimationStartDelay = kAnimationDurationMs - 20; | |
35 | |
36 ui::Layer* GetLayer(views::Widget* widget) { | |
37 return widget->GetNativeView()->layer(); | |
38 } | |
39 | |
40 } // namespace | |
41 | |
42 //////////////////////////////////////////////////////////////////////////////// | |
43 // AppList, public: | |
44 | |
45 AppList::AppList() : is_visible_(false), view_(NULL) { | |
46 IconCache::CreateInstance(); | |
47 } | |
48 | |
49 AppList::~AppList() { | |
50 ResetView(); | |
51 IconCache::DeleteInstance(); | |
52 } | |
53 | |
54 // static | |
55 bool AppList::UseAppListV2() { | |
56 return CommandLine::ForCurrentProcess()->HasSwitch( | |
57 switches::kEnableAppListV2); | |
58 } | |
59 | |
60 void AppList::SetVisible(bool visible) { | |
61 if (visible == is_visible_) | |
62 return; | |
63 | |
64 is_visible_ = visible; | |
65 | |
66 // App list needs to know the new shelf layout in order to calculate its | |
67 // UI layout when AppListView visibility changes. | |
68 Shell::GetInstance()->shelf()->UpdateAutoHideState(); | |
69 | |
70 if (view_) { | |
71 ScheduleAnimation(); | |
72 } else if (is_visible_) { | |
73 // AppListModel and AppListViewDelegate are owned by AppListView. They | |
74 // will be released with AppListView on close. | |
75 SetView(new AppListView( | |
76 Shell::GetInstance()->delegate()->CreateAppListViewDelegate())); | |
77 } | |
78 } | |
79 | |
80 bool AppList::IsVisible() { | |
81 return view_ && view_->GetWidget()->IsVisible(); | |
82 } | |
83 | |
84 aura::Window* AppList::GetWindow() { | |
85 return is_visible_ && view_ ? view_->GetWidget()->GetNativeWindow() : NULL; | |
86 } | |
87 | |
88 //////////////////////////////////////////////////////////////////////////////// | |
89 // AppList, private: | |
90 | |
91 void AppList::SetView(AppListView* view) { | |
92 DCHECK(view_ == NULL); | |
93 | |
94 if (is_visible_) { | |
95 IconCache::GetInstance()->MarkAllEntryUnused(); | |
96 | |
97 view_ = view; | |
98 views::Widget* widget = view_->GetWidget(); | |
99 widget->AddObserver(this); | |
100 Shell::GetInstance()->AddRootWindowEventFilter(this); | |
101 widget->GetNativeView()->GetRootWindow()->AddRootWindowObserver(this); | |
102 | |
103 widget->SetOpacity(0); | |
104 ScheduleAnimation(); | |
105 | |
106 view_->GetWidget()->Show(); | |
107 } else { | |
108 view->GetWidget()->Close(); | |
109 } | |
110 } | |
111 | |
112 void AppList::ResetView() { | |
113 if (!view_) | |
114 return; | |
115 | |
116 views::Widget* widget = view_->GetWidget(); | |
117 widget->RemoveObserver(this); | |
118 GetLayer(widget)->GetAnimator()->RemoveObserver(this); | |
119 Shell::GetInstance()->RemoveRootWindowEventFilter(this); | |
120 widget->GetNativeView()->GetRootWindow()->RemoveRootWindowObserver(this); | |
121 view_ = NULL; | |
122 | |
123 IconCache::GetInstance()->PurgeAllUnused(); | |
124 } | |
125 | |
126 void AppList::ScheduleAnimation() { | |
127 second_animation_timer_.Stop(); | |
128 | |
129 // Stop observing previous animation. | |
130 StopObservingImplicitAnimations(); | |
131 | |
132 ScheduleDimmingAnimation(); | |
133 | |
134 // No browser window fading and app list secondary animation for v2. | |
135 if (UseAppListV2()) | |
136 return; | |
137 | |
138 if (is_visible_) { | |
139 ScheduleBrowserWindowsAnimation(); | |
140 second_animation_timer_.Start( | |
141 FROM_HERE, | |
142 base::TimeDelta::FromMilliseconds(kSecondAnimationStartDelay), | |
143 this, | |
144 &AppList::ScheduleAppListAnimation); | |
145 } else { | |
146 ScheduleAppListAnimation(); | |
147 second_animation_timer_.Start( | |
148 FROM_HERE, | |
149 base::TimeDelta::FromMilliseconds(kSecondAnimationStartDelay), | |
150 this, | |
151 &AppList::ScheduleBrowserWindowsAnimation); | |
152 } | |
153 | |
154 } | |
155 | |
156 void AppList::ScheduleBrowserWindowsAnimationForContainer( | |
157 aura::Window* container) { | |
158 DCHECK(container); | |
159 ui::Layer* layer = container->layer(); | |
160 layer->GetAnimator()->StopAnimating(); | |
161 | |
162 ui::ScopedLayerAnimationSettings animation(layer->GetAnimator()); | |
163 animation.SetTransitionDuration( | |
164 base::TimeDelta::FromMilliseconds(kAnimationDurationMs)); | |
165 animation.SetTweenType( | |
166 is_visible_ ? ui::Tween::EASE_IN : ui::Tween::EASE_OUT); | |
167 | |
168 layer->SetOpacity(is_visible_ ? 0.0 : 1.0); | |
169 layer->SetTransform(is_visible_ ? | |
170 ui::GetScaleTransform( | |
171 gfx::Point(layer->bounds().width() / 2, | |
172 layer->bounds().height() / 2), | |
173 kContainerAnimationScaleFactor) : | |
174 ui::Transform()); | |
175 } | |
176 | |
177 void AppList::ScheduleBrowserWindowsAnimation() { | |
178 // Note: containers could be NULL during Shell shutdown. | |
179 aura::Window* default_container = Shell::GetInstance()->GetContainer( | |
180 internal::kShellWindowId_DefaultContainer); | |
181 if (default_container) | |
182 ScheduleBrowserWindowsAnimationForContainer(default_container); | |
183 aura::Window* always_on_top_container = Shell::GetInstance()->GetContainer( | |
184 internal::kShellWindowId_AlwaysOnTopContainer); | |
185 if (always_on_top_container) | |
186 ScheduleBrowserWindowsAnimationForContainer(always_on_top_container); | |
187 } | |
188 | |
189 void AppList::ScheduleDimmingAnimation() { | |
190 ui::Layer* layer = GetLayer(view_->GetWidget()); | |
191 layer->GetAnimator()->StopAnimating(); | |
192 | |
193 int duration = UseAppListV2() ? | |
194 kAnimationDurationMs : 2 * kAnimationDurationMs; | |
195 | |
196 ui::ScopedLayerAnimationSettings animation(layer->GetAnimator()); | |
197 animation.SetTransitionDuration( | |
198 base::TimeDelta::FromMilliseconds(duration)); | |
199 animation.AddObserver(this); | |
200 | |
201 layer->SetOpacity(is_visible_ ? 1.0 : 0.0); | |
202 } | |
203 | |
204 void AppList::ScheduleAppListAnimation() { | |
205 if (is_visible_) | |
206 view_->AnimateShow(kAnimationDurationMs); | |
207 else | |
208 view_->AnimateHide(kAnimationDurationMs); | |
209 } | |
210 | |
211 //////////////////////////////////////////////////////////////////////////////// | |
212 // AppList, aura::EventFilter implementation: | |
213 | |
214 bool AppList::PreHandleKeyEvent(aura::Window* target, | |
215 aura::KeyEvent* event) { | |
216 return false; | |
217 } | |
218 | |
219 bool AppList::PreHandleMouseEvent(aura::Window* target, | |
220 aura::MouseEvent* event) { | |
221 if (view_ && is_visible_ && event->type() == ui::ET_MOUSE_PRESSED) { | |
222 views::Widget* widget = view_->GetWidget(); | |
223 aura::MouseEvent translated(*event, target, widget->GetNativeView()); | |
224 if (!widget->GetNativeView()->ContainsPoint(translated.location())) | |
225 SetVisible(false); | |
226 } | |
227 return false; | |
228 } | |
229 | |
230 ui::TouchStatus AppList::PreHandleTouchEvent(aura::Window* target, | |
231 aura::TouchEvent* event) { | |
232 return ui::TOUCH_STATUS_UNKNOWN; | |
233 } | |
234 | |
235 ui::GestureStatus AppList::PreHandleGestureEvent( | |
236 aura::Window* target, | |
237 aura::GestureEvent* event) { | |
238 return ui::GESTURE_STATUS_UNKNOWN; | |
239 } | |
240 | |
241 //////////////////////////////////////////////////////////////////////////////// | |
242 // AppList, ura::RootWindowObserver implementation: | |
243 void AppList::OnRootWindowResized(const aura::RootWindow* root, | |
244 const gfx::Size& old_size) { | |
245 if (view_ && is_visible_) | |
246 view_->UpdateBounds(); | |
247 } | |
248 | |
249 void AppList::OnWindowFocused(aura::Window* window) { | |
250 if (view_ && is_visible_) { | |
251 aura::Window* applist_container = Shell::GetInstance()->GetContainer( | |
252 internal::kShellWindowId_AppListContainer); | |
253 aura::Window* bubble_container = Shell::GetInstance()->GetContainer( | |
254 internal::kShellWindowId_SettingBubbleContainer); | |
255 if (window->parent() != applist_container && | |
256 window->parent() != bubble_container) { | |
257 SetVisible(false); | |
258 } | |
259 } | |
260 } | |
261 | |
262 //////////////////////////////////////////////////////////////////////////////// | |
263 // AppList, ui::ImplicitAnimationObserver implementation: | |
264 | |
265 void AppList::OnImplicitAnimationsCompleted() { | |
266 if (is_visible_ ) | |
267 view_->GetWidget()->Activate(); | |
268 else | |
269 view_->GetWidget()->Close(); | |
270 } | |
271 | |
272 //////////////////////////////////////////////////////////////////////////////// | |
273 // AppList, views::Widget::Observer implementation: | |
274 | |
275 void AppList::OnWidgetClosing(views::Widget* widget) { | |
276 DCHECK(view_->GetWidget() == widget); | |
277 if (is_visible_) | |
278 SetVisible(false); | |
279 ResetView(); | |
280 } | |
281 | |
282 } // namespace internal | |
283 } // namespace ash | |
OLD | NEW |