mirror of
https://bitbucket.org/chromiumembedded/cef
synced 2025-06-05 21:39:12 +02:00
Create 1453 release branch for CEF1.
git-svn-id: https://chromiumembedded.googlecode.com/svn/branches/1453@1184 5089003a-bbd8-11dd-ad1f-f1f9622dbc98
This commit is contained in:
352
cef1/libcef/geolocation_client.cc
Normal file
352
cef1/libcef/geolocation_client.cc
Normal file
@@ -0,0 +1,352 @@
|
||||
// Copyright (c) 2012 The Chromium Embedded Framework Authors.
|
||||
// Portions copyright (c) 2011 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 "libcef/geolocation_client.h"
|
||||
#include "libcef/browser_impl.h"
|
||||
#include "libcef/cef_context.h"
|
||||
#include "libcef/cef_thread.h"
|
||||
|
||||
#include "base/bind.h"
|
||||
#include "base/logging.h"
|
||||
#include "content/browser/geolocation/geolocation_observer.h"
|
||||
#include "content/browser/geolocation/geolocation_provider.h"
|
||||
#include "content/browser/geolocation/location_provider.h"
|
||||
#include "content/public/browser/access_token_store.h"
|
||||
#include "content/public/browser/content_browser_client.h"
|
||||
#include "content/public/common/geoposition.h"
|
||||
#include "content/public/common/content_client.h"
|
||||
#include "content/public/common/content_switches.h"
|
||||
#include "net/url_request/url_request_context_getter.h"
|
||||
#include "third_party/WebKit/Source/Platform/chromium/public/WebString.h"
|
||||
#include "third_party/WebKit/Source/WebKit/chromium/public/WebGeolocationPermissionRequest.h"
|
||||
#include "third_party/WebKit/Source/WebKit/chromium/public/WebGeolocationPermissionRequestManager.h"
|
||||
#include "third_party/WebKit/Source/WebKit/chromium/public/WebGeolocationClient.h"
|
||||
#include "third_party/WebKit/Source/WebKit/chromium/public/WebGeolocationPosition.h"
|
||||
#include "third_party/WebKit/Source/WebKit/chromium/public/WebGeolocationError.h"
|
||||
#include "third_party/WebKit/Source/WebKit/chromium/public/WebSecurityOrigin.h"
|
||||
#include "webkit/user_agent/user_agent.h"
|
||||
|
||||
using WebKit::WebGeolocationController;
|
||||
using WebKit::WebGeolocationError;
|
||||
using WebKit::WebGeolocationPermissionRequest;
|
||||
using WebKit::WebGeolocationPermissionRequestManager;
|
||||
using WebKit::WebGeolocationPosition;
|
||||
|
||||
namespace {
|
||||
|
||||
class CefURLRequestContextGetter : public net::URLRequestContextGetter {
|
||||
public:
|
||||
CefURLRequestContextGetter() {}
|
||||
|
||||
virtual net::URLRequestContext* GetURLRequestContext() OVERRIDE {
|
||||
return _Context->request_context();
|
||||
}
|
||||
|
||||
virtual scoped_refptr<base::SingleThreadTaskRunner>
|
||||
GetNetworkTaskRunner() const OVERRIDE {
|
||||
return CefThread::GetMessageLoopProxyForThread(CefThread::IO);
|
||||
}
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(CefURLRequestContextGetter);
|
||||
};
|
||||
|
||||
// In-memory store for access tokens used by geolocation.
|
||||
class CefAccessTokenStore : public content::AccessTokenStore {
|
||||
public:
|
||||
CefAccessTokenStore() {}
|
||||
|
||||
virtual void LoadAccessTokens(
|
||||
const LoadAccessTokensCallbackType& callback) OVERRIDE {
|
||||
if (!request_context_getter_)
|
||||
request_context_getter_ = new CefURLRequestContextGetter;
|
||||
callback.Run(access_token_set_, request_context_getter_);
|
||||
}
|
||||
|
||||
virtual void SaveAccessToken(
|
||||
const GURL& server_url, const string16& access_token) OVERRIDE {
|
||||
access_token_set_[server_url] = access_token;
|
||||
}
|
||||
|
||||
private:
|
||||
AccessTokenSet access_token_set_;
|
||||
scoped_refptr<CefURLRequestContextGetter> request_context_getter_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(CefAccessTokenStore);
|
||||
};
|
||||
|
||||
// Stub implementation of ContentClient.
|
||||
class CefContentClient : public content::ContentClient {
|
||||
public:
|
||||
CefContentClient() {}
|
||||
|
||||
virtual std::string GetUserAgent() const OVERRIDE {
|
||||
return webkit_glue::GetUserAgent(GURL());
|
||||
}
|
||||
};
|
||||
|
||||
// Stub implementation of ContentBrowserClient.
|
||||
class CefContentBrowserClient : public content::ContentBrowserClient {
|
||||
public:
|
||||
CefContentBrowserClient() {}
|
||||
|
||||
virtual content::AccessTokenStore* CreateAccessTokenStore() OVERRIDE {
|
||||
return new CefAccessTokenStore();
|
||||
}
|
||||
};
|
||||
|
||||
void NotifyArbitratorPermissionGranted() {
|
||||
DCHECK(CefThread::CurrentlyOn(CefThread::IO));
|
||||
content::GeolocationProvider::GetInstance()->OnPermissionGranted();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
// CefGeolocationCallback implementation.
|
||||
class CefGeolocationCallbackImpl : public CefGeolocationCallback {
|
||||
public:
|
||||
CefGeolocationCallbackImpl(CefGeolocationClient* client, int bridge_id)
|
||||
: client_(client),
|
||||
bridge_id_(bridge_id) {}
|
||||
|
||||
virtual void Continue(bool allow) OVERRIDE {
|
||||
if (CefThread::CurrentlyOn(CefThread::UI)) {
|
||||
if (client_) {
|
||||
client_->OnPermissionSet(bridge_id_, allow);
|
||||
client_ = NULL;
|
||||
}
|
||||
} else {
|
||||
CefThread::PostTask(CefThread::UI, FROM_HERE,
|
||||
base::Bind(&CefGeolocationCallbackImpl::Continue, this, allow));
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
scoped_refptr<CefGeolocationClient> client_;
|
||||
int bridge_id_;
|
||||
|
||||
IMPLEMENT_REFCOUNTING(CefGeolocationCallbackImpl);
|
||||
};
|
||||
|
||||
|
||||
CefGeolocationClient::CefGeolocationClient(CefBrowserImpl* browser)
|
||||
: browser_(browser),
|
||||
pending_permissions_(new WebGeolocationPermissionRequestManager()),
|
||||
enable_high_accuracy_(false),
|
||||
updating_(false),
|
||||
location_provider_(NULL) {
|
||||
}
|
||||
|
||||
CefGeolocationClient::~CefGeolocationClient() {}
|
||||
|
||||
// static
|
||||
void CefGeolocationClient::InitializeEnvironment() {
|
||||
// GeolocationArbitrator uses ContentClient to retrieve the AccessTokenStore.
|
||||
// Simulate the necessary interfaces here.
|
||||
if (!content::GetContentClient()) {
|
||||
static CefContentClient content_client;
|
||||
static CefContentBrowserClient browser_client;
|
||||
content_client.set_browser_for_testing(&browser_client);
|
||||
content::SetContentClient(&content_client);
|
||||
}
|
||||
}
|
||||
|
||||
void CefGeolocationClient::geolocationDestroyed() {
|
||||
DCHECK(CefThread::CurrentlyOn(CefThread::UI));
|
||||
|
||||
controller_.reset();
|
||||
DCHECK(!updating_);
|
||||
}
|
||||
|
||||
void CefGeolocationClient::startUpdating() {
|
||||
DCHECK(CefThread::CurrentlyOn(CefThread::UI));
|
||||
|
||||
CefThread::PostTask(CefThread::IO, FROM_HERE,
|
||||
base::Bind(&CefGeolocationClient::OnStartUpdating, this,
|
||||
enable_high_accuracy_));
|
||||
updating_ = true;
|
||||
}
|
||||
|
||||
void CefGeolocationClient::stopUpdating() {
|
||||
DCHECK(CefThread::CurrentlyOn(CefThread::UI));
|
||||
|
||||
CefThread::PostTask(CefThread::IO, FROM_HERE,
|
||||
base::Bind(&CefGeolocationClient::OnStopUpdating, this));
|
||||
updating_ = false;
|
||||
}
|
||||
|
||||
void CefGeolocationClient::setEnableHighAccuracy(bool enable_high_accuracy) {
|
||||
DCHECK(CefThread::CurrentlyOn(CefThread::UI));
|
||||
|
||||
// GeolocationController calls setEnableHighAccuracy(true) before
|
||||
// startUpdating in response to the first high-accuracy Geolocation
|
||||
// subscription. When the last high-accuracy Geolocation unsubscribes
|
||||
// it calls setEnableHighAccuracy(false) after stopUpdating.
|
||||
bool has_changed = enable_high_accuracy_ != enable_high_accuracy;
|
||||
enable_high_accuracy_ = enable_high_accuracy;
|
||||
// We have a different accuracy requirement. Request browser to update.
|
||||
if (updating_ && has_changed)
|
||||
startUpdating();
|
||||
}
|
||||
|
||||
void CefGeolocationClient::setController(
|
||||
WebGeolocationController* controller) {
|
||||
controller_.reset(controller);
|
||||
}
|
||||
|
||||
bool CefGeolocationClient::lastPosition(WebGeolocationPosition&) {
|
||||
DCHECK(CefThread::CurrentlyOn(CefThread::UI));
|
||||
|
||||
// The latest position is stored in the browser, not the renderer, so we
|
||||
// would have to fetch it synchronously to give a good value here. The
|
||||
// WebCore::GeolocationController already caches the last position it
|
||||
// receives, so there is not much benefit to more position caching here.
|
||||
return false;
|
||||
}
|
||||
|
||||
void CefGeolocationClient::requestPermission(
|
||||
const WebGeolocationPermissionRequest& permissionRequest) {
|
||||
DCHECK(CefThread::CurrentlyOn(CefThread::UI));
|
||||
|
||||
int bridge_id = pending_permissions_->add(permissionRequest);
|
||||
GURL origin = GURL(permissionRequest.securityOrigin().toString());
|
||||
|
||||
CefRefPtr<CefClient> client = browser_->GetClient();
|
||||
if (client.get()) {
|
||||
CefRefPtr<CefGeolocationHandler> handler =
|
||||
client->GetGeolocationHandler();
|
||||
if (handler.get()) {
|
||||
CefRefPtr<CefGeolocationCallbackImpl> callbackPtr(
|
||||
new CefGeolocationCallbackImpl(this, bridge_id));
|
||||
|
||||
handler->OnRequestGeolocationPermission(browser_, origin.spec(),
|
||||
bridge_id, callbackPtr.get());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Disallow geolocation access by default.
|
||||
OnPermissionSet(bridge_id, false);
|
||||
}
|
||||
|
||||
void CefGeolocationClient::cancelPermissionRequest(
|
||||
const WebGeolocationPermissionRequest& permissionRequest) {
|
||||
DCHECK(CefThread::CurrentlyOn(CefThread::UI));
|
||||
|
||||
int bridge_id;
|
||||
if (!pending_permissions_->remove(permissionRequest, bridge_id))
|
||||
return;
|
||||
GURL origin = GURL(permissionRequest.securityOrigin().toString());
|
||||
|
||||
CefRefPtr<CefClient> client = browser_->GetClient();
|
||||
if (client.get()) {
|
||||
CefRefPtr<CefGeolocationHandler> handler =
|
||||
client->GetGeolocationHandler();
|
||||
if (handler.get()) {
|
||||
handler->OnCancelGeolocationPermission(browser_, origin.spec(),
|
||||
bridge_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CefGeolocationClient::OnStartUpdating(bool enable_high_accuracy) {
|
||||
DCHECK(CefThread::CurrentlyOn(CefThread::IO));
|
||||
|
||||
InitializeEnvironment();
|
||||
|
||||
if (!location_provider_)
|
||||
location_provider_ = content::GeolocationProvider::GetInstance();
|
||||
|
||||
// Re-add to re-establish our options, in case they changed.
|
||||
location_provider_->AddObserver(
|
||||
this, content::GeolocationObserverOptions(enable_high_accuracy));
|
||||
}
|
||||
|
||||
void CefGeolocationClient::OnStopUpdating() {
|
||||
DCHECK(CefThread::CurrentlyOn(CefThread::IO));
|
||||
|
||||
if (location_provider_) {
|
||||
location_provider_->RemoveObserver(this);
|
||||
location_provider_ = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void CefGeolocationClient::OnLocationUpdate(
|
||||
const content::Geoposition& position) {
|
||||
DCHECK(CefThread::CurrentlyOn(CefThread::IO));
|
||||
|
||||
CefThread::PostTask(CefThread::UI, FROM_HERE,
|
||||
base::Bind(&CefGeolocationClient::OnPositionUpdated, this, position));
|
||||
}
|
||||
|
||||
// Permission for using geolocation has been set.
|
||||
void CefGeolocationClient::OnPermissionSet(int bridge_id, bool is_allowed) {
|
||||
DCHECK(CefThread::CurrentlyOn(CefThread::UI));
|
||||
|
||||
WebGeolocationPermissionRequest permissionRequest;
|
||||
if (!pending_permissions_->remove(bridge_id, permissionRequest))
|
||||
return;
|
||||
permissionRequest.setIsAllowed(is_allowed);
|
||||
|
||||
if (is_allowed) {
|
||||
CefThread::PostTask(
|
||||
CefThread::IO, FROM_HERE,
|
||||
base::Bind(&NotifyArbitratorPermissionGranted));
|
||||
}
|
||||
}
|
||||
|
||||
// We have an updated geolocation position or error code.
|
||||
void CefGeolocationClient::OnPositionUpdated(
|
||||
const content::Geoposition& geoposition) {
|
||||
DCHECK(CefThread::CurrentlyOn(CefThread::UI));
|
||||
|
||||
// It is possible for the browser process to have queued an update message
|
||||
// before receiving the stop updating message.
|
||||
if (!updating_)
|
||||
return;
|
||||
|
||||
if (geoposition.Validate()) {
|
||||
controller_->positionChanged(
|
||||
WebGeolocationPosition(
|
||||
geoposition.timestamp.ToDoubleT(),
|
||||
geoposition.latitude, geoposition.longitude,
|
||||
geoposition.accuracy,
|
||||
// Lowest point on land is at approximately -400 meters.
|
||||
geoposition.altitude > -10000.,
|
||||
geoposition.altitude,
|
||||
geoposition.altitude_accuracy >= 0.,
|
||||
geoposition.altitude_accuracy,
|
||||
geoposition.heading >= 0. && geoposition.heading <= 360.,
|
||||
geoposition.heading,
|
||||
geoposition.speed >= 0.,
|
||||
geoposition.speed));
|
||||
} else {
|
||||
WebGeolocationError::Error code;
|
||||
switch (geoposition.error_code) {
|
||||
case content::Geoposition::ERROR_CODE_PERMISSION_DENIED:
|
||||
code = WebGeolocationError::ErrorPermissionDenied;
|
||||
break;
|
||||
case content::Geoposition::ERROR_CODE_POSITION_UNAVAILABLE:
|
||||
code = WebGeolocationError::ErrorPositionUnavailable;
|
||||
break;
|
||||
default:
|
||||
NOTREACHED() << geoposition.error_code;
|
||||
return;
|
||||
}
|
||||
controller_->errorOccurred(
|
||||
WebGeolocationError(
|
||||
code, WebKit::WebString::fromUTF8(geoposition.error_message)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Extract from content/public/common/content_switches.cc.
|
||||
|
||||
namespace switches {
|
||||
|
||||
const char kExperimentalLocationFeatures[] = "experimental-location-features";
|
||||
|
||||
} // namespace switches
|
Reference in New Issue
Block a user