1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
|
// 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.
// MSVC++ requires this to be set before any other includes to get M_PI.
#define _USE_MATH_DEFINES
#include "content/browser/geofencing/mock_geofencing_service.h"
#include <cmath>
#include "base/bind.h"
#include "base/message_loop/message_loop.h"
#include "content/browser/geofencing/geofencing_registration_delegate.h"
#include "third_party/WebKit/public/platform/WebCircularGeofencingRegion.h"
namespace content {
namespace {
void RegisterRegionResult(GeofencingRegistrationDelegate* delegate,
int64 geofencing_registration_id,
GeofencingStatus status) {
base::MessageLoop::current()->PostTask(
FROM_HERE,
base::Bind(&GeofencingRegistrationDelegate::RegistrationFinished,
base::Unretained(delegate), geofencing_registration_id,
status));
}
double DegreesToRadians(float degrees) {
return (M_PI * degrees) / 180.f;
}
double Haversin(double theta) {
double temp = sin(theta / 2);
return temp * temp;
}
// Calculates the distance in meters between two points with coordinates in
// degrees.
double Distance(double lat1, double long1, double lat2, double long2) {
double R = 6371000; // radius of earth in meters
double phi1 = DegreesToRadians(lat1);
double phi2 = DegreesToRadians(lat2);
double dphi = DegreesToRadians(lat2 - lat1);
double dlambda = DegreesToRadians(long2 - long1);
double haversine = Haversin(dphi) + cos(phi1) * cos(phi2) * Haversin(dlambda);
return 2 * R * asin(sqrt(haversine));
}
// Returns true iff the provided coordinate is inside the region.
bool PositionInRegion(double latitude,
double longitude,
const blink::WebCircularGeofencingRegion& region) {
return Distance(latitude, longitude, region.latitude, region.longitude) <=
region.radius;
}
}
struct MockGeofencingService::Registration {
blink::WebCircularGeofencingRegion region;
GeofencingRegistrationDelegate* delegate;
// True iff the last event emitted for this region was a RegionEntered event.
bool is_inside;
};
MockGeofencingService::MockGeofencingService(bool service_available)
: available_(service_available),
next_id_(0),
has_position_(false),
last_latitude_(0),
last_longitude_(0) {
}
MockGeofencingService::~MockGeofencingService() {
}
void MockGeofencingService::SetMockPosition(double latitude, double longitude) {
has_position_ = true;
last_latitude_ = latitude;
last_longitude_ = longitude;
for (auto& registration : registrations_) {
bool is_inside =
PositionInRegion(latitude, longitude, registration.second.region);
if (is_inside != registration.second.is_inside) {
if (is_inside)
registration.second.delegate->RegionEntered(registration.first);
else
registration.second.delegate->RegionExited(registration.first);
}
registration.second.is_inside = is_inside;
}
}
bool MockGeofencingService::IsServiceAvailable() {
return available_;
}
int64 MockGeofencingService::RegisterRegion(
const blink::WebCircularGeofencingRegion& region,
GeofencingRegistrationDelegate* delegate) {
int64 id = next_id_++;
Registration& registration = registrations_[id];
registration.region = region;
registration.delegate = delegate;
registration.is_inside =
has_position_ &&
PositionInRegion(last_latitude_, last_longitude_, region);
RegisterRegionResult(delegate, id, GEOFENCING_STATUS_OK);
if (registration.is_inside) {
base::MessageLoop::current()->PostTask(
FROM_HERE, base::Bind(&GeofencingRegistrationDelegate::RegionEntered,
base::Unretained(delegate), id));
}
return id;
}
void MockGeofencingService::UnregisterRegion(int64 geofencing_registration_id) {
registrations_.erase(geofencing_registration_id);
}
} // namespace content
|