Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / components / gcm_driver / gcm_driver.cc
1 // Copyright 2014 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 "components/gcm_driver/gcm_driver.h"
6
7 #include <algorithm>
8
9 #include "base/logging.h"
10 #include "base/metrics/field_trial.h"
11 #include "components/gcm_driver/gcm_app_handler.h"
12
13 namespace gcm {
14
15 namespace {
16 const char kGCMFieldTrialName[] = "GCM";
17 const char kGCMFieldTrialEnabledGroupName[] = "Enabled";
18 }  // namespace
19
20 // static
21 bool GCMDriver::IsAllowedForAllUsers() {
22   std::string group_name =
23       base::FieldTrialList::FindFullName(kGCMFieldTrialName);
24   return group_name == kGCMFieldTrialEnabledGroupName;
25 }
26
27 GCMDriver::GCMDriver() : weak_ptr_factory_(this) {
28 }
29
30 GCMDriver::~GCMDriver() {
31 }
32
33 void GCMDriver::Register(const std::string& app_id,
34                          const std::vector<std::string>& sender_ids,
35                          const RegisterCallback& callback) {
36   DCHECK(!app_id.empty());
37   DCHECK(!sender_ids.empty());
38   DCHECK(!callback.is_null());
39
40   GCMClient::Result result = EnsureStarted();
41   if (result != GCMClient::SUCCESS) {
42     callback.Run(std::string(), result);
43     return;
44   }
45
46   // If previous register operation is still in progress, bail out.
47   if (register_callbacks_.find(app_id) != register_callbacks_.end()) {
48     callback.Run(std::string(), GCMClient::ASYNC_OPERATION_PENDING);
49     return;
50   }
51
52   // Normalize the sender IDs by making them sorted.
53   std::vector<std::string> normalized_sender_ids = sender_ids;
54   std::sort(normalized_sender_ids.begin(), normalized_sender_ids.end());
55
56   register_callbacks_[app_id] = callback;
57
58   // If previous unregister operation is still in progress, wait until it
59   // finishes. We don't want to throw ASYNC_OPERATION_PENDING when the user
60   // uninstalls an app (ungistering) and then reinstalls the app again
61   // (registering).
62   std::map<std::string, UnregisterCallback>::iterator unregister_iter =
63       unregister_callbacks_.find(app_id);
64   if (unregister_iter != unregister_callbacks_.end()) {
65     // Replace the original unregister callback with an intermediate callback
66     // that will invoke the original unregister callback and trigger the pending
67     // registration after the unregistration finishes.
68     // Note that some parameters to RegisterAfterUnregister are specified here
69     // when the callback is created (base::Bind supports the partial binding
70     // of parameters).
71     unregister_iter->second = base::Bind(
72         &GCMDriver::RegisterAfterUnregister,
73         weak_ptr_factory_.GetWeakPtr(),
74         app_id,
75         normalized_sender_ids,
76         unregister_iter->second);
77     return;
78   }
79
80   RegisterImpl(app_id, normalized_sender_ids);
81 }
82
83 void GCMDriver::Unregister(const std::string& app_id,
84                            const UnregisterCallback& callback) {
85   DCHECK(!app_id.empty());
86   DCHECK(!callback.is_null());
87
88   GCMClient::Result result = EnsureStarted();
89   if (result != GCMClient::SUCCESS) {
90     callback.Run(result);
91     return;
92   }
93
94   // If previous un/register operation is still in progress, bail out.
95   if (register_callbacks_.find(app_id) != register_callbacks_.end() ||
96       unregister_callbacks_.find(app_id) != unregister_callbacks_.end()) {
97     callback.Run(GCMClient::ASYNC_OPERATION_PENDING);
98     return;
99   }
100
101   unregister_callbacks_[app_id] = callback;
102
103   UnregisterImpl(app_id);
104 }
105
106 void GCMDriver::Send(const std::string& app_id,
107                      const std::string& receiver_id,
108                      const GCMClient::OutgoingMessage& message,
109                      const SendCallback& callback) {
110   DCHECK(!app_id.empty());
111   DCHECK(!receiver_id.empty());
112   DCHECK(!callback.is_null());
113
114   GCMClient::Result result = EnsureStarted();
115   if (result != GCMClient::SUCCESS) {
116     callback.Run(std::string(), result);
117     return;
118   }
119
120   // If the message with send ID is still in progress, bail out.
121   std::pair<std::string, std::string> key(app_id, message.id);
122   if (send_callbacks_.find(key) != send_callbacks_.end()) {
123     callback.Run(message.id, GCMClient::INVALID_PARAMETER);
124     return;
125   }
126
127   send_callbacks_[key] = callback;
128
129   SendImpl(app_id, receiver_id, message);
130 }
131
132 void GCMDriver::RegisterFinished(const std::string& app_id,
133                                  const std::string& registration_id,
134                                  GCMClient::Result result) {
135   std::map<std::string, RegisterCallback>::iterator callback_iter =
136       register_callbacks_.find(app_id);
137   if (callback_iter == register_callbacks_.end()) {
138     // The callback could have been removed when the app is uninstalled.
139     return;
140   }
141
142   RegisterCallback callback = callback_iter->second;
143   register_callbacks_.erase(callback_iter);
144   callback.Run(registration_id, result);
145 }
146
147 void GCMDriver::UnregisterFinished(const std::string& app_id,
148                                    GCMClient::Result result) {
149   std::map<std::string, UnregisterCallback>::iterator callback_iter =
150       unregister_callbacks_.find(app_id);
151   if (callback_iter == unregister_callbacks_.end())
152     return;
153
154   UnregisterCallback callback = callback_iter->second;
155   unregister_callbacks_.erase(callback_iter);
156   callback.Run(result);
157 }
158
159 void GCMDriver::SendFinished(const std::string& app_id,
160                              const std::string& message_id,
161                              GCMClient::Result result) {
162   std::map<std::pair<std::string, std::string>, SendCallback>::iterator
163       callback_iter = send_callbacks_.find(
164           std::pair<std::string, std::string>(app_id, message_id));
165   if (callback_iter == send_callbacks_.end()) {
166     // The callback could have been removed when the app is uninstalled.
167     return;
168   }
169
170   SendCallback callback = callback_iter->second;
171   send_callbacks_.erase(callback_iter);
172   callback.Run(message_id, result);
173 }
174
175 void GCMDriver::Shutdown() {
176   for (GCMAppHandlerMap::const_iterator iter = app_handlers_.begin();
177        iter != app_handlers_.end(); ++iter) {
178     DVLOG(1) << "Calling ShutdownHandler for: " << iter->first;
179     iter->second->ShutdownHandler();
180   }
181   app_handlers_.clear();
182 }
183
184 void GCMDriver::AddAppHandler(const std::string& app_id,
185                               GCMAppHandler* handler) {
186   DCHECK(!app_id.empty());
187   DCHECK(handler);
188   DCHECK_EQ(app_handlers_.count(app_id), 0u);
189   app_handlers_[app_id] = handler;
190   DVLOG(1) << "App handler added for: " << app_id;
191 }
192
193 void GCMDriver::RemoveAppHandler(const std::string& app_id) {
194   DCHECK(!app_id.empty());
195   app_handlers_.erase(app_id);
196   DVLOG(1) << "App handler removed for: " << app_id;
197 }
198
199 GCMAppHandler* GCMDriver::GetAppHandler(const std::string& app_id) {
200   // Look for exact match.
201   GCMAppHandlerMap::const_iterator iter = app_handlers_.find(app_id);
202   if (iter != app_handlers_.end())
203     return iter->second;
204
205   // Ask the handlers whether they know how to handle it.
206   for (iter = app_handlers_.begin(); iter != app_handlers_.end(); ++iter) {
207     if (iter->second->CanHandle(app_id))
208       return iter->second;
209   }
210
211   return &default_app_handler_;
212 }
213
214 bool GCMDriver::HasRegisterCallback(const std::string& app_id) {
215   return register_callbacks_.find(app_id) != register_callbacks_.end();
216 }
217
218 void GCMDriver::ClearCallbacks() {
219   register_callbacks_.clear();
220   unregister_callbacks_.clear();
221   send_callbacks_.clear();
222 }
223
224 void GCMDriver::RegisterAfterUnregister(
225     const std::string& app_id,
226     const std::vector<std::string>& normalized_sender_ids,
227     const UnregisterCallback& unregister_callback,
228     GCMClient::Result result) {
229   // Invoke the original unregister callback.
230   unregister_callback.Run(result);
231
232   // Trigger the pending registration.
233   DCHECK(register_callbacks_.find(app_id) != register_callbacks_.end());
234   RegisterImpl(app_id, normalized_sender_ids);
235 }
236
237 }  // namespace gcm