diff --git a/res/drawable-hdpi/ic_ambient_light.png b/res/drawable-hdpi/ic_ambient_light.png
new file mode 100755
index 0000000..01cd42f
Binary files /dev/null and b/res/drawable-hdpi/ic_ambient_light.png differ
diff --git a/res/drawable-hdpi/ic_pdk_accelerometer.png b/res/drawable-hdpi/ic_pdk_accelerometer.png
new file mode 100755
index 0000000..0fdc766
Binary files /dev/null and b/res/drawable-hdpi/ic_pdk_accelerometer.png differ
diff --git a/res/drawable-hdpi/ic_pdk_action_lock.png b/res/drawable-hdpi/ic_pdk_action_lock.png
new file mode 100755
index 0000000..6409845
Binary files /dev/null and b/res/drawable-hdpi/ic_pdk_action_lock.png differ
diff --git a/res/drawable-hdpi/ic_pdk_action_unlock.png b/res/drawable-hdpi/ic_pdk_action_unlock.png
new file mode 100755
index 0000000..f5a7c05
Binary files /dev/null and b/res/drawable-hdpi/ic_pdk_action_unlock.png differ
diff --git a/res/drawable-mdpi/ic_ambient_light.png b/res/drawable-mdpi/ic_ambient_light.png
new file mode 100755
index 0000000..183e053
Binary files /dev/null and b/res/drawable-mdpi/ic_ambient_light.png differ
diff --git a/res/drawable-mdpi/ic_pdk_accelerometer.png b/res/drawable-mdpi/ic_pdk_accelerometer.png
new file mode 100755
index 0000000..5570049
Binary files /dev/null and b/res/drawable-mdpi/ic_pdk_accelerometer.png differ
diff --git a/res/drawable-mdpi/ic_pdk_action_lock.png b/res/drawable-mdpi/ic_pdk_action_lock.png
new file mode 100755
index 0000000..53377c1
Binary files /dev/null and b/res/drawable-mdpi/ic_pdk_action_lock.png differ
diff --git a/res/drawable-mdpi/ic_pdk_action_unlock.png b/res/drawable-mdpi/ic_pdk_action_unlock.png
new file mode 100755
index 0000000..542703d
Binary files /dev/null and b/res/drawable-mdpi/ic_pdk_action_unlock.png differ
diff --git a/res/drawable-xhdpi/ic_ambient_light.png b/res/drawable-xhdpi/ic_ambient_light.png
new file mode 100755
index 0000000..64185f1
Binary files /dev/null and b/res/drawable-xhdpi/ic_ambient_light.png differ
diff --git a/res/drawable-xhdpi/ic_pdk_accelerometer.png b/res/drawable-xhdpi/ic_pdk_accelerometer.png
new file mode 100755
index 0000000..b5cdeaf
Binary files /dev/null and b/res/drawable-xhdpi/ic_pdk_accelerometer.png differ
diff --git a/res/drawable-xhdpi/ic_pdk_action_lock.png b/res/drawable-xhdpi/ic_pdk_action_lock.png
new file mode 100755
index 0000000..093cf20
Binary files /dev/null and b/res/drawable-xhdpi/ic_pdk_action_lock.png differ
diff --git a/res/drawable-xhdpi/ic_pdk_action_unlock.png b/res/drawable-xhdpi/ic_pdk_action_unlock.png
new file mode 100755
index 0000000..5d14385
Binary files /dev/null and b/res/drawable-xhdpi/ic_pdk_action_unlock.png differ
diff --git a/res/drawable-xxhdpi/ic_ambient_light.png b/res/drawable-xxhdpi/ic_ambient_light.png
new file mode 100755
index 0000000..84d9cbb
Binary files /dev/null and b/res/drawable-xxhdpi/ic_ambient_light.png differ
diff --git a/res/drawable-xxhdpi/ic_pdk_accelerometer.png b/res/drawable-xxhdpi/ic_pdk_accelerometer.png
new file mode 100755
index 0000000..d9970ce
Binary files /dev/null and b/res/drawable-xxhdpi/ic_pdk_accelerometer.png differ
diff --git a/res/drawable-xxhdpi/ic_pdk_action_lock.png b/res/drawable-xxhdpi/ic_pdk_action_lock.png
new file mode 100755
index 0000000..620d614
Binary files /dev/null and b/res/drawable-xxhdpi/ic_pdk_action_lock.png differ
diff --git a/res/drawable-xxhdpi/ic_pdk_action_unlock.png b/res/drawable-xxhdpi/ic_pdk_action_unlock.png
new file mode 100755
index 0000000..0ffdc60
Binary files /dev/null and b/res/drawable-xxhdpi/ic_pdk_action_unlock.png differ
diff --git a/res/drawable-xxxhdpi/ic_ambient_light.png b/res/drawable-xxxhdpi/ic_ambient_light.png
new file mode 100755
index 0000000..d5c3269
Binary files /dev/null and b/res/drawable-xxxhdpi/ic_ambient_light.png differ
diff --git a/res/drawable-xxxhdpi/ic_pdk_accelerometer.png b/res/drawable-xxxhdpi/ic_pdk_accelerometer.png
new file mode 100755
index 0000000..855cdd6
Binary files /dev/null and b/res/drawable-xxxhdpi/ic_pdk_accelerometer.png differ
diff --git a/res/drawable-xxxhdpi/ic_pdk_action_lock.png b/res/drawable-xxxhdpi/ic_pdk_action_lock.png
new file mode 100755
index 0000000..ae3f973
Binary files /dev/null and b/res/drawable-xxxhdpi/ic_pdk_action_lock.png differ
diff --git a/res/drawable-xxxhdpi/ic_pdk_action_unlock.png b/res/drawable-xxxhdpi/ic_pdk_action_unlock.png
new file mode 100755
index 0000000..bc597c2
Binary files /dev/null and b/res/drawable-xxxhdpi/ic_pdk_action_unlock.png differ
diff --git a/res/layout/card_generator_sensors_accelerometer.xml b/res/layout/card_generator_sensors_accelerometer.xml
new file mode 100755
index 0000000..3f80ec3
--- /dev/null
+++ b/res/layout/card_generator_sensors_accelerometer.xml
@@ -0,0 +1,63 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/res/layout/card_generator_sensors_ambient_light.xml b/res/layout/card_generator_sensors_ambient_light.xml
new file mode 100755
index 0000000..62dd685
--- /dev/null
+++ b/res/layout/card_generator_sensors_ambient_light.xml
@@ -0,0 +1,63 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/res/menu/activity_data_stream.xml b/res/menu/activity_data_stream.xml
new file mode 100755
index 0000000..d6a6bbf
--- /dev/null
+++ b/res/menu/activity_data_stream.xml
@@ -0,0 +1,8 @@
+
+
diff --git a/res/values/databases.xml b/res/values/databases.xml
index 9e41810..0b74d73 100755
--- a/res/values/databases.xml
+++ b/res/values/databases.xml
@@ -27,8 +27,14 @@
CREATE TABLE history(_id INTEGER PRIMARY KEY AUTOINCREMENT, fetched INTEGER, transmitted INTEGER, observed INTEGER, health TEXT, level INTERGER, plugged TEXT, present INTEGER, scale INTEGER, temperature INTEGER, voltage INTEGER, technology TEXT, status TEXT);
-
+
CREATE TABLE history(_id INTEGER PRIMARY KEY AUTOINCREMENT, fetched INTEGER, transmitted INTEGER, observed INTEGER, application TEXT);
ALTER TABLE history ADD duration REAL;
+ ALTER TABLE history ADD screen_active INTEGER;
+
+ CREATE TABLE history(_id INTEGER PRIMARY KEY AUTOINCREMENT, fetched INTEGER, transmitted INTEGER, observed INTEGER, light_level REAL, raw_timestamp BIGINT, accuracy INTEGER);
+
+
+ CREATE TABLE history(_id INTEGER PRIMARY KEY AUTOINCREMENT, fetched INTEGER, transmitted INTEGER, observed INTEGER, x REAL, y REAL, z REAL, raw_timestamp BIGINT, accuracy INTEGER);
diff --git a/res/values/generators.xml b/res/values/generators.xml
index b4037cd..0150e72 100755
--- a/res/values/generators.xml
+++ b/res/values/generators.xml
@@ -158,4 +158,23 @@
Most Used (Last 24 Hours)
Recently Used
%1$s: %2$.0fm
-
\ No newline at end of file
+
+
+ Ambient Light
+ No ambient light levels have been recorded yet.
+ #FFD600
+ #80FFEB3B
+ #ffFFEB3B
+
+
+ Accelerometer
+ No accelerometer readings have been recorded yet.
+ #3F51B5
+ #80F44336
+ #ffF44336
+ #804CAF50
+ #ff4CAF50
+ #802196F3
+ #ff2196F3
+
+
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 73b220f..3c77eb0 100755
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -6,6 +6,8 @@
Data Stream
Continue
+ Toggle Sort Lock
+
- %d generator
- %d generators
diff --git a/src/com/audacious_software/passive_data_kit/activities/DataStreamActivity.java b/src/com/audacious_software/passive_data_kit/activities/DataStreamActivity.java
index 3e80bb0..c3a33f4 100755
--- a/src/com/audacious_software/passive_data_kit/activities/DataStreamActivity.java
+++ b/src/com/audacious_software/passive_data_kit/activities/DataStreamActivity.java
@@ -1,11 +1,16 @@
package com.audacious_software.passive_data_kit.activities;
+import android.content.Intent;
+import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
+import android.preference.PreferenceManager;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
+import android.view.Menu;
+import android.view.MenuItem;
import com.audacious_software.passive_data_kit.activities.generators.DataPointsAdapter;
import com.audacious_software.passive_data_kit.generators.Generators;
@@ -15,6 +20,7 @@
public class DataStreamActivity extends AppCompatActivity implements Generators.GeneratorUpdatedListener {
private DataPointsAdapter mAdapter = null;
+ private Menu mMenu = null;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -70,4 +76,50 @@ public void run() {
}
});
}
+
+ public boolean onCreateOptionsMenu(Menu menu) {
+ // Inflate the menu; this adds items to the action bar if it is present.
+ this.getMenuInflater().inflate(R.menu.activity_data_stream, menu);
+
+ this.mMenu = menu;
+
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ // Handle action bar item clicks here. The action bar will
+ // automatically handle clicks on the Home/Up button, so long
+ // as you specify a parent activity in AndroidManifest.xml.
+ int id = item.getItemId();
+
+ //noinspection SimplifiableIfStatement
+ if (id == R.id.action_pdk_toggle_sort_lock) {
+ this.toggleSortLock();
+
+ return true;
+ }
+
+ return true;
+ }
+
+ private void toggleSortLock() {
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
+
+ boolean locked = prefs.getBoolean(DataPointsAdapter.SORT_BY_UPDATED, DataPointsAdapter.SORT_BY_UPDATED_DEFAULT);
+
+ MenuItem lockedItem = this.mMenu.findItem(R.id.action_pdk_toggle_sort_lock);
+
+ if (locked) {
+ lockedItem.setIcon(R.drawable.ic_pdk_action_unlock);
+ } else {
+ lockedItem.setIcon(R.drawable.ic_pdk_action_lock);
+ }
+
+ SharedPreferences.Editor e = prefs.edit();
+ e.putBoolean(DataPointsAdapter.SORT_BY_UPDATED, (locked == false));
+ e.apply();
+
+ this.mAdapter.notifyDataSetChanged();
+ }
}
diff --git a/src/com/audacious_software/passive_data_kit/activities/generators/DataPointsAdapter.java b/src/com/audacious_software/passive_data_kit/activities/generators/DataPointsAdapter.java
index b934071..38cffc3 100755
--- a/src/com/audacious_software/passive_data_kit/activities/generators/DataPointsAdapter.java
+++ b/src/com/audacious_software/passive_data_kit/activities/generators/DataPointsAdapter.java
@@ -1,6 +1,8 @@
package com.audacious_software.passive_data_kit.activities.generators;
import android.content.Context;
+import android.content.SharedPreferences;
+import android.preference.PreferenceManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.View;
@@ -18,6 +20,9 @@
import java.util.List;
public class DataPointsAdapter extends RecyclerView.Adapter {
+ public static final String SORT_BY_UPDATED = "com.audacious_software.passive_data_kit.activities.generators.DataPointsAdapter";
+ public static final boolean SORT_BY_UPDATED_DEFAULT = true;
+
private Context mContext = null;
@Override
@@ -85,46 +90,57 @@ public int getItemCount() {
}
private void sortGenerators(final Context context, List> generators) {
- Collections.sort(generators, new Comparator>() {
- @Override
- public int compare(Class extends Generator> one, Class extends Generator> two) {
- long oneUpdated = 0;
-
- try {
- Method oneGenerated = one.getDeclaredMethod("latestPointGenerated", Context.class);
-
- oneUpdated = (long) oneGenerated.invoke(null, context);
- } catch (NoSuchMethodException e) {
- e.printStackTrace();
- } catch (InvocationTargetException e) {
- e.printStackTrace();
- } catch (IllegalAccessException e) {
- e.printStackTrace();
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
+
+ if (prefs.getBoolean(DataPointsAdapter.SORT_BY_UPDATED, DataPointsAdapter.SORT_BY_UPDATED_DEFAULT)) {
+ Collections.sort(generators, new Comparator>() {
+ @Override
+ public int compare(Class extends Generator> one, Class extends Generator> two) {
+ long oneUpdated = 0;
+
+ try {
+ Method oneGenerated = one.getDeclaredMethod("latestPointGenerated", Context.class);
+
+ oneUpdated = (long) oneGenerated.invoke(null, context);
+ } catch (NoSuchMethodException e) {
+ e.printStackTrace();
+ } catch (InvocationTargetException e) {
+ e.printStackTrace();
+ } catch (IllegalAccessException e) {
+ e.printStackTrace();
+ }
+
+ long twoUpdated = 0;
+
+ try {
+ Method twoGenerated = two.getDeclaredMethod("latestPointGenerated", Context.class);
+
+ twoUpdated = (long) twoGenerated.invoke(null, context);
+ } catch (NoSuchMethodException e) {
+ e.printStackTrace();
+ } catch (InvocationTargetException e) {
+ e.printStackTrace();
+ } catch (IllegalAccessException e) {
+ e.printStackTrace();
+ }
+
+ if (oneUpdated < twoUpdated) {
+ return 1;
+ } else if (oneUpdated > twoUpdated) {
+ return -1;
+ }
+
+ return 0;
}
-
- long twoUpdated = 0;
-
- try {
- Method twoGenerated = two.getDeclaredMethod("latestPointGenerated", Context.class);
-
- twoUpdated = (long) twoGenerated.invoke(null, context);
- } catch (NoSuchMethodException e) {
- e.printStackTrace();
- } catch (InvocationTargetException e) {
- e.printStackTrace();
- } catch (IllegalAccessException e) {
- e.printStackTrace();
+ });
+ } else {
+ Collections.sort(generators, new Comparator>() {
+ @Override
+ public int compare(Class extends Generator> one, Class extends Generator> two) {
+ return one.getCanonicalName().compareTo(two.getCanonicalName());
}
-
- if (oneUpdated < twoUpdated) {
- return 1;
- } else if (oneUpdated > twoUpdated) {
- return -1;
- }
-
- return 0;
- }
- });
+ });
+ }
}
public int getItemViewType (int position) {
diff --git a/src/com/audacious_software/passive_data_kit/generators/device/Battery.java b/src/com/audacious_software/passive_data_kit/generators/device/Battery.java
index f940c35..6fead94 100755
--- a/src/com/audacious_software/passive_data_kit/generators/device/Battery.java
+++ b/src/com/audacious_software/passive_data_kit/generators/device/Battery.java
@@ -11,7 +11,6 @@
import android.os.BatteryManager;
import android.os.Bundle;
import android.support.v4.content.ContextCompat;
-import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -342,13 +341,9 @@ public String getFormattedValue(float value, AxisBase axis) {
if (level != lastLevel) {
values.add(0, new Entry(when, level));
lastLevel = level;
-
- Log.e("SLEEP-SIGHT", "VALUE: " + level + " -- " + (when - start));
}
}
- Log.e("SLEEP-SIGHT", "BATT VALUES COUNT 2: " + values.size());
-
LineDataSet set = new LineDataSet(values, "Battery");
set.setAxisDependency(YAxis.AxisDependency.LEFT);
set.setLineWidth(2.0f);
diff --git a/src/com/audacious_software/passive_data_kit/generators/device/ForegroundApplication.java b/src/com/audacious_software/passive_data_kit/generators/device/ForegroundApplication.java
index 4eb5410..90f4620 100755
--- a/src/com/audacious_software/passive_data_kit/generators/device/ForegroundApplication.java
+++ b/src/com/audacious_software/passive_data_kit/generators/device/ForegroundApplication.java
@@ -13,9 +13,11 @@
import android.os.Bundle;
import android.provider.Settings;
import android.util.Log;
+import android.view.Display;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
@@ -46,12 +48,13 @@ public class ForegroundApplication extends Generator{
private static final String ENABLED = "com.audacious_software.passive_data_kit.generators.device.ForegroundApplication.ENABLED";
private static final boolean ENABLED_DEFAULT = true;
- private static int DATABASE_VERSION = 2;
+ private static int DATABASE_VERSION = 3;
private static final String TABLE_HISTORY = "history";
private static final String HISTORY_OBSERVED = "observed";
private static final String HISTORY_APPLICATION = "application";
private static final String HISTORY_DURATION = "duration";
+ private static final String HISTORY_SCREEN_ACTIVE = "screen_active";
private static ForegroundApplication sInstance = null;
@@ -94,14 +97,26 @@ private void startGenerator() {
this.mAppChecker.other(new AppChecker.Listener() {
@Override
public void onForeground(String process) {
- Log.e("PDK", "PROCESS: " + process);
-
long now = System.currentTimeMillis();
+ WindowManager window = (WindowManager) me.mContext.getSystemService(Context.WINDOW_SERVICE);
+ Display display = window.getDefaultDisplay();
+
+ boolean screenActive = true;
+
+ if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) {
+ if (display.getState() != Display.STATE_ON) {
+ screenActive = false;
+ }
+ }
+
+ Log.e("PDK", "PROCESS: " + process + " -- " + screenActive);
+
ContentValues values = new ContentValues();
values.put(ForegroundApplication.HISTORY_OBSERVED, now);
values.put(ForegroundApplication.HISTORY_APPLICATION, process);
values.put(ForegroundApplication.HISTORY_DURATION, me.mSampleInterval);
+ values.put(ForegroundApplication.HISTORY_SCREEN_ACTIVE, screenActive);
me.mDatabase.insert(ForegroundApplication.TABLE_HISTORY, null, values);
@@ -130,6 +145,8 @@ public void onForeground(String process) {
this.mDatabase.execSQL(this.mContext.getString(R.string.pdk_generator_foreground_applications_create_history_table));
case 1:
this.mDatabase.execSQL(this.mContext.getString(R.string.pdk_generator_foreground_applications_history_table_add_duration));
+ case 2:
+ this.mDatabase.execSQL(this.mContext.getString(R.string.pdk_generator_foreground_applications_history_table_add_screen_active));
}
this.setDatabaseVersion(this.mDatabase, ForegroundApplication.DATABASE_VERSION);
@@ -200,8 +217,8 @@ public static void bindViewHolder(DataPointViewHolder holder) {
ArrayList latest = new ArrayList<>();
- String where = ForegroundApplication.HISTORY_OBSERVED + " > ?";
- String[] args = { "" + yesterday };
+ String where = ForegroundApplication.HISTORY_OBSERVED + " > ? AND " + ForegroundApplication.HISTORY_SCREEN_ACTIVE + " = ?";
+ String[] args = { "" + yesterday, "1" };
c = generator.mDatabase.query(ForegroundApplication.TABLE_HISTORY, null, where, args, null, null, ForegroundApplication.HISTORY_OBSERVED);
@@ -298,16 +315,19 @@ public int compare(HashMap mapOne, HashMap mapTw
for (String key : appDef.keySet()) {
double duration = appDef.get(key);
+ double minutes = duration / (1000 * 60);
+
try {
String name = packageManager.getApplicationLabel(packageManager.getApplicationInfo(key, PackageManager.GET_META_DATA)).toString();
- double minutes = duration / (1000 * 60);
-
appName.setText(context.getString(R.string.generator_foreground_application_app_name_duration, name, minutes));
Drawable icon = packageManager.getApplicationIcon(key);
appIcon.setImageDrawable(icon);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
+
+ appName.setText(context.getString(R.string.generator_foreground_application_app_name_duration, key, minutes));
+ appIcon.setImageDrawable(null);
}
double remainder = largestUsage - duration;
diff --git a/src/com/audacious_software/passive_data_kit/generators/sensors/Accelerometer.java b/src/com/audacious_software/passive_data_kit/generators/sensors/Accelerometer.java
index 3828e56..93e805d 100755
--- a/src/com/audacious_software/passive_data_kit/generators/sensors/Accelerometer.java
+++ b/src/com/audacious_software/passive_data_kit/generators/sensors/Accelerometer.java
@@ -1,8 +1,658 @@
package com.audacious_software.passive_data_kit.generators.sensors;
+import android.app.Activity;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener;
+import android.hardware.SensorManager;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.support.v4.content.ContextCompat;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import com.audacious_software.passive_data_kit.PassiveDataKit;
+import com.audacious_software.passive_data_kit.activities.generators.DataPointViewHolder;
+import com.audacious_software.passive_data_kit.diagnostics.DiagnosticAction;
+import com.audacious_software.passive_data_kit.generators.Generator;
+import com.audacious_software.passive_data_kit.generators.Generators;
+import com.audacious_software.pdk.passivedatakit.R;
+import com.github.mikephil.charting.charts.LineChart;
+import com.github.mikephil.charting.components.AxisBase;
+import com.github.mikephil.charting.components.XAxis;
+import com.github.mikephil.charting.components.YAxis;
+import com.github.mikephil.charting.data.Entry;
+import com.github.mikephil.charting.data.LineData;
+import com.github.mikephil.charting.data.LineDataSet;
+import com.github.mikephil.charting.formatter.IAxisValueFormatter;
+
+import java.io.File;
+import java.text.DateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
/**
* Created by cjkarr on 4/17/2017.
*/
-public class Accelerometer {
+public class Accelerometer extends SensorGenerator implements SensorEventListener {
+ private static final String GENERATOR_IDENTIFIER = "pdk-sensor-accelerometer";
+
+ private static final String ENABLED = "com.audacious_software.passive_data_kit.generators.device.Accelerometer.ENABLED";
+ private static final boolean ENABLED_DEFAULT = true;
+
+ private static final String DATABASE_PATH = "pdk-sensor-accelerometer.sqlite";
+ private static final int DATABASE_VERSION = 1;
+
+ public static final String TABLE_HISTORY = "history";
+
+ public static final String HISTORY_OBSERVED = "observed";
+ private static final String HISTORY_RAW_TIMESTAMP = "raw_timestamp";
+ private static final String HISTORY_ACCURACY = "accuracy";
+ public static final String HISTORY_X = "x";
+ public static final String HISTORY_Y = "y";
+ public static final String HISTORY_Z = "z";
+
+ private static Accelerometer sInstance = null;
+ private static Handler sHandler = null;
+
+ private static boolean sIsDrawing = false;
+ private static long sLastDrawStart = 0;
+
+ private SQLiteDatabase mDatabase = null;
+
+ private Sensor mSensor = null;
+
+ private static int NUM_BUFFERS = 3;
+ private static int BUFFER_SIZE = 1024;
+
+ private long mLastCleanup = 0;
+ private long mCleanupInterval = 15 * 60 * 1000;
+
+ private int mActiveBuffersIndex = 0;
+ private int mCurrentBufferIndex = 0;
+
+ private float[][] mXValueBuffers = null;
+ private float[][] mYValueBuffers = null;
+ private float[][] mZValueBuffers = null;
+ private int[][] mAccuracyBuffers = null;
+ private long[][] mRawTimestampBuffers = null;
+ private long[][] mTimestampBuffers = null;
+
+ long mBaseTimestamp = 0;
+
+ private long mLatestTimestamp = 0;
+
+ public static Accelerometer getInstance(Context context) {
+ if (Accelerometer.sInstance == null) {
+ Accelerometer.sInstance = new Accelerometer(context.getApplicationContext());
+ }
+
+ return Accelerometer.sInstance;
+ }
+
+ public Accelerometer(Context context) {
+ super(context);
+ }
+
+ public static void start(final Context context) {
+ Accelerometer.getInstance(context).startGenerator();
+ }
+
+ private void startGenerator() {
+ final SensorManager sensors = (SensorManager) this.mContext.getSystemService(Context.SENSOR_SERVICE);
+
+ final Accelerometer me = this;
+
+ Generators.getInstance(this.mContext).registerCustomViewClass(Accelerometer.GENERATOR_IDENTIFIER, Accelerometer.class);
+
+ File path = PassiveDataKit.getGeneratorsStorage(this.mContext);
+
+ path = new File(path, Accelerometer.DATABASE_PATH);
+
+ this.mDatabase = SQLiteDatabase.openOrCreateDatabase(path, null);
+
+ int version = this.getDatabaseVersion(this.mDatabase);
+
+ switch (version) {
+ case 0:
+ this.mDatabase.execSQL(this.mContext.getString(R.string.pdk_generator_accelerometer_create_history_table));
+ }
+
+ this.setDatabaseVersion(this.mDatabase, Accelerometer.DATABASE_VERSION);
+
+ if (Accelerometer.isEnabled(this.mContext)) {
+ this.mSensor = sensors.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
+
+ Runnable r = new Runnable()
+ {
+ public void run()
+ {
+ Looper.prepare();
+
+ me.mXValueBuffers = new float[Accelerometer.NUM_BUFFERS][Accelerometer.BUFFER_SIZE];
+ me.mYValueBuffers = new float[Accelerometer.NUM_BUFFERS][Accelerometer.BUFFER_SIZE];
+ me.mZValueBuffers = new float[Accelerometer.NUM_BUFFERS][Accelerometer.BUFFER_SIZE];
+ me.mAccuracyBuffers = new int[Accelerometer.NUM_BUFFERS][Accelerometer.BUFFER_SIZE];
+ me.mRawTimestampBuffers = new long[Accelerometer.NUM_BUFFERS][Accelerometer.BUFFER_SIZE];
+ me.mTimestampBuffers = new long[Accelerometer.NUM_BUFFERS][Accelerometer.BUFFER_SIZE];
+
+ me.mActiveBuffersIndex = 0;
+ me.mCurrentBufferIndex = 0;
+
+ Accelerometer.sHandler = new Handler();
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
+ sensors.registerListener(me, me.mSensor, SensorManager.SENSOR_DELAY_NORMAL, 0, Accelerometer.sHandler);
+ else
+ sensors.registerListener(me, me.mSensor, SensorManager.SENSOR_DELAY_NORMAL, Accelerometer.sHandler);
+
+ Looper.loop();
+ }
+ };
+
+ Thread t = new Thread(r, "accelerometer");
+ t.start();
+ } else {
+ if (this.mSensor != null) {
+ sensors.unregisterListener(this, this.mSensor);
+
+ if (Accelerometer.sHandler != null) {
+ Looper loop = Accelerometer.sHandler.getLooper();
+ loop.quit();
+
+ Accelerometer.sHandler = null;
+ }
+
+ me.mXValueBuffers = null;
+ me.mYValueBuffers = null;
+ me.mZValueBuffers = null;
+ me.mAccuracyBuffers = null;
+ me.mRawTimestampBuffers = null;
+ me.mTimestampBuffers = null;
+
+ me.mActiveBuffersIndex = 0;
+ me.mCurrentBufferIndex = 0;
+
+ this.mSensor = null;
+ }
+ }
+ }
+
+ public static boolean isEnabled(Context context) {
+ SharedPreferences prefs = Generators.getInstance(context).getSharedPreferences(context);
+
+ return prefs.getBoolean(Accelerometer.ENABLED, Accelerometer.ENABLED_DEFAULT);
+ }
+
+ public static boolean isRunning(Context context) {
+ if (Accelerometer.sInstance == null) {
+ return false;
+ }
+
+ return Accelerometer.sInstance.mSensor != null;
+ }
+
+ public static ArrayList diagnostics(Context context) {
+ return new ArrayList<>();
+ }
+
+ public static void bindViewHolder(final DataPointViewHolder holder) {
+ if (Accelerometer.sIsDrawing) {
+ Log.e("PDK", "IS DRAWING");
+ return;
+ }
+
+ final long drawStart = System.currentTimeMillis();
+
+ if (drawStart - Accelerometer.sLastDrawStart < (30 * 1000)) {
+ Log.e("PDK", "TOO SOON");
+ return;
+ }
+
+ Accelerometer.sLastDrawStart = drawStart;
+
+ Accelerometer.sIsDrawing = true;
+
+ Log.e("PDK", "HOLDER " + holder.hashCode());
+
+ final Context context = holder.itemView.getContext();
+ final View itemView = holder.itemView;
+
+ final Accelerometer generator = Accelerometer.getInstance(context);
+
+ final long now = System.currentTimeMillis() / (1000 * 60 * 5);
+ final long start = now - (24 * 12); // * 60);
+
+ Log.e("PDK", "START QUERY: " + (System.currentTimeMillis() - drawStart));
+
+ Cursor c = generator.mDatabase.query(Accelerometer.TABLE_HISTORY, null, null, null, null, null, Accelerometer.HISTORY_OBSERVED + " DESC");
+
+ Log.e("PDK", "END QUERY: " + (System.currentTimeMillis() - drawStart));
+
+ View cardContent = itemView.findViewById(R.id.card_content);
+ View cardEmpty = itemView.findViewById(R.id.card_empty);
+ TextView dateLabel = (TextView) itemView.findViewById(R.id.generator_data_point_date);
+
+ Log.e("PDK", "ACCEL PREP: " + (System.currentTimeMillis() - drawStart) + " -- COUNT: " + c.getCount());
+
+ if (c.moveToNext() && (context instanceof Activity)) {
+ cardContent.setVisibility(View.VISIBLE);
+ cardEmpty.setVisibility(View.GONE);
+
+ long timestamp = c.getLong(c.getColumnIndex(Accelerometer.HISTORY_OBSERVED)) / (1000 * 1000 * 1000);
+
+ dateLabel.setText(Generator.formatTimestamp(context, timestamp));
+
+ Runnable r = new Runnable() {
+ @Override
+ public void run() {
+ Log.e("PDK", "THREAD START: " + (System.currentTimeMillis() - drawStart));
+
+ final ArrayList xLowValues = new ArrayList<>();
+ final ArrayList xHighValues = new ArrayList<>();
+
+ final ArrayList yLowValues = new ArrayList<>();
+ final ArrayList yHighValues = new ArrayList<>();
+
+ final ArrayList zLowValues = new ArrayList<>();
+ final ArrayList zHighValues = new ArrayList<>();
+
+ final String where = Accelerometer.HISTORY_OBSERVED + " >= ? AND _id % 1024 = 0";
+ final String[] args = { "" + start };
+
+ Cursor c = generator.mDatabase.query(Accelerometer.TABLE_HISTORY, null, where, args, null, null, Accelerometer.HISTORY_OBSERVED + " DESC");
+
+ long lastTimestamp = -1;
+
+ float maxValue = 0;
+ float minValue = 0;
+
+ float lowX = -1;
+ float highX = -1;
+
+ float lowY = -1;
+ float highY = -1;
+
+ float lowZ = -1;
+ float highZ = -1;
+
+ int whenIndex = c.getColumnIndex(Accelerometer.HISTORY_OBSERVED);
+ int xIndex = c.getColumnIndex(Accelerometer.HISTORY_X);
+ int yIndex = c.getColumnIndex(Accelerometer.HISTORY_Y);
+ int zIndex = c.getColumnIndex(Accelerometer.HISTORY_Z);
+
+ Log.e("PDK", "COUNT: " + c.getCount());
+ Log.e("PDK", "ACCEL START BUILD: " + (System.currentTimeMillis() - drawStart));
+
+ while (c.moveToNext()) {
+ long when = c.getLong(whenIndex);
+
+ when = when / (1000 * 1000);
+ when = when / (1000 * 6 * 50);
+
+ float x = c.getFloat(xIndex);
+ float y = c.getFloat(yIndex);
+ float z = c.getFloat(zIndex);
+
+ if (lastTimestamp != when) {
+ if (lastTimestamp != -1) {
+ xLowValues.add(0, new Entry(lastTimestamp, lowX));
+ xHighValues.add(0, new Entry(lastTimestamp, highX));
+
+ yLowValues.add(0, new Entry(lastTimestamp, lowY));
+ yHighValues.add(0, new Entry(lastTimestamp, highY));
+
+ zLowValues.add(0, new Entry(lastTimestamp, lowZ));
+ zHighValues.add(0, new Entry(lastTimestamp, highZ));
+ }
+
+ lastTimestamp = when;
+
+ lowX = x;
+ highX = x;
+
+ lowY = y;
+ highY = y;
+
+ lowZ = z;
+ highZ = z;
+ } else {
+ if (x < lowX) {
+ lowX = x;
+ }
+
+ if (x > highX) {
+ highX = x;
+ }
+
+ if (y < lowY) {
+ lowY = y;
+ }
+
+ if (y > highY) {
+ highY = y;
+ }
+
+ if (z < lowZ) {
+ lowZ = z;
+ }
+
+ if (z > highZ) {
+ highZ = z;
+ }
+ }
+
+ if (x > maxValue) {
+ maxValue = x;
+ }
+
+ if (x < minValue) {
+ minValue = x;
+ }
+
+ if (y > maxValue) {
+ maxValue = y;
+ }
+
+ if (y < minValue) {
+ minValue = y;
+ }
+
+ if (z > maxValue) {
+ maxValue = z;
+ }
+
+ if (z < minValue) {
+ minValue = z;
+ }
+ }
+
+ Log.e("PDK", "ACCEL END BUILD BUILD: " + (System.currentTimeMillis() - drawStart));
+
+ Log.e("PDK", "DATA COUNT: " + xLowValues.size());
+
+ if (lastTimestamp != -1) {
+ xLowValues.add(0, new Entry(lastTimestamp, lowX));
+ xHighValues.add(0, new Entry(lastTimestamp, highX));
+
+ yLowValues.add(0, new Entry(lastTimestamp, lowY));
+ yHighValues.add(0, new Entry(lastTimestamp, highY));
+
+ zLowValues.add(0, new Entry(lastTimestamp, lowZ));
+ zHighValues.add(0, new Entry(lastTimestamp, highZ));
+ }
+
+ c.close();
+
+ Activity activity = (Activity) context;
+
+ final float finalMaxValue = maxValue;
+ final float finalMinValue = minValue;
+
+ Log.e("PDK", "THREAD HANDOFF: " + (System.currentTimeMillis() - drawStart));
+
+ final List> data = new ArrayList<>();
+ data.add(xLowValues);
+ data.add(xHighValues);
+ data.add(yLowValues);
+ data.add(yHighValues);
+ data.add(zLowValues);
+ data.add(zHighValues);
+
+ activity.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ Log.e("PDK", "UI START: " + (System.currentTimeMillis() - drawStart));
+
+ int[] colors = {
+ R.color.generator_accelerometer_x_low,
+ R.color.generator_accelerometer_x_high,
+ R.color.generator_accelerometer_y_low,
+ R.color.generator_accelerometer_y_high,
+ R.color.generator_accelerometer_z_low,
+ R.color.generator_accelerometer_z_high
+ };
+
+ LineData chartData = new LineData();
+
+ for (int i = 0; i < colors.length; i++) {
+ int color = colors[i];
+
+ ArrayList entries = data.get(i);
+
+ LineDataSet set = new LineDataSet(entries, "");
+ set.setAxisDependency(YAxis.AxisDependency.LEFT);
+ set.setLineWidth(1.0f);
+ set.setDrawCircles(false);
+ set.setFillAlpha(192);
+ set.setDrawFilled(false);
+ set.setDrawValues(true);
+ set.setColor(ContextCompat.getColor(context, color));
+ set.setDrawCircleHole(false);
+ set.setDrawValues(false);
+ set.setMode(LineDataSet.Mode.LINEAR);
+
+ chartData.addDataSet(set);
+ }
+
+ Log.e("PDK", "ACCEL START GRAPH: " + (System.currentTimeMillis() - drawStart));
+
+ final LineChart chart = (LineChart) itemView.findViewById(R.id.accelerometer_chart);
+
+ if (chart != null) {
+ chart.setViewPortOffsets(0, 0, 0, 0);
+ chart.setHighlightPerDragEnabled(false);
+ chart.setHighlightPerTapEnabled(false);
+ chart.setBackgroundColor(ContextCompat.getColor(context, android.R.color.black));
+ chart.setPinchZoom(false);
+
+ final DateFormat timeFormat = android.text.format.DateFormat.getTimeFormat(context);
+
+ final XAxis xAxis = chart.getXAxis();
+ xAxis.setPosition(XAxis.XAxisPosition.BOTTOM_INSIDE);
+ xAxis.setTextSize(10f);
+ xAxis.setDrawAxisLine(true);
+ xAxis.setDrawGridLines(true);
+ xAxis.setCenterAxisLabels(true);
+ xAxis.setDrawLabels(true);
+ xAxis.setTextColor(ContextCompat.getColor(context, android.R.color.white));
+ xAxis.setGranularityEnabled(true);
+ xAxis.setGranularity(1);
+ xAxis.setAxisMinimum(start);
+ xAxis.setAxisMaximum(now);
+ xAxis.setValueFormatter(new IAxisValueFormatter() {
+ @Override
+ public String getFormattedValue(float value, AxisBase axis) {
+ Date date = new Date((long) value * 5 * 60 * 1000);
+
+ return timeFormat.format(date);
+ }
+ });
+
+ YAxis leftAxis = chart.getAxisLeft();
+ leftAxis.setPosition(YAxis.YAxisLabelPosition.INSIDE_CHART);
+ leftAxis.setDrawGridLines(true);
+ leftAxis.setDrawAxisLine(true);
+ leftAxis.setGranularityEnabled(true);
+ leftAxis.setTextColor(ContextCompat.getColor(context, android.R.color.white));
+
+ YAxis rightAxis = chart.getAxisRight();
+ rightAxis.setEnabled(false);
+
+ chart.getLegend().setEnabled(false);
+ chart.getDescription().setEnabled(false);
+
+ chart.setVisibleYRange((float) Math.floor(finalMinValue) - 1, (float) Math.ceil(finalMaxValue) + 1, YAxis.AxisDependency.LEFT);
+ chart.setData(chartData);
+ }
+
+ Log.e("PDK", "UI END: " + (System.currentTimeMillis() - drawStart));
+
+ Accelerometer.sIsDrawing = false;
+ }
+ });
+ }
+ };
+
+ Thread t = new Thread(r, "render_accelerometer_graph");
+ t.start();
+
+ c.close();
+ } else {
+ cardContent.setVisibility(View.GONE);
+ cardEmpty.setVisibility(View.VISIBLE);
+
+ dateLabel.setText(R.string.label_never_pdk);
+ }
+
+ c.close();
+
+ Log.e("PDK", "MAIN DONE: " + (System.currentTimeMillis() - drawStart));
+ }
+
+ public static View fetchView(ViewGroup parent)
+ {
+ return LayoutInflater.from(parent.getContext()).inflate(R.layout.card_generator_sensors_accelerometer, parent, false);
+ }
+
+ @Override
+ public List fetchPayloads() {
+ return new ArrayList<>();
+ }
+
+ public static long latestPointGenerated(Context context) {
+ Accelerometer me = Accelerometer.getInstance(context);
+
+ if (me.mLatestTimestamp == 0) {
+ Cursor c = me.mDatabase.query(Accelerometer.TABLE_HISTORY, null, null, null, null, null, Accelerometer.HISTORY_OBSERVED + " DESC");
+
+ if (c.moveToNext()) {
+ me.mLatestTimestamp = c.getLong(c.getColumnIndex(Accelerometer.HISTORY_OBSERVED) / (1000 * 1000));
+ }
+
+ c.close();
+ }
+
+ return me.mLatestTimestamp;
+ }
+
+ public Cursor queryHistory(String[] cols, String where, String[] args, String orderBy) {
+ return this.mDatabase.query(Accelerometer.TABLE_HISTORY, cols, where, args, null, null, orderBy);
+ }
+
+ @Override
+ public void onSensorChanged(SensorEvent sensorEvent) {
+ long rawTimestamp = sensorEvent.timestamp;
+
+ if (this.mBaseTimestamp == 0) {
+ this.mBaseTimestamp = (System.currentTimeMillis() * (1000 * 1000)) - rawTimestamp;
+ }
+
+ int accuracy = sensorEvent.accuracy;
+ long normalizedTimestamp = this.mBaseTimestamp + rawTimestamp;
+
+ if (this.mCurrentBufferIndex >= Accelerometer.BUFFER_SIZE) {
+ this.saveBuffer(this.mActiveBuffersIndex, this.mCurrentBufferIndex);
+
+ this.mCurrentBufferIndex = 0;
+ this.mActiveBuffersIndex += 1;
+
+ if (this.mActiveBuffersIndex >= Accelerometer.NUM_BUFFERS) {
+ this.mActiveBuffersIndex = 0;
+ }
+ }
+
+// Log.e("PDK", "ACCEL[" + this.mCurrentBufferIndex + "/" + this.mActiveBuffersIndex + "] = " + sensorEvent.values[0] + " -- " + sensorEvent.values[1] + " -- " + sensorEvent.values[2]);
+
+ this.mXValueBuffers[this.mActiveBuffersIndex][this.mCurrentBufferIndex] = sensorEvent.values[0];
+ this.mYValueBuffers[this.mActiveBuffersIndex][this.mCurrentBufferIndex] = sensorEvent.values[1];
+ this.mZValueBuffers[this.mActiveBuffersIndex][this.mCurrentBufferIndex] = sensorEvent.values[2];
+ this.mAccuracyBuffers[this.mActiveBuffersIndex][this.mCurrentBufferIndex] = accuracy;
+ this.mRawTimestampBuffers[this.mActiveBuffersIndex][this.mCurrentBufferIndex] = rawTimestamp;
+ this.mTimestampBuffers[this.mActiveBuffersIndex][this.mCurrentBufferIndex] = normalizedTimestamp;
+
+ this.mCurrentBufferIndex += 1;
+ }
+
+ private void saveBuffer(final int bufferIndex, final int bufferSize) {
+ final Accelerometer me = this;
+
+ me.mLatestTimestamp = System.currentTimeMillis();
+
+ Runnable r = new Runnable() {
+ @Override
+ public void run() {
+ long now = System.currentTimeMillis();
+
+ try {
+ me.mDatabase.beginTransaction();
+
+ for (int i = 0; i < bufferSize; i++) {
+ ContentValues values = new ContentValues();
+
+ values.put(Accelerometer.HISTORY_X, me.mXValueBuffers[bufferIndex][i]);
+ values.put(Accelerometer.HISTORY_Y, me.mYValueBuffers[bufferIndex][i]);
+ values.put(Accelerometer.HISTORY_Z, me.mZValueBuffers[bufferIndex][i]);
+ values.put(Accelerometer.HISTORY_OBSERVED, me.mTimestampBuffers[bufferIndex][i]);
+ values.put(Accelerometer.HISTORY_RAW_TIMESTAMP, me.mRawTimestampBuffers[bufferIndex][i]);
+ values.put(Accelerometer.HISTORY_ACCURACY, me.mAccuracyBuffers[bufferIndex][i]);
+
+ me.mDatabase.insert(Accelerometer.TABLE_HISTORY, null, values);
+ }
+
+ me.mDatabase.setTransactionSuccessful();
+ } finally {
+ me.mDatabase.endTransaction();
+ }
+
+ Bundle update = new Bundle();
+ update.putLong(Accelerometer.HISTORY_OBSERVED, now);
+
+ Bundle sensorReadings = new Bundle();
+
+ sensorReadings.putFloatArray(Accelerometer.HISTORY_X, me.mXValueBuffers[bufferIndex]);
+ sensorReadings.putFloatArray(Accelerometer.HISTORY_Y, me.mYValueBuffers[bufferIndex]);
+ sensorReadings.putFloatArray(Accelerometer.HISTORY_Z, me.mZValueBuffers[bufferIndex]);
+ sensorReadings.putLongArray(Accelerometer.HISTORY_RAW_TIMESTAMP, me.mRawTimestampBuffers[bufferIndex]);
+ sensorReadings.putLongArray(Accelerometer.HISTORY_OBSERVED, me.mTimestampBuffers[bufferIndex]);
+ sensorReadings.putIntArray(Accelerometer.HISTORY_ACCURACY, me.mAccuracyBuffers[bufferIndex]);
+
+ update.putBundle(SensorGenerator.SENSOR_DATA, sensorReadings);
+ SensorGenerator.addSensorMetadata(update, me.mSensor);
+
+ Generators.getInstance(me.mContext).notifyGeneratorUpdated(Accelerometer.GENERATOR_IDENTIFIER, update);
+
+ if (now - me.mLastCleanup > me.mCleanupInterval) {
+ me.mLastCleanup = now;
+
+ long start = (now - (2 * 24 * 60 * 60 * 1000)) * 1000 * 1000;
+
+ String where = Accelerometer.HISTORY_OBSERVED + " < ?";
+ String[] args = { "" + start };
+
+ me.mDatabase.delete(Accelerometer.TABLE_HISTORY, where, args);
+ }
+ }
+ };
+
+ Thread t = new Thread(r, "accelerometer-save-buffer");
+ t.start();
+ }
+
+ @Override
+ public void onAccuracyChanged(Sensor sensor, int newAccuracy) {
+ // Do nothing...
+ }
}
diff --git a/src/com/audacious_software/passive_data_kit/generators/sensors/AmbientLight.java b/src/com/audacious_software/passive_data_kit/generators/sensors/AmbientLight.java
index 4dbedf8..cba3bc2 100755
--- a/src/com/audacious_software/passive_data_kit/generators/sensors/AmbientLight.java
+++ b/src/com/audacious_software/passive_data_kit/generators/sensors/AmbientLight.java
@@ -1,5 +1,6 @@
package com.audacious_software.passive_data_kit.generators.sensors;
+import android.content.ContentValues;
import android.content.Context;
import android.content.SharedPreferences;
import android.database.Cursor;
@@ -13,7 +14,6 @@
import android.os.Handler;
import android.os.Looper;
import android.support.v4.content.ContextCompat;
-import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -24,7 +24,6 @@
import com.audacious_software.passive_data_kit.diagnostics.DiagnosticAction;
import com.audacious_software.passive_data_kit.generators.Generator;
import com.audacious_software.passive_data_kit.generators.Generators;
-import com.audacious_software.passive_data_kit.generators.device.Battery;
import com.audacious_software.pdk.passivedatakit.R;
import com.github.mikephil.charting.charts.LineChart;
import com.github.mikephil.charting.components.AxisBase;
@@ -45,19 +44,21 @@
* Created by cjkarr on 4/17/2017.
*/
-public class AmbientLight extends Generator implements SensorEventListener {
+public class AmbientLight extends SensorGenerator implements SensorEventListener {
private static final String GENERATOR_IDENTIFIER = "pdk-sensor-light";
private static final String ENABLED = "com.audacious_software.passive_data_kit.generators.device.AmbientLight.ENABLED";
private static final boolean ENABLED_DEFAULT = true;
- private static final String DATABASE_PATH = "pdk-sensor-light.sqlite";
+ private static final String DATABASE_PATH = "pdk-sensor-ambient-light.sqlite";
private static final int DATABASE_VERSION = 1;
public static final String TABLE_HISTORY = "history";
public static final String HISTORY_OBSERVED = "observed";
public static final String HISTORY_LEVEL = "light_level";
+ private static final String HISTORY_RAW_TIMESTAMP = "raw_timestamp";
+ private static final String HISTORY_ACCURACY = "accuracy";
private static AmbientLight sInstance = null;
private static Handler sHandler = null;
@@ -66,6 +67,23 @@ public class AmbientLight extends Generator implements SensorEventListener {
private Sensor mSensor = null;
+ private static int NUM_BUFFERS = 3;
+ private static int BUFFER_SIZE = 32;
+
+ private long mLastCleanup = 0;
+ private long mCleanupInterval = 15 * 60 * 1000;
+
+ private int mActiveBuffersIndex = 0;
+ private int mCurrentBufferIndex = 0;
+
+ private float[][] mValueBuffers = null;
+ private int[][] mAccuracyBuffers = null;
+ private long[][] mRawTimestampBuffers = null;
+ private long[][] mTimestampBuffers = null;
+
+ long mBaseTimestamp = 0;
+ private long mLatestTimestamp = 0;
+
public static AmbientLight getInstance(Context context) {
if (AmbientLight.sInstance == null) {
AmbientLight.sInstance = new AmbientLight(context.getApplicationContext());
@@ -87,6 +105,23 @@ private void startGenerator() {
final AmbientLight me = this;
+ Generators.getInstance(this.mContext).registerCustomViewClass(AmbientLight.GENERATOR_IDENTIFIER, AmbientLight.class);
+
+ File path = PassiveDataKit.getGeneratorsStorage(this.mContext);
+
+ path = new File(path, AmbientLight.DATABASE_PATH);
+
+ this.mDatabase = SQLiteDatabase.openOrCreateDatabase(path, null);
+
+ int version = this.getDatabaseVersion(this.mDatabase);
+
+ switch (version) {
+ case 0:
+ this.mDatabase.execSQL(this.mContext.getString(R.string.pdk_generator_ambient_light_create_history_table));
+ }
+
+ this.setDatabaseVersion(this.mDatabase, AmbientLight.DATABASE_VERSION);
+
if (AmbientLight.isEnabled(this.mContext)) {
this.mSensor = sensors.getDefaultSensor(Sensor.TYPE_LIGHT);
@@ -96,12 +131,20 @@ public void run()
{
Looper.prepare();
+ me.mValueBuffers = new float[AmbientLight.NUM_BUFFERS][AmbientLight.BUFFER_SIZE];
+ me.mAccuracyBuffers = new int[AmbientLight.NUM_BUFFERS][AmbientLight.BUFFER_SIZE];
+ me.mRawTimestampBuffers = new long[AmbientLight.NUM_BUFFERS][AmbientLight.BUFFER_SIZE];
+ me.mTimestampBuffers = new long[AmbientLight.NUM_BUFFERS][AmbientLight.BUFFER_SIZE];
+
+ me.mActiveBuffersIndex = 0;
+ me.mCurrentBufferIndex = 0;
+
AmbientLight.sHandler = new Handler();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
- sensors.registerListener(me, me.mSensor, SensorManager.SENSOR_DELAY_NORMAL, 0, AmbientLight.sHandler);
+ sensors.registerListener(me, me.mSensor, SensorManager.SENSOR_DELAY_FASTEST, 0, AmbientLight.sHandler);
else
- sensors.registerListener(me, me.mSensor, SensorManager.SENSOR_DELAY_NORMAL, AmbientLight.sHandler);
+ sensors.registerListener(me, me.mSensor, SensorManager.SENSOR_DELAY_FASTEST, AmbientLight.sHandler);
Looper.loop();
}
@@ -111,6 +154,8 @@ public void run()
t.start();
} else {
if (this.mSensor != null) {
+ sensors.unregisterListener(this, this.mSensor);
+
if (AmbientLight.sHandler != null) {
Looper loop = AmbientLight.sHandler.getLooper();
loop.quit();
@@ -118,30 +163,17 @@ public void run()
AmbientLight.sHandler = null;
}
- sensors.unregisterListener(this, this.mSensor);
+ me.mValueBuffers = null;
+ me.mAccuracyBuffers = null;
+ me.mRawTimestampBuffers = null;
+ me.mTimestampBuffers = null;
+
+ me.mActiveBuffersIndex = 0;
+ me.mCurrentBufferIndex = 0;
this.mSensor = null;
}
}
-
-
- Generators.getInstance(this.mContext).registerCustomViewClass(AmbientLight.GENERATOR_IDENTIFIER, Battery.class);
-
- File path = PassiveDataKit.getGeneratorsStorage(this.mContext);
-
- path = new File(path, AmbientLight.DATABASE_PATH);
-
- this.mDatabase = SQLiteDatabase.openOrCreateDatabase(path, null);
-
- int version = this.getDatabaseVersion(this.mDatabase);
-
- switch (version) {
- case 0:
-//
-// this.mDatabase.execSQL(this.mContext.getString(R.string.pdk_generator_device_ambient_light_create_history_table));
- }
-
- this.setDatabaseVersion(this.mDatabase, AmbientLight.DATABASE_VERSION);
}
public static boolean isEnabled(Context context) {
@@ -167,8 +199,8 @@ public static void bindViewHolder(DataPointViewHolder holder) {
AmbientLight generator = AmbientLight.getInstance(context);
- long now = System.currentTimeMillis();
- long start = now - (24 * 60 * 60 * 1000);
+ long now = System.currentTimeMillis() / (1000 * 60 * 5);
+ long start = now - (24 * 12); // * 60);
String where = AmbientLight.HISTORY_OBSERVED + " >= ?";
String[] args = { "" + start };
@@ -183,13 +215,13 @@ public static void bindViewHolder(DataPointViewHolder holder) {
cardContent.setVisibility(View.VISIBLE);
cardEmpty.setVisibility(View.GONE);
- long timestamp = c.getLong(c.getColumnIndex(AmbientLight.HISTORY_OBSERVED)) / 1000;
+ long timestamp = c.getLong(c.getColumnIndex(AmbientLight.HISTORY_OBSERVED)) / (1000 * 1000 * 1000);
dateLabel.setText(Generator.formatTimestamp(context, timestamp));
c.moveToPrevious();
- final LineChart chart = (LineChart) holder.itemView.findViewById(R.id.battery_level_chart);
+ final LineChart chart = (LineChart) holder.itemView.findViewById(R.id.light_chart);
chart.setViewPortOffsets(0,0,0,0);
chart.setHighlightPerDragEnabled(false);
chart.setHighlightPerTapEnabled(false);
@@ -213,7 +245,7 @@ public static void bindViewHolder(DataPointViewHolder holder) {
xAxis.setValueFormatter(new IAxisValueFormatter() {
@Override
public String getFormattedValue(float value, AxisBase axis) {
- Date date = new Date((long) value);
+ Date date = new Date((long) value * 5 * 60 * 1000);
return timeFormat.format(date);
}
@@ -224,8 +256,6 @@ public String getFormattedValue(float value, AxisBase axis) {
leftAxis.setDrawGridLines(true);
leftAxis.setDrawAxisLine(true);
leftAxis.setGranularityEnabled(true);
- leftAxis.setAxisMaximum(110);
- leftAxis.setAxisMinimum(-10);
leftAxis.setTextColor(ContextCompat.getColor(context, android.R.color.white));
YAxis rightAxis = chart.getAxisRight();
@@ -234,38 +264,88 @@ public String getFormattedValue(float value, AxisBase axis) {
chart.getLegend().setEnabled(false);
chart.getDescription().setEnabled(false);
- ArrayList values = new ArrayList<>();
+ ArrayList lowValues = new ArrayList<>();
+ ArrayList highValues = new ArrayList<>();
- long lastLevel = -1;
+ long lastTimestamp = -1;
+
+ float maxValue = 0;
+ float minValue = 0;
+
+ float lowLevel = -1;
+ float highLevel = -1;
while (c.moveToNext()) {
long when = c.getLong(c.getColumnIndex(AmbientLight.HISTORY_OBSERVED));
- long level = c.getLong(c.getColumnIndex(AmbientLight.HISTORY_LEVEL));
- if (level != lastLevel) {
- values.add(0, new Entry(when, level));
- lastLevel = level;
+ when = when / (1000 * 1000);
+ when = when / (1000 * 6 * 50);
+
+ float level = c.getFloat(c.getColumnIndex(AmbientLight.HISTORY_LEVEL));
+
+ if (lastTimestamp != when) {
+ if (lastTimestamp != -1) {
+ lowValues.add(0, new Entry(lastTimestamp, lowLevel));
+ highValues.add(0, new Entry(lastTimestamp, highLevel));
+ }
+
+ lastTimestamp = when;
+ lowLevel = level;
+ highLevel = level;
+ } else {
+ if (level < lowLevel) {
+ lowLevel = level;
+ }
+
+ if (level > highLevel) {
+ highLevel = level;
+ }
+ }
+
+ if (level > maxValue) {
+ maxValue = level;
+ }
- Log.e("SLEEP-SIGHT", "VALUE: " + level + " -- " + (when - start));
+ if (level < minValue) {
+ minValue = level;
}
}
- Log.e("SLEEP-SIGHT", "LIGHT VALUES COUNT 2: " + values.size());
+ if (lastTimestamp != -1) {
+ lowValues.add(0, new Entry(lastTimestamp, lowLevel));
+ highValues.add(0, new Entry(lastTimestamp, highLevel));
+ }
- LineDataSet set = new LineDataSet(values, "Light Level");
+ LineDataSet set = new LineDataSet(lowValues, "Low Light Levels");
set.setAxisDependency(YAxis.AxisDependency.LEFT);
- set.setLineWidth(2.0f);
+ set.setLineWidth(1.0f);
set.setDrawCircles(false);
set.setFillAlpha(192);
set.setDrawFilled(false);
set.setDrawValues(true);
- set.setColor(ContextCompat.getColor(context, R.color.generator_battery_plot));
+ set.setColor(ContextCompat.getColor(context, R.color.generator_ambient_light_low));
set.setDrawCircleHole(false);
set.setDrawValues(false);
set.setMode(LineDataSet.Mode.LINEAR);
- chart.setVisibleYRange(0, 120, YAxis.AxisDependency.LEFT);
- chart.setData(new LineData(set));
+ LineData chartData = new LineData(set);
+
+ set = new LineDataSet(highValues, "High Light Levels");
+ set.setAxisDependency(YAxis.AxisDependency.LEFT);
+ set.setLineWidth(1.0f);
+ set.setDrawCircles(false);
+ set.setFillAlpha(192);
+ set.setDrawFilled(false);
+ set.setDrawValues(true);
+ set.setColor(ContextCompat.getColor(context, R.color.generator_ambient_light_high));
+ set.setDrawCircleHole(false);
+ set.setDrawValues(false);
+ set.setMode(LineDataSet.Mode.LINEAR);
+
+ chartData.addDataSet(set);
+
+ chart.setVisibleYRange((float) Math.floor(minValue) - 1, (float) Math.ceil(maxValue) + 1, YAxis.AxisDependency.LEFT);
+ chart.setData(chartData);
} else {
cardContent.setVisibility(View.GONE);
cardEmpty.setVisibility(View.VISIBLE);
@@ -278,7 +358,7 @@ public String getFormattedValue(float value, AxisBase axis) {
public static View fetchView(ViewGroup parent)
{
- return LayoutInflater.from(parent.getContext()).inflate(R.layout.card_generator_device_battery, parent, false);
+ return LayoutInflater.from(parent.getContext()).inflate(R.layout.card_generator_sensors_ambient_light, parent, false);
}
@Override
@@ -287,19 +367,19 @@ public List fetchPayloads() {
}
public static long latestPointGenerated(Context context) {
- long timestamp = 0;
-
AmbientLight me = AmbientLight.getInstance(context);
- Cursor c = me.mDatabase.query(AmbientLight.TABLE_HISTORY, null, null, null, null, null, AmbientLight.HISTORY_OBSERVED + " DESC");
+ if (me.mLatestTimestamp == 0) {
+ Cursor c = me.mDatabase.query(AmbientLight.TABLE_HISTORY, null, null, null, null, null, Accelerometer.HISTORY_OBSERVED + " DESC");
- if (c.moveToNext()) {
- timestamp = c.getLong(c.getColumnIndex(AmbientLight.HISTORY_OBSERVED));
- }
+ if (c.moveToNext()) {
+ me.mLatestTimestamp = c.getLong(c.getColumnIndex(Accelerometer.HISTORY_OBSERVED) / (1000 * 1000));
+ }
- c.close();
+ c.close();
+ }
- return timestamp;
+ return me.mLatestTimestamp;
}
public Cursor queryHistory(String[] cols, String where, String[] args, String orderBy) {
@@ -308,11 +388,98 @@ public Cursor queryHistory(String[] cols, String where, String[] args, String or
@Override
public void onSensorChanged(SensorEvent sensorEvent) {
+ long rawTimestamp = sensorEvent.timestamp;
+
+ if (this.mBaseTimestamp == 0) {
+ this.mBaseTimestamp = (System.currentTimeMillis() * (1000 * 1000)) - rawTimestamp;
+ }
+
+ int accuracy = sensorEvent.accuracy;
+ long normalizedTimestamp = this.mBaseTimestamp + rawTimestamp;
+ float value = sensorEvent.values[0];
+
+ if (this.mCurrentBufferIndex >= AmbientLight.BUFFER_SIZE) {
+ this.saveBuffer(this.mActiveBuffersIndex, this.mCurrentBufferIndex);
+
+ this.mCurrentBufferIndex = 0;
+ this.mActiveBuffersIndex += 1;
+
+ if (this.mActiveBuffersIndex >= AmbientLight.NUM_BUFFERS) {
+ this.mActiveBuffersIndex = 0;
+ }
+ }
+ this.mValueBuffers[this.mActiveBuffersIndex][this.mCurrentBufferIndex] = value;
+ this.mAccuracyBuffers[this.mActiveBuffersIndex][this.mCurrentBufferIndex] = accuracy;
+ this.mRawTimestampBuffers[this.mActiveBuffersIndex][this.mCurrentBufferIndex] = rawTimestamp;
+ this.mTimestampBuffers[this.mActiveBuffersIndex][this.mCurrentBufferIndex] = normalizedTimestamp;
+
+ this.mCurrentBufferIndex += 1;
+ }
+
+ private void saveBuffer(final int bufferIndex, final int bufferSize) {
+ final AmbientLight me = this;
+
+ me.mLatestTimestamp = System.currentTimeMillis();
+
+ Runnable r = new Runnable() {
+ @Override
+ public void run() {
+ long now = System.currentTimeMillis();
+
+ try {
+ me.mDatabase.beginTransaction();
+
+ for (int i = 0; i < bufferSize; i++) {
+ ContentValues values = new ContentValues();
+
+ values.put(AmbientLight.HISTORY_LEVEL, me.mValueBuffers[bufferIndex][i]);
+ values.put(AmbientLight.HISTORY_OBSERVED, me.mTimestampBuffers[bufferIndex][i]);
+ values.put(AmbientLight.HISTORY_RAW_TIMESTAMP, me.mRawTimestampBuffers[bufferIndex][i]);
+ values.put(AmbientLight.HISTORY_ACCURACY, me.mAccuracyBuffers[bufferIndex][i]);
+
+ me.mDatabase.insert(AmbientLight.TABLE_HISTORY, null, values);
+ }
+
+ me.mDatabase.setTransactionSuccessful();
+ } finally {
+ me.mDatabase.endTransaction();
+ }
+
+ Bundle update = new Bundle();
+ update.putLong(AmbientLight.HISTORY_OBSERVED, now);
+
+ Bundle sensorReadings = new Bundle();
+
+ sensorReadings.putFloatArray(AmbientLight.HISTORY_LEVEL, me.mValueBuffers[bufferIndex]);
+ sensorReadings.putLongArray(AmbientLight.HISTORY_RAW_TIMESTAMP, me.mRawTimestampBuffers[bufferIndex]);
+ sensorReadings.putLongArray(AmbientLight.HISTORY_OBSERVED, me.mTimestampBuffers[bufferIndex]);
+ sensorReadings.putIntArray(AmbientLight.HISTORY_ACCURACY, me.mAccuracyBuffers[bufferIndex]);
+
+ update.putBundle(SensorGenerator.SENSOR_DATA, sensorReadings);
+ SensorGenerator.addSensorMetadata(update, me.mSensor);
+
+ Generators.getInstance(me.mContext).notifyGeneratorUpdated(AmbientLight.GENERATOR_IDENTIFIER, update);
+
+ if (now - me.mLastCleanup > me.mCleanupInterval) {
+ me.mLastCleanup = now;
+
+ long start = (now - (2 * 24 * 60 * 60 * 1000)) * 1000 * 1000;
+
+ String where = AmbientLight.HISTORY_OBSERVED + " < ?";
+ String[] args = { "" + start };
+
+ me.mDatabase.delete(AmbientLight.TABLE_HISTORY, where, args);
+ }
+ }
+ };
+
+ Thread t = new Thread(r, "ambient-light-save-buffer");
+ t.start();
}
@Override
public void onAccuracyChanged(Sensor sensor, int newAccuracy) {
-
+ // Do nothing...
}
}
diff --git a/src/com/audacious_software/passive_data_kit/generators/sensors/SensorGenerator.java b/src/com/audacious_software/passive_data_kit/generators/sensors/SensorGenerator.java
new file mode 100755
index 0000000..947858b
--- /dev/null
+++ b/src/com/audacious_software/passive_data_kit/generators/sensors/SensorGenerator.java
@@ -0,0 +1,74 @@
+package com.audacious_software.passive_data_kit.generators.sensors;
+
+import android.content.Context;
+import android.hardware.Sensor;
+import android.os.Build;
+import android.os.Bundle;
+
+import com.audacious_software.passive_data_kit.generators.Generator;
+
+/**
+ * Created by cjkarr on 5/11/2017.
+ */
+
+public abstract class SensorGenerator extends Generator {
+ public static final String SENSOR_DATA = "sensor_data";
+
+ private static final String SENSOR_REPORTING_MODE = "reporting_mode";
+ private static final String SENSOR_NAME = "name";
+ private static final String SENSOR_VENDOR = "vendor";
+ private static final String SENSOR_MAX_RANGE = "max_range";
+ private static final String SENSOR_POWER_USAGE = "power_usage";
+ private static final String SENSOR_RESOLUTION = "resolution";
+ private static final String SENSOR_MIN_DELAY = "min_delay";
+ private static final String SENSOR_VERSION = "version";
+ private static final String SENSOR_TYPE = "type";
+ private static final String SENSOR_MAX_DELAY = "max_delay";
+ private static final String SENSOR_IS_WAKEUP = "is_wakeup";
+
+ private static final String SENSOR_REPORTING_MODE_CONTINUOUS = "continuous";
+ private static final String SENSOR_REPORTING_MODE_ON_CHANGE = "on_change";
+ private static final String SENSOR_REPORTING_MODE_ONE_SHOT = "one_shot";
+ private static final String SENSOR_REPORTING_MODE_SPECIAL_TRIGGER = "special_trigger";
+
+ public SensorGenerator(Context context) {
+ super(context);
+ }
+
+ public static void addSensorMetadata(Bundle update, Sensor sensor) {
+ update.putString(SensorGenerator.SENSOR_NAME, sensor.getName());
+ update.putString(SensorGenerator.SENSOR_VENDOR, sensor.getVendor());
+
+ update.putFloat(SensorGenerator.SENSOR_MAX_RANGE, sensor.getMaximumRange());
+ update.putFloat(SensorGenerator.SENSOR_POWER_USAGE, sensor.getPower());
+ update.putFloat(SensorGenerator.SENSOR_RESOLUTION, sensor.getResolution());
+
+ update.putInt(SensorGenerator.SENSOR_MIN_DELAY, sensor.getMinDelay());
+ update.putInt(SensorGenerator.SENSOR_VERSION, sensor.getVersion());
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) {
+ update.putString(SensorGenerator.SENSOR_TYPE, sensor.getStringType());
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ update.putInt(SensorGenerator.SENSOR_MAX_DELAY, sensor.getMaxDelay());
+
+ switch(sensor.getReportingMode()) {
+ case Sensor.REPORTING_MODE_CONTINUOUS:
+ update.putString(SensorGenerator.SENSOR_REPORTING_MODE, SensorGenerator.SENSOR_REPORTING_MODE_CONTINUOUS);
+ break;
+ case Sensor.REPORTING_MODE_ON_CHANGE:
+ update.putString(SensorGenerator.SENSOR_REPORTING_MODE, SensorGenerator.SENSOR_REPORTING_MODE_ON_CHANGE);
+ break;
+ case Sensor.REPORTING_MODE_ONE_SHOT:
+ update.putString(SensorGenerator.SENSOR_REPORTING_MODE, SensorGenerator.SENSOR_REPORTING_MODE_ONE_SHOT);
+ break;
+ case Sensor.REPORTING_MODE_SPECIAL_TRIGGER:
+ update.putString(SensorGenerator.SENSOR_REPORTING_MODE, SensorGenerator.SENSOR_REPORTING_MODE_SPECIAL_TRIGGER);
+ break;
+ }
+
+ update.putBoolean(SensorGenerator.SENSOR_IS_WAKEUP, sensor.isWakeUpSensor());
+ }
+ }
+ }
+}