Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1008)

Side by Side Diff: chrome/browser/ui/ash/multi_user/user_switch_animator_chromeos.cc

Issue 223823004: Improving the user transition to add special cases for maximized windows and make the transition "m… (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fixed preferences browser test [disabling animations] Created 6 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/ui/ash/multi_user/user_switch_animator_chromeos.h"
6
7 #include "ash/desktop_background/user_wallpaper_delegate.h"
8 #include "ash/root_window_controller.h"
9 #include "ash/shelf/shelf_layout_manager.h"
10 #include "ash/shell.h"
11 #include "ash/wm/mru_window_tracker.h"
12 #include "ash/wm/window_positioner.h"
13 #include "ash/wm/window_state.h"
14 #include "chrome/browser/chromeos/login/wallpaper_manager.h"
15 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
16 #include "chrome/browser/ui/ash/multi_user/multi_user_notification_blocker_chrom eos.h"
17 #include "chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos.h"
18 #include "ui/wm/public/activation_client.h"
19
20 namespace chrome {
21
22 namespace {
23
24 // The animation time in milliseconds for the fade in and / or out when
25 // switching users.
26 const int kUserFadeTimeMS = 110;
27
28 // The minimal possible animation time for animations which should happen
29 // "instantly".
30 const int kMinimalAnimationTimeMS = 1;
31
32 // logic while the user gets switched.
33 class UserChangeActionDisabler {
34 public:
35 UserChangeActionDisabler() {
36 ash::WindowPositioner::DisableAutoPositioning(true);
37 ash::Shell::GetInstance()->mru_window_tracker()->SetIgnoreActivations(true);
38 }
39
40 ~UserChangeActionDisabler() {
41 ash::WindowPositioner::DisableAutoPositioning(false);
42 ash::Shell::GetInstance()->mru_window_tracker()->SetIgnoreActivations(
43 false);
44 }
45 private:
46
47 DISALLOW_COPY_AND_ASSIGN(UserChangeActionDisabler);
48 };
49
50 } // namespace
51
52 UserSwichAnimatorChromeOS::UserSwichAnimatorChromeOS(
53 MultiUserWindowManagerChromeOS* owner,
54 const std::string& new_user_id,
55 bool animation_disabled)
56 : owner_(owner),
57 new_user_id_(new_user_id),
58 animation_disabled_(animation_disabled),
59 animation_step_(ANIMATION_STEP_HIDE_OLD_USER),
60 screen_cover_(GetScreenCover()) {
61 AdvanceUserTransitionAnimation();
62
63 if (animation_disabled_) {
64 FinalizeAnimation();
65 } else {
66 user_changed_animation_timer_.reset(new base::Timer(
67 FROM_HERE,
68 base::TimeDelta::FromMilliseconds(kUserFadeTimeMS),
69 base::Bind(
70 &UserSwichAnimatorChromeOS::AdvanceUserTransitionAnimation,
71 base::Unretained(this)),
mtomasz 2014/04/08 18:35:09 Why Unretained? I believe we should have a weak pt
72 true));
73 user_changed_animation_timer_->Reset();
74 }
75 }
76
77 UserSwichAnimatorChromeOS::~UserSwichAnimatorChromeOS() {
78 FinalizeAnimation();
79 }
80
81 // static
82 bool UserSwichAnimatorChromeOS::CoversScreen(aura::Window* window) {
83 // Full screen covers the screen naturally. Since a normal window can have the
84 // same size as the work area, we only compare the bounds against the work
85 // area.
86 if (ash::wm::GetWindowState(window)->IsFullscreen())
87 return true;
88 gfx::Rect bounds = window->GetBoundsInRootWindow();
89 gfx::Rect work_area = gfx::Screen::GetScreenFor(window)->
90 GetDisplayNearestWindow(window).work_area();
91 bounds.Intersect(work_area);
92 return work_area == bounds;
93 }
94
95 void UserSwichAnimatorChromeOS::AdvanceUserTransitionAnimation() {
96 DCHECK_NE(animation_step_, ANIMATION_STEP_ENDED);
97
98 TransitionWallpaper(animation_step_);
99 TransitionUserShelf(animation_step_);
100 TransitionWindows(animation_step_);
101
102 // Advance to the next step.
103 switch (animation_step_) {
104 case ANIMATION_STEP_HIDE_OLD_USER:
105 animation_step_ = ANIMATION_STEP_SHOW_NEW_USER;
106 break;
107 case ANIMATION_STEP_SHOW_NEW_USER:
108 animation_step_ = ANIMATION_STEP_FINALIZE;
109 break;
110 case ANIMATION_STEP_FINALIZE:
111 user_changed_animation_timer_.reset();
112 animation_step_ = ANIMATION_STEP_ENDED;
113 break;
114 case ANIMATION_STEP_ENDED:
115 NOTREACHED();
116 break;
117 }
118 }
119
120 void UserSwichAnimatorChromeOS::FinalizeAnimation() {
121 user_changed_animation_timer_.reset();
122 while (ANIMATION_STEP_ENDED != animation_step_)
123 AdvanceUserTransitionAnimation();
124 }
125
126 void UserSwichAnimatorChromeOS::TransitionWallpaper(
127 AnimationStep animation_step) {
128 // Handle the wallpaper switch.
129 ash::UserWallpaperDelegate* wallpaper_delegate =
130 ash::Shell::GetInstance()->user_wallpaper_delegate();
131 if (animation_step == ANIMATION_STEP_HIDE_OLD_USER) {
132 // Set the wallpaper cross dissolve animation duration to our complete
133 // animation cycle for a fade in and fade out.
134 wallpaper_delegate->SetAnimationDurationOverride(
135 NO_USER_COVERS_SCREEN == screen_cover_ ? (2 * kUserFadeTimeMS) :
136 kMinimalAnimationTimeMS);
137 if (screen_cover_ != NEW_USER_COVERS_SCREEN) {
138 chromeos::WallpaperManager::Get()->SetUserWallpaperNow(new_user_id_);
139 wallpaper_user_id_ =
140 (NO_USER_COVERS_SCREEN == screen_cover_ ? "->" : "") +
141 new_user_id_;
142 }
143 } else if (animation_step == ANIMATION_STEP_FINALIZE) {
144 // Revert the wallpaper cross dissolve animation duration back to the
145 // default.
146 if (screen_cover_ == NEW_USER_COVERS_SCREEN)
147 chromeos::WallpaperManager::Get()->SetUserWallpaperNow(new_user_id_);
148
149 // Coming here the wallpaper user id is the final result. No matter how we
150 // got here.
151 wallpaper_user_id_ = new_user_id_;
152 wallpaper_delegate->SetAnimationDurationOverride(0);
153 }
154 }
155
156 void UserSwichAnimatorChromeOS::TransitionUserShelf(
157 AnimationStep animation_step) {
158 // The shelf animation duration override.
159 int duration_override = kUserFadeTimeMS;
160 // Handle the shelf order of items. This is done once the old user is hidden.
161 if (animation_step == ANIMATION_STEP_SHOW_NEW_USER) {
162 // Some unit tests have no ChromeLauncherController.
163 if (ChromeLauncherController::instance())
164 ChromeLauncherController::instance()->ActiveUserChanged(new_user_id_);
165 // We kicked off the shelf animation in the command above. As such we can
166 // disable the override now again.
167 duration_override = 0;
168 }
169
170 if (animation_disabled_ || animation_step == ANIMATION_STEP_FINALIZE)
171 return;
172
173 ash::Shell::RootWindowControllerList controller =
174 ash::Shell::GetInstance()->GetAllRootWindowControllers();
175 for (ash::Shell::RootWindowControllerList::iterator iter = controller.begin();
176 iter != controller.end(); ++iter) {
177 (*iter)->GetShelfLayoutManager()->SetAnimationDurationOverride(
178 duration_override);
179 }
180
181 // For each root window hide the shelf.
182 if (animation_step == ANIMATION_STEP_HIDE_OLD_USER) {
183 aura::Window::Windows root_windows = ash::Shell::GetAllRootWindows();
184 for (aura::Window::Windows::const_iterator iter = root_windows.begin();
185 iter != root_windows.end(); ++iter) {
186 // This shelf change is only part of the animation and will be updated by
187 // ChromeLauncherController::ActiveUserChanged() to the new users value.
188 // Note that the user perference will not be changed.
189 ash::Shell::GetInstance()->SetShelfAutoHideBehavior(
190 ash::SHELF_AUTO_HIDE_ALWAYS_HIDDEN, *iter);
191 }
192 }
193 }
194
195 void UserSwichAnimatorChromeOS::TransitionWindows(
196 AnimationStep animation_step) {
197 // Disable the window position manager and the MRU window tracker temporarily.
198 UserChangeActionDisabler disabler;
199
200 if (animation_step == ANIMATION_STEP_HIDE_OLD_USER ||
201 (animation_step == ANIMATION_STEP_FINALIZE &&
202 screen_cover_ == BOTH_USERS_COVER_SCREEN)) {
203 // We need to show/hide the windows in the same order as they were created
204 // in their parent window(s) to keep the layer / window hierarchy in sync.
205 // To achieve that we first collect all parent windows and then enumerate
206 // all windows in those parent windows and show or hide them accordingly.
207
208 // Create a list of all parent windows we have to check.
209 std::set<aura::Window*> parent_list;
210 for (MultiUserWindowManagerChromeOS::WindowToEntryMap::const_iterator it =
211 owner_->window_to_entry().begin();
212 it != owner_->window_to_entry().end(); ++it) {
213 aura::Window* parent = it->first->parent();
214 if (parent_list.find(parent) == parent_list.end())
215 parent_list.insert(parent);
216 }
217
218 for (std::set<aura::Window*>::iterator it_parents = parent_list.begin();
219 it_parents != parent_list.end(); ++it_parents) {
220 const aura::Window::Windows window_list = (*it_parents)->children();
221 // In case of |BOTH_USERS_COVER_SCREEN| the desktop might shine through
222 // if all windows fade (in or out). To avoid this we only fade the topmost
223 // covering window (in / out) and make / keep all other covering windows
224 // visible while animating. |foreground_window_found| will get set when
225 // the top fading window was found.
226 bool foreground_window_found = false;
227 // Covering windows which follow the fade direction will also fade - all
228 // others will get immediately shown / kept shown until the animation is
229 // finished.
230 bool foreground_becomes_visible = false;
231 for (aura::Window::Windows::const_reverse_iterator it_window =
232 window_list.rbegin();
233 it_window != window_list.rend(); ++it_window) {
234 aura::Window* window = *it_window;
235 MultiUserWindowManagerChromeOS::WindowToEntryMap::const_iterator
236 it_map = owner_->window_to_entry().find(window);
237 if (it_map != owner_->window_to_entry().end()) {
238 bool should_be_visible =
239 it_map->second->show_for_user() == new_user_id_ &&
240 it_map->second->show();
241 bool is_visible = window->IsVisible();
242 ash::wm::WindowState* window_state = ash::wm::GetWindowState(window);
243 if (it_map->second->owner() == new_user_id_ &&
244 it_map->second->show_for_user() != new_user_id_ &&
245 window_state->IsMinimized()) {
246 // Pull back minimized visiting windows to the owners desktop.
247 owner_->ShowWindowForUserIntern(window, new_user_id_);
248 window_state->Unminimize();
249 } else if (should_be_visible != is_visible) {
250 bool animate = true;
251 int duration = animation_step == ANIMATION_STEP_FINALIZE ?
252 kMinimalAnimationTimeMS : (2 * kUserFadeTimeMS);
253 if (animation_step != ANIMATION_STEP_FINALIZE &&
254 screen_cover_ == BOTH_USERS_COVER_SCREEN &&
255 CoversScreen(window)) {
256 if (!foreground_window_found) {
257 foreground_window_found = true;
258 foreground_becomes_visible = should_be_visible;
259 } else if (should_be_visible != foreground_becomes_visible) {
260 // Covering windows behind the foreground window which are
261 // inverting their visibility should immediately become visible
262 // or stay visible until the animation is finished.
263 duration = kMinimalAnimationTimeMS;
264 if (!should_be_visible)
265 animate = false;
266 }
267 }
268 if (animate)
269 owner_->SetWindowVisibility(window, should_be_visible, duration);
270 }
271 }
272 }
273 }
274 }
275
276 // Activation and real switch are happening after the other user gets shown.
277 if (animation_step == ANIMATION_STEP_SHOW_NEW_USER) {
278 // Finally we need to restore the previously active window.
279 ash::MruWindowTracker::WindowList mru_list =
280 ash::Shell::GetInstance()->mru_window_tracker()->BuildMruWindowList();
281 if (!mru_list.empty()) {
282 aura::Window* window = mru_list[0];
283 ash::wm::WindowState* window_state = ash::wm::GetWindowState(window);
284 if (owner_->IsWindowOnDesktopOfUser(window, new_user_id_) &&
285 !window_state->IsMinimized()) {
286 aura::client::ActivationClient* client =
287 aura::client::GetActivationClient(window->GetRootWindow());
288 // Several unit tests come here without an activation client.
289 if (client)
290 client->ActivateWindow(window);
291 }
292 }
293
294 // This is called directly here to make sure notification_blocker will see
295 // the new window status.
296 owner_->notification_blocker()->ActiveUserChanged(new_user_id_);
297 }
298 }
299
300 UserSwichAnimatorChromeOS::TransitioningScreenCover
301 UserSwichAnimatorChromeOS::GetScreenCover() {
302 TransitioningScreenCover cover = NO_USER_COVERS_SCREEN;
303 for (MultiUserWindowManagerChromeOS::WindowToEntryMap::const_iterator it_map =
304 owner_->window_to_entry().begin();
305 it_map != owner_->window_to_entry().end();
306 ++it_map) {
307 aura::Window* window = it_map->first;
308 if (window->IsVisible() && CoversScreen(window)) {
309 if (cover == NEW_USER_COVERS_SCREEN)
310 return BOTH_USERS_COVER_SCREEN;
311 else
312 cover = OLD_USER_COVERS_SCREEN;
313 } else if (owner_->IsWindowOnDesktopOfUser(window, new_user_id_) &&
314 CoversScreen(window)) {
315 if (cover == OLD_USER_COVERS_SCREEN)
316 return BOTH_USERS_COVER_SCREEN;
317 else
318 cover = NEW_USER_COVERS_SCREEN;
319 }
320 }
321 return cover;
322 }
323
324 } // namespace chrome
OLDNEW
« no previous file with comments | « chrome/browser/ui/ash/multi_user/user_switch_animator_chromeos.h ('k') | chrome/chrome_browser_ui.gypi » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698