summaryrefslogtreecommitdiffstats
path: root/content/browser/geofencing
diff options
context:
space:
mode:
authormek <mek@chromium.org>2014-10-23 15:06:09 -0700
committerCommit bot <commit-bot@chromium.org>2014-10-23 22:06:35 +0000
commit0c55c7f631795d3f76b38bc7f6b54f5be7da8f22 (patch)
tree5c6b4c75cbea82cdd5b38b61b87a62a6b1fc858c /content/browser/geofencing
parent4087adc5677bb8dd7f414c0afafc8f4215ce0077 (diff)
downloadchromium_src-0c55c7f631795d3f76b38bc7f6b54f5be7da8f22.zip
chromium_src-0c55c7f631795d3f76b38bc7f6b54f5be7da8f22.tar.gz
chromium_src-0c55c7f631795d3f76b38bc7f6b54f5be7da8f22.tar.bz2
Refactor GeofencingManager to have one instance per StoragePartition.
Add a new GeofencingService class for the few global tasks GeofencingManager used to do. BUG=383125 Review URL: https://codereview.chromium.org/645763003 Cr-Commit-Position: refs/heads/master@{#300960}
Diffstat (limited to 'content/browser/geofencing')
-rw-r--r--content/browser/geofencing/geofencing_dispatcher_host.cc24
-rw-r--r--content/browser/geofencing/geofencing_dispatcher_host.h6
-rw-r--r--content/browser/geofencing/geofencing_manager.cc295
-rw-r--r--content/browser/geofencing/geofencing_manager.h115
-rw-r--r--content/browser/geofencing/geofencing_manager_unittest.cc319
-rw-r--r--content/browser/geofencing/geofencing_provider.h23
-rw-r--r--content/browser/geofencing/geofencing_registration_delegate.h29
-rw-r--r--content/browser/geofencing/geofencing_service.cc199
-rw-r--r--content/browser/geofencing/geofencing_service.h105
-rw-r--r--content/browser/geofencing/geofencing_service_unittest.cc191
10 files changed, 915 insertions, 391 deletions
diff --git a/content/browser/geofencing/geofencing_dispatcher_host.cc b/content/browser/geofencing/geofencing_dispatcher_host.cc
index 077485b..f2fe54a 100644
--- a/content/browser/geofencing/geofencing_dispatcher_host.cc
+++ b/content/browser/geofencing/geofencing_dispatcher_host.cc
@@ -7,16 +7,15 @@
#include "content/browser/geofencing/geofencing_manager.h"
#include "content/common/geofencing_messages.h"
#include "third_party/WebKit/public/platform/WebCircularGeofencingRegion.h"
-#include "url/gurl.h"
namespace content {
static const int kMaxRegionIdLength = 200;
GeofencingDispatcherHost::GeofencingDispatcherHost(
- BrowserContext* browser_context)
+ GeofencingManager* geofencing_manager)
: BrowserMessageFilter(GeofencingMsgStart),
- browser_context_(browser_context),
+ manager_(geofencing_manager),
weak_factory_(this) {
}
@@ -47,10 +46,8 @@ void GeofencingDispatcherHost::OnRegisterRegion(
return;
}
// TODO(mek): Actually pass service worker information to manager.
- GeofencingManager::GetInstance()->RegisterRegion(
- browser_context_,
- 0, /* service_worker_registration_id */
- GURL(), /* service_worker_origin */
+ manager_->RegisterRegion(
+ 0, /* service_worker_registration_id */
region_id,
region,
base::Bind(&GeofencingDispatcherHost::RegisterRegionCompleted,
@@ -70,10 +67,8 @@ void GeofencingDispatcherHost::OnUnregisterRegion(
return;
}
// TODO(mek): Actually pass service worker information to manager.
- GeofencingManager::GetInstance()->UnregisterRegion(
- browser_context_,
- 0, /* service_worker_registration_id */
- GURL(), /* service_worker_origin */
+ manager_->UnregisterRegion(
+ 0, /* service_worker_registration_id */
region_id,
base::Bind(&GeofencingDispatcherHost::UnregisterRegionCompleted,
weak_factory_.GetWeakPtr(),
@@ -86,11 +81,8 @@ void GeofencingDispatcherHost::OnGetRegisteredRegions(int thread_id,
GeofencingRegistrations result;
// TODO(mek): Actually pass service worker information to manager.
GeofencingStatus status =
- GeofencingManager::GetInstance()->GetRegisteredRegions(
- browser_context_,
- 0, /* service_worker_registration_id */
- GURL(), /* service_worker_origin */
- &result);
+ manager_->GetRegisteredRegions(0, /* service_worker_registration_id */
+ &result);
Send(new GeofencingMsg_GetRegisteredRegionsComplete(
thread_id, request_id, status, result));
}
diff --git a/content/browser/geofencing/geofencing_dispatcher_host.h b/content/browser/geofencing/geofencing_dispatcher_host.h
index 86858b8..16bc2b4 100644
--- a/content/browser/geofencing/geofencing_dispatcher_host.h
+++ b/content/browser/geofencing/geofencing_dispatcher_host.h
@@ -14,11 +14,11 @@ struct WebCircularGeofencingRegion;
namespace content {
-class BrowserContext;
+class GeofencingManager;
class GeofencingDispatcherHost : public BrowserMessageFilter {
public:
- explicit GeofencingDispatcherHost(BrowserContext* browser_context);
+ explicit GeofencingDispatcherHost(GeofencingManager* geofencing_manager);
private:
~GeofencingDispatcherHost() override;
@@ -42,7 +42,7 @@ class GeofencingDispatcherHost : public BrowserMessageFilter {
int request_id,
GeofencingStatus result);
- BrowserContext* browser_context_;
+ scoped_refptr<GeofencingManager> manager_;
base::WeakPtrFactory<GeofencingDispatcherHost> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(GeofencingDispatcherHost);
diff --git a/content/browser/geofencing/geofencing_manager.cc b/content/browser/geofencing/geofencing_manager.cc
index 94b0f25..33afae5 100644
--- a/content/browser/geofencing/geofencing_manager.cc
+++ b/content/browser/geofencing/geofencing_manager.cc
@@ -7,97 +7,90 @@
#include <algorithm>
#include "base/callback.h"
-#include "base/memory/singleton.h"
-#include "content/browser/geofencing/geofencing_provider.h"
+#include "content/browser/geofencing/geofencing_service.h"
+#include "content/browser/service_worker/service_worker_context_wrapper.h"
#include "content/public/browser/browser_thread.h"
#include "third_party/WebKit/public/platform/WebCircularGeofencingRegion.h"
-#include "url/gurl.h"
namespace content {
-struct GeofencingManager::RegistrationKey {
- RegistrationKey(BrowserContext* browser_context,
- int64 service_worker_registration_id,
- const GURL& service_worker_origin,
- const std::string& region_id);
-
- BrowserContext* browser_context;
+struct GeofencingManager::Registration {
+ Registration(int64 service_worker_registration_id,
+ const std::string& region_id,
+ const blink::WebCircularGeofencingRegion& region,
+ const StatusCallback& callback,
+ int64 geofencing_registration_id);
int64 service_worker_registration_id;
- GURL service_worker_origin;
-
std::string region_id;
-};
-
-GeofencingManager::RegistrationKey::RegistrationKey(
- BrowserContext* browser_context,
- int64 service_worker_registration_id,
- const GURL& service_worker_origin,
- const std::string& region_id)
- : browser_context(browser_context),
- service_worker_registration_id(service_worker_registration_id),
- service_worker_origin(service_worker_origin),
- region_id(region_id) {
-}
-
-struct GeofencingManager::Registration {
- Registration();
- Registration(const RegistrationKey& key,
- const blink::WebCircularGeofencingRegion& region);
-
- RegistrationKey key;
blink::WebCircularGeofencingRegion region;
- // Registration id as returned by the GeofencingProvider, set to -1 if not
- // currently registered with the provider.
- int registration_id;
+ // Registration ID as returned by the |GeofencingService|.
+ int64 geofencing_registration_id;
+
+ // Callback to call when registration is completed. This field is reset when
+ // registration is complete.
+ StatusCallback registration_callback;
- // Flag to indicate if this registration has completed, and thus should be
+ // Returns true if registration has been completed, and thus should be
// included in calls to GetRegisteredRegions.
- bool is_active;
+ bool is_active() const { return registration_callback.is_null(); }
};
-GeofencingManager::Registration::Registration() : key(nullptr, -1, GURL(), "") {
+GeofencingManager::Registration::Registration(
+ int64 service_worker_registration_id,
+ const std::string& region_id,
+ const blink::WebCircularGeofencingRegion& region,
+ const GeofencingManager::StatusCallback& callback,
+ int64 geofencing_registration_id)
+ : service_worker_registration_id(service_worker_registration_id),
+ region_id(region_id),
+ region(region),
+ geofencing_registration_id(geofencing_registration_id),
+ registration_callback(callback) {
}
-GeofencingManager::Registration::Registration(
- const RegistrationKey& key,
- const blink::WebCircularGeofencingRegion& region)
- : key(key), region(region), registration_id(-1), is_active(false) {
+GeofencingManager::GeofencingManager(
+ const scoped_refptr<ServiceWorkerContextWrapper>& service_worker_context)
+ : service_(nullptr), service_worker_context_(service_worker_context) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
}
-class GeofencingManager::RegistrationMatches {
- public:
- RegistrationMatches(const RegistrationKey& key) : key_(key) {}
-
- bool operator()(const Registration& registration) {
- return registration.key.browser_context == key_.browser_context &&
- registration.key.service_worker_registration_id ==
- key_.service_worker_registration_id &&
- registration.key.service_worker_origin ==
- key_.service_worker_origin &&
- registration.key.region_id == key_.region_id;
- }
+GeofencingManager::~GeofencingManager() {
+}
- private:
- const RegistrationKey& key_;
-};
+void GeofencingManager::Init() {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ BrowserThread::PostTask(BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(&GeofencingManager::InitOnIO, this));
+}
-GeofencingManager::GeofencingManager() {
+void GeofencingManager::Shutdown() {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ BrowserThread::PostTask(BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(&GeofencingManager::ShutdownOnIO, this));
}
-GeofencingManager::~GeofencingManager() {
+void GeofencingManager::InitOnIO() {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ service_ = GeofencingServiceImpl::GetInstance();
}
-GeofencingManager* GeofencingManager::GetInstance() {
+void GeofencingManager::ShutdownOnIO() {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
- return Singleton<GeofencingManager>::get();
+ // Clean up all registrations with the |GeofencingService|.
+ // TODO(mek): This will need to change to support geofence registrations that
+ // outlive the browser, although removing the references to this
+ // |GeofencingManager| from the |GeofencingService| will still be needed.
+ for (const auto& registration : registrations_by_id_) {
+ service_->UnregisterRegion(registration.first);
+ }
}
void GeofencingManager::RegisterRegion(
- BrowserContext* browser_context,
int64 service_worker_registration_id,
- const GURL& service_worker_origin,
const std::string& region_id,
const blink::WebCircularGeofencingRegion& region,
const StatusCallback& callback) {
@@ -105,148 +98,148 @@ void GeofencingManager::RegisterRegion(
// TODO(mek): Validate region_id and region.
- if (!provider_.get()) {
- callback.Run(GeofencingStatus::
- GEOFENCING_STATUS_OPERATION_FAILED_SERVICE_NOT_AVAILABLE);
+ if (!service_->IsServiceAvailable()) {
+ callback.Run(GEOFENCING_STATUS_OPERATION_FAILED_SERVICE_NOT_AVAILABLE);
return;
}
- RegistrationKey key(browser_context,
- service_worker_registration_id,
- service_worker_origin,
- region_id);
- if (FindRegistration(key)) {
+ if (FindRegistration(service_worker_registration_id, region_id)) {
// Already registered, return an error.
- callback.Run(GeofencingStatus::GEOFENCING_STATUS_ERROR);
+ // TODO(mek): Use a more specific error code.
+ callback.Run(GEOFENCING_STATUS_ERROR);
return;
}
- // Add registration, but don't mark it as active yet. This prevents duplicate
- // registrations.
- AddRegistration(key, region);
-
- // Register with provider.
- provider_->RegisterRegion(
- region,
- base::Bind(&GeofencingManager::RegisterRegionCompleted,
- base::Unretained(this),
- callback,
- key));
+ AddRegistration(service_worker_registration_id,
+ region_id,
+ region,
+ callback,
+ service_->RegisterRegion(region, this));
}
-void GeofencingManager::UnregisterRegion(BrowserContext* browser_context,
- int64 service_worker_registration_id,
- const GURL& service_worker_origin,
+void GeofencingManager::UnregisterRegion(int64 service_worker_registration_id,
const std::string& region_id,
const StatusCallback& callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
// TODO(mek): Validate region_id.
- if (!provider_.get()) {
- callback.Run(GeofencingStatus::
- GEOFENCING_STATUS_OPERATION_FAILED_SERVICE_NOT_AVAILABLE);
+ if (!service_->IsServiceAvailable()) {
+ callback.Run(GEOFENCING_STATUS_OPERATION_FAILED_SERVICE_NOT_AVAILABLE);
return;
}
- RegistrationKey key(browser_context,
- service_worker_registration_id,
- service_worker_origin,
- region_id);
- Registration* registration = FindRegistration(key);
+ Registration* registration =
+ FindRegistration(service_worker_registration_id, region_id);
if (!registration) {
- // Not registered, return an error/
- callback.Run(GeofencingStatus::GEOFENCING_STATUS_ERROR);
+ // Not registered, return an error.
+ callback.Run(GEOFENCING_STATUS_UNREGISTRATION_FAILED_NOT_REGISTERED);
return;
}
- if (!registration->is_active) {
+ if (!registration->is_active()) {
// Started registration, but not completed yet, error.
- callback.Run(GeofencingStatus::GEOFENCING_STATUS_ERROR);
+ callback.Run(GEOFENCING_STATUS_UNREGISTRATION_FAILED_NOT_REGISTERED);
return;
}
- if (registration->registration_id != -1) {
- provider_->UnregisterRegion(registration->registration_id);
- }
- ClearRegistration(key);
- callback.Run(GeofencingStatus::GEOFENCING_STATUS_OK);
+ service_->UnregisterRegion(registration->geofencing_registration_id);
+ ClearRegistration(registration);
+ callback.Run(GEOFENCING_STATUS_OK);
}
GeofencingStatus GeofencingManager::GetRegisteredRegions(
- BrowserContext* browser_context,
int64 service_worker_registration_id,
- const GURL& service_worker_origin,
std::map<std::string, blink::WebCircularGeofencingRegion>* result) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
CHECK(result);
- if (!provider_.get()) {
- return GeofencingStatus::
- GEOFENCING_STATUS_OPERATION_FAILED_SERVICE_NOT_AVAILABLE;
+ if (!service_->IsServiceAvailable()) {
+ return GEOFENCING_STATUS_OPERATION_FAILED_SERVICE_NOT_AVAILABLE;
}
// Populate result, filtering out inactive registrations.
result->clear();
- for (const auto& registration : registrations_) {
- if (registration.key.browser_context == browser_context &&
- registration.key.service_worker_registration_id ==
- service_worker_registration_id &&
- registration.key.service_worker_origin == service_worker_origin &&
- registration.is_active) {
- (*result)[registration.key.region_id] = registration.region;
- }
+ ServiceWorkerRegistrationsMap::iterator registrations =
+ registrations_.find(service_worker_registration_id);
+ if (registrations == registrations_.end())
+ return GEOFENCING_STATUS_OK;
+ for (const auto& registration : registrations->second) {
+ if (registration.second.is_active())
+ (*result)[registration.first] = registration.second.region;
}
- return GeofencingStatus::GEOFENCING_STATUS_OK;
+ return GEOFENCING_STATUS_OK;
}
-void GeofencingManager::RegisterRegionCompleted(const StatusCallback& callback,
- const RegistrationKey& key,
- GeofencingStatus status,
- int registration_id) {
+void GeofencingManager::RegistrationFinished(int64 geofencing_registration_id,
+ GeofencingStatus status) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
- if (status != GEOFENCING_STATUS_OK) {
- ClearRegistration(key);
- callback.Run(status);
- return;
- }
-
- Registration* registration = FindRegistration(key);
+ Registration* registration = FindRegistrationById(geofencing_registration_id);
DCHECK(registration);
- registration->registration_id = registration_id;
- registration->is_active = true;
- callback.Run(GeofencingStatus::GEOFENCING_STATUS_OK);
-}
+ DCHECK(!registration->is_active());
+ registration->registration_callback.Run(status);
+ registration->registration_callback.Reset();
-void GeofencingManager::SetProviderForTests(
- scoped_ptr<GeofencingProvider> provider) {
- DCHECK(!provider_.get());
- provider_ = provider.Pass();
+ // If the registration wasn't succesful, remove it from our storage.
+ if (status != GEOFENCING_STATUS_OK)
+ ClearRegistration(registration);
}
GeofencingManager::Registration* GeofencingManager::FindRegistration(
- const RegistrationKey& key) {
- std::vector<Registration>::iterator it = std::find_if(
- registrations_.begin(), registrations_.end(), RegistrationMatches(key));
- if (it == registrations_.end())
+ int64 service_worker_registration_id,
+ const std::string& region_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ ServiceWorkerRegistrationsMap::iterator registrations_iterator =
+ registrations_.find(service_worker_registration_id);
+ if (registrations_iterator == registrations_.end())
+ return nullptr;
+ RegionIdRegistrationMap::iterator registration =
+ registrations_iterator->second.find(region_id);
+ if (registration == registrations_iterator->second.end())
return nullptr;
- return &*it;
+ return &registration->second;
+}
+
+GeofencingManager::Registration* GeofencingManager::FindRegistrationById(
+ int64 geofencing_registration_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ RegistrationIdRegistrationMap::iterator registration_iterator =
+ registrations_by_id_.find(geofencing_registration_id);
+ if (registration_iterator == registrations_by_id_.end())
+ return nullptr;
+ return &registration_iterator->second->second;
}
GeofencingManager::Registration& GeofencingManager::AddRegistration(
- const RegistrationKey& key,
- const blink::WebCircularGeofencingRegion& region) {
- DCHECK(!FindRegistration(key));
- registrations_.push_back(Registration(key, region));
- return registrations_.back();
+ int64 service_worker_registration_id,
+ const std::string& region_id,
+ const blink::WebCircularGeofencingRegion& region,
+ const StatusCallback& callback,
+ int64 geofencing_registration_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ DCHECK(!FindRegistration(service_worker_registration_id, region_id));
+ RegionIdRegistrationMap::iterator registration =
+ registrations_[service_worker_registration_id]
+ .insert(std::make_pair(region_id,
+ Registration(service_worker_registration_id,
+ region_id,
+ region,
+ callback,
+ geofencing_registration_id)))
+ .first;
+ registrations_by_id_[geofencing_registration_id] = registration;
+ return registration->second;
}
-void GeofencingManager::ClearRegistration(const RegistrationKey& key) {
- std::vector<Registration>::iterator it = std::find_if(
- registrations_.begin(), registrations_.end(), RegistrationMatches(key));
- if (it == registrations_.end())
- return;
- registrations_.erase(it);
+void GeofencingManager::ClearRegistration(Registration* registration) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ registrations_by_id_.erase(registration->geofencing_registration_id);
+ ServiceWorkerRegistrationsMap::iterator registrations_iterator =
+ registrations_.find(registration->service_worker_registration_id);
+ DCHECK(registrations_iterator != registrations_.end());
+ registrations_iterator->second.erase(registration->region_id);
+ if (registrations_iterator->second.empty())
+ registrations_.erase(registrations_iterator);
}
} // namespace content
diff --git a/content/browser/geofencing/geofencing_manager.h b/content/browser/geofencing/geofencing_manager.h
index cae5edd..d5842b3 100644
--- a/content/browser/geofencing/geofencing_manager.h
+++ b/content/browser/geofencing/geofencing_manager.h
@@ -11,7 +11,9 @@
#include "base/callback_forward.h"
#include "base/macros.h"
+#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
+#include "content/browser/geofencing/geofencing_registration_delegate.h"
#include "content/common/content_export.h"
#include "content/common/geofencing_status.h"
@@ -25,34 +27,30 @@ struct WebCircularGeofencingRegion;
namespace content {
-class BrowserContext;
-class GeofencingProvider;
+class GeofencingService;
+class ServiceWorkerContextWrapper;
-// This is the main API to the geofencing subsystem. The application will hold
-// a single instance of this class.
+// This is the main API to the geofencing subsystem. There is one instance of
+// this class per storage partition.
// This class is responsible for keeping track of which geofences are currently
// registered by websites/workers, persisting this list of registrations and
-// registering a subset of these active registrations with the underlying
-// platform specific |GeofencingProvider| instance.
-// This class lives on the IO thread, and all public methods of it should only
-// ever be called from that same thread.
-// FIXME: Does it make more sense for this to live on the UI thread instead of
-// the IO thread?
+// registering them with the global |GeofencingService|.
+// This class is created on the UI thread, but all its methods should only be
+// called from the IO thread.
// TODO(mek): Implement some kind of persistence of registrations.
-// TODO(mek): Limit the number of geofences that are registered with the
-// underlying GeofencingProvider.
-class CONTENT_EXPORT GeofencingManager {
+class CONTENT_EXPORT GeofencingManager
+ : NON_EXPORTED_BASE(public GeofencingRegistrationDelegate),
+ public base::RefCountedThreadSafe<GeofencingManager> {
public:
typedef base::Callback<void(GeofencingStatus)> StatusCallback;
- typedef base::Callback<void(
- GeofencingStatus,
- const std::map<std::string, blink::WebCircularGeofencingRegion>&)>
- RegistrationsCallback;
- // Gets a pointer to the singleton instance of the geofencing manager. This
- // must only be called on the IO thread so that the GeofencingManager is
- // always instantiated on the same thread. Ownership is NOT returned.
- static GeofencingManager* GetInstance();
+ explicit GeofencingManager(
+ const scoped_refptr<ServiceWorkerContextWrapper>& service_worker_context);
+
+ // Init and Shutdown are for use on the UI thread when the storagepartition is
+ // being setup and torn down.
+ void Init();
+ void Shutdown();
// Initiates registration of a new geofence. StatusCallback is called when
// registration has completed or failed (which could possibly be before
@@ -61,9 +59,7 @@ class CONTENT_EXPORT GeofencingManager {
// (or in progress of being registered) region will fail.
// TODO(mek): Behavior when using an already used ID might need to be revised
// depending on what the actual spec ends up saying about this.
- void RegisterRegion(BrowserContext* browser_context,
- int64 service_worker_registration_id,
- const GURL& service_worker_origin,
+ void RegisterRegion(int64 service_worker_registration_id,
const std::string& region_id,
const blink::WebCircularGeofencingRegion& region,
const StatusCallback& callback);
@@ -74,9 +70,7 @@ class CONTENT_EXPORT GeofencingManager {
// (RegisterRegion hasn't called its callback yet) will fail.
// TODO(mek): Maybe better behavior would be to allow unregistering still
// in-progress registrations.
- void UnregisterRegion(BrowserContext* browser_context,
- int64 service_worker_registration_id,
- const GURL& service_worker_origin,
+ void UnregisterRegion(int64 service_worker_registration_id,
const std::string& region_id,
const StatusCallback& callback);
@@ -87,51 +81,64 @@ class CONTENT_EXPORT GeofencingManager {
// has been called already (so it doesn't include still in progress
// registrations).
GeofencingStatus GetRegisteredRegions(
- BrowserContext* browser_context,
int64 service_worker_registration_id,
- const GURL& service_worker_origin,
- std::map<std::string, blink::WebCircularGeofencingRegion>* regions);
+ std::map<std::string, blink::WebCircularGeofencingRegion>* result);
- void SetProviderForTests(scoped_ptr<GeofencingProvider> provider);
+ void SetServiceForTesting(GeofencingService* service) {
+ service_ = service;
+ }
protected:
- friend struct DefaultSingletonTraits<GeofencingManager>;
- friend class GeofencingManagerTest;
- GeofencingManager();
- virtual ~GeofencingManager();
+ friend class base::RefCountedThreadSafe<GeofencingManager>;
+ ~GeofencingManager() override;
private:
// Internal bookkeeping associated with each registered geofence.
- struct RegistrationKey;
struct Registration;
- class RegistrationMatches;
- // Called by GeofencingProvider when the platform specific provider completes
- // registration of a geofence.
- void RegisterRegionCompleted(const StatusCallback& callback,
- const RegistrationKey& key,
- GeofencingStatus status,
- int registration_id);
+ void InitOnIO();
+ void ShutdownOnIO();
+
+ // GeofencingRegistrationDelegate implementation.
+ void RegistrationFinished(int64 geofencing_registration_id,
+ GeofencingStatus status) override;
// Looks up a particular geofence registration. Returns nullptr if no
// registration with the given IDs exists.
- Registration* FindRegistration(const RegistrationKey& key);
+ Registration* FindRegistration(int64 service_worker_registration_id,
+ const std::string& region_id);
+
+ // Looks up a particular geofence registration. Returns nullptr if no
+ // registration with the given ID exists.
+ Registration* FindRegistrationById(int64 geofencing_registration_id);
// Registers a new registration, returning a reference to the newly inserted
// object. Assumes no registration with the same IDs currently exists.
Registration& AddRegistration(
- const RegistrationKey& key,
- const blink::WebCircularGeofencingRegion& region);
+ int64 service_worker_registration_id,
+ const std::string& region_id,
+ const blink::WebCircularGeofencingRegion& region,
+ const StatusCallback& callback,
+ int64 geofencing_registration_id);
// Clears a registration.
- void ClearRegistration(const RegistrationKey& key);
-
- // List of all currently registered geofences.
- // TODO(mek): Better way of storing these that allows more efficient lookup
- // and deletion.
- std::vector<Registration> registrations_;
-
- scoped_ptr<GeofencingProvider> provider_;
+ void ClearRegistration(Registration* registration);
+
+ // Map of all registered regions for a particular service worker registration.
+ typedef std::map<std::string, Registration> RegionIdRegistrationMap;
+ // Map of service worker registration id to the regions registered by that
+ // service worker.
+ typedef std::map<int64, RegionIdRegistrationMap>
+ ServiceWorkerRegistrationsMap;
+ ServiceWorkerRegistrationsMap registrations_;
+
+ // Map of all registered regions by geofencing_registration_id.
+ typedef std::map<int64, RegionIdRegistrationMap::iterator>
+ RegistrationIdRegistrationMap;
+ RegistrationIdRegistrationMap registrations_by_id_;
+
+ GeofencingService* service_;
+ scoped_refptr<ServiceWorkerContextWrapper> service_worker_context_;
DISALLOW_COPY_AND_ASSIGN(GeofencingManager);
};
diff --git a/content/browser/geofencing/geofencing_manager_unittest.cc b/content/browser/geofencing/geofencing_manager_unittest.cc
index 78828ac..6970b71 100644
--- a/content/browser/geofencing/geofencing_manager_unittest.cc
+++ b/content/browser/geofencing/geofencing_manager_unittest.cc
@@ -5,14 +5,13 @@
#include "base/callback.h"
#include "base/message_loop/message_loop.h"
#include "content/browser/geofencing/geofencing_manager.h"
-#include "content/browser/geofencing/geofencing_provider.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/test/test_browser_thread.h"
+#include "content/browser/geofencing/geofencing_service.h"
+#include "content/browser/service_worker/service_worker_context_wrapper.h"
+#include "content/public/test/test_browser_thread_bundle.h"
#include "content/public/test/test_utils.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/WebKit/public/platform/WebCircularGeofencingRegion.h"
-#include "url/gurl.h"
using blink::WebCircularGeofencingRegion;
typedef std::map<std::string, WebCircularGeofencingRegion> RegionMap;
@@ -22,6 +21,8 @@ namespace {
static const char* kTestRegionId = "region-id";
static const int64 kTestServiceWorkerRegistrationId = 123;
static const int64 kTestServiceWorkerRegistrationId2 = 456;
+static const int64 kTestGeofencingRegistrationId = 42;
+static const int64 kTestGeofencingRegistrationId2 = 43;
bool RegionsMatch(const WebCircularGeofencingRegion& expected,
const WebCircularGeofencingRegion& arg) {
@@ -33,20 +34,21 @@ bool RegionsMatch(const WebCircularGeofencingRegion& expected,
namespace content {
-class TestGeofencingProvider : public GeofencingProvider {
+class TestGeofencingService : public GeofencingService {
public:
+ MOCK_METHOD0(IsServiceAvailable, bool());
MOCK_METHOD2(RegisterRegion,
- void(const WebCircularGeofencingRegion& region,
- const RegisterCallback& callback));
- MOCK_METHOD1(UnregisterRegion, void(int registration_id));
+ int64(const WebCircularGeofencingRegion& region,
+ GeofencingRegistrationDelegate* delegate));
+ MOCK_METHOD1(UnregisterRegion, void(int64 geofencing_registration_id));
};
-ACTION_P2(CallRegisterCallback, status, id) {
- arg1.Run(status, id);
+ACTION_P(SaveDelegate, delegate) {
+ *delegate = arg1;
}
-ACTION_P(SaveRegisterCallback, callback) {
- *callback = arg1;
+ACTION_P(QuitRunner, runner) {
+ runner->Quit();
}
MATCHER_P(WebCircularGeofencingRegionEq, expected, "") {
@@ -78,25 +80,30 @@ class StatusCatcher {
class GeofencingManagerTest : public testing::Test {
public:
- GeofencingManagerTest()
- : message_loop_(),
- io_thread_(BrowserThread::IO, &message_loop_),
- provider_(0),
- manager_(0),
- test_origin_("https://example.com/") {
+ GeofencingManagerTest() : service_(nullptr) {
test_region_.latitude = 37.421999;
test_region_.longitude = -122.084015;
test_region_.radius = 100;
expected_regions_[kTestRegionId] = test_region_;
}
- virtual void SetUp() { manager_ = new GeofencingManager(); }
+ virtual void SetUp() {
+ service_ = new TestGeofencingService();
+ ON_CALL(*service_, IsServiceAvailable())
+ .WillByDefault(testing::Return(false));
+ manager_ = new GeofencingManager(nullptr /* ServiceWorkerContextWrapper */);
+ manager_->SetServiceForTesting(service_);
+ }
- virtual void TearDown() { delete manager_; }
+ virtual void TearDown() {
+ manager_ = nullptr;
+ delete service_;
+ service_ = nullptr;
+ }
- void SetProviderForTests() {
- provider_ = new TestGeofencingProvider();
- manager_->SetProviderForTests(scoped_ptr<GeofencingProvider>(provider_));
+ void SetHasProviderForTests() {
+ ON_CALL(*service_, IsServiceAvailable())
+ .WillByDefault(testing::Return(true));
}
GeofencingStatus RegisterRegionSync(
@@ -105,48 +112,46 @@ class GeofencingManagerTest : public testing::Test {
const WebCircularGeofencingRegion& region) {
StatusCatcher result;
manager_->RegisterRegion(
- nullptr, /* browser_context */
service_worker_registration_id,
- test_origin_,
id,
region,
base::Bind(&StatusCatcher::Done, base::Unretained(&result)));
return result.Wait();
}
- GeofencingStatus RegisterRegionSyncWithProviderResult(
+ GeofencingStatus RegisterRegionSyncWithServiceResult(
int64 service_worker_registration_id,
const std::string& id,
const WebCircularGeofencingRegion& region,
- GeofencingStatus provider_status,
- int provider_result) {
+ GeofencingStatus service_status,
+ int64 geofencing_registration_id) {
StatusCatcher result;
+ GeofencingRegistrationDelegate* delegate = 0;
EXPECT_CALL(
- *provider_,
+ *service_,
RegisterRegion(WebCircularGeofencingRegionEq(region), testing::_))
- .WillOnce(CallRegisterCallback(provider_status, provider_result));
+ .WillOnce(testing::DoAll(SaveDelegate(&delegate),
+ testing::Return(geofencing_registration_id)));
manager_->RegisterRegion(
- nullptr, /* browser_context */
service_worker_registration_id,
- test_origin_,
id,
region,
base::Bind(&StatusCatcher::Done, base::Unretained(&result)));
+ CHECK(delegate);
+ delegate->RegistrationFinished(geofencing_registration_id, service_status);
return result.Wait();
}
GeofencingStatus UnregisterRegionSync(int64 service_worker_registration_id,
const std::string& id,
- bool should_call_provider,
- int provider_id = 0) {
+ bool should_call_service,
+ int64 geofencing_registration_id = 0) {
StatusCatcher result;
- if (should_call_provider) {
- EXPECT_CALL(*provider_, UnregisterRegion(provider_id));
+ if (should_call_service) {
+ EXPECT_CALL(*service_, UnregisterRegion(geofencing_registration_id));
}
manager_->UnregisterRegion(
- nullptr, /* browser_context */
service_worker_registration_id,
- test_origin_,
id,
base::Bind(&StatusCatcher::Done, base::Unretained(&result)));
return result.Wait();
@@ -155,10 +160,8 @@ class GeofencingManagerTest : public testing::Test {
void VerifyRegions(int64 service_worker_registration_id,
const RegionMap& expected_regions) {
RegionMap regions;
- EXPECT_EQ(GeofencingStatus::GEOFENCING_STATUS_OK,
- manager_->GetRegisteredRegions(nullptr, /* browser_context */
- service_worker_registration_id,
- test_origin_,
+ EXPECT_EQ(GEOFENCING_STATUS_OK,
+ manager_->GetRegisteredRegions(service_worker_registration_id,
&regions));
EXPECT_EQ(expected_regions.size(), regions.size());
for (RegionMap::const_iterator it = expected_regions.begin();
@@ -170,236 +173,242 @@ class GeofencingManagerTest : public testing::Test {
}
protected:
- base::MessageLoop message_loop_;
- TestBrowserThread io_thread_;
- TestGeofencingProvider* provider_;
- GeofencingManager* manager_;
+ TestBrowserThreadBundle threads_;
+ TestGeofencingService* service_;
+ scoped_refptr<GeofencingManager> manager_;
WebCircularGeofencingRegion test_region_;
RegionMap expected_regions_;
- GURL test_origin_;
};
-TEST_F(GeofencingManagerTest, RegisterRegion_NoProvider) {
- EXPECT_EQ(GeofencingStatus::
- GEOFENCING_STATUS_OPERATION_FAILED_SERVICE_NOT_AVAILABLE,
+TEST_F(GeofencingManagerTest, RegisterRegion_NoService) {
+ EXPECT_EQ(GEOFENCING_STATUS_OPERATION_FAILED_SERVICE_NOT_AVAILABLE,
RegisterRegionSync(
kTestServiceWorkerRegistrationId, kTestRegionId, test_region_));
}
-TEST_F(GeofencingManagerTest, UnregisterRegion_NoProvider) {
- EXPECT_EQ(GeofencingStatus::
- GEOFENCING_STATUS_OPERATION_FAILED_SERVICE_NOT_AVAILABLE,
+TEST_F(GeofencingManagerTest, UnregisterRegion_NoService) {
+ EXPECT_EQ(GEOFENCING_STATUS_OPERATION_FAILED_SERVICE_NOT_AVAILABLE,
UnregisterRegionSync(
kTestServiceWorkerRegistrationId, kTestRegionId, false));
}
-TEST_F(GeofencingManagerTest, GetRegisteredRegions_NoProvider) {
+TEST_F(GeofencingManagerTest, GetRegisteredRegions_NoService) {
RegionMap regions;
- EXPECT_EQ(GeofencingStatus::
- GEOFENCING_STATUS_OPERATION_FAILED_SERVICE_NOT_AVAILABLE,
- manager_->GetRegisteredRegions(nullptr, /* browser_context */
- kTestServiceWorkerRegistrationId,
- test_origin_,
+ EXPECT_EQ(GEOFENCING_STATUS_OPERATION_FAILED_SERVICE_NOT_AVAILABLE,
+ manager_->GetRegisteredRegions(kTestServiceWorkerRegistrationId,
&regions));
EXPECT_TRUE(regions.empty());
}
-TEST_F(GeofencingManagerTest, RegisterRegion_FailsInProvider) {
- SetProviderForTests();
+TEST_F(GeofencingManagerTest, RegisterRegion_FailsInService) {
+ SetHasProviderForTests();
EXPECT_EQ(
- GeofencingStatus::GEOFENCING_STATUS_ERROR,
- RegisterRegionSyncWithProviderResult(kTestServiceWorkerRegistrationId,
- kTestRegionId,
- test_region_,
- GEOFENCING_STATUS_ERROR,
- -1));
+ GEOFENCING_STATUS_ERROR,
+ RegisterRegionSyncWithServiceResult(kTestServiceWorkerRegistrationId,
+ kTestRegionId,
+ test_region_,
+ GEOFENCING_STATUS_ERROR,
+ -1));
}
-TEST_F(GeofencingManagerTest, RegisterRegion_SucceedsInProvider) {
- SetProviderForTests();
+TEST_F(GeofencingManagerTest, RegisterRegion_SucceedsInService) {
+ SetHasProviderForTests();
EXPECT_EQ(
- GeofencingStatus::GEOFENCING_STATUS_OK,
- RegisterRegionSyncWithProviderResult(kTestServiceWorkerRegistrationId,
- kTestRegionId,
- test_region_,
- GEOFENCING_STATUS_OK,
- 0));
+ GEOFENCING_STATUS_OK,
+ RegisterRegionSyncWithServiceResult(kTestServiceWorkerRegistrationId,
+ kTestRegionId,
+ test_region_,
+ GEOFENCING_STATUS_OK,
+ kTestGeofencingRegistrationId));
VerifyRegions(kTestServiceWorkerRegistrationId, expected_regions_);
}
TEST_F(GeofencingManagerTest, RegisterRegion_AlreadyRegistered) {
- SetProviderForTests();
+ SetHasProviderForTests();
EXPECT_EQ(
- GeofencingStatus::GEOFENCING_STATUS_OK,
- RegisterRegionSyncWithProviderResult(kTestServiceWorkerRegistrationId,
- kTestRegionId,
- test_region_,
- GEOFENCING_STATUS_OK,
- 0));
+ GEOFENCING_STATUS_OK,
+ RegisterRegionSyncWithServiceResult(kTestServiceWorkerRegistrationId,
+ kTestRegionId,
+ test_region_,
+ GEOFENCING_STATUS_OK,
+ kTestGeofencingRegistrationId));
VerifyRegions(kTestServiceWorkerRegistrationId, expected_regions_);
WebCircularGeofencingRegion region2;
region2.latitude = 43.2;
region2.longitude = 1.45;
region2.radius = 8.5;
- EXPECT_EQ(GeofencingStatus::GEOFENCING_STATUS_ERROR,
+ EXPECT_EQ(GEOFENCING_STATUS_ERROR,
RegisterRegionSync(
kTestServiceWorkerRegistrationId, kTestRegionId, region2));
VerifyRegions(kTestServiceWorkerRegistrationId, expected_regions_);
}
TEST_F(GeofencingManagerTest, UnregisterRegion_NotRegistered) {
- SetProviderForTests();
- EXPECT_EQ(GeofencingStatus::GEOFENCING_STATUS_ERROR,
+ SetHasProviderForTests();
+ EXPECT_EQ(GEOFENCING_STATUS_UNREGISTRATION_FAILED_NOT_REGISTERED,
UnregisterRegionSync(
kTestServiceWorkerRegistrationId, kTestRegionId, false));
}
TEST_F(GeofencingManagerTest, UnregisterRegion_Success) {
- SetProviderForTests();
- int provider_id = 123;
-
- EXPECT_EQ(
- GeofencingStatus::GEOFENCING_STATUS_OK,
- RegisterRegionSyncWithProviderResult(kTestServiceWorkerRegistrationId,
- kTestRegionId,
- test_region_,
- GEOFENCING_STATUS_OK,
- provider_id));
+ SetHasProviderForTests();
EXPECT_EQ(
- GeofencingStatus::GEOFENCING_STATUS_OK,
- UnregisterRegionSync(
- kTestServiceWorkerRegistrationId, kTestRegionId, true, provider_id));
+ GEOFENCING_STATUS_OK,
+ RegisterRegionSyncWithServiceResult(kTestServiceWorkerRegistrationId,
+ kTestRegionId,
+ test_region_,
+ GEOFENCING_STATUS_OK,
+ kTestGeofencingRegistrationId));
+
+ EXPECT_EQ(GEOFENCING_STATUS_OK,
+ UnregisterRegionSync(kTestServiceWorkerRegistrationId,
+ kTestRegionId,
+ true,
+ kTestGeofencingRegistrationId));
VerifyRegions(kTestServiceWorkerRegistrationId, RegionMap());
}
TEST_F(GeofencingManagerTest, GetRegisteredRegions_RegistrationInProgress) {
- SetProviderForTests();
+ SetHasProviderForTests();
StatusCatcher result;
- GeofencingProvider::RegisterCallback callback;
+ GeofencingRegistrationDelegate* delegate = nullptr;
EXPECT_CALL(
- *provider_,
+ *service_,
RegisterRegion(WebCircularGeofencingRegionEq(test_region_), testing::_))
- .WillOnce(SaveRegisterCallback(&callback));
+ .WillOnce(testing::DoAll(SaveDelegate(&delegate),
+ testing::Return(kTestGeofencingRegistrationId)));
manager_->RegisterRegion(
- nullptr, /* browser_context */
kTestServiceWorkerRegistrationId,
- test_origin_,
kTestRegionId,
test_region_,
base::Bind(&StatusCatcher::Done, base::Unretained(&result)));
// At this point the manager should have tried registering the region with
- // the provider, resulting in |callback| being set. Until the callback is
+ // the service, resulting in |delegate| being set. Until the callback is
// called the registration is not complete though.
- EXPECT_FALSE(callback.is_null());
+ EXPECT_NE(delegate, nullptr);
VerifyRegions(kTestServiceWorkerRegistrationId, RegionMap());
// Now call the callback, and verify the registration completed succesfully.
- callback.Run(GEOFENCING_STATUS_OK, 123);
- EXPECT_EQ(GeofencingStatus::GEOFENCING_STATUS_OK, result.Wait());
+ delegate->RegistrationFinished(kTestGeofencingRegistrationId,
+ GEOFENCING_STATUS_OK);
+ EXPECT_EQ(GEOFENCING_STATUS_OK, result.Wait());
VerifyRegions(kTestServiceWorkerRegistrationId, expected_regions_);
}
TEST_F(GeofencingManagerTest, UnregisterRegion_RegistrationInProgress) {
- SetProviderForTests();
+ SetHasProviderForTests();
StatusCatcher result;
- GeofencingProvider::RegisterCallback callback;
+ GeofencingRegistrationDelegate* delegate = nullptr;
EXPECT_CALL(
- *provider_,
+ *service_,
RegisterRegion(WebCircularGeofencingRegionEq(test_region_), testing::_))
- .WillOnce(SaveRegisterCallback(&callback));
+ .WillOnce(testing::DoAll(SaveDelegate(&delegate),
+ testing::Return(kTestGeofencingRegistrationId)));
manager_->RegisterRegion(
- nullptr, /* browser_context */
kTestServiceWorkerRegistrationId,
- test_origin_,
kTestRegionId,
test_region_,
base::Bind(&StatusCatcher::Done, base::Unretained(&result)));
// At this point the manager should have tried registering the region with
- // the provider, resulting in |callback| being set. Until the callback is
+ // the service, resulting in |delegate| being set. Until the callback is
// called the registration is not complete though.
- EXPECT_FALSE(callback.is_null());
+ EXPECT_NE(delegate, nullptr);
- EXPECT_EQ(GeofencingStatus::GEOFENCING_STATUS_ERROR,
+ EXPECT_EQ(GEOFENCING_STATUS_UNREGISTRATION_FAILED_NOT_REGISTERED,
UnregisterRegionSync(
kTestServiceWorkerRegistrationId, kTestRegionId, false));
}
TEST_F(GeofencingManagerTest, GetRegisteredRegions_NoRegions) {
- SetProviderForTests();
+ SetHasProviderForTests();
VerifyRegions(kTestServiceWorkerRegistrationId, RegionMap());
}
TEST_F(GeofencingManagerTest, RegisterRegion_SeparateServiceWorkers) {
- SetProviderForTests();
- int provider_id1 = 12;
- int provider_id2 = 34;
+ SetHasProviderForTests();
EXPECT_EQ(
- GeofencingStatus::GEOFENCING_STATUS_OK,
- RegisterRegionSyncWithProviderResult(kTestServiceWorkerRegistrationId,
- kTestRegionId,
- test_region_,
- GEOFENCING_STATUS_OK,
- provider_id1));
+ GEOFENCING_STATUS_OK,
+ RegisterRegionSyncWithServiceResult(kTestServiceWorkerRegistrationId,
+ kTestRegionId,
+ test_region_,
+ GEOFENCING_STATUS_OK,
+ kTestGeofencingRegistrationId));
VerifyRegions(kTestServiceWorkerRegistrationId, expected_regions_);
VerifyRegions(kTestServiceWorkerRegistrationId2, RegionMap());
EXPECT_EQ(
- GeofencingStatus::GEOFENCING_STATUS_OK,
- RegisterRegionSyncWithProviderResult(kTestServiceWorkerRegistrationId2,
- kTestRegionId,
- test_region_,
- GEOFENCING_STATUS_OK,
- provider_id2));
+ GEOFENCING_STATUS_OK,
+ RegisterRegionSyncWithServiceResult(kTestServiceWorkerRegistrationId2,
+ kTestRegionId,
+ test_region_,
+ GEOFENCING_STATUS_OK,
+ kTestGeofencingRegistrationId2));
VerifyRegions(kTestServiceWorkerRegistrationId, expected_regions_);
VerifyRegions(kTestServiceWorkerRegistrationId2, expected_regions_);
}
TEST_F(GeofencingManagerTest, UnregisterRegion_SeparateServiceWorkers) {
- SetProviderForTests();
- int provider_id1 = 12;
- int provider_id2 = 34;
+ SetHasProviderForTests();
EXPECT_EQ(
- GeofencingStatus::GEOFENCING_STATUS_OK,
- RegisterRegionSyncWithProviderResult(kTestServiceWorkerRegistrationId,
- kTestRegionId,
- test_region_,
- GEOFENCING_STATUS_OK,
- provider_id1));
+ GEOFENCING_STATUS_OK,
+ RegisterRegionSyncWithServiceResult(kTestServiceWorkerRegistrationId,
+ kTestRegionId,
+ test_region_,
+ GEOFENCING_STATUS_OK,
+ kTestGeofencingRegistrationId));
EXPECT_EQ(
- GeofencingStatus::GEOFENCING_STATUS_OK,
- RegisterRegionSyncWithProviderResult(kTestServiceWorkerRegistrationId2,
- kTestRegionId,
- test_region_,
- GEOFENCING_STATUS_OK,
- provider_id2));
-
- EXPECT_EQ(
- GeofencingStatus::GEOFENCING_STATUS_OK,
- UnregisterRegionSync(
- kTestServiceWorkerRegistrationId, kTestRegionId, true, provider_id1));
+ GEOFENCING_STATUS_OK,
+ RegisterRegionSyncWithServiceResult(kTestServiceWorkerRegistrationId2,
+ kTestRegionId,
+ test_region_,
+ GEOFENCING_STATUS_OK,
+ kTestGeofencingRegistrationId2));
+
+ EXPECT_EQ(GEOFENCING_STATUS_OK,
+ UnregisterRegionSync(kTestServiceWorkerRegistrationId,
+ kTestRegionId,
+ true,
+ kTestGeofencingRegistrationId));
VerifyRegions(kTestServiceWorkerRegistrationId, RegionMap());
VerifyRegions(kTestServiceWorkerRegistrationId2, expected_regions_);
- EXPECT_EQ(GeofencingStatus::GEOFENCING_STATUS_OK,
+ EXPECT_EQ(GEOFENCING_STATUS_OK,
UnregisterRegionSync(kTestServiceWorkerRegistrationId2,
kTestRegionId,
true,
- provider_id2));
+ kTestGeofencingRegistrationId2));
VerifyRegions(kTestServiceWorkerRegistrationId, RegionMap());
VerifyRegions(kTestServiceWorkerRegistrationId2, RegionMap());
}
+TEST_F(GeofencingManagerTest, ShutdownCleansRegistrations) {
+ SetHasProviderForTests();
+ scoped_refptr<MessageLoopRunner> runner(new MessageLoopRunner());
+ EXPECT_EQ(
+ GEOFENCING_STATUS_OK,
+ RegisterRegionSyncWithServiceResult(kTestServiceWorkerRegistrationId,
+ kTestRegionId,
+ test_region_,
+ GEOFENCING_STATUS_OK,
+ kTestGeofencingRegistrationId));
+
+ EXPECT_CALL(*service_, UnregisterRegion(kTestGeofencingRegistrationId))
+ .WillOnce(QuitRunner(runner));
+ manager_->Shutdown();
+ runner->Run();
+}
+
} // namespace content
diff --git a/content/browser/geofencing/geofencing_provider.h b/content/browser/geofencing/geofencing_provider.h
index ab5faa0..dec96b5 100644
--- a/content/browser/geofencing/geofencing_provider.h
+++ b/content/browser/geofencing/geofencing_provider.h
@@ -5,6 +5,7 @@
#ifndef CONTENT_BROWSER_GEOFENCING_GEOFENCING_PROVIDER_H_
#define CONTENT_BROWSER_GEOFENCING_GEOFENCING_PROVIDER_H_
+#include "base/basictypes.h"
#include "base/callback_forward.h"
#include "content/common/geofencing_status.h"
@@ -16,28 +17,26 @@ namespace content {
class GeofencingProvider {
public:
- // Callback that gets called on completion of registering a new region. The
- // status indicates success or failure, and in case of success, an id to use
- // to later unregister the region is passed as |registration_id|. If
- // registration failed, providers should set |registration_id| to -1.
- typedef base::Callback<void(GeofencingStatus, int registration_id)>
- RegisterCallback;
+ typedef base::Callback<void(GeofencingStatus)> StatusCallback;
virtual ~GeofencingProvider() {}
- // Called by |GeofencingManager| to register a new fence. GeofencingManager is
+ // Called by |GeofencingService| to register a new fence. GeofencingService is
// responsible for handling things like duplicate regions, so platform
// specific implementations shouldn't have to worry about things like that.
- // Also GeofencingManager should be making sure the total number of geofences
+ // Also GeofencingService should be making sure the total number of geofences
// that is registered with the platform specific provider does not exceed the
// number of regions supported by the platform, although that isn't
// implemented yet.
- virtual void RegisterRegion(const blink::WebCircularGeofencingRegion& region,
- const RegisterCallback& callback) = 0;
+ // Implementations of RegisterRegion must asynchronously call the |callback|
+ // to indicate success or failure.
+ virtual void RegisterRegion(int64 geofencing_registration_id,
+ const blink::WebCircularGeofencingRegion& region,
+ const StatusCallback& callback) = 0;
- // Called by |GeofencingManager| to unregister an existing registration. Will
+ // Called by |GeofencingService| to unregister an existing registration. Will
// only be called once for each registration.
- virtual void UnregisterRegion(int registration_id) = 0;
+ virtual void UnregisterRegion(int64 geofencing_registration_id) = 0;
};
} // namespace content
diff --git a/content/browser/geofencing/geofencing_registration_delegate.h b/content/browser/geofencing/geofencing_registration_delegate.h
new file mode 100644
index 0000000..ba7836c
--- /dev/null
+++ b/content/browser/geofencing/geofencing_registration_delegate.h
@@ -0,0 +1,29 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_GEOFENCING_GEOFENCING_REGISTRATION_DELEGATE_H_
+#define CONTENT_BROWSER_GEOFENCING_GEOFENCING_REGISTRATION_DELEGATE_H_
+
+#include "base/basictypes.h"
+#include "content/common/geofencing_status.h"
+
+namespace content {
+
+// |GeofencingService| has an instance of this class associated with each
+// geofence registration, and uses it to inform about events related to the
+// registration, such as the geofence finishing being registered.
+// These methods will always be called on the IO thread.
+// TODO(mek): Add methods for geofence enter/leave events.
+class GeofencingRegistrationDelegate {
+ public:
+ virtual void RegistrationFinished(int64 geofencing_registration_id,
+ GeofencingStatus status) = 0;
+
+ protected:
+ virtual ~GeofencingRegistrationDelegate() {}
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_GEOFENCING_GEOFENCING_REGISTRATION_DELEGATE_H_
diff --git a/content/browser/geofencing/geofencing_service.cc b/content/browser/geofencing/geofencing_service.cc
new file mode 100644
index 0000000..11df952
--- /dev/null
+++ b/content/browser/geofencing/geofencing_service.cc
@@ -0,0 +1,199 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/geofencing/geofencing_service.h"
+
+#include "base/memory/singleton.h"
+#include "base/message_loop/message_loop.h"
+#include "content/browser/geofencing/geofencing_provider.h"
+#include "content/browser/geofencing/geofencing_registration_delegate.h"
+#include "content/public/browser/browser_thread.h"
+#include "third_party/WebKit/public/platform/WebCircularGeofencingRegion.h"
+
+namespace content {
+
+namespace {
+
+void RunSoon(const base::Closure& callback) {
+ if (!callback.is_null())
+ base::MessageLoop::current()->PostTask(FROM_HERE, callback);
+}
+
+} // namespace
+
+struct GeofencingServiceImpl::Registration {
+ Registration();
+ Registration(const blink::WebCircularGeofencingRegion& region,
+ int64 geofencing_registration_id,
+ GeofencingRegistrationDelegate* delegate);
+
+ blink::WebCircularGeofencingRegion region;
+ int64 geofencing_registration_id;
+ GeofencingRegistrationDelegate* delegate;
+
+ enum RegistrationState {
+ // In progress of being registered with provider.
+ STATE_REGISTERING,
+ // Currently registered with provider.
+ STATE_REGISTERED,
+ // In progress of being registered with provider, but should be unregistered
+ // and deleted.
+ STATE_SHOULD_UNREGISTER_AND_DELETE,
+ // Not currently registered with provider, but still an active registration.
+ STATE_UNREGISTERED
+ };
+ RegistrationState state;
+};
+
+GeofencingServiceImpl::Registration::Registration()
+ : geofencing_registration_id(-1),
+ delegate(nullptr),
+ state(STATE_UNREGISTERED) {
+}
+
+GeofencingServiceImpl::Registration::Registration(
+ const blink::WebCircularGeofencingRegion& region,
+ int64 geofencing_registration_id,
+ GeofencingRegistrationDelegate* delegate)
+ : region(region),
+ geofencing_registration_id(geofencing_registration_id),
+ delegate(delegate),
+ state(STATE_REGISTERING) {
+}
+
+GeofencingServiceImpl::GeofencingServiceImpl() : next_registration_id_(0) {
+}
+
+GeofencingServiceImpl::~GeofencingServiceImpl() {
+}
+
+GeofencingServiceImpl* GeofencingServiceImpl::GetInstance() {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ return Singleton<GeofencingServiceImpl>::get();
+}
+
+bool GeofencingServiceImpl::IsServiceAvailable() {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ return EnsureProvider();
+}
+
+int64 GeofencingServiceImpl::RegisterRegion(
+ const blink::WebCircularGeofencingRegion& region,
+ GeofencingRegistrationDelegate* delegate) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ int64 geofencing_registration_id = GetNextId();
+ registrations_[geofencing_registration_id] =
+ Registration(region, geofencing_registration_id, delegate);
+
+ if (!EnsureProvider()) {
+ RunSoon(
+ base::Bind(&GeofencingServiceImpl::NotifyRegistrationFinished,
+ base::Unretained(this),
+ geofencing_registration_id,
+ GEOFENCING_STATUS_OPERATION_FAILED_SERVICE_NOT_AVAILABLE));
+ return geofencing_registration_id;
+ }
+
+ provider_->RegisterRegion(
+ geofencing_registration_id,
+ region,
+ base::Bind(&GeofencingServiceImpl::NotifyRegistrationFinished,
+ base::Unretained(this),
+ geofencing_registration_id));
+ return geofencing_registration_id;
+}
+
+void GeofencingServiceImpl::UnregisterRegion(int64 geofencing_registration_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ RegistrationsMap::iterator registration_iterator =
+ registrations_.find(geofencing_registration_id);
+ DCHECK(registration_iterator != registrations_.end());
+
+ if (!EnsureProvider())
+ return;
+
+ switch (registration_iterator->second.state) {
+ case Registration::STATE_REGISTERED:
+ provider_->UnregisterRegion(geofencing_registration_id);
+ // fallthru
+ case Registration::STATE_UNREGISTERED:
+ registrations_.erase(registration_iterator);
+ break;
+ case Registration::STATE_REGISTERING:
+ // Update state, NotifyRegistrationFinished will take care of actually
+ // unregistering.
+ registration_iterator->second.state =
+ Registration::STATE_SHOULD_UNREGISTER_AND_DELETE;
+ break;
+ case Registration::STATE_SHOULD_UNREGISTER_AND_DELETE:
+ // Should not happen.
+ NOTREACHED();
+ break;
+ }
+}
+
+void GeofencingServiceImpl::SetProviderForTesting(
+ scoped_ptr<GeofencingProvider> provider) {
+ DCHECK(!provider_.get());
+ provider_ = provider.Pass();
+}
+
+int GeofencingServiceImpl::RegistrationCountForTesting() {
+ return registrations_.size();
+}
+
+bool GeofencingServiceImpl::EnsureProvider() {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ if (!provider_) {
+ // TODO(mek): Create platform specific provider.
+ return false;
+ }
+ return true;
+}
+
+int64 GeofencingServiceImpl::GetNextId() {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ return next_registration_id_++;
+}
+
+void GeofencingServiceImpl::NotifyRegistrationFinished(
+ int64 geofencing_registration_id,
+ GeofencingStatus status) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ RegistrationsMap::iterator registration_iterator =
+ registrations_.find(geofencing_registration_id);
+ DCHECK(registration_iterator != registrations_.end());
+ DCHECK(registration_iterator->second.state ==
+ Registration::STATE_REGISTERING ||
+ registration_iterator->second.state ==
+ Registration::STATE_SHOULD_UNREGISTER_AND_DELETE);
+
+ if (registration_iterator->second.state ==
+ Registration::STATE_SHOULD_UNREGISTER_AND_DELETE) {
+ // Don't call delegate, but unregister with provider if registration was
+ // succesfull.
+ if (status == GEOFENCING_STATUS_OK) {
+ provider_->UnregisterRegion(geofencing_registration_id);
+ }
+ registrations_.erase(registration_iterator);
+ return;
+ }
+
+ // Normal case, mark as registered and call delegate.
+ registration_iterator->second.state = Registration::STATE_REGISTERED;
+ registration_iterator->second.delegate->RegistrationFinished(
+ geofencing_registration_id, status);
+
+ if (status != GEOFENCING_STATUS_OK) {
+ // Registration failed, remove from our book-keeping.
+ registrations_.erase(registration_iterator);
+ }
+}
+
+} // namespace content
diff --git a/content/browser/geofencing/geofencing_service.h b/content/browser/geofencing/geofencing_service.h
new file mode 100644
index 0000000..dc3d832
--- /dev/null
+++ b/content/browser/geofencing/geofencing_service.h
@@ -0,0 +1,105 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_GEOFENCING_GEOFENCING_SERVICE_H_
+#define CONTENT_BROWSER_GEOFENCING_GEOFENCING_SERVICE_H_
+
+#include <map>
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "content/common/content_export.h"
+#include "content/common/geofencing_status.h"
+
+template <typename T>
+struct DefaultSingletonTraits;
+
+namespace blink {
+struct WebCircularGeofencingRegion;
+};
+
+namespace content {
+
+class GeofencingProvider;
+class GeofencingRegistrationDelegate;
+
+// This interface exists primarily to facilitate testing of classes that depend
+// on GeofencingService. It defines the interface exposed by
+// |GeofencingService|.
+class GeofencingService {
+ public:
+ virtual ~GeofencingService() {}
+
+ // Returns if a geofencing service is available.
+ virtual bool IsServiceAvailable() = 0;
+
+ // Register a region. This returns a unique registration ID, and
+ // asynchronously calls the |delegate|s RegistrationFinished method to
+ // inform the delegate of the result of the attempt to register the region.
+ // This does not transfer ownership of the |delegate|. Callers have to ensure
+ // that the delegate remains valid as long as the region is registered.
+ virtual int64 RegisterRegion(const blink::WebCircularGeofencingRegion& region,
+ GeofencingRegistrationDelegate* delegate) = 0;
+
+ // Unregister a region. This is assumed to always succeed. It is safe to call
+ // this even if a registration is still in progress.
+ virtual void UnregisterRegion(int64 geofencing_registration_id) = 0;
+};
+
+// This class combines all the geofence registrations from the various per
+// storage partition |GeofencingManager| instances, and registers a subset
+// of those fences with an underlying platform specific |GeofencingProvider|.
+// TODO(mek): Limit the number of geofences that are registered with the
+// underlying GeofencingProvider.
+class CONTENT_EXPORT GeofencingServiceImpl
+ : NON_EXPORTED_BASE(public GeofencingService) {
+ public:
+ // Gets a pointer to the singleton instance of the geofencing service. This
+ // must only be called on the IO thread so that the GeofencingService is
+ // always instantiated on the same thread. Ownership is NOT returned.
+ static GeofencingServiceImpl* GetInstance();
+
+ // GeofencingServiceInterface implementation.
+ bool IsServiceAvailable() override;
+ int64 RegisterRegion(
+ const blink::WebCircularGeofencingRegion& region,
+ GeofencingRegistrationDelegate* delegate) override;
+ void UnregisterRegion(int64 geofencing_registration_id) override;
+
+ protected:
+ friend class GeofencingServiceTest;
+ friend struct DefaultSingletonTraits<GeofencingServiceImpl>;
+ GeofencingServiceImpl();
+ ~GeofencingServiceImpl() override;
+
+ void SetProviderForTesting(scoped_ptr<GeofencingProvider> provider);
+ int RegistrationCountForTesting();
+
+ private:
+ struct Registration;
+ typedef std::map<int64, Registration> RegistrationsMap;
+
+ // This method checks if a |GeofencingProvider| exists, creates a new one if
+ // not, and finally returns false if it can't create a provider for the
+ // current platform.
+ bool EnsureProvider();
+
+ // Returns a new unique ID to use for the next geofence registration.
+ int64 GetNextId();
+
+ // Notifies the correct delegate that registration has completed for a
+ // specific geofence registration.
+ void NotifyRegistrationFinished(int64 geofencing_registration_id,
+ GeofencingStatus status);
+
+ int64 next_registration_id_;
+ RegistrationsMap registrations_;
+ scoped_ptr<GeofencingProvider> provider_;
+
+ DISALLOW_COPY_AND_ASSIGN(GeofencingServiceImpl);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_GEOFENCING_GEOFENCING_SERVICE_H_
diff --git a/content/browser/geofencing/geofencing_service_unittest.cc b/content/browser/geofencing/geofencing_service_unittest.cc
new file mode 100644
index 0000000..329fcaf
--- /dev/null
+++ b/content/browser/geofencing/geofencing_service_unittest.cc
@@ -0,0 +1,191 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/geofencing/geofencing_provider.h"
+#include "content/browser/geofencing/geofencing_registration_delegate.h"
+#include "content/browser/geofencing/geofencing_service.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "content/public/test/test_utils.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/WebKit/public/platform/WebCircularGeofencingRegion.h"
+
+using blink::WebCircularGeofencingRegion;
+
+namespace {
+
+bool RegionsMatch(const WebCircularGeofencingRegion& expected,
+ const WebCircularGeofencingRegion& arg) {
+ return testing::Matches(expected.latitude)(arg.latitude) &&
+ testing::Matches(expected.longitude)(arg.longitude) &&
+ testing::Matches(expected.radius)(arg.radius);
+}
+
+} // namespace
+
+namespace content {
+
+class MockGeofencingRegistrationDelegate
+ : public GeofencingRegistrationDelegate {
+ public:
+ MOCK_METHOD2(RegistrationFinished,
+ void(int64 geofencing_registration_id, GeofencingStatus status));
+};
+
+class MockGeofencingProvider : public GeofencingProvider {
+ public:
+ MOCK_METHOD3(RegisterRegion,
+ void(int64 geofencing_registration_id,
+ const blink::WebCircularGeofencingRegion& region,
+ const StatusCallback& callback));
+ MOCK_METHOD1(UnregisterRegion, void(int64 geofencing_registration_id));
+};
+
+ACTION_P(QuitRunner, runner) {
+ runner->Quit();
+}
+
+ACTION_P(SaveRegistrationId, geofencing_registration_id) {
+ *geofencing_registration_id = arg0;
+}
+
+ACTION_P(SaveStatusCallback, callback) {
+ *callback = arg2;
+}
+
+MATCHER_P(WebCircularGeofencingRegionEq, expected, "") {
+ return RegionsMatch(expected, arg);
+}
+
+class GeofencingServiceTest : public testing::Test {
+ public:
+ GeofencingServiceTest() : service_(nullptr) {
+ test_region_.latitude = 37.421999;
+ test_region_.longitude = -122.084015;
+ test_region_.radius = 100;
+ }
+
+ virtual void SetUp() { service_ = new GeofencingServiceImpl(); }
+
+ virtual void TearDown() { delete service_; }
+
+ void SetProviderForTests() {
+ provider_ = new MockGeofencingProvider();
+ service_->SetProviderForTesting(make_scoped_ptr(provider_));
+ }
+
+ int RegistrationCount() { return service_->RegistrationCountForTesting(); }
+
+ int64 RegisterRegionSync(const WebCircularGeofencingRegion& region,
+ GeofencingStatus provider_status) {
+ scoped_refptr<MessageLoopRunner> runner(new MessageLoopRunner());
+
+ // The registration ID that is passed to the provider.
+ int64 provider_registration_id = -1;
+ // The callback that is passed to the provider.
+ GeofencingProvider::StatusCallback callback;
+
+ EXPECT_CALL(
+ *provider_,
+ RegisterRegion(
+ testing::_, WebCircularGeofencingRegionEq(region), testing::_))
+ .WillOnce(testing::DoAll(SaveRegistrationId(&provider_registration_id),
+ SaveStatusCallback(&callback)));
+
+ int64 geofencing_registration_id =
+ service_->RegisterRegion(region, &delegate_);
+
+ // Service should have synchronously called the provider.
+ CHECK(!callback.is_null());
+ CHECK(provider_registration_id == geofencing_registration_id);
+
+ // Finish up registration by calling the callback and waiting for the
+ // delegate to be called.
+ EXPECT_CALL(
+ delegate_,
+ RegistrationFinished(geofencing_registration_id, provider_status))
+ .WillOnce(QuitRunner(runner));
+ callback.Run(provider_status);
+ runner->Run();
+ return geofencing_registration_id;
+ }
+
+ protected:
+ TestBrowserThreadBundle threads_;
+ GeofencingServiceImpl* service_;
+ MockGeofencingProvider* provider_;
+ MockGeofencingRegistrationDelegate delegate_;
+
+ WebCircularGeofencingRegion test_region_;
+};
+
+TEST_F(GeofencingServiceTest, RegisterRegion_NoProvider) {
+ scoped_refptr<MessageLoopRunner> runner(new MessageLoopRunner());
+ int64 geofencing_registration_id =
+ service_->RegisterRegion(test_region_, &delegate_);
+ EXPECT_CALL(delegate_,
+ RegistrationFinished(
+ geofencing_registration_id,
+ GEOFENCING_STATUS_OPERATION_FAILED_SERVICE_NOT_AVAILABLE))
+ .WillOnce(QuitRunner(runner));
+ runner->Run();
+ EXPECT_EQ(0, RegistrationCount());
+}
+
+TEST_F(GeofencingServiceTest, RegisterRegion_FailsInProvider) {
+ SetProviderForTests();
+ RegisterRegionSync(test_region_, GEOFENCING_STATUS_ERROR);
+ EXPECT_EQ(0, RegistrationCount());
+}
+
+TEST_F(GeofencingServiceTest, RegisterRegion_SucceedsInProvider) {
+ SetProviderForTests();
+ RegisterRegionSync(test_region_, GEOFENCING_STATUS_OK);
+ EXPECT_EQ(1, RegistrationCount());
+}
+
+TEST_F(GeofencingServiceTest, UnregisterRegion_AfterRegistration) {
+ SetProviderForTests();
+ int geofencing_registration_id =
+ RegisterRegionSync(test_region_, GEOFENCING_STATUS_OK);
+ EXPECT_EQ(1, RegistrationCount());
+
+ EXPECT_CALL(*provider_, UnregisterRegion(geofencing_registration_id));
+ service_->UnregisterRegion(geofencing_registration_id);
+ EXPECT_EQ(0, RegistrationCount());
+}
+
+TEST_F(GeofencingServiceTest, UnregisterRegion_DuringSuccesfullRegistration) {
+ SetProviderForTests();
+ scoped_refptr<MessageLoopRunner> runner(new MessageLoopRunner());
+
+ // The callback that is passed to the provider.
+ GeofencingProvider::StatusCallback callback;
+
+ EXPECT_CALL(
+ *provider_,
+ RegisterRegion(
+ testing::_, WebCircularGeofencingRegionEq(test_region_), testing::_))
+ .WillOnce(SaveStatusCallback(&callback));
+
+ int64 geofencing_registration_id =
+ service_->RegisterRegion(test_region_, &delegate_);
+
+ // Service should have synchronously called the provider.
+ CHECK(!callback.is_null());
+
+ // Call unregister before registration is finished.
+ service_->UnregisterRegion(geofencing_registration_id);
+
+ // Finish up registration by calling the callback and waiting for the
+ // provider to be called. The delegate should not be called in this case.
+ EXPECT_CALL(delegate_, RegistrationFinished(testing::_, testing::_)).Times(0);
+ EXPECT_CALL(*provider_, UnregisterRegion(geofencing_registration_id))
+ .WillOnce(QuitRunner(runner));
+ callback.Run(GEOFENCING_STATUS_OK);
+ runner->Run();
+ EXPECT_EQ(0, RegistrationCount());
+}
+
+} // namespace content