Android Open Source - SleepGuard Sleep Chart






From Project

Back to project page SleepGuard.

License

The source code is released under:

GNU General Public License

If you think the Android project SleepGuard 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

package com.szabolcs.szijarto.sleepguard;
//w w w .jav  a  2s  .  co  m
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.LinkedList;
import java.util.ListIterator;
import java.util.Locale;

import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Path;
import android.graphics.Rect;

public class SleepChart {
  
  private Recording myrec;
  private LinkedList<HeartRateRec> hrlist;
  private LinkedList<Peak> peaklist;
  private int x_sec_per_pixel;        // horizontal resolution of chart: normally 10
  private int chart_width, chart_height;    // vertical size of the chart in BPM
  private int x_border, y_border, header_height;
  private int x_size, y_size, min_width; 
  private int x_origo, y_origo;
  private int marker_size;
  private int max_bpm, min_bpm, bpm_minor, bpm_major;
  private int text_size_small;
  private int text_size_medium, text_height_medium;
  private long elapsed_secs;
  private int elapsed_hour, elapsed_min, elapsed_sec;
  private HeartRateRec rec_first, rec_last;
  private int max_ind;
  private Bitmap b;
  private Canvas c;
  private Paint p;
  
  public SleepChart(Recording r) {
    myrec = r;
    hrlist = r.getHrLst();
    peaklist = r.getPeaks();
    draw();
  }

  public void setHrList(LinkedList<HeartRateRec> hrlst) {
    hrlist = hrlst;
  }

  public void setPeakList(LinkedList<Peak> peaklst) {
    peaklist = peaklst;
  }
  
  public void draw() {
    init();
    draw_background();
    draw_x_axis();
    draw_y_axis();
    draw_treshold();
    draw_peaks();
    draw_chart();
    draw_header();
  }

  private void init() {
    min_bpm = 50;
    max_bpm = 250;
    bpm_minor = 10;
    bpm_major = 50;
    rec_first = hrlist.getFirst();
    rec_last = hrlist.getLast();
    
    // the chart will only be created up to this position, in case values are still being added in parallel
    max_ind = hrlist.lastIndexOf(rec_last);

    elapsed_secs = ( rec_last.timestamp.getTime() - rec_first.timestamp.getTime() ) / 1000;
    elapsed_hour = (int) (elapsed_secs / 3600 ); 
    elapsed_min = (int) ( (elapsed_secs-elapsed_hour*3600) / 60 );
    elapsed_sec = (int) (elapsed_secs-elapsed_hour*3600-elapsed_min*60) ;
    // calculate dimensions
    if (elapsed_secs < 600) {
      x_sec_per_pixel = 1;  // if total duration is < 10 minutes, 1 pixel = 1 sec (high horizontal resolution)
    } else {
      // TODO TESTING ONLY, OTHERWISE 5
      x_sec_per_pixel = 1;  // otherwise 1 pixel = 1 sec (lower horizontal resolution)
    }
    x_border = 20;
    y_border = 15;
    header_height = 50;
    chart_width = (int)Math.ceil(elapsed_secs / x_sec_per_pixel);
    chart_height = max_bpm;
    min_width = 380;
    x_size = chart_width+2*x_border;
    y_size = chart_height+4*y_border+header_height;
    if (x_size<min_width) { x_size = min_width; }
    x_origo = x_border;
    y_origo = y_size-y_border;
    marker_size = 2;
    text_size_small = 9;
    text_size_medium = 12;
    text_height_medium = text_size_medium + 3;

    // create bitmap, canvas and paint
    b = Bitmap.createBitmap( x_size, y_size, Bitmap.Config.ARGB_8888);
    c = new Canvas (b);
    p = new Paint();
  }

  private void draw_background() {
    p.setColor(Color.argb(255, 225, 225, 225)); // light gray, non-transparent
    c.drawPaint(p);
  }

  private void draw_treshold() {
    short t = myrec.getTreshold();
    p.setColor(Color.argb(128, 200, 0, 0)); // red, semi-transparent
    c.drawLine(x_origo, y_origo-t, x_origo+chart_width, y_origo-t, p);
  }
  
  private void draw_peaks() {
    Peak peak;
    int x1, x2;
    
    p.setColor(Color.argb(128, 230, 0, 0)); // light red, semi-transparent
    p.setStyle(Style.FILL);
    
    ListIterator<Peak> l = peaklist.listIterator(0) ;
    while (l.hasNext()) {
      peak = l.next();
      x1 = (int) Math.floor( (peak.start_time.getTime() - rec_first.timestamp.getTime()) /1000.0 /x_sec_per_pixel );
      x2 = (int) Math.floor( (peak.end_time.getTime() - rec_first.timestamp.getTime()) /1000.0 /x_sec_per_pixel );
      Rect r = new Rect(x_origo+x1, y_origo-40, x_origo+x2, y_origo-chart_height-10);
      c.drawRect(r, p);
    }
  }
  
  private void draw_header() {
    p.setColor(Color.BLACK);
    c.drawRect(x_border, y_border, x_size-x_border, y_border+header_height, p);
    SimpleDateFormat ft;
    ft = new SimpleDateFormat ("yyyy.MM.dd HH:mm:ss", Locale.US);
    print_header_text(1, "Timeframe : "+ft.format(rec_first.timestamp.getTime()) +
              " - "+ft.format(rec_last.timestamp.getTime()) + "     " +
              "Duration : "+elapsed_hour+":"+elapsed_min+":"+elapsed_sec );
    // TODO this should be a method of Recording, similar to getDurationString() in Peaks
    long secs = myrec.getPeaks_dur();
    int hour  = (int) ( secs / 3600 ) ;
    int min   = (int) ( secs - (hour*3600) ) / 60 ;
    int sec   = (int) ( secs - (hour*3600) ) % 60 ;
    print_header_text(2, "Peaks : "+myrec.getPeaks_cnt() + "     " +
              "Duration : "+ hour + ":" + min + ":" + sec + "     " +
              "Max Bpm: "+myrec.getPeaks_max() );
  }

  private void print_header_text(int n, String s) {
    p.setColor(Color.BLACK);
    p.setTextSize(text_size_medium);
    c.drawText(s, x_origo+x_border/2, y_border+y_border/2+n*text_height_medium, p);
  }
  
  private void draw_x_axis() {
    p.setColor(Color.BLACK);
    c.drawLine(x_origo, y_origo, x_origo+chart_width, y_origo, p);
    
    // calculate offset of markers
    @SuppressWarnings("deprecation")
    int minutes = rec_first.timestamp.getMinutes();
    @SuppressWarnings("deprecation")
    int seconds = rec_first.timestamp.getSeconds();
    int timeoffset = (minutes*60+seconds);
    
    // draw markers and labels
    int x = 0;
    String timelabel;
    Date timehere = new Date();
    SimpleDateFormat f = new SimpleDateFormat ("HH:mm", Locale.US);
    for (int i=0; i<(elapsed_secs+timeoffset); i+=60 /* step by 1 minute */ ) {

      // TODO there *must* be a better way to do this...
      x = (i -timeoffset) / x_sec_per_pixel;
      if (x<0) continue; // skip if this marker would be off the chart
      
      if (i%(600) == 0) {   // 600 = every 10 minutes
        p.setColor(Color.BLACK);  // long black marker every 10 minutes
        c.drawLine(x_origo+x, y_origo+marker_size, x_origo+x, y_origo-marker_size, p);
        p.setColor(Color.GRAY);    // ...and gray vertical line too 
        c.drawLine(x_origo+x, y_origo-2*marker_size, x_origo+x, y_origo-chart_height, p);
        // time label
        timehere.setTime( rec_first.timestamp.getTime() + (i-timeoffset)*1000 );
        timelabel = f.format(timehere);
        p.setTextSize(text_size_small);
        p.setColor(Color.BLACK);
        c.drawText(timelabel, x_origo+x-10, y_origo+text_size_small, p);
      } else {
        p.setColor(Color.BLACK);  // otherwise short black markers every minute in between 
        c.drawLine(x_origo+x, y_origo            , x_origo+x, y_origo-marker_size, p);
      }
    }
  }
  
  private void draw_y_axis() {
    p.setColor(Color.BLACK);
    c.drawLine(x_origo-1, y_origo, x_origo-1, y_origo-chart_height-y_border, p);
    
    // draw markers and labels
    for (int mind = min_bpm; mind <= max_bpm ; mind=mind+bpm_minor) {
      p.setColor(Color.BLACK);
      p.setTextSize(text_size_small);
      if (mind%bpm_major == 0) {
        c.drawLine(x_origo-1-2*marker_size, y_origo-mind, x_origo+2*marker_size, y_origo-mind, p);  // Y axis long marker
        c.drawText(String.valueOf(mind), 1, y_origo-mind-1, p);
      } else {
        c.drawLine(x_origo-1-marker_size, y_origo-mind, x_origo+marker_size, y_origo-mind, p);    // Y axis short marker
      }
      p.setColor(Color.GRAY);
      c.drawLine(x_origo+2*marker_size, y_origo-mind, x_origo+chart_width, y_origo-mind, p);      // horizontal line
    }

    // print "Bpm" on top
    p.setColor(Color.BLACK);
    p.setTextSize(text_size_small);
    c.drawText("Bpm", x_origo-12, y_origo-chart_height-20, p);
  }

  private void draw_chart() {
    int offset;
    boolean started;
    HeartRateRec r;
    ListIterator<HeartRateRec> l = hrlist.listIterator(0) ;
    Path t = new Path();
    started = false;
    while (l.hasNext() && (l.nextIndex()<max_ind)) {  // stop if no more records, or at max_ind, just in case extra records were added to the list in the meantime
      r = l.next();
      offset = (int) Math.floor( (r.timestamp.getTime() - rec_first.timestamp.getTime()) /1000.0 /x_sec_per_pixel );
      if (!started) {
        t.setLastPoint(x_origo+offset, y_origo-r.pulse);
        started = true;
      }
      t.lineTo(x_origo+offset, y_origo-r.pulse);
    }
    p.setColor(Color.argb(255, 0, 0, 170)); // dark blue, non-transparent
    p.setStyle(Paint.Style.STROKE);
    c.drawPath(t, p);
  }
  
  public Bitmap getBitmap() {
    return b;
  }
}




Java Source Code List

com.szabolcs.szijarto.sleepguard.Activity_Main.java
com.szabolcs.szijarto.sleepguard.Activity_ShowRecording.java
com.szabolcs.szijarto.sleepguard.GenericWatcherException.java
com.szabolcs.szijarto.sleepguard.GenericWatcher.java
com.szabolcs.szijarto.sleepguard.HeartRateRec.java
com.szabolcs.szijarto.sleepguard.HeartRateWatcher.java
com.szabolcs.szijarto.sleepguard.Peak.java
com.szabolcs.szijarto.sleepguard.RecordingFile.java
com.szabolcs.szijarto.sleepguard.RecordingListView.java
com.szabolcs.szijarto.sleepguard.Recording.java
com.szabolcs.szijarto.sleepguard.SleepChart.java