J2i.Net

Nothing at all and Everything in general.

Tizen based Speedometer

Just before heading off to the Samsung Developer's conference I had a chance to implement a Tizen based speedometer for the Gear. The Galaxy Gear and Galaxy Gear 2 don't have hardware for determining the user's location or speed. To make a usable application a second executable was needed that would run on the user's phone to use it's location hardware and send the information back to the watch over Bluetooth. The full details of how I did this have been documented and posted on CodeProject.com. You can find the details here

While at the conference I managed to snag a Galaxy Gear S (or three) and decided to modify the application to run as a standalong application on the Gear S. While I was successful at doing this, my general advice is against doing so unless no other method is necessary. There are two reasons I say this. The first is that the Gear S would not generate location/speed updates at a frequency that I considered acceptable (they could be as close together as 2 seconds but seemed to typically be around 10 seconds apart). The phone's location hardware seemed to generate updates about once per second. The second reason I advise against this is to give priority on protecting the watches's battery over the phone's. Given a full charge and light use the phone can last several days on it's battery (and much longer on conservative use). The watch does not have the potential of being able to last nearly as long as the phone. Nevertheless there are still occasions where using the phone's hardware may be desirable; such as when the phone is left behind or location services are disabled and not available on the phone. 

The Tizen Wearable SDK allows the development on Tizen based applications using HTML, JavaScript, and CSS. There are some Tizen specific classes available in JavaScript for accessing hardware specific features (ex: power management), but most of the rest of what is available is based on web standards. A user's speed and location can be acquired using the W3C Geolocation API Specification. There also exists a library called the Tizen Advanced UI (TAU) framework that's useful for constructing UI components and interactions. 

Constructing the UI

The UI is built in HTML. Most of the elements that make up the UI will make sense if you are experienced at editing HTML. There are a few points that have meaning specific to the TAU framework. Throughout the UI some of the CSS classes are associated with TAU behaviours. These include

 

  • ui-page - the contents of this element for a virtual page. Only one virtual page is visible at a time even though there may be several virtual pages in the same HTML file.
  • ui-page-active - marks the virtual page that is currently displayed
  • ui-header - An element with this style will appear at the top of the display
  • ui-footer - an element with this style will appear at the bottom of the page
There are other UI styles that come with the TAU framework (look in tau.js in the source code). The classes ui-page and ui-page-active are most relevant to navigation within the application. Navigation occurs by changing which element has the ui-page-active class. Only one virtual page will have this class set at any given time. The TAU framework will also take care of manipulation of these classes. Navigation can be implemented through what appears to be regular anchor tags. The href attribute for the anchor is set to the ID of the virtual page to which we want to navigate with a # before the name.  The entirity of the contents for the <body> element of the file that forms this application is below (I've omitted the header which contains the CSS and JS files that get included into the interface). 

 

 

 <div class="ui-page ui-page-active" id="main">
 	<div class="ui-header" data-position="fixed">
 		<h2 class="ui-title">Speedometer</h2>
 	</div>	 	 	
 	<div class="content" style='margin:auto;text-align:center;vertical-align:center;height:200px'>
	  	<div style='margin:auto;'  style="height:80%;">
	  		<div  id="speedText">...</div>
	  		<div  id="speedUnitText" ></div>
	  		<div id="statusText"></div>
	  	</div>  
 	</div>
 	<div class="ui-footer appBar">
 		<a href="#settings" data-transition="slideup">
 			<img id="startTracking" src="images/dark/gear.png" class="appBarItem"  />	 			
 		</a>	 		
 	</div>
 </div>	 
 
<div id="settings" class="ui-page">
 	<div class="ui-header" data-position="fixed">
 		<h2 class="ui-title">Settings</h2>
 	</div>
 	<div class="content">
 		<ul class="ui-listview" id="unitsList">	 			
 		</ul>
 		<input type="checkbox" id="keepScreenOn" name="keepScreenOn" />
 		<label style="font-size:1.25em" for="keepScreenOn" onclick="setPowerPolicy()">Keep Screen On</label> 
 	</div>	 	
 </div>

For this application there are only two virtual pages. One is the screen that displays speed. The other is the settings screen. 

Acquiring Speed

Speed information is inexorably linked to location information. To get a user's speed we must request their location. Depending on the resolution of the location information speed information may or may no be available within it (you may receive a location without speed, but never a speed without location). To request location information the geolocation object within the navigator object is used. This method can be used in many other browsers, though if geolocation information is not supported on the browser this object will return null. The object has several methods that can be used to retrieve location information. The one we want to use is called watchLocation. It will begin the cycle of retrieving several location updates until the geolocation object is asked to stop watching. The watchLocation method takes as it's arguments a reference to the method that we want to use to receive location information, a reference to the method that should be called when an error occurs, and optionally an additional parameter that may contain additional information on timeouts or the maximum age of location information. 

function startWatch() {
	if(locationWatchId === null) {
		console.log('starting location watch');
		locationWatchId  = navigator.geolocation.watchPosition(locationUpdate, locationUpdateError, {maximumAge:250})
		console.log('watch id:' + locationWatchId);
	}
}

function locationUpdate( position ) {
	console.log('position update:' + position.toString() + ':' + (new Date()));
	lastPosition = position;
	var currentSpeed = lastPosition.coords.speed;
	hasLocation = true; 
	$('#speedText').html(formatSpeed(currentSpeed));
	$('#speedUnitText').html(currentUnit.label);
	$('#speedText').css('color', '#fff');
}

When I receive the location information I'm using jQuery to display the updated information on the screen. Speed information is received in meters per second. The formatSpeed method is a method that I've made to convert the speed to either miles per hour or kilometers per hour.

Keeping the Screen On

The default power settings on the Galaxy Gear S keep it fairly prompt about turning the screen off. For the speedometer application one might want to keep the screen on. I've included a checkbox in the settings screen that allows the screen to be kept turned on. One of the tizen specific calls is the ability to control the power state of the device. When the checkbox is set I request that the minimum power state of the device to be set to SCREEN_NORMAL. This is sufficient for keeping the device running and the screen on. If the checkbox is cleared I release the request.

function applyPowerPolicy() {
	if(!tizen) { return; }
	var screenPolicy = localStorage.getItem('screenPower');
	if (screenPolicy === null) {
		screenPolicy = 'SCREEN_NORMAL';		
	}
	
	console.log(screenPolicy);
	if(screenPolicy === "SCREEN_NORMAL") 
		{ tizen.power.request("SCREEN", "SCREEN_NORMAL"); }
	else
		{ tizen.power.release("SCREEN"); }
}

function setPowerPolicy() {	
	var isChecked = $("keepScreenOn").is(':checked');
	var policy = isChecked ? "SCREEN_NORMAL" : "";
	localStorage.setItem('screenPower', policy);
	applyPowerPolicy();
}

Other Implementation Details

The other details of how the standalone Speedometer application works can be found in the CodeProject article. Be sure to check it out. I've opened a Samsung Seller application and plan to post the application in their store once it passes certification. I plan to write about my experience once I get through the process.

Comments are closed