Compare commits
13 Commits
release_3.
...
release_3.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2b4c328071 | ||
|
|
4dcde2a8ca | ||
|
|
1f00790069 | ||
|
|
7a9d068949 | ||
|
|
a49d4d712c | ||
|
|
39b752c24a | ||
|
|
d7dfbae3a5 | ||
|
|
6621352551 | ||
|
|
ec620db595 | ||
|
|
b18fa9a254 | ||
|
|
f43b1f1ff0 | ||
|
|
1f48123bd2 | ||
|
|
cf2111829c |
29
.gitignore
vendored
@@ -1,5 +1,4 @@
|
||||
Makefile
|
||||
.qmake.stash
|
||||
|
||||
# old skool
|
||||
.svn
|
||||
@@ -15,19 +14,15 @@ lib/
|
||||
bin/
|
||||
plugins/
|
||||
resources/
|
||||
src/debug/
|
||||
src/release/
|
||||
|
||||
qwt/src/debug/
|
||||
qwt/src/release/
|
||||
src/Makefile.Debug
|
||||
src/Makefile.Release
|
||||
src/object_script.GoldenCheetah.Debug
|
||||
src/object_script.GoldenCheetah.Release
|
||||
qwt/src/object_script.libqwt.Release
|
||||
qwt/src/object_script.libqwtd.Debug
|
||||
qwt/src/Makefile.Release
|
||||
qwt/src/Makefile.Debug
|
||||
qwt/textengines/mathml/debug/
|
||||
qwt/textengines/mathml/release/
|
||||
build.pro.user
|
||||
|
||||
qwt/src/debug/
|
||||
qwt/src/release/
|
||||
src/Makefile.Debug
|
||||
src/Makefile.Release
|
||||
src/object_script.GoldenCheetah.Debug
|
||||
src/object_script.GoldenCheetah.Release
|
||||
qwt/src/object_script.libqwt.Release
|
||||
qwt/src/object_script.libqwtd.Debug
|
||||
qwt/src/Makefile.Release
|
||||
qwt/src/Makefile.Debug
|
||||
build.pro.user
|
||||
@@ -5,8 +5,8 @@
|
||||
Mark Liversedge
|
||||
John Ehrlinger
|
||||
|
||||
Jan 2015
|
||||
Version 1.2
|
||||
May 2011
|
||||
Version 1.1
|
||||
|
||||
A walkthrough of building GoldenCheetah from scratch on Ubuntu linux. This walkthrough
|
||||
should be largely the same for any Linux distro.
|
||||
@@ -30,6 +30,8 @@ CONTENTS
|
||||
- bison
|
||||
- libical - Diary window and CalDAV support (google/mobileme calendar integration)
|
||||
- libvlc - Video playback in training mode
|
||||
- clucene - Indexing/Searching ride files
|
||||
|
||||
|
||||
1. BASIC INSTALLATION WITH MANDATORY DEPENDENCIES
|
||||
=================================================
|
||||
@@ -371,3 +373,30 @@ VLC_INSTALL = /usr/include/vlc/
|
||||
$ make clean
|
||||
$ qmake
|
||||
$ make
|
||||
|
||||
CLUCENE - Indexing and Searching ride files (search box)
|
||||
--------------------------------------------------------
|
||||
|
||||
You will need clucene runtime and core libraries, we developed against 0.9.21b-2 but
|
||||
any 0.9 branch should work fine, let us know if you experience any issues. You may find
|
||||
that the libclucene0ldbl runtime is already installed, this is fine and typical since
|
||||
clucene is a very popular search library.
|
||||
|
||||
$ sudo apt-get install libclucene-dev
|
||||
$ sudo apt-get install libclucene0ldbl
|
||||
|
||||
By default, and this is deliberate, the clucene install places the config headers into
|
||||
a platform specific location. For my install I just copy the platform (linux) specific
|
||||
header config into the normal /usr/include/CLucene directory with the following:
|
||||
|
||||
$ sudo cp /usr/lib/CLucene/clucene-config.h /usr/include/CLucene
|
||||
|
||||
Next we need to comment out the two CLUCENE lines in gcconfig.pri and they should read:
|
||||
|
||||
CLUCENE_INCLUDE = /usr/include/CLucene
|
||||
CLUCENE_LIBS = -lclucene
|
||||
|
||||
$ make clean
|
||||
$ qmake
|
||||
$ make
|
||||
|
||||
|
||||
17
INSTALL-MAC
@@ -4,8 +4,8 @@
|
||||
|
||||
Mark Liversedge
|
||||
|
||||
Jan 2015
|
||||
Version 1.2
|
||||
Nov 2011
|
||||
Version 1.1
|
||||
|
||||
A walkthrough of building GoldenCheetah from scratch on Mac OSX. This was performed
|
||||
on Mac OSX Lion (10.7) but the instructions are largely the same for all versions of
|
||||
@@ -25,6 +25,7 @@ CONTENTS
|
||||
- libkml
|
||||
- libusb
|
||||
- libical
|
||||
- libclucene
|
||||
|
||||
|
||||
1. BASIC INSTALLATION WITH MANDATORY DEPENDENCIES
|
||||
@@ -296,3 +297,15 @@ libical (0.46)
|
||||
first run autogen.sh
|
||||
then
|
||||
./configure CFLAGS="-isysroot /Developer/SDKs/MacOSX10.7.sdk -arch x86_64" --disable-dependency-tracking
|
||||
|
||||
2.7 clucene
|
||||
-----------
|
||||
|
||||
DO NOT USE THE MACPORTS VERSION (0.9.23) IT DOES NOT WORK.
|
||||
|
||||
git clone git://clucene.git.sourceforge.net/gitroot/clucene/clucene
|
||||
cmake -G "Unix Makefiles"
|
||||
make
|
||||
sudo make install
|
||||
|
||||
will install clucene into /usr/local/include/clucene and /usr/local/lib
|
||||
|
||||
@@ -1,316 +0,0 @@
|
||||
From 7be04e65a53b22ce382d640a6c409b5d3bfe5645 Mon Sep 17 00:00:00 2001
|
||||
From: Joern <joern.rm@gmail.com>
|
||||
Date: Sat, 20 Dec 2014 12:42:37 +0100
|
||||
Subject: [PATCH] Patch-Windows-MingGW-subset for GC
|
||||
|
||||
... reduce the libs in Make to what GoldenCheetah needs
|
||||
... add two functions missing in MingGW standard libs
|
||||
---
|
||||
Makefile.am | 2 +-
|
||||
configure.ac | 44 -------------------
|
||||
src/Makefile.am | 2 +-
|
||||
src/kml/base/file_posix.cc | 102 ++++++++++++++++++++++++++++++++++++++++++++
|
||||
src/kml/base/string_util.cc | 17 ++++++++
|
||||
third_party/Makefile.am | 42 +++---------------
|
||||
6 files changed, 126 insertions(+), 83 deletions(-)
|
||||
|
||||
diff --git a/Makefile.am b/Makefile.am
|
||||
index 2be0803..e29201e 100644
|
||||
--- a/Makefile.am
|
||||
+++ b/Makefile.am
|
||||
@@ -1,7 +1,7 @@
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
|
||||
# Order is important:
|
||||
-SUBDIRS = third_party src testdata examples msvc xcode
|
||||
+SUBDIRS = third_party src
|
||||
|
||||
EXTRA_DIST = \
|
||||
AUTHORS \
|
||||
diff --git a/configure.ac b/configure.ac
|
||||
index d5fa75f..033128b 100644
|
||||
--- a/configure.ac
|
||||
+++ b/configure.ac
|
||||
@@ -203,23 +203,6 @@ AC_CHECK_LIB(pthread, pthread_create,,
|
||||
|
||||
AC_CONFIG_FILES([
|
||||
Makefile
|
||||
- examples/Makefile
|
||||
- examples/domviewer/Makefile
|
||||
- examples/engine/Makefile
|
||||
- examples/gpx/Makefile
|
||||
- examples/gx/Makefile
|
||||
- examples/hellonet/Makefile
|
||||
- examples/helloworld/Makefile
|
||||
- examples/java/Makefile
|
||||
- examples/kml/Makefile
|
||||
- examples/python/Makefile
|
||||
- examples/regionator/Makefile
|
||||
- examples/wxregionator/Makefile
|
||||
- examples/wxviewer/Makefile
|
||||
- examples/xsd/Makefile
|
||||
- msvc/Makefile
|
||||
- msvc/examples/Makefile
|
||||
- msvc/tests/Makefile
|
||||
src/Makefile
|
||||
src/kml/Makefile
|
||||
src/kml/convenience/Makefile
|
||||
@@ -228,34 +211,7 @@ AC_CONFIG_FILES([
|
||||
src/kml/regionator/Makefile
|
||||
src/kml/base/Makefile
|
||||
src/kml/xsd/Makefile
|
||||
- src/swig/Makefile
|
||||
- src/swig/java/Makefile
|
||||
- src/swig/python/Makefile
|
||||
- testdata/Makefile
|
||||
- testdata/atom/Makefile
|
||||
- testdata/balloon/Makefile
|
||||
- testdata/csv/Makefile
|
||||
- testdata/deprecated/Makefile
|
||||
- testdata/gdata/Makefile
|
||||
- testdata/gmaps/Makefile
|
||||
- testdata/gpx/Makefile
|
||||
- testdata/gx/Makefile
|
||||
- testdata/kml/Makefile
|
||||
- testdata/kmz/Makefile
|
||||
- testdata/kmz/files/Makefile
|
||||
- testdata/kmz/kmzfiles/Makefile
|
||||
- testdata/kmz/rumsey/Makefile
|
||||
- testdata/kmz/rumsey/kml/Makefile
|
||||
- testdata/kmz/rumsey/imagery/Makefile
|
||||
- testdata/links/Makefile
|
||||
- testdata/style/Makefile
|
||||
- testdata/style/weather/Makefile
|
||||
- testdata/update/Makefile
|
||||
- testdata/xal/Makefile
|
||||
- testdata/xsd/Makefile
|
||||
third_party/Makefile
|
||||
- xcode/Makefile
|
||||
- xcode/LibKML/Makefile
|
||||
])
|
||||
|
||||
AC_OUTPUT
|
||||
diff --git a/src/Makefile.am b/src/Makefile.am
|
||||
index 0bf15ac..721209e 100644
|
||||
--- a/src/Makefile.am
|
||||
+++ b/src/Makefile.am
|
||||
@@ -1,4 +1,4 @@
|
||||
-SUBDIRS = kml swig
|
||||
+SUBDIRS = kml
|
||||
|
||||
# TODO: use the phc files in msvc.
|
||||
EXTRA_DIST = \
|
||||
diff --git a/src/kml/base/file_posix.cc b/src/kml/base/file_posix.cc
|
||||
index b9461c0..920a996 100644
|
||||
--- a/src/kml/base/file_posix.cc
|
||||
+++ b/src/kml/base/file_posix.cc
|
||||
@@ -33,8 +33,110 @@
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h> // For unlink, close.
|
||||
|
||||
+// START PATCH
|
||||
+#include <fcntl.h>
|
||||
+#include <sys/time.h>
|
||||
+#include <sys/stat.h>
|
||||
+// END PATCH
|
||||
+
|
||||
namespace kmlbase {
|
||||
|
||||
+// START PATCH
|
||||
+// Implementation of missing functions
|
||||
+
|
||||
+/* mkstemp extracted from libc/sysdeps/posix/tempname.c. Copyright
|
||||
+ (C) 1991-1999, 2000, 2001, 2006 Free Software Foundation, Inc.
|
||||
+
|
||||
+ The GNU C Library is free software; you can redistribute it and/or
|
||||
+ modify it under the terms of the GNU Lesser General Public
|
||||
+ License as published by the Free Software Foundation; either
|
||||
+ version 2.1 of the License, or (at your option) any later version. */
|
||||
+
|
||||
+static const char letters[] =
|
||||
+"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
||||
+
|
||||
+/* Generate a temporary file name based on TMPL. TMPL must match the
|
||||
+ rules for mk[s]temp (i.e. end in "XXXXXX"). The name constructed
|
||||
+ does not exist at the time of the call to mkstemp. TMPL is
|
||||
+ overwritten with the result. */
|
||||
+int
|
||||
+mkstemp (char *tmpl)
|
||||
+{
|
||||
+ int len;
|
||||
+ char *XXXXXX;
|
||||
+ static unsigned long value;
|
||||
+ unsigned long random_time_bits;
|
||||
+ unsigned int count;
|
||||
+ int fd = -1;
|
||||
+ int save_errno = errno;
|
||||
+
|
||||
+ /* A lower bound on the number of temporary files to attempt to
|
||||
+ generate. The maximum total number of temporary file names that
|
||||
+ can exist for a given template is 62**6. It should never be
|
||||
+ necessary to try all these combinations. Instead if a reasonable
|
||||
+ number of names is tried (we define reasonable as 62**3) fail to
|
||||
+ give the system administrator the chance to remove the problems. */
|
||||
+#define ATTEMPTS_MIN (62 * 62 * 62)
|
||||
+
|
||||
+ /* The number of times to attempt to generate a temporary file. To
|
||||
+ conform to POSIX, this must be no smaller than TMP_MAX. */
|
||||
+#if ATTEMPTS_MIN < TMP_MAX
|
||||
+ unsigned int attempts = TMP_MAX;
|
||||
+#else
|
||||
+ unsigned int attempts = ATTEMPTS_MIN;
|
||||
+#endif
|
||||
+
|
||||
+ len = strlen (tmpl);
|
||||
+ if (len < 6 || strcmp (&tmpl[len - 6], "XXXXXX"))
|
||||
+ {
|
||||
+ errno = EINVAL;
|
||||
+ return -1;
|
||||
+ }
|
||||
+
|
||||
+/* This is where the Xs start. */
|
||||
+ XXXXXX = &tmpl[len - 6];
|
||||
+
|
||||
+ /* Get some more or less random data. */
|
||||
+ {
|
||||
+ struct timeval tv;
|
||||
+ gettimeofday (&tv, NULL);
|
||||
+ random_time_bits = ((uint64_t) tv.tv_usec << 16) ^ tv.tv_sec;
|
||||
+ }
|
||||
+ value += random_time_bits ^ getpid ();
|
||||
+
|
||||
+ for (count = 0; count < attempts; value += 7777, ++count)
|
||||
+ {
|
||||
+ unsigned long v = value;
|
||||
+
|
||||
+ /* Fill in the random bits. */
|
||||
+ XXXXXX[0] = letters[v % 62];
|
||||
+ v /= 62;
|
||||
+ XXXXXX[1] = letters[v % 62];
|
||||
+ v /= 62;
|
||||
+ XXXXXX[2] = letters[v % 62];
|
||||
+ v /= 62;
|
||||
+ XXXXXX[3] = letters[v % 62];
|
||||
+ v /= 62;
|
||||
+ XXXXXX[4] = letters[v % 62];
|
||||
+ v /= 62;
|
||||
+ XXXXXX[5] = letters[v % 62];
|
||||
+
|
||||
+ fd = open (tmpl, O_RDWR | O_CREAT | O_EXCL, _S_IREAD | _S_IWRITE);
|
||||
+ if (fd >= 0)
|
||||
+ {
|
||||
+ errno = save_errno;
|
||||
+ return fd;
|
||||
+ }
|
||||
+ else if (errno != EEXIST)
|
||||
+ return -1;
|
||||
+ }
|
||||
+
|
||||
+ /* We got out of the loop because we ran out of combinations to try. */
|
||||
+ errno = EEXIST;
|
||||
+ return -1;
|
||||
+}
|
||||
+// END PATCH
|
||||
+
|
||||
// Internal to the POSIX File class.
|
||||
static bool StatFile(const char* path, struct stat* stat_data) {
|
||||
struct stat tmp;
|
||||
diff --git a/src/kml/base/string_util.cc b/src/kml/base/string_util.cc
|
||||
index b3a9654..3fdba2b 100644
|
||||
--- a/src/kml/base/string_util.cc
|
||||
+++ b/src/kml/base/string_util.cc
|
||||
@@ -31,6 +31,23 @@
|
||||
|
||||
namespace kmlbase {
|
||||
|
||||
+// START PATCH
|
||||
+int strncasecmp(const char *s1, const char *s2, size_t n) {
|
||||
+ while (*s1 != 0 && tolower(*s1) == tolower(*s2)) {
|
||||
+ ++s1;
|
||||
+ ++s2;
|
||||
+ }
|
||||
+
|
||||
+ return
|
||||
+ (*s2 == 0)
|
||||
+ ? (*s1 != 0)
|
||||
+ : (*s1 == 0)
|
||||
+ ? -1
|
||||
+ : (tolower(*s1) - tolower(*s2));
|
||||
+}
|
||||
+
|
||||
+// ENDPATCH
|
||||
+
|
||||
void b2a_hex(uint32_t i, char* out) {
|
||||
char map[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'a', 'b', 'c', 'd', 'e', 'f'};
|
||||
diff --git a/third_party/Makefile.am b/third_party/Makefile.am
|
||||
index b73dec3..fe34dea 100644
|
||||
--- a/third_party/Makefile.am
|
||||
+++ b/third_party/Makefile.am
|
||||
@@ -12,7 +12,7 @@ AM_CPPFLAGS = -I$(top_srcdir)/third_party/zlib-1.2.3/contrib \
|
||||
-I$(top_srcdir)/third_party/gtest-1.7.0/include
|
||||
|
||||
lib_LTLIBRARIES = libminizip.la liburiparser.la
|
||||
-noinst_LTLIBRARIES = libgtest.la libgtest_main.la
|
||||
+#noinst_LTLIBRARIES = libgtest.la libgtest_main.la
|
||||
|
||||
libminizip_la_SOURCES = \
|
||||
zlib-1.2.3/contrib/minizip/unzip.c \
|
||||
@@ -83,11 +83,11 @@ libboostconfigplatforminclude_HEADERS = \
|
||||
$(boost)/config/platform/linux.hpp \
|
||||
$(boost)/config/platform/macos.hpp
|
||||
|
||||
-libgtest_la_SOURCES = \
|
||||
- gtest-1.7.0/src/gtest-all.cc
|
||||
+#libgtest_la_SOURCES = \
|
||||
+# gtest-1.7.0/src/gtest-all.cc
|
||||
|
||||
-libgtest_main_la_SOURCES = gtest-1.7.0/src/gtest_main.cc
|
||||
-libgtest_main_la_LIBADD = libgtest.la
|
||||
+#libgtest_main_la_SOURCES = gtest-1.7.0/src/gtest_main.cc
|
||||
+#libgtest_main_la_LIBADD = libgtest.la
|
||||
|
||||
# TODO: add the new gtest libs for windows.
|
||||
# gtest-1.7.0.win32/debug/gtest.lib \
|
||||
@@ -149,38 +149,6 @@ EXTRA_DIST = \
|
||||
$(boost)/config/stdlib/sgi.hpp \
|
||||
$(boost)/config/stdlib/stlport.hpp \
|
||||
$(boost)/config/stdlib/vacpp.hpp \
|
||||
- gtest-1.7.0/include/gtest/gtest-death-test.h \
|
||||
- gtest-1.7.0/include/gtest/gtest-message.h \
|
||||
- gtest-1.7.0/include/gtest/gtest-param-test.h \
|
||||
- gtest-1.7.0/include/gtest/gtest-param-test.h.pump \
|
||||
- gtest-1.7.0/include/gtest/gtest-printers.h \
|
||||
- gtest-1.7.0/include/gtest/gtest-spi.h \
|
||||
- gtest-1.7.0/include/gtest/gtest-test-part.h \
|
||||
- gtest-1.7.0/include/gtest/gtest-typed-test.h \
|
||||
- gtest-1.7.0/include/gtest/gtest.h \
|
||||
- gtest-1.7.0/include/gtest/gtest_pred_impl.h \
|
||||
- gtest-1.7.0/include/gtest/gtest_prod.h \
|
||||
- gtest-1.7.0/include/gtest/internal/gtest-death-test-internal.h \
|
||||
- gtest-1.7.0/include/gtest/internal/gtest-filepath.h \
|
||||
- gtest-1.7.0/include/gtest/internal/gtest-internal.h \
|
||||
- gtest-1.7.0/include/gtest/internal/gtest-linked_ptr.h \
|
||||
- gtest-1.7.0/include/gtest/internal/gtest-param-util-generated.h \
|
||||
- gtest-1.7.0/include/gtest/internal/gtest-param-util-generated.h.pump \
|
||||
- gtest-1.7.0/include/gtest/internal/gtest-param-util.h \
|
||||
- gtest-1.7.0/include/gtest/internal/gtest-port.h \
|
||||
- gtest-1.7.0/include/gtest/internal/gtest-string.h \
|
||||
- gtest-1.7.0/include/gtest/internal/gtest-tuple.h \
|
||||
- gtest-1.7.0/include/gtest/internal/gtest-tuple.h.pump \
|
||||
- gtest-1.7.0/include/gtest/internal/gtest-type-util.h \
|
||||
- gtest-1.7.0/include/gtest/internal/gtest-type-util.h.pump \
|
||||
- gtest-1.7.0/src/gtest-death-test.cc \
|
||||
- gtest-1.7.0/src/gtest-filepath.cc \
|
||||
- gtest-1.7.0/src/gtest-internal-inl.h \
|
||||
- gtest-1.7.0/src/gtest-port.cc \
|
||||
- gtest-1.7.0/src/gtest-printers.cc \
|
||||
- gtest-1.7.0/src/gtest-test-part.cc \
|
||||
- gtest-1.7.0/src/gtest-typed-test.cc \
|
||||
- gtest-1.7.0/src/gtest.cc \
|
||||
uriparser-0.7.5/COPYING \
|
||||
uriparser-0.7.5.win32/debug/uriparser.lib \
|
||||
uriparser-0.7.5.win32/release/uriparser.lib \
|
||||
--
|
||||
1.9.5.github.0
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
|
||||
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
|
||||
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.DEPENDENCIES"/>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry kind="src" path="gen"/>
|
||||
<classpathentry kind="output" path="bin/classes"/>
|
||||
</classpath>
|
||||
12
contrib/RideLogger/.gitignore
vendored
@@ -1,12 +0,0 @@
|
||||
# Ignores for Eclipse
|
||||
/.settings/
|
||||
|
||||
# Ignores for Android Projects
|
||||
/bin/
|
||||
/gen/
|
||||
/publish/
|
||||
/local.properties
|
||||
/secure.properties
|
||||
|
||||
# Ignores for Mac machines
|
||||
.DS_Store
|
||||
@@ -1,39 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE AndroidXML>
|
||||
<manifest
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:installLocation="auto"
|
||||
package="com.ridelogger"
|
||||
android:versionCode="040000"
|
||||
android:versionName="4.0.0"
|
||||
android:icon="@drawable/ic_launcher" >
|
||||
<uses-sdk android:minSdkVersion="14"
|
||||
android:targetSdkVersion="21" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
|
||||
<uses-permission android:name="android.permission.SEND_SMS"/>
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:icon="@drawable/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@android:style/Theme.DeviceDefault.Light" >
|
||||
<service
|
||||
android:name="com.ridelogger.RideService"
|
||||
android:icon="@drawable/ic_launcher"
|
||||
android:label="@string/service_name" >
|
||||
</service>
|
||||
<activity
|
||||
android:name="com.ridelogger.StartActivity"
|
||||
android:label="@string/app_name" >
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name="com.ridelogger.SettingsActivity"
|
||||
android:label="@string/setting_title" >
|
||||
</activity>
|
||||
</application>
|
||||
</manifest>
|
||||
|
Before Width: | Height: | Size: 176 KiB |
@@ -1,3 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<lint>
|
||||
</lint>
|
||||
@@ -1,68 +0,0 @@
|
||||
# This is a configuration file for ProGuard.
|
||||
# http://proguard.sourceforge.net/index.html#manual/usage.html
|
||||
|
||||
# Optimizations: If you don't want to optimize, use the
|
||||
# proguard-android.txt configuration file instead of this one, which
|
||||
# turns off the optimization flags. Adding optimization introduces
|
||||
# certain risks, since for example not all optimizations performed by
|
||||
# ProGuard works on all versions of Dalvik. The following flags turn
|
||||
# off various optimizations known to have issues, but the list may not
|
||||
# be complete or up to date. (The "arithmetic" optimization can be
|
||||
# used if you are only targeting Android 2.0 or later.) Make sure you
|
||||
# test thoroughly if you go this route.
|
||||
-optimizations code/simplification/arithmetic,code/simplification/cast,field/*,class/merging/*
|
||||
-optimizationpasses 24
|
||||
-allowaccessmodification
|
||||
-dontpreverify
|
||||
|
||||
# The remainder of this file is identical to the non-optimized version
|
||||
# of the Proguard configuration file (except that the other file has
|
||||
# flags to turn off optimization).
|
||||
|
||||
-dontusemixedcaseclassnames
|
||||
-dontskipnonpubliclibraryclasses
|
||||
-verbose
|
||||
|
||||
-keepattributes *Annotation*
|
||||
-keep public class com.google.vending.licensing.ILicensingService
|
||||
-keep public class com.android.vending.licensing.ILicensingService
|
||||
|
||||
# For native methods, see http://proguard.sourceforge.net/manual/examples.html#native
|
||||
-keepclasseswithmembernames class * {
|
||||
native <methods>;
|
||||
}
|
||||
|
||||
# keep setters in Views so that animations can still work.
|
||||
# see http://proguard.sourceforge.net/manual/examples.html#beans
|
||||
-keepclassmembers public class * extends android.view.View {
|
||||
void set*(***);
|
||||
*** get*();
|
||||
}
|
||||
|
||||
# We want to keep methods in Activity that could be used in the XML attribute onClick
|
||||
-keepclassmembers class * extends android.app.Activity {
|
||||
public void *(android.view.View);
|
||||
}
|
||||
|
||||
# For enumeration classes, see http://proguard.sourceforge.net/manual/examples.html#enumerations
|
||||
-keepclassmembers enum * {
|
||||
public static **[] values();
|
||||
public static ** valueOf(java.lang.String);
|
||||
}
|
||||
|
||||
-keep class * implements android.os.Parcelable {
|
||||
public static final android.os.Parcelable$Creator *;
|
||||
}
|
||||
|
||||
-keepclassmembers class **.R$* {
|
||||
public static <fields>;
|
||||
}
|
||||
|
||||
# The support library contains references to newer platform versions.
|
||||
# Don't warn about those in case this app is linking against an older
|
||||
# platform version. We know about them, and they are safe.
|
||||
-dontwarn android.support.**
|
||||
|
||||
-keep public class com.ridelogger.SettingsActivity$GeneralFragment
|
||||
-keep public class com.ridelogger.SettingsActivity$AntFragment
|
||||
-keep public class com.ridelogger.SettingsActivity$SensorsFragment
|
||||
@@ -1,15 +0,0 @@
|
||||
# This file is automatically generated by Android Tools.
|
||||
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
|
||||
#
|
||||
# This file must be checked in Version Control Systems.
|
||||
#
|
||||
# To customize properties used by the Ant build system edit
|
||||
# "ant.properties", and override values to adapt the script to your
|
||||
# project structure.
|
||||
#
|
||||
# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
|
||||
proguard.config=proguard-android-optimize.txt
|
||||
|
||||
# Project target.
|
||||
target=android-21
|
||||
min=android-14
|
||||
|
Before Width: | Height: | Size: 7.8 KiB |
|
Before Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 4.4 KiB |
|
Before Width: | Height: | Size: 12 KiB |
@@ -1,10 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE AndroidXML>
|
||||
<GridView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/LayoutData"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:numColumns="auto_fit"
|
||||
android:stretchMode="columnWidth"
|
||||
android:gravity="right"
|
||||
/>
|
||||
@@ -1,13 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<preference-headers
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<header android:fragment="com.ridelogger.SettingsActivity$GeneralFragment"
|
||||
android:title="@string/setting_general_title"
|
||||
android:summary="@string/setting_general_note" />
|
||||
<header android:fragment="com.ridelogger.SettingsActivity$AntFragment"
|
||||
android:title="@string/setting_ant_title"
|
||||
android:summary="@string/setting_ant_note" />
|
||||
<header android:fragment="com.ridelogger.SettingsActivity$SensorsFragment"
|
||||
android:title="@string/setting_sensors_title"
|
||||
android:summary="@string/setting_sensors_note" />
|
||||
</preference-headers>
|
||||
@@ -1,11 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||
|
||||
<item android:id="@+id/Start"
|
||||
android:title="@string/start" />
|
||||
<item android:id="@+id/Stop"
|
||||
android:title="@string/stop" />
|
||||
<item android:id="@+id/Settings"
|
||||
android:title="@string/edit_settings"
|
||||
android:showAsAction="never" />
|
||||
</menu>
|
||||
@@ -1,97 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE AndroidXML>
|
||||
<resources>
|
||||
<string name="app_name">Ride Logger</string>
|
||||
<string name="service_name">Logging Ride</string>
|
||||
|
||||
<string name="emergency_contact_dialog_title">Emergency Contact</string>
|
||||
<string name="emergency_contact_dialog_note">Should a text messesage be sent on ride start and periodically to let your emergency contact know you are alright?</string>
|
||||
|
||||
<string name="sms_period_dialog_title">Emergency Contact SMS Period</string>
|
||||
<string name="sms_period_dialog_note">Period in Minutes:</string>
|
||||
|
||||
<string name="crash_detection_dialog_title">Crash Detection</string>
|
||||
<string name="crash_detection_dialog_note">Should a text messesage be sent on crash detction to your emergency contact?</string>
|
||||
|
||||
<string name="emergency_contact_number_dialog_title">Emergency Contact Number</string>
|
||||
<string name="emergency_contact_number_dialog_note">Emergency phone number to update position on crash detection</string>
|
||||
|
||||
<string name="ant_setup_title">Set Ant+</string>
|
||||
<string name="ant_setup_note">Pair your Ant+ devices now?</string>
|
||||
|
||||
<string name="ant_pair_dialog_title">Select Ant Devices</string>
|
||||
<string name="ant_pair_dialog_button_note">Pair</string>
|
||||
|
||||
<string name="gc_rider_name_dialog_title">Enter Rider Name</string>
|
||||
<string name="gc_rider_name_dialog_note">What is your Golder Cheata Rider Name?</string>
|
||||
|
||||
<string name="save_setting_button">Next</string>
|
||||
<string name="skip_setting_button">Skip</string>
|
||||
|
||||
<string name="boolean_dialog_yes">Yes</string>
|
||||
<string name="boolean_dialog_no">No</string>
|
||||
|
||||
<string name="starting_ride">Starting Ride!</string>
|
||||
<string name="stopping_ride">Stoping Ride!</string>
|
||||
|
||||
<string name="ride_on">Ride On</string>
|
||||
<string name="building_ride">Building ride: </string>
|
||||
|
||||
<string name="click_to_stop"> Click to stop ride.</string>
|
||||
|
||||
<string name="ride_start_title">Start Ride</string>
|
||||
<string name="ride_start_note">Make sure locations is turned on. Internet connection is NOT required.</string>
|
||||
|
||||
<string name="start">Start Logging</string>
|
||||
<string name="edit_settings">Settings</string>
|
||||
|
||||
<string name="ride_stop_title">Ride in Progress</string>
|
||||
<string name="ride_stop_note">Would you like to stop the ride or view current values.</string>
|
||||
|
||||
<string name="stop">Stop Logging</string>
|
||||
<string name="view">View</string>
|
||||
|
||||
<string name="crash_warning">WARNING CRASH!</string>
|
||||
<string name="crash_confirm">CRASH CONFIRMED!</string>
|
||||
<string name="crash_unknow_location">Unknow location.</string>
|
||||
<string name="crash_magnitude">Mag</string>
|
||||
|
||||
<string name="ride_start_sms">I\'m starting my ride.</string>
|
||||
<string name="ride_stop_sms">I have finished my ride.</string>
|
||||
<string name="riding_ok_sms">I\'m ok.</string>
|
||||
|
||||
<string name="setting_title">Settings</string>
|
||||
|
||||
<string name="setting_general_title">General</string>
|
||||
<string name="setting_general_note">Settings</string>
|
||||
|
||||
<string name="setting_ant_title">Ant+</string>
|
||||
<string name="setting_ant_note">Setup your Ant+ Devices</string>
|
||||
|
||||
<string name="searching_for_ants">Searching for Ant+ Devices...</string>
|
||||
<string name="found_ants">Found Ant+ Devices, Press to Pair.</string>
|
||||
<string name="no_found_ants">Nothing found to pair.</string>
|
||||
|
||||
<string name="setting_sensors_title">Display Sensors</string>
|
||||
<string name="setting_sensors_note">List of Sensors Display</string>
|
||||
|
||||
<string name="setting_wheel_size">Wheel Circumference in Meters</string>
|
||||
|
||||
<string name="imperial_units_title">Imperial Units</string>
|
||||
<string name="imperial_units_note">Show Measurements in Imperial Units</string>
|
||||
|
||||
<string name="setting_size_title">Display Text Size</string>
|
||||
|
||||
<string name="PREFS_NAME">RideLogger</string>
|
||||
<string name="PREF_RIDER_NAME">RiderName</string>
|
||||
<string name="PREF_EMERGENCY_NUMBER">EmergencyNumbuer</string>
|
||||
<string name="PREF_DETECT_CRASH">DetectCrash</string>
|
||||
<string name="PREF_PHONE_HOME">PhoneHome</string>
|
||||
<string name="PREF_PAIRED_ANTS">PairedAnts</string>
|
||||
<string name="PREF_PHONE_HOME_PERIOD">PhoneHomePeriod</string>
|
||||
<string name="PREF_TRACKING_SENSORS">TrackingSensors</string>
|
||||
<string name="PREF_TRACKING_SIZE">TrackingSize</string>
|
||||
<string name="PREF_TRACKING_IMPERIAL_UNITS">TrackingImperialUnits</string>
|
||||
<string name="PREF_WHEEL_SIZE">WheelSize</string>
|
||||
|
||||
</resources>
|
||||
@@ -1,20 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||
<PreferenceCategory
|
||||
android:title="@string/PREFS_NAME">
|
||||
|
||||
<MultiSelectListPreference
|
||||
android:key="@string/PREF_PAIRED_ANTS"
|
||||
android:title="@string/ant_pair_dialog_title"
|
||||
android:summary="@string/ant_pair_dialog_button_note"
|
||||
/>
|
||||
|
||||
<EditTextPreference
|
||||
android:key="@string/PREF_WHEEL_SIZE"
|
||||
android:title="@string/setting_wheel_size"
|
||||
android:defaultValue="2.096"
|
||||
/>
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
</PreferenceScreen>
|
||||
@@ -1,42 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||
<PreferenceCategory
|
||||
android:title="@string/PREFS_NAME"
|
||||
android:persistent="true">
|
||||
|
||||
<EditTextPreference
|
||||
android:key="@string/PREF_RIDER_NAME"
|
||||
android:title="@string/gc_rider_name_dialog_title"
|
||||
android:summary="@string/gc_rider_name_dialog_note" />
|
||||
|
||||
<EditTextPreference
|
||||
android:key="@string/PREF_EMERGENCY_NUMBER"
|
||||
android:title="@string/emergency_contact_number_dialog_title"
|
||||
android:summary="@string/emergency_contact_number_dialog_note" />
|
||||
|
||||
<CheckBoxPreference
|
||||
android:layout="?android:attr/preferenceLayoutChild"
|
||||
android:dependency="@string/PREF_EMERGENCY_NUMBER"
|
||||
android:key="@string/PREF_DETECT_CRASH"
|
||||
android:title="@string/crash_detection_dialog_title"
|
||||
android:summary="@string/crash_detection_dialog_note" />
|
||||
|
||||
<!-- The visual style of a child is defined by this styled theme attribute. -->
|
||||
<CheckBoxPreference
|
||||
android:layout="?android:attr/preferenceLayoutChild"
|
||||
android:dependency="@string/PREF_EMERGENCY_NUMBER"
|
||||
android:key="@string/PREF_PHONE_HOME"
|
||||
android:title="@string/emergency_contact_dialog_title"
|
||||
android:summary="@string/emergency_contact_dialog_note" />
|
||||
|
||||
<EditTextPreference
|
||||
android:layout="?android:attr/preferenceLayoutChild"
|
||||
android:dependency="@string/PREF_PHONE_HOME"
|
||||
android:key="@string/PREF_PHONE_HOME_PERIOD"
|
||||
android:title="@string/sms_period_dialog_title"
|
||||
android:summary="@string/sms_period_dialog_note"
|
||||
android:defaultValue="20" />
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
</PreferenceScreen>
|
||||
@@ -1,25 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||
<PreferenceCategory
|
||||
android:title="@string/PREFS_NAME">
|
||||
|
||||
<MultiSelectListPreference
|
||||
android:key="@string/PREF_TRACKING_SENSORS"
|
||||
android:title="@string/setting_sensors_title"
|
||||
android:summary="@string/setting_sensors_note"
|
||||
/>
|
||||
<CheckBoxPreference
|
||||
android:key="@string/PREF_TRACKING_IMPERIAL_UNITS"
|
||||
android:title="@string/imperial_units_title"
|
||||
android:summary="@string/imperial_units_note"
|
||||
/>
|
||||
|
||||
<EditTextPreference
|
||||
android:key="@string/PREF_TRACKING_SIZE"
|
||||
android:title="@string/setting_size_title"
|
||||
android:defaultValue="20"
|
||||
/>
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
</PreferenceScreen>
|
||||
@@ -1,281 +0,0 @@
|
||||
package com.ridelogger;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import android.content.SharedPreferences;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.Typeface;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.util.TypedValue;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.BaseAdapter;
|
||||
import android.widget.GridView;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
public class CurrentValuesAdapter extends BaseAdapter {
|
||||
private StartActivity context;
|
||||
|
||||
private int[] keys;
|
||||
private String[] values;
|
||||
private String[] keyLabels;
|
||||
private int size = 20;
|
||||
private boolean imperial = false;
|
||||
private SharedPreferences settings = null;
|
||||
|
||||
private GridView layout;
|
||||
|
||||
public CurrentValuesAdapter(StartActivity c, GridView pLayout) {
|
||||
context = c;
|
||||
layout = pLayout;
|
||||
|
||||
layout.setBackgroundColor(Color.BLACK);
|
||||
layout.setVerticalSpacing(4);
|
||||
layout.setHorizontalSpacing(4);
|
||||
|
||||
settings = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
Set<String> sensors = settings.getStringSet(context.getString(R.string.PREF_TRACKING_SENSORS), null);
|
||||
|
||||
size = Integer.valueOf(settings.getString(context.getString(R.string.PREF_TRACKING_SIZE), "20"));
|
||||
imperial = settings.getBoolean(context.getString(R.string.PREF_TRACKING_IMPERIAL_UNITS), false);
|
||||
|
||||
initKeys(sensors);
|
||||
initKeyLables();
|
||||
initValues();
|
||||
|
||||
settings.registerOnSharedPreferenceChangeListener(
|
||||
new SharedPreferences.OnSharedPreferenceChangeListener() {
|
||||
@Override
|
||||
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String pkey) {
|
||||
if(pkey == context.getString(R.string.PREF_TRACKING_SIZE)) {
|
||||
size = Integer.valueOf(sharedPreferences.getString(context.getString(R.string.PREF_TRACKING_SIZE), "20"));
|
||||
setupWidth();
|
||||
notifyDataSetChanged();
|
||||
} else if (pkey == context.getString(R.string.PREF_TRACKING_SENSORS)) {
|
||||
Set<String> sensors = sharedPreferences.getStringSet(context.getString(R.string.PREF_TRACKING_SENSORS), null);
|
||||
|
||||
initKeys(sensors);
|
||||
initKeyLables();
|
||||
initValues();
|
||||
|
||||
layout.setAdapter(CurrentValuesAdapter.this);
|
||||
notifyDataSetChanged();
|
||||
} else if (pkey == context.getString(R.string.PREF_TRACKING_IMPERIAL_UNITS)) {
|
||||
imperial = sharedPreferences.getBoolean(pkey, false);
|
||||
|
||||
initKeyLables();
|
||||
initValues();
|
||||
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
private void initKeys(Set<String> sensors) {
|
||||
if(sensors != null && sensors.size() > 0) {
|
||||
keys = new int[sensors.size()];
|
||||
int i = 0;
|
||||
for(String sensor : sensors) {
|
||||
keys[i] = Integer.parseInt(sensor);
|
||||
i++;
|
||||
}
|
||||
} else {
|
||||
keys = new int[RideService.KEYS.length];
|
||||
for (int i = 0; i < RideService.KEYS.length; i++) {
|
||||
keys[i] = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void initKeyLables() {
|
||||
keyLabels = new String[keys.length];
|
||||
|
||||
if(!imperial) {
|
||||
for(int key : keys) {
|
||||
keyLabels[key] = RideService.KEYS[key].toString().toLowerCase();
|
||||
}
|
||||
} else {
|
||||
for(int key : keys) {
|
||||
switch (key) {
|
||||
case RideService.ALTITUDE:
|
||||
keyLabels[key] = "ft";
|
||||
break;
|
||||
|
||||
case RideService.KPH:
|
||||
keyLabels[key] = "mph";
|
||||
break;
|
||||
|
||||
case RideService.KM:
|
||||
keyLabels[key] = "m";
|
||||
break;
|
||||
|
||||
default:
|
||||
keyLabels[key] = RideService.KEYS[key].toString().toLowerCase();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void initValues() {
|
||||
values = new String[keys.length];
|
||||
for (int key : keys) {
|
||||
if(key == RideService.SECS) {
|
||||
values[key] = "00:00:00";
|
||||
} else {
|
||||
values[key] = "0.0";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private RelativeLayout newRelativeLayout(int key) {
|
||||
RelativeLayout view = new RelativeLayout(context);
|
||||
view.setBackgroundColor(Color.WHITE);
|
||||
|
||||
TextView valueView = newValueTv(key);
|
||||
TextView keyView = newKeyTv(key);
|
||||
|
||||
RelativeLayout.LayoutParams valueLayoutParams = new RelativeLayout.LayoutParams(
|
||||
RelativeLayout.LayoutParams.WRAP_CONTENT,
|
||||
RelativeLayout.LayoutParams.WRAP_CONTENT
|
||||
);
|
||||
|
||||
valueLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_TOP);
|
||||
valueLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
|
||||
|
||||
view.addView(valueView, valueLayoutParams);
|
||||
|
||||
RelativeLayout.LayoutParams keyLayoutParams = new RelativeLayout.LayoutParams(
|
||||
RelativeLayout.LayoutParams.WRAP_CONTENT,
|
||||
RelativeLayout.LayoutParams.WRAP_CONTENT
|
||||
);
|
||||
|
||||
keyLayoutParams.addRule(RelativeLayout.BELOW, valueView.getId());
|
||||
keyLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
|
||||
keyLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
|
||||
|
||||
view.addView(keyView, keyLayoutParams);
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
|
||||
private TextView newValueTv(int key){
|
||||
TextView tv = new TextView(context);
|
||||
tv.setTextAppearance(context, android.R.attr.textAppearanceLarge);
|
||||
tv.setTypeface(Typeface.MONOSPACE, Typeface.BOLD);
|
||||
tv.setTextSize(TypedValue.COMPLEX_UNIT_SP, size);
|
||||
tv.setText(values[key]);
|
||||
tv.setId(key + 1);
|
||||
return tv;
|
||||
}
|
||||
|
||||
|
||||
private TextView newKeyTv(int key){
|
||||
TextView tv = new TextView(context);
|
||||
tv.setTextSize(TypedValue.COMPLEX_UNIT_SP, 14);
|
||||
tv.setBackgroundColor(Color.LTGRAY);
|
||||
tv.setTypeface(Typeface.MONOSPACE, Typeface.BOLD);
|
||||
tv.setPadding(4, 1, 4, 1);
|
||||
tv.setText(keyLabels[key]);
|
||||
return tv;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return keys.length;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Object getItem(int position) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
if (convertView == null) {
|
||||
return newRelativeLayout(keys[position]);
|
||||
} else {
|
||||
RelativeLayout view = (RelativeLayout) convertView;
|
||||
TextView valueView = (TextView) (view.getChildAt(0));
|
||||
TextView valueKey = (TextView) (view.getChildAt(1));
|
||||
|
||||
if(valueView.getText() != values[keys[position]])
|
||||
valueView.setText(values[keys[position]]);
|
||||
|
||||
valueView.setTextSize(TypedValue.COMPLEX_UNIT_SP, size);
|
||||
|
||||
if(valueKey.getText() != keyLabels[keys[position]])
|
||||
valueKey.setText(keyLabels[keys[position]]);
|
||||
|
||||
return convertView;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void update(float[] current_float_values) {
|
||||
for (int key: keys) {
|
||||
if(key == RideService.SECS) {
|
||||
int hr = (int) (current_float_values[key]/3600);
|
||||
int rem = (int) (current_float_values[key]%3600);
|
||||
int mn = rem/60;
|
||||
int sec = rem%60;
|
||||
|
||||
values[key] = (hr<10 ? "0" : "") + hr + ":" + (mn<10 ? "0" : "") + mn + ":" + (sec<10 ? "0" : "")+sec;
|
||||
} else if(!imperial) {
|
||||
values[key] = String.format("%.1f", current_float_values[key]);
|
||||
} else {
|
||||
switch (key) {
|
||||
case RideService.ALTITUDE:
|
||||
values[key] = String.format("%.1f", current_float_values[key] * 3.28084);
|
||||
break;
|
||||
|
||||
case RideService.KPH:
|
||||
values[key] = String.format("%.1f", current_float_values[key] * 0.621371);
|
||||
break;
|
||||
|
||||
case RideService.KM:
|
||||
values[key] = String.format("%.1f", current_float_values[key] * 0.621371);
|
||||
break;
|
||||
|
||||
default:
|
||||
values[key] = String.format("%.1f", current_float_values[key]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the size of the cell basted on 8 chars wide and the configured size param
|
||||
* @return int
|
||||
*/
|
||||
private void setupWidth() {
|
||||
TextView tv = new TextView(context);
|
||||
tv.setTextAppearance(context, android.R.attr.textAppearanceLarge);
|
||||
tv.setTypeface(Typeface.MONOSPACE, Typeface.BOLD);
|
||||
tv.setTextSize(TypedValue.COMPLEX_UNIT_SP, size);
|
||||
tv.setText(String.format("%.1f", 1111.11));
|
||||
|
||||
Rect bounds = new Rect();
|
||||
tv.getPaint().getTextBounds("00:00:00", 0, "00:00:00".length(), bounds);
|
||||
|
||||
layout.setColumnWidth(bounds.width() + 16);
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
package com.ridelogger;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
|
||||
public class GzipWriter extends GZIPOutputStream {
|
||||
public GzipWriter(OutputStream os) throws IOException {
|
||||
super(os);
|
||||
}
|
||||
|
||||
public void write(String data) throws IOException {
|
||||
super.write(data.getBytes());
|
||||
}
|
||||
|
||||
public void write(float data) throws IOException {
|
||||
super.write(Float.floatToIntBits(data));
|
||||
}
|
||||
|
||||
public void write(CharSequence data) throws IOException {
|
||||
byte[] barr = new byte[data.length()];
|
||||
for (int i = 0; i < barr.length; i++) {
|
||||
barr[i] = (byte) data.charAt(i);
|
||||
}
|
||||
|
||||
super.write(barr);
|
||||
}
|
||||
}
|
||||
@@ -1,417 +0,0 @@
|
||||
package com.ridelogger;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Set;
|
||||
import java.util.TimeZone;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
import com.dsi.ant.plugins.antplus.pcc.defines.DeviceType;
|
||||
import com.dsi.ant.plugins.utility.log.LogAnt;
|
||||
import com.ridelogger.formats.BaseFormat;
|
||||
import com.ridelogger.formats.JsonFormat;
|
||||
import com.ridelogger.listners.Base;
|
||||
import com.ridelogger.listners.Gps;
|
||||
import com.ridelogger.listners.HeartRate;
|
||||
import com.ridelogger.listners.Power;
|
||||
import com.ridelogger.listners.Sensors;
|
||||
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.Service;
|
||||
import android.app.TaskStackBuilder;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.os.Environment;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.Message;
|
||||
import android.os.Messenger;
|
||||
import android.os.RemoteException;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.v4.app.NotificationCompat;
|
||||
import android.telephony.PhoneNumberUtils;
|
||||
import android.telephony.SmsManager;
|
||||
|
||||
|
||||
/**
|
||||
* RideService
|
||||
* @author Chet Henry
|
||||
* Performs ride logging from sensors as an android service
|
||||
*/
|
||||
public class RideService extends Service
|
||||
{
|
||||
public static final int notifyID = 1; //Id of the notification in the top android bar that this class creates and alters
|
||||
|
||||
public static final int SECS = 0;
|
||||
public static final int KPH = 1;
|
||||
public static final int ALTITUDE = 2;
|
||||
public static final int bearing = 3;
|
||||
public static final int gpsa = 4;
|
||||
public static final int LAT = 5;
|
||||
public static final int LON = 6;
|
||||
public static final int HR = 7;
|
||||
public static final int WATTS = 8;
|
||||
public static final int NM = 9;
|
||||
public static final int CAD = 10;
|
||||
public static final int KM = 11;
|
||||
public static final int LTE = 12;
|
||||
public static final int RTE = 13;
|
||||
public static final int SNPLC = 14;
|
||||
public static final int SNPR = 15;
|
||||
public static final int ms2x = 16;
|
||||
public static final int ms2y = 17;
|
||||
public static final int ms2z = 18;
|
||||
public static final int temp = 19;
|
||||
public static final int uTx = 20;
|
||||
public static final int uTy = 21;
|
||||
public static final int uTz = 22;
|
||||
public static final int press = 23;
|
||||
public static final int lux = 24;
|
||||
|
||||
public static CharSequence[] KEYS = {
|
||||
"SECS",
|
||||
"KPH",
|
||||
"ALTITUDE",
|
||||
"bearing",
|
||||
"gpsa",
|
||||
"LAT",
|
||||
"LON",
|
||||
"HR",
|
||||
"WATTS",
|
||||
"NM",
|
||||
"CAD",
|
||||
"KM",
|
||||
"LTE",
|
||||
"RTE",
|
||||
"SNPLC",
|
||||
"SNPR",
|
||||
"ms2x",
|
||||
"ms2y",
|
||||
"ms2z",
|
||||
"temp",
|
||||
"uTx",
|
||||
"uTy",
|
||||
"uTz",
|
||||
"press",
|
||||
"lux"
|
||||
};
|
||||
|
||||
public GzipWriter buf; //writes to log file buffered
|
||||
public long startTime; //start time of the ride
|
||||
public float[] currentValues = new float[RideService.KEYS.length]; //float array of current values
|
||||
private Messenger mMessenger = null; //class to send back current values if needed
|
||||
private boolean rideStarted = false; //have we started logging the ride
|
||||
private int sensor_index = 0; //current index of sensors
|
||||
private String emergencyNumbuer; //the number to send the messages to
|
||||
private Timer timer; //timer class to control the periodic messages
|
||||
private Timer timerUI; //timer class to control the periodic messages
|
||||
private Base<?>[] sensors; //list of sensors tracking
|
||||
public BaseFormat<?> fileFormat;
|
||||
|
||||
|
||||
/**
|
||||
* starts the ride on service start
|
||||
*/
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
startRide();
|
||||
return Service.START_NOT_STICKY;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* returns the messenger to talk to the app with
|
||||
*/
|
||||
@Override
|
||||
public IBinder onBind(Intent arg0) {
|
||||
mMessenger = new Messenger(new Handler() { // Handler of incoming messages from clients.
|
||||
Messenger replyTo;
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
if(timerUI != null) {
|
||||
timerUI.cancel();
|
||||
timerUI = null;
|
||||
}
|
||||
|
||||
timerUI = new Timer();
|
||||
|
||||
if(msg.replyTo != null) {
|
||||
replyTo = msg.replyTo;
|
||||
timerUI.scheduleAtFixedRate(
|
||||
new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
Message msg = Message.obtain(null, 2, 0, 0);
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putSerializable("currentValues", currentValues);
|
||||
msg.setData(bundle);
|
||||
try {
|
||||
replyTo.send(msg);
|
||||
} catch (RemoteException e) {}
|
||||
}
|
||||
},
|
||||
1000,
|
||||
1000
|
||||
); //every second update the screen
|
||||
}
|
||||
}
|
||||
}); // Target we publish for clients to send messages to IncomingHandler.
|
||||
|
||||
return mMessenger.getBinder();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* releases the timer that sends messages to the app
|
||||
*/
|
||||
@Override
|
||||
public boolean onUnbind (Intent intent) {
|
||||
if(timerUI != null) {
|
||||
timerUI.cancel();
|
||||
timerUI = null;
|
||||
}
|
||||
|
||||
mMessenger = null;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* stop the ride on service stop
|
||||
*/
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
stopRide();
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
/**
|
||||
* start a ride if there is not one started yet
|
||||
*/
|
||||
protected void startRide() {
|
||||
if(rideStarted) return;
|
||||
|
||||
SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
emergencyNumbuer = settings.getString(getString(R.string.PREF_EMERGENCY_NUMBER), "");
|
||||
currentValues[SECS] = (float) 0.0;
|
||||
|
||||
startTime = System.currentTimeMillis();
|
||||
|
||||
|
||||
Date startDate = new Date(startTime);
|
||||
|
||||
SimpleDateFormat startTimef = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
|
||||
SimpleDateFormat filef = new SimpleDateFormat("yyyy_MM_dd_HH_mm_ss");
|
||||
SimpleDateFormat month = new SimpleDateFormat("MMMMM");
|
||||
SimpleDateFormat year = new SimpleDateFormat("yyyy");
|
||||
SimpleDateFormat day = new SimpleDateFormat("EEEEE");
|
||||
|
||||
startTimef.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||
filef.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||
month.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||
year.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||
day.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||
|
||||
final String fileName = filef.format(startDate) + ".json.gz";
|
||||
|
||||
if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
|
||||
fileFormat = new JsonFormat(this);
|
||||
fileFormat.createFile();
|
||||
fileFormat.writeHeader();
|
||||
|
||||
LogAnt.setDebugLevel(LogAnt.DebugLevel.NONE, this);
|
||||
|
||||
final Set<String> pairedAnts = settings.getStringSet(getString(R.string.PREF_PAIRED_ANTS), null);
|
||||
|
||||
if(pairedAnts != null && !pairedAnts.isEmpty()){
|
||||
sensors = new Base<?>[pairedAnts.size() + 2];
|
||||
for(String deviceNumber: pairedAnts) {
|
||||
DeviceType deviceType = DeviceType.getValueFromInt(settings.getInt(deviceNumber, 0));
|
||||
switch (deviceType) {
|
||||
case BIKE_CADENCE:
|
||||
break;
|
||||
case BIKE_POWER:
|
||||
sensors[sensor_index++] = new Power(Integer.valueOf(deviceNumber), this);
|
||||
break;
|
||||
case BIKE_SPD:
|
||||
break;
|
||||
case BIKE_SPDCAD:
|
||||
break;
|
||||
case BLOOD_PRESSURE:
|
||||
break;
|
||||
case ENVIRONMENT:
|
||||
break;
|
||||
case WEIGHT_SCALE:
|
||||
break;
|
||||
case HEARTRATE:
|
||||
sensors[sensor_index++] = new HeartRate(Integer.valueOf(deviceNumber), this);
|
||||
break;
|
||||
case STRIDE_SDM:
|
||||
break;
|
||||
case FITNESS_EQUIPMENT:
|
||||
break;
|
||||
case GEOCACHE:
|
||||
case CONTROLLABLE_DEVICE:
|
||||
break;
|
||||
case UNKNOWN:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
sensors = new Base<?>[4];
|
||||
sensors[sensor_index++] = new HeartRate(0, this);
|
||||
sensors[sensor_index++] = new Power(0, this);
|
||||
}
|
||||
|
||||
sensors[sensor_index++] = new Gps(this);
|
||||
sensors[sensor_index++] = new Sensors(this);
|
||||
}
|
||||
rideStarted = true;
|
||||
|
||||
if(settings.getBoolean(getString(R.string.PREF_PHONE_HOME), false)) {
|
||||
timer = new Timer();
|
||||
int period = Integer.parseInt(settings.getString(getString(R.string.PREF_PHONE_HOME_PERIOD), "10"));
|
||||
|
||||
timer.scheduleAtFixedRate(
|
||||
new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
phoneHome();
|
||||
}
|
||||
},
|
||||
60000 * period,
|
||||
60000 * period
|
||||
); //every ten min let them know where you are at
|
||||
phoneStart();
|
||||
}
|
||||
|
||||
//build the notification in the top android drawer
|
||||
NotificationCompat.Builder mBuilder = new NotificationCompat
|
||||
.Builder(this)
|
||||
.setSmallIcon(R.drawable.ic_launcher)
|
||||
.setContentTitle(getString(R.string.ride_on))
|
||||
.setContentText(getString(R.string.building_ride) + " " + fileName + " " + getString(R.string.click_to_stop))
|
||||
.setProgress(0, 0, true)
|
||||
.setContentIntent(
|
||||
TaskStackBuilder
|
||||
.create(this)
|
||||
.addParentStack(StartActivity.class)
|
||||
.addNextIntent(new Intent(this, StartActivity.class))
|
||||
.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT)
|
||||
);
|
||||
|
||||
startForeground(notifyID, mBuilder.build());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* let a love one know where you are at about every 10 min
|
||||
*/
|
||||
public void phoneCrash(double mag) {
|
||||
smsHome(
|
||||
getString(R.string.crash_warning) + "\n" + getLocationLink()
|
||||
+ "\n " + getString(R.string.crash_magnitude) + ": " + String.valueOf(mag)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* confirm the crash if we are not moving
|
||||
*/
|
||||
public void phoneCrashConfirm() {
|
||||
smsHome(getString(R.string.crash_confirm) + "!\n" + getLocationLink());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* let them know we are starting
|
||||
*/
|
||||
public void phoneStart() {
|
||||
smsWithLocation(getString(R.string.ride_start_sms));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* let them know we are stopping
|
||||
*/
|
||||
public void phoneStop() {
|
||||
smsWithLocation(getString(R.string.ride_stop_sms));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* send an sms with location
|
||||
*/
|
||||
public void smsWithLocation(String body) {
|
||||
smsHome(body + "\n " + getLocationLink());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* let a love one know where you are at about every 10 min
|
||||
*/
|
||||
public void phoneHome() {
|
||||
smsWithLocation(getString(R.string.riding_ok_sms));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* send a sms message
|
||||
*/
|
||||
public void smsHome(String body) {
|
||||
SmsManager smsManager = SmsManager.getDefault();
|
||||
if(emergencyNumbuer != null && PhoneNumberUtils.isWellFormedSmsAddress(emergencyNumbuer)) {
|
||||
smsManager.sendTextMessage(emergencyNumbuer, null, body, null, null);
|
||||
}
|
||||
}
|
||||
|
||||
public String getLocationLink() {
|
||||
if(currentValues[LAT] != 0.0 || currentValues[LON] != 0.0) {
|
||||
return "https://www.google.com/maps/place/" + currentValues[LAT] + "," + currentValues[LON];
|
||||
}
|
||||
return getString(R.string.crash_unknow_location);
|
||||
}
|
||||
|
||||
|
||||
//stop the ride and clean up resources
|
||||
protected void stopRide() {
|
||||
if(!rideStarted) return;
|
||||
|
||||
SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
if(settings.getBoolean(getString(R.string.PREF_PHONE_HOME), false)) {
|
||||
phoneStop();
|
||||
}
|
||||
|
||||
for(Base<?> sensor: sensors) {
|
||||
if(sensor != null) {
|
||||
sensor.onDestroy();
|
||||
}
|
||||
}
|
||||
|
||||
//stop the phoneHome timer if we need to.
|
||||
if(timer != null) {
|
||||
timer.cancel();
|
||||
timer = null;
|
||||
}
|
||||
|
||||
if(timerUI != null) {
|
||||
timerUI.cancel();
|
||||
timerUI = null;
|
||||
}
|
||||
|
||||
fileFormat.writeFooter();
|
||||
|
||||
rideStarted = false;
|
||||
NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
mNotificationManager.cancel(notifyID);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,274 +0,0 @@
|
||||
package com.ridelogger;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
import com.dsi.ant.plugins.antplus.pcc.defines.DeviceType;
|
||||
import com.dsi.ant.plugins.antplus.pcc.defines.RequestAccessResult;
|
||||
import com.dsi.ant.plugins.antplus.pccbase.MultiDeviceSearch;
|
||||
import com.dsi.ant.plugins.antplus.pccbase.MultiDeviceSearch.MultiDeviceSearchResult;
|
||||
import com.dsi.ant.plugins.utility.log.LogAnt;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.app.ActivityManager.RunningServiceInfo;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.SharedPreferences.Editor;
|
||||
import android.content.res.Configuration;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.preference.MultiSelectListPreference;
|
||||
import android.preference.Preference;
|
||||
import android.preference.PreferenceActivity;
|
||||
import android.preference.PreferenceFragment;
|
||||
import android.preference.PreferenceManager;
|
||||
|
||||
public class SettingsActivity extends PreferenceActivity {
|
||||
|
||||
static ArrayList<MultiDeviceSearchResult> foundDevices = new ArrayList<MultiDeviceSearchResult>();
|
||||
|
||||
/**
|
||||
* This fragment contains a second-level set of preference that you
|
||||
* can get to by tapping an item in the first preferences fragment.
|
||||
*/
|
||||
public static class GeneralFragment extends PreferenceFragment {
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
// Load the preferences from an XML resource
|
||||
addPreferencesFromResource(R.xml.general_settings);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
// TODO Auto-generated method stub
|
||||
super.onResume();
|
||||
|
||||
if(((SettingsActivity) getActivity()).getServiceRunning(RideService.class) != null) {
|
||||
Preference pref = findPreference(getString(R.string.PREF_RIDER_NAME));
|
||||
pref.setEnabled(false);
|
||||
|
||||
pref = findPreference(getString(R.string.PREF_EMERGENCY_NUMBER));
|
||||
pref.setEnabled(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This fragment contains a second-level set of preference that you
|
||||
* can get to by tapping an item in the first preferences fragment.
|
||||
*/
|
||||
public static class SensorsFragment extends PreferenceFragment {
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
addPreferencesFromResource(R.xml.sensors_settings);
|
||||
MultiSelectListPreference mMultiSelectListPreference = (MultiSelectListPreference) findPreference(getString(R.string.PREF_TRACKING_SENSORS));
|
||||
mMultiSelectListPreference.setEntries( RideService.KEYS );
|
||||
|
||||
CharSequence[] keys = new CharSequence[RideService.KEYS.length];
|
||||
|
||||
for (int i = 0; i < RideService.KEYS.length; i++) {
|
||||
keys[i] = String.valueOf(i);
|
||||
}
|
||||
mMultiSelectListPreference.setEntryValues(keys);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isValidFragment(String fragment) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This fragment contains a second-level set of preference that you
|
||||
* can get to by tapping an item in the first preferences fragment.
|
||||
*/
|
||||
public static class AntFragment extends PreferenceFragment {
|
||||
private MultiDeviceSearch mSearch;
|
||||
private MultiSelectListPreference mMultiSelectListPreference;
|
||||
|
||||
@Override
|
||||
public void onConfigurationChanged(Configuration newConfig) {
|
||||
// TODO Auto-generated method stub
|
||||
super.onConfigurationChanged(newConfig);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
addPreferencesFromResource(R.xml.ant_settings);
|
||||
mMultiSelectListPreference = (MultiSelectListPreference) findPreference(getString(R.string.PREF_PAIRED_ANTS));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
// TODO Auto-generated method stub
|
||||
super.onResume();
|
||||
initAntSearch();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* search for ant+ if we are not recording
|
||||
*/
|
||||
public void initAntSearch() {
|
||||
mMultiSelectListPreference.setEnabled(false);
|
||||
if(((SettingsActivity) getActivity()).getServiceRunning(RideService.class) == null) {
|
||||
mMultiSelectListPreference.setSummary(R.string.searching_for_ants);
|
||||
|
||||
setupAnt();
|
||||
|
||||
Timer timer = new Timer();
|
||||
final Handler handler = new Handler();
|
||||
|
||||
timer.schedule(
|
||||
new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
if(mMultiSelectListPreference.getEntryValues().length > 0) {
|
||||
handler.post(new Runnable() {
|
||||
public void run() {
|
||||
mMultiSelectListPreference.setEnabled(true);
|
||||
mMultiSelectListPreference.setSummary(R.string.found_ants);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
handler.post(new Runnable() {
|
||||
public void run() {
|
||||
mMultiSelectListPreference.setEnabled(true);
|
||||
mMultiSelectListPreference.setSummary(R.string.no_found_ants);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
5000
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* try to pair some ant+ devices
|
||||
*/
|
||||
protected void setupAnt() {
|
||||
MultiDeviceSearch.SearchCallbacks mCallback;
|
||||
MultiDeviceSearch.RssiCallback mRssiCallback;
|
||||
|
||||
updateList(foundDevices);
|
||||
|
||||
LogAnt.setDebugLevel(LogAnt.DebugLevel.NONE, this.getActivity());
|
||||
|
||||
mCallback = new MultiDeviceSearch.SearchCallbacks(){
|
||||
public void onDeviceFound(final MultiDeviceSearchResult deviceFound)
|
||||
{
|
||||
if(!foundDevices.contains(deviceFound)) {
|
||||
foundDevices.add(deviceFound);
|
||||
updateList(foundDevices);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSearchStopped(RequestAccessResult arg0) {}
|
||||
};
|
||||
|
||||
mRssiCallback = new MultiDeviceSearch.RssiCallback() {
|
||||
@Override
|
||||
public void onRssiUpdate(final int resultId, final int rssi){}
|
||||
};
|
||||
|
||||
// start the multi-device search
|
||||
mSearch = new MultiDeviceSearch(this.getActivity(), EnumSet.allOf(DeviceType.class), mCallback, mRssiCallback);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* dialog of soon to be paired ant devices
|
||||
* @param foundDevices
|
||||
*/
|
||||
protected void updateList(final ArrayList<MultiDeviceSearchResult> foundDevices) {
|
||||
ArrayList<CharSequence> foundDevicesString = new ArrayList<CharSequence>();
|
||||
ArrayList<CharSequence> foundDevicesValues = new ArrayList<CharSequence>();
|
||||
|
||||
for(MultiDeviceSearchResult device : foundDevices) {
|
||||
foundDevicesString.add(device.getAntDeviceType() + ": " + String.valueOf(device.getAntDeviceNumber()));
|
||||
}
|
||||
|
||||
for(MultiDeviceSearchResult device : foundDevices) {
|
||||
foundDevicesValues.add(String.valueOf(device.getAntDeviceNumber()));
|
||||
}
|
||||
|
||||
if(mMultiSelectListPreference != null) {
|
||||
mMultiSelectListPreference.setEntries(
|
||||
foundDevicesString.toArray(new CharSequence[foundDevicesString.size()])
|
||||
);
|
||||
mMultiSelectListPreference.setEntryValues(
|
||||
foundDevicesValues.toArray(new CharSequence[foundDevicesValues.size()])
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
if(mSearch != null) mSearch.close();
|
||||
super.onDestroy();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Populate the activity with the top-level headers.
|
||||
*/
|
||||
@Override
|
||||
public void onBuildHeaders(List<Header> target) {
|
||||
loadHeadersFromResource(R.layout.settings, target);
|
||||
|
||||
SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
settings.registerOnSharedPreferenceChangeListener(
|
||||
new SharedPreferences.OnSharedPreferenceChangeListener() {
|
||||
@Override
|
||||
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String pkey) {
|
||||
if (pkey == getString(R.string.PREF_PAIRED_ANTS)) {
|
||||
Set<String> sensors = sharedPreferences.getStringSet(pkey, null);
|
||||
if(sensors != null && sensors.size() > 0) {
|
||||
Editor editor = sharedPreferences.edit();
|
||||
for(MultiDeviceSearchResult result : foundDevices) {
|
||||
sensors.contains(String.valueOf(result.getAntDeviceNumber()));
|
||||
editor.putInt(String.valueOf(result.getAntDeviceNumber()), result.getAntDeviceType().getIntValue());
|
||||
}
|
||||
editor.commit();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* is a service running or not
|
||||
* @param serviceClass
|
||||
* @return
|
||||
*/
|
||||
public RunningServiceInfo getServiceRunning(Class<?> serviceClass) {
|
||||
ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
|
||||
for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
|
||||
if (serviceClass.getName().equals(service.service.getClassName())) {
|
||||
return service;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,215 +0,0 @@
|
||||
package com.ridelogger;
|
||||
import android.app.ActivityManager;
|
||||
import android.app.ActivityManager.RunningServiceInfo;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.ServiceConnection;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.Message;
|
||||
import android.os.Messenger;
|
||||
import android.os.RemoteException;
|
||||
import android.support.v4.app.FragmentActivity;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.widget.GridView;
|
||||
import android.widget.Toast;
|
||||
|
||||
public class StartActivity extends FragmentActivity
|
||||
{
|
||||
private MenuItem startMenu;
|
||||
private MenuItem stopMenu;
|
||||
|
||||
private ServiceConnection mConnection;
|
||||
static CurrentValuesAdapter currentValuesAdapter;
|
||||
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
// Inflate the menu items for use in the action bar
|
||||
MenuInflater inflater = getMenuInflater();
|
||||
inflater.inflate(R.menu.start_activity, menu);
|
||||
return super.onCreateOptionsMenu(menu);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
// Handle presses on the action bar items
|
||||
if(item.getItemId() == R.id.Settings) {
|
||||
setupSettings();
|
||||
} else if(item.getItemId() == R.id.Start) {
|
||||
startRide();
|
||||
} else {
|
||||
stopRide();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* start up our class
|
||||
*/
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState)
|
||||
{
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_dashboard);
|
||||
|
||||
GridView layout = (GridView) findViewById(R.id.LayoutData);
|
||||
currentValuesAdapter = new CurrentValuesAdapter(this, layout);
|
||||
layout.setAdapter(currentValuesAdapter);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
bindToService();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
unBindToService();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStop() {
|
||||
super.onStop();
|
||||
unBindToService();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* setup the settings for the user
|
||||
*/
|
||||
private void setupSettings() {
|
||||
Intent intent = new Intent(this, SettingsActivity.class);
|
||||
startActivity(intent);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* stop ride and clean up references
|
||||
*/
|
||||
private void stopRide() {
|
||||
Toast toast = Toast.makeText(getApplicationContext(), getString(R.string.stopping_ride), Toast.LENGTH_LONG);
|
||||
toast.show();
|
||||
|
||||
Intent rsi = new Intent(this, RideService.class);
|
||||
this.stopService(rsi);
|
||||
finish();
|
||||
}
|
||||
|
||||
static final Handler mHandler = new Handler(){
|
||||
@Override
|
||||
public void handleMessage(Message msg_internal) {
|
||||
updateValues(msg_internal.getData());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* tell the service to start sending us messages with current values
|
||||
*/
|
||||
private void bindToService() {
|
||||
RunningServiceInfo service = getServiceRunning(RideService.class);
|
||||
|
||||
if(service != null) {
|
||||
mConnection = new ServiceConnection() {
|
||||
public void onServiceConnected(ComponentName className, IBinder service) {
|
||||
Messenger mService = new Messenger(service);
|
||||
try {
|
||||
Message msg = Message.obtain();
|
||||
msg.replyTo = new Messenger(mHandler);
|
||||
|
||||
mService.send(msg);
|
||||
} catch (RemoteException e) {
|
||||
// In this case the service has crashed before we could even do anything with it
|
||||
}
|
||||
}
|
||||
|
||||
public void onServiceDisconnected(ComponentName className) {}
|
||||
};
|
||||
|
||||
bindService(new Intent(StartActivity.this, RideService.class), mConnection, Context.BIND_AUTO_CREATE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* tell the service to stop sending us messages with current values
|
||||
*/
|
||||
private void unBindToService() {
|
||||
if (mConnection != null) {
|
||||
// Detach our existing connection.
|
||||
unbindService(mConnection);
|
||||
mConnection = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* update the text fields with current values
|
||||
* @param bundle
|
||||
*/
|
||||
private static void updateValues(Bundle bundle) {
|
||||
currentValuesAdapter.update((float[]) bundle.getSerializable("currentValues"));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean onPrepareOptionsMenu(Menu menu) {
|
||||
super.onPrepareOptionsMenu(menu);
|
||||
|
||||
RunningServiceInfo service = getServiceRunning(RideService.class);
|
||||
startMenu = menu.findItem(R.id.Start);
|
||||
stopMenu = menu.findItem(R.id.Stop);
|
||||
if(service == null) {
|
||||
startMenu.setVisible(true);
|
||||
stopMenu.setVisible(false);
|
||||
} else {
|
||||
startMenu.setVisible(false);
|
||||
stopMenu.setVisible(true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* start the ride and notify the user of success
|
||||
*/
|
||||
private void startRide() {
|
||||
Intent rsi = new Intent(this, RideService.class);
|
||||
this.startService(rsi);
|
||||
|
||||
startMenu.setVisible(false);
|
||||
stopMenu.setVisible(true);
|
||||
|
||||
bindToService();
|
||||
|
||||
Toast toast = Toast.makeText(getApplicationContext(), getString(R.string.starting_ride), Toast.LENGTH_LONG);
|
||||
toast.show();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* is a service running or not
|
||||
* @param serviceClass
|
||||
* @return
|
||||
*/
|
||||
private RunningServiceInfo getServiceRunning(Class<?> serviceClass) {
|
||||
ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
|
||||
for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
|
||||
if (serviceClass.getName().equals(service.service.getClassName())) {
|
||||
return service;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
package com.ridelogger.formats;
|
||||
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
import android.os.Environment;
|
||||
|
||||
import com.ridelogger.GzipWriter;
|
||||
import com.ridelogger.RideService;
|
||||
|
||||
|
||||
public class BaseFormat<T> {
|
||||
protected GzipWriter buf;
|
||||
protected RideService context;
|
||||
protected String subExt = "";
|
||||
|
||||
public BaseFormat(RideService rideService) {
|
||||
context = rideService;
|
||||
}
|
||||
|
||||
|
||||
public void createFile() {
|
||||
File dir = new File(
|
||||
Environment.getExternalStorageDirectory(),
|
||||
"Rides"
|
||||
);
|
||||
|
||||
dir.mkdirs();
|
||||
|
||||
Date startDate = new Date(context.startTime);
|
||||
SimpleDateFormat filef = new SimpleDateFormat("yyyy_MM_dd_HH_mm_ss");
|
||||
String fileName = filef.format(startDate) + subExt + ".gz";
|
||||
|
||||
try {
|
||||
buf = new GzipWriter(new BufferedOutputStream(new FileOutputStream(new File(dir, fileName))));
|
||||
} catch (Exception e) {}
|
||||
}
|
||||
|
||||
|
||||
public void writeHeader(){
|
||||
try {
|
||||
synchronized (buf) {
|
||||
for(CharSequence key : RideService.KEYS) {
|
||||
buf.write(key);
|
||||
buf.write(",");
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {}
|
||||
}
|
||||
|
||||
|
||||
public void writeValues() {
|
||||
try {
|
||||
synchronized (buf) {
|
||||
for(float value : context.currentValues) {
|
||||
buf.write(value);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {}
|
||||
}
|
||||
|
||||
|
||||
public void writeFooter() {
|
||||
try {
|
||||
buf.close();
|
||||
} catch (Exception e) {}
|
||||
}
|
||||
}
|
||||
@@ -1,93 +0,0 @@
|
||||
package com.ridelogger.formats;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import com.ridelogger.R;
|
||||
import com.ridelogger.RideService;
|
||||
|
||||
import android.content.SharedPreferences;
|
||||
import android.preference.PreferenceManager;
|
||||
|
||||
public class JsonFormat extends BaseFormat<Object> {
|
||||
public JsonFormat(RideService rideService) {
|
||||
super(rideService);
|
||||
subExt = ".json";
|
||||
}
|
||||
|
||||
public void writeHeader() {
|
||||
SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
Date startDate = new Date(context.startTime);
|
||||
|
||||
SimpleDateFormat startTimef = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
|
||||
SimpleDateFormat filef = new SimpleDateFormat("yyyy_MM_dd_HH_mm_ss");
|
||||
SimpleDateFormat month = new SimpleDateFormat("MMMMM");
|
||||
SimpleDateFormat year = new SimpleDateFormat("yyyy");
|
||||
SimpleDateFormat day = new SimpleDateFormat("EEEEE");
|
||||
|
||||
startTimef.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||
filef.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||
month.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||
year.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||
day.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||
|
||||
try {
|
||||
buf.write("{" +
|
||||
"\"RIDE\":{" +
|
||||
"\"STARTTIME\":\"" + startTimef.format(startDate) + " UTC\"," +
|
||||
"\"RECINTSECS\":1," +
|
||||
"\"DEVICETYPE\":\"Android\"," +
|
||||
"\"IDENTIFIER\":\"\"," +
|
||||
"\"TAGS\":{" +
|
||||
"\"Athlete\":\"" + settings.getString(context.getString(R.string.PREF_RIDER_NAME), "") + "\"," +
|
||||
"\"Calendar Text\":\"Auto Recored Android Ride\"," +
|
||||
"\"Change History\":\"\"," +
|
||||
"\"Data\":\"\"," +
|
||||
"\"Device\":\"\"," +
|
||||
"\"Device Info\":\"\"," +
|
||||
"\"File Format\":\"\"," +
|
||||
"\"Filename\":\"\"," +
|
||||
"\"Month\":\"" + month.format(startDate) +"\"," +
|
||||
"\"Notes\":\"\"," +
|
||||
"\"Objective\":\"\"," +
|
||||
"\"Sport\":\"Bike\"," +
|
||||
"\"Weekday\":\"" + day.format(startDate) + "\"," +
|
||||
"\"Workout Code\":\"\"," +
|
||||
"\"Year\":\"" + year.format(startDate) + "\"" +
|
||||
"}," +
|
||||
"\"SAMPLES\":[{\"SECS\":0}");
|
||||
} catch (Exception e) {}
|
||||
}
|
||||
|
||||
|
||||
public void writeValues() {
|
||||
try {
|
||||
synchronized (buf) {
|
||||
buf.write(",{");
|
||||
buf.write("\"");
|
||||
buf.write(RideService.KEYS[0]);
|
||||
buf.write("\":");
|
||||
buf.write(String.format("%f", context.currentValues[0]));
|
||||
|
||||
for (int i = 1; i < context.currentValues.length; i++) {
|
||||
buf.write(",\"");
|
||||
buf.write(RideService.KEYS[i]);
|
||||
buf.write("\":");
|
||||
buf.write(String.format("%f", context.currentValues[i]));
|
||||
}
|
||||
|
||||
buf.write("}");
|
||||
}
|
||||
} catch (Exception e) {}
|
||||
}
|
||||
|
||||
|
||||
public void writeFooter() {
|
||||
try {
|
||||
buf.write("]}}");
|
||||
|
||||
} catch (Exception e) {}
|
||||
super.writeFooter();
|
||||
}
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
package com.ridelogger.listners;
|
||||
|
||||
import com.dsi.ant.plugins.antplus.pcc.defines.DeviceState;
|
||||
import com.dsi.ant.plugins.antplus.pccbase.PccReleaseHandle;
|
||||
import com.dsi.ant.plugins.antplus.pccbase.AntPluginPcc.IDeviceStateChangeReceiver;
|
||||
import com.dsi.ant.plugins.antplus.pccbase.AntPluginPcc.IPluginAccessResultReceiver;
|
||||
import com.ridelogger.RideService;
|
||||
|
||||
|
||||
/**
|
||||
* Ant
|
||||
* @author Chet Henry
|
||||
* Listen to and log Ant+ events base class
|
||||
*/
|
||||
public abstract class Ant extends Base<Object>
|
||||
{
|
||||
protected PccReleaseHandle<?> releaseHandle; //Handle class
|
||||
public IPluginAccessResultReceiver<?> mResultReceiver; //Receiver class
|
||||
protected int deviceNumber = 0;
|
||||
|
||||
|
||||
//setup listeners and logging
|
||||
public Ant(int pDeviceNumber, RideService mContext)
|
||||
{
|
||||
super(mContext);
|
||||
deviceNumber = pDeviceNumber;
|
||||
}
|
||||
|
||||
|
||||
public IDeviceStateChangeReceiver mDeviceStateChangeReceiver = new IDeviceStateChangeReceiver()
|
||||
{
|
||||
@Override
|
||||
public void onDeviceStateChange(final DeviceState newDeviceState){
|
||||
//if we lose a device zero out its values
|
||||
if(newDeviceState.equals(DeviceState.DEAD)) {
|
||||
zeroReadings();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
abstract protected void requestAccess();
|
||||
|
||||
|
||||
@Override
|
||||
public void onDestroy()
|
||||
{
|
||||
if(releaseHandle != null) {
|
||||
releaseHandle.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
package com.ridelogger.listners;
|
||||
|
||||
import com.ridelogger.RideService;
|
||||
|
||||
/**
|
||||
* Base
|
||||
* @author Chet Henry
|
||||
* Base sensor class that has methods to time stamp are write to buffer
|
||||
*/
|
||||
public class Base<T>
|
||||
{
|
||||
public RideService context;
|
||||
|
||||
public Base(RideService mContext) {
|
||||
context = mContext;
|
||||
}
|
||||
|
||||
|
||||
public void alterCurrentData(int key, float value)
|
||||
{
|
||||
synchronized (context.currentValues) {
|
||||
context.currentValues[RideService.SECS] = getTs();
|
||||
context.currentValues[key] = value;
|
||||
context.fileFormat.writeValues();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void alterCurrentData(int[] keys, float[] values)
|
||||
{
|
||||
synchronized (context.currentValues) {
|
||||
context.currentValues[RideService.SECS] = getTs();
|
||||
|
||||
int i = 0;
|
||||
for (int key : keys) {
|
||||
context.currentValues[key] = values[i];
|
||||
i++;
|
||||
}
|
||||
|
||||
context.fileFormat.writeValues();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//get current time stamp
|
||||
public float getTs() {
|
||||
return (float) ((System.currentTimeMillis() - context.startTime) / 1000.0);
|
||||
}
|
||||
|
||||
|
||||
//Clean up my listeners here
|
||||
public void onDestroy() {}
|
||||
|
||||
//zero any of my values
|
||||
public void zeroReadings() {}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
package com.ridelogger.listners;
|
||||
|
||||
import com.ridelogger.RideService;
|
||||
|
||||
import android.content.Context;
|
||||
import android.location.Location;
|
||||
import android.location.LocationListener;
|
||||
import android.location.LocationManager;
|
||||
|
||||
import android.os.Bundle;
|
||||
|
||||
/**
|
||||
* Gps
|
||||
* @author henry
|
||||
* Listen and log gps events
|
||||
*/
|
||||
public class Gps extends Base<Gps>
|
||||
{
|
||||
public Gps(RideService mContext)
|
||||
{
|
||||
super(mContext);
|
||||
|
||||
LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
|
||||
|
||||
//listen to gps events and log them
|
||||
LocationListener locationListener = new LocationListener() {
|
||||
public void onLocationChanged(Location location) {
|
||||
int[] keys = {
|
||||
RideService.ALTITUDE,
|
||||
RideService.KPH,
|
||||
RideService.bearing,
|
||||
RideService.gpsa,
|
||||
RideService.LAT,
|
||||
RideService.LON
|
||||
};
|
||||
|
||||
float[] values = {
|
||||
(float) location.getAltitude(),
|
||||
location.getSpeed(),
|
||||
location.getBearing(),
|
||||
location.getAccuracy(),
|
||||
(float) location.getLatitude(),
|
||||
(float) location.getLongitude()
|
||||
};
|
||||
|
||||
alterCurrentData(keys, values);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStatusChanged(String provider, int status, Bundle extras) {}
|
||||
|
||||
@Override
|
||||
public void onProviderEnabled(String provider) {}
|
||||
|
||||
@Override
|
||||
public void onProviderDisabled(String provider) {}
|
||||
};
|
||||
|
||||
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListener);
|
||||
}
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
package com.ridelogger.listners;
|
||||
|
||||
import com.dsi.ant.plugins.antplus.pcc.AntPlusHeartRatePcc;
|
||||
import com.dsi.ant.plugins.antplus.pcc.AntPlusHeartRatePcc.DataState;
|
||||
import com.dsi.ant.plugins.antplus.pcc.AntPlusHeartRatePcc.IHeartRateDataReceiver;
|
||||
import com.dsi.ant.plugins.antplus.pcc.defines.DeviceState;
|
||||
import com.dsi.ant.plugins.antplus.pcc.defines.EventFlag;
|
||||
import com.dsi.ant.plugins.antplus.pcc.defines.RequestAccessResult;
|
||||
import com.dsi.ant.plugins.antplus.pccbase.AntPluginPcc.IPluginAccessResultReceiver;
|
||||
import com.ridelogger.RideService;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.EnumSet;
|
||||
|
||||
/**
|
||||
* HeartRate
|
||||
* @author Chet Henry
|
||||
* Listen to and log Ant+ HearRate events
|
||||
*/
|
||||
public class HeartRate extends Ant
|
||||
{
|
||||
public IPluginAccessResultReceiver<AntPlusHeartRatePcc> mResultReceiver;
|
||||
|
||||
public HeartRate(int pDeviceNumber, RideService mContext) {
|
||||
super(pDeviceNumber, mContext);
|
||||
|
||||
mResultReceiver = new IPluginAccessResultReceiver<AntPlusHeartRatePcc>() {
|
||||
//Handle the result, connecting to events on success or reporting failure to user.
|
||||
@Override
|
||||
public void onResultReceived(AntPlusHeartRatePcc result, RequestAccessResult resultCode, DeviceState initialDeviceState)
|
||||
{
|
||||
if(resultCode == com.dsi.ant.plugins.antplus.pcc.defines.RequestAccessResult.SUCCESS) {
|
||||
deviceNumber = result.getAntDeviceNumber();
|
||||
result.subscribeHeartRateDataEvent(
|
||||
new IHeartRateDataReceiver() {
|
||||
@Override
|
||||
public void onNewHeartRateData(final long estTimestamp, EnumSet<EventFlag> eventFlags, final int computedHeartRate, final long heartBeatCount, final BigDecimal heartBeatEventTime, final DataState dataState) {
|
||||
alterCurrentData(RideService.HR, (float) computedHeartRate);
|
||||
}
|
||||
}
|
||||
);
|
||||
} else if(resultCode == com.dsi.ant.plugins.antplus.pcc.defines.RequestAccessResult.SEARCH_TIMEOUT) {
|
||||
if(deviceNumber != 0) {
|
||||
requestAccess();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
requestAccess();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
protected void requestAccess() {
|
||||
releaseHandle = AntPlusHeartRatePcc.requestAccess(context, deviceNumber, 0, mResultReceiver, mDeviceStateChangeReceiver);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public void zeroReadings()
|
||||
{
|
||||
alterCurrentData(RideService.HR, (float) 0.0);
|
||||
}
|
||||
}
|
||||
@@ -1,223 +0,0 @@
|
||||
package com.ridelogger.listners;
|
||||
import android.preference.PreferenceManager;
|
||||
|
||||
import com.dsi.ant.plugins.antplus.pcc.AntPlusBikePowerPcc;
|
||||
import com.dsi.ant.plugins.antplus.pcc.AntPlusBikePowerPcc.CalculatedWheelDistanceReceiver;
|
||||
import com.dsi.ant.plugins.antplus.pcc.AntPlusBikePowerPcc.CalculatedWheelSpeedReceiver;
|
||||
import com.dsi.ant.plugins.antplus.pcc.AntPlusBikePowerPcc.DataSource;
|
||||
import com.dsi.ant.plugins.antplus.pcc.AntPlusBikePowerPcc.ICalculatedCrankCadenceReceiver;
|
||||
import com.dsi.ant.plugins.antplus.pcc.AntPlusBikePowerPcc.ICalculatedPowerReceiver;
|
||||
import com.dsi.ant.plugins.antplus.pcc.AntPlusBikePowerPcc.ICalculatedTorqueReceiver;
|
||||
import com.dsi.ant.plugins.antplus.pcc.AntPlusBikePowerPcc.IInstantaneousCadenceReceiver;
|
||||
import com.dsi.ant.plugins.antplus.pcc.AntPlusBikePowerPcc.IRawPowerOnlyDataReceiver;
|
||||
import com.dsi.ant.plugins.antplus.pcc.defines.DeviceState;
|
||||
import com.dsi.ant.plugins.antplus.pcc.defines.EventFlag;
|
||||
import com.dsi.ant.plugins.antplus.pcc.defines.RequestAccessResult;
|
||||
import com.dsi.ant.plugins.antplus.pccbase.AntPluginPcc.IPluginAccessResultReceiver;
|
||||
import com.ridelogger.R;
|
||||
import com.ridelogger.RideService;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.EnumSet;
|
||||
|
||||
/**
|
||||
* Power
|
||||
* @author Chet Henry
|
||||
* Listen to and log Ant+ Power events
|
||||
*/
|
||||
public class Power extends Ant
|
||||
{
|
||||
public BigDecimal wheelCircumferenceInMeters; //size of wheel to calculate speed
|
||||
public IPluginAccessResultReceiver<AntPlusBikePowerPcc> mResultReceiver;
|
||||
|
||||
//setup listeners and logging
|
||||
public Power(int pDeviceNumber, RideService mContext) {
|
||||
super(pDeviceNumber, mContext);
|
||||
|
||||
wheelCircumferenceInMeters = new BigDecimal(
|
||||
PreferenceManager.getDefaultSharedPreferences(context).getString(context.getString(R.string.PREF_WHEEL_SIZE), "2.096")
|
||||
);
|
||||
|
||||
//Handle messages
|
||||
mResultReceiver = new IPluginAccessResultReceiver<AntPlusBikePowerPcc>() {
|
||||
//Handle the result, connecting to events on success or reporting failure to user.
|
||||
@Override
|
||||
public void onResultReceived(AntPlusBikePowerPcc result, RequestAccessResult resultCode, DeviceState initialDeviceState) {
|
||||
if(resultCode == com.dsi.ant.plugins.antplus.pcc.defines.RequestAccessResult.SUCCESS) {
|
||||
deviceNumber = result.getAntDeviceNumber();
|
||||
|
||||
result.subscribeCalculatedPowerEvent(new ICalculatedPowerReceiver() {
|
||||
@Override
|
||||
public void onNewCalculatedPower(final long estTimestamp, final EnumSet<EventFlag> eventFlags, final DataSource dataSource, final BigDecimal calculatedPower) {
|
||||
alterCurrentData(RideService.WATTS, calculatedPower.floatValue());
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
result.subscribeCalculatedTorqueEvent(
|
||||
new ICalculatedTorqueReceiver() {
|
||||
@Override
|
||||
public void onNewCalculatedTorque(final long estTimestamp, final EnumSet<EventFlag> eventFlags, final DataSource dataSource, final BigDecimal calculatedTorque) {
|
||||
alterCurrentData(RideService.NM, calculatedTorque.floatValue());
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
result.subscribeCalculatedCrankCadenceEvent(
|
||||
new ICalculatedCrankCadenceReceiver() {
|
||||
@Override
|
||||
public void onNewCalculatedCrankCadence(final long estTimestamp, final EnumSet<EventFlag> eventFlags, final DataSource dataSource, final BigDecimal calculatedCrankCadence) {
|
||||
alterCurrentData(RideService.CAD, calculatedCrankCadence.floatValue());
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
result.subscribeCalculatedWheelSpeedEvent(
|
||||
new CalculatedWheelSpeedReceiver(wheelCircumferenceInMeters) {
|
||||
@Override
|
||||
public void onNewCalculatedWheelSpeed(final long estTimestamp, final EnumSet<EventFlag> eventFlags, final DataSource dataSource, final BigDecimal calculatedWheelSpeed)
|
||||
{
|
||||
alterCurrentData(RideService.KPH, calculatedWheelSpeed.floatValue());
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
result.subscribeCalculatedWheelDistanceEvent(
|
||||
new CalculatedWheelDistanceReceiver(wheelCircumferenceInMeters) {
|
||||
@Override
|
||||
public void onNewCalculatedWheelDistance(final long estTimestamp, final EnumSet<EventFlag> eventFlags, final DataSource dataSource, final BigDecimal calculatedWheelDistance)
|
||||
{
|
||||
alterCurrentData(RideService.KM, calculatedWheelDistance.floatValue());
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
result.subscribeInstantaneousCadenceEvent(
|
||||
new IInstantaneousCadenceReceiver() {
|
||||
@Override
|
||||
public void onNewInstantaneousCadence(final long estTimestamp, final EnumSet<EventFlag> eventFlags, final DataSource dataSource, final int instantaneousCadence)
|
||||
{
|
||||
alterCurrentData(RideService.CAD, (float) instantaneousCadence);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
result.subscribeRawPowerOnlyDataEvent(
|
||||
new IRawPowerOnlyDataReceiver() {
|
||||
@Override
|
||||
public void onNewRawPowerOnlyData(final long estTimestamp, final EnumSet<EventFlag> eventFlags, final long powerOnlyUpdateEventCount, final int instantaneousPower, final long accumulatedPower)
|
||||
{
|
||||
alterCurrentData(RideService.WATTS, (float) instantaneousPower);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
/*result.subscribePedalPowerBalanceEvent(
|
||||
new IPedalPowerBalanceReceiver() {
|
||||
@Override
|
||||
public void onNewPedalPowerBalance(final long estTimestamp, final EnumSet<EventFlag> eventFlags, final boolean rightPedalIndicator, final int pedalPowerPercentage)
|
||||
{
|
||||
alterCurrentData(RideService.LTE, pedalPowerPercentage);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
result.subscribeRawWheelTorqueDataEvent(
|
||||
new IRawWheelTorqueDataReceiver() {
|
||||
@Override
|
||||
public void onNewRawWheelTorqueData(final long estTimestamp, final EnumSet<EventFlag> eventFlags, final long wheelTorqueUpdateEventCount, final long accumulatedWheelTicks, final BigDecimal accumulatedWheelPeriod, final BigDecimal accumulatedWheelTorque)
|
||||
{
|
||||
alterCurrentData(RideService.NM, accumulatedWheelTorque);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
result.subscribeRawCrankTorqueDataEvent(
|
||||
new IRawCrankTorqueDataReceiver() {
|
||||
@Override
|
||||
public void onNewRawCrankTorqueData(final long estTimestamp, final EnumSet<EventFlag> eventFlags, final long crankTorqueUpdateEventCount, final long accumulatedCrankTicks, final BigDecimal accumulatedCrankPeriod, final BigDecimal accumulatedCrankTorque)
|
||||
{
|
||||
alterCurrentData(RideService.NM, accumulatedCrankTorque);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
result.subscribeTorqueEffectivenessEvent(
|
||||
new ITorqueEffectivenessReceiver() {
|
||||
@Override
|
||||
public void onNewTorqueEffectiveness(final long estTimestamp, final EnumSet<EventFlag> eventFlags, final long powerOnlyUpdateEventCount, final BigDecimal leftTorqueEffectiveness, final BigDecimal rightTorqueEffectiveness)
|
||||
{
|
||||
int[] keys = {
|
||||
RideService.LTE,
|
||||
RideService.RTE
|
||||
};
|
||||
|
||||
float[] values = {
|
||||
leftTorqueEffectiveness,
|
||||
rightTorqueEffectiveness
|
||||
}
|
||||
|
||||
alterCurrentData(keys, values);
|
||||
}
|
||||
|
||||
}
|
||||
);
|
||||
|
||||
result.subscribePedalSmoothnessEvent(new IPedalSmoothnessReceiver() {
|
||||
@Override
|
||||
public void onNewPedalSmoothness(final long estTimestamp, final EnumSet<EventFlag> eventFlags, final long powerOnlyUpdateEventCount, final boolean separatePedalSmoothnessSupport, final BigDecimal leftOrCombinedPedalSmoothness, final BigDecimal rightPedalSmoothness)
|
||||
{
|
||||
int[] keys = {
|
||||
RideService.SNPLC,
|
||||
RideService.SNPR
|
||||
};
|
||||
|
||||
float[] values = {
|
||||
leftOrCombinedPedalSmoothness,
|
||||
rightPedalSmoothness
|
||||
}
|
||||
|
||||
alterCurrentData(map);
|
||||
}
|
||||
}
|
||||
);*/
|
||||
} else if(resultCode == com.dsi.ant.plugins.antplus.pcc.defines.RequestAccessResult.SEARCH_TIMEOUT) {
|
||||
if(deviceNumber != 0) {
|
||||
requestAccess();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
requestAccess();
|
||||
}
|
||||
|
||||
protected void requestAccess() {
|
||||
releaseHandle = AntPlusBikePowerPcc.requestAccess(context, deviceNumber, 0, mResultReceiver, mDeviceStateChangeReceiver);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void zeroReadings()
|
||||
{
|
||||
int[] keys = {
|
||||
RideService.WATTS,
|
||||
RideService.NM,
|
||||
RideService.CAD,
|
||||
RideService.KPH,
|
||||
RideService.KM
|
||||
};
|
||||
|
||||
float[] values = {
|
||||
(float) 0.0,
|
||||
(float) 0.0,
|
||||
(float) 0.0,
|
||||
(float) 0.0,
|
||||
(float) 0.0
|
||||
};
|
||||
|
||||
alterCurrentData(keys, values);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,222 +0,0 @@
|
||||
package com.ridelogger.listners;
|
||||
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
import com.ridelogger.R;
|
||||
import com.ridelogger.RideService;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.hardware.Sensor;
|
||||
import android.hardware.SensorEvent;
|
||||
import android.hardware.SensorEventListener;
|
||||
import android.hardware.SensorManager;
|
||||
import android.preference.PreferenceManager;
|
||||
|
||||
/**
|
||||
* Sensors
|
||||
* @author Chet Henry
|
||||
* Listen to android sensor events and log them
|
||||
*/
|
||||
public class Sensors extends Base<Object>
|
||||
{
|
||||
public static final double CRASHMAGNITUDE = 30.0;
|
||||
|
||||
private SensorEventListener luxListner;
|
||||
private SensorEventListener accelListner;
|
||||
private SensorEventListener pressListner;
|
||||
private SensorEventListener tempListner;
|
||||
private SensorEventListener fieldListner;
|
||||
|
||||
public Sensors(RideService mContext)
|
||||
{
|
||||
super(mContext);
|
||||
|
||||
SensorManager mSensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
|
||||
|
||||
Sensor mLight = mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
|
||||
Sensor mAccel = mSensorManager.getDefaultSensor(Sensor.TYPE_LINEAR_ACCELERATION);
|
||||
Sensor mPress = mSensorManager.getDefaultSensor(Sensor.TYPE_PRESSURE);
|
||||
Sensor mTemp = mSensorManager.getDefaultSensor(Sensor.TYPE_AMBIENT_TEMPERATURE);
|
||||
Sensor mField = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
|
||||
|
||||
if(mLight != null) {
|
||||
luxListner = new SensorEventListener() {
|
||||
@Override
|
||||
public final void onAccuracyChanged(Sensor sensor, int accuracy) {}
|
||||
|
||||
@Override
|
||||
public final void onSensorChanged(SensorEvent event) {
|
||||
// The light sensor returns a single value.
|
||||
// Many sensors return 3 values, one for each axis.
|
||||
alterCurrentData(RideService.lux, event.values[0]);
|
||||
}
|
||||
};
|
||||
|
||||
mSensorManager.registerListener(luxListner, mLight, 3000000);
|
||||
}
|
||||
|
||||
if(mAccel != null) {
|
||||
SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
if(settings.getBoolean(context.getString(R.string.PREF_DETECT_CRASH), false)) {
|
||||
accelListner = new SensorEventListener() {
|
||||
private boolean crashed = false;
|
||||
private Timer timer = new Timer();
|
||||
private double[] St = new double[3];
|
||||
|
||||
@Override
|
||||
public final void onAccuracyChanged(Sensor sensor, int accuracy) {}
|
||||
|
||||
@Override
|
||||
public final void onSensorChanged(SensorEvent event) {
|
||||
int[] keys = {
|
||||
RideService.ms2x,
|
||||
RideService.ms2y,
|
||||
RideService.ms2z
|
||||
};
|
||||
|
||||
alterCurrentData(keys, event.values);
|
||||
|
||||
if(St.length == 0) {
|
||||
St[0] = event.values[0];
|
||||
St[1] = event.values[1];
|
||||
St[2] = event.values[2];
|
||||
}
|
||||
|
||||
St[0] = 0.6 * event.values[0] + 0.4 * St[0];
|
||||
St[1] = 0.6 * event.values[1] + 0.4 * St[1];
|
||||
St[2] = 0.6 * event.values[2] + 0.4 * St[2];
|
||||
|
||||
double amag = Math.sqrt(St[0]*St[0] + St[1]*St[1] + St[2]*St[2]);
|
||||
|
||||
if(amag > CRASHMAGNITUDE && !crashed) {
|
||||
crashed = true;
|
||||
context.phoneCrash(amag);
|
||||
|
||||
if(!Float.isNaN(context.currentValues[RideService.KPH])) {
|
||||
timer.schedule(
|
||||
new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
//if we are traveling less then 1km/h at 5 seconds after crash detection
|
||||
// confirm the crash
|
||||
if(1.0 > context.currentValues[RideService.KPH]) {
|
||||
context.phoneCrashConfirm();
|
||||
} else {
|
||||
crashed = false;
|
||||
context.phoneHome();
|
||||
}
|
||||
}
|
||||
},
|
||||
5000
|
||||
); //in five sec reset
|
||||
} else {
|
||||
timer.schedule(
|
||||
new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
crashed = false;
|
||||
}
|
||||
},
|
||||
180000
|
||||
); //in three min reset
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
} else {
|
||||
accelListner = new SensorEventListener() {
|
||||
@Override
|
||||
public final void onAccuracyChanged(Sensor sensor, int accuracy) {}
|
||||
|
||||
@Override
|
||||
public final void onSensorChanged(SensorEvent event) {
|
||||
int[] keys = {
|
||||
RideService.ms2x,
|
||||
RideService.ms2y,
|
||||
RideService.ms2z
|
||||
};
|
||||
|
||||
alterCurrentData(keys, event.values);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
mSensorManager.registerListener(accelListner, mAccel, SensorManager.SENSOR_DELAY_NORMAL);
|
||||
}
|
||||
|
||||
if(mPress != null) {
|
||||
pressListner = new SensorEventListener() {
|
||||
@Override
|
||||
public final void onAccuracyChanged(Sensor sensor, int accuracy) {}
|
||||
|
||||
@Override
|
||||
public final void onSensorChanged(SensorEvent event) {
|
||||
// The light sensor returns a single value.
|
||||
// Many sensors return 3 values, one for each axis.
|
||||
alterCurrentData(RideService.press, event.values[0]);
|
||||
}
|
||||
};
|
||||
|
||||
mSensorManager.registerListener(pressListner, mPress, 3000000);
|
||||
}
|
||||
|
||||
if(mTemp != null) {
|
||||
tempListner = new SensorEventListener() {
|
||||
@Override
|
||||
public final void onAccuracyChanged(Sensor sensor, int accuracy) {}
|
||||
|
||||
@Override
|
||||
public final void onSensorChanged(SensorEvent event) {
|
||||
// The light sensor returns a single value.
|
||||
// Many sensors return 3 values, one for each axis.
|
||||
alterCurrentData(RideService.temp, event.values[0]);
|
||||
}
|
||||
};
|
||||
|
||||
mSensorManager.registerListener(tempListner, mTemp, 3000000);
|
||||
}
|
||||
|
||||
if(mField != null) {
|
||||
fieldListner = new SensorEventListener() {
|
||||
@Override
|
||||
public final void onAccuracyChanged(Sensor sensor, int accuracy) {}
|
||||
|
||||
@Override
|
||||
public final void onSensorChanged(SensorEvent event) {
|
||||
int[] keys = {
|
||||
RideService.uTx,
|
||||
RideService.uTy,
|
||||
RideService.uTz
|
||||
};
|
||||
|
||||
alterCurrentData(keys, event.values);
|
||||
}
|
||||
};
|
||||
|
||||
mSensorManager.registerListener(fieldListner, mField, SensorManager.SENSOR_DELAY_NORMAL);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy()
|
||||
{
|
||||
SensorManager mSensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
|
||||
if(luxListner != null) {
|
||||
mSensorManager.unregisterListener(luxListner);
|
||||
}
|
||||
if(accelListner != null) {
|
||||
mSensorManager.unregisterListener(accelListner);
|
||||
}
|
||||
if(pressListner != null) {
|
||||
mSensorManager.unregisterListener(pressListner);
|
||||
}
|
||||
if(tempListner != null) {
|
||||
mSensorManager.unregisterListener(tempListner);
|
||||
}
|
||||
if(fieldListner != null) {
|
||||
mSensorManager.unregisterListener(fieldListner);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 173 KiB |
|
Before Width: | Height: | Size: 431 KiB After Width: | Height: | Size: 115 KiB |
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 3.9 MiB After Width: | Height: | Size: 3.9 MiB |
|
Before Width: | Height: | Size: 154 KiB After Width: | Height: | Size: 154 KiB |
|
Before Width: | Height: | Size: 165 KiB After Width: | Height: | Size: 165 KiB |
|
Before Width: | Height: | Size: 155 KiB After Width: | Height: | Size: 155 KiB |
|
Before Width: | Height: | Size: 181 KiB After Width: | Height: | Size: 181 KiB |
|
Before Width: | Height: | Size: 67 KiB After Width: | Height: | Size: 67 KiB |
|
Before Width: | Height: | Size: 323 KiB After Width: | Height: | Size: 150 KiB |
|
Before Width: | Height: | Size: 116 KiB |
|
Before Width: | Height: | Size: 121 KiB |
|
Before Width: | Height: | Size: 129 KiB After Width: | Height: | Size: 73 KiB |
|
Before Width: | Height: | Size: 166 KiB |
|
Before Width: | Height: | Size: 108 KiB After Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 109 KiB After Width: | Height: | Size: 98 KiB |
|
Before Width: | Height: | Size: 151 KiB After Width: | Height: | Size: 90 KiB |
|
Before Width: | Height: | Size: 388 KiB After Width: | Height: | Size: 133 KiB |
|
Before Width: | Height: | Size: 116 KiB After Width: | Height: | Size: 60 KiB |
|
Before Width: | Height: | Size: 51 KiB After Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 67 KiB After Width: | Height: | Size: 44 KiB |
|
Before Width: | Height: | Size: 154 KiB |
|
Before Width: | Height: | Size: 304 KiB After Width: | Height: | Size: 164 KiB |
|
Before Width: | Height: | Size: 447 KiB After Width: | Height: | Size: 251 KiB |
|
Before Width: | Height: | Size: 216 KiB After Width: | Height: | Size: 106 KiB |
|
Before Width: | Height: | Size: 166 KiB After Width: | Height: | Size: 144 KiB |
|
Before Width: | Height: | Size: 122 KiB After Width: | Height: | Size: 127 KiB |
|
Before Width: | Height: | Size: 196 KiB |
|
Before Width: | Height: | Size: 150 KiB After Width: | Height: | Size: 167 KiB |
|
Before Width: | Height: | Size: 209 KiB |
|
Before Width: | Height: | Size: 165 KiB After Width: | Height: | Size: 162 KiB |
|
Before Width: | Height: | Size: 131 KiB After Width: | Height: | Size: 126 KiB |
|
Before Width: | Height: | Size: 198 KiB After Width: | Height: | Size: 178 KiB |
|
Before Width: | Height: | Size: 161 KiB |
|
Before Width: | Height: | Size: 359 KiB After Width: | Height: | Size: 214 KiB |
|
Before Width: | Height: | Size: 181 KiB After Width: | Height: | Size: 99 KiB |
|
Before Width: | Height: | Size: 299 KiB After Width: | Height: | Size: 129 KiB |
|
Before Width: | Height: | Size: 220 KiB After Width: | Height: | Size: 130 KiB |
|
Before Width: | Height: | Size: 175 KiB After Width: | Height: | Size: 133 KiB |
|
Before Width: | Height: | Size: 162 KiB After Width: | Height: | Size: 134 KiB |
|
Before Width: | Height: | Size: 578 KiB After Width: | Height: | Size: 578 KiB |
|
Before Width: | Height: | Size: 2.7 MiB After Width: | Height: | Size: 2.7 MiB |
|
Before Width: | Height: | Size: 87 KiB After Width: | Height: | Size: 87 KiB |
|
Before Width: | Height: | Size: 82 KiB After Width: | Height: | Size: 82 KiB |
|
Before Width: | Height: | Size: 88 KiB After Width: | Height: | Size: 88 KiB |
|
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 50 KiB |
|
Before Width: | Height: | Size: 60 KiB After Width: | Height: | Size: 60 KiB |
|
Before Width: | Height: | Size: 127 KiB After Width: | Height: | Size: 127 KiB |
|
Before Width: | Height: | Size: 110 KiB After Width: | Height: | Size: 110 KiB |
|
Before Width: | Height: | Size: 8.1 KiB After Width: | Height: | Size: 8.1 KiB |
|
Before Width: | Height: | Size: 344 KiB After Width: | Height: | Size: 344 KiB |
|
Before Width: | Height: | Size: 124 KiB After Width: | Height: | Size: 124 KiB |
|
Before Width: | Height: | Size: 119 KiB |
BIN
doc/wiki/Share_Ride.jpg
Normal file
|
After Width: | Height: | Size: 81 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 96 KiB After Width: | Height: | Size: 96 KiB |
|
Before Width: | Height: | Size: 75 KiB After Width: | Height: | Size: 75 KiB |
|
Before Width: | Height: | Size: 163 KiB After Width: | Height: | Size: 163 KiB |