diff -r 000000000000 -r 4f2f89ce4247 WebCore/page/GeolocationPositionCache.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebCore/page/GeolocationPositionCache.cpp Fri Sep 17 09:02:29 2010 +0300 @@ -0,0 +1,178 @@ +/* + * Copyright 2010, The Android Open Source Project + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "GeolocationPositionCache.h" + +#if ENABLE(GEOLOCATION) + +#include "Geoposition.h" +#include "SQLValue.h" +#include "SQLiteDatabase.h" +#include "SQLiteFileSystem.h" +#include "SQLiteStatement.h" +#include "SQLiteTransaction.h" + +namespace WebCore { + +static const char* databaseName = "CachedGeoposition.db"; + +int GeolocationPositionCache::s_instances = 0; +RefPtr* GeolocationPositionCache::s_cachedPosition; +String* GeolocationPositionCache::s_databaseFile = 0; + +GeolocationPositionCache::GeolocationPositionCache() +{ + if (!(s_instances++)) { + s_cachedPosition = new RefPtr; + *s_cachedPosition = readFromDB(); + } +} + +GeolocationPositionCache::~GeolocationPositionCache() +{ + if (!(--s_instances)) { + if (*s_cachedPosition) + writeToDB(s_cachedPosition->get()); + delete s_cachedPosition; + } +} + +void GeolocationPositionCache::setCachedPosition(Geoposition* cachedPosition) +{ + *s_cachedPosition = cachedPosition; +} + +Geoposition* GeolocationPositionCache::cachedPosition() +{ + return s_cachedPosition->get(); +} + +void GeolocationPositionCache::setDatabasePath(const String& databasePath) +{ + if (!s_databaseFile) + s_databaseFile = new String; + *s_databaseFile = SQLiteFileSystem::appendDatabaseFileNameToPath(databasePath, databaseName); + // If we don't have have a cached position, attempt to read one from the + // DB at the new path. + if (s_instances && !(*s_cachedPosition)) + *s_cachedPosition = readFromDB(); +} + +PassRefPtr GeolocationPositionCache::readFromDB() +{ + SQLiteDatabase database; + if (!s_databaseFile || !database.open(*s_databaseFile)) + return 0; + + // Create the table here, such that even if we've just created the + // DB, the commands below should succeed. + if (!database.executeCommand("CREATE TABLE IF NOT EXISTS CachedPosition (" + "latitude REAL NOT NULL, " + "longitude REAL NOT NULL, " + "altitude REAL, " + "accuracy REAL NOT NULL, " + "altitudeAccuracy REAL, " + "heading REAL, " + "speed REAL, " + "timestamp INTEGER NOT NULL)")) + return 0; + + SQLiteStatement statement(database, "SELECT * FROM CachedPosition"); + if (statement.prepare() != SQLResultOk) + return 0; + + if (statement.step() != SQLResultRow) + return 0; + + bool providesAltitude = statement.getColumnValue(2).type() != SQLValue::NullValue; + bool providesAltitudeAccuracy = statement.getColumnValue(4).type() != SQLValue::NullValue; + bool providesHeading = statement.getColumnValue(5).type() != SQLValue::NullValue; + bool providesSpeed = statement.getColumnValue(6).type() != SQLValue::NullValue; + RefPtr coordinates = Coordinates::create(statement.getColumnDouble(0), // latitude + statement.getColumnDouble(1), // longitude + providesAltitude, statement.getColumnDouble(2), // altitude + statement.getColumnDouble(3), // accuracy + providesAltitudeAccuracy, statement.getColumnDouble(4), // altitudeAccuracy + providesHeading, statement.getColumnDouble(5), // heading + providesSpeed, statement.getColumnDouble(6)); // speed + return Geoposition::create(coordinates.release(), statement.getColumnInt64(7)); // timestamp +} + +void GeolocationPositionCache::writeToDB(const Geoposition* position) +{ + ASSERT(position); + + SQLiteDatabase database; + if (!s_databaseFile || !database.open(*s_databaseFile)) + return; + + SQLiteTransaction transaction(database); + + if (!database.executeCommand("DELETE FROM CachedPosition")) + return; + + SQLiteStatement statement(database, "INSERT INTO CachedPosition (" + "latitude, " + "longitude, " + "altitude, " + "accuracy, " + "altitudeAccuracy, " + "heading, " + "speed, " + "timestamp) " + "VALUES (?, ?, ?, ?, ?, ?, ?, ?)"); + if (statement.prepare() != SQLResultOk) + return; + + statement.bindDouble(1, position->coords()->latitude()); + statement.bindDouble(2, position->coords()->longitude()); + if (position->coords()->canProvideAltitude()) + statement.bindDouble(3, position->coords()->altitude()); + else + statement.bindNull(3); + statement.bindDouble(4, position->coords()->accuracy()); + if (position->coords()->canProvideAltitudeAccuracy()) + statement.bindDouble(5, position->coords()->altitudeAccuracy()); + else + statement.bindNull(5); + if (position->coords()->canProvideHeading()) + statement.bindDouble(6, position->coords()->heading()); + else + statement.bindNull(6); + if (position->coords()->canProvideSpeed()) + statement.bindDouble(7, position->coords()->speed()); + else + statement.bindNull(7); + statement.bindInt64(8, position->timestamp()); + if (!statement.executeCommand()) + return; + + transaction.commit(); +} + +} // namespace WebCore + +#endif // ENABLE(GEOLOCATION)