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/sync/glue/device_info.h"
6
7#include "base/command_line.h"
8#include "base/threading/sequenced_worker_pool.h"
9#include "base/values.h"
10#include "chrome/common/chrome_version_info.h"
11#include "chrome/common/chrome_switches.h"
12#include "content/public/browser/browser_thread.h"
13#include "sync/util/get_session_name.h"
14#include "ui/base/device_form_factor.h"
15
16namespace browser_sync {
17
18namespace {
19
20#if defined(OS_ANDROID)
21bool IsTabletUI() {
22  return ui::GetDeviceFormFactor() == ui::DEVICE_FORM_FACTOR_TABLET;
23}
24#endif
25
26// Converts VersionInfo::Channel to string for user-agent string.
27std::string ChannelToString(chrome::VersionInfo::Channel channel) {
28  switch (channel) {
29    case chrome::VersionInfo::CHANNEL_UNKNOWN:
30      return "unknown";
31    case chrome::VersionInfo::CHANNEL_CANARY:
32      return "canary";
33    case chrome::VersionInfo::CHANNEL_DEV:
34      return "dev";
35    case chrome::VersionInfo::CHANNEL_BETA:
36      return "beta";
37    case chrome::VersionInfo::CHANNEL_STABLE:
38      return "stable";
39    default:
40      NOTREACHED();
41      return "unknown";
42  };
43}
44
45}  // namespace
46
47DeviceInfo::DeviceInfo(const std::string& guid,
48                       const std::string& client_name,
49                       const std::string& chrome_version,
50                       const std::string& sync_user_agent,
51                       const sync_pb::SyncEnums::DeviceType device_type)
52    : guid_(guid),
53      client_name_(client_name),
54      chrome_version_(chrome_version),
55      sync_user_agent_(sync_user_agent),
56      device_type_(device_type) {
57}
58
59DeviceInfo::~DeviceInfo() { }
60
61const std::string& DeviceInfo::guid() const {
62  return guid_;
63}
64
65const std::string& DeviceInfo::client_name() const {
66  return client_name_;
67}
68
69const std::string& DeviceInfo::chrome_version() const {
70  return chrome_version_;
71}
72
73const std::string& DeviceInfo::sync_user_agent() const {
74  return sync_user_agent_;
75}
76
77const std::string& DeviceInfo::public_id() const {
78  return public_id_;
79}
80
81sync_pb::SyncEnums::DeviceType DeviceInfo::device_type() const {
82  return device_type_;
83}
84
85std::string DeviceInfo::GetOSString() const {
86  switch (device_type_) {
87    case sync_pb::SyncEnums_DeviceType_TYPE_WIN:
88      return "win";
89    case sync_pb::SyncEnums_DeviceType_TYPE_MAC:
90      return "mac";
91    case sync_pb::SyncEnums_DeviceType_TYPE_LINUX:
92      return "linux";
93    case sync_pb::SyncEnums_DeviceType_TYPE_CROS:
94      return "chrome_os";
95    case sync_pb::SyncEnums_DeviceType_TYPE_PHONE:
96    case sync_pb::SyncEnums_DeviceType_TYPE_TABLET:
97      // TODO(lipalani): crbug.com/170375. Add support for ios
98      // phones and tablets.
99      return "android";
100    default:
101      return "unknown";
102  }
103}
104
105std::string DeviceInfo::GetDeviceTypeString() const {
106  switch (device_type_) {
107    case sync_pb::SyncEnums_DeviceType_TYPE_WIN:
108    case sync_pb::SyncEnums_DeviceType_TYPE_MAC:
109    case sync_pb::SyncEnums_DeviceType_TYPE_LINUX:
110    case sync_pb::SyncEnums_DeviceType_TYPE_CROS:
111      return "desktop_or_laptop";
112    case sync_pb::SyncEnums_DeviceType_TYPE_PHONE:
113      return "phone";
114    case sync_pb::SyncEnums_DeviceType_TYPE_TABLET:
115      return "tablet";
116    default:
117      return "unknown";
118  }
119}
120
121bool DeviceInfo::Equals(const DeviceInfo& other) const {
122  return this->guid() == other.guid()
123      && this->client_name() == other.client_name()
124      && this->chrome_version() == other.chrome_version()
125      && this->sync_user_agent() == other.sync_user_agent()
126      && this->device_type() == other.device_type();
127}
128
129// static.
130sync_pb::SyncEnums::DeviceType DeviceInfo::GetLocalDeviceType() {
131#if defined(OS_CHROMEOS)
132  return sync_pb::SyncEnums_DeviceType_TYPE_CROS;
133#elif defined(OS_LINUX)
134  return sync_pb::SyncEnums_DeviceType_TYPE_LINUX;
135#elif defined(OS_MACOSX)
136  return sync_pb::SyncEnums_DeviceType_TYPE_MAC;
137#elif defined(OS_WIN)
138  return sync_pb::SyncEnums_DeviceType_TYPE_WIN;
139#elif defined(OS_ANDROID)
140  return IsTabletUI() ?
141      sync_pb::SyncEnums_DeviceType_TYPE_TABLET :
142      sync_pb::SyncEnums_DeviceType_TYPE_PHONE;
143#else
144  return sync_pb::SyncEnums_DeviceType_TYPE_OTHER;
145#endif
146}
147
148// static
149std::string DeviceInfo::MakeUserAgentForSyncApi(
150    const chrome::VersionInfo& version_info) {
151  std::string user_agent;
152  user_agent = "Chrome ";
153#if defined(OS_WIN)
154  user_agent += "WIN ";
155#elif defined(OS_CHROMEOS)
156  user_agent += "CROS ";
157#elif defined(OS_ANDROID)
158  if (IsTabletUI())
159    user_agent += "ANDROID-TABLET ";
160  else
161    user_agent += "ANDROID-PHONE ";
162#elif defined(OS_LINUX)
163  user_agent += "LINUX ";
164#elif defined(OS_FREEBSD)
165  user_agent += "FREEBSD ";
166#elif defined(OS_OPENBSD)
167  user_agent += "OPENBSD ";
168#elif defined(OS_MACOSX)
169  user_agent += "MAC ";
170#endif
171  if (!version_info.is_valid()) {
172    DLOG(ERROR) << "Unable to create chrome::VersionInfo object";
173    return user_agent;
174  }
175
176  user_agent += version_info.Version();
177  user_agent += " (" + version_info.LastChange() + ")";
178  if (!version_info.IsOfficialBuild()) {
179    user_agent += "-devel";
180  } else {
181    user_agent += " channel(" +
182        ChannelToString(version_info.GetChannel()) + ")";
183  }
184
185  return user_agent;
186}
187
188base::DictionaryValue* DeviceInfo::ToValue() {
189  base::DictionaryValue* value = new base::DictionaryValue();
190  value->SetString("name", client_name_);
191  value->SetString("id", public_id_);
192  value->SetString("os", GetOSString());
193  value->SetString("type", GetDeviceTypeString());
194  value->SetString("chromeVersion", chrome_version_);
195  return value;
196}
197
198void DeviceInfo::set_public_id(std::string id) {
199  public_id_ = id;
200}
201
202// static.
203void DeviceInfo::CreateLocalDeviceInfo(
204    const std::string& guid,
205    base::Callback<void(const DeviceInfo& local_info)> callback) {
206  GetClientName(
207      base::Bind(&DeviceInfo::CreateLocalDeviceInfoContinuation,
208                 guid,
209                 callback));
210}
211
212// static.
213void DeviceInfo::GetClientName(
214    base::Callback<void(const std::string& client_name)> callback) {
215  syncer::GetSessionName(
216      content::BrowserThread::GetBlockingPool(),
217      base::Bind(&DeviceInfo::GetClientNameContinuation,
218                 callback));
219}
220
221void DeviceInfo::GetClientNameContinuation(
222    base::Callback<void(const std::string& local_info)> callback,
223    const std::string& session_name) {
224  callback.Run(session_name);
225}
226
227// static.
228void DeviceInfo::CreateLocalDeviceInfoContinuation(
229    const std::string& guid,
230    base::Callback<void(const DeviceInfo& local_info)> callback,
231    const std::string& session_name) {
232  chrome::VersionInfo version_info;
233
234  DeviceInfo local_info(
235      guid,
236      session_name,
237      version_info.CreateVersionString(),
238      MakeUserAgentForSyncApi(version_info),
239      GetLocalDeviceType());
240
241  callback.Run(local_info);
242}
243
244}  // namespace browser_sync
245