Android Open Source - humiditytracker Show Records Activity






From Project

Back to project page humiditytracker.

License

The source code is released under:

GNU General Public License

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

Java Source Code

/*
This file is part of leafdigital Humidity tracker.
/*from   w ww  . jav  a  2 s  . c om*/
Humidity tracker is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Humidity tracker is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with Humidity tracker. If not, see <http://www.gnu.org/licenses/>.

Copyright 2010 Samuel Marshall.
*/
package com.leafdigital.humidity;

import java.text.SimpleDateFormat;
import java.util.Date;

import com.leafdigital.humidity.ClimateData.FieldValue;

import android.app.*;
import android.app.AlertDialog.Builder;
import android.content.*;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.*;
import android.os.Bundle;
import android.text.*;
import android.util.*;
import android.view.*;
import android.view.View.OnClickListener;
import android.widget.*;
import android.widget.LinearLayout.LayoutParams;

import static com.leafdigital.humidity.ClimateData.*;
import static com.leafdigital.humidity.HumidityActivity.*;

public class ShowRecordsActivity extends Activity
{
  private int bank;
  private DataPoint[] data;
  private RecordsGraph graph;
  private int graphField;

  private int nearestPointIndex;

  private final static String PREFS_CURRENT_GRAPH = "currentGraph";

  public final static float[] MAX_RANGE = { 40.0f, 100.0f, 40.0f, 50.0f };
  public final static float[] RANGE_STEP = { 5.0f, 5.0f, 5.0f, 5.0f };
  public final static int[] FIELD_LABEL = { R.string.temp, R.string.humidity,
    R.string.dewpoint, R.string.density };
  public final static int[] FIELD_UNIT = { R.string.degreesc, R.string.percent,
    R.string.degreesc, R.string.gm3 };

  private final static float HIT_RADIUS = 48;
  private final static float GRAPH_PADDING = 10;

  private final static long ONE_DAY = 24L * 3600L * 1000L;

  private final static int DIALOG_POINT=1, DIALOG_NAME=2, DIALOG_DELETE=3;

  private static class DataPoint
  {
    long javaTime;
    ClimateData data;

    private DataPoint(long javaTime, ClimateData data)
    {
      this.javaTime = javaTime;
      this.data = data;
    }
  }

  private class RecordsGraph extends View
  {
    private float xScale, yScale, left, bottom, density;
    private long startTime;

    public RecordsGraph()
    {
      super(ShowRecordsActivity.this);
      setLayoutParams(new LinearLayout.LayoutParams(
        LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT, 1.0f));
    }

    @Override
    public boolean onTouchEvent(MotionEvent event)
    {
      switch(event.getAction())
      {
      case MotionEvent.ACTION_DOWN:
      case MotionEvent.ACTION_MOVE:
        updateNearestPoint(event.getX(), event.getY());
        return true;
      case MotionEvent.ACTION_UP:
        updateNearestPoint(event.getX(), event.getY());
        if(nearestPointIndex != -1)
        {
          showDialog(DIALOG_POINT);
        }
        nearestPointIndex = -1;
        invalidate();
        return true;
      }
      return false;
    }

    private void updateNearestPoint(float x, float y)
    {
      // Crap algorithm, but let's just try all the points within any kind of
      // range.
      float radius = HIT_RADIUS * density;
      float bestDiff = radius * radius;
      int bestIndex = -1;
      for(int i=0; i<data.length; i++)
      {
        // Get X point and check if within range
        float pointX = (float)(data[i].javaTime - startTime) * xScale + left;
        if (pointX > x + radius)
        {
          break;
        }
        if (pointX < x - radius)
        {
          continue;
        }

        // Find Y point
        FieldValue field = data[i].data.getField(graphField);
        float pointY = bottom - field.getMeasured() * yScale;

        // Work out difference (= distance squared)
        float diff = (pointY - y) * (pointY - y) + (pointX - x) * (pointX - x);
        if (diff < bestDiff)
        {
          bestDiff = diff;
          bestIndex = i;
        }
      }

      if(bestIndex != nearestPointIndex)
      {
        nearestPointIndex = bestIndex;
        invalidate();
      }
    }

    @Override
    protected void onDraw(Canvas canvas)
    {
      DisplayMetrics metrics = new DisplayMetrics();
      getWindowManager().getDefaultDisplay().getMetrics(metrics);
      density = metrics.density;
      float blobRadius = 2f * density;
      float padding = GRAPH_PADDING * density;

      // Clear to off-black
      canvas.drawColor(Color.argb(255, 30, 30, 30));

      // Get available width and height for graph
      float w = getWidth() - padding*2, h = getHeight() - padding*2;
      left = padding;
      bottom = getHeight() - padding;

      // Draw axes in grey
      Paint grey = new Paint(Paint.ANTI_ALIAS_FLAG);
      grey.setColor(Color.argb(255, 128, 128, 128));
      canvas.drawLine(left, bottom, left+w, bottom, grey);
      canvas.drawLine(left, bottom, left, bottom-h, grey);
      canvas.drawLine(left, bottom-h, left+ 1.5f*blobRadius, bottom-h, grey);

      // Work out Y scaling
      float actualMax = 0;
      for(int i=0; i<data.length; i++)
      {
        float value = data[i].data.getField(graphField).getMax();
        if(value > actualMax)
        {
          actualMax = value;
        }
      }
      float range = MAX_RANGE[graphField];
      if(data.length == 0)
      {
        actualMax = range;
      }
      while(range - RANGE_STEP[graphField] > actualMax)
      {
        range -= RANGE_STEP[graphField];
      }

      yScale = h / range;

      // Draw scale text
      String max = String.format("%.0f", range);
      grey.setTextSize(12f * density);
      Rect bounds = new Rect();
      grey.getTextBounds(max, 0, max.length(), bounds);
      canvas.drawText(max, left + blobRadius * 2 * density,
        bottom - h - bounds.top, grey);

      // If there is no data, stop here
      if(data.length == 0)
      {
        return;
      }

      // Work out X scaling
      startTime = data[0].javaTime;
      long timeRange = data[data.length - 1].javaTime - startTime;
      if(timeRange == 0)
      {
        timeRange = 1;
      }
      xScale = w / (float)timeRange;

      // Draw each point
      Paint white = new Paint(Paint.ANTI_ALIAS_FLAG);
      white.setColor(Color.argb(255, 255, 255, 255));
      Paint faintLine = new Paint(Paint.ANTI_ALIAS_FLAG);
      faintLine.setColor(Color.argb(160, 0, 255, 0));
      for(int i=0; i<data.length; i++)
      {
        float x = (float)(data[i].javaTime - startTime) * xScale;
        FieldValue field = data[i].data.getField(graphField);
        float yMin = field.getMin() * yScale, yMax = field.getMax() * yScale;
        float y = field.getMeasured() * yScale;
        if (i==nearestPointIndex)
        {
          Paint faint = new Paint(Paint.ANTI_ALIAS_FLAG);
          faint.setColor(Color.argb(64,255,255,255));
          canvas.drawCircle(x + left, bottom - y, blobRadius*20, faint);
        }

        canvas.drawLine(x + left, bottom - yMin, x + left, bottom - yMax, faintLine);
        canvas.drawCircle(x + left, bottom - y, blobRadius, white);
      }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
    {
      int w;
      if(MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.UNSPECIFIED)
      {
        w = 100;
      }
      else
      {
        w = MeasureSpec.getSize(widthMeasureSpec);
      }

      int h;
      if(MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.UNSPECIFIED)
      {
        h = 100;
      }
      else
      {
        h = MeasureSpec.getSize(heightMeasureSpec);
      }
      setMeasuredDimension(w, h);
    }
  }

  /** Called when the activity is first created. */
  @Override
  public void onCreate(Bundle savedInstanceState)
  {
    super.onCreate(savedInstanceState);

    // Get current bank and set title
    bank = getIntent().getIntExtra(HumidityActivity.EXTRA_SAVEBANK, -1);

    loadData();

    setContentView(R.layout.showrecords);
    LinearLayout layout = (LinearLayout)findViewById(R.id.layout);

    graph = new RecordsGraph();
    layout.addView(graph, 0);

    // Get default field
    setField(getSharedPreferences("com.leafdigital.humidity", MODE_PRIVATE).getInt(
      PREFS_CURRENT_GRAPH, FIELD_HUMIDITY));
  }

  private void loadData()
  {
    // Load records. (Note: This uses a writable database because it might need
    // to do a db version update, so it has to be able to write)
    SQLiteDatabase db = new RecordsOpenHelper(this).getWritableDatabase();
    Cursor cursor = db.query(
      "readings", new String[] {  "javatime", "temperature", "temperature_error",
        "humidity", "humidity_error" },
      "bank = ?",  new String[] { bank + "" },  null, null, "javatime");
    int count = cursor.getCount();
    data = new DataPoint[count];
    for(int i=0; i<count; i++)
    {
      cursor.moveToNext();
      data[i] = new DataPoint(cursor.getLong(0), new ClimateData(cursor.getFloat(1),
        cursor.getFloat(2),cursor.getFloat(3),cursor.getFloat(4)));
    }
    cursor.close();
    db.close();

    // Clear other fields that depend on data
    nearestPointIndex = -1;
  }

  private void setField(int field)
  {
    this.graphField = field;
    setTitle(HumidityActivity.getBankName(this, bank) + " - " + getString(FIELD_LABEL[field])
      + " (" + getString(FIELD_UNIT[field]) + ")");
    graph.invalidate();

    SharedPreferences prefs = getSharedPreferences("com.leafdigital.humidity", MODE_PRIVATE);
    if(prefs.getInt(PREFS_CURRENT_GRAPH, FIELD_HUMIDITY) != field)
    {
      if(field == FIELD_HUMIDITY)
      {
        prefs.edit().remove(PREFS_CURRENT_GRAPH).commit();
      }
      else
      {
        prefs.edit().putInt(PREFS_CURRENT_GRAPH, field).commit();
      }
    }
  }

  @Override
  public boolean onCreateOptionsMenu(Menu menu)
  {
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.showrecords, menu);
    return true;
  }

  @Override
  public boolean onPrepareOptionsMenu(Menu menu)
  {
    int id = -1;
    switch(graphField)
    {
    case FIELD_TEMPERATURE :
      id = R.id.temp;
      break;
    case FIELD_HUMIDITY :
      id = R.id.humidity;
      break;
    case FIELD_DEWPOINT :
      id = R.id.dewpoint;
      break;
    case FIELD_DENSITY :
      id = R.id.density;
      break;
    }
    menu.findItem(id).setChecked(true);

    menu.findItem(R.id.delete).setEnabled(data.length != 0);
    long now = System.currentTimeMillis();
    menu.findItem(R.id.deletebefore1d).setEnabled(data.length>0
      && now - data[0].javaTime > 1 * ONE_DAY);
    menu.findItem(R.id.deletebefore7d).setEnabled(data.length>0
      && now - data[0].javaTime > 7 * ONE_DAY);
    menu.findItem(R.id.deletebefore30d).setEnabled(data.length>0
      && now - data[0].javaTime > 30 * ONE_DAY);

    return super.onPrepareOptionsMenu(menu);
  }

  @Override
  public boolean onOptionsItemSelected(MenuItem item)
  {
    switch(item.getItemId())
    {
    case R.id.temp :
      setField(FIELD_TEMPERATURE);
      return true;
    case R.id.humidity :
      setField(FIELD_HUMIDITY);
      return true;
    case R.id.dewpoint :
      setField(FIELD_DEWPOINT);
      return true;
    case R.id.density :
      setField(FIELD_DENSITY);
      return true;
    case R.id.name :
      showDialog(DIALOG_NAME);
      return true;
    case R.id.deletelast :
      deleteData(data[data.length-1].javaTime-1, getString(R.string.deletelast), true);
      return true;
    case R.id.deletebefore1d :
      deleteData(System.currentTimeMillis() - ONE_DAY, getString(R.string.deletebefore1d), false);
      return true;
    case R.id.deletebefore7d :
      deleteData(System.currentTimeMillis() - 7 * ONE_DAY, getString(R.string.deletebefore7d), false);
      return true;
    case R.id.deletebefore30d :
      deleteData(System.currentTimeMillis() - 30 * ONE_DAY, getString(R.string.deletebefore30d), false);
      return true;
    case R.id.deleteall :
      deleteData(System.currentTimeMillis() + 1, getString(R.string.deleteall), false);
      return true;
    default:
      return super.onOptionsItemSelected(item);
    }
  }

  @Override
  protected Dialog onCreateDialog(int id)
  {
    // Create dialog
    final Dialog dialog = new Dialog(this);
    switch(id)
    {
    case DIALOG_POINT :
      dialog.setContentView(R.layout.pointdialog);
      View ok = dialog.findViewById(R.id.ok);
      ok.setOnClickListener(new OnClickListener()
      {
        @Override
        public void onClick(View v)
        {
          dialog.cancel();
        }
      });
      break;

    case DIALOG_NAME :
      dialog.setContentView(R.layout.namedialog);
      dialog.setTitle(R.string.name);
      final EditText edit = (EditText)dialog.findViewById(R.id.name);
      final View okName = dialog.findViewById(R.id.ok);
      okName.setOnClickListener(new OnClickListener()
      {
        @Override
        public void onClick(View v)
        {
          String name = edit.getText().toString();
          SharedPreferences.Editor editor = getSharedPreferences("com.leafdigital.humidity",MODE_PRIVATE).edit();
          editor.putString(PREFS_BANK_NAME + bank, name);
          editor.commit();
          dialog.dismiss();
          setField(graphField);
        }
      });
      edit.addTextChangedListener(new TextWatcher()
      {
        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count)
        {
        }

        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after)
        {
        }

        @Override
        public void afterTextChanged(Editable s)
        {
          int length = edit.getText().length();
          okName.setEnabled(length <= 6 && length >= 1);
        }
      });
      break;

    case DIALOG_DELETE:
      AlertDialog.Builder builder = new AlertDialog.Builder(this);
      builder.setMessage(getString(R.string.confirmdelete));
      builder.setPositiveButton(getString(R.string.delete),
        new DialogInterface.OnClickListener()
        {
          @Override
          public void onClick(DialogInterface dialog, int which)
          {
            confirmDelete();
            dialog.dismiss();
          }
        });
      builder.setNegativeButton(getString(R.string.cancel),
        new DialogInterface.OnClickListener()
      {
        @Override
        public void onClick(DialogInterface dialog, int which)
        {
          dialog.cancel();
        }
      });
      builder.setTitle("Placeholder");
      return builder.create();
    }
    return dialog;
  }

  @Override
  protected void onPrepareDialog(int id, Dialog dialog)
  {
    switch(id)
    {
    case DIALOG_POINT :
      preparePointDialog(dialog);
      break;
    case DIALOG_NAME :
      prepareNameDialog(dialog);
      break;
    case DIALOG_DELETE :
      prepareDeleteDialog(dialog);
      break;
    }
  }

  private void preparePointDialog(Dialog dialog)
  {
    // Get data
    DataPoint point = data[nearestPointIndex];
    FieldValue field = point.data.getField(graphField);

    // Set title to date
    SimpleDateFormat date = new SimpleDateFormat("yyyy-MM-dd HH:mm");
    dialog.setTitle(date.format(new Date(point.javaTime)));

    // Set icon
    ImageView image = (ImageView)dialog.findViewById(R.id.icon);
    int icon = -1;
    switch(graphField)
    {
    case FIELD_TEMPERATURE:
      icon = R.drawable.menu_temp;
      break;
    case FIELD_HUMIDITY:
      icon = R.drawable.menu_humidity;
      break;
    case FIELD_DEWPOINT:
      icon = R.drawable.menu_dewpoint;
      break;
    case FIELD_DENSITY:
      icon = R.drawable.menu_density;
      break;
    }
    image.setImageResource(icon);

    // Set units
    for(int unitId : new int[] { R.id.unit1, R.id.unit2, R.id.unit3 })
    {
      ((TextView)dialog.findViewById(unitId)).setText(getString(FIELD_UNIT[graphField]));
    }

    // Set actual values
    String format = graphField == FIELD_DENSITY ? "%.2f" : "%.1f";
    ((TextView)dialog.findViewById(R.id.minValue)).setText(
      String.format(format, field.getMin()));
    ((TextView)dialog.findViewById(R.id.estValue)).setText(
      String.format(format, field.getMeasured()));
    ((TextView)dialog.findViewById(R.id.maxValue)).setText(
      String.format(format, field.getMax()));
  }

  private void prepareNameDialog(Dialog dialog)
  {
    ((EditText)dialog.findViewById(R.id.name)).setText(
      HumidityActivity.getBankName(this, bank));
    ((Button)dialog.findViewById(R.id.ok)).setEnabled(true);
  }

  private void prepareDeleteDialog(Dialog dialog)
  {
    dialog.setTitle(deleteMessage);
  }

  private long deleteTime;
  private boolean deleteAfter;
  private String deleteMessage;

  private void deleteData(long time, String message, boolean after)
  {
    // This is crappy, but I have to call showDislog and then use this stuff
    // later.
    this.deleteTime = time;
    this.deleteMessage = message;
    this.deleteAfter = after;
    showDialog(DIALOG_DELETE);
  }

  private void confirmDelete()
  {
    SQLiteDatabase db = new RecordsOpenHelper(this).getWritableDatabase();

    db.delete("readings", "javatime " + (deleteAfter ? ">" : "<")
      + " ? AND bank = ?", new String[] { deleteTime + "", bank + ""});

    db.close();

    loadData();

     graph.invalidate();
  }
}




Java Source Code List

com.leafdigital.humidity.ClimateData.java
com.leafdigital.humidity.HumidityActivity.java
com.leafdigital.humidity.RecordsOpenHelper.java
com.leafdigital.humidity.SaveReadingActivity.java
com.leafdigital.humidity.ShowReadingActivity.java
com.leafdigital.humidity.ShowRecordsActivity.java
com.leafdigital.humidity.TakeReadingActivity.java