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 "chrome/browser/ui/views/profiles/user_manager_view.h"
7 #include "base/memory/scoped_ptr.h"
8 #include "base/time/time.h"
9 #include "chrome/browser/browser_process.h"
10 #include "chrome/browser/lifetime/application_lifetime.h"
11 #include "chrome/browser/profiles/profile_avatar_icon_util.h"
12 #include "chrome/browser/profiles/profile_manager.h"
13 #include "chrome/browser/profiles/profile_metrics.h"
14 #include "chrome/browser/profiles/profile_window.h"
15 #include "chrome/browser/profiles/profiles_state.h"
16 #include "chrome/browser/signin/signin_promo.h"
17 #include "chrome/browser/ui/browser.h"
18 #include "chrome/browser/ui/browser_dialogs.h"
19 #include "chrome/browser/ui/browser_finder.h"
20 #include "chrome/browser/ui/browser_window.h"
21 #include "chrome/browser/ui/user_manager.h"
22 #include "chrome/browser/ui/views/auto_keep_alive.h"
23 #include "chrome/browser/ui/views/browser_dialogs.h"
24 #include "chrome/grit/chromium_strings.h"
25 #include "chrome/grit/generated_resources.h"
26 #include "components/guest_view/browser/guest_view_manager.h"
27 #include "content/public/browser/navigation_details.h"
28 #include "content/public/browser/render_widget_host_view.h"
29 #include "content/public/browser/web_contents.h"
30 #include "google_apis/gaia/gaia_urls.h"
31 #include "ui/base/l10n/l10n_util.h"
32 #include "ui/gfx/screen.h"
33 #include "ui/views/controls/webview/webview.h"
34 #include "ui/views/layout/fill_layout.h"
35 #include "ui/views/view.h"
36 #include "ui/views/widget/widget.h"
37 #include "ui/views/window/dialog_client_view.h"
38 #include "ui/views/window/dialog_delegate.h"
41 #include "chrome/browser/shell_integration.h"
42 #include "ui/base/win/shell.h"
43 #include "ui/views/win/hwnd_util.h"
47 #include "ash/shelf/shelf_util.h"
48 #include "ash/wm/window_util.h"
49 #include "grit/ash_resources.h"
54 // An open User Manager window. There can only be one open at a time. This
55 // is reset to NULL when the window is closed.
56 UserManagerView
* instance_
= NULL
;
57 bool instance_under_construction_
= false;
59 class ReauthDelegate
: public views::DialogDelegateView
,
60 public UserManager::ReauthDialogObserver
{
62 ReauthDelegate(views::WebView
* web_view
,
63 const std::string
& email_address
);
64 ~ReauthDelegate() override
{}
68 // views::DialogDelegate:
69 gfx::Size
GetPreferredSize() const override
;
70 bool CanResize() const override
;
71 bool CanMaximize() const override
;
72 bool CanMinimize() const override
;
73 bool UseNewStyleForThisDialog() const override
;
74 ui::ModalType
GetModalType() const override
;
75 void DeleteDelegate() override
;
76 base::string16
GetWindowTitle() const override
;
77 int GetDialogButtons() const override
;
79 // UserManager::ReauthObserver:
80 void CloseReauthDialog() override
;
82 views::WebView
* web_view_
;
83 const std::string email_address_
;
85 DISALLOW_COPY_AND_ASSIGN(ReauthDelegate
);
88 ReauthDelegate::ReauthDelegate(views::WebView
* web_view
,
89 const std::string
& email_address
)
90 : UserManager::ReauthDialogObserver(
91 web_view
->GetWebContents(), email_address
),
93 email_address_(email_address
) {
94 AddChildView(web_view_
);
95 SetLayoutManager(new views::FillLayout());
97 // Load the re-auth URL, prepopulated with the user's email address.
98 // Add the index of the profile to the URL so that the inline login page
99 // knows which profile to load and update the credentials.
100 GURL url
= signin::GetReauthURLWithEmail(email_address_
);
101 web_view_
->LoadInitialURL(url
);
104 gfx::Size
ReauthDelegate::GetPreferredSize() const {
105 return gfx::Size(UserManager::kReauthDialogWidth
,
106 UserManager::kReauthDialogHeight
);
109 bool ReauthDelegate::CanResize() const {
113 bool ReauthDelegate::CanMaximize() const {
117 bool ReauthDelegate::CanMinimize() const {
121 bool ReauthDelegate::UseNewStyleForThisDialog() const {
125 ui::ModalType
ReauthDelegate::GetModalType() const {
126 return ui::MODAL_TYPE_WINDOW
;
129 void ReauthDelegate::DeleteDelegate() {
133 base::string16
ReauthDelegate::GetWindowTitle() const {
134 return l10n_util::GetStringUTF16(IDS_PROFILES_GAIA_SIGNIN_TITLE
);
137 int ReauthDelegate::GetDialogButtons() const {
138 return ui::DIALOG_BUTTON_NONE
;
141 void ReauthDelegate::CloseReauthDialog() {
142 GetWidget()->Close();
147 // UserManager -----------------------------------------------------------------
150 void UserManager::Show(
151 const base::FilePath
& profile_path_to_focus
,
152 profiles::UserManagerTutorialMode tutorial_mode
,
153 profiles::UserManagerProfileSelected profile_open_action
) {
154 DCHECK(profile_path_to_focus
!= ProfileManager::GetGuestProfilePath());
156 ProfileMetrics::LogProfileOpenMethod(ProfileMetrics::OPEN_USER_MANAGER
);
158 // If we are showing the User Manager after locking a profile, change the
159 // active profile to Guest.
160 profiles::SetActiveProfileToGuestIfLocked();
162 // Note the time we started opening the User Manager.
163 instance_
->set_user_manager_started_showing(base::Time::Now());
165 // If there's a user manager window open already, just activate it.
166 instance_
->GetWidget()->Activate();
170 // Under some startup conditions, we can try twice to create the User Manager.
171 // Because creating the System profile is asynchronous, it's possible for
172 // there to then be multiple pending operations and eventually multiple
174 if (instance_under_construction_
)
177 // Create the system profile, if necessary, and open the user manager
178 // from the system profile.
179 UserManagerView
* user_manager
= new UserManagerView();
180 user_manager
->set_user_manager_started_showing(base::Time::Now());
181 profiles::CreateSystemProfileForUserManager(
182 profile_path_to_focus
,
185 base::Bind(&UserManagerView::OnSystemProfileCreated
,
186 base::Passed(make_scoped_ptr(user_manager
)),
187 base::Owned(new base::AutoReset
<bool>(
188 &instance_under_construction_
, true))));
192 void UserManager::Hide() {
194 instance_
->GetWidget()->Close();
198 bool UserManager::IsShowing() {
199 return instance_
? instance_
->GetWidget()->IsActive() : false;
203 void UserManager::OnUserManagerShown() {
205 instance_
->LogTimeToOpen();
209 void UserManager::ShowReauthDialog(content::BrowserContext
* browser_context
,
210 const std::string
& email
) {
211 // This method should only be called if the user manager is already showing.
215 // The dialog delegate will be deleted when the dialog closes and the created
216 // WebView's lifetime is managed by the delegate.
217 views::DialogDelegate
* delegate
=
218 new ReauthDelegate(new views::WebView(browser_context
), email
);
219 gfx::NativeView parent
= instance_
->GetWidget()->GetNativeView();
220 views::DialogDelegate::CreateDialogWidget(delegate
, nullptr, parent
);
221 delegate
->GetWidget()->Show();
224 // UserManagerView -------------------------------------------------------------
226 UserManagerView::UserManagerView()
228 keep_alive_(new AutoKeepAlive(NULL
)),
229 user_manager_started_showing_(base::Time()) {
232 UserManagerView::~UserManagerView() {
236 void UserManagerView::OnSystemProfileCreated(
237 scoped_ptr
<UserManagerView
> instance
,
238 base::AutoReset
<bool>* pending
,
239 Profile
* system_profile
,
240 const std::string
& url
) {
241 // If we are showing the User Manager after locking a profile, change the
242 // active profile to Guest.
243 profiles::SetActiveProfileToGuestIfLocked();
246 instance_
= instance
.release(); // |instance_| takes over ownership.
247 instance_
->Init(system_profile
, GURL(url
));
250 void UserManagerView::Init(Profile
* system_profile
, const GURL
& url
) {
251 web_view_
= new views::WebView(system_profile
);
252 web_view_
->set_allow_accelerators(true);
253 AddChildView(web_view_
);
254 SetLayoutManager(new views::FillLayout
);
255 AddAccelerator(ui::Accelerator(ui::VKEY_W
, ui::EF_CONTROL_DOWN
));
256 AddAccelerator(ui::Accelerator(ui::VKEY_F4
, ui::EF_ALT_DOWN
));
258 // If the user manager is being displayed from an existing profile, use
259 // its last active browser to determine where the user manager should be
260 // placed. This is used so that we can center the dialog on the correct
261 // monitor in a multiple-monitor setup.
263 // If the last active profile is empty (for example, starting up chrome
264 // when all existing profiles are locked), not loaded (for example, if guest
265 // was set after locking the only open profile) or we can't find an active
266 // browser, bounds will remain empty and the user manager will be centered on
267 // the default monitor by default.
269 // Note the profile is accessed via GetProfileByPath(GetLastUsedProfileDir())
270 // instead of GetLastUsedProfile(). If the last active profile isn't loaded,
271 // the latter may try to synchronously load it, which can only be done on a
272 // thread where disk IO is allowed.
274 ProfileManager
* profile_manager
= g_browser_process
->profile_manager();
275 const base::FilePath
& last_used_profile_path
=
276 profile_manager
->GetLastUsedProfileDir(profile_manager
->user_data_dir());
277 Profile
* profile
= profile_manager
->GetProfileByPath(last_used_profile_path
);
279 Browser
* browser
= chrome::FindLastActiveWithProfile(profile
,
280 chrome::GetActiveDesktop());
282 gfx::NativeView native_view
=
283 views::Widget::GetWidgetForNativeWindow(
284 browser
->window()->GetNativeWindow())->GetNativeView();
285 bounds
= gfx::Screen::GetScreenFor(native_view
)->
286 GetDisplayNearestWindow(native_view
).work_area();
287 bounds
.ClampToCenteredSize(gfx::Size(UserManager::kWindowWidth
,
288 UserManager::kWindowHeight
));
292 DialogDelegate::CreateDialogWidgetWithBounds(this, NULL
, NULL
, bounds
);
294 // Since the User Manager can be the only top level window, we don't
295 // want to accidentally quit all of Chrome if the user is just trying to
296 // unfocus the selected pod in the WebView.
297 GetDialogClientView()->RemoveAccelerator(
298 ui::Accelerator(ui::VKEY_ESCAPE
, ui::EF_NONE
));
301 // Set the app id for the task manager to the app id of its parent
302 ui::win::SetAppIdForWindow(
303 ShellIntegration::GetChromiumModelIdForProfile(
304 system_profile
->GetPath()),
305 views::HWNDForWidget(GetWidget()));
309 gfx::NativeWindow native_window
= GetWidget()->GetNativeWindow();
310 ash::SetShelfItemDetailsForDialogWindow(
311 native_window
, IDR_ASH_SHELF_LIST_BROWSER
, native_window
->title());
314 web_view_
->LoadInitialURL(url
);
315 content::RenderWidgetHostView
* rwhv
=
316 web_view_
->GetWebContents()->GetRenderWidgetHostView();
318 rwhv
->SetBackgroundColor(profiles::kUserManagerBackgroundColor
);
321 web_view_
->RequestFocus();
324 void UserManagerView::LogTimeToOpen() {
325 if (user_manager_started_showing_
== base::Time())
328 ProfileMetrics::LogTimeToOpenUserManager(
329 base::Time::Now() - user_manager_started_showing_
);
330 user_manager_started_showing_
= base::Time();
333 bool UserManagerView::AcceleratorPressed(const ui::Accelerator
& accelerator
) {
334 int key
= accelerator
.key_code();
335 int modifier
= accelerator
.modifiers();
336 DCHECK((key
== ui::VKEY_W
&& modifier
== ui::EF_CONTROL_DOWN
) ||
337 (key
== ui::VKEY_F4
&& modifier
== ui::EF_ALT_DOWN
));
338 GetWidget()->Close();
342 gfx::Size
UserManagerView::GetPreferredSize() const {
343 return gfx::Size(UserManager::kWindowWidth
, UserManager::kWindowHeight
);
346 bool UserManagerView::CanResize() const {
350 bool UserManagerView::CanMaximize() const {
354 bool UserManagerView::CanMinimize() const {
358 base::string16
UserManagerView::GetWindowTitle() const {
359 return l10n_util::GetStringUTF16(IDS_PRODUCT_NAME
);
362 int UserManagerView::GetDialogButtons() const {
363 return ui::DIALOG_BUTTON_NONE
;
366 void UserManagerView::WindowClosing() {
367 // Now that the window is closed, we can allow a new one to be opened.
368 // (WindowClosing comes in asynchronously from the call to Close() and we
369 // may have already opened a new instance).
370 if (instance_
== this)
374 bool UserManagerView::UseNewStyleForThisDialog() const {