Home | History | Annotate | Download | only in page
      1 /*
      2  * Copyright 2010, The Android Open Source Project
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  *  * Redistributions of source code must retain the above copyright
      8  *    notice, this list of conditions and the following disclaimer.
      9  *  * Redistributions in binary form must reproduce the above copyright
     10  *    notice, this list of conditions and the following disclaimer in the
     11  *    documentation and/or other materials provided with the distribution.
     12  *
     13  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
     14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
     17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     24  */
     25 
     26 #include "config.h"
     27 #include "GeolocationPositionCache.h"
     28 
     29 #include "Geoposition.h"
     30 #include "SQLValue.h"
     31 #include "SQLiteDatabase.h"
     32 #include "SQLiteFileSystem.h"
     33 #include "SQLiteStatement.h"
     34 #include "SQLiteTransaction.h"
     35 
     36 
     37 namespace WebCore {
     38 
     39 static const char* databaseName = "CachedGeoposition.db";
     40 
     41 int GeolocationPositionCache::s_instances = 0;
     42 RefPtr<Geoposition>* GeolocationPositionCache::s_cachedPosition;
     43 String* GeolocationPositionCache::s_databaseFile = 0;
     44 
     45 GeolocationPositionCache::GeolocationPositionCache()
     46 {
     47     if (!(s_instances++)) {
     48         s_cachedPosition = new RefPtr<Geoposition>;
     49         *s_cachedPosition = readFromDB();
     50     }
     51 }
     52 
     53 GeolocationPositionCache::~GeolocationPositionCache()
     54 {
     55     if (!(--s_instances)) {
     56         if (*s_cachedPosition)
     57             writeToDB(s_cachedPosition->get());
     58         delete s_cachedPosition;
     59     }
     60 }
     61 
     62 void GeolocationPositionCache::setCachedPosition(Geoposition* cachedPosition)
     63 {
     64     *s_cachedPosition = cachedPosition;
     65 }
     66 
     67 Geoposition* GeolocationPositionCache::cachedPosition()
     68 {
     69     return s_cachedPosition->get();
     70 }
     71 
     72 void GeolocationPositionCache::setDatabasePath(const String& databasePath)
     73 {
     74     if (!s_databaseFile)
     75         s_databaseFile = new String;
     76     *s_databaseFile = SQLiteFileSystem::appendDatabaseFileNameToPath(databasePath, databaseName);
     77     // If we don't have have a cached position, attempt to read one from the
     78     // DB at the new path.
     79     if (s_instances && !(*s_cachedPosition))
     80         *s_cachedPosition = readFromDB();
     81 }
     82 
     83 PassRefPtr<Geoposition> GeolocationPositionCache::readFromDB()
     84 {
     85     SQLiteDatabase database;
     86     if (!s_databaseFile || !database.open(*s_databaseFile))
     87         return 0;
     88 
     89     // Create the table here, such that even if we've just created the
     90     // DB, the commands below should succeed.
     91     if (!database.executeCommand("CREATE TABLE IF NOT EXISTS CachedPosition ("
     92             "latitude REAL NOT NULL, "
     93             "longitude REAL NOT NULL, "
     94             "altitude REAL, "
     95             "accuracy REAL NOT NULL, "
     96             "altitudeAccuracy REAL, "
     97             "heading REAL, "
     98             "speed REAL, "
     99             "timestamp INTEGER NOT NULL)"))
    100         return 0;
    101 
    102     SQLiteStatement statement(database, "SELECT * FROM CachedPosition");
    103     if (statement.prepare() != SQLResultOk)
    104         return 0;
    105 
    106     if (statement.step() != SQLResultRow)
    107         return 0;
    108 
    109     bool providesAltitude = statement.getColumnValue(2).type() != SQLValue::NullValue;
    110     bool providesAltitudeAccuracy = statement.getColumnValue(4).type() != SQLValue::NullValue;
    111     bool providesHeading = statement.getColumnValue(5).type() != SQLValue::NullValue;
    112     bool providesSpeed = statement.getColumnValue(6).type() != SQLValue::NullValue;
    113     RefPtr<Coordinates> coordinates = Coordinates::create(statement.getColumnDouble(0), // latitude
    114                                                           statement.getColumnDouble(1), // longitude
    115                                                           providesAltitude, statement.getColumnDouble(2), // altitude
    116                                                           statement.getColumnDouble(3), // accuracy
    117                                                           providesAltitudeAccuracy, statement.getColumnDouble(4), // altitudeAccuracy
    118                                                           providesHeading, statement.getColumnDouble(5), // heading
    119                                                           providesSpeed, statement.getColumnDouble(6)); // speed
    120     return Geoposition::create(coordinates.release(), statement.getColumnInt64(7)); // timestamp
    121 }
    122 
    123 void GeolocationPositionCache::writeToDB(const Geoposition* position)
    124 {
    125     ASSERT(position);
    126 
    127     SQLiteDatabase database;
    128     if (!s_databaseFile || !database.open(*s_databaseFile))
    129         return;
    130 
    131     SQLiteTransaction transaction(database);
    132 
    133     if (!database.executeCommand("DELETE FROM CachedPosition"))
    134         return;
    135 
    136     SQLiteStatement statement(database, "INSERT INTO CachedPosition ("
    137         "latitude, "
    138         "longitude, "
    139         "altitude, "
    140         "accuracy, "
    141         "altitudeAccuracy, "
    142         "heading, "
    143         "speed, "
    144         "timestamp) "
    145         "VALUES (?, ?, ?, ?, ?, ?, ?, ?)");
    146     if (statement.prepare() != SQLResultOk)
    147         return;
    148 
    149     statement.bindDouble(1, position->coords()->latitude());
    150     statement.bindDouble(2, position->coords()->longitude());
    151     if (position->coords()->canProvideAltitude())
    152         statement.bindDouble(3, position->coords()->altitude());
    153     else
    154         statement.bindNull(3);
    155     statement.bindDouble(4, position->coords()->accuracy());
    156     if (position->coords()->canProvideAltitudeAccuracy())
    157         statement.bindDouble(5, position->coords()->altitudeAccuracy());
    158     else
    159         statement.bindNull(5);
    160     if (position->coords()->canProvideHeading())
    161         statement.bindDouble(6, position->coords()->heading());
    162     else
    163         statement.bindNull(6);
    164     if (position->coords()->canProvideSpeed())
    165         statement.bindDouble(7, position->coords()->speed());
    166     else
    167         statement.bindNull(7);
    168     statement.bindInt64(8, position->timestamp());
    169     if (!statement.executeCommand())
    170         return;
    171 
    172     transaction.commit();
    173 }
    174 
    175 } // namespace WebCore
    176