From b0ccf25954b2931d65981ce8f32192e77d66fbf4 Mon Sep 17 00:00:00 2001 From: "Chris J. Karr" Date: Fri, 12 May 2017 23:55:18 -0500 Subject: [PATCH] Visualization performance improvements --- build.gradle | 2 +- .../activities/DataStreamActivity.java | 47 ++- .../generators/DataPointsAdapter.java | 46 +-- .../generators/device/Battery.java | 34 +- .../device/ForegroundApplication.java | 17 +- .../generators/sensors/Accelerometer.java | 47 +-- .../generators/sensors/AmbientLight.java | 290 ++++++++++-------- 7 files changed, 268 insertions(+), 215 deletions(-) diff --git a/build.gradle b/build.gradle index 3dbd2ce..713328b 100755 --- a/build.gradle +++ b/build.gradle @@ -9,7 +9,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:2.3.1' + classpath 'com.android.tools.build:gradle:2.3.2' } } 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 c3a33f4..a0f4808 100755 --- a/src/com/audacious_software/passive_data_kit/activities/DataStreamActivity.java +++ b/src/com/audacious_software/passive_data_kit/activities/DataStreamActivity.java @@ -9,6 +9,7 @@ import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; +import android.util.Log; import android.view.Menu; import android.view.MenuItem; @@ -21,6 +22,7 @@ public class DataStreamActivity extends AppCompatActivity implements Generators.GeneratorUpdatedListener { private DataPointsAdapter mAdapter = null; private Menu mMenu = null; + private boolean mIsUpdating = false; protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -28,8 +30,11 @@ protected void onCreate(Bundle savedInstanceState) { this.setTitle(R.string.activity_data_stream); this.getSupportActionBar().setSubtitle(this.getResources().getQuantityString(R.plurals.activity_data_stream_subtitle, 0, 0)); + this.getSupportActionBar().setDisplayHomeAsUpEnabled(true); + this.mAdapter = new DataPointsAdapter(); this.mAdapter.setContext(this.getApplicationContext()); + this.mAdapter.sortGenerators(); RecyclerView listView = (RecyclerView) this.findViewById(R.id.list_view); @@ -67,12 +72,21 @@ protected void onPause() { public void onGeneratorUpdated(String identifier, long timestamp, Bundle data) { final DataStreamActivity me = this; + if (me.mIsUpdating) { + return; + } + + me.mIsUpdating = true; + this.runOnUiThread(new Runnable() { @Override public void run() { + me.mAdapter.sortGenerators(); me.mAdapter.notifyDataSetChanged(); int count = me.mAdapter.getItemCount(); me.getSupportActionBar().setSubtitle(me.getResources().getQuantityString(R.plurals.activity_data_stream_subtitle, count, count)); + + me.mIsUpdating = false; } }); } @@ -83,20 +97,29 @@ public boolean onCreateOptionsMenu(Menu menu) { this.mMenu = menu; + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); + boolean sortEnabled = prefs.getBoolean(DataPointsAdapter.SORT_BY_UPDATED, DataPointsAdapter.SORT_BY_UPDATED_DEFAULT); + + MenuItem lockedItem = this.mMenu.findItem(R.id.action_pdk_toggle_sort_lock); + + if (sortEnabled) { + lockedItem.setIcon(R.drawable.ic_pdk_action_unlock); + } else { + lockedItem.setIcon(R.drawable.ic_pdk_action_lock); + } + return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { - // Handle action bar item clicks here. The action bar will - // automatically handle clicks on the Home/Up button, so long - // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); - //noinspection SimplifiableIfStatement - if (id == R.id.action_pdk_toggle_sort_lock) { + if (id == android.R.id.home) { + this.finish(); + return true; + } else if (id == R.id.action_pdk_toggle_sort_lock) { this.toggleSortLock(); - return true; } @@ -106,20 +129,20 @@ public boolean onOptionsItemSelected(MenuItem item) { private void toggleSortLock() { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); - boolean locked = prefs.getBoolean(DataPointsAdapter.SORT_BY_UPDATED, DataPointsAdapter.SORT_BY_UPDATED_DEFAULT); + boolean sortEnabled = prefs.getBoolean(DataPointsAdapter.SORT_BY_UPDATED, DataPointsAdapter.SORT_BY_UPDATED_DEFAULT); MenuItem lockedItem = this.mMenu.findItem(R.id.action_pdk_toggle_sort_lock); - if (locked) { - lockedItem.setIcon(R.drawable.ic_pdk_action_unlock); - } else { + if (sortEnabled) { lockedItem.setIcon(R.drawable.ic_pdk_action_lock); + } else { + lockedItem.setIcon(R.drawable.ic_pdk_action_unlock); } SharedPreferences.Editor e = prefs.edit(); - e.putBoolean(DataPointsAdapter.SORT_BY_UPDATED, (locked == false)); + e.putBoolean(DataPointsAdapter.SORT_BY_UPDATED, (sortEnabled == false)); e.apply(); - this.mAdapter.notifyDataSetChanged(); + this.mAdapter.sortGenerators(); } } 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 38cffc3..5c11fd8 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 @@ -24,6 +24,7 @@ public class DataPointsAdapter extends RecyclerView.Adapter public static final boolean SORT_BY_UPDATED_DEFAULT = true; private Context mContext = null; + private List> mActiveGenerators = null; @Override public DataPointViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { @@ -55,13 +56,21 @@ public DataPointViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { return null; } + private List> getGenerators(Context context) { + if (this.mActiveGenerators == null) { + this.mActiveGenerators = Generators.getInstance(context).activeGenerators(); + } + + this.sortGenerators(); + + return this.mActiveGenerators; + } + @Override public void onBindViewHolder(final DataPointViewHolder holder, int position) { - List> activeGenerators = Generators.getInstance(holder.itemView.getContext()).activeGenerators(); - - this.sortGenerators(this.mContext, activeGenerators); + this.getGenerators(holder.itemView.getContext()); - Class generatorClass = activeGenerators.get(position); + Class generatorClass = this.mActiveGenerators.get(position); try { Method bindViewHolder = generatorClass.getDeclaredMethod("bindViewHolder", DataPointViewHolder.class); @@ -86,14 +95,24 @@ public void onBindViewHolder(final DataPointViewHolder holder, int position) { @Override public int getItemCount() { - return Generators.getInstance(null).activeGenerators().size(); + this.getGenerators(this.mContext); + + return this.mActiveGenerators.size(); } - private void sortGenerators(final Context context, List> generators) { + public void sortGenerators() { + final Context context = this.mContext; + + if (this.mActiveGenerators == null) { + this.mActiveGenerators = Generators.getInstance(this.mContext).activeGenerators(); + } + + final DataPointsAdapter me = this; + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); if (prefs.getBoolean(DataPointsAdapter.SORT_BY_UPDATED, DataPointsAdapter.SORT_BY_UPDATED_DEFAULT)) { - Collections.sort(generators, new Comparator>() { + Collections.sort(me.mActiveGenerators, new Comparator>() { @Override public int compare(Class one, Class two) { long oneUpdated = 0; @@ -133,22 +152,13 @@ public int compare(Class one, Class tw return 0; } }); - } else { - Collections.sort(generators, new Comparator>() { - @Override - public int compare(Class one, Class two) { - return one.getCanonicalName().compareTo(two.getCanonicalName()); - } - }); } } public int getItemViewType (int position) { - List> activeGenerators = Generators.getInstance(this.mContext).activeGenerators(); - - this.sortGenerators(this.mContext, activeGenerators); + this.getGenerators(this.mContext); - Class generatorClass = activeGenerators.get(position); + Class generatorClass = this.mActiveGenerators.get(position); return generatorClass.hashCode(); } diff --git a/src/com/audacious_software/passive_data_kit/generators/device/Battery.java b/src/com/audacious_software/passive_data_kit/generators/device/Battery.java index 6fead94..d652be9 100755 --- a/src/com/audacious_software/passive_data_kit/generators/device/Battery.java +++ b/src/com/audacious_software/passive_data_kit/generators/device/Battery.java @@ -11,6 +11,7 @@ import android.os.BatteryManager; import android.os.Bundle; import android.support.v4.content.ContextCompat; +import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -91,6 +92,8 @@ public class Battery extends Generator { private SQLiteDatabase mDatabase = null; + private long mLastTimestamp = 0; + public static Battery getInstance(Context context) { if (Battery.sInstance == null) { Battery.sInstance = new Battery(context.getApplicationContext()); @@ -110,11 +113,13 @@ public static void start(final Context context) { private void startGenerator() { final Battery me = this; + final long now = System.currentTimeMillis(); + + me.mLastTimestamp = now; + this.mReceiver = new BroadcastReceiver() { @Override public void onReceive(final Context context, Intent intent) { - long now = System.currentTimeMillis(); - ContentValues values = new ContentValues(); values.put(Battery.HISTORY_OBSERVED, now); @@ -271,6 +276,8 @@ public static void bindViewHolder(DataPointViewHolder holder) { Cursor c = generator.mDatabase.query(Battery.TABLE_HISTORY, null, where, args, null, null, Battery.HISTORY_OBSERVED + " DESC"); + Log.e("PDK", "BATTERY COUNT: " + c.getCount()); + 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); @@ -334,9 +341,12 @@ public String getFormattedValue(float value, AxisBase axis) { long lastLevel = -1; + int observedIndex = c.getColumnIndex(Battery.HISTORY_OBSERVED); + int levelIndex = c.getColumnIndex(Battery.HISTORY_LEVEL); + while (c.moveToNext()) { - long when = c.getLong(c.getColumnIndex(Battery.HISTORY_OBSERVED)); - long level = c.getLong(c.getColumnIndex(Battery.HISTORY_LEVEL)); + long when = c.getLong(observedIndex); + long level = c.getLong(levelIndex); if (level != lastLevel) { values.add(0, new Entry(when, level)); @@ -379,19 +389,19 @@ public List fetchPayloads() { } public static long latestPointGenerated(Context context) { - long timestamp = 0; - Battery me = Battery.getInstance(context); - Cursor c = me.mDatabase.query(Battery.TABLE_HISTORY, null, null, null, null, null, Battery.HISTORY_OBSERVED + " DESC"); + if (me.mLastTimestamp == 0) { + Cursor c = me.mDatabase.query(Battery.TABLE_HISTORY, null, null, null, null, null, Battery.HISTORY_OBSERVED + " DESC"); - if (c.moveToNext()) { - timestamp = c.getLong(c.getColumnIndex(Battery.HISTORY_OBSERVED)); - } + if (c.moveToNext()) { + me.mLastTimestamp = c.getLong(c.getColumnIndex(Battery.HISTORY_OBSERVED)); + } - c.close(); + c.close(); + } - return timestamp; + return me.mLastTimestamp; } public Cursor queryHistory(String[] cols, String where, String[] args, String orderBy) { diff --git a/src/com/audacious_software/passive_data_kit/generators/device/ForegroundApplication.java b/src/com/audacious_software/passive_data_kit/generators/device/ForegroundApplication.java index 90f4620..c664a3a 100755 --- a/src/com/audacious_software/passive_data_kit/generators/device/ForegroundApplication.java +++ b/src/com/audacious_software/passive_data_kit/generators/device/ForegroundApplication.java @@ -65,6 +65,7 @@ public class ForegroundApplication extends Generator{ private SQLiteDatabase mDatabase = null; private long mSampleInterval = 15000; private AppChecker mAppChecker = null; + private long mLastTimestamp = 0; public static ForegroundApplication getInstance(Context context) { if (ForegroundApplication.sInstance == null) { @@ -389,18 +390,18 @@ public static View fetchView(ViewGroup parent) } public static long latestPointGenerated(Context context) { - long timestamp = 0; - ForegroundApplication me = ForegroundApplication.getInstance(context); - Cursor c = me.mDatabase.query(ForegroundApplication.TABLE_HISTORY, null, null, null, null, null, ForegroundApplication.HISTORY_OBSERVED + " DESC"); + if (me.mLastTimestamp == 0) { + Cursor c = me.mDatabase.query(ForegroundApplication.TABLE_HISTORY, null, null, null, null, null, ForegroundApplication.HISTORY_OBSERVED + " DESC"); - if (c.moveToNext()) { - timestamp = c.getLong(c.getColumnIndex(ForegroundApplication.HISTORY_OBSERVED)); - } + if (c.moveToNext()) { + me.mLastTimestamp = c.getLong(c.getColumnIndex(ForegroundApplication.HISTORY_OBSERVED)); + } - c.close(); + c.close(); + } - return timestamp; + return me.mLastTimestamp; } } diff --git a/src/com/audacious_software/passive_data_kit/generators/sensors/Accelerometer.java b/src/com/audacious_software/passive_data_kit/generators/sensors/Accelerometer.java index 93e805d..823e776 100755 --- a/src/com/audacious_software/passive_data_kit/generators/sensors/Accelerometer.java +++ b/src/com/audacious_software/passive_data_kit/generators/sensors/Accelerometer.java @@ -210,14 +210,12 @@ public static ArrayList diagnostics(Context context) { public static void bindViewHolder(final DataPointViewHolder holder) { if (Accelerometer.sIsDrawing) { - Log.e("PDK", "IS DRAWING"); return; } final long drawStart = System.currentTimeMillis(); if (drawStart - Accelerometer.sLastDrawStart < (30 * 1000)) { - Log.e("PDK", "TOO SOON"); return; } @@ -225,8 +223,6 @@ public static void bindViewHolder(final DataPointViewHolder holder) { Accelerometer.sIsDrawing = true; - Log.e("PDK", "HOLDER " + holder.hashCode()); - final Context context = holder.itemView.getContext(); final View itemView = holder.itemView; @@ -235,31 +231,19 @@ public static void bindViewHolder(final DataPointViewHolder holder) { final long now = System.currentTimeMillis() / (1000 * 60 * 5); final long start = now - (24 * 12); // * 60); - Log.e("PDK", "START QUERY: " + (System.currentTimeMillis() - drawStart)); - - Cursor c = generator.mDatabase.query(Accelerometer.TABLE_HISTORY, null, null, null, null, null, Accelerometer.HISTORY_OBSERVED + " DESC"); - - Log.e("PDK", "END QUERY: " + (System.currentTimeMillis() - drawStart)); - View cardContent = itemView.findViewById(R.id.card_content); View cardEmpty = itemView.findViewById(R.id.card_empty); TextView dateLabel = (TextView) itemView.findViewById(R.id.generator_data_point_date); - Log.e("PDK", "ACCEL PREP: " + (System.currentTimeMillis() - drawStart) + " -- COUNT: " + c.getCount()); - - if (c.moveToNext() && (context instanceof Activity)) { + if (context instanceof Activity) { cardContent.setVisibility(View.VISIBLE); cardEmpty.setVisibility(View.GONE); - long timestamp = c.getLong(c.getColumnIndex(Accelerometer.HISTORY_OBSERVED)) / (1000 * 1000 * 1000); - - dateLabel.setText(Generator.formatTimestamp(context, timestamp)); + dateLabel.setText(Generator.formatTimestamp(context, Accelerometer.latestPointGenerated(generator.mContext) / 1000)); Runnable r = new Runnable() { @Override public void run() { - Log.e("PDK", "THREAD START: " + (System.currentTimeMillis() - drawStart)); - final ArrayList xLowValues = new ArrayList<>(); final ArrayList xHighValues = new ArrayList<>(); @@ -270,7 +254,7 @@ public void run() { final ArrayList zHighValues = new ArrayList<>(); final String where = Accelerometer.HISTORY_OBSERVED + " >= ? AND _id % 1024 = 0"; - final String[] args = { "" + start }; + final String[] args = { "" + (System.currentTimeMillis() - (24 * 60 * 60 * 1000)) }; Cursor c = generator.mDatabase.query(Accelerometer.TABLE_HISTORY, null, where, args, null, null, Accelerometer.HISTORY_OBSERVED + " DESC"); @@ -293,9 +277,6 @@ public void run() { int yIndex = c.getColumnIndex(Accelerometer.HISTORY_Y); int zIndex = c.getColumnIndex(Accelerometer.HISTORY_Z); - Log.e("PDK", "COUNT: " + c.getCount()); - Log.e("PDK", "ACCEL START BUILD: " + (System.currentTimeMillis() - drawStart)); - while (c.moveToNext()) { long when = c.getLong(whenIndex); @@ -379,10 +360,6 @@ public void run() { } } - Log.e("PDK", "ACCEL END BUILD BUILD: " + (System.currentTimeMillis() - drawStart)); - - Log.e("PDK", "DATA COUNT: " + xLowValues.size()); - if (lastTimestamp != -1) { xLowValues.add(0, new Entry(lastTimestamp, lowX)); xHighValues.add(0, new Entry(lastTimestamp, highX)); @@ -401,8 +378,6 @@ public void run() { final float finalMaxValue = maxValue; final float finalMinValue = minValue; - Log.e("PDK", "THREAD HANDOFF: " + (System.currentTimeMillis() - drawStart)); - final List> data = new ArrayList<>(); data.add(xLowValues); data.add(xHighValues); @@ -414,8 +389,6 @@ public void run() { activity.runOnUiThread(new Runnable() { @Override public void run() { - Log.e("PDK", "UI START: " + (System.currentTimeMillis() - drawStart)); - int[] colors = { R.color.generator_accelerometer_x_low, R.color.generator_accelerometer_x_high, @@ -447,8 +420,6 @@ public void run() { chartData.addDataSet(set); } - Log.e("PDK", "ACCEL START GRAPH: " + (System.currentTimeMillis() - drawStart)); - final LineChart chart = (LineChart) itemView.findViewById(R.id.accelerometer_chart); if (chart != null) { @@ -498,18 +469,14 @@ public String getFormattedValue(float value, AxisBase axis) { chart.setData(chartData); } - Log.e("PDK", "UI END: " + (System.currentTimeMillis() - drawStart)); - Accelerometer.sIsDrawing = false; } }); } }; - Thread t = new Thread(r, "render_accelerometer_graph"); + Thread t = new Thread(r, "render-accelerometer-graph"); t.start(); - - c.close(); } else { cardContent.setVisibility(View.GONE); cardEmpty.setVisibility(View.VISIBLE); @@ -517,8 +484,6 @@ public String getFormattedValue(float value, AxisBase axis) { dateLabel.setText(R.string.label_never_pdk); } - c.close(); - Log.e("PDK", "MAIN DONE: " + (System.currentTimeMillis() - drawStart)); } @@ -536,10 +501,10 @@ public static long latestPointGenerated(Context context) { Accelerometer me = Accelerometer.getInstance(context); if (me.mLatestTimestamp == 0) { - Cursor c = me.mDatabase.query(Accelerometer.TABLE_HISTORY, null, null, null, null, null, Accelerometer.HISTORY_OBSERVED + " DESC"); + Cursor c = me.mDatabase.query(Accelerometer.TABLE_HISTORY, null, null, null, null, null, Accelerometer.HISTORY_OBSERVED + " DESC", "1"); if (c.moveToNext()) { - me.mLatestTimestamp = c.getLong(c.getColumnIndex(Accelerometer.HISTORY_OBSERVED) / (1000 * 1000)); + me.mLatestTimestamp = c.getLong(c.getColumnIndex(Accelerometer.HISTORY_OBSERVED) / 1000); } c.close(); diff --git a/src/com/audacious_software/passive_data_kit/generators/sensors/AmbientLight.java b/src/com/audacious_software/passive_data_kit/generators/sensors/AmbientLight.java index cba3bc2..eee9a3b 100755 --- a/src/com/audacious_software/passive_data_kit/generators/sensors/AmbientLight.java +++ b/src/com/audacious_software/passive_data_kit/generators/sensors/AmbientLight.java @@ -1,5 +1,6 @@ package com.audacious_software.passive_data_kit.generators.sensors; +import android.app.Activity; import android.content.ContentValues; import android.content.Context; import android.content.SharedPreferences; @@ -14,6 +15,7 @@ import android.os.Handler; import android.os.Looper; import android.support.v4.content.ContextCompat; +import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -62,6 +64,8 @@ public class AmbientLight extends SensorGenerator implements SensorEventListener private static AmbientLight sInstance = null; private static Handler sHandler = null; + private static boolean sIsDrawing = false; + private static long sLastDrawStart = 0; private SQLiteDatabase mDatabase = null; @@ -194,166 +198,206 @@ public static ArrayList diagnostics(Context context) { return new ArrayList<>(); } - public static void bindViewHolder(DataPointViewHolder holder) { - final Context context = holder.itemView.getContext(); + public static void bindViewHolder(final DataPointViewHolder holder) { + if (AmbientLight.sIsDrawing) { + return; + } - AmbientLight generator = AmbientLight.getInstance(context); + final long drawStart = System.currentTimeMillis(); + + if (drawStart - AmbientLight.sLastDrawStart < (30 * 1000)) { + return; + } - long now = System.currentTimeMillis() / (1000 * 60 * 5); - long start = now - (24 * 12); // * 60); + AmbientLight.sLastDrawStart = drawStart; + + AmbientLight.sIsDrawing = true; + + final Context context = holder.itemView.getContext(); - String where = AmbientLight.HISTORY_OBSERVED + " >= ?"; - String[] args = { "" + start }; + final AmbientLight generator = AmbientLight.getInstance(context); - Cursor c = generator.mDatabase.query(AmbientLight.TABLE_HISTORY, null, where, args, null, null, AmbientLight.HISTORY_OBSERVED + " DESC"); + final long now = System.currentTimeMillis() / (1000 * 60 * 5); + final long start = now - (24 * 12); // * 60); 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 (c.moveToNext()) { + if (context instanceof Activity) { cardContent.setVisibility(View.VISIBLE); cardEmpty.setVisibility(View.GONE); - long timestamp = c.getLong(c.getColumnIndex(AmbientLight.HISTORY_OBSERVED)) / (1000 * 1000 * 1000); - - dateLabel.setText(Generator.formatTimestamp(context, timestamp)); - - c.moveToPrevious(); - - final LineChart chart = (LineChart) holder.itemView.findViewById(R.id.light_chart); - chart.setViewPortOffsets(0,0,0,0); - chart.setHighlightPerDragEnabled(false); - chart.setHighlightPerTapEnabled(false); - chart.setBackgroundColor(ContextCompat.getColor(context, android.R.color.black)); - chart.setPinchZoom(false); - - final DateFormat timeFormat = android.text.format.DateFormat.getTimeFormat(context); - - final XAxis xAxis = chart.getXAxis(); - xAxis.setPosition(XAxis.XAxisPosition.BOTTOM_INSIDE); - xAxis.setTextSize(10f); - xAxis.setDrawAxisLine(true); - xAxis.setDrawGridLines(true); - xAxis.setCenterAxisLabels(true); - xAxis.setDrawLabels(true); - xAxis.setTextColor(ContextCompat.getColor(context, android.R.color.white)); - xAxis.setGranularityEnabled(true); - xAxis.setGranularity(1); - xAxis.setAxisMinimum(start); - xAxis.setAxisMaximum(now); - xAxis.setValueFormatter(new IAxisValueFormatter() { + dateLabel.setText(Generator.formatTimestamp(context, AmbientLight.latestPointGenerated(context) / 1000)); + + Runnable r = new Runnable() { @Override - public String getFormattedValue(float value, AxisBase axis) { - Date date = new Date((long) value * 5 * 60 * 1000); + public void run() { + final ArrayList lowValues = new ArrayList<>(); + final ArrayList highValues = new ArrayList<>(); - return timeFormat.format(date); - } - }); + long lastTimestamp = -1; - YAxis leftAxis = chart.getAxisLeft(); - leftAxis.setPosition(YAxis.YAxisLabelPosition.INSIDE_CHART); - leftAxis.setDrawGridLines(true); - leftAxis.setDrawAxisLine(true); - leftAxis.setGranularityEnabled(true); - leftAxis.setTextColor(ContextCompat.getColor(context, android.R.color.white)); + float maxValue = 0; + float minValue = 0; - YAxis rightAxis = chart.getAxisRight(); - rightAxis.setEnabled(false); + float lowLevel = -1; + float highLevel = -1; - chart.getLegend().setEnabled(false); - chart.getDescription().setEnabled(false); + final String where = Accelerometer.HISTORY_OBSERVED + " >= ? AND _id"; + final String[] args = { "" + (System.currentTimeMillis() - (24 * 60 * 60 * 1000)) }; - ArrayList lowValues = new ArrayList<>(); - ArrayList highValues = new ArrayList<>(); + Cursor c = generator.mDatabase.query(AmbientLight.TABLE_HISTORY, null, where, args, null, null, AmbientLight.HISTORY_OBSERVED + " DESC"); - long lastTimestamp = -1; + while (c.moveToNext()) { + long when = c.getLong(c.getColumnIndex(AmbientLight.HISTORY_OBSERVED)); - float maxValue = 0; - float minValue = 0; + when = when / (1000 * 1000); + when = when / (1000 * 6 * 50); - float lowLevel = -1; - float highLevel = -1; + float level = c.getFloat(c.getColumnIndex(AmbientLight.HISTORY_LEVEL)); - while (c.moveToNext()) { - long when = c.getLong(c.getColumnIndex(AmbientLight.HISTORY_OBSERVED)); + if (level < 0.001) { + level = 0.001f; + } - when = when / (1000 * 1000); - when = when / (1000 * 6 * 50); + level = (float) Math.log10(level); - float level = c.getFloat(c.getColumnIndex(AmbientLight.HISTORY_LEVEL)); + if (lastTimestamp != when) { + if (lastTimestamp != -1) { + lowValues.add(0, new Entry(lastTimestamp, lowLevel)); + highValues.add(0, new Entry(lastTimestamp, highLevel)); + } - if (lastTimestamp != when) { - if (lastTimestamp != -1) { - lowValues.add(0, new Entry(lastTimestamp, lowLevel)); - highValues.add(0, new Entry(lastTimestamp, highLevel)); - } + lastTimestamp = when; + lowLevel = level; + highLevel = level; + } else { + if (level < lowLevel) { + lowLevel = level; + } - lastTimestamp = when; - lowLevel = level; - highLevel = level; - } else { - if (level < lowLevel) { - lowLevel = level; - } + if (level > highLevel) { + highLevel = level; + } + } - if (level > highLevel) { - highLevel = level; + if (level > maxValue) { + maxValue = level; + } + + if (level < minValue) { + minValue = level; + } } - } - if (level > maxValue) { - maxValue = level; - } + if (lastTimestamp != -1) { + lowValues.add(0, new Entry(lastTimestamp, lowLevel)); + highValues.add(0, new Entry(lastTimestamp, highLevel)); + } - if (level < minValue) { - minValue = level; + final float finalMaxValue = maxValue; + final float finalMinValue = minValue; + + Activity activity = (Activity) context; + + activity.runOnUiThread(new Runnable() { + @Override + public void run() { + final LineChart chart = (LineChart) holder.itemView.findViewById(R.id.light_chart); + chart.setViewPortOffsets(0,0,0,0); + chart.setHighlightPerDragEnabled(false); + chart.setHighlightPerTapEnabled(false); + chart.setBackgroundColor(ContextCompat.getColor(context, android.R.color.black)); + chart.setPinchZoom(false); + + final DateFormat timeFormat = android.text.format.DateFormat.getTimeFormat(context); + + final XAxis xAxis = chart.getXAxis(); + xAxis.setPosition(XAxis.XAxisPosition.BOTTOM_INSIDE); + xAxis.setTextSize(10f); + xAxis.setDrawAxisLine(true); + xAxis.setDrawGridLines(true); + xAxis.setCenterAxisLabels(true); + xAxis.setDrawLabels(true); + xAxis.setTextColor(ContextCompat.getColor(context, android.R.color.white)); + xAxis.setGranularityEnabled(true); + xAxis.setGranularity(1); + xAxis.setAxisMinimum(start); + xAxis.setAxisMaximum(now); + xAxis.setValueFormatter(new IAxisValueFormatter() { + @Override + public String getFormattedValue(float value, AxisBase axis) { + Date date = new Date((long) value * 5 * 60 * 1000); + + return timeFormat.format(date); + } + }); + + YAxis leftAxis = chart.getAxisLeft(); + leftAxis.setPosition(YAxis.YAxisLabelPosition.INSIDE_CHART); + leftAxis.setDrawGridLines(true); + leftAxis.setDrawAxisLine(true); + leftAxis.setGranularityEnabled(true); + leftAxis.setTextColor(ContextCompat.getColor(context, android.R.color.white)); + leftAxis.setValueFormatter(new IAxisValueFormatter() { + @Override + public String getFormattedValue(float value, AxisBase axis) { + return "" + Math.pow(10, value); + } + }); + + YAxis rightAxis = chart.getAxisRight(); + rightAxis.setEnabled(false); + + chart.getLegend().setEnabled(false); + chart.getDescription().setEnabled(false); + + LineDataSet set = new LineDataSet(lowValues, "Low Light Levels"); + set.setAxisDependency(YAxis.AxisDependency.LEFT); + set.setLineWidth(1.0f); + set.setDrawCircles(false); + set.setFillAlpha(192); + set.setDrawFilled(false); + set.setDrawValues(true); + set.setColor(ContextCompat.getColor(context, R.color.generator_ambient_light_low)); + set.setDrawCircleHole(false); + set.setDrawValues(false); + set.setMode(LineDataSet.Mode.LINEAR); + + LineData chartData = new LineData(set); + + set = new LineDataSet(highValues, "High Light Levels"); + set.setAxisDependency(YAxis.AxisDependency.LEFT); + set.setLineWidth(1.0f); + set.setDrawCircles(false); + set.setFillAlpha(192); + set.setDrawFilled(false); + set.setDrawValues(true); + set.setColor(ContextCompat.getColor(context, R.color.generator_ambient_light_high)); + set.setDrawCircleHole(false); + set.setDrawValues(false); + set.setMode(LineDataSet.Mode.LINEAR); + + chartData.addDataSet(set); + + chart.setVisibleYRange((float) Math.floor(finalMinValue) - 1, (float) Math.ceil(finalMaxValue) + 1, YAxis.AxisDependency.LEFT); + chart.setData(chartData); + + AmbientLight.sIsDrawing = false; + } + }); } - } - - if (lastTimestamp != -1) { - lowValues.add(0, new Entry(lastTimestamp, lowLevel)); - highValues.add(0, new Entry(lastTimestamp, highLevel)); - } + }; - LineDataSet set = new LineDataSet(lowValues, "Low Light Levels"); - set.setAxisDependency(YAxis.AxisDependency.LEFT); - set.setLineWidth(1.0f); - set.setDrawCircles(false); - set.setFillAlpha(192); - set.setDrawFilled(false); - set.setDrawValues(true); - set.setColor(ContextCompat.getColor(context, R.color.generator_ambient_light_low)); - set.setDrawCircleHole(false); - set.setDrawValues(false); - set.setMode(LineDataSet.Mode.LINEAR); - - LineData chartData = new LineData(set); - - set = new LineDataSet(highValues, "High Light Levels"); - set.setAxisDependency(YAxis.AxisDependency.LEFT); - set.setLineWidth(1.0f); - set.setDrawCircles(false); - set.setFillAlpha(192); - set.setDrawFilled(false); - set.setDrawValues(true); - set.setColor(ContextCompat.getColor(context, R.color.generator_ambient_light_high)); - set.setDrawCircleHole(false); - set.setDrawValues(false); - set.setMode(LineDataSet.Mode.LINEAR); - - chartData.addDataSet(set); - - chart.setVisibleYRange((float) Math.floor(minValue) - 1, (float) Math.ceil(maxValue) + 1, YAxis.AxisDependency.LEFT); - chart.setData(chartData); + Thread t = new Thread(r, "render-ambient-light-graph"); + t.start(); } else { cardContent.setVisibility(View.GONE); cardEmpty.setVisibility(View.VISIBLE); dateLabel.setText(R.string.label_never_pdk); } - - c.close(); } public static View fetchView(ViewGroup parent) @@ -370,7 +414,7 @@ public static long latestPointGenerated(Context context) { AmbientLight me = AmbientLight.getInstance(context); if (me.mLatestTimestamp == 0) { - Cursor c = me.mDatabase.query(AmbientLight.TABLE_HISTORY, null, null, null, null, null, Accelerometer.HISTORY_OBSERVED + " DESC"); + Cursor c = me.mDatabase.query(AmbientLight.TABLE_HISTORY, null, null, null, null, null, Accelerometer.HISTORY_OBSERVED + " DESC", "1"); if (c.moveToNext()) { me.mLatestTimestamp = c.getLong(c.getColumnIndex(Accelerometer.HISTORY_OBSERVED) / (1000 * 1000));