diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 3b7277a..5dd65d6 100755
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -4,6 +4,7 @@
+
diff --git a/build.gradle b/build.gradle
index de82287..e6359b3 100755
--- a/build.gradle
+++ b/build.gradle
@@ -53,6 +53,7 @@ android {
compile 'com.google.android.gms:play-services-nearby:10.0.1'
compile 'com.google.android.gms:play-services-places:10.0.1'
compile 'com.google.android.gms:play-services-awareness:10.0.1'
+ compile 'com.google.maps.android:android-maps-utils:0.4'
compile 'com.squareup.okhttp3:okhttp:3.2.0'
compile 'commons-io:commons-io:2.4'
compile 'commons-codec:commons-codec:1.10'
diff --git a/res/drawable-hdpi/ic_text_messages.png b/res/drawable-hdpi/ic_text_messages.png
new file mode 100755
index 0000000..ef5d391
Binary files /dev/null and b/res/drawable-hdpi/ic_text_messages.png differ
diff --git a/res/drawable-mdpi/ic_text_messages.png b/res/drawable-mdpi/ic_text_messages.png
new file mode 100755
index 0000000..cdabac0
Binary files /dev/null and b/res/drawable-mdpi/ic_text_messages.png differ
diff --git a/res/drawable-xhdpi/ic_text_messages.png b/res/drawable-xhdpi/ic_text_messages.png
new file mode 100755
index 0000000..a0a8ceb
Binary files /dev/null and b/res/drawable-xhdpi/ic_text_messages.png differ
diff --git a/res/drawable-xxhdpi/ic_text_messages.png b/res/drawable-xxhdpi/ic_text_messages.png
new file mode 100755
index 0000000..31ceb29
Binary files /dev/null and b/res/drawable-xxhdpi/ic_text_messages.png differ
diff --git a/res/drawable-xxxhdpi/ic_text_messages.png b/res/drawable-xxxhdpi/ic_text_messages.png
new file mode 100755
index 0000000..352d5d5
Binary files /dev/null and b/res/drawable-xxxhdpi/ic_text_messages.png differ
diff --git a/res/drawable/ic_location_heatmap_marker.xml b/res/drawable/ic_location_heatmap_marker.xml
new file mode 100755
index 0000000..1df13e4
--- /dev/null
+++ b/res/drawable/ic_location_heatmap_marker.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
diff --git a/res/layout/card_generator_location_google.xml b/res/layout/card_generator_location_google.xml
index 716536d..979c932 100755
--- a/res/layout/card_generator_location_google.xml
+++ b/res/layout/card_generator_location_google.xml
@@ -2,6 +2,7 @@
@@ -42,24 +43,29 @@
android:textColor="@android:color/white"
android:layout_marginRight="8dp"/>
-
+ android:layout_height="200dp">
-
+
-
+ android:layout_gravity="bottom|right"
+ android:layout_marginRight="6dp"
+ android:layout_marginBottom="104dp" />
+
\ No newline at end of file
diff --git a/res/layout/card_generator_phone_calls.xml b/res/layout/card_generator_phone_calls.xml
index f66de04..2a2725b 100755
--- a/res/layout/card_generator_phone_calls.xml
+++ b/res/layout/card_generator_phone_calls.xml
@@ -41,7 +41,8 @@
android:textColor="@android:color/white"
android:layout_marginRight="8dp"/>
-
@@ -150,6 +151,12 @@
android:layout_marginBottom="8dp"/>
+
\ No newline at end of file
diff --git a/res/layout/card_generator_screen_state.xml b/res/layout/card_generator_screen_state.xml
index f09f805..7af3c2d 100755
--- a/res/layout/card_generator_screen_state.xml
+++ b/res/layout/card_generator_screen_state.xml
@@ -41,7 +41,8 @@
android:textColor="@android:color/white"
android:layout_marginRight="8dp"/>
-
@@ -138,6 +139,12 @@
+
\ No newline at end of file
diff --git a/res/layout/card_generator_text_messages.xml b/res/layout/card_generator_text_messages.xml
new file mode 100755
index 0000000..03c022d
--- /dev/null
+++ b/res/layout/card_generator_text_messages.xml
@@ -0,0 +1,134 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/res/values/databases.xml b/res/values/databases.xml
new file mode 100755
index 0000000..a6d7f01
--- /dev/null
+++ b/res/values/databases.xml
@@ -0,0 +1,15 @@
+
+ CREATE TABLE metadata(key TEXT, value TEXT, last_updated INTEGER);
+
+
+ CREATE TABLE history(_id INTEGER PRIMARY KEY AUTOINCREMENT, fetched INTEGER, transmitted INTEGER, observed INTEGER, latitude REAL, longitude REAL, altitude REAL, bearing REAL, speed REAL, provider TEXT, location_timestamp INTEGER, accuracy REAL);
+
+
+ CREATE TABLE history(_id INTEGER PRIMARY KEY AUTOINCREMENT, fetched INTEGER, transmitted INTEGER, observed INTEGER, state TEXT);
+
+
+ CREATE TABLE history(_id INTEGER PRIMARY KEY AUTOINCREMENT, fetched INTEGER, transmitted INTEGER, observed INTEGER, duration INTEGER, call_type TEXT, number TEXT, post_dial_digits TEXT, via_number TEXT, is_new INTEGER, pulled_externally INTEGER, country_iso TEXT, data_usage INTEGER, geocoded_location TEXT, is_video INTEGER, presentation TEXT, is_read INTEGER);
+
+
+ CREATE TABLE history(_id INTEGER PRIMARY KEY AUTOINCREMENT, fetched INTEGER, transmitted INTEGER, observed INTEGER, direction TEXT, length INTEGER, body TEXT, number_name TEXT, number TEXT);
+
\ No newline at end of file
diff --git a/res/values/generators.xml b/res/values/generators.xml
index c4d60a2..b5e805f 100755
--- a/res/values/generators.xml
+++ b/res/values/generators.xml
@@ -3,6 +3,7 @@
- com.audacious_software.passive_data_kit.generators.device.Location
- com.audacious_software.passive_data_kit.generators.device.ScreenState
- com.audacious_software.passive_data_kit.generators.communication.PhoneCalls
+ - com.audacious_software.passive_data_kit.generators.communication.TextMessages
- com.audacious_software.passive_data_kit.generators.wearables.MicrosoftBand
- com.audacious_software.passive_data_kit.generators.services.GoogleAwareness
@@ -45,6 +46,30 @@
Screen State
+ On
+ Off
+ Doze
+ Unknown
+ Legend:
+ No screen state changes have been observed yet.
+
+
+ SMS Text Messages
+ Incoming
+ Outgoing
+ Other
+
+ #3F51B5
+ #4CAF50
+ #9E9E9E
+
+ Latest Text Message
+ Length
+ Direction
+ %1$d chars.
+
+ No text messages have been sent or received on this device.
+ Please all the app permission to access your text messages to gather and report your messaging activity statistics.
Phone Calls
@@ -63,4 +88,6 @@
Direction
%1$.2f min.
+ No phone calls have been made or received on this device.
+
\ No newline at end of file
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 61e918e..6474efa 100755
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -14,10 +14,6 @@
Today
- On
- Off
- Doze
- Unknown
- Legend:
+ Never
diff --git a/src/com/audacious_software/passive_data_kit/PassiveDataKit.java b/src/com/audacious_software/passive_data_kit/PassiveDataKit.java
index 8a8efc1..285f97e 100755
--- a/src/com/audacious_software/passive_data_kit/PassiveDataKit.java
+++ b/src/com/audacious_software/passive_data_kit/PassiveDataKit.java
@@ -5,9 +5,13 @@
import com.audacious_software.passive_data_kit.diagnostics.DiagnosticAction;
import com.audacious_software.passive_data_kit.generators.Generators;
+import java.io.File;
import java.util.ArrayList;
public class PassiveDataKit {
+ private static final String STORAGE_PATH = "passive-data-kit";
+ private static final String GENERATORS_PATH = "generators";
+
private Context mContext = null;
private boolean mStarted = false;
@@ -30,6 +34,17 @@ public static ArrayList diagnostics(Context context)
return actions;
}
+ public static File getGeneratorsStorage(Context context) {
+ File path = new File(context.getFilesDir(), PassiveDataKit.STORAGE_PATH);
+ path = new File(path, PassiveDataKit.GENERATORS_PATH);
+
+ if (path.exists() == false) {
+ path.mkdirs();
+ }
+
+ return path;
+ }
+
private static class PassiveDataKitHolder {
public static PassiveDataKit instance = new PassiveDataKit();
}
diff --git a/src/com/audacious_software/passive_data_kit/PhoneUtililties.java b/src/com/audacious_software/passive_data_kit/PhoneUtililties.java
new file mode 100755
index 0000000..0213eb1
--- /dev/null
+++ b/src/com/audacious_software/passive_data_kit/PhoneUtililties.java
@@ -0,0 +1,30 @@
+package com.audacious_software.passive_data_kit;
+
+import android.content.Context;
+
+/**
+ * Created by cjkarr on 12/13/2016.
+ */
+
+public class PhoneUtililties {
+ public static String normalizedPhoneNumber(String phoneNumber)
+ {
+ if (phoneNumber == null) {
+ return null;
+ }
+
+ phoneNumber = phoneNumber.replaceAll("[^\\d.]", "");
+
+ while (phoneNumber.length() > 10) {
+ phoneNumber = phoneNumber.substring(1);
+ }
+
+ while (phoneNumber.length() < 10) {
+ phoneNumber += "0";
+ }
+
+
+ return phoneNumber;
+ }
+}
+
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 184173a..a4a1300 100755
--- a/src/com/audacious_software/passive_data_kit/activities/DataStreamActivity.java
+++ b/src/com/audacious_software/passive_data_kit/activities/DataStreamActivity.java
@@ -20,7 +20,7 @@
import java.util.ArrayList;
-public class DataStreamActivity extends AppCompatActivity implements Generators.NewDataPointListener {
+public class DataStreamActivity extends AppCompatActivity implements Generators.GeneratorUpdatedListener {
private DataPointsAdapter mAdapter = null;
protected void onCreate(Bundle savedInstanceState) {
@@ -30,6 +30,7 @@ protected void onCreate(Bundle savedInstanceState) {
this.getSupportActionBar().setSubtitle(this.getResources().getQuantityString(R.plurals.activity_data_stream_subtitle, 0, 0));
this.mAdapter = new DataPointsAdapter();
+ this.mAdapter.setContext(this.getApplicationContext());
RecyclerView listView = (RecyclerView) this.findViewById(R.id.list_view);
@@ -41,20 +42,33 @@ protected void onCreate(Bundle savedInstanceState) {
protected void onResume() {
super.onResume();
- Generators.getInstance(this).addNewDataPointListener(this);
+ Generators.getInstance(this).addNewGeneratorUpdatedListener(this);
- Generators.getInstance(this).broadcastLatestDataPoints();
+ final int count = this.mAdapter.getItemCount();
+
+ Handler mainHandler = new Handler(Looper.getMainLooper());
+
+ final DataStreamActivity me = this;
+
+ mainHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ me.getSupportActionBar().setSubtitle(me.getResources().getQuantityString(R.plurals.activity_data_stream_subtitle, count, count));
+ }
+ });
}
protected void onPause() {
super.onPause();
- Generators.getInstance(this).removeNewDataPointListener(this);
+ Generators.getInstance(this).removeGeneratorUpdatedListener(this);
}
@Override
- public void onNewDataPoint(String identifier, Bundle data) {
- this.mAdapter.updateDataPoint(identifier, data);
+ public void onGeneratorUpdated(String identifier, Bundle data) {
+ Log.e("PDK", "GOT GENERATOR UPDATE: " + identifier + " -- " + data);
+
+ this.mAdapter.notifyDataSetChanged();
final int count = this.mAdapter.getItemCount();
@@ -68,5 +82,9 @@ public void run() {
me.getSupportActionBar().setSubtitle(me.getResources().getQuantityString(R.plurals.activity_data_stream_subtitle, count, count));
}
});
+
+// RecyclerView listView = (RecyclerView) this.findViewById(R.id.list_view);
+// listView.setAdapter(this.mAdapter);
+// listView.invalidate();
}
}
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 b711460..fd1679d 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,9 +1,6 @@
package com.audacious_software.passive_data_kit.activities.generators;
import android.content.Context;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Looper;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.view.ViewGroup;
@@ -14,15 +11,17 @@
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
-import java.util.ArrayList;
import java.util.Collections;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.List;
public class DataPointsAdapter extends RecyclerView.Adapter {
- private ArrayList mDataPoints = new ArrayList<>();
+ private Context mContext = null;
@Override
public DataPointViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
- Class extends Generator> generatorClass = Generators.getInstance(null).fetchCustomViewClass(viewType);
+ Class extends Generator> generatorClass = Generators.getInstance(this.mContext).fetchCustomViewClass(viewType);
try {
Method fetchView = generatorClass.getDeclaredMethod("fetchView", ViewGroup.class);
@@ -51,20 +50,24 @@ public DataPointViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
}
@Override
- public void onBindViewHolder(DataPointViewHolder holder, int position) {
- Bundle dataPoint = this.mDataPoints.get(position);
- Class extends Generator> generatorClass = Generators.getInstance(null).fetchCustomViewClass(dataPoint.getBundle(Generator.PDK_METADATA).getString(Generator.IDENTIFIER));
+ public void onBindViewHolder(final DataPointViewHolder holder, int position) {
+ List> activeGenerators = Generators.getInstance(holder.itemView.getContext()).activeGenerators();
+
+ this.sortGenerators(this.mContext, activeGenerators);
+
+ Class extends Generator> generatorClass = activeGenerators.get(position);
try {
- Method bindViewHolder = generatorClass.getDeclaredMethod("bindViewHolder", DataPointViewHolder.class, Bundle.class);
- bindViewHolder.invoke(null, holder, dataPoint);
+ Method bindViewHolder = generatorClass.getDeclaredMethod("bindViewHolder", DataPointViewHolder.class);
+ bindViewHolder.invoke(null, holder);
} catch (Exception e) {
e.printStackTrace();
try {
generatorClass = Generator.class;
- Method bindViewHolder = generatorClass.getDeclaredMethod("bindViewHolder", DataPointViewHolder.class, Bundle.class);
- bindViewHolder.invoke(null, holder, dataPoint);
+ Method bindViewHolder = generatorClass.getDeclaredMethod("bindViewHolder", DataPointViewHolder.class);
+
+ bindViewHolder.invoke(null, holder);
} catch (NoSuchMethodException e1) {
Logger.getInstance(holder.itemView.getContext()).logThrowable(e1);
} catch (InvocationTargetException e1) {
@@ -77,51 +80,63 @@ public void onBindViewHolder(DataPointViewHolder holder, int position) {
@Override
public int getItemCount() {
- return this.mDataPoints.size();
+ return Generators.getInstance(null).activeGenerators().size();
}
- public int getItemViewType (int position) {
- Bundle dataPoint = this.mDataPoints.get(position);
- Class extends Generator> generatorClass = Generators.getInstance(null).fetchCustomViewClass(dataPoint.getBundle(Generator.PDK_METADATA).getString(Generator.IDENTIFIER));
-
- return generatorClass.hashCode();
- }
-
- public void updateDataPoint(String identifier, Bundle data) {
- ArrayList toDelete = new ArrayList<>();
-
- Handler mainHandler = new Handler(Looper.getMainLooper());
- final DataPointsAdapter me = this;
-
- for (Bundle bundle : this.mDataPoints) {
- if (bundle.getBundle(Generator.PDK_METADATA).getString(Generator.IDENTIFIER).equals(identifier)) {
- toDelete.add(bundle);
+ 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();
+ }
+
+ 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;
}
- }
-
- Collections.reverse(toDelete);
+ });
+ }
- for (Bundle delete : toDelete) {
- final int position = this.mDataPoints.indexOf(delete);
+ public int getItemViewType (int position) {
+ List> activeGenerators = Generators.getInstance(this.mContext).activeGenerators();
- this.mDataPoints.remove(position);
+ this.sortGenerators(this.mContext, activeGenerators);
-// mainHandler.post(new Runnable() {
-// @Override
-// public void run() {
-// me.notifyItemRemoved(position);
-// }
-// });
- }
+ Class extends Generator> generatorClass = activeGenerators.get(position);
- this.mDataPoints.add(0, data);
+ return generatorClass.hashCode();
+ }
- mainHandler.post(new Runnable() {
- @Override
- public void run() {
-// me.notifyItemInserted(0);
- me.notifyDataSetChanged();
- }
- });
+ public void setContext(Context context) {
+ this.mContext = context;
}
}
diff --git a/src/com/audacious_software/passive_data_kit/generators/Generator.java b/src/com/audacious_software/passive_data_kit/generators/Generator.java
index dedb648..abb0938 100755
--- a/src/com/audacious_software/passive_data_kit/generators/Generator.java
+++ b/src/com/audacious_software/passive_data_kit/generators/Generator.java
@@ -1,6 +1,9 @@
package com.audacious_software.passive_data_kit.generators;
+import android.content.ContentValues;
import android.content.Context;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
@@ -13,6 +16,7 @@
import java.text.DateFormat;
import java.util.Calendar;
import java.util.Date;
+import java.util.List;
@SuppressWarnings("unused")
public abstract class Generator
@@ -25,6 +29,15 @@ public abstract class Generator
public static final String MEDIA_ATTACHMENT_KEY = "attachment";
public static final String MEDIA_CONTENT_TYPE_KEY = "attachment-type";
public static final String MEDIA_ATTACHMENT_GUID_KEY = "attachment-guid";
+ public static final String LATITUDE = "latitude";
+ public static final String LONGITUDE = "longitude";
+
+ private static final String TABLE_SQLITE_MASTER = "sqlite_master";
+
+ private static final String TABLE_METADATA = "metadata";
+ private static String TABLE_METADATA_LAST_UPDATED = "last_updated";
+ private static String TABLE_METADATA_KEY = "key";
+ private static String TABLE_METADATA_VALUE = "value";
protected Context mContext = null;
@@ -41,10 +54,6 @@ public static void stop(Context context) {
// Do nothing - override in subclasses.
}
- public static void broadcastLatestDataPoint(Context context) {
- // Do nothing - override in subclasses.
- }
-
public static boolean isEnabled(Context context)
{
return false;
@@ -55,12 +64,18 @@ public static boolean isRunning(Context context)
return false;
}
+ public static long latestPointGenerated(Context context) {
+ return 0;
+ }
+
public static View fetchView(ViewGroup parent) {
return LayoutInflater.from(parent.getContext()).inflate(R.layout.card_generator_generic, parent, false);
}
- public static void bindViewHolder(DataPointViewHolder holder, Bundle dataPoint) {
- String identifier = dataPoint.getBundle(Generator.PDK_METADATA).getString(Generator.IDENTIFIER);
+ public static void bindViewHolder(DataPointViewHolder holder) {
+ Class currentClass = new Object() { }.getClass().getEnclosingClass();
+
+ String identifier = currentClass.getCanonicalName();
TextView generatorLabel = (TextView) holder.itemView.findViewById(R.id.label_generator);
@@ -87,4 +102,62 @@ public static String formatTimestamp(Context context, double timestamp) {
return context.getString(R.string.format_full_timestamp_pdk, date, time);
}
+
+ public abstract List fetchPayloads();
+
+ protected int getDatabaseVersion(SQLiteDatabase db) {
+ String where = "type = ? AND name = ?";
+ String[] args = { "table", Generator.TABLE_METADATA };
+
+ Cursor c = db.query(Generator.TABLE_SQLITE_MASTER, null, where, args, null, null, null);
+
+ if (c.getCount() > 0) {
+ // Do nothing - table exists...
+ } else {
+ db.execSQL(this.mContext.getString(R.string.pdk_generator_create_version_table));
+ }
+
+ c.close();
+
+ String versionWhere = Generator.TABLE_METADATA_KEY + " = ?";
+ String[] versionArgs = { "version" };
+
+ c = db.query(Generator.TABLE_METADATA, null, versionWhere, versionArgs, null, null, Generator.TABLE_METADATA_LAST_UPDATED + " DESC");
+
+ int version = 0;
+
+ if (c.moveToNext()) {
+ version = Integer.parseInt(c.getString(c.getColumnIndex(Generator.TABLE_METADATA_VALUE)));
+ }
+
+ c.close();
+
+ return version;
+ }
+
+ protected void setDatabaseVersion(SQLiteDatabase db, int newVersion) {
+ boolean keyExists = false;
+
+ String versionWhere = Generator.TABLE_METADATA_KEY + " = ?";
+ String[] versionArgs = { "version" };
+
+ Cursor c = db.query(Generator.TABLE_METADATA, null, versionWhere, versionArgs, null, null, Generator.TABLE_METADATA_LAST_UPDATED + " DESC");
+
+ if (c.getCount() > 0) {
+ keyExists = true;
+ }
+
+ c.close();
+
+ ContentValues values = new ContentValues();
+ values.put(Generator.TABLE_METADATA_KEY, "version");
+ values.put(Generator.TABLE_METADATA_VALUE, "" + newVersion);
+ values.put(Generator.TABLE_METADATA_LAST_UPDATED, System.currentTimeMillis());
+
+ if (keyExists) {
+ db.update(Generator.TABLE_METADATA, values, versionWhere, versionArgs);
+ } else {
+ db.insert(Generator.TABLE_METADATA, null, values);
+ }
+ }
}
diff --git a/src/com/audacious_software/passive_data_kit/generators/Generators.java b/src/com/audacious_software/passive_data_kit/generators/Generators.java
index fb9e412..42b4cd9 100755
--- a/src/com/audacious_software/passive_data_kit/generators/Generators.java
+++ b/src/com/audacious_software/passive_data_kit/generators/Generators.java
@@ -19,6 +19,7 @@
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.List;
public class Generators {
private Context mContext = null;
@@ -26,9 +27,9 @@ public class Generators {
private ArrayList mGenerators = new ArrayList<>();
private HashSet mActiveGenerators = new HashSet<>();
private SharedPreferences mSharedPreferences = null;
- private HashSet mNewDataPointListeners = new HashSet<>();
private HashMap> mGeneratorMap = new HashMap<>();
private SparseArray> mViewTypeMap = new SparseArray<>();
+ private HashSet mGeneratorUpdatedListeners = new HashSet<>();
public void start() {
if (!this.mStarted)
@@ -148,27 +149,11 @@ public ArrayList diagnostics() {
return actions;
}
- public void transmitData(String identifier, Bundle data) {
- double now = (double) System.currentTimeMillis();
- now = now / 1000; // Convert to seconds...
-
- Bundle metadata = new Bundle();
- metadata.putString(Generator.IDENTIFIER, identifier);
- metadata.putDouble(Generator.TIMESTAMP, now);
- metadata.putString(Generator.GENERATOR, this.getGeneratorFullName(identifier));
- metadata.putString(Generator.SOURCE, this.getSource());
- data.putBundle(Generator.PDK_METADATA, metadata);
-
- for (Generators.NewDataPointListener listener : this.mNewDataPointListeners) {
- listener.onNewDataPoint(identifier, data);
- }
- }
-
- private String getSource() {
+ public String getSource() {
return "unknown-user-please-set-me";
}
- private String getGeneratorFullName(String identifier) {
+ public String getGeneratorFullName(String identifier) {
String pdkName = this.mContext.getString(R.string.pdk_name);
String pdkVersion = this.mContext.getString(R.string.pdk_version);
String appName = this.mContext.getString(this.mContext.getApplicationInfo().labelRes);
@@ -186,10 +171,6 @@ private String getGeneratorFullName(String identifier) {
return identifier + ": " + appName + "/" + version + " " + pdkName + "/" + pdkVersion;
}
- public void removeNewDataPointListener(Generators.NewDataPointListener listener) {
- this.mNewDataPointListeners.remove(listener);
- }
-
public void registerCustomViewClass(String identifier, Class extends Generator> generatorClass) {
this.mGeneratorMap.put(identifier, generatorClass);
this.mViewTypeMap.put(generatorClass.hashCode(), generatorClass);
@@ -215,29 +196,51 @@ public Class extends Generator> fetchCustomViewClass(int viewType) {
return generatorClass;
}
- public void broadcastLatestDataPoints() {
- for (String className : this.mGenerators)
- {
- try {
- Class extends Generator> generatorClass = (Class) Class.forName(className);
-
- Log.e("PDK", "CLASS " + generatorClass);
+ public Generator getGenerator(String className) {
+ Log.e("BB", "GENERATOR FIND START");
+ for (String name : this.mActiveGenerators) {
+ Log.e("BB", "GENERATOR NAME: " + name);
+ }
+ Log.e("BB", "GENERATOR FIND END");
- if (generatorClass != null) {
- Method broadcast = generatorClass.getDeclaredMethod("broadcastLatestDataPoint", Context.class);
+ if (this.mActiveGenerators.contains(className)) {
+ try {
+ Class probeClass = (Class) Class.forName(className);
- broadcast.invoke(null, this.mContext);
- }
+ Method getInstance = probeClass.getDeclaredMethod("getInstance", Context.class);
+ return (Generator) getInstance.invoke(null, this.mContext);
+ } catch (ClassNotFoundException e) {
+ e.printStackTrace();
} catch (NoSuchMethodException e) {
-
- } catch (InvocationTargetException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
+ } catch (InvocationTargetException e) {
+ e.printStackTrace();
+ }
+ }
+
+ return null;
+ }
+
+ public List> activeGenerators() {
+ ArrayList> active = new ArrayList<>();
+
+ for (String className : this.mActiveGenerators) {
+ try {
+ active.add((Class extends Generator>) Class.forName(className));
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
+
+ return active;
+ }
+
+ public void notifyGeneratorUpdated(String identifier, Bundle bundle) {
+ for (GeneratorUpdatedListener listener : this.mGeneratorUpdatedListeners) {
+ listener.onGeneratorUpdated(identifier, bundle);
+ }
}
private static class GeneratorsHolder {
@@ -257,11 +260,15 @@ private void setContext(Context context) {
this.mContext = context.getApplicationContext();
}
- public void addNewDataPointListener(Generators.NewDataPointListener listener) {
- this.mNewDataPointListeners.add(listener);
+ public void addNewGeneratorUpdatedListener(Generators.GeneratorUpdatedListener listener) {
+ this.mGeneratorUpdatedListeners.add(listener);
+ }
+
+ public void removeGeneratorUpdatedListener(Generators.GeneratorUpdatedListener listener) {
+ this.mGeneratorUpdatedListeners.remove(listener);
}
- public interface NewDataPointListener {
- void onNewDataPoint(String identifier, Bundle data);
+ public interface GeneratorUpdatedListener {
+ void onGeneratorUpdated(String identifier, Bundle data);
}
}
diff --git a/src/com/audacious_software/passive_data_kit/generators/communication/PhoneCalls.java b/src/com/audacious_software/passive_data_kit/generators/communication/PhoneCalls.java
index 4294ab8..93677c0 100755
--- a/src/com/audacious_software/passive_data_kit/generators/communication/PhoneCalls.java
+++ b/src/com/audacious_software/passive_data_kit/generators/communication/PhoneCalls.java
@@ -1,11 +1,13 @@
package com.audacious_software.passive_data_kit.generators.communication;
import android.Manifest;
+import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
import android.graphics.Typeface;
import android.os.Build;
import android.os.Bundle;
@@ -20,6 +22,7 @@
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.activities.generators.RequestPermissionActivity;
import com.audacious_software.passive_data_kit.diagnostics.DiagnosticAction;
@@ -27,19 +30,17 @@
import com.audacious_software.passive_data_kit.generators.Generators;
import com.audacious_software.pdk.passivedatakit.R;
import com.github.mikephil.charting.charts.PieChart;
-import com.github.mikephil.charting.components.Description;
-import com.github.mikephil.charting.components.Legend;
import com.github.mikephil.charting.data.Entry;
import com.github.mikephil.charting.data.PieData;
import com.github.mikephil.charting.data.PieDataSet;
import com.github.mikephil.charting.data.PieEntry;
import com.github.mikephil.charting.formatter.IValueFormatter;
-import com.github.mikephil.charting.utils.ColorTemplate;
import com.github.mikephil.charting.utils.ViewPortHandler;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.codec.digest.DigestUtils;
+import java.io.File;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@@ -50,21 +51,6 @@ public class PhoneCalls extends Generator {
private static final String ENABLED = "com.audacious_software.passive_data_kit.generators.communication.PhoneCalls.ENABLED";
private static final boolean ENABLED_DEFAULT = true;
- private static final String SAMPLE_INTERVAL = "com.audacious_software.passive_data_kit.generators.communication.PhoneCalls.SAMPLE_INTERVAL";
- private static final long SAMPLE_INTERVAL_DEFAULT = 30000; // 300000;
-
- private static final String LAST_INCOMING_COUNT = "com.audacious_software.passive_data_kit.generators.communication.PhoneCalls.LAST_INCOMING_COUNT";
- private static final String LAST_OUTGOING_COUNT = "com.audacious_software.passive_data_kit.generators.communication.PhoneCalls.LAST_OUTGOING_COUNT";
- private static final String LAST_MISSED_COUNT = "com.audacious_software.passive_data_kit.generators.communication.PhoneCalls.LAST_MISSED_COUNT";
- private static final String LAST_TOTAL_COUNT = "com.audacious_software.passive_data_kit.generators.communication.PhoneCalls.LAST_TOTAL_COUNT";
-
- private static final String LAST_CALL_TIMESTAMP = "com.audacious_software.passive_data_kit.generators.communication.PhoneCalls.LAST_CALL_TIMESTAMP";
- private static final String LAST_CALL_DURATION = "com.audacious_software.passive_data_kit.generators.communication.PhoneCalls.LAST_CALL_DURATION";
- private static final String LAST_CALL_TYPE = "com.audacious_software.passive_data_kit.generators.communication.PhoneCalls.LAST_CALL_TYPE";
-
- private static final String LAST_SAMPLE = "com.audacious_software.passive_data_kit.generators.communication.PhoneCalls.LAST_SAMPLE";
- private static final long LAST_SAMPLE_DEFAULT = 0;
-
private static final String CALL_DATE_KEY = "call_timestamp";
private static final String CALL_DURATION_KEY = "duration";
private static final String CALL_IS_NEW_KEY = "is_new";
@@ -94,9 +80,33 @@ public class PhoneCalls extends Generator {
private static final String CALL_PRESENTATION_PAYPHONE = "payphone";
private static final String CALL_PRESENTATION_UNKNOWN = "unknown";
+ private static int DATABASE_VERSION = 2;
+
+ private static final String TABLE_HISTORY = "history";
+ private static final String HISTORY_OBSERVED = "observed";
+ private static final String HISTORY_DURATION = "duration";
+ private static final String HISTORY_NUMBER = "number";
+ private static final String HISTORY_IS_NEW = "is_new";
+ private static final String HISTORY_PULLED_EXTERNALLY = "pulled_externally";
+ private static final String HISTORY_POST_DIAL_DIGITS = "post_dial_digits";
+ private static final String HISTORY_COUNTRY_ISO = "country_iso";
+ private static final String HISTORY_DATA_USAGE = "data_usage";
+ private static final String HISTORY_GEOCODED_LOCATION = "geocoded_location";
+ private static final String HISTORY_VIDEO = "is_video";
+ private static final String HISTORY_VIA_NUMBER = "via_number";
+ private static final String HISTORY_PRESENTATION = "presentation";
+ private static final String HISTORY_IS_READ = "is_read";
+ private static final String HISTORY_CALL_TYPE = "call_type";
+
private static PhoneCalls sInstance = null;
private Handler mHandler = null;
+ private Context mContext = null;
+
+ private static final String DATABASE_PATH = "pdk-phone-calls.sqlite";
+
+ private SQLiteDatabase mDatabase = null;
+ private long mSampleInterval = 60000;
public static PhoneCalls getInstance(Context context) {
if (PhoneCalls.sInstance == null) {
@@ -108,6 +118,8 @@ public static PhoneCalls getInstance(Context context) {
public PhoneCalls(Context context) {
super(context);
+
+ this.mContext = context.getApplicationContext();
}
public static void start(final Context context) {
@@ -115,12 +127,14 @@ public static void start(final Context context) {
}
private void startGenerator() {
- Log.e("PDK", "START PHONE CALL GENERATOR");
-
final PhoneCalls me = this;
if (this.mHandler != null) {
- this.mHandler.getLooper().quitSafely();
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
+ this.mHandler.getLooper().quitSafely();
+ } else {
+ this.mHandler.getLooper().quit();
+ }
this.mHandler = null;
}
@@ -128,9 +142,6 @@ private void startGenerator() {
final Runnable checkLogs = new Runnable() {
@Override
public void run() {
- SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(me.mContext);
- SharedPreferences.Editor e = prefs.edit();
-
boolean approved = false;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
@@ -143,28 +154,30 @@ public void run() {
Log.e("PDK", "TODO: Fetch Call Logs...");
- long now = System.currentTimeMillis();
-
if (approved) {
- long totalIncoming = prefs.getLong(PhoneCalls.LAST_INCOMING_COUNT, 0);
- long totalOutgoing = prefs.getLong(PhoneCalls.LAST_OUTGOING_COUNT, 0);
- long totalMissed = prefs.getLong(PhoneCalls.LAST_MISSED_COUNT, 0);
- long total = prefs.getLong(PhoneCalls.LAST_TOTAL_COUNT, 0);
+ long lastObserved = 0;
- long lastSample = prefs.getLong(PhoneCalls.LAST_SAMPLE, PhoneCalls.LAST_SAMPLE_DEFAULT);
+ Cursor lastCursor = me.mDatabase.query(PhoneCalls.TABLE_HISTORY, null, null, null, null, null, PhoneCalls.HISTORY_OBSERVED + " DESC");
- String where = CallLog.Calls.DATE + " > ?";
- String[] args = {"" + lastSample};
+ if (lastCursor.moveToNext()) {
+ lastObserved = lastCursor.getLong(lastCursor.getColumnIndex(PhoneCalls.HISTORY_OBSERVED));
+ }
- long latestCallTimestamp = -1;
- String latestCallType = null;
- long latestCallDuration = -1;
+ lastCursor.close();
+
+ String where = CallLog.Calls.DATE + " > ?";
+ String[] args = {"" + lastObserved};
Cursor c = me.mContext.getContentResolver().query(CallLog.Calls.CONTENT_URI, null, where, args, CallLog.Calls.DATE);
while (c.moveToNext()) {
- Bundle bundle = new Bundle();
+ ContentValues values = new ContentValues();
+ values.put(PhoneCalls.HISTORY_OBSERVED, c.getLong(c.getColumnIndex(CallLog.Calls.DATE)));
+ values.put(PhoneCalls.HISTORY_DURATION, c.getLong(c.getColumnIndex(CallLog.Calls.DURATION)));
+ values.put(PhoneCalls.HISTORY_NUMBER, c.getLong(c.getColumnIndex(CallLog.Calls.DURATION)));
+ values.put(PhoneCalls.HISTORY_IS_NEW, (c.getInt(c.getColumnIndex(CallLog.Calls.NEW)) != 0));
+ Bundle bundle = new Bundle();
bundle.putLong(PhoneCalls.CALL_DATE_KEY, c.getLong(c.getColumnIndex(CallLog.Calls.DATE)));
bundle.putLong(PhoneCalls.CALL_DURATION_KEY, c.getLong(c.getColumnIndex(CallLog.Calls.DURATION)));
bundle.putString(PhoneCalls.CALL_NUMBER_KEY, c.getString(c.getColumnIndex(CallLog.Calls.NUMBER)));
@@ -186,6 +199,8 @@ public void run() {
}
bundle.putBoolean(PhoneCalls.CALL_PULLED_EXTERNALLY_KEY, ((features & CallLog.Calls.FEATURES_PULLED_EXTERNALLY) == CallLog.Calls.FEATURES_PULLED_EXTERNALLY));
+
+ values.put(PhoneCalls.HISTORY_PULLED_EXTERNALLY, ((features & CallLog.Calls.FEATURES_PULLED_EXTERNALLY) == CallLog.Calls.FEATURES_PULLED_EXTERNALLY));
case 24:
if (typeInt == CallLog.Calls.REJECTED_TYPE) {
type = PhoneCalls.CALL_TYPE_REJECTED;
@@ -195,6 +210,9 @@ public void run() {
bundle.putString(PhoneCalls.CALL_POST_DIAL_DIGITS_KEY, c.getString(c.getColumnIndex(CallLog.Calls.POST_DIAL_DIGITS)));
bundle.putString(PhoneCalls.CALL_VIA_NUMBER_KEY, c.getString(c.getColumnIndex(CallLog.Calls.VIA_NUMBER)));
+
+ values.put(PhoneCalls.HISTORY_POST_DIAL_DIGITS, c.getString(c.getColumnIndex(CallLog.Calls.POST_DIAL_DIGITS)));
+ values.put(PhoneCalls.HISTORY_VIA_NUMBER, c.getString(c.getColumnIndex(CallLog.Calls.VIA_NUMBER)));
case 21:
if (typeInt == CallLog.Calls.VOICEMAIL_TYPE) {
type = PhoneCalls.CALL_TYPE_VOICEMAIL;
@@ -203,57 +221,53 @@ public void run() {
bundle.putString(PhoneCalls.CALL_COUNTRY_ISO_KEY, c.getString(c.getColumnIndex(CallLog.Calls.COUNTRY_ISO)));
bundle.putLong(PhoneCalls.CALL_DATA_USAGE_KEY, c.getLong(c.getColumnIndex(CallLog.Calls.DATA_USAGE)));
bundle.putString(PhoneCalls.CALL_GEOCODED_LOCATION_KEY, c.getString(c.getColumnIndex(CallLog.Calls.GEOCODED_LOCATION)));
-
bundle.putBoolean(PhoneCalls.CALL_VIDEO_KEY, ((features & CallLog.Calls.FEATURES_VIDEO) == CallLog.Calls.FEATURES_VIDEO));
+ values.put(PhoneCalls.HISTORY_COUNTRY_ISO, c.getString(c.getColumnIndex(CallLog.Calls.COUNTRY_ISO)));
+ values.put(PhoneCalls.HISTORY_DATA_USAGE, c.getLong(c.getColumnIndex(CallLog.Calls.DATA_USAGE)));
+ values.put(PhoneCalls.HISTORY_GEOCODED_LOCATION, c.getString(c.getColumnIndex(CallLog.Calls.GEOCODED_LOCATION)));
+ values.put(PhoneCalls.HISTORY_VIDEO, ((features & CallLog.Calls.FEATURES_VIDEO) == CallLog.Calls.FEATURES_VIDEO));
+
// bundle.putString(PhoneCalls.CALL_TRANSCRIPTION_KEY, c.getString(c.getColumnIndex(CallLog.Calls.TRANSCRIPTION)));
case 19:
switch (c.getInt(c.getColumnIndex(CallLog.Calls.NUMBER_PRESENTATION))) {
case CallLog.Calls.PRESENTATION_ALLOWED:
bundle.putString(PhoneCalls.CALL_PRESENTATION_KEY, PhoneCalls.CALL_PRESENTATION_ALLOWED);
+ values.put(PhoneCalls.HISTORY_PRESENTATION, PhoneCalls.CALL_PRESENTATION_ALLOWED);
break;
case CallLog.Calls.PRESENTATION_RESTRICTED:
bundle.putString(PhoneCalls.CALL_PRESENTATION_KEY, PhoneCalls.CALL_PRESENTATION_RESTRICTED);
+ values.put(PhoneCalls.HISTORY_PRESENTATION, PhoneCalls.CALL_PRESENTATION_RESTRICTED);
break;
case CallLog.Calls.PRESENTATION_PAYPHONE:
bundle.putString(PhoneCalls.CALL_PRESENTATION_KEY, PhoneCalls.CALL_PRESENTATION_PAYPHONE);
+ values.put(PhoneCalls.HISTORY_PRESENTATION, PhoneCalls.CALL_PRESENTATION_PAYPHONE);
break;
case CallLog.Calls.PRESENTATION_UNKNOWN:
bundle.putString(PhoneCalls.CALL_PRESENTATION_KEY, PhoneCalls.CALL_PRESENTATION_UNKNOWN);
+ values.put(PhoneCalls.HISTORY_PRESENTATION, PhoneCalls.CALL_PRESENTATION_UNKNOWN);
break;
}
case 14:
bundle.putBoolean(PhoneCalls.CALL_IS_READ_KEY, (c.getInt(c.getColumnIndex(CallLog.Calls.IS_READ)) != 0));
+ values.put(PhoneCalls.HISTORY_IS_READ, (c.getInt(c.getColumnIndex(CallLog.Calls.IS_READ)) != 0));
case 1:
if (typeInt == CallLog.Calls.INCOMING_TYPE) {
type = PhoneCalls.CALL_TYPE_INCOMING;
- totalIncoming += 1;
} else if (typeInt == CallLog.Calls.OUTGOING_TYPE) {
type = PhoneCalls.CALL_TYPE_OUTGOING;
- totalOutgoing += 1;
} else if (typeInt == CallLog.Calls.MISSED_TYPE) {
type = PhoneCalls.CALL_TYPE_MISSED;
- totalMissed += 1;
}
}
bundle.putString(PhoneCalls.CALL_TYPE_KEY, type);
-
- if (bundle.getLong(PhoneCalls.CALL_DATE_KEY, 0) > latestCallTimestamp) {
- latestCallTimestamp = bundle.getLong(PhoneCalls.CALL_DATE_KEY, 0);
- latestCallDuration = bundle.getLong(PhoneCalls.CALL_DURATION_KEY, 0);
- latestCallType = type;
- }
-
- Log.e("PDK", "------");
- for (int i = 0; i < c.getColumnCount(); i++) {
- Log.e("PDK", "CALL LOG: " + c.getColumnName(i) + " --> " + c.getString(i));
- }
+ values.put(PhoneCalls.HISTORY_CALL_TYPE, type);
String[] sensitiveFields = {
PhoneCalls.CALL_NUMBER_KEY,
PhoneCalls.CALL_POST_DIAL_DIGITS_KEY,
- PhoneCalls.CALL_VIA_NUMBER_KEY
+ PhoneCalls.CALL_VIA_NUMBER_KEY,
};
for (String field : sensitiveFields) {
@@ -262,38 +276,49 @@ public void run() {
}
}
- Generators.getInstance(me.mContext).transmitData(PhoneCalls.GENERATOR_IDENTIFIER, bundle);
- }
-
- Log.e("PDK", "------");
+ String[] valueSensitiveFields = {
+ PhoneCalls.HISTORY_NUMBER,
+ PhoneCalls.HISTORY_POST_DIAL_DIGITS,
+ PhoneCalls.HISTORY_VIA_NUMBER,
+ };
- total += c.getCount();
+ for (String field : valueSensitiveFields) {
+ if (values.containsKey(field)) {
+ values.put(field, new String(Hex.encodeHex(DigestUtils.sha256(values.getAsString(field)))));
+ }
+ }
- c.close();
+ me.mDatabase.insert(PhoneCalls.TABLE_HISTORY, null, values);
- if (latestCallType != null) {
- e.putLong(PhoneCalls.LAST_CALL_TIMESTAMP, latestCallTimestamp);
- e.putLong(PhoneCalls.LAST_CALL_DURATION, latestCallDuration);
- e.putString(PhoneCalls.LAST_CALL_TYPE, latestCallType);
+ Generators.getInstance(me.mContext).notifyGeneratorUpdated(PhoneCalls.GENERATOR_IDENTIFIER, bundle);
}
- e.putLong(PhoneCalls.LAST_INCOMING_COUNT, totalIncoming);
- e.putLong(PhoneCalls.LAST_OUTGOING_COUNT, totalOutgoing);
- e.putLong(PhoneCalls.LAST_MISSED_COUNT, totalMissed);
- e.putLong(PhoneCalls.LAST_TOTAL_COUNT, total);
-
- e.putLong(PhoneCalls.LAST_SAMPLE, now);
- e.apply();
+ c.close();
}
- long sampleInterval = prefs.getLong(PhoneCalls.SAMPLE_INTERVAL, PhoneCalls.SAMPLE_INTERVAL_DEFAULT);
-
if (me.mHandler != null) {
- me.mHandler.postDelayed(this, sampleInterval);
+ me.mHandler.postDelayed(this, me.mSampleInterval);
}
}
};
+ File path = PassiveDataKit.getGeneratorsStorage(this.mContext);
+
+ path = new File(path, PhoneCalls.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_phone_calls_create_history_table));
+ case 1:
+ this.mDatabase.delete(PhoneCalls.TABLE_HISTORY, null, null);
+ }
+
+ this.setDatabaseVersion(this.mDatabase, PhoneCalls.DATABASE_VERSION);
+
Runnable r = new Runnable() {
@Override
public void run() {
@@ -363,92 +388,136 @@ public void run() {
return actions;
}
- public static void bindViewHolder(DataPointViewHolder holder, final Bundle dataPoint) {
+ public static void bindViewHolder(DataPointViewHolder holder) {
final Context context = holder.itemView.getContext();
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
- double timestamp = dataPoint.getBundle(Generator.PDK_METADATA).getDouble(Generator.TIMESTAMP);
+ long lastTimestamp = 0;
+ long lastDuration = 0;
+ String callType = null;
- TextView dateLabel = (TextView) holder.itemView.findViewById(R.id.generator_data_point_date);
+ long totalIncoming = 0;
+ long totalOutgoing = 0;
+ long totalMissed = 0;
+ long total = 0;
- dateLabel.setText(Generator.formatTimestamp(context, timestamp));
+ PhoneCalls generator = PhoneCalls.getInstance(holder.itemView.getContext());
- PieChart pieChart = (PieChart) holder.itemView.findViewById(R.id.chart_phone_calls);
- pieChart.getLegend().setEnabled(false);
+ Cursor c = generator.mDatabase.query(PhoneCalls.TABLE_HISTORY, null, null, null, null, null, PhoneCalls.HISTORY_OBSERVED + " DESC");
- pieChart.setEntryLabelColor(android.R.color.transparent);
- pieChart.getDescription().setEnabled(false);
- pieChart.setDrawHoleEnabled(false);
+ while (c.moveToNext()) {
+ if (lastTimestamp == 0) {
+ lastTimestamp = c.getLong(c.getColumnIndex(PhoneCalls.HISTORY_OBSERVED));
+ lastDuration = c.getLong(c.getColumnIndex(PhoneCalls.HISTORY_DURATION));
+ }
- long totalIncoming = prefs.getLong(PhoneCalls.LAST_INCOMING_COUNT, 0);
- long totalOutgoing = prefs.getLong(PhoneCalls.LAST_OUTGOING_COUNT, 0);
- long totalMissed = prefs.getLong(PhoneCalls.LAST_MISSED_COUNT, 0);
- long total = prefs.getLong(PhoneCalls.LAST_TOTAL_COUNT, 0);
+ total += 1;
- List entries = new ArrayList<>();
+ String type = c.getString(c.getColumnIndex(PhoneCalls.HISTORY_CALL_TYPE));
- if (totalIncoming > 0) {
- entries.add(new PieEntry(totalIncoming, context.getString(R.string.generator_phone_calls_incoming_label)));
- }
+ if (PhoneCalls.CALL_TYPE_INCOMING.equals(type)) {
+ totalIncoming += 1;
+ } else if (PhoneCalls.CALL_TYPE_OUTGOING.equals(type)) {
+ totalOutgoing += 1;
+ } else if (PhoneCalls.CALL_TYPE_MISSED.equals(type)) {
+ totalOutgoing += 1;
+ }
- if (totalOutgoing > 0) {
- entries.add(new PieEntry(totalOutgoing, context.getString(R.string.generator_phone_calls_outgoing_label)));
+ if (callType == null) {
+ callType = type;
+ }
}
- if (totalMissed > 0) {
- entries.add(new PieEntry(totalMissed, context.getString(R.string.generator_phone_calls_missed_label)));
- }
+ c.close();
- long other = total - (totalIncoming + totalOutgoing + totalMissed);
+ View cardContent = holder.itemView.findViewById(R.id.card_content);
+ View cardEmpty = holder.itemView.findViewById(R.id.card_empty);
+ TextView dateLabel = (TextView) holder.itemView.findViewById(R.id.generator_data_point_date);
- if (other > 0) {
- entries.add(new PieEntry(other, context.getString(R.string.generator_phone_calls_other_label)));
- }
+ if (total > 0) {
+ cardContent.setVisibility(View.VISIBLE);
+ cardEmpty.setVisibility(View.GONE);
- PieDataSet set = new PieDataSet(entries, " ");
+ dateLabel.setText(Generator.formatTimestamp(context, lastTimestamp));
- int[] colors = {
- R.color.generator_phone_call_incoming,
- R.color.generator_phone_call_outgoing,
- R.color.generator_phone_call_missed,
- R.color.generator_phone_call_other
- };
+ PieChart pieChart = (PieChart) holder.itemView.findViewById(R.id.chart_phone_calls);
+ pieChart.getLegend().setEnabled(false);
- set.setColors(colors, context);
+ pieChart.setEntryLabelColor(android.R.color.transparent);
+ pieChart.getDescription().setEnabled(false);
+ pieChart.setDrawHoleEnabled(false);
- PieData data = new PieData(set);
- data.setValueTextSize(14);
- data.setValueTypeface(Typeface.DEFAULT_BOLD);
- data.setValueTextColor(0xffffffff);
+ List entries = new ArrayList<>();
- data.setValueFormatter(new IValueFormatter() {
- @Override
- public String getFormattedValue(float value, Entry entry, int dataSetIndex, ViewPortHandler viewPortHandler) {
- return "" + ((Float) value).intValue();
+ if (totalIncoming > 0) {
+ entries.add(new PieEntry(totalIncoming, context.getString(R.string.generator_phone_calls_incoming_label)));
}
- });
- pieChart.setData(data);
- pieChart.invalidate();
+ if (totalOutgoing > 0) {
+ entries.add(new PieEntry(totalOutgoing, context.getString(R.string.generator_phone_calls_outgoing_label)));
+ }
- long latest = prefs.getLong(PhoneCalls.LAST_CALL_TIMESTAMP, 0);
- long duration = prefs.getLong(PhoneCalls.LAST_CALL_DURATION, 0);
- String direction = prefs.getString(PhoneCalls.LAST_CALL_TYPE, "");
+ if (totalMissed > 0) {
+ entries.add(new PieEntry(totalMissed, context.getString(R.string.generator_phone_calls_missed_label)));
+ }
+
+ long other = total - (totalIncoming + totalOutgoing + totalMissed);
+
+ if (other > 0) {
+ entries.add(new PieEntry(other, context.getString(R.string.generator_phone_calls_other_label)));
+ }
- TextView latestField = (TextView) holder.itemView.findViewById(R.id.field_latest_call);
- TextView durationField = (TextView) holder.itemView.findViewById(R.id.field_duration);
- TextView directionField = (TextView) holder.itemView.findViewById(R.id.field_direction);
+ PieDataSet set = new PieDataSet(entries, " ");
- Date lateDate = new Date(latest);
- String day = android.text.format.DateFormat.getMediumDateFormat(context).format(lateDate);
- String time = android.text.format.DateFormat.getTimeFormat(context).format(lateDate);
+ int[] colors = {
+ R.color.generator_phone_call_incoming,
+ R.color.generator_phone_call_outgoing,
+ R.color.generator_phone_call_missed,
+ R.color.generator_phone_call_other
+ };
- latestField.setText(context.getString(R.string.format_full_timestamp_pdk, day, time));
- durationField.setText(context.getString(R.string.generator_phone_calls_duration_format, ((float) duration) / 60));
- directionField.setText(direction);
+ set.setColors(colors, context);
- dateLabel.setText(Generator.formatTimestamp(context, latest / 1000));
+ PieData data = new PieData(set);
+ data.setValueTextSize(14);
+ data.setValueTypeface(Typeface.DEFAULT_BOLD);
+ data.setValueTextColor(0xffffffff);
+
+ data.setValueFormatter(new IValueFormatter() {
+ @Override
+ public String getFormattedValue(float value, Entry entry, int dataSetIndex, ViewPortHandler viewPortHandler) {
+ return "" + ((Float) value).intValue();
+ }
+ });
+
+ pieChart.setData(data);
+ pieChart.invalidate();
+
+ TextView latestField = (TextView) holder.itemView.findViewById(R.id.field_latest_call);
+ TextView durationField = (TextView) holder.itemView.findViewById(R.id.field_duration);
+ TextView directionField = (TextView) holder.itemView.findViewById(R.id.field_direction);
+
+ Date lateDate = new Date(lastTimestamp);
+ String day = android.text.format.DateFormat.getMediumDateFormat(context).format(lateDate);
+ String time = android.text.format.DateFormat.getTimeFormat(context).format(lateDate);
+
+ latestField.setText(context.getString(R.string.format_full_timestamp_pdk, day, time));
+ durationField.setText(context.getString(R.string.generator_phone_calls_duration_format, ((float) lastDuration) / 60));
+ directionField.setText(callType);
+
+ dateLabel.setText(Generator.formatTimestamp(context, lastTimestamp / 1000));
+ } else {
+ cardContent.setVisibility(View.GONE);
+ cardEmpty.setVisibility(View.VISIBLE);
+
+ dateLabel.setText(R.string.label_never_pdk);
+ }
+ }
+
+ @Override
+ public List fetchPayloads() {
+ return new ArrayList<>();
}
public static View fetchView(ViewGroup parent)
@@ -456,8 +525,19 @@ public static View fetchView(ViewGroup parent)
return LayoutInflater.from(parent.getContext()).inflate(R.layout.card_generator_phone_calls, parent, false);
}
- public static void broadcastLatestDataPoint(Context context) {
- Generators.getInstance(context).transmitData(PhoneCalls.GENERATOR_IDENTIFIER, new Bundle());
- }
+ public static long latestPointGenerated(Context context) {
+ long timestamp = 0;
+
+ PhoneCalls me = PhoneCalls.getInstance(context);
+
+ Cursor c = me.mDatabase.query(PhoneCalls.TABLE_HISTORY, null, null, null, null, null, PhoneCalls.HISTORY_OBSERVED + " DESC");
+ if (c.moveToNext()) {
+ timestamp = c.getLong(c.getColumnIndex(PhoneCalls.HISTORY_OBSERVED));
+ }
+
+ c.close();
+
+ return timestamp;
+ }
}
diff --git a/src/com/audacious_software/passive_data_kit/generators/communication/TextMessages.java b/src/com/audacious_software/passive_data_kit/generators/communication/TextMessages.java
new file mode 100755
index 0000000..3ad7c05
--- /dev/null
+++ b/src/com/audacious_software/passive_data_kit/generators/communication/TextMessages.java
@@ -0,0 +1,469 @@
+package com.audacious_software.passive_data_kit.generators.communication;
+
+import android.Manifest;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.pm.PackageManager;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.graphics.Typeface;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.preference.PreferenceManager;
+import android.support.v4.content.ContextCompat;
+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.PhoneUtililties;
+import com.audacious_software.passive_data_kit.activities.generators.DataPointViewHolder;
+import com.audacious_software.passive_data_kit.activities.generators.RequestPermissionActivity;
+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.PieChart;
+import com.github.mikephil.charting.data.Entry;
+import com.github.mikephil.charting.data.PieData;
+import com.github.mikephil.charting.data.PieDataSet;
+import com.github.mikephil.charting.data.PieEntry;
+import com.github.mikephil.charting.formatter.IValueFormatter;
+import com.github.mikephil.charting.utils.ViewPortHandler;
+
+import org.apache.commons.codec.binary.Hex;
+import org.apache.commons.codec.digest.DigestUtils;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.List;
+
+public class TextMessages extends Generator {
+ private static final String GENERATOR_IDENTIFIER = "pdk-text-messages";
+
+ private static final String ENABLED = "com.audacious_software.passive_data_kit.generators.communication.TextMessages.ENABLED";
+ private static final boolean ENABLED_DEFAULT = true;
+
+ private static final Uri SMS_INBOX_URI = Uri.parse("content://sms/inbox");
+ private static final Uri SMS_SENT_URI = Uri.parse("content://sms/sent");
+
+ private static final String SMS_DATE = "date";
+ private static final String SMS_BODY = "body";
+ private static final String SMS_NUMBER_NAME = "person";
+ private static final String SMS_NUMBER = "address";
+ private static final String SMS_LENGTH = "length";
+ private static final String SMS_DIRECTION = "direction";
+
+ private static int DATABASE_VERSION = 1;
+
+ private static final String TABLE_HISTORY = "history";
+ private static final String HISTORY_OBSERVED = "observed";
+ private static final String HISTORY_DIRECTION = "direction";
+ private static final String HISTORY_LENGTH = "length";
+ private static final String HISTORY_BODY = "body";
+ private static final String HISTORY_NUMBER_NAME = "number_name";
+ private static final String HISTORY_NUMBER = "number";
+ private static final String HISTORY_DIRECTION_INCOMING = "incoming";
+ private static final String HISTORY_DIRECTION_OUTGOING = "outgoing";
+
+ private static TextMessages sInstance = null;
+
+ private Handler mHandler = null;
+ private Context mContext = null;
+
+ private static final String DATABASE_PATH = "pdk-text-messages.sqlite";
+
+ private SQLiteDatabase mDatabase = null;
+ private long mSampleInterval = 60000;
+
+ public static TextMessages getInstance(Context context) {
+ if (TextMessages.sInstance == null) {
+ TextMessages.sInstance = new TextMessages(context.getApplicationContext());
+ }
+
+ return TextMessages.sInstance;
+ }
+
+ public TextMessages(Context context) {
+ super(context);
+
+ this.mContext = context.getApplicationContext();
+ }
+
+ public static void start(final Context context) {
+ TextMessages.getInstance(context).startGenerator();
+ }
+
+ private void startGenerator() {
+ final TextMessages me = this;
+
+ if (this.mHandler != null) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
+ this.mHandler.getLooper().quitSafely();
+ } else {
+ this.mHandler.getLooper().quit();
+ }
+
+ this.mHandler = null;
+ }
+
+ final Runnable checkLogs = new Runnable() {
+ @Override
+ public void run() {
+ boolean approved = false;
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ if (ContextCompat.checkSelfPermission(me.mContext, Manifest.permission.READ_SMS) == PackageManager.PERMISSION_GRANTED){
+ approved = true;
+ }
+ } else {
+ approved = true;
+ }
+
+ if (approved) {
+ long lastObserved = 0;
+
+ Cursor lastCursor = me.mDatabase.query(TextMessages.TABLE_HISTORY, null, null, null, null, null, TextMessages.HISTORY_OBSERVED + " DESC");
+
+ if (lastCursor.moveToNext()) {
+ lastObserved = lastCursor.getLong(lastCursor.getColumnIndex(TextMessages.HISTORY_OBSERVED));
+ }
+
+ lastCursor.close();
+
+ ArrayList toTransmit = new ArrayList<>();
+
+ String where = TextMessages.SMS_DATE + " > ?";
+ String[] args = {"" + lastObserved};
+
+ Cursor c = me.mContext.getContentResolver().query(TextMessages.SMS_INBOX_URI, null, where, args, TextMessages.SMS_DATE);
+
+ while (c.moveToNext()) {
+ ContentValues values = new ContentValues();
+ values.put(TextMessages.HISTORY_OBSERVED, c.getLong(c.getColumnIndex(TextMessages.SMS_DATE)));
+
+ String body = c.getString(c.getColumnIndex(TextMessages.SMS_BODY));
+
+ values.put(TextMessages.HISTORY_LENGTH, body.length());
+ values.put(TextMessages.HISTORY_BODY, body);
+
+ String name = c.getString(c.getColumnIndex(TextMessages.SMS_NUMBER_NAME));
+ String number = c.getString(c.getColumnIndex(TextMessages.SMS_NUMBER));
+
+ if (name == null) {
+ name = number;
+ }
+
+ values.put(TextMessages.HISTORY_NUMBER_NAME, name);
+ values.put(TextMessages.HISTORY_NUMBER, number);
+
+ values.put(TextMessages.HISTORY_DIRECTION, TextMessages.HISTORY_DIRECTION_INCOMING);
+
+ toTransmit.add(values);
+ }
+
+ c.close();
+
+ c = me.mContext.getContentResolver().query(TextMessages.SMS_SENT_URI, null, where, args, TextMessages.SMS_DATE);
+
+ while (c.moveToNext()) {
+ ContentValues values = new ContentValues();
+ values.put(TextMessages.HISTORY_OBSERVED, c.getLong(c.getColumnIndex(TextMessages.SMS_DATE)));
+
+ String body = c.getString(c.getColumnIndex(TextMessages.SMS_BODY));
+
+ values.put(TextMessages.HISTORY_LENGTH, body.length());
+ values.put(TextMessages.HISTORY_BODY, body);
+
+ String name = c.getString(c.getColumnIndex(TextMessages.SMS_NUMBER_NAME));
+ String number = c.getString(c.getColumnIndex(TextMessages.SMS_NUMBER));
+
+ if (name == null) {
+ name = number;
+ }
+
+ values.put(TextMessages.HISTORY_NUMBER_NAME, name);
+ values.put(TextMessages.HISTORY_NUMBER, number);
+
+ values.put(TextMessages.HISTORY_DIRECTION, TextMessages.HISTORY_DIRECTION_OUTGOING);
+
+ toTransmit.add(values);
+ }
+
+ c.close();
+
+ Collections.sort(toTransmit, new Comparator() {
+ @Override
+ public int compare(ContentValues one, ContentValues two) {
+ Long oneTime = one.getAsLong(TextMessages.HISTORY_OBSERVED);
+ Long twoTime = two.getAsLong(TextMessages.HISTORY_OBSERVED);
+
+ return oneTime.compareTo(twoTime);
+ }
+ });
+
+ for (ContentValues values : toTransmit) {
+ String[] sensitiveFields = {
+ TextMessages.HISTORY_NUMBER_NAME,
+ TextMessages.HISTORY_NUMBER,
+ TextMessages.HISTORY_BODY,
+ };
+
+ for (String field : sensitiveFields) {
+ if (values.containsKey(field)) {
+ String value = values.getAsString(field);
+
+ if (TextMessages.HISTORY_NUMBER.equals(TextMessages.HISTORY_NUMBER)) {
+ value = PhoneUtililties.normalizedPhoneNumber(value);
+ }
+
+ values.put(field, new String(Hex.encodeHex(DigestUtils.sha256(value))));
+ }
+ }
+
+ Bundle bundle = new Bundle();
+ bundle.putLong(TextMessages.SMS_DATE, values.getAsLong(TextMessages.HISTORY_OBSERVED));
+ bundle.putInt(TextMessages.SMS_LENGTH, values.getAsInteger(TextMessages.HISTORY_LENGTH));
+ bundle.putString(TextMessages.SMS_NUMBER_NAME, values.getAsString(TextMessages.HISTORY_NUMBER_NAME));
+ bundle.putString(TextMessages.SMS_NUMBER, values.getAsString(TextMessages.HISTORY_NUMBER));
+ bundle.putString(TextMessages.SMS_DIRECTION, values.getAsString(TextMessages.HISTORY_DIRECTION));
+ bundle.putString(TextMessages.SMS_BODY, values.getAsString(TextMessages.HISTORY_BODY));
+
+ me.mDatabase.insert(TextMessages.TABLE_HISTORY, null, values);
+
+ Generators.getInstance(me.mContext).notifyGeneratorUpdated(TextMessages.GENERATOR_IDENTIFIER, bundle);
+ }
+ }
+
+ if (me.mHandler != null) {
+ me.mHandler.postDelayed(this, me.mSampleInterval);
+ }
+ }
+ };
+
+ File path = PassiveDataKit.getGeneratorsStorage(this.mContext);
+
+ path = new File(path, TextMessages.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_text_messages_create_history_table));
+ }
+
+ this.setDatabaseVersion(this.mDatabase, TextMessages.DATABASE_VERSION);
+
+ Runnable r = new Runnable() {
+ @Override
+ public void run() {
+ Looper.prepare();
+
+ me.mHandler = new Handler();
+
+ Looper.loop();
+ }
+ };
+
+ Thread t = new Thread(r);
+ t.start();
+
+ try {
+ Thread.sleep(50);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+
+ me.mHandler.post(checkLogs);
+
+ Generators.getInstance(this.mContext).registerCustomViewClass(TextMessages.GENERATOR_IDENTIFIER, TextMessages.class);
+ }
+
+ public static boolean isEnabled(Context context) {
+ SharedPreferences prefs = Generators.getInstance(context).getSharedPreferences(context);
+
+ return prefs.getBoolean(TextMessages.ENABLED, TextMessages.ENABLED_DEFAULT);
+ }
+
+ public static boolean isRunning(Context context) {
+ if (TextMessages.sInstance == null) {
+ return false;
+ }
+
+ return TextMessages.sInstance.mHandler != null;
+ }
+
+ public static ArrayList diagnostics(final Context context) {
+ ArrayList actions = new ArrayList<>();
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ if (ContextCompat.checkSelfPermission(context, Manifest.permission.READ_SMS) != PackageManager.PERMISSION_GRANTED){
+ final Handler handler = new Handler(Looper.getMainLooper());
+
+ actions.add(new DiagnosticAction(context.getString(R.string.diagnostic_sms_log_permission_required), new Runnable() {
+
+ @Override
+ public void run() {
+ handler.post(new Runnable() {
+
+ @Override
+ public void run() {
+ Intent intent = new Intent(context, RequestPermissionActivity.class);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.putExtra(RequestPermissionActivity.PERMISSION, Manifest.permission.READ_SMS);
+
+ context.startActivity(intent);
+ }
+ });
+ }
+ }));
+ }
+ }
+
+ return actions;
+ }
+
+ public static void bindViewHolder(DataPointViewHolder holder) {
+ final Context context = holder.itemView.getContext();
+
+ long lastTimestamp = 0;
+ int lastLength = 0;
+
+ long totalIncoming = 0;
+ long totalOutgoing = 0;
+ long total = 0;
+
+ TextMessages generator = TextMessages.getInstance(holder.itemView.getContext());
+ String lastDirection = null;
+
+ Cursor c = generator.mDatabase.query(TextMessages.TABLE_HISTORY, null, null, null, null, null, TextMessages.HISTORY_OBSERVED + " DESC");
+
+ while (c.moveToNext()) {
+ if (lastTimestamp == 0) {
+ lastTimestamp = c.getLong(c.getColumnIndex(TextMessages.HISTORY_OBSERVED));
+ lastDirection = c.getString(c.getColumnIndex(TextMessages.HISTORY_DIRECTION));
+ lastLength = c.getInt(c.getColumnIndex(TextMessages.HISTORY_LENGTH));
+ }
+
+ total += 1;
+
+ String direction = c.getString(c.getColumnIndex(TextMessages.HISTORY_DIRECTION));
+
+ if (TextMessages.HISTORY_DIRECTION_INCOMING.equals(direction)) {
+ totalIncoming += 1;
+ } else if (TextMessages.HISTORY_DIRECTION_OUTGOING.equals(direction)) {
+ totalOutgoing += 1;
+ }
+ }
+
+ c.close();
+
+ View cardContent = holder.itemView.findViewById(R.id.card_content);
+ View cardEmpty = holder.itemView.findViewById(R.id.card_empty);
+ TextView dateLabel = (TextView) holder.itemView.findViewById(R.id.generator_data_point_date);
+
+ if (total > 0) {
+ cardContent.setVisibility(View.VISIBLE);
+ cardEmpty.setVisibility(View.GONE);
+
+ dateLabel.setText(Generator.formatTimestamp(context, lastTimestamp));
+
+ PieChart pieChart = (PieChart) holder.itemView.findViewById(R.id.chart_text_messages);
+ pieChart.getLegend().setEnabled(false);
+
+ pieChart.setEntryLabelColor(android.R.color.transparent);
+ pieChart.getDescription().setEnabled(false);
+ pieChart.setDrawHoleEnabled(false);
+
+ List entries = new ArrayList<>();
+
+ if (totalIncoming > 0) {
+ entries.add(new PieEntry(totalIncoming, context.getString(R.string.generator_text_messages_incoming_label)));
+ }
+
+ if (totalOutgoing > 0) {
+ entries.add(new PieEntry(totalOutgoing, context.getString(R.string.generator_text_messages_outgoing_label)));
+ }
+
+ PieDataSet set = new PieDataSet(entries, " ");
+
+ int[] colors = {
+ R.color.generator_text_messages_incoming,
+ R.color.generator_text_messages_outgoing
+ };
+
+ set.setColors(colors, context);
+
+ PieData data = new PieData(set);
+ data.setValueTextSize(14);
+ data.setValueTypeface(Typeface.DEFAULT_BOLD);
+ data.setValueTextColor(0xffffffff);
+
+ data.setValueFormatter(new IValueFormatter() {
+ @Override
+ public String getFormattedValue(float value, Entry entry, int dataSetIndex, ViewPortHandler viewPortHandler) {
+ return "" + ((Float) value).intValue();
+ }
+ });
+
+ pieChart.setData(data);
+ pieChart.invalidate();
+
+ TextView latestField = (TextView) holder.itemView.findViewById(R.id.field_latest_text_message);
+ TextView lengthField = (TextView) holder.itemView.findViewById(R.id.field_length);
+ TextView directionField = (TextView) holder.itemView.findViewById(R.id.field_direction);
+
+ Date lateDate = new Date(lastTimestamp);
+ String day = android.text.format.DateFormat.getMediumDateFormat(context).format(lateDate);
+ String time = android.text.format.DateFormat.getTimeFormat(context).format(lateDate);
+
+ latestField.setText(context.getString(R.string.format_full_timestamp_pdk, day, time));
+ lengthField.setText(context.getString(R.string.generator_text_messages_length_format, lastLength));
+ directionField.setText(lastDirection);
+
+ dateLabel.setText(Generator.formatTimestamp(context, lastTimestamp / 1000));
+ } else {
+ cardContent.setVisibility(View.GONE);
+ cardEmpty.setVisibility(View.VISIBLE);
+
+ dateLabel.setText(R.string.label_never_pdk);
+ }
+ }
+
+ @Override
+ public List fetchPayloads() {
+ return new ArrayList<>();
+ }
+
+ public static View fetchView(ViewGroup parent)
+ {
+ return LayoutInflater.from(parent.getContext()).inflate(R.layout.card_generator_text_messages, parent, false);
+ }
+
+ public static long latestPointGenerated(Context context) {
+ long timestamp = 0;
+
+ TextMessages me = TextMessages.getInstance(context);
+
+ Cursor c = me.mDatabase.query(TextMessages.TABLE_HISTORY, null, null, null, null, null, TextMessages.HISTORY_OBSERVED + " DESC");
+
+ if (c.moveToNext()) {
+ timestamp = c.getLong(c.getColumnIndex(TextMessages.HISTORY_OBSERVED));
+ }
+
+ c.close();
+
+ return timestamp;
+ }
+}
diff --git a/src/com/audacious_software/passive_data_kit/generators/device/Location.java b/src/com/audacious_software/passive_data_kit/generators/device/Location.java
index 814c5ad..c76a801 100755
--- a/src/com/audacious_software/passive_data_kit/generators/device/Location.java
+++ b/src/com/audacious_software/passive_data_kit/generators/device/Location.java
@@ -1,25 +1,35 @@
package com.audacious_software.passive_data_kit.generators.device;
import android.Manifest;
+import android.app.Activity;
+import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
+import android.content.res.ColorStateList;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.graphics.Bitmap;
+import android.graphics.drawable.Drawable;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.preference.PreferenceManager;
-import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
+import android.support.v4.content.res.ResourcesCompat;
+import android.support.v4.graphics.drawable.DrawableCompat;
+import android.support.v7.widget.SwitchCompat;
import android.util.DisplayMetrics;
-import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.CompoundButton;
import android.widget.TextView;
import com.audacious_software.passive_data_kit.DeviceInformation;
+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.activities.generators.RequestPermissionActivity;
import com.audacious_software.passive_data_kit.diagnostics.DiagnosticAction;
@@ -35,16 +45,20 @@
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.MapView;
import com.google.android.gms.maps.OnMapReadyCallback;
-import com.google.android.gms.maps.UiSettings;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.LatLng;
+import com.google.android.gms.maps.model.LatLngBounds;
import com.google.android.gms.maps.model.MarkerOptions;
+import com.google.maps.android.ui.IconGenerator;
+import java.io.File;
import java.util.ArrayList;
+import java.util.List;
@SuppressWarnings("unused")
public class Location extends Generator implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener {
private static final String GENERATOR_IDENTIFIER = "pdk-location";
+ private static final String DATABASE_PATH = "pdk-location.sqlite";
private static final String ENABLED = "com.audacious_software.passive_data_kit.generators.device.Location.ENABLED";
private static final boolean ENABLED_DEFAULT = true;
@@ -61,18 +75,27 @@ public class Location extends Generator implements GoogleApiClient.ConnectionCal
private static final String BEARING_KEY = "bearing";
private static final String SPEED_KEY = "speed";
private static final String EXTRAS_KEY = "extras";
-
- private static final String LAST_KNOWN_LATITUDE = "com.audacious_software.passive_data_kit.generators.device.Location.LAST_KNOWN_LATITUDE";
- private static final float LAST_KNOWN_LATITUDE_DEFAULT = 0;
-
- private static final String LAST_KNOWN_LONGITUDE = "com.audacious_software.passive_data_kit.generators.device.Location.LAST_KNOWN_LONGITUDE";
- private static final float LAST_KNOWN_LONGITUDE_DEFAULT = 0;
-
- private static final String LAST_KNOWN_TIMESTAMP = "com.audacious_software.passive_data_kit.generators.device.Location.LAST_KNOWN_TIMESTAMP";;
+ private static final String SETTING_DISPLAY_HYBRID_MAP = "com.audacious_software.passive_data_kit.generators.device.Location.SETTING_DISPLAY_HYBRID_MAP";
+ private static final boolean SETTING_DISPLAY_HYBRID_MAP_DEFAULT = true;
private static Location sInstance = null;
private GoogleApiClient mGoogleApiClient = null;
private android.location.Location mLastLocation = null;
+ private long mUpdateInterval = 60000;
+
+ private SQLiteDatabase mDatabase = null;
+ private static int DATABASE_VERSION = 1;
+
+ private static final String TABLE_HISTORY = "history";
+ private static final String HISTORY_OBSERVED = "observed";
+ private static final String HISTORY_LATITUDE = "latitude";
+ private static final String HISTORY_LONGITUDE = "longitude";
+ private static final String HISTORY_ALTITUDE = "altitude";
+ private static final String HISTORY_BEARING = "bearing";
+ private static final String HISTORY_SPEED = "speed";
+ private static final String HISTORY_PROVIDER = "provider";
+ private static final String HISTORY_LOCATION_TIMESTAMP = "location_timestamp";
+ private static final String HISTORY_ACCURACY = "accuracy";
public static Location getInstance(Context context) {
if (Location.sInstance == null) {
@@ -114,7 +137,6 @@ else if (Location.useGoogleLocationServices(me.mContext))
me.mGoogleApiClient = builder.build();
me.mGoogleApiClient.connect();
}
-
}
else
{
@@ -128,6 +150,31 @@ else if (Location.useGoogleLocationServices(me.mContext))
t.start();
Generators.getInstance(this.mContext).registerCustomViewClass(Location.GENERATOR_IDENTIFIER, Location.class);
+
+ File path = PassiveDataKit.getGeneratorsStorage(this.mContext);
+
+ path = new File(path, Location.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_location_create_history_table));
+ }
+
+ this.setDatabaseVersion(this.mDatabase, Location.DATABASE_VERSION);
+ }
+
+ private void stopGenerator() {
+ if (this.mGoogleApiClient != null) {
+ this.mGoogleApiClient.disconnect();
+ this.mGoogleApiClient = null;
+ }
+
+ this.mDatabase.close();
+ this.mDatabase = null;
}
public static boolean useGoogleLocationServices(Context context) {
@@ -206,13 +253,13 @@ public void run() {
return actions;
}
-
@Override
public void onConnected(Bundle bundle) {
final LocationRequest request = new LocationRequest();
request.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
- request.setInterval(60000);
+ request.setFastestInterval(this.mUpdateInterval);
+ request.setInterval(this.mUpdateInterval);
if (this.mGoogleApiClient != null && this.mGoogleApiClient.isConnected()) {
if (ContextCompat.checkSelfPermission(this.mContext, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
@@ -239,78 +286,103 @@ public void onLocationChanged(android.location.Location location) {
long now = System.currentTimeMillis();
- Bundle bundle = new Bundle();
+ ContentValues values = new ContentValues();
+ values.put(Location.HISTORY_OBSERVED, System.currentTimeMillis());
+ values.put(Location.HISTORY_LATITUDE, location.getLatitude());
+ values.put(Location.HISTORY_LONGITUDE, location.getLongitude());
+ values.put(Location.HISTORY_PROVIDER, location.getProvider());
+ values.put(Location.HISTORY_LOCATION_TIMESTAMP, location.getTime());
- bundle.putDouble(Location.LATITUDE_KEY, location.getLatitude());
- bundle.putDouble(Location.LONGITUDE_KEY, location.getLongitude());
- bundle.putDouble(Location.FIX_TIMESTAMP_KEY, ((double) location.getTime()) / 1000);
- bundle.putString(Location.PROVIDER_KEY, location.getProvider());
+ Bundle updated = new Bundle();
+ updated.putLong(Location.HISTORY_OBSERVED, System.currentTimeMillis());
+ updated.putDouble(Location.HISTORY_LATITUDE, location.getLatitude());
+ updated.putDouble(Location.HISTORY_LONGITUDE, location.getLongitude());
+ updated.putString(Location.HISTORY_PROVIDER, location.getProvider());
+ updated.putLong(Location.HISTORY_LOCATION_TIMESTAMP, location.getTime());
- this.mLastLocation = location;
+ Bundle metadata = new Bundle();
+ metadata.putDouble(Generator.LATITUDE, location.getLatitude());
+ metadata.putDouble(Generator.LONGITUDE, location.getLongitude());
- if (location.hasAccuracy()) {
- bundle.putFloat(Location.ACCURACY_KEY, location.getAccuracy());
- }
+ updated.putBundle(Generator.PDK_METADATA, metadata);
if (location.hasAltitude()) {
- bundle.putDouble(Location.ALTITUDE_KEY, location.getAltitude());
+ values.put(Location.HISTORY_ALTITUDE, location.getAltitude());
+ updated.putDouble(Location.HISTORY_ALTITUDE, location.getAltitude());
}
if (location.hasBearing()) {
- bundle.putFloat(Location.BEARING_KEY, location.getBearing());
+ values.put(Location.HISTORY_BEARING, location.getBearing());
+ updated.putDouble(Location.HISTORY_BEARING, location.getBearing());
}
if (location.hasSpeed()) {
- bundle.putFloat(Location.SPEED_KEY, location.getSpeed());
+ values.put(Location.HISTORY_SPEED, location.getBearing());
+ updated.putDouble(Location.HISTORY_SPEED, location.getBearing());
}
- Bundle extras = location.getExtras();
-
- if (extras != null) {
- bundle.putBundle(Location.EXTRAS_KEY, extras);
+ if (location.hasAccuracy()) {
+ values.put(Location.HISTORY_ACCURACY, location.getAccuracy());
+ updated.putDouble(Location.HISTORY_ACCURACY, location.getAccuracy());
}
- Generators.getInstance(this.mContext).transmitData(Location.GENERATOR_IDENTIFIER, bundle);
+ this.mDatabase.insert(Location.TABLE_HISTORY, null, values);
- SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this.mContext);
- SharedPreferences.Editor e = prefs.edit();
+ Generators.getInstance(this.mContext).notifyGeneratorUpdated(Location.GENERATOR_IDENTIFIER, updated);
+ }
- e.putFloat(Location.LAST_KNOWN_LATITUDE, (float) location.getLatitude());
- e.putFloat(Location.LAST_KNOWN_LONGITUDE, (float) location.getLongitude());
- e.putLong(Location.LAST_KNOWN_TIMESTAMP, System.currentTimeMillis());
+ public static long latestPointGenerated(Context context) {
+ long timestamp = 0;
- e.apply();
- }
+ Location me = Location.getInstance(context);
- public static void bindViewHolder(DataPointViewHolder holder, final Bundle dataPoint) {
- Log.e("PDK", "DRAWING LOCATION: " + dataPoint);
+ Cursor c = me.mDatabase.query(Location.TABLE_HISTORY, null, null, null, null, null, Location.HISTORY_OBSERVED + " DESC");
+ if (c.moveToNext()) {
+ timestamp = c.getLong(c.getColumnIndex(Location.HISTORY_OBSERVED));
+ }
+
+ c.close();
+
+ return timestamp;
+ }
+
+ public static void bindViewHolder(DataPointViewHolder holder) {
final Context context = holder.itemView.getContext();
- String identifier = dataPoint.getBundle(Generator.PDK_METADATA).getString(Generator.IDENTIFIER);
+ Location me = Location.getInstance(context);
+
+ double lastLatitude = 0.0;
+ double lastLongitude = 0.0;
+ long timestamp = 0;
+
+ final List locations = new ArrayList<>();
+
+ String where = Location.HISTORY_OBSERVED + " > ?";
+ String[] args = { "" + (System.currentTimeMillis() - (1000 * 60 * 60 * 24)) };
- double timestamp = dataPoint.getBundle(Generator.PDK_METADATA).getDouble(Generator.TIMESTAMP);
+ Cursor c = me.mDatabase.query(Location.TABLE_HISTORY, null, where, args, null, null, Location.HISTORY_OBSERVED);
- double latitude = Location.LAST_KNOWN_LATITUDE_DEFAULT;
- double longitude = Location.LAST_KNOWN_LONGITUDE_DEFAULT;
+ while (c.moveToNext()) {
+ lastLatitude = c.getDouble(c.getColumnIndex(Location.HISTORY_LATITUDE));
+ lastLongitude = c.getDouble(c.getColumnIndex(Location.HISTORY_LONGITUDE));
+ timestamp = c.getLong(c.getColumnIndex(Location.HISTORY_OBSERVED));
- if (dataPoint.containsKey(Location.LATITUDE_KEY) && dataPoint.containsKey(Location.LONGITUDE_KEY)) {
- latitude = dataPoint.getDouble(Location.LATITUDE_KEY);
- longitude = dataPoint.getDouble(Location.LONGITUDE_KEY);
- } else { // Empty point - retrieve last known location...
- Log.e("PDK", "FETCHING LAST KNOWN LOCATION...");
- SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
+ LatLng location = new LatLng(lastLatitude, lastLongitude);
- latitude = prefs.getFloat(Location.LAST_KNOWN_LATITUDE, Location.LAST_KNOWN_LATITUDE_DEFAULT);
- longitude = prefs.getFloat(Location.LAST_KNOWN_LONGITUDE, Location.LAST_KNOWN_LONGITUDE_DEFAULT);
- timestamp = ((double) prefs.getLong(Location.LAST_KNOWN_TIMESTAMP, System.currentTimeMillis())) / 1000 ;
+ locations.add(location);
}
+ c.close();
+
TextView dateLabel = (TextView) holder.itemView.findViewById(R.id.generator_data_point_date);
- dateLabel.setText(Generator.formatTimestamp(context, timestamp));
+ dateLabel.setText(Generator.formatTimestamp(context, timestamp / 1000));
+
+ final double finalLatitude = lastLatitude;
+ final double finalLongitude = lastLongitude;
- final double finalLatitude = latitude;
- final double finalLongitude = longitude;
+ final DisplayMetrics metrics = new DisplayMetrics();
+ ((Activity) context).getWindowManager().getDefaultDisplay().getMetrics(metrics);
if (Location.useKindleLocationServices())
{
@@ -322,24 +394,93 @@ else if (Location.useGoogleLocationServices(holder.itemView.getContext()))
final MapView mapView = (MapView) holder.itemView.findViewById(R.id.map_view);
mapView.onCreate(null);
+ final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
+
+ final boolean useHybrid = prefs.getBoolean(Location.SETTING_DISPLAY_HYBRID_MAP, Location.SETTING_DISPLAY_HYBRID_MAP_DEFAULT);
+
+ SwitchCompat hybridSwitch = (SwitchCompat) holder.itemView.findViewById(R.id.pdk_google_location_map_type_hybrid);
+ hybridSwitch.setChecked(useHybrid);
+
+ hybridSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
+ @Override
+ public void onCheckedChanged(CompoundButton compoundButton, final boolean checked) {
+ SharedPreferences.Editor e = prefs.edit();
+ e.putBoolean(Location.SETTING_DISPLAY_HYBRID_MAP, checked);
+ e.apply();
+
+ mapView.getMapAsync(new OnMapReadyCallback() {
+ public void onMapReady(GoogleMap googleMap) {
+ if (checked) {
+ googleMap.setMapType(GoogleMap.MAP_TYPE_HYBRID);
+ } else {
+ googleMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);
+ }
+ }
+ });
+ }
+ });
+
+ ColorStateList buttonStates = new ColorStateList(
+ new int[][]{
+ new int[]{android.R.attr.state_checked},
+ new int[]{-android.R.attr.state_enabled},
+ new int[]{}
+ },
+ new int[]{
+ 0xfff1f1f1,
+ 0x1c000000,
+ 0xff33691E
+ }
+ );
+
+ DrawableCompat.setTintList(hybridSwitch.getThumbDrawable(), buttonStates);
+
+ IconGenerator iconGen = new IconGenerator(context);
+
+ Drawable shapeDrawable = ResourcesCompat.getDrawable(context.getResources(), R.drawable.ic_location_heatmap_marker, null);
+ iconGen.setBackground(shapeDrawable);
+
+ View view = new View(context);
+ view.setLayoutParams(new ViewGroup.LayoutParams(8, 8));
+ iconGen.setContentView(view);
+
+ final Bitmap bitmap = iconGen.makeIcon();
+
mapView.getMapAsync(new OnMapReadyCallback() {
public void onMapReady(GoogleMap googleMap) {
- googleMap.setMapType(GoogleMap.MAP_TYPE_HYBRID);
- googleMap.getUiSettings().setZoomControlsEnabled(false);
+ if (ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED ||
+ ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
+ googleMap.setMyLocationEnabled(true);
+ }
+
+ if (useHybrid) {
+ googleMap.setMapType(GoogleMap.MAP_TYPE_HYBRID);
+ } else {
+ googleMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);
+ }
+
+ googleMap.getUiSettings().setZoomControlsEnabled(true);
googleMap.getUiSettings().setMyLocationButtonEnabled(false);
+ googleMap.getUiSettings().setMapToolbarEnabled(false);
+ googleMap.getUiSettings().setAllGesturesEnabled(false);
- googleMap.animateCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(finalLatitude, finalLongitude), 14));
+ LatLngBounds.Builder builder = new LatLngBounds.Builder();
+
+ for (LatLng latlng : locations) {
+ builder.include(latlng);
+ }
- googleMap.addMarker(new MarkerOptions()
- .position(new LatLng(finalLatitude, finalLongitude)));
-// .icon(BitmapDescriptorFactory.fromResource(R.drawable.ic_marker_none)));
+ googleMap.moveCamera(CameraUpdateFactory.newLatLngBounds(builder.build(), (int) (16 * metrics.density)));
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
- googleMap.setPadding(0, 0, 0, (int) (32 * metrics.density));
+ for (LatLng latLng : locations) {
+ googleMap.addMarker(new MarkerOptions()
+ .position(latLng)
+ .icon(BitmapDescriptorFactory.fromBitmap(bitmap)));
+ }
- UiSettings settings = googleMap.getUiSettings();
- settings.setMapToolbarEnabled(false);
+ mapView.onResume();
}
});
}
@@ -348,9 +489,11 @@ public void onMapReady(GoogleMap googleMap) {
// TODO
throw new RuntimeException("Throw rocks at developer to implement generic location support.");
}
+ }
- TextView description = (TextView) holder.itemView.findViewById(R.id.generator_location_description);
- description.setText(context.getResources().getString(R.string.generator_location_value, latitude, longitude));
+ @Override
+ public List fetchPayloads() {
+ return new ArrayList();
}
public static View fetchView(ViewGroup parent)
@@ -380,26 +523,23 @@ public android.location.Location getLastKnownLocation() {
android.location.Location last = null;
- if (ContextCompat.checkSelfPermission(this.mContext, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED &&
+ if (ContextCompat.checkSelfPermission(this.mContext, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED ||
ContextCompat.checkSelfPermission(this.mContext, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
- Log.e("FC", "LOCATION PERMISSIONS GRANTED...");
-
last = locations.getLastKnownLocation(LocationManager.GPS_PROVIDER);
- Log.e("FC", "GPS: " + last);
-
if (last == null) {
last = locations.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
-
- Log.e("FC", "NETWORK: " + last);
}
}
return last;
}
- public static void broadcastLatestDataPoint(Context context) {
- Generators.getInstance(context).transmitData(Location.GENERATOR_IDENTIFIER, new Bundle());
+ public void setUpdateInterval(long interval) {
+ this.mUpdateInterval = interval;
+
+ this.stopGenerator();
+ this.startGenerator();
}
}
diff --git a/src/com/audacious_software/passive_data_kit/generators/device/ScreenState.java b/src/com/audacious_software/passive_data_kit/generators/device/ScreenState.java
index 4d314aa..2107447 100755
--- a/src/com/audacious_software/passive_data_kit/generators/device/ScreenState.java
+++ b/src/com/audacious_software/passive_data_kit/generators/device/ScreenState.java
@@ -1,13 +1,15 @@
package com.audacious_software.passive_data_kit.generators.device;
import android.content.BroadcastReceiver;
+import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
import android.os.Build;
import android.os.Bundle;
-import android.preference.PreferenceManager;
import android.view.Display;
import android.view.LayoutInflater;
import android.view.View;
@@ -16,20 +18,18 @@
import android.widget.LinearLayout;
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 org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-
+import java.io.File;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Calendar;
-import java.util.Date;
+import java.util.List;
public class ScreenState extends Generator{
private static final String GENERATOR_IDENTIFIER = "pdk-screen-state";
@@ -37,20 +37,24 @@ public class ScreenState extends Generator{
private static final String ENABLED = "com.audacious_software.passive_data_kit.generators.device.ScreenState.ENABLED";
private static final boolean ENABLED_DEFAULT = true;
- private static final String SCREEN_STATE_KEY = "screen_state";
private static final String STATE_DOZE = "doze";
private static final String STATE_DOZE_SUSPEND = "doze_suspend";
private static final String STATE_ON = "on";
private static final String STATE_OFF = "off";
private static final String STATE_UNKNOWN = "unknown";
- private static final String SCREEN_HISTORY_KEY = "com.audacious_software.passive_data_kit.generators.device.ScreenState.SCREEN_HISTORY_KEY";;
- private static final String SCREEN_HISTORY_TIMESTAMP = "ts";
- private static final String SCREEN_HISTORY_STATE = "state";
+
+ private static final String DATABASE_PATH = "pdk-screen-state.sqlite";
+ private static final int DATABASE_VERSION = 2;
+ private static final String HISTORY_OBSERVED = "observed";
+ private static final String HISTORY_STATE = "state";
+ private static final String TABLE_HISTORY = "history";
private static ScreenState sInstance = null;
private BroadcastReceiver mReceiver = null;
+ private SQLiteDatabase mDatabase = null;
+
public static ScreenState getInstance(Context context) {
if (ScreenState.sInstance == null) {
ScreenState.sInstance = new ScreenState(context.getApplicationContext());
@@ -68,10 +72,18 @@ public static void start(final Context context) {
}
private void startGenerator() {
+ final ScreenState me = this;
+
this.mReceiver = new BroadcastReceiver() {
@Override
- public void onReceive(Context context, Intent intent) {
- Bundle bundle = new Bundle();
+ public void onReceive(final Context context, Intent intent) {
+ long now = System.currentTimeMillis();
+
+ ContentValues values = new ContentValues();
+ values.put(ScreenState.HISTORY_OBSERVED, now);
+
+ Bundle update = new Bundle();
+ update.putLong(ScreenState.HISTORY_OBSERVED, now);
WindowManager window = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display display = window.getDefaultDisplay();
@@ -81,62 +93,36 @@ public void onReceive(Context context, Intent intent) {
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) {
switch (display.getState()) {
case Display.STATE_DOZE:
- bundle.putString(ScreenState.SCREEN_STATE_KEY, ScreenState.STATE_DOZE);
+ values.put(ScreenState.HISTORY_STATE, ScreenState.STATE_DOZE);
break;
case Display.STATE_DOZE_SUSPEND:
- bundle.putString(ScreenState.SCREEN_STATE_KEY, ScreenState.STATE_DOZE_SUSPEND);
+ values.put(ScreenState.HISTORY_STATE, ScreenState.STATE_DOZE_SUSPEND);
break;
case Display.STATE_ON:
- bundle.putString(ScreenState.SCREEN_STATE_KEY, ScreenState.STATE_ON);
+ values.put(ScreenState.HISTORY_STATE, ScreenState.STATE_ON);
break;
case Display.STATE_OFF:
- bundle.putString(ScreenState.SCREEN_STATE_KEY, ScreenState.STATE_OFF);
+ values.put(ScreenState.HISTORY_STATE, ScreenState.STATE_OFF);
break;
case Display.STATE_UNKNOWN:
- bundle.putString(ScreenState.SCREEN_STATE_KEY, ScreenState.STATE_UNKNOWN);
+ values.put(ScreenState.HISTORY_STATE, ScreenState.STATE_UNKNOWN);
break;
}
} else {
if (Intent.ACTION_SCREEN_OFF.equals(action)) {
- bundle.putString(ScreenState.SCREEN_STATE_KEY, ScreenState.STATE_OFF);
+ values.put(ScreenState.HISTORY_STATE, ScreenState.STATE_OFF);
} else if (Intent.ACTION_SCREEN_ON.equals(action)) {
- bundle.putString(ScreenState.SCREEN_STATE_KEY, ScreenState.STATE_ON);
+ values.put(ScreenState.HISTORY_STATE, ScreenState.STATE_ON);
} else {
- bundle.putString(ScreenState.SCREEN_STATE_KEY, ScreenState.STATE_UNKNOWN);
+ values.put(ScreenState.HISTORY_STATE, ScreenState.STATE_UNKNOWN);
}
}
- Generators.getInstance(context).transmitData(ScreenState.GENERATOR_IDENTIFIER, bundle);
-
- SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
-
- try {
- JSONArray history = new JSONArray(prefs.getString(ScreenState.SCREEN_HISTORY_KEY, "[]"));
+ me.mDatabase.insert(ScreenState.TABLE_HISTORY, null, values);
- JSONObject latest = new JSONObject();
- latest.put(ScreenState.SCREEN_HISTORY_TIMESTAMP, System.currentTimeMillis());
+ update.putString(ScreenState.HISTORY_STATE, values.getAsString(ScreenState.HISTORY_STATE));
- if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) {
- latest.put(ScreenState.SCREEN_HISTORY_STATE, display.getState());
- } else {
- if (Intent.ACTION_SCREEN_OFF.equals(action)) {
- latest.put(ScreenState.SCREEN_HISTORY_STATE, 0x01);
- } else if (Intent.ACTION_SCREEN_ON.equals(action)) {
- latest.put(ScreenState.SCREEN_HISTORY_STATE, 0x02);
- } else {
- latest.put(ScreenState.SCREEN_HISTORY_STATE, 0x00);
- }
- }
-
- history.put(latest);
-
- SharedPreferences.Editor e = prefs.edit();
-
- e.putString(ScreenState.SCREEN_HISTORY_KEY, history.toString());
- e.apply();
- } catch (JSONException e) {
- e.printStackTrace();
- }
+ Generators.getInstance(context).notifyGeneratorUpdated(ScreenState.GENERATOR_IDENTIFIER, update);
}
};
@@ -147,7 +133,23 @@ public void onReceive(Context context, Intent intent) {
Generators.getInstance(this.mContext).registerCustomViewClass(ScreenState.GENERATOR_IDENTIFIER, ScreenState.class);
- this.mReceiver.onReceive(this.mContext, null);
+ File path = PassiveDataKit.getGeneratorsStorage(this.mContext);
+
+ path = new File(path, ScreenState.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_screen_state_create_history_table));
+ case 1:
+ this.mDatabase.execSQL("DROP TABLE history");
+ this.mDatabase.execSQL(this.mContext.getString(R.string.pdk_generator_screen_state_create_history_table));
+ }
+
+ this.setDatabaseVersion(this.mDatabase, ScreenState.DATABASE_VERSION);
}
public static boolean isEnabled(Context context) {
@@ -168,95 +170,111 @@ public static ArrayList diagnostics(Context context) {
return new ArrayList<>();
}
- public static void bindViewHolder(DataPointViewHolder holder, final Bundle dataPoint) {
+ public static void bindViewHolder(DataPointViewHolder holder) {
final Context context = holder.itemView.getContext();
- try {
- SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
- JSONArray history = new JSONArray(prefs.getString(ScreenState.SCREEN_HISTORY_KEY, "[]"));
-
-// Log.e("PDK", "SCREEN HISTORY: " + history.toString(2));
+ Calendar cal = Calendar.getInstance();
+ cal.set(Calendar.HOUR_OF_DAY, 0);
+ cal.set(Calendar.MINUTE, 0);
+ cal.set(Calendar.SECOND, 0);
+ cal.set(Calendar.MILLISECOND, 0);
- Calendar cal = Calendar.getInstance();
- cal.set(Calendar.HOUR_OF_DAY, 0);
- cal.set(Calendar.MINUTE, 0);
- cal.set(Calendar.SECOND, 0);
- cal.set(Calendar.MILLISECOND, 0);
+ long zeroStart = cal.getTimeInMillis();
+ cal.add(Calendar.DATE, -1);
- long zeroStart = cal.getTimeInMillis();
- cal.add(Calendar.DATE, -1);
+ LinearLayout zeroTimeline = (LinearLayout) holder.itemView.findViewById(R.id.day_zero_value);
- LinearLayout zeroTimeline = (LinearLayout) holder.itemView.findViewById(R.id.day_zero_value);
+ ScreenState.populateTimeline(context, zeroTimeline, zeroStart);
- ScreenState.populateTimeline(context, zeroTimeline, zeroStart, history);
+ long oneStart = cal.getTimeInMillis();
+ cal.add(Calendar.DATE, -1);
- long oneStart = cal.getTimeInMillis();
- cal.add(Calendar.DATE, -1);
+ LinearLayout oneTimeline = (LinearLayout) holder.itemView.findViewById(R.id.day_one_value);
- LinearLayout oneTimeline = (LinearLayout) holder.itemView.findViewById(R.id.day_one_value);
+ ScreenState.populateTimeline(context, oneTimeline, oneStart);
- ScreenState.populateTimeline(context, oneTimeline, oneStart, history);
+ long twoStart = cal.getTimeInMillis();
- long twoStart = cal.getTimeInMillis();
+ LinearLayout twoTimeline = (LinearLayout) holder.itemView.findViewById(R.id.day_two_value);
- LinearLayout twoTimeline = (LinearLayout) holder.itemView.findViewById(R.id.day_two_value);
+ ScreenState.populateTimeline(context, twoTimeline, twoStart);
- ScreenState.populateTimeline(context, twoTimeline, twoStart, history);
- } catch (JSONException e) {
- e.printStackTrace();
- }
+ ScreenState generator = ScreenState.getInstance(context);
- double timestamp = dataPoint.getBundle(Generator.PDK_METADATA).getDouble(Generator.TIMESTAMP);
+ Cursor c = generator.mDatabase.query(ScreenState.TABLE_HISTORY, null, null, null, null, null, ScreenState.HISTORY_OBSERVED + " DESC");
+ View cardContent = holder.itemView.findViewById(R.id.card_content);
+ View cardEmpty = holder.itemView.findViewById(R.id.card_empty);
TextView dateLabel = (TextView) holder.itemView.findViewById(R.id.generator_data_point_date);
- dateLabel.setText(Generator.formatTimestamp(context, timestamp));
+ if (c.moveToNext()) {
+ cardContent.setVisibility(View.VISIBLE);
+ cardEmpty.setVisibility(View.GONE);
- Calendar cal = Calendar.getInstance();
- DateFormat format = android.text.format.DateFormat.getDateFormat(context);
+ long timestamp = c.getLong(c.getColumnIndex(ScreenState.HISTORY_OBSERVED)) / 1000;
- TextView zeroDayLabel = (TextView) holder.itemView.findViewById(R.id.day_zero_label);
- zeroDayLabel.setText(format.format(cal.getTime()));
+ dateLabel.setText(Generator.formatTimestamp(context, timestamp));
- cal.add(Calendar.DATE, -1);
+ cal = Calendar.getInstance();
+ DateFormat format = android.text.format.DateFormat.getDateFormat(context);
- TextView oneDayLabel = (TextView) holder.itemView.findViewById(R.id.day_one_label);
- oneDayLabel.setText(format.format(cal.getTime()));
+ TextView zeroDayLabel = (TextView) holder.itemView.findViewById(R.id.day_zero_label);
+ zeroDayLabel.setText(format.format(cal.getTime()));
- cal.add(Calendar.DATE, -1);
+ cal.add(Calendar.DATE, -1);
+
+ TextView oneDayLabel = (TextView) holder.itemView.findViewById(R.id.day_one_label);
+ oneDayLabel.setText(format.format(cal.getTime()));
+
+ cal.add(Calendar.DATE, -1);
+
+ TextView twoDayLabel = (TextView) holder.itemView.findViewById(R.id.day_two_label);
+ twoDayLabel.setText(format.format(cal.getTime()));
+ } else {
+ cardContent.setVisibility(View.GONE);
+ cardEmpty.setVisibility(View.VISIBLE);
+
+ dateLabel.setText(R.string.label_never_pdk);
+ }
- TextView twoDayLabel = (TextView) holder.itemView.findViewById(R.id.day_two_label);
- twoDayLabel.setText(format.format(cal.getTime()));
+ c.close();
}
- private static void populateTimeline(Context context, LinearLayout timeline, long start, JSONArray history) {
+ private static void populateTimeline(Context context, LinearLayout timeline, long start) {
timeline.removeAllViews();
+ ScreenState generator = ScreenState.getInstance(context);
+
long end = start + (24 * 60 * 60 * 1000);
- long now = System.currentTimeMillis();
+ String where = ScreenState.HISTORY_OBSERVED + " >= ? AND " + ScreenState.HISTORY_OBSERVED + " < ?";
+ String[] args = { "" + start, "" + end };
- int lastState = -1;
+ Cursor c = generator.mDatabase.query(ScreenState.TABLE_HISTORY, null, where, args, null, null, ScreenState.HISTORY_OBSERVED);
- ArrayList activeStates = new ArrayList<>();
+ ArrayList activeStates = new ArrayList<>();
ArrayList activeTimestamps = new ArrayList<>();
- for (int i = 0; i < history.length(); i++) {
- try {
- JSONObject point = history.getJSONObject(i);
+ while (c.moveToNext()) {
+ long timestamp = c.getLong(c.getColumnIndex(ScreenState.HISTORY_OBSERVED));
- long timestamp = point.getLong(ScreenState.SCREEN_HISTORY_TIMESTAMP);
- int state = point.getInt(ScreenState.SCREEN_HISTORY_STATE);
+ activeTimestamps.add(timestamp);
- if (timestamp < start) {
- lastState = state;
- } else if (timestamp < end) {
- activeStates.add(state);
- activeTimestamps.add(timestamp);
- }
- } catch (JSONException e) {
- e.printStackTrace();
- }
+ String state = c.getString(c.getColumnIndex(ScreenState.HISTORY_STATE));
+ activeStates.add(state);
+ }
+
+ c.close();
+
+ String lastState = ScreenState.STATE_UNKNOWN;
+
+ String lastWhere = ScreenState.HISTORY_OBSERVED + " < ?";
+ String[] lastArgs = { "" + start };
+
+ c = generator.mDatabase.query(ScreenState.TABLE_HISTORY, null, lastWhere, lastArgs, null, null, ScreenState.HISTORY_OBSERVED + " DESC");
+
+ if (c.moveToNext()) {
+ lastState = c.getString(c.getColumnIndex(ScreenState.HISTORY_STATE));
}
if (activeStates.size() > 0) {
@@ -265,25 +283,24 @@ private static void populateTimeline(Context context, LinearLayout timeline, lon
View startView = new View(context);
-
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) {
- if (lastState == -1) {
+ if (ScreenState.STATE_UNKNOWN.equals(lastState)) {
- } else if (firstState == Display.STATE_ON) {
+ } else if (ScreenState.STATE_ON.equals(lastState)) {
startView.setBackgroundColor(0xff4CAF50);
- } else if (firstState == Display.STATE_OFF) {
+ } else if (ScreenState.STATE_OFF.equals(lastState)) {
startView.setBackgroundColor(0xff263238);
- } else if (firstState == Display.STATE_DOZE) {
+ } else if (ScreenState.STATE_DOZE.equals(lastState)) {
startView.setBackgroundColor(0xff1b5e20);
- } else if (firstState == Display.STATE_DOZE_SUSPEND) {
+ } else if (ScreenState.STATE_DOZE_SUSPEND.equals(lastState)) {
startView.setBackgroundColor(0xff1b5e20);
}
} else {
- if (lastState == -1) {
+ if (ScreenState.STATE_UNKNOWN.equals(lastState)) {
- } else if (firstState == 0x02) {
+ } else if (ScreenState.STATE_ON.equals(lastState)) {
startView.setBackgroundColor(0xff4CAF50);
- } else if (firstState == 0x01) {
+ } else if (ScreenState.STATE_OFF.equals(lastState)) {
startView.setBackgroundColor(0xff263238);
}
}
@@ -293,28 +310,30 @@ private static void populateTimeline(Context context, LinearLayout timeline, lon
timeline.addView(startView);
+ long now = System.currentTimeMillis();
+
if (activeStates.size() == 1) {
View v = new View(context);
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) {
- if (firstState == Display.STATE_ON) {
+ if (ScreenState.STATE_ON.equals(firstState)) {
v.setBackgroundColor(0xff4CAF50);
- } else if (firstState == Display.STATE_OFF) {
+ } else if (ScreenState.STATE_OFF.equals(firstState)) {
v.setBackgroundColor(0xff263238);
- } else if (firstState == Display.STATE_DOZE) {
+ } else if (ScreenState.STATE_DOZE.equals(firstState)) {
v.setBackgroundColor(0xff3f51b5);
- } else if (firstState == Display.STATE_DOZE_SUSPEND) {
+ } else if (ScreenState.STATE_DOZE_SUSPEND.equals(firstState)) {
v.setBackgroundColor(0xff3f51b5);
}
} else {
- if (firstState == 0x02) {
+ if (ScreenState.STATE_ON.equals(firstState)) {
v.setBackgroundColor(0xff4CAF50);
- } else if (firstState == 0x01) {
+ } else if (ScreenState.STATE_OFF.equals(firstState)) {
v.setBackgroundColor(0xff263238);
}
}
- if (end > now) {
+ if (end > System.currentTimeMillis()) {
params = new LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.MATCH_PARENT, now - firstTimestamp);
v.setLayoutParams(params);
} else {
@@ -328,24 +347,24 @@ private static void populateTimeline(Context context, LinearLayout timeline, lon
long currentTimestamp = activeTimestamps.get(i);
long priorTimestamp = activeTimestamps.get(i - 1);
- long priorState = activeStates.get(i - 1);
+ String priorState = activeStates.get(i - 1);
View v = new View(context);
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) {
- if (priorState == Display.STATE_ON) {
+ if (ScreenState.STATE_ON.equals(priorState)) {
v.setBackgroundColor(0xff4CAF50);
- } else if (priorState == Display.STATE_OFF) {
+ } else if (ScreenState.STATE_OFF.equals(priorState)) {
v.setBackgroundColor(0xff263238);
- } else if (priorState == Display.STATE_DOZE) {
+ } else if (ScreenState.STATE_DOZE.equals(priorState)) {
v.setBackgroundColor(0xff3f51b5);
- } else if (priorState == Display.STATE_DOZE_SUSPEND) {
+ } else if (ScreenState.STATE_DOZE_SUSPEND.equals(priorState)) {
v.setBackgroundColor(0xff3f51b5);
}
} else {
- if (priorState == 0x02) {
+ if (ScreenState.STATE_ON.equals(priorState)) {
v.setBackgroundColor(0xff4CAF50);
- } else if (priorState == 0x01) {
+ } else if (ScreenState.STATE_OFF.equals(priorState)) {
v.setBackgroundColor(0xff263238);
}
}
@@ -357,17 +376,17 @@ private static void populateTimeline(Context context, LinearLayout timeline, lon
}
long finalTimestamp = activeTimestamps.get(activeTimestamps.size() - 1);
- long finalState = activeStates.get(activeStates.size() - 1);
+ String finalState = activeStates.get(activeStates.size() - 1);
View v = new View(context);
- if (finalState == Display.STATE_ON) {
+ if (ScreenState.STATE_ON.equals(finalState)) {
v.setBackgroundColor(0xff4CAF50);
- } else if (finalState == Display.STATE_OFF) {
+ } else if (ScreenState.STATE_OFF.equals(finalState)) {
v.setBackgroundColor(0xff263238);
- } else if (finalState == Display.STATE_DOZE) {
+ } else if (ScreenState.STATE_DOZE.equals(finalState)) {
v.setBackgroundColor(0xff3f51b5);
- } else if (finalState == Display.STATE_DOZE_SUSPEND) {
+ } else if (ScreenState.STATE_DOZE_SUSPEND.equals(finalState)) {
v.setBackgroundColor(0xff3f51b5);
}
@@ -390,6 +409,8 @@ private static void populateTimeline(Context context, LinearLayout timeline, lon
timeline.addView(v);
}
+ } else {
+
}
}
@@ -398,7 +419,24 @@ public static View fetchView(ViewGroup parent)
return LayoutInflater.from(parent.getContext()).inflate(R.layout.card_generator_screen_state, parent, false);
}
- public static void broadcastLatestDataPoint(Context context) {
- Generators.getInstance(context).transmitData(ScreenState.GENERATOR_IDENTIFIER, new Bundle());
+ @Override
+ public List fetchPayloads() {
+ return new ArrayList<>();
+ }
+
+ public static long latestPointGenerated(Context context) {
+ long timestamp = 0;
+
+ ScreenState me = ScreenState.getInstance(context);
+
+ Cursor c = me.mDatabase.query(ScreenState.TABLE_HISTORY, null, null, null, null, null, ScreenState.HISTORY_OBSERVED + " DESC");
+
+ if (c.moveToNext()) {
+ timestamp = c.getLong(c.getColumnIndex(ScreenState.HISTORY_OBSERVED));
+ }
+
+ c.close();
+
+ return timestamp;
}
}
diff --git a/src/com/audacious_software/passive_data_kit/generators/services/GoogleAwareness.java b/src/com/audacious_software/passive_data_kit/generators/services/GoogleAwareness.java
index 796b1c2..9aea317 100755
--- a/src/com/audacious_software/passive_data_kit/generators/services/GoogleAwareness.java
+++ b/src/com/audacious_software/passive_data_kit/generators/services/GoogleAwareness.java
@@ -28,6 +28,7 @@
import com.google.android.gms.location.DetectedActivity;
import java.util.ArrayList;
+import java.util.List;
/**
* Created by cjkarr on 6/28/2016.
@@ -219,4 +220,9 @@ public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
Log.e("PDK", "GA onConnectionFailed");
this.mGoogleApiClient = null;
}
+
+ @Override
+ public List fetchPayloads() {
+ return new ArrayList<>();
+ }
}
diff --git a/src/com/audacious_software/passive_data_kit/generators/wearables/MicrosoftBand.java b/src/com/audacious_software/passive_data_kit/generators/wearables/MicrosoftBand.java
index 295aade..b8f4d3b 100755
--- a/src/com/audacious_software/passive_data_kit/generators/wearables/MicrosoftBand.java
+++ b/src/com/audacious_software/passive_data_kit/generators/wearables/MicrosoftBand.java
@@ -65,6 +65,7 @@
import java.util.ArrayList;
import java.util.Collections;
+import java.util.List;
@SuppressWarnings("unused")
public class MicrosoftBand extends Generator
@@ -543,7 +544,7 @@ private void transmitData(BandSensorManager sensors) {
this.mHeartRateVariabilityDataPoints.clear();
}
- Generators.getInstance(this.mContext).transmitData(MicrosoftBand.GENERATOR_IDENTIFIER, bundle);
+// Generators.getInstance(this.mContext).transmitData(MicrosoftBand.GENERATOR_IDENTIFIER, bundle);
}
public static ArrayList diagnostics(Context context)
@@ -1429,4 +1430,9 @@ public static void bindViewHolder(DataPointViewHolder holder, Bundle dataPoint)
uvLevel.setText(context.getString(R.string.generator_value_not_applicable));
}
}
+
+ @Override
+ public List fetchPayloads() {
+ return new ArrayList<>();
+ }
}
diff --git a/src/com/audacious_software/passive_data_kit/transmitters/HttpTransmitter.java b/src/com/audacious_software/passive_data_kit/transmitters/HttpTransmitter.java
index ab65bc8..863d30e 100755
--- a/src/com/audacious_software/passive_data_kit/transmitters/HttpTransmitter.java
+++ b/src/com/audacious_software/passive_data_kit/transmitters/HttpTransmitter.java
@@ -46,7 +46,7 @@
import okhttp3.Response;
import okio.Buffer;
-public class HttpTransmitter extends Transmitter implements Generators.NewDataPointListener {
+public class HttpTransmitter extends Transmitter implements Generators.GeneratorUpdatedListener {
public static final String UPLOAD_URI = "com.audacious_software.passive_data_kit.transmitters.HttpTransmitter.UPLOAD_URI";
public static final String USER_ID = "com.audacious_software.passive_data_kit.transmitters.HttpTransmitter.USER_ID";
private static final String HASH_ALGORITHM = "com.audacious_software.passive_data_kit.transmitters.HttpTransmitter.HASH_ALGORITHM";
@@ -133,7 +133,7 @@ else if (!options.containsKey(HttpTransmitter.USER_ID)) {
this.mContext = context.getApplicationContext();
- Generators.getInstance(this.mContext).addNewDataPointListener(this);
+ Generators.getInstance(this.mContext).addNewGeneratorUpdatedListener(this);
}
private boolean shouldAttemptUpload(boolean force) {
@@ -424,12 +424,26 @@ public long transmittedSize() {
}
@Override
- public void onNewDataPoint(String identifier, Bundle data) {
+ public void onGeneratorUpdated(String identifier, Bundle data) {
if (data.keySet().size() > 1) { // Only transmit non-empty bundles...
+ double now = (double) System.currentTimeMillis();
+ now = now / 1000; // Convert to seconds...
+
+ Generators generators = Generators.getInstance(this.mContext);
+
+ Bundle metadata = new Bundle();
+
if (data.containsKey(Generator.PDK_METADATA)) {
- data.getBundle(Generator.PDK_METADATA).putString(Generator.SOURCE, this.mUserId);
+ metadata = data.getBundle(Generator.PDK_METADATA);
}
+ metadata.putString(Generator.IDENTIFIER, identifier);
+ metadata.putDouble(Generator.TIMESTAMP, now);
+ metadata.putString(Generator.GENERATOR, generators.getGeneratorFullName(identifier));
+ metadata.putString(Generator.SOURCE, generators.getSource());
+ metadata.putString(Generator.SOURCE, this.mUserId);
+ data.putBundle(Generator.PDK_METADATA, metadata);
+
if (this.mJsonGenerator == null) {
this.mCurrentFile = new File(this.getPendingFolder(), System.currentTimeMillis() + HttpTransmitter.TEMP_EXTENSION);