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 "chrome/browser/chromeos/input_method/browser_state_monitor.h"
6
7#include "base/logging.h"
8#include "chrome/browser/chrome_notification_types.h"
9#include "chrome/browser/chromeos/input_method/input_method_util.h"
10#include "chromeos/ime/input_method_delegate.h"
11#include "content/public/browser/notification_service.h"
12
13namespace chromeos {
14namespace input_method {
15
16BrowserStateMonitor::BrowserStateMonitor(
17    const base::Callback<void(InputMethodManager::UISessionState)>& observer)
18    : observer_(observer), ui_session_(InputMethodManager::STATE_LOGIN_SCREEN) {
19  notification_registrar_.Add(this,
20                              chrome::NOTIFICATION_LOGIN_USER_CHANGED,
21                              content::NotificationService::AllSources());
22  notification_registrar_.Add(this,
23                              chrome::NOTIFICATION_SESSION_STARTED,
24                              content::NotificationService::AllSources());
25  notification_registrar_.Add(this,
26                              chrome::NOTIFICATION_SCREEN_LOCK_STATE_CHANGED,
27                              content::NotificationService::AllSources());
28  // We should not use ALL_BROWSERS_CLOSING here since logout might be cancelled
29  // by JavaScript after ALL_BROWSERS_CLOSING is sent (crosbug.com/11055).
30  notification_registrar_.Add(this,
31                              chrome::NOTIFICATION_APP_TERMINATING,
32                              content::NotificationService::AllSources());
33
34  if (!observer_.is_null())
35    observer_.Run(ui_session_);
36}
37
38BrowserStateMonitor::~BrowserStateMonitor() {
39}
40
41void BrowserStateMonitor::Observe(
42    int type,
43    const content::NotificationSource& source,
44    const content::NotificationDetails& details) {
45  const InputMethodManager::UISessionState old_ui_session = ui_session_;
46  switch (type) {
47    case chrome::NOTIFICATION_APP_TERMINATING: {
48      ui_session_ = InputMethodManager::STATE_TERMINATING;
49      break;
50    }
51    case chrome::NOTIFICATION_LOGIN_USER_CHANGED: {
52      // The user logged in, but the browser window for user session is not yet
53      // ready. An initial input method hasn't been set to the manager.
54      // Note that the notification is also sent when Chrome crashes/restarts
55      // as of writing, but it might be changed in the future (therefore we need
56      // to listen to NOTIFICATION_SESSION_STARTED as well.)
57      DVLOG(1) << "Received chrome::NOTIFICATION_LOGIN_USER_CHANGED";
58      ui_session_ = InputMethodManager::STATE_BROWSER_SCREEN;
59      break;
60    }
61    case chrome::NOTIFICATION_SESSION_STARTED: {
62      // The user logged in, and the browser window for user session is ready.
63      // An initial input method has already been set.
64      // We should NOT call InitializePrefMembers() here since the notification
65      // is sent in the PreProfileInit phase in case when Chrome crashes and
66      // restarts.
67      DVLOG(1) << "Received chrome::NOTIFICATION_SESSION_STARTED";
68      ui_session_ = InputMethodManager::STATE_BROWSER_SCREEN;
69      break;
70    }
71    case chrome::NOTIFICATION_SCREEN_LOCK_STATE_CHANGED: {
72      const bool is_screen_locked = *content::Details<bool>(details).ptr();
73      ui_session_ = is_screen_locked ? InputMethodManager::STATE_LOCK_SCREEN
74                                     : InputMethodManager::STATE_BROWSER_SCREEN;
75      break;
76    }
77    default: {
78      NOTREACHED();
79      break;
80    }
81  }
82
83  if (old_ui_session != ui_session_ && !observer_.is_null())
84    observer_.Run(ui_session_);
85
86  // Note: browser notifications are sent in the following order.
87  //
88  // Normal login:
89  // 1. chrome::NOTIFICATION_LOGIN_USER_CHANGED is sent.
90  // 2. Preferences::NotifyPrefChanged() is called. preload_engines (which
91  //    might change the current input method) and current/previous input method
92  //    are sent to the manager.
93  // 3. chrome::NOTIFICATION_SESSION_STARTED is sent.
94  //
95  // Chrome crash/restart (after logging in):
96  // 1. chrome::NOTIFICATION_LOGIN_USER_CHANGED might be sent.
97  // 2. chrome::NOTIFICATION_SESSION_STARTED is sent.
98  // 3. Preferences::NotifyPrefChanged() is called. The same things as above
99  //    happen.
100  //
101  // We have to be careful not to overwrite both local and user prefs when
102  // preloaded engine is set. Note that it does not work to do nothing in
103  // InputMethodChanged() between chrome::NOTIFICATION_LOGIN_USER_CHANGED and
104  // chrome::NOTIFICATION_SESSION_STARTED because SESSION_STARTED is sent very
105  // early on Chrome crash/restart.
106}
107
108}  // namespace input_method
109}  // namespace chromeos
110