/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is mozilla.org code. * * The Initial Developer of the Original Code is Mozilla Foundation * Portions created by the Initial Developer are Copyright (C) 2012 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Kan-Ru Chen (Original Author) * * Alternatively, the contents of this file may be used under the terms of * either of the GNU General Public License Version 2 or later (the "GPL"), * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #include #include #include "mozilla/Preferences.h" #include "nsGeoPosition.h" #include "GonkGPSGeolocationProvider.h" using namespace mozilla; NS_IMPL_ISUPPORTS1(GonkGPSGeolocationProvider, nsIGeolocationProvider) GonkGPSGeolocationProvider* GonkGPSGeolocationProvider::sSingleton; static void LocationCallback(GpsLocation* location) { nsRefPtr provider = GonkGPSGeolocationProvider::GetSingleton(); nsCOMPtr callback = provider->GetLocationCallback(); if (!callback) return; nsRefPtr somewhere = new nsGeoPosition(location->latitude, location->longitude, location->altitude, location->accuracy, location->accuracy, location->bearing, location->speed, location->timestamp); callback->Update(somewhere); } typedef void *(*pthread_func)(void *); /** Callback for creating a thread that can call into the JS codes. */ static pthread_t CreateThreadCallback(const char* name, void (*start)(void *), void* arg) { pthread_t thread; pthread_attr_t attr; pthread_attr_init(&attr); /* Unfortunately pthread_create and the callback disagreed on what * start function should return. */ pthread_create(&thread, &attr, reinterpret_cast(start), arg); return thread; } static GpsCallbacks gCallbacks = { sizeof(GpsCallbacks), LocationCallback, NULL, /* StatusCallback */ NULL, /* SvStatusCallback */ NULL, /* NmeaCallback */ NULL, /* SetCapabilitiesCallback */ NULL, /* AcquireWakelockCallback */ NULL, /* ReleaseWakelockCallback */ CreateThreadCallback, }; GonkGPSGeolocationProvider::GonkGPSGeolocationProvider() : mStarted(false) , mGpsInterface(nsnull) { } GonkGPSGeolocationProvider::~GonkGPSGeolocationProvider() { Shutdown(); sSingleton = NULL; } /* static */ already_AddRefed GonkGPSGeolocationProvider::GetSingleton() { if (!sSingleton) sSingleton = new GonkGPSGeolocationProvider(); NS_ADDREF(sSingleton); return sSingleton; } already_AddRefed GonkGPSGeolocationProvider::GetLocationCallback() { nsCOMPtr callback = mLocationCallback; return callback.forget(); } const GpsInterface* GonkGPSGeolocationProvider::GetGPSInterface() { hw_module_t* module; if (hw_get_module(GPS_HARDWARE_MODULE_ID, (hw_module_t const**)&module)) return NULL; hw_device_t* device; if (module->methods->open(module, GPS_HARDWARE_MODULE_ID, &device)) return NULL; gps_device_t* gps_device = (gps_device_t *)device; const GpsInterface* result = gps_device->get_gps_interface(gps_device); if (result->size != sizeof(GpsInterface)) { return nsnull; } return result; } NS_IMETHODIMP GonkGPSGeolocationProvider::Startup() { if (mStarted) return NS_OK; mGpsInterface = GetGPSInterface(); NS_ENSURE_TRUE(mGpsInterface, NS_ERROR_FAILURE); PRInt32 update = Preferences::GetInt("geo.default.update", 1000); if (mGpsInterface->init(&gCallbacks) != 0) return NS_ERROR_FAILURE; mGpsInterface->start(); mGpsInterface->set_position_mode(GPS_POSITION_MODE_STANDALONE, GPS_POSITION_RECURRENCE_PERIODIC, update, 0, 0); mStarted = true; return NS_OK; } NS_IMETHODIMP GonkGPSGeolocationProvider::Watch(nsIGeolocationUpdate* aCallback) { mLocationCallback = aCallback; return NS_OK; } NS_IMETHODIMP GonkGPSGeolocationProvider::Shutdown() { if (!mStarted) return NS_OK; NS_ENSURE_TRUE(mGpsInterface, NS_OK); mGpsInterface->stop(); mGpsInterface->cleanup(); return NS_OK; } NS_IMETHODIMP GonkGPSGeolocationProvider::SetHighAccuracy(bool) { return NS_OK; }