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" |
| 8 #include "chrome/browser/profiles/profile.h" |
| 9 #include "chrome/common/chrome_switches.h" |
7 #include "content/public/browser/geolocation.h" | 10 #include "content/public/browser/geolocation.h" |
8 #include "content/public/common/geoposition.h" | 11 #include "content/public/common/geoposition.h" |
| 12 #include "net/http/http_status_code.h" |
| 13 #include "net/url_request/url_fetcher.h" |
| 14 #include "net/url_request/url_request_context.h" |
9 | 15 |
10 using base::Bind; | 16 using base::Bind; |
11 using base::TimeDelta; | 17 using base::TimeDelta; |
12 using content::Geoposition; | 18 using content::Geoposition; |
13 using net::URLRequest; | 19 using net::HTTP_OK; |
| 20 using net::URLFetcher; |
| 21 using net::URLRequestStatus; |
14 | 22 |
15 namespace { | 23 namespace { |
16 // TODO(vadimt): Figure out the values of the constants. | 24 // TODO(vadimt): Figure out the values of the constants. |
17 | 25 |
18 // Period for polling for Google Now cards to use when the period from the | 26 // Period for polling for Google Now cards to use when the period from the |
19 // server is not available. | 27 // server is not available. |
20 // TODO(vadimt): Figure out the consequences for LBS and battery. | 28 // TODO(vadimt): Figure out the consequences for LBS and battery. |
21 // TODO(vadimt): Consider triggers other than the timer for refreshing the | 29 // TODO(vadimt): Consider triggers other than the timer for refreshing the |
22 // position, such as waking from sleep. | 30 // position, such as waking from sleep. |
23 const int kDefaultPollingPeriodMs = 300000; // 5 minutes | 31 const int kDefaultPollingPeriodMs = 300000; // 5 minutes |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
64 | 72 |
65 next_update_timer_.Start(FROM_HERE, delay, | 73 next_update_timer_.Start(FROM_HERE, delay, |
66 this, &GoogleNowService::OnWaitingForNextUpdateEnds); | 74 this, &GoogleNowService::OnWaitingForNextUpdateEnds); |
67 } | 75 } |
68 | 76 |
69 void GoogleNowService::OnWaitingForNextUpdateEnds() { | 77 void GoogleNowService::OnWaitingForNextUpdateEnds() { |
70 DCHECK(IsGoogleNowEnabled()); | 78 DCHECK(IsGoogleNowEnabled()); |
71 DCHECK(!next_update_timer_.IsRunning()); | 79 DCHECK(!next_update_timer_.IsRunning()); |
72 DCHECK(!geolocation_request_timer_.IsRunning()); | 80 DCHECK(!geolocation_request_timer_.IsRunning()); |
73 DCHECK(!geolocation_request_weak_factory_.HasWeakPtrs()); | 81 DCHECK(!geolocation_request_weak_factory_.HasWeakPtrs()); |
| 82 DCHECK(fetcher_.get() == NULL); |
74 | 83 |
75 UpdateCards(); | 84 UpdateCards(); |
76 } | 85 } |
77 | 86 |
78 void GoogleNowService::StartObtainingGeolocation() { | 87 void GoogleNowService::StartObtainingGeolocation() { |
79 DCHECK(!geolocation_request_weak_factory_.HasWeakPtrs()); | 88 DCHECK(!geolocation_request_weak_factory_.HasWeakPtrs()); |
80 content::RequestLocationUpdate(Bind( | 89 content::RequestLocationUpdate(Bind( |
81 &GoogleNowService::OnLocationObtained, | 90 &GoogleNowService::OnLocationObtained, |
82 geolocation_request_weak_factory_.GetWeakPtr())); | 91 geolocation_request_weak_factory_.GetWeakPtr())); |
83 | 92 |
84 DCHECK(!geolocation_request_timer_.IsRunning()); | 93 DCHECK(!geolocation_request_timer_.IsRunning()); |
85 geolocation_request_timer_.Start(FROM_HERE, | 94 geolocation_request_timer_.Start(FROM_HERE, |
86 TimeDelta::FromMilliseconds(kGeolocationRequestTimeoutMs), | 95 TimeDelta::FromMilliseconds(kGeolocationRequestTimeoutMs), |
87 this, &GoogleNowService::OnLocationRequestTimeout); | 96 this, &GoogleNowService::OnLocationRequestTimeout); |
88 } | 97 } |
89 | 98 |
90 void GoogleNowService::OnLocationObtained(const Geoposition& position) { | 99 void GoogleNowService::OnLocationObtained(const Geoposition& position) { |
91 DCHECK(IsGoogleNowEnabled()); | 100 DCHECK(IsGoogleNowEnabled()); |
92 DCHECK(!next_update_timer_.IsRunning()); | 101 DCHECK(!next_update_timer_.IsRunning()); |
93 DCHECK(geolocation_request_timer_.IsRunning()); | 102 DCHECK(geolocation_request_timer_.IsRunning()); |
94 DCHECK(geolocation_request_weak_factory_.HasWeakPtrs()); | 103 DCHECK(geolocation_request_weak_factory_.HasWeakPtrs()); |
| 104 DCHECK(fetcher_.get() == NULL); |
95 | 105 |
96 geolocation_request_weak_factory_.InvalidateWeakPtrs(); | 106 geolocation_request_weak_factory_.InvalidateWeakPtrs(); |
97 geolocation_request_timer_.Stop(); | 107 geolocation_request_timer_.Stop(); |
98 StartServerRequest(position); | 108 StartServerRequest(position); |
99 } | 109 } |
100 | 110 |
101 void GoogleNowService::OnLocationRequestTimeout() { | 111 void GoogleNowService::OnLocationRequestTimeout() { |
102 DCHECK(IsGoogleNowEnabled()); | 112 DCHECK(IsGoogleNowEnabled()); |
103 DCHECK(!next_update_timer_.IsRunning()); | 113 DCHECK(!next_update_timer_.IsRunning()); |
104 DCHECK(!geolocation_request_timer_.IsRunning()); | 114 DCHECK(!geolocation_request_timer_.IsRunning()); |
105 DCHECK(geolocation_request_weak_factory_.HasWeakPtrs()); | 115 DCHECK(geolocation_request_weak_factory_.HasWeakPtrs()); |
| 116 DCHECK(fetcher_.get() == NULL); |
106 | 117 |
107 geolocation_request_weak_factory_.InvalidateWeakPtrs(); | 118 geolocation_request_weak_factory_.InvalidateWeakPtrs(); |
108 StartServerRequest(Geoposition()); | 119 StartServerRequest(Geoposition()); |
109 } | 120 } |
110 | 121 |
| 122 std::string GoogleNowService::BuildRequestURL( |
| 123 const content::Geoposition& position) { |
| 124 std::string server_path = |
| 125 CommandLine::ForCurrentProcess()->GetSwitchValueASCII( |
| 126 switches::kEnableGoogleNowIntegration); |
| 127 DCHECK(!server_path.empty()); |
| 128 |
| 129 if (position.Validate()) { |
| 130 // If position is available, append it to the URL. |
| 131 std::stringstream parameters; |
| 132 parameters << "?q=" |
| 133 << position.latitude << ',' |
| 134 << position.longitude << ',' |
| 135 << position.accuracy; |
| 136 server_path += parameters.str(); |
| 137 } |
| 138 |
| 139 return server_path; |
| 140 } |
| 141 |
111 void GoogleNowService::StartServerRequest( | 142 void GoogleNowService::StartServerRequest( |
112 const content::Geoposition& position) { | 143 const content::Geoposition& position) { |
113 // TODO(vadimt): Implement via making URLRequest to the server. | 144 DCHECK(fetcher_.get() == NULL); |
114 OnServerRequestCompleted(NULL, 0); | 145 fetcher_.reset(URLFetcher::Create(GURL(BuildRequestURL(position)), |
| 146 URLFetcher::GET, |
| 147 this)); |
| 148 |
| 149 // TODO(vadimt): Figure out how to send user's identity to the server. Make |
| 150 // sure we never get responses like 'Select an account' page. |
| 151 fetcher_->SetRequestContext(profile_->GetRequestContext()); |
| 152 fetcher_->SetLoadFlags( |
| 153 net::LOAD_BYPASS_CACHE | net::LOAD_DISABLE_CACHE | |
| 154 net::LOAD_DO_NOT_SAVE_COOKIES); |
| 155 |
| 156 fetcher_->Start(); |
115 } | 157 } |
116 | 158 |
117 void GoogleNowService::OnServerRequestCompleted(URLRequest* request, | 159 bool GoogleNowService::ParseServerResponse(const std::string& response_string, |
118 int num_bytes) { | |
119 DCHECK(IsGoogleNowEnabled()); | |
120 DCHECK(!next_update_timer_.IsRunning()); | |
121 DCHECK(!geolocation_request_timer_.IsRunning()); | |
122 // TODO(vadimt): Uncomment the check below once OnServerRequestCompleted is | |
123 // called asynchronously. | |
124 // DCHECK(!geolocation_request_weak_factory_.HasWeakPtrs()); | |
125 | |
126 ServerResponse server_response; | |
127 // TODO(vadimt): Check request's status. | |
128 if (ParseServerResponse(request, num_bytes, &server_response)) { | |
129 ShowNotifications(server_response); | |
130 // Once the cards are shown, schedule next cards update after the delay | |
131 // suggested by the server. | |
132 StartWaitingForNextUpdate(server_response.next_request_delay); | |
133 } else { | |
134 // If the server response is bad, schedule next cards update after the | |
135 // default delay. | |
136 // TODO(vadimt): Consider exponential backoff with randomized jitter. | |
137 StartWaitingForNextUpdate( | |
138 TimeDelta::FromMilliseconds(kDefaultPollingPeriodMs)); | |
139 } | |
140 } | |
141 | |
142 bool GoogleNowService::ParseServerResponse(const URLRequest* request, | |
143 int num_bytes, | |
144 ServerResponse* server_response) { | 160 ServerResponse* server_response) { |
145 // TODO(vadimt): Do real parsing. | 161 // TODO(vadimt): Do real parsing. |
146 server_response->next_request_delay = | 162 server_response->next_request_delay = |
147 TimeDelta::FromMilliseconds(kDefaultPollingPeriodMs); | 163 TimeDelta::FromMilliseconds(kDefaultPollingPeriodMs); |
148 return true; | 164 return true; |
149 } | 165 } |
150 | 166 |
151 void GoogleNowService::ShowNotifications( | 167 void GoogleNowService::ShowNotifications( |
152 const ServerResponse& server_response) { | 168 const ServerResponse& server_response) { |
153 // TODO(vadimt): Implement using Chrome Notifications. | 169 // TODO(vadimt): Implement using Chrome Notifications. |
154 } | 170 } |
| 171 |
| 172 void GoogleNowService::OnURLFetchComplete(const net::URLFetcher* source) { |
| 173 DCHECK(source != NULL); |
| 174 DCHECK(IsGoogleNowEnabled()); |
| 175 DCHECK(!next_update_timer_.IsRunning()); |
| 176 DCHECK(!geolocation_request_timer_.IsRunning()); |
| 177 DCHECK(!geolocation_request_weak_factory_.HasWeakPtrs()); |
| 178 DCHECK(fetcher_.get() == source); |
| 179 |
| 180 // TODO(vadimt): Implement exponential backoff with randomized jitter. |
| 181 TimeDelta next_request_delay = |
| 182 TimeDelta::FromMilliseconds(kDefaultPollingPeriodMs); |
| 183 |
| 184 if (source->GetStatus().status() == URLRequestStatus::SUCCESS && |
| 185 source->GetResponseCode() == HTTP_OK) { |
| 186 std::string response_string; |
| 187 |
| 188 if (source->GetResponseAsString(&response_string)) { |
| 189 ServerResponse server_response; |
| 190 |
| 191 if (ParseServerResponse(response_string, &server_response)) { |
| 192 ShowNotifications(server_response); |
| 193 next_request_delay = server_response.next_request_delay; |
| 194 } |
| 195 } |
| 196 } |
| 197 |
| 198 fetcher_.reset(NULL); |
| 199 StartWaitingForNextUpdate(next_request_delay); |
| 200 } |
OLD | NEW |