Android Open Source - ArcTimer Arc Timer View






From Project

Back to project page ArcTimer.

License

The source code is released under:

GNU General Public License

If you think the Android project ArcTimer 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.taavo.arctimer;
// w w  w  .  j a va2s.co  m
import java.util.concurrent.Semaphore;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Typeface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

public class ArcTimerView extends SurfaceView implements Runnable, SurfaceHolder.Callback {

  private int startTotalAngle = -90; 
  private int sweepTotalAngle = 360;

  private int startLapAngle = -90; 
  private int sweepLapAngle = 360;

  private RectF totalRect = new RectF();  
  private RectF lapRect   = new RectF();
  private Rect textRect  = new Rect();  
  
  private Paint workPaint = new Paint();
  private Paint workBorderPaint = new Paint();
  private Paint restPaint = new Paint();
  private Paint restBorderPaint = new Paint();

  
  private Paint textPaint = new Paint();
  private Paint strokePaint = new Paint();
  
  private float totalTextX = 0;
  private float totalTextY = 0;
  private float lapTextX = 0;
  private float lapTextY = 0;
  
  private String totalText;
  private String lapText;
  
  protected final Semaphore sem = new Semaphore(0);
  
  private IntervalSession is;
  
  private int totalAngle;
  private int lapAngle;
  private long totalTime;
  private long lapTime;
  
  Thread t = null;
  SurfaceHolder sh;
  protected boolean run_thread = false;
  
  public ArcTimerView(Context context, IntervalSession is) {
    super(context);
    
    sh = getHolder();
    
    sh.addCallback(this);
    
    this.is = is;  
    
    calcTextTime();
    
    workPaint.setColor(0xff00ff00); 
    workPaint.setAntiAlias(true);

    restPaint.setColor(0xffff0000);
    restPaint.setAntiAlias(true);
    
    workBorderPaint.setColor(0xffaaffaa); 
    workBorderPaint.setAntiAlias(true);
    workBorderPaint.setStyle(Paint.Style.STROKE);
    workBorderPaint.setStrokeJoin(Paint.Join.ROUND);
    workBorderPaint.setStrokeWidth(15);

    restBorderPaint.setColor(0xffff8383);
    restBorderPaint.setAntiAlias(true);
    restBorderPaint.setStyle(Paint.Style.STROKE);
    restBorderPaint.setStrokeJoin(Paint.Join.ROUND);
    restBorderPaint.setStrokeWidth(15);
    
    textPaint.setColor(0xffffffff);
    textPaint.setAntiAlias(true);
    textPaint.setTypeface(Typeface.createFromAsset(context.getAssets(), "fonts/codename_coder_free_4f.ttf"));
    textPaint.setTextSize(90); // TODO: Set text size dynamically
    textPaint.getTextBounds(totalText, 0, totalText.length(), textRect);
    

    strokePaint.setColor(0xff000000);
    strokePaint.setAntiAlias(true);
    strokePaint.setTextSize(90);
    strokePaint.setStyle(Paint.Style.STROKE);
      strokePaint.setStrokeWidth(2);
      strokePaint.setTypeface(Typeface.createFromAsset(context.getAssets(), "fonts/codename_coder_free_4f.ttf"));    
  }
  

  
  public void updateClocks() {
    totalAngle = (int) is.elapsedTime*360/(int)((is.restCycleTime+is.workCycleTime)*is.totalWorkCycles - is.restCycleTime);
    lapAngle   = (int) is.elapsedCycleTime*360/(int)(is.currentCycleTime);
    
    startTotalAngle = (totalAngle%360 - 90);
    sweepTotalAngle = (270 - startTotalAngle);
    
    startLapAngle = (lapAngle%360 - 90);
    sweepLapAngle = (270 - startLapAngle);
    
    calcTextTime();
    
    sem.release();
  }
  
  private void calcTextTime() {
    totalTime = (is.restCycleTime+is.workCycleTime)*is.totalWorkCycles - is.restCycleTime - is.elapsedTime;
    lapTime   = (is.currentCycleTime - is.elapsedCycleTime);
    
    int totalDec = (int) (totalTime%1000)/10;
    int totalSec = (int) totalTime/1000%60;
    int totalMin = (int) totalTime/1000/60;

    int lapDec = (int) (lapTime%1000)/10;
    int lapSec = (int) lapTime/1000%60;
    int lapMin = (int) lapTime/1000/60;
    
    totalText = String.format("%02d:%02d.%02d", totalMin, totalSec, totalDec);
    lapText = String.format("%02d:%02d.%02d", lapMin, lapSec, lapDec);
  }
  

  protected void doDraw(Canvas canvas) {    
    canvas.drawRGB(0, 0, 0);

    Paint p = (is.currentCycleType == IntervalSession.TYPE_REST)?restPaint:workPaint;
    Paint b = (is.currentCycleType == IntervalSession.TYPE_REST)?restBorderPaint:workBorderPaint;
    
    canvas.drawArc(totalRect, startTotalAngle, sweepTotalAngle, true, p);
    canvas.drawArc(totalRect, startTotalAngle, sweepTotalAngle, true, b);
    
    canvas.drawArc(lapRect, startLapAngle, sweepLapAngle, true, p);
    canvas.drawArc(lapRect, startLapAngle, sweepLapAngle, true, b);
    
    canvas.drawText(totalText, totalTextX, totalTextY+20, strokePaint);
    canvas.drawText(totalText, totalTextX, totalTextY+20, textPaint);

    canvas.drawText(lapText, lapTextX, lapTextY+20, strokePaint);
    canvas.drawText(lapText, lapTextX, lapTextY+20, textPaint);
  }



  /**
   * Calculate dimensions of gfx objects. Called when surface is created or resized.
   * Surface is also created when switching between landscape/portrait 
   */
  public void surfaceChanged(SurfaceHolder holder, int format, int width,  int height) {      
    
    // Recalculate dimensions    
    float totalX = 0, totalY = 0;
    float lapX = 0, lapY = 0;
  
    float diameter = 0;
    float scale = (float) 0.90;
    
    if ( height > width ) { // portrait - clocks go over & under
      
      // smallest dimension determine max radius of circle (otherwise circle overflows or is squashed)
      if( (height/2) > width) { // width determines max radius
        diameter = width * scale;
      } else { // (height/2) determines max radius
        diameter = (height/2) * scale;  
      }

      totalY = height/4 - diameter/2;
      totalX = width/2 - diameter/2; 
      
      lapY = height - height/4 - diameter/2;
      lapX = width/2 - diameter/2;
      
      totalTextX = width/2 - textRect.width()/2;
      totalTextY = height/4;
      
      lapTextX = width/2 - textRect.width()/2;
      lapTextY = height - height/4;
      
    } else { // landscape - clocks go side-by-side      
      if( (width/2) > height) { // height determines max radius        
        diameter = height * scale;
      } else { // (width/2) determines max radius
        diameter = (width/2) * scale;
      }

      totalY = height/2 - diameter/2;
      totalX = width/4 - diameter/2;
      
      lapY = height/2 - diameter/2;
      lapX = width - width/4 - diameter/2;
      
      totalTextX = width/4 - textRect.centerX();
      totalTextY = height/2;
      
      lapTextX = width - width/4 - textRect.centerX();
      lapTextY = height/2;

    }          
    totalRect.set(totalX, totalY, totalX + diameter, totalY + diameter);
    lapRect.set(lapX, lapY, lapX + diameter, lapY + diameter);    
    
    // re-calc angles and text
    updateClocks();
  }

  public void surfaceCreated(SurfaceHolder holder) {
    run_thread = true;
    t = new Thread(this);
    t.start();
    sem.release();
  }

  public void surfaceDestroyed(SurfaceHolder holder) {
    run_thread = false;
    sem.release();    
    while(true) {
      try{
        t.join();
        break;
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }
    t = null;
  }
  
  /**
   * Gfx thread. Blocks until semaphore is released by updateClocks(), 
   * then locks canvas and draws.
   */
  public void run() {
    Canvas c = null;
    while(run_thread) {
      c = null;
      try { // Block until semaphore is released
        sem.acquire();
        c = sh.lockCanvas();      
        if (c != null) {
          doDraw(c);
        }      
      } catch (InterruptedException e) {
        e.printStackTrace();
      } finally {
        if (c != null) {
          sh.unlockCanvasAndPost(c);
        }
      }
    }
  }
}




Java Source Code List

com.taavo.arctimer.ArcTimerActivity.java
com.taavo.arctimer.ArcTimerView.java
com.taavo.arctimer.IntervalSession.java
com.taavo.arctimer.Prefs.java