cloud_print_proxy_service.cc revision 0f1bc08d4cfcc34181b0b5cbf065c40f687bf740
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/printing/cloud_print/cloud_print_proxy_service.h"
6
7#include <stack>
8#include <vector>
9
10#include "base/bind.h"
11#include "base/bind_helpers.h"
12#include "base/command_line.h"
13#include "base/file_util.h"
14#include "base/json/json_reader.h"
15#include "base/message_loop/message_loop.h"
16#include "base/metrics/histogram.h"
17#include "base/prefs/pref_service.h"
18#include "base/strings/utf_string_conversions.h"
19#include "chrome/browser/browser_process.h"
20#include "chrome/browser/chrome_notification_types.h"
21#include "chrome/browser/lifetime/application_lifetime.h"
22#include "chrome/browser/notifications/desktop_notification_service.h"
23#include "chrome/browser/notifications/notification.h"
24#include "chrome/browser/notifications/notification_ui_manager.h"
25#include "chrome/browser/profiles/profile.h"
26#include "chrome/browser/service/service_process_control.h"
27#include "chrome/common/chrome_switches.h"
28#include "chrome/common/cloud_print/cloud_print_proxy_info.h"
29#include "chrome/common/pref_names.h"
30#include "chrome/common/service_messages.h"
31#include "content/public/browser/browser_thread.h"
32#include "grit/generated_resources.h"
33#include "printing/backend/print_backend.h"
34#include "ui/base/l10n/l10n_util.h"
35
36using content::BrowserThread;
37
38CloudPrintProxyService::CloudPrintProxyService(Profile* profile)
39    : profile_(profile),
40      weak_factory_(this),
41      enforcing_connector_policy_(false) {
42}
43
44CloudPrintProxyService::~CloudPrintProxyService() {
45}
46
47void CloudPrintProxyService::Initialize() {
48  UMA_HISTOGRAM_ENUMERATION("CloudPrint.ServiceEvents",
49                            ServiceProcessControl::SERVICE_EVENT_INITIALIZE,
50                            ServiceProcessControl::SERVICE_EVENT_MAX);
51  if (profile_->GetPrefs()->HasPrefPath(prefs::kCloudPrintEmail) &&
52      (!profile_->GetPrefs()->GetString(prefs::kCloudPrintEmail).empty() ||
53       !profile_->GetPrefs()->GetBoolean(prefs::kCloudPrintProxyEnabled))) {
54    // If the cloud print proxy is enabled, or the policy preventing it from
55    // being enabled is set, establish a channel with the service process and
56    // update the status. This will check the policy when the status is sent
57    // back.
58    UMA_HISTOGRAM_ENUMERATION(
59        "CloudPrint.ServiceEvents",
60        ServiceProcessControl::SERVICE_EVENT_ENABLED_ON_LAUNCH,
61        ServiceProcessControl::SERVICE_EVENT_MAX);
62    RefreshStatusFromService();
63  }
64
65  pref_change_registrar_.Init(profile_->GetPrefs());
66  pref_change_registrar_.Add(
67      prefs::kCloudPrintProxyEnabled,
68      base::Bind(
69          base::IgnoreResult(
70              &CloudPrintProxyService::ApplyCloudPrintConnectorPolicy),
71          base::Unretained(this)));
72}
73
74void CloudPrintProxyService::RefreshStatusFromService() {
75  InvokeServiceTask(
76      base::Bind(&CloudPrintProxyService::RefreshCloudPrintProxyStatus,
77                 weak_factory_.GetWeakPtr()));
78}
79
80bool CloudPrintProxyService::EnforceCloudPrintConnectorPolicyAndQuit() {
81  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
82  enforcing_connector_policy_ = true;
83  if (ApplyCloudPrintConnectorPolicy())
84    return true;
85  return false;
86}
87
88void CloudPrintProxyService::EnableForUserWithRobot(
89    const std::string& robot_auth_code,
90    const std::string& robot_email,
91    const std::string& user_email,
92    const base::DictionaryValue& user_preferences) {
93  UMA_HISTOGRAM_ENUMERATION("CloudPrint.ServiceEvents",
94                            ServiceProcessControl::SERVICE_EVENT_ENABLE,
95                            ServiceProcessControl::SERVICE_EVENT_MAX);
96  if (profile_->GetPrefs()->GetBoolean(prefs::kCloudPrintProxyEnabled)) {
97    InvokeServiceTask(
98        base::Bind(&CloudPrintProxyService::EnableCloudPrintProxyWithRobot,
99                   weak_factory_.GetWeakPtr(), robot_auth_code, robot_email,
100                   user_email, base::Owned(user_preferences.DeepCopy())));
101  }
102}
103
104void CloudPrintProxyService::DisableForUser() {
105  UMA_HISTOGRAM_ENUMERATION("CloudPrint.ServiceEvents",
106                            ServiceProcessControl::SERVICE_EVENT_DISABLE,
107                            ServiceProcessControl::SERVICE_EVENT_MAX);
108  InvokeServiceTask(
109      base::Bind(&CloudPrintProxyService::DisableCloudPrintProxy,
110                 weak_factory_.GetWeakPtr()));
111}
112
113bool CloudPrintProxyService::ApplyCloudPrintConnectorPolicy() {
114  if (!profile_->GetPrefs()->GetBoolean(prefs::kCloudPrintProxyEnabled)) {
115    std::string email =
116        profile_->GetPrefs()->GetString(prefs::kCloudPrintEmail);
117    if (!email.empty()) {
118      UMA_HISTOGRAM_ENUMERATION(
119          "CloudPrint.ServiceEvents",
120          ServiceProcessControl::SERVICE_EVENT_DISABLE_BY_POLICY,
121          ServiceProcessControl::SERVICE_EVENT_MAX);
122      DisableForUser();
123      profile_->GetPrefs()->SetString(prefs::kCloudPrintEmail, std::string());
124      if (enforcing_connector_policy_) {
125        base::MessageLoop::current()->PostTask(
126            FROM_HERE,
127            base::Bind(&CloudPrintProxyService::RefreshCloudPrintProxyStatus,
128                       weak_factory_.GetWeakPtr()));
129      }
130      return false;
131    } else if (enforcing_connector_policy_) {
132      base::MessageLoop::current()->PostTask(FROM_HERE,
133                                             base::MessageLoop::QuitClosure());
134    }
135  }
136  return true;
137}
138
139void CloudPrintProxyService::GetPrintersAvalibleForRegistration(
140      std::vector<std::string>* printers) {
141  base::FilePath list_path(
142      CommandLine::ForCurrentProcess()->GetSwitchValuePath(
143          switches::kCloudPrintSetupProxy));
144  if (!list_path.empty()) {
145    std::string printers_json;
146    base::ReadFileToString(list_path, &printers_json);
147    scoped_ptr<Value> value(base::JSONReader::Read(printers_json));
148    base::ListValue* list = NULL;
149    if (value && value->GetAsList(&list) && list) {
150      for (size_t i = 0; i < list->GetSize(); ++i) {
151        std::string printer;
152        if (list->GetString(i, &printer))
153          printers->push_back(printer);
154      }
155    }
156    UMA_HISTOGRAM_COUNTS_10000("CloudPrint.AvailablePrintersList",
157                               printers->size());
158  } else {
159    printing::PrinterList printer_list;
160    scoped_refptr<printing::PrintBackend> backend(
161        printing::PrintBackend::CreateInstance(NULL));
162    if (backend.get())
163      backend->EnumeratePrinters(&printer_list);
164    for (size_t i = 0; i < printer_list.size(); ++i)
165      printers->push_back(printer_list[i].printer_name);
166    UMA_HISTOGRAM_COUNTS_10000("CloudPrint.AvailablePrinters",
167                               printers->size());
168  }
169}
170
171void CloudPrintProxyService::RefreshCloudPrintProxyStatus() {
172  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
173  ServiceProcessControl* process_control = GetServiceProcessControl();
174  DCHECK(process_control->IsConnected());
175  ServiceProcessControl::CloudPrintProxyInfoHandler callback =
176       base::Bind(&CloudPrintProxyService::ProxyInfoCallback,
177                  base::Unretained(this));
178  // GetCloudPrintProxyInfo takes ownership of callback.
179  process_control->GetCloudPrintProxyInfo(callback);
180}
181
182void CloudPrintProxyService::EnableCloudPrintProxyWithRobot(
183    const std::string& robot_auth_code,
184    const std::string& robot_email,
185    const std::string& user_email,
186    const base::DictionaryValue* user_preferences) {
187  ServiceProcessControl* process_control = GetServiceProcessControl();
188  DCHECK(process_control->IsConnected());
189  process_control->Send(
190      new ServiceMsg_EnableCloudPrintProxyWithRobot(
191          robot_auth_code, robot_email, user_email, *user_preferences));
192  // Assume the IPC worked.
193  profile_->GetPrefs()->SetString(prefs::kCloudPrintEmail, user_email);
194}
195
196void CloudPrintProxyService::DisableCloudPrintProxy() {
197  ServiceProcessControl* process_control = GetServiceProcessControl();
198  DCHECK(process_control->IsConnected());
199  process_control->Send(new ServiceMsg_DisableCloudPrintProxy);
200  // Assume the IPC worked.
201  profile_->GetPrefs()->SetString(prefs::kCloudPrintEmail, std::string());
202}
203
204void CloudPrintProxyService::ProxyInfoCallback(
205    const cloud_print::CloudPrintProxyInfo& proxy_info) {
206  proxy_id_ = proxy_info.proxy_id;
207  profile_->GetPrefs()->SetString(
208      prefs::kCloudPrintEmail,
209      proxy_info.enabled ? proxy_info.email : std::string());
210  ApplyCloudPrintConnectorPolicy();
211}
212
213bool CloudPrintProxyService::InvokeServiceTask(const base::Closure& task) {
214  GetServiceProcessControl()->Launch(task, base::Closure());
215  return true;
216}
217
218ServiceProcessControl* CloudPrintProxyService::GetServiceProcessControl() {
219  return ServiceProcessControl::GetInstance();
220}
221