1// Copyright (c) 2011 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/printing/cloud_print/cloud_print_proxy_service.h"
6
7#include <stack>
8#include <vector>
9
10#include "base/utf_string_conversions.h"
11#include "chrome/browser/browser_process.h"
12#include "chrome/browser/notifications/desktop_notification_service.h"
13#include "chrome/browser/notifications/notification.h"
14#include "chrome/browser/notifications/notification_ui_manager.h"
15#include "chrome/browser/prefs/pref_service.h"
16#include "chrome/browser/printing/cloud_print/cloud_print_setup_flow.h"
17#include "chrome/browser/profiles/profile.h"
18#include "chrome/browser/service/service_process_control.h"
19#include "chrome/browser/service/service_process_control_manager.h"
20#include "chrome/browser/ui/browser_list.h"
21#include "chrome/common/pref_names.h"
22#include "chrome/common/service_messages.h"
23#include "content/browser/browser_thread.h"
24#include "grit/generated_resources.h"
25#include "ui/base/l10n/l10n_util.h"
26
27// TODO(sanjeevr): Localize the product name?
28const char kCloudPrintProductName[] = "Google Cloud Print";
29
30class CloudPrintProxyService::TokenExpiredNotificationDelegate
31    : public NotificationDelegate {
32 public:
33  explicit TokenExpiredNotificationDelegate(
34      CloudPrintProxyService* cloud_print_service)
35          : cloud_print_service_(cloud_print_service) {
36  }
37  void Display() {}
38  void Error() {
39    cloud_print_service_->OnTokenExpiredNotificationError();
40  }
41  void Close(bool by_user) {
42    cloud_print_service_->OnTokenExpiredNotificationClosed(by_user);
43  }
44  void Click() {
45    cloud_print_service_->OnTokenExpiredNotificationClick();
46  }
47  std::string id() const { return "cloudprint.tokenexpired"; }
48
49 private:
50  CloudPrintProxyService* cloud_print_service_;
51  DISALLOW_COPY_AND_ASSIGN(TokenExpiredNotificationDelegate);
52};
53
54CloudPrintProxyService::CloudPrintProxyService(Profile* profile)
55    : profile_(profile), token_expired_delegate_(NULL) {
56}
57
58CloudPrintProxyService::~CloudPrintProxyService() {
59}
60
61void CloudPrintProxyService::Initialize() {
62  if (profile_->GetPrefs()->HasPrefPath(prefs::kCloudPrintEmail) &&
63      !profile_->GetPrefs()->GetString(prefs::kCloudPrintEmail).empty()) {
64    // If the cloud print proxy is enabled, establish a channel with the
65    // service process and update the status.
66    RefreshStatusFromService();
67  }
68}
69
70void CloudPrintProxyService::RefreshStatusFromService() {
71  InvokeServiceTask(
72      NewRunnableMethod(
73          this, &CloudPrintProxyService::RefreshCloudPrintProxyStatus));
74}
75
76void CloudPrintProxyService::EnableForUser(const std::string& lsid,
77                                           const std::string& email) {
78  InvokeServiceTask(
79      NewRunnableMethod(
80          this, &CloudPrintProxyService::EnableCloudPrintProxy, lsid, email));
81}
82
83void CloudPrintProxyService::DisableForUser() {
84  InvokeServiceTask(
85      NewRunnableMethod(
86          this, &CloudPrintProxyService::DisableCloudPrintProxy));
87}
88
89bool CloudPrintProxyService::ShowTokenExpiredNotification() {
90  // If we already have a pending notification, don't show another one.
91  if (token_expired_delegate_.get())
92    return false;
93
94  // TODO(sanjeevr): Get icon for this notification.
95  GURL icon_url;
96
97  string16 title = UTF8ToUTF16(kCloudPrintProductName);
98  string16 message =
99      l10n_util::GetStringUTF16(IDS_CLOUD_PRINT_TOKEN_EXPIRED_MESSAGE);
100  string16 content_url = DesktopNotificationService::CreateDataUrl(
101      icon_url, title, message, WebKit::WebTextDirectionDefault);
102  token_expired_delegate_ = new TokenExpiredNotificationDelegate(this);
103  Notification notification(GURL(), GURL(content_url), string16(), string16(),
104                            token_expired_delegate_.get());
105  g_browser_process->notification_ui_manager()->Add(notification, profile_);
106  // Keep the browser alive while we are showing the notification.
107  BrowserList::StartKeepAlive();
108  return true;
109}
110
111void CloudPrintProxyService::OnTokenExpiredNotificationError() {
112  TokenExpiredNotificationDone(false);
113}
114
115void CloudPrintProxyService::OnTokenExpiredNotificationClosed(bool by_user) {
116  TokenExpiredNotificationDone(false);
117}
118
119void CloudPrintProxyService::OnTokenExpiredNotificationClick() {
120  TokenExpiredNotificationDone(true);
121  // Clear the cached cloud print email pref so that the cloud print setup
122  // flow happens.
123  profile_->GetPrefs()->SetString(prefs::kCloudPrintEmail, std::string());
124  cloud_print_setup_handler_.reset(new CloudPrintSetupHandler(this));
125  CloudPrintSetupFlow::OpenDialog(
126      profile_, cloud_print_setup_handler_->AsWeakPtr(), NULL);
127}
128
129void CloudPrintProxyService::TokenExpiredNotificationDone(bool keep_alive) {
130  if (token_expired_delegate_.get()) {
131    g_browser_process->notification_ui_manager()->CancelById(
132        token_expired_delegate_->id());
133    token_expired_delegate_ = NULL;
134    if (!keep_alive)
135      BrowserList::EndKeepAlive();
136  }
137}
138
139void CloudPrintProxyService::OnCloudPrintSetupClosed() {
140  MessageLoop::current()->PostTask(
141      FROM_HERE, NewRunnableFunction(&BrowserList::EndKeepAlive));
142}
143
144void CloudPrintProxyService::RefreshCloudPrintProxyStatus() {
145  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
146  ServiceProcessControl* process_control =
147      ServiceProcessControlManager::GetInstance()->GetProcessControl(profile_);
148  DCHECK(process_control->is_connected());
149  Callback2<bool, std::string>::Type* callback =
150       NewCallback(this, &CloudPrintProxyService::StatusCallback);
151  // GetCloudPrintProxyStatus takes ownership of callback.
152  process_control->GetCloudPrintProxyStatus(callback);
153}
154
155void CloudPrintProxyService::EnableCloudPrintProxy(const std::string& lsid,
156                                                   const std::string& email) {
157  ServiceProcessControl* process_control =
158      ServiceProcessControlManager::GetInstance()->GetProcessControl(profile_);
159  DCHECK(process_control->is_connected());
160  process_control->Send(new ServiceMsg_EnableCloudPrintProxy(lsid));
161  // Assume the IPC worked.
162  profile_->GetPrefs()->SetString(prefs::kCloudPrintEmail, email);
163}
164
165void CloudPrintProxyService::DisableCloudPrintProxy() {
166  ServiceProcessControl* process_control =
167      ServiceProcessControlManager::GetInstance()->GetProcessControl(profile_);
168  DCHECK(process_control->is_connected());
169  process_control->Send(new ServiceMsg_DisableCloudPrintProxy);
170  // Assume the IPC worked.
171  profile_->GetPrefs()->SetString(prefs::kCloudPrintEmail, std::string());
172}
173
174void CloudPrintProxyService::StatusCallback(bool enabled, std::string email) {
175  profile_->GetPrefs()->SetString(prefs::kCloudPrintEmail,
176                                  enabled ? email : std::string());
177}
178
179bool CloudPrintProxyService::InvokeServiceTask(Task* task) {
180  ServiceProcessControl* process_control =
181      ServiceProcessControlManager::GetInstance()->GetProcessControl(profile_);
182  DCHECK(process_control);
183  if (process_control)
184    process_control->Launch(task, NULL);
185  return !!process_control;
186}
187