Android Open Source - Pedometer Database






From Project

Back to project page Pedometer.

License

The source code is released under:

Apache License

If you think the Android project Pedometer listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

/*
 * Copyright 2013 Thomas Hoffmann/*from w w  w  . j  a v  a  2s  .  c om*/
 * 
 * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package de.j4velin.pedometer;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Pair;

import java.util.Date;
import java.util.concurrent.atomic.AtomicInteger;

import de.j4velin.pedometer.util.Logger;
import de.j4velin.pedometer.util.Util;

public class Database extends SQLiteOpenHelper {

    private final static String DB_NAME = "steps";
    private final static int DB_VERSION = 2;

    private static Database instance;
    private static final AtomicInteger openCounter = new AtomicInteger();

    private Database(final Context context) {
        super(context, DB_NAME, null, DB_VERSION);
    }

    public static synchronized Database getInstance(final Context c) {
        if (instance == null) {
            instance = new Database(c.getApplicationContext());
        }
        openCounter.incrementAndGet();
        return instance;
    }

    @Override
    public void close() {
        if (openCounter.decrementAndGet() == 0) {
            super.close();
        }
    }

    @Override
    public void onCreate(final SQLiteDatabase db) {
        db.execSQL("CREATE TABLE " + DB_NAME + " (date INTEGER, steps INTEGER)");
    }

    @Override
    public void onUpgrade(final SQLiteDatabase db, int oldVersion, int newVersion) {
        if (oldVersion == 1) {
            // drop PRIMARY KEY constraint
            db.execSQL("CREATE TABLE " + DB_NAME + "2 (date INTEGER, steps INTEGER)");
            db.execSQL("INSERT INTO " + DB_NAME + "2 (date, steps) SELECT date, steps FROM " +
                    DB_NAME);
            db.execSQL("DROP TABLE " + DB_NAME);
            db.execSQL("ALTER TABLE " + DB_NAME + "2 RENAME TO " + DB_NAME + "");
        }
    }

    /**
     * Query the 'steps' table. Remember to close the cursor!
     *
     * @param columns       the colums
     * @param selection     the selection
     * @param selectionArgs the selction arguments
     * @param groupBy       the group by statement
     * @param having        the having statement
     * @param orderBy       the order by statement
     * @return the cursor
     */
    Cursor query(final String[] columns, final String selection, final String[] selectionArgs, final String groupBy, final String having, final String orderBy, final String limit) {
        return getReadableDatabase()
                .query(DB_NAME, columns, selection, selectionArgs, groupBy, having, orderBy, limit);
    }

    /**
     * Inserts a new entry in the database, if there is no entry for the given
     * date yet. Steps should be the current number of steps and it's negative
     * value will be used as offset for the new date. Also adds 'steps' steps to
     * the previous day, if there is an entry for that date.
     * <p/>
     * This method does nothing if there is already an entry for 'date' - use
     * {@link #updateSteps} in this case.
     * <p/>
     * To restore data from a backup, use {@link #insertDayFromBackup}
     *
     * @param date  the date in ms since 1970
     * @param steps the current step value to be used as negative offset for the
     *              new day; must be >= 0
     */
    public void insertNewDay(long date, int steps) {
        getWritableDatabase().beginTransaction();
        try {
            Cursor c = getReadableDatabase().query(DB_NAME, new String[]{"date"}, "date = ?",
                    new String[]{String.valueOf(date)}, null, null, null);
            if (c.getCount() == 0 && steps >= 0) {
                ContentValues values = new ContentValues();
                values.put("date", date);
                // use the negative steps as offset
                values.put("steps", -steps);
                getWritableDatabase().insert(DB_NAME, null, values);

                // add 'steps' to yesterdays count
                date -= 24 * 60 * 60 * 1000;
                updateSteps(date, steps);
            }
            c.close();
            if (BuildConfig.DEBUG) {
                Logger.log("insertDay " + date + " / " + steps);
                logState();
            }
            getWritableDatabase().setTransactionSuccessful();
        } finally {
            getWritableDatabase().endTransaction();
        }
    }

    /**
     * Inserts a new entry in the database, if there is no entry for the given
     * date yet. Use this method for restoring data from a backup.
     * <p/>
     * This method does nothing if there is already an entry for 'date'.
     *
     * @param date  the date in ms since 1970
     * @param steps the step value for 'date'; must be >= 0
     * @return true if a new entry was created, false if there was already an
     * entry for 'date'
     */
    public boolean insertDayFromBackup(long date, int steps) {
        getWritableDatabase().beginTransaction();
        boolean re;
        try {
            Cursor c = getReadableDatabase().query(DB_NAME, new String[]{"date"}, "date = ?",
                    new String[]{String.valueOf(date)}, null, null, null);
            re = c.getCount() == 0 && steps >= 0;
            if (re) {
                ContentValues values = new ContentValues();
                values.put("date", date);
                values.put("steps", steps);
                getWritableDatabase().insert(DB_NAME, null, values);
            }
            c.close();
            getWritableDatabase().setTransactionSuccessful();
        } finally {
            getWritableDatabase().endTransaction();
        }
        return re;
    }

    /**
     * Writes the current steps database to the log
     */
    public void logState() {
        if (BuildConfig.DEBUG) {
            Cursor c = getReadableDatabase()
                    .query(DB_NAME, null, null, null, null, null, "date DESC", "5");
            Logger.log(c);
            c.close();
        }
    }

    /**
     * Adds 'steps' steps to the row for the date 'date'. Won't do anything if
     * there isn't a row for the given date
     *
     * @param date  the date to update the steps for in millis since 1970
     * @param steps the steps to add to the current steps-value for the date
     */
    public void updateSteps(final long date, int steps) {
        getWritableDatabase().execSQL(
                "UPDATE " + DB_NAME + " SET steps = steps + " + steps + " WHERE date = " + date);
        if (BuildConfig.DEBUG) {
            Logger.log("updateSteps " + date + " / " + steps);
            logState();
        }
    }

    /**
     * Get the total of steps taken without today's value
     *
     * @return number of steps taken, ignoring today
     */
    int getTotalWithoutToday() {
        Cursor c = getReadableDatabase()
                .query(DB_NAME, new String[]{"SUM(steps)"}, "steps > 0 AND date > 0 AND date < ?",
                        new String[]{String.valueOf(Util.getToday())}, null, null, null);
        c.moveToFirst();
        int re = c.getInt(0);
        c.close();
        return re;
    }

    /**
     * Get the maximum of steps walked in one day
     *
     * @return the maximum number of steps walked in one day
     */
    int getRecord() {
        Cursor c = getReadableDatabase()
                .query(DB_NAME, new String[]{"MAX(steps)"}, "date > 0", null, null, null, null);
        c.moveToFirst();
        int re = c.getInt(0);
        c.close();
        return re;
    }

    /**
     * Get the maximum of steps walked in one day and the date that happend
     *
     * @return a pair containing the date (Date) in millis since 1970 and the
     * step value (Integer)
     */
    Pair<Date, Integer> getRecordData() {
        Cursor c = getReadableDatabase()
                .query(DB_NAME, new String[]{"date, steps"}, "date > 0", null, null, null,
                        "steps DESC", "1");
        c.moveToFirst();
        Pair<Date, Integer> p = new Pair<Date, Integer>(new Date(c.getLong(0)), c.getInt(1));
        c.close();
        return p;
    }

    /**
     * Get the number of steps taken for a specific date.
     * <p/>
     * If date is Util.getToday(), this method returns the offset which needs to
     * be added to the value returned by getCurrentSteps() to get todays steps.
     *
     * @param date the date in millis since 1970
     * @return the steps taken on this date or Integer.MIN_VALUE if date doesn't
     * exist in the database
     */
    public int getSteps(final long date) {
        Cursor c = getReadableDatabase().query(DB_NAME, new String[]{"steps"}, "date = ?",
                new String[]{String.valueOf(date)}, null, null, null);
        c.moveToFirst();
        int re;
        if (c.getCount() == 0) re = Integer.MIN_VALUE;
        else re = c.getInt(0);
        c.close();
        return re;
    }

    /**
     * Get the number of steps taken between 'start' and 'end' date
     * <p/>
     * Note that todays entry might have a negative value, so take care of that
     * if 'end' >= Util.getToday()!
     *
     * @param start start date in ms since 1970 (steps for this date included)
     * @param end   end date in ms since 1970 (steps for this date included)
     * @return the number of steps from 'start' to 'end'. Can be < 0 as todays
     * entry might have negative value
     */
    public int getSteps(final long start, final long end) {
        Cursor c = getReadableDatabase()
                .query(DB_NAME, new String[]{"SUM(steps)"}, "date >= ? AND date <= ?",
                        new String[]{String.valueOf(start), String.valueOf(end)}, null, null, null);
        int re;
        if (c.getCount() == 0) {
            re = 0;
        } else {
            c.moveToFirst();
            re = c.getInt(0);
        }
        c.close();
        return re;
    }

    /**
     * Removes all entries with negative values.
     * <p/>
     * Only call this directly after boot, otherwise it might remove the current
     * day as the current offset is likely to be negative
     */
    void removeNegativeEntries() {
        getWritableDatabase().delete(DB_NAME, "steps < ?", new String[]{"0"});
    }

    /**
     * Removes invalid entries from the database.
     * <p/>
     * Currently, an invalid input is such with steps >= 200,000
     */
    void removeInvalidEntries() {
        getWritableDatabase().delete(DB_NAME, "steps >= ?", new String[]{"200000"});
    }

    /**
     * Get the number of 'valid' days (= days with a step value > 0).
     * <p/>
     * The current day is also added to this number, even if the value in the
     * database might still be < 0.
     * <p/>
     * It is safe to divide by the return value as this will be at least 1 (and
     * not 0).
     *
     * @return the number of days with a step value > 0, return will be >= 1
     */
    int getDays() {
        Cursor c = getReadableDatabase()
                .query(DB_NAME, new String[]{"COUNT(*)"}, "steps > ? AND date < ? AND date > 0",
                        new String[]{String.valueOf(0), String.valueOf(Util.getToday())}, null,
                        null, null);
        c.moveToFirst();
        // todays is not counted yet
        int re = c.getInt(0) + 1;
        c.close();
        return re <= 0 ? 1 : re;
    }

    /**
     * Saves the current 'steps since boot' sensor value in the database.
     *
     * @param steps since boot
     */
    public void saveCurrentSteps(int steps) {
        ContentValues values = new ContentValues();
        values.put("steps", steps);
        if (getWritableDatabase().update(DB_NAME, values, "date = -1", null) == 0) {
            values.put("date", -1);
            getWritableDatabase().insert(DB_NAME, null, values);
        }
        if (BuildConfig.DEBUG) {
            Logger.log("saving steps in db: " + steps);
        }
    }

    /**
     * Reads the latest saved value for the 'steps since boot' sensor value.
     *
     * @return the current number of steps saved in the database or 0 if there
     * is no entry
     */
    public int getCurrentSteps() {
        int re = getSteps(-1);
        return re == Integer.MIN_VALUE ? 0 : re;
    }

    /**
     * Should be called when the timezone on the device changes. This will adjust the databas entries
     * so that each entry still translates to midnight of a day.
     *
     * @param offsetDifference the difference in the rawOffsets of the two timeZones (new - old) in milliseconds
     */
    public void timeZoneChanged(int offsetDifference) {
        getWritableDatabase()
                .execSQL("UPDATE " + DB_NAME + " SET date = date - '" + offsetDifference +
                        "' WHERE date > 0");
    }

}




Java Source Code List

com.google.example.games.basegameutils.ApplicationTest.java
com.google.example.games.basegameutils.BaseGameActivity.java
com.google.example.games.basegameutils.GameHelperUtils.java
com.google.example.games.basegameutils.GameHelper.java
com.nineoldandroids.ApplicationTest.java
com.nineoldandroids.animation.AnimatorInflater.java
com.nineoldandroids.animation.AnimatorListenerAdapter.java
com.nineoldandroids.animation.AnimatorSet.java
com.nineoldandroids.animation.Animator.java
com.nineoldandroids.animation.ArgbEvaluator.java
com.nineoldandroids.animation.FloatEvaluator.java
com.nineoldandroids.animation.FloatKeyframeSet.java
com.nineoldandroids.animation.IntEvaluator.java
com.nineoldandroids.animation.IntKeyframeSet.java
com.nineoldandroids.animation.KeyframeSet.java
com.nineoldandroids.animation.Keyframe.java
com.nineoldandroids.animation.ObjectAnimator.java
com.nineoldandroids.animation.PreHoneycombCompat.java
com.nineoldandroids.animation.PropertyValuesHolder.java
com.nineoldandroids.animation.TimeAnimator.java
com.nineoldandroids.animation.TypeEvaluator.java
com.nineoldandroids.animation.ValueAnimator.java
com.nineoldandroids.util.FloatProperty.java
com.nineoldandroids.util.IntProperty.java
com.nineoldandroids.util.NoSuchPropertyException.java
com.nineoldandroids.util.Property.java
com.nineoldandroids.util.ReflectiveProperty.java
com.nineoldandroids.view.ViewHelper.java
com.nineoldandroids.view.ViewPropertyAnimatorHC.java
com.nineoldandroids.view.ViewPropertyAnimatorICS.java
com.nineoldandroids.view.ViewPropertyAnimatorPreHC.java
com.nineoldandroids.view.ViewPropertyAnimator.java
com.nineoldandroids.view.animation.AnimatorProxy.java
de.j4velin.pedometer.Activity_Main.java
de.j4velin.pedometer.AppUpdatedReceiver.java
de.j4velin.pedometer.ApplicationTest.java
de.j4velin.pedometer.BootReceiver.java
de.j4velin.pedometer.Database.java
de.j4velin.pedometer.Dialog_Split.java
de.j4velin.pedometer.Dialog_Statistics.java
de.j4velin.pedometer.Fragment_Overview.java
de.j4velin.pedometer.Fragment_Settings.java
de.j4velin.pedometer.PlayServices.java
de.j4velin.pedometer.background.SensorListener.java
de.j4velin.pedometer.background.ShutdownRecevier.java
de.j4velin.pedometer.util.ColorPreview.java
de.j4velin.pedometer.util.Logger.java
de.j4velin.pedometer.util.TimeZoneListener.java
de.j4velin.pedometer.util.Util.java
de.j4velin.pedometer.widget.DashClock.java
de.j4velin.pedometer.widget.WidgetConfig.java
de.j4velin.pedometer.widget.WidgetUpdateService.java
de.j4velin.pedometer.widget.Widget.java
net.margaritov.preference.colorpicker.AlphaPatternDrawable.java
net.margaritov.preference.colorpicker.ApplicationTest.java
net.margaritov.preference.colorpicker.ColorPickerDialog.java
net.margaritov.preference.colorpicker.ColorPickerPanelView.java
net.margaritov.preference.colorpicker.ColorPickerPreference.java
net.margaritov.preference.colorpicker.ColorPickerView.java
net.margaritov.preference.colorpicker.Test.java
org.eazegraph.lib.ApplicationTest.java
org.eazegraph.lib.charts.BarChart.java
org.eazegraph.lib.charts.BaseBarChart.java
org.eazegraph.lib.charts.BaseChart.java
org.eazegraph.lib.charts.PieChart.java
org.eazegraph.lib.charts.StackedBarChart.java
org.eazegraph.lib.charts.ValueLineChart.java
org.eazegraph.lib.communication.IOnBarClickedListener.java
org.eazegraph.lib.communication.IOnItemFocusChangedListener.java
org.eazegraph.lib.communication.IOnPointFocusedListener.java
org.eazegraph.lib.models.BarModel.java
org.eazegraph.lib.models.BaseModel.java
org.eazegraph.lib.models.LegendModel.java
org.eazegraph.lib.models.PieModel.java
org.eazegraph.lib.models.Point2D.java
org.eazegraph.lib.models.StackedBarModel.java
org.eazegraph.lib.models.StandardValue.java
org.eazegraph.lib.models.ValueLinePoint.java
org.eazegraph.lib.models.ValueLineSeries.java
org.eazegraph.lib.utils.Utils.java