OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/ui/google_now/google_now_service.h" | 5 #include "chrome/browser/ui/google_now/google_now_service.h" |
6 | 6 |
7 #include "base/command_line.h" | 7 #include "base/command_line.h" |
| 8 #include "base/json/json_reader.h" |
| 9 #include "base/memory/scoped_vector.h" |
| 10 #include "base/utf_string_conversions.h" |
| 11 #include "base/values.h" |
| 12 #include "chrome/browser/browser_process.h" |
| 13 #include "chrome/browser/notifications/notification.h" |
| 14 #include "chrome/browser/notifications/notification_ui_manager.h" |
8 #include "chrome/browser/profiles/profile.h" | 15 #include "chrome/browser/profiles/profile.h" |
| 16 #include "chrome/browser/ui/google_now/google_now_notification_delegate.h" |
9 #include "chrome/common/chrome_switches.h" | 17 #include "chrome/common/chrome_switches.h" |
| 18 #include "chrome/common/extensions/api/experimental_notification.h" |
10 #include "content/public/browser/geolocation.h" | 19 #include "content/public/browser/geolocation.h" |
11 #include "content/public/common/geoposition.h" | 20 #include "content/public/common/geoposition.h" |
12 #include "net/http/http_status_code.h" | 21 #include "net/http/http_status_code.h" |
13 #include "net/url_request/url_fetcher.h" | 22 #include "net/url_request/url_fetcher.h" |
14 #include "net/url_request/url_request_context.h" | 23 #include "net/url_request/url_request_context.h" |
15 | 24 |
16 using base::Bind; | 25 using base::Bind; |
| 26 using base::JSONReader; |
17 using base::TimeDelta; | 27 using base::TimeDelta; |
| 28 using base::Value; |
18 using content::Geoposition; | 29 using content::Geoposition; |
| 30 using extensions::api::experimental_notification::ShowOptions; |
19 using net::HTTP_OK; | 31 using net::HTTP_OK; |
20 using net::URLFetcher; | 32 using net::URLFetcher; |
21 using net::URLRequestStatus; | 33 using net::URLRequestStatus; |
22 | 34 |
23 namespace { | 35 namespace { |
24 // TODO(vadimt): Figure out the values of the constants. | 36 // TODO(vadimt): Figure out the values of the constants. |
25 | 37 |
26 // Period for polling for Google Now cards to use when the period from the | 38 // Period for polling for Google Now cards to use when the period from the |
27 // server is not available. | 39 // server is not available. |
28 // TODO(vadimt): Figure out the consequences for LBS and battery. | 40 // TODO(vadimt): Figure out the consequences for LBS and battery. |
29 // TODO(vadimt): Consider triggers other than the timer for refreshing the | 41 // TODO(vadimt): Consider triggers other than the timer for refreshing the |
30 // position, such as waking from sleep. | 42 // position, such as waking from sleep. |
31 const int kDefaultPollingPeriodMs = 300000; // 5 minutes | 43 const int kDefaultPollingPeriodMs = 300000; // 5 minutes |
32 // Time allocated to a geolocation request. | 44 // Time allocated to a geolocation request. |
33 const int kGeolocationRequestTimeoutMs = 60000; // 1 minute | 45 const int kGeolocationRequestTimeoutMs = 60000; // 1 minute |
| 46 // JSON key for expiration timestamp. |
| 47 const char kExpirationTimestampKey[] = "expiration_timestamp_seconds"; |
| 48 // JSON key for cards. |
| 49 const char kCardsKey[] = "cards"; |
34 } // namespace | 50 } // namespace |
35 | 51 |
| 52 // Google Now cards in the server response. |
| 53 typedef ScopedVector<ShowOptions> ParsedCards; |
| 54 |
36 struct GoogleNowService::ServerResponse { | 55 struct GoogleNowService::ServerResponse { |
37 // TODO(vadimt): Populate this structure with real fields. | 56 ParsedCards cards; |
38 TimeDelta next_request_delay; | 57 TimeDelta next_request_delay; |
39 }; | 58 }; |
40 | 59 |
41 GoogleNowService::GoogleNowService(Profile* profile) | 60 GoogleNowService::GoogleNowService(Profile* profile) |
42 : profile_(profile), | 61 : profile_(profile), |
43 ALLOW_THIS_IN_INITIALIZER_LIST(geolocation_request_weak_factory_(this)) { | 62 ALLOW_THIS_IN_INITIALIZER_LIST(geolocation_request_weak_factory_(this)) { |
44 DCHECK(profile_); | 63 DCHECK(profile_); |
45 } | 64 } |
46 | 65 |
47 GoogleNowService::~GoogleNowService() { | 66 GoogleNowService::~GoogleNowService() { |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
151 fetcher_->SetRequestContext(profile_->GetRequestContext()); | 170 fetcher_->SetRequestContext(profile_->GetRequestContext()); |
152 fetcher_->SetLoadFlags( | 171 fetcher_->SetLoadFlags( |
153 net::LOAD_BYPASS_CACHE | net::LOAD_DISABLE_CACHE | | 172 net::LOAD_BYPASS_CACHE | net::LOAD_DISABLE_CACHE | |
154 net::LOAD_DO_NOT_SAVE_COOKIES); | 173 net::LOAD_DO_NOT_SAVE_COOKIES); |
155 | 174 |
156 fetcher_->Start(); | 175 fetcher_->Start(); |
157 } | 176 } |
158 | 177 |
159 bool GoogleNowService::ParseServerResponse(const std::string& response_string, | 178 bool GoogleNowService::ParseServerResponse(const std::string& response_string, |
160 ServerResponse* server_response) { | 179 ServerResponse* server_response) { |
161 // TODO(vadimt): Do real parsing. | 180 // Server response is in JSON format. |
| 181 scoped_ptr<Value> value(JSONReader::Read(response_string)); |
| 182 |
| 183 if (value == NULL) |
| 184 return false; |
| 185 |
| 186 const DictionaryValue* root; |
| 187 if (!value->GetAsDictionary(&root)) |
| 188 return false; |
| 189 |
| 190 int expiration_timestamp_seconds; |
| 191 if (!root->GetInteger(kExpirationTimestampKey, |
| 192 &expiration_timestamp_seconds)) { |
| 193 return false; |
| 194 } |
| 195 |
162 server_response->next_request_delay = | 196 server_response->next_request_delay = |
163 TimeDelta::FromMilliseconds(kDefaultPollingPeriodMs); | 197 TimeDelta::FromSeconds(expiration_timestamp_seconds); |
| 198 |
| 199 const ListValue* cards; |
| 200 if (!root->GetList(kCardsKey, &cards)) |
| 201 return false; |
| 202 |
| 203 for (size_t index = 0; index < cards->GetSize(); ++index) { |
| 204 const base::DictionaryValue* card; |
| 205 if (!cards->GetDictionary(index, &card)) |
| 206 return false; |
| 207 |
| 208 scoped_ptr<ShowOptions> show_options(new ShowOptions()); |
| 209 |
| 210 if (!ShowOptions::Populate(*card, show_options.get())) |
| 211 return false; |
| 212 |
| 213 server_response->cards.push_back(show_options.release()); |
| 214 } |
| 215 |
164 return true; | 216 return true; |
165 } | 217 } |
166 | 218 |
167 void GoogleNowService::ShowNotifications( | 219 void GoogleNowService::ShowNotifications( |
168 const ServerResponse& server_response) { | 220 const ServerResponse& server_response) { |
169 // TODO(vadimt): Implement using Chrome Notifications. | 221 // TODO(vadimt): Most of the code below duplicates the code in |
| 222 // NotificationShowFunction::RunImpl. Once we finally decide the format of the |
| 223 // server response, remove the duplication. Before this, keep this code in |
| 224 // sync with its origin. |
| 225 for (ParsedCards::const_iterator it = server_response.cards.begin(); |
| 226 it != server_response.cards.end(); |
| 227 ++it) { |
| 228 ShowOptions* show_options = *it; |
| 229 |
| 230 ui::notifications::NotificationType type = |
| 231 ui::notifications::StringToNotificationType(show_options->type); |
| 232 GURL icon_url(UTF8ToUTF16(show_options->icon_url)); |
| 233 string16 title(UTF8ToUTF16(show_options->title)); |
| 234 string16 message(UTF8ToUTF16(show_options->message)); |
| 235 |
| 236 scoped_ptr<DictionaryValue> optional_fields(new DictionaryValue()); |
| 237 |
| 238 // For all notification types. |
| 239 if (show_options->priority.get()) |
| 240 optional_fields->SetInteger(ui::notifications::kPriorityKey, |
| 241 *show_options->priority); |
| 242 if (show_options->timestamp.get()) |
| 243 optional_fields->SetString(ui::notifications::kTimestampKey, |
| 244 *show_options->timestamp); |
| 245 if (show_options->second_icon_url.get()) |
| 246 optional_fields->SetString(ui::notifications::kSecondIconUrlKey, |
| 247 UTF8ToUTF16(*show_options->second_icon_url)); |
| 248 if (show_options->unread_count.get()) |
| 249 optional_fields->SetInteger(ui::notifications::kUnreadCountKey, |
| 250 *show_options->unread_count); |
| 251 if (show_options->button_one_title.get()) |
| 252 optional_fields->SetString(ui::notifications::kButtonOneTitleKey, |
| 253 UTF8ToUTF16(*show_options->button_one_title)); |
| 254 if (show_options->button_two_title.get()) |
| 255 optional_fields->SetString(ui::notifications::kButtonTwoTitleKey, |
| 256 UTF8ToUTF16(*show_options->button_two_title)); |
| 257 if (show_options->expanded_message.get()) |
| 258 optional_fields->SetString(ui::notifications::kExpandedMessageKey, |
| 259 UTF8ToUTF16(*show_options->expanded_message)); |
| 260 |
| 261 // For image notifications (type == 'image'). |
| 262 if (show_options->image_url.get()) |
| 263 optional_fields->SetString(ui::notifications::kImageUrlKey, |
| 264 UTF8ToUTF16(*show_options->image_url)); |
| 265 |
| 266 // For multiple-item notifications (type == 'multiple'). |
| 267 if (show_options->items.get()) { |
| 268 base::ListValue* items = new base::ListValue(); |
| 269 std::vector< |
| 270 linked_ptr< |
| 271 extensions::api::experimental_notification::NotificationItem> >:: |
| 272 iterator i; |
| 273 for (i = show_options->items->begin(); |
| 274 i != show_options->items->end(); |
| 275 ++i) { |
| 276 base::DictionaryValue* item = new base::DictionaryValue(); |
| 277 item->SetString(ui::notifications::kItemTitleKey, |
| 278 UTF8ToUTF16(i->get()->title)); |
| 279 item->SetString(ui::notifications::kItemMessageKey, |
| 280 UTF8ToUTF16(i->get()->message)); |
| 281 items->Append(item); |
| 282 } |
| 283 optional_fields->Set(ui::notifications::kItemsKey, items); |
| 284 } |
| 285 |
| 286 string16 replace_id(UTF8ToUTF16(show_options->replace_id)); |
| 287 |
| 288 Notification notification(type, icon_url, title, message, |
| 289 WebKit::WebTextDirectionDefault, |
| 290 string16(), replace_id, |
| 291 optional_fields.get(), |
| 292 new GoogleNowNotificationDelegate()); |
| 293 g_browser_process->notification_ui_manager()->Add(notification, profile_); |
| 294 } |
170 } | 295 } |
171 | 296 |
172 void GoogleNowService::OnURLFetchComplete(const net::URLFetcher* source) { | 297 void GoogleNowService::OnURLFetchComplete(const net::URLFetcher* source) { |
173 DCHECK(source != NULL); | 298 DCHECK(source != NULL); |
174 DCHECK(IsGoogleNowEnabled()); | 299 DCHECK(IsGoogleNowEnabled()); |
175 DCHECK(!next_update_timer_.IsRunning()); | 300 DCHECK(!next_update_timer_.IsRunning()); |
176 DCHECK(!geolocation_request_timer_.IsRunning()); | 301 DCHECK(!geolocation_request_timer_.IsRunning()); |
177 DCHECK(!geolocation_request_weak_factory_.HasWeakPtrs()); | 302 DCHECK(!geolocation_request_weak_factory_.HasWeakPtrs()); |
178 DCHECK(fetcher_.get() == source); | 303 DCHECK(fetcher_.get() == source); |
179 | 304 |
(...skipping 11 matching lines...) Expand all Loading... |
191 if (ParseServerResponse(response_string, &server_response)) { | 316 if (ParseServerResponse(response_string, &server_response)) { |
192 ShowNotifications(server_response); | 317 ShowNotifications(server_response); |
193 next_request_delay = server_response.next_request_delay; | 318 next_request_delay = server_response.next_request_delay; |
194 } | 319 } |
195 } | 320 } |
196 } | 321 } |
197 | 322 |
198 fetcher_.reset(NULL); | 323 fetcher_.reset(NULL); |
199 StartWaitingForNextUpdate(next_request_delay); | 324 StartWaitingForNextUpdate(next_request_delay); |
200 } | 325 } |
OLD | NEW |