Android development about listeners

For my App I need to use service discovery. Service Discovery is a piece of code that lets your android device search for other devices in the same network that can connect to you. But also it gives you the power to generate your own service so other devices can find you.

I wont go into detail about how to setup all this but it involves a lot of callback listeners. Althrough I like the idea of this I dont like the way some people on the internet, who explain this to people who never done this before, implement it. As stated in my previous android blogpost the standard tutorials work with the idea of putting everything in a activity. And well I just dont like that.

So for the service discovery logic and all listeners (3!) that go with it I created a class called ServiceHelper ( if you take a look at the tutorials from android about service discovery they use the same idea ). This helper is a singleton that registers a certain service on the network and works as its own listener for these type of events. So how is this different from the default approach?

The difference comes when I want to let the activity know that something has happened. I’m using the so called Observer/Observable pattern for this. I create my activity. I retrieve an instance of my servicehelper and add myself as a listener to that helper class.

the only thing I need to do next is to add a method ‘update’ so the helper can inform me about what happened. Why I like this idea better? Simple. If an activity implements a RegisterServiceListener, a ResolveListener, a GetMeSomeCoffeeListener the activity gets poluted with all kinds of ‘listener’ methods such as ‘onCoffeeServed’ or ‘onNoCoffeeAnymore’ methods.

Now I only have 1 method update(source, data) and in this update method I can add the logic to handle all the events I’m interested in. I think it makes the code a bit cleaner and easier to understand.

Android Development

It has been a while since my last dev related posting but here it goes. I decided to pick up android development to see how it goes and if it is as hard as people say it is. This blogpost will give you a little insight in the things I stumbled upon. Be warned. This blogpost is not written in some chronological order. It just a bunch of things I have to remember when doing android development. Therefore this post can be updated in the future.

Continue reading “Android Development”

Java: Reading GPX data from Endomondo

I’ve started using Endomondo as my primary workout application for a couple of weeks now and although it is a great app I want to have more control over my data. Luckily for us endomondo users they offer a export function that exports the workouts in GPX format.

Today I’ve been playing around with this library: https://sourceforge.net/projects/gpxparser/ and get the GPX file from Endomondo to be parsed succesfully..

So first of all I created a new project in my Eclipse and imported the GPX parser from the website into another project. I downloaded a file from my endomondo account and wrote a little code:

GPXParser p = new GPXParser();
p.addExtensionParser(new HeartRateExtensionParser());
FileInputStream in = new FileInputStream(location);
GPX gpxFile = p.parseGPX(in);

As you can see. Nothing to fancy. So now what? If we take a sneak peek at the file http://www.jeroensomhorst.eu/wp-content/uploads/20140816_100357.gpx you will see there is no information whatsoever about distance, speed, average heartrate and so on. We have to add that ourselves. Luckily its GNU license so I can edit the source as I please (or atleast that’s what I make out of the license..).

Let start by refactor the GPXParser class. I want to generate a custom GPX class that implements my interface EndomondoGPX. First create the interface

public interface IEndomondoGPx {

	public double getAverageHearthRate();
	public double getTotalDistance();
	public double getMaxHearthRate();
	public double getMinHearthRate();
	public double getTotalDuration();
	public double getMaxSpeed();
}

Nice, isn’t? Next create a new class called EndomondoGPX

package org.alternativevision.gpx.beans;

import java.util.ArrayList;
import java.util.Iterator;
import org.alternativevision.gpx.beans.sort.WayPointComparator;
import org.alternativevision.gpx.extensions.HeartRateExtensionParser;

public class EndomondoGPX extends GPX implements IEndomondoGPx {

	double avgHearthRate = -1;
	double trackpoints = -1;
	double maxHearthRate = -1;
	double TotalDuration = -1;
	double maxSpeed = -1;
	double minHearthRate = -1;

	public EndomondoGPX() {
		super();
	}

	private Iterator<Waypoint> getAllTrackPoints() {
		ArrayList<Waypoint> tp = new ArrayList<Waypoint>();
		for (Object o : this.getTracks().toArray()) {
			Track t = (Track) o;
			tp.addAll(t.getTrackPoints());
		}
		tp.sort(new WayPointComparator());
		return tp.iterator();
	}

	public double getAverageHearthRate() {

		if (avgHearthRate == -1){
			double hearthRate = 0;
			int trackpointcount = 0;
			
			Iterator<Waypoint> trackpionts = getAllTrackPoints();
			while(trackpionts.hasNext()){
				Waypoint wp = trackpionts.next();
				Object hr = wp.getExtensionData(HeartRateExtensionParser.PARSER_ID);
				if(hr instanceof HearthRate){
					hearthRate += ((HearthRate) hr).getHearthRate();
					trackpointcount++;
				}
			}
			
			this.avgHearthRate = (hearthRate / trackpointcount);
		}
		return avgHearthRate;

	}

	@Override
	public double getTotalDistance() {
		double currentDistance = 0;
		Iterator<Waypoint> trackpoints = this.getAllTrackPoints();
		while(trackpoints.hasNext()){
			Waypoint p1 = trackpoints.next();
			Waypoint p2 = null;
			if(trackpoints.hasNext()){
				p2 = trackpoints.next();	
			}
			
			if(p2 != null){
				System.out.println(p1.getTime());
				System.out.println(p2.getTime());
					double distance = getDistance(p1,p2);
					if(distance == 0){
						distance = getDistance(p2,p1);
					}
					System.out.println(distance);
					currentDistance += distance;
			
			
			}
		}
		currentDistance = (currentDistance/100)*101;
		return currentDistance;
	}

	@Override
	public double getMaxHearthRate() {

		if (this.maxHearthRate < 0) {
			double hearthRate = -1;
			Iterator<Waypoint> trackpoints = this.getAllTrackPoints();
			while(trackpoints.hasNext()){
				Object hr = trackpoints.next().getExtensionData(HeartRateExtensionParser.PARSER_ID);
				
				if (hr != null && hr instanceof HearthRate) {
					if (((HearthRate) hr).getHearthRate() > hearthRate) {
						hearthRate = ((HearthRate) hr).getHearthRate();
					}
				}
			}
			this.maxHearthRate = hearthRate;
		}
		return this.maxHearthRate;
	}

	@Override
	public double getMinHearthRate() {
		if(this.minHearthRate<0){
			double hearthRate = -1;
			Iterator<Waypoint> trackpoints = this.getAllTrackPoints();
			while(trackpoints.hasNext()){
				Object hr = trackpoints.next().getExtensionData(HeartRateExtensionParser.PARSER_ID);
				if (hr != null && hr instanceof HearthRate) {
					double entryRate = ((HearthRate)hr).getHearthRate();
					if(hearthRate == -1){
						hearthRate = entryRate;
					}
					else if(entryRate< hearthRate){
						hearthRate = entryRate;
					}
				
					
				}
			}
			this.minHearthRate = hearthRate;
		}
		return this.minHearthRate;
	}

	@Override
	public double getTotalDuration() {
		Iterator<Waypoint> trackpoints = this.getAllTrackPoints();
		while(trackpoints.hasNext()){
			Waypoint p = trackpoints.next();
			p.getTime();
		}
		return 0;
	}

	@Override
	public double getMaxSpeed() {
		// TODO Auto-generated method stub
		return 0;
	}
	
	private static double getDistance(Waypoint p1, Waypoint p2){
		double EARTH_RADIUS = 6371;
		double dLat = toRad(p2.getLatitude() - p1.getLatitude());
		double dLon = toRad(p2.getLongitude() - p1.getLongitude());
		double dLat1 = toRad(p1.getLatitude());
		double dlat2 = toRad(p2.getLatitude());
		double a = Math.sin(dLat/2)*Math.sin(dLat/2)+Math.cos(dLat1)*Math.cos(dlat2)*Math.sin(dLon/2)*Math.sin(dLon);
		double c = 2 * Math.atan2(Math.sqrt(a),Math.sqrt(1-a));
		double d = EARTH_RADIUS * c; // distance Kilometer
		return d;
		
	}
	private static final double toRad(double f){
		return f * (Math.PI/180);
	}
}

The code is pretty simple. There are some util functions there for retrieving all the trackpoints. This method also sorts them by time.

To make this happen I had to make  change to class that is base for all classes in the default GPX parser. The extension class. I had to make it abstract, implement a interface (comparable !) and make a abstract method public int compareTo(Object o1, Object o2).

All other classes such as waypoint should implement the compareTo. For this patch I only need to add the compareTo to the Waypoint class.

After some testing I found out there is a little bug in the GPX parser. When there is more then 1 trkseg node it will overide that node all the time. So you will end up with only the last trkseg node. In this case (see file) it will only contain one trkseg with one trkpt node. Not what we want!

The fix for this is the following method in Track.java

public void setTrackPoints(ArrayList<Waypoint> trackPoints) {
		
		if(this.trackPoints == null){
			this.trackPoints = trackPoints;
		}else{
			this.trackPoints.addAll(trackPoints);
		}
	}

It won’t overwrite all trackpoints for the current track it will add them. For now that is correct but I wont recommend it for all GPX files out there.

So, when that is done. We can start changing our Parser class.

Open up the GPXParser class and add the following method:

	@SuppressWarnings("unchecked")
	public <T extends GPX> T parseGPX(InputStream in, Class c) throws ParserConfigurationException, SAXException, IOException{
		try {
			return (T) parseGPX(in,(GPX) c.newInstance());
		} catch (InstantiationException e) {
			logger.error("Could not Instantiate custom GPX class");
		} catch (IllegalAccessException e) {
			logger.error("Could not instantiate custom GPX class illegal access");
		}
		return null;
	}

and refactor the method signature of parseGPX to

private GPX parseGPX(InputStream in, GPX gpx) throws ParserConfigurationException, SAXException, IOException {
..
}

Now add the following method for backwards compatability:

	public GPX parseGPX(InputStream in) throws ParserConfigurationException, SAXException, IOException{
		return this.parseGPX(in,new GPX());
	}

What we have done is pretty simple. First we created a new method to parse given GPX file (using inputstream) to a object of our own. We tell the GPXParser to parse the xml to our own instance of the GPX class. (in our case EndomondoGPX ).

Next, because we added that method we had to change the default method. We made it private, so that nobody can use it behind our back and we added a new parameter an instance of the GPX class. Inside this method we had to remove the  the GPX gpx = new GPX() because we now send it in as a parameter;

Last of but least we had to add a new method for backwards compatability. All this does is creating a new default GPX object and pass it into the changed method. We can now change our first code snippet to :

GPXParser p = new GPXParser();
p.addExtensionParser(new HeartRateExtensionParser());
FileInputStream in = new FileInputStream(location);
IEndomondoGPx gpxFile = (IEndomondoGPx) p.parseGPX(in, EndomondoGPX.class);
gpxFile.getAverageHearthRate();
gpxFile.getTotalDistance();
gpxFile.getMaxSpeed();
gpxFile.getMaxHearthRate();
gpxFile.getMinHearthRate();
gpxFile.getTotalDuration();

As you can see we have now full control what type of GPX object we get.

To get this all working by the way you also need to create a new HeartRateExtensionParser class. This class is used to parse extensions that comes with Endomondo.

<gpxtpx:TrackPointExtension>
            <gpxtpx:hr>146</gpxtpx:hr>
          </gpxtpx:TrackPointExtension>
package org.alternativevision.gpx.extensions;

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import org.alternativevision.gpx.beans.GPX;
import org.alternativevision.gpx.beans.HearthRate;
import org.alternativevision.gpx.beans.Route;
import org.alternativevision.gpx.beans.Track;
import org.alternativevision.gpx.beans.Waypoint;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

public class HeartRateExtensionParser implements IExtensionParser {

	public static final String PARSER_ID = "HeartRateExtensionParser";
	private XPathFactory xPathFactory = XPathFactory.newInstance();
	private XPath xpath = xPathFactory.newXPath();
	private XPathExpression exp = null;
	
	
	
	public HeartRateExtensionParser() {
		try {
			exp  = xpath.compile("d");
			
		} catch (XPathExpressionException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	
	@Override
	public String getId() {
		return PARSER_ID;
	}

	@Override
	public Object parseWaypointExtension(Node node) {
		NodeList childNodes = node.getChildNodes();
		for(int i = 0; i < childNodes.getLength();i++){
			Node n = childNodes.item(i);
			if("gpxtpx:TrackPointExtension".equals(n.getNodeName())){
				NodeList tpNodes = n.getChildNodes();
				for(int j = 0;j<tpNodes.getLength();j++){
					Node m = tpNodes.item(j);
					if("gpxtpx:hr".equals(m.getNodeName())){
						String t = m.getTextContent();
						if(t!= null && !"".equals(t)){
							double d = Double.parseDouble(t);
							return new HearthRate(d);
						}
						
						
						
					}
				}
			}
		}
		
		System.out.println("No Hearthrate node found..");
		return null;
	}

	@Override
	public Object parseTrackExtension(Node node) {
		System.out.println("Parse Track Extension");
		return null;
	}

	@Override
	public Object parseGPXExtension(Node node) {
		System.out.println("Parse gpx Extension");
		return null;
	}

	@Override
	public Object parseRouteExtension(Node node) {
		System.out.println("Parse Route Extension");
		return null;
	}

	@Override
	public void writeGPXExtensionData(Node node, GPX wpt, Document doc) {
		System.out.println("Write ExtensionData");
	}

	@Override
	public void writeWaypointExtensionData(Node node, Waypoint wpt, Document doc) {
		System.out.println("Write WaypiontExtensionData");

	}

	@Override
	public void writeTrackExtensionData(Node node, Track wpt, Document doc) {
		System.out.println("Track extension");

	}

	@Override
	public void writeRouteExtensionData(Node node, Route wpt, Document doc) {
		System.out.println("Write Route Extension");
	}

}

If you want to code.. let me know. It is still little buggy (the distance calculations seems to be a bit odd compared to endomondo ) but it works.

Prestigio Multipad_4_QUANTUM_9.7

If you ever have the need for buying a Multipad_4_QUANTUM_9.7 from prestigio. Please be aware that you should follow the following instructions when ipgrading your firmware. Because if you don’t you will spend HOURS and HOURS finding out why you’re tablet is not recognized by the ‘splendid’ rkbatcher tool.

oh and just to warn you . If you upgrade you’re firmware you lost all your settings.. and data..

1. Shutdown tablet

2. Remove external SD card (if present)
3. Plugin USB cable into tablet
4. Hold Vol+ and Power and connect USB to computer. When computer detects new device, release buttons (this is typically after 3-4 secs – if you hold longer, you will get to recovery mode (android bot with open belly) and you don’t need to be there => use volume to bring up menu, use volume again to select “reboot” and power button to confirm).  It remains a bit of trial & error…
5. Install driver from rockchip package.  => See below
6. Optional: Shutdown tablet (not necessary in my case, since I can see the device stays connected in Windows Device Manager)
7. Start Rockbatchtool after correcting the config.ini file => see below
8. Press Power & Volume+ to start tablet –> will be recognized by Rockbatch tool (green button at connected devices)
9. Load update image and click Restore … wait until reboot

 

Installing driver goes like this:

1. Windows / Open Control Panel (you wanna have this open before starting the above procedure)
2. Select “System”
3. Open “Device Manager”
4. Watch the list as it will change upon detection of a new device.  It should add something like “Class of Rockchip Devices” near the top of the list. You’ll see a device with a yellowish exclamation mark
5. Right click onto the new device and “Install/Update Driver”
6. Choose the driver from “My Computer”

 

Now: as for the config.ini modification, I found on minixforums a post by user Snurb that does the trick.  You open config.ini (located in the same folder where the .exe file is) and look for this line:

LOGFLAG=TRUE

#SUPPORTLOWUSB=TRUE时,扫描支持full speed usb设备,默认只支持high speed usb设备
SUPPORTLOWUSB=

This you change into:

LOGFLAG=TRUE
#SUPPORTLOWUSB=TRUE时,扫描支持full speed usb设备,默认只支持high speed usb设备
SUPPORTLOWUSB=TRUE
FULLSPEEDUSB=TRUE

Save & close.

Then you start Rockbatch Tool and all of a sudden, I had a green flashing light… ready to flash the new firmware!

 

Hope this helps.  Happy flashing!

 

source: http://xpag.es/?1DBA

REST framework for XPages (2)

In my previous post I announced the framework I’ve been building the last couple of weeks to implement REST services in xPages. In theory you can drag’n’drop a restcontrol on an xpage, bind the apibean to it and you are good to go.

But of course you still need to write code that handles the incoming request. In this post I will explain to you how a normal flow will be in the framework. We will use the demo application found on github (the project is also a demo app ).

A primer

First of all you need to create a new app from the source from github. You can do so by downloading the project and associate it with a new NSF (info) When you have done this please use the agent initialize agent to create the default keywords used by the application.

Next of you can go to index.php and you will be able to add measurements from your energy usage ( electricity / gas / water ). The application supports get, post, put and delete of the very simple measurement object.

All you see at the frontend is bootstrapped and pure javascript

The POST request

So what happens if you enter a date, a value and hit the save button? The framework will go through the following flow (warning! Huge image )

restframework

 

as you can see here a lot is going on. First of all the framework will search if there is a router object that can handle the current endpoint ( ie. /measurement ). If such an entry is found it will forward the request to this object.

This gives you the ability to concentrate the logic that belongs to that endpoint in a single tree of objects. Removing that tree won’t break the api framework only removes the endpoint. If implemented correct you dont end up with 4 methods ( get, post, put, delete ) in the base class (apibean) too handke lots of endpoints. Every endpoint has its own class tree.

Depending the mehod executing the input data is being parsed by the inputhandler object. This is by default a JSON object. The data is being validated ( not in the image ) by so called validators and if this all works out the dataservice object that is going to talk to domino / mysql / other db system is doing its job.

There are , as you can see , several layers where things are happening and the succes of 1 layer decides the flow of the other layers. If there is an error with parsing the request body the dataservice will not be accessed etc etc.

This concludes this post. I hope you have a little understanding of how the framework, at a very high level, does its thing. In the next chapter I will explain to you how to add a new endpoint to the application.

Stay tuned

 

REST Framework for xPages

A couple of weeks ago I wanted to pickup xPages again during my free time. So I created a little app and all worked well. But then for some reason I wanted to add Rest controls again ( as I did a couple of months ago ). This time I wanted to start of easy. First re-explore the workings again and eventually add a java backend to it.

This.. got a little out of hand ;). Instead of creating 1 simple API bean that handles a single type of entrypoint I decided to create a complete framework so that 1 rest control could be used to handle multiple endpoints. I’ve just added the project to github. The framework could do the following

  1. Finds out by itself (using config docs ) depending on the url it was triggered on what class ( ‘servlet’) to load
  2. Load the datastore for it ( IDataService ).
  3. Parses the input.
  4. Depending on the method type ( GET, PUT, POST, DELETE ) validates the input and executes the correct methods
  5. Sets the correct response code and returns data if needed ( with delete/put no data is returned

The great thing about this framework is that also contains simple validation. The framework should not be used in production at the moment but should be used as a bunch of code that shows how you COULD implement a REST API. It’s far from complete ( contains bugs… )

I will blog about the framework in the coming days to explain how it works and how you can modify it to adapt it to your own needs.

Small question regarding Dates and Rest services

To all the people out there who sometimes read my blogposts. What is , in your opinion the best way to represent dates when generating a REST api which returns JSON.

Is it time in milliseconds since epoch

Is it dd-mm-yyyy H:m:s:u ?

or is it mm-dd-yyyy H:m:s:u

or is it simple the ISO 8601 spec which will be something like

Year + “-” + Month + “-” + Day +”T” +Hours + “:” + Minutes + “:” + Seconds + “+01:00”

I’m more towards the ISO spec because its an ISO format and documented and so on but for now I just dont know for sure.. Any input would be helpfull.

RPC Calls ( and notes in 9) to the rescue

After a little downtime on the xPages departement I started to do some xPages again ( a few weeks ago ). Today I faced the following problem. We want to transfer data from one app to the other to generate Word documents using a xpage control. The problem is that the call is done in the ‘website’  database and the real logic is stored in the ‘data’  database. The word document is also generated clientside (don’t ask). So I needed to find a way to transfer data from one app to the other.

I first made the obvious error to set a sessionScope and to get that scope at the other application. But since scopes are not inherited (ofcourse..) that didn’t work. The thing I didn’t want was to add multiple url parameters to acccess the other database. So what’s next?

the Remote procedure call! A colleague told me that they are are using RPC’s all over the application currently and maybe that could be a solution. There was only one problem. I didn’t even know that was possible nowadays in xPages. So I first browsed the source to find the current RPC’s and started to create my own.. but all I’ve got was a call that did throw errors all over the place.

To resolve the issue I checked www.notesin9.com to see if there was someone who did a session in the past about RPCs. And yes there is. John Jardin, who is a great speaker by the way, did a vid about RPC’s. Its very basic but it’s just enough for me to get started!

What would xPages be without http://notesin9.com/ and John Jardin…?

SugarCRM: Logic hook default handlers

This post is a little tip for all those SugarCRM developer noobies out there ( including myself ). When you want to do field validation serverside or do some business calculations while saving the bean(s) you should use logic hooks ( more info here ). Logic hooks can hook into several stages of the applications/module’s process.

Something that I have found very useful is to create a default class for handling all specific events and to copy this file to the instance of the project. Therefore I only need to worry about the customer specific things I have to do. A skeleton class for the module logic hooks could look like this:

<?php
class DefaultModuleLogicHookHandler{
	function before_delete($bean, $event, $arguments){}
	function after_delete($bean,$event,$arguments){}

	function before_relationship_add($bean, $event, $arguments){}
	function after_relationship_add($bean, $event, $arguments){}
	function after_relationship_delete($bean, $event, $arguments){}

	function after_restore($bean, $event, $arguments){}
	function after_retrieve($bean, $event, $arguments){}
	function after_save($bean, $event, $arguments){}

	function before_relationship_delete($bean, $event, $arguments){}
	function before_restore($bean, $event, $arguments){}
	function before_save($bean, $event, $arguments){}
	function handle_exception($bean, $event, $exception){}
	function process_record($bean, $event, $arguments){}

}
?>

Now when you start a new project the only thing you need to do is to make a copy of the file and add it to the correct directory . For instance /custom/modules/Accounts/AccountLogicHookHandler.php

and rename the class in that file to AccountModuleLogicHookHandler. In your logic_hooks.php you need to add the following to get it working for the  before_save

$hook_array['before_save'] = Array();
$hook_array['before_save'][] = Array(1,'AccountHandler','custom/modules/Accounts/AccountLogicHookHandler.php','AccountModuleLogicHookHandler','before_save');

And whenever you need to implement a new hook you only need to add the correct entry in the logic_hooks file and write the implementation. Easy as pie and saves a lot of time finding out which parameters each hook function has etc..

 

Happy coding!