Currently there are only few applications for smartphones/tablets, that play a role in industrial processes and are actually used in customer service or in production. With the new generations of smartphones/tablets and the advance of new forms of information distribution (e.g., augmented reality), a much wider range of use is possible in industry.

In the following article I use the example of an application for customer service to demonstrate how such a usage might look like.

If you are looking for a way to implement location based services within your android application without using the web services of Google, you might be interested in the CloudMade web services. These web services provide functions like geocoding, searching for objects which are close to a given coordinate, retrieving map tiles as images and even to create a full route from a start point via several transit points to an end point.

To provide these services, CloudMade relies on the collaborative OpenStreetMap (OSM) project which follows the same principles as Wikipedia to create a free map.

To ensure an easy usage of the web services, CloudMade provides several libraries for the iPhone and other programming languages. The provided Java API is using an old implementation of the Apache HTTP Client which makes it unusable for Android devices. That’s why I’ve created a port of the lightweight CloudMade Java API which can be used on android devices.

The core of this library is the com.appsolut.api.cloudmade.CMClient which hides the HTTP communication of the different calls from the developer. The methods within this class are well documented and I will only give short overview of the most important methods:

public GeoResults find(String query, int results, int skip, BBox bbox, boolean bboxOnly, boolean returnGeometry, boolean returnLocation)

This method provides the geocoding functionality:

public GeoResult findClosest(String object_type, Point point) throws ObjectNotFoundException

If you want to find a certain object which is close to a point you can use this method:

public byte[] getTile(double latitude, double longitude, int zoom, int styleId, int size)

This method will return a png image of a map tile. For example, this might return a tile which looks like the following:

 

An example tile retrieved from the CloudMade web service

public Route route(Point start, Point end, RouteType routeType, List<Point> transitPoints, RouteTypeModifier typeModifier, String lang, MeasureUnit units) throws RouteNotFoundException

Using this method it is possible to create a route.

There exists also an android test project which can be used to ensure that everything works fine. You can also take a look at the test cases to see an example of how to use the library.

You can download or browse the source code at our repository at Google Code (http://code.google.com/p/android-cloudmade-api/) or use svn to check it out.

For more information you can refer to the following links:

If you are having trouble with this port feel free to ask questions.

Please Note:
It is important that you create your own API key when you are using the CloudMade web services. Please refer to the CloudMade FAQ for more information on this topic.

by Kevin Kratzer

In this post I will introduce a library which you can use to display elements from any java.util.Collection (e.g. LinkedList, ArrayList, HashSet, Queue, Stack, TreeSet,…) within a ListView or a Spinner. It’s even possible to use this library to implement any layout you want for your entries (e.g. a multi-line entry, an entry with including an image, etc…).

So this library is a very generic approach to display various data sets with custom layouts in a Spinner or a ListView.

To demonstrate the basic usage of this adapter I’ve created a simple example application which is using the library for a spinner adapter for a HashSet of UUIDs and a list adapter to display the single parts of the UUID together with an image.

Feel free to download the library and to reuse it within your own projects. You can also examine the source code at our Google code repository (http://code.google.com/p/android-collections-list-and-spinner-adapter/) by browsing the source or by checking it out using svn.

Basic Usage

Initialization

To ensure an easy usage of the library the CollectionsAdapter provides constructors which are closely related to the default android ArrayAdapter. The basic usage includes the use of the adapter with a simple TextView resource id or with a layout resource id and a TextView resource id which is located within this layout. When you are using this methods the objects toString method will be used to populate the give TextView element with text.

The corresponding constructors of the com.appsolut.adapter.collections. CollectionsAdapter<E>  class have the following signature:

public CollectionsAdapter(Context context, int textViewResourceId, Collection<E> content)
public CollectionsAdapter(Context context, int layoutResourceId, int textViewResourceId, Collection<E> content)

Where the parameters should be:

    • context – The context for the adapter. This could be your Activity.
    • layoutResourceId – If you are using the constructor which also uses a give layout resource id this parameter should point to this layout.
    • textViewResourceId – The resource id which is referring to the text view element used to fill in the text.
    • content – The collection containing the data. The collection can be modified afterwards.

 

In the example project this is demonstrated by the adapter for the spinner:

final Set<UUID> spinnerContent = new HashSet<UUID>();
for(int i = 0; i < 10; i++) {
	spinnerContent.add(UUID.randomUUID());
}
final CollectionsAdapter<UUID> spinnerAdapter = new CollectionsAdapter<UUID>(this, android.R.layout.simple_spinner_item, spinnerContent);
final Spinner spinner = (Spinner)findViewById(R.id.exampleSpinner);
spinner.setAdapter(spinnerAdapter);

Modifying the Data

If you later on want to modify the data you can either do this directly within the corresponding collection and then calling the notifyDataSetChanged() of the adapter to signal that you have modified the data or you can use the provided methods within the adapter which will take care of this. The signature of these methods is just like within the Collection interface:

      • public boolean add(E object)
      • public boolean addAll(Collection<? extends E> c)
      • public boolean remove(E object)
      • public boolean removeAll(Collection<?> c)
      • public void clear()

The boolean return value of the add and remove methods indicate if the data of your collection has been actually changed by the method call.

So as you can see the basic usage of the adapter is very simple.

 

Defining custom Layouts

If you want to use custom layouts within the adapter you can use the third available constructor of the com.appsolut.adapter.collections. CollectionsAdapter<E> class:

public CollectionsAdapter(Context context, Collection<E> content, ICollectionsAdapterViewFactory<E> viewFactory)

This constructor requires a context, the collection which will be used as data basis for the adapter and an com.appsolut.adapter.collections.view.ICollectionsAdapterViewFactory<E> viewFactory. The ICollectionsAdapterViewFactory<E> interface defines a method which will be called to display an element. During this method call you can create your own layout:

public View getView(int position, View convertView, ViewGroup parent, E item, LayoutInflater inflater, Context context)

If you have already created custom views for an adapter the method should look familiar to you. There are just some new parameters which ensure an easy creation of the view. If custom views within an adapter are completely new you should check out my previous posting on this topic first (http://xinfo.de/2011/03/using-custom-layouts-for-spinner-or-listview-entries-in-android/) and the return here.

So let’s take a look at the parameters of the method:

      • position – indicates the position of the element within the data set which should be displayed
      • convertView – “The old view to reuse, if possible. Note: You should check that this view is non-null and of an appropriate type before using. If it is not possible to convert this view to display the correct data, this method can create a new view.” – taken from the original Android API
      • parent – The parent view to which you should attach your view
      • item – The item which should be displayed by this view
      • inflater – The layout inflater service used to inflate xml layouts
      • context – The current context

In the example project I’ve implemented such an ICollectionsAdapterViewFactory which will populate a layout consisting of an ImageView and two TextViews:

public class NumberedViewFactory<T> implements
		ICollectionsAdapterViewFactory<T> {

	@Override
	public View getView(int position, View convertView,
			ViewGroup parent, T item, LayoutInflater inflater,
			Context context) {
		View layoutView;
		if (convertView == null) {
			layoutView = inflater.inflate(R.layout.listview_entry, parent, false);
		} else {
			layoutView = convertView;
		}
		final TextView segmentText = (TextView)layoutView.findViewById(R.id.textSegment);
		segmentText.setText(item.toString());

		final TextView segmentNumber = (TextView)layoutView.findViewById(R.id.segmentNumber);
		segmentNumber.setText(Integer.toString(position) + ". ");

		final ImageView imageView = (ImageView)layoutView.findViewById(R.id.image);
		if(position%2 == 0) {
			imageView.setBackgroundResource(android.R.drawable.presence_online);
		} else {
			imageView.setBackgroundResource(android.R.drawable.presence_invisible);
		}

		return layoutView;
	}

}

Summary

I hope you can use this flexible library to populate your ListViews and Spinners with various data sets. If you have any problems or suggestions on how to improve this library feel free to post comments.

by Kevin Kratzer

The technical advances in the last years, like fast processors, rapid data transmission, better displays and enhanced miniaturization, permit applications based on augmented reality to be processed on a smartphone or a tablet computer. Thus, such applications penetrate more and more into the everyday world. They are mostly designed for marketing, sales and advertising; many are simply playing around, just to demonstrate the possibilities of the new technology.

In industry, augmented reality applications have been used for quite some time. However, the necessary hardware is complex, such as special camera systems, sensors, displays and eye-tracking devices. Therefore, the applications are limited to specific areas.

Think of an iOS app which plays an HTML5 video you can stop, play and interact with. This is exactly what we’re going to build in this tutorial.

The HTML

Because only small changes are necessary, we will start by editing the HTML/JS code provided in this article. First, we attach a JavaScript onclick attribute to every elements’ surrounding

 via the setupItems() function:

var t = $(items[i][3]);

(Note that the encoding is necessary because the above string is given as function parameter).

As you can see, Overlay.call() is called with the appropriate item id when clicking on a box. Call() works similar to the way we used windows.location to submit data to the iOS parent app in a previous article – it takes the id and forwards the page to something like ?cmd=call&param=2. This string  can be read later by the iOS app.

That’s it! Now fire up Xcode and create a new view based application. Call it App Solut InteractiveVideoInterface and open your ViewController header file. Put this code in:

@interface App_Solut_InteractiveVideoInterfaceViewController : UIViewController {

IBOutlet UIWebView *webView;
IBOutlet UILabel *label;
}
@property(retain, nonatomic) UIWebView *webView;
@property(retain, nonatomic) UILabel *label;

@end

Save the file, switch to interface builder and edit your ViewControllers’ xib file. Drag both a webView and a label to the screen and connect the just created outlets. To do so, control-drag from your webview object to the files’ owner and select delegate. Then do the same vice-versa: Control-drag (or right click-drag if you own a standard mouse) from files’ owner to both the webview and the label and select the appropriate entries from the list. You have now created the connection between your code and your interface.

In your implementation file synthesize both the label and the webview:

@synthesize webView;
@synthesize label;

Similar to the webview interface code we add the following function to catch all webpage requests.

- (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType {
NSString *url = [[request URL] absoluteString];
NSArray *urlArray = [url componentsSeparatedByString:@"?"];
NSString *cmd = @"";
NSMutableArray *paramsToPass = nil;
if([urlArray count] > 1) {
NSString *paramsString = [urlArray objectAtIndex:1];
NSArray *urlParamsArray = [paramsString componentsSeparatedByString:@"&"];
cmd = [[[urlParamsArray objectAtIndex:0] componentsSeparatedByString:@"="] objectAtIndex:1];
int numCommands = [urlParamsArray count];
paramsToPass = [[NSMutableArray alloc] initWithCapacity:numCommands-1];
for(int i = 1; i < numCommands; i++){
NSString *aParam = [[[urlParamsArray objectAtIndex:i] componentsSeparatedByString:@"="] objectAtIndex:1];
[paramsToPass addObject:aParam];
}
}
if([cmd compare:@"call"] == NSOrderedSame) {
NSString *message = [[paramsToPass objectAtIndex:0]stringByReplacingPercentEscapesUsingEncoding:NSASCIIStringEncoding];
[label setText:[NSString stringWithFormat:@"You just clicked button #%@", message]];
}
/* Only load the page if it is not an appcall */
NSRange aSubStringRange = [url rangeOfString:@"appcall"];
if(aSubStringRange.length != 0){
NSLog(@"App call found: request cancelled");
return NO;
} else {
return YES;
}
}

You can see that the value given in the parameter param is attached to a string which is then set as the label text. In this scenario, every video overlay will have it’s own ID send to the app when clicked on. From this point your imagination is set free. You can at this point react to the users click and do whatever you want.

Download sample project

Again, you can find a sample project at GitHub: InteractiveVideoInterface-Example

A WebView element is a smart and easy way to integrate both platform-independent and dynamic content into an ordinary iOS app. While using it to display webpages might be simple things become more complicated when some kind of interaction between the parent app and the webpage is needed. At the moment there is no common way for a page to send any messages to its WebView controller. This article shows basic principles of a two-way communication, providing a work-around for the function missing.
At the end you’ll find a download link to a full iOS sample project.

Calling JavaScript code from your App

This part is easy: Assuming you have a WebView set up in your project displaying just any page. There is a method called stringByEvaluatingJavaScriptFromString which does the job. Example:

[myWebView stringByEvaluatingJavaScriptFromString:@"alert('Hello World!');"];

Will display – you guessed it – an alert message sent by your webpage. That way you can call any JavaScript function available to your webpage from outside, making it a snap to alter pages on the fly.

Calling functions in your App from inside a WebView

As I mentioned earlier, the other way around is far more complicated. First, we have to think about a way a webpage can communicate to an app. Fortunately, the WebView element provides some interesting attributes and events.
First of all an event called shouldStartLoadWithRequest is fired when a page is requested. Here is an example implementation:

-(BOOL)myWebView:(UIWebView*)myWebView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNaviagtionType)navigationType {
   [...]
}

The great thing about this function is that it is called before the page actually gets loaded and that it expects a boolean as a return. Returning YES makes the WebView start loading the desired page while returning NO stops it from doing so.
Now the plan is as follows: A JavaScript function loads a fictional page including some GET parameters via window.location. Because of the special URL keyword the app is able to figure out whether a real page should be loaded or an in-app function is called (namely an app-call). At that point the function can stop the request and execute the action or just let it load.
So the above function needs to get two things done:

  • check whether a normal link or an app call is requested and returning the proper boolean
  • extract given parameters and check if they fit into predefined actions

Based on a sample by tetontech this is the code we are going to talk about:

- (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType {
 NSString *url = [[request URL] absoluteString];
 NSLog(@"Requesting: %@",url);
 NSArray *urlArray = [url componentsSeparatedByString:@"?"];
 NSString *cmd = @"";
 NSMutableArray *paramsToPass = nil;
 // isolate command and parameters
 if([urlArray count] < 1){
 NSString *paramsString = [urlArray objectAtIndex:1];
 NSArray *urlParamsArray = [paramsString componentsSeparatedByString:@"&"];
 cmd = [[[urlParamsArray objectAtIndex:0] componentsSeparatedByString:@"="] objectAtIndex:1];
 int numCommands = [urlParamsArray count];
 paramsToPass = [[NSMutableArray alloc] initWithCapacity:numCommands-1];
 for(int i = 1; i < numCommands; i++){
 NSString *aParam = [[[urlParamsArray objectAtIndex:i] componentsSeparatedByString:@"="] objectAtIndex:1];
 [paramsToPass addObject:aParam];
 }
 }
 if([cmd compare:@"toggleWorking"] == NSOrderedSame){
 NSLog(@"Turning working indicator...");
 if([UIApplication sharedApplication].networkActivityIndicatorVisible == NO) {
 [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
 NSLog(@"...on");
 } else {
 [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
 NSLog(@"...off");
 }
 } else if([cmd compare:@"logMessage"] == NSOrderedSame) {
 NSString *message = [[paramsToPass objectAtIndex:0] stringByReplacingOccurrencesOfString:@"%20" withString:@" "];
 NSString *message = [[paramsToPass objectAtIndex:0] stringByReplacingPercentEscapesUsingEncoding:NSASCIIStringEncoding];
 NSLog(@"Received JS message: %@",message);
 }
 // only load the page if it is the initial index.html file
 NSRange aSubStringRange = [url rangeOfString:@"index.html"];
 if(aSubStringRange.length != 0){
 return YES;
 } else {
 NSLog(@"App call found: request cancelled");
 return NO;
 }
}

As stated before this function extracts and isolates every parameter and command given and runs through a couple of if-statements to check whether a command is recognized. If that’s the case additional arguments might be used to execute an action.

In this example there are just two possible actions to call: By requesting ?cmd=toggleWorking a spinning wheel in iPads’ tab bar is turned on or off depending on it’s current state. Second action logMessage might be called like this: ?cmd=logMessage&param=Hello%20World. It will forward any given message to the debug console as a log.

NSRange aSubStringRange = [url rangeOfString:@"index.html"];
if(aSubStringRange.length != 0){

The last check is really important! Assuming your mainpage is named index.html this makes sure the page gets loaded once at start. Other requests are blocked right now but you can most likely think of different approaches to make sure app calls don’t get loaded.

Download sample project

Header over to GitHub and download the WebViewInterface-Example
Source:

In order to implement your own style ideas or a given layout it might be necessary to create custom UITableViewCells with round corners. In the App the UITableView might look like this:

UITableViewCells with round corners

With your custom UITableViewCell class and some core graphics it’s quite easy to solve this problem.

Open your project in XCode. At first we have to add a new file of type UITableViewCell. I call it “RoundedTableViewCell”.

We have to import the QuartzCore framework which includes all core graphics.

#import <QuartzCore/QuartzCore/>

Don’t forget to add it also to the “frameworks” folder of your project:

add QuartzCore FRamework to your project add QuartzCore framework

In the RoundedTableViewCell.h-file we define a CALayer for every corner of the cell. These small square layers will later on “cover” the round corners where desired.

CALayer* topleft;
CALayer* topright;
CALayer* bottomleft;
CALayer* bottomright;
CALayer* bglayer;
...
@property (nonatomic, retain) CALayer* topleft;
@property (nonatomic, retain) CALayer* topright;
@property (nonatomic, retain) CALayer* bottomleft;
@property (nonatomic, retain) CALayer* bottomright;
@property (nonatomic, retain) CALayer* bglayer;

We also need two BOOLs:

BOOL roundTop;
BOOL roundBottom;
...
@property (nonatomic) BOOL roundTop;
@property (nonatomic) BOOL roundBottom;

.. and two methods to tell the single cell to have round corners at the top and/or the bottom:

-(void) drawRoundTop;
-(void) drawRoundBottom;

That’s it for the .h-file. In the RoundedTableViewCell.m we have now to implement the rounded corners. At first we define a corner radius and a background color for the cell (between #import and @implemetation):

#define rad 15  // radius
#define normalColor [UIColor colorWithRed:0.39 green:0.15 blue:0.24 alpha:1.0]  // cell background color, dark red

Whithin the implementation we have to synthesize our defined CALayers and BOOLs:

@synthesize topleft;
@synthesize topright;
@synthesize bottomleft;
@synthesize bottomright;
@synthesize bglayer;
@synthesize roundTop;
@synthesize roundBottom;

In the initWithStyle-Method we define an UILabel with some style attributes:

// add label
 label = [[UILabel alloc] initWithFrame:self.contentView.frame];
 label.textAlignment = UITextAlignmentLeft;
 label.backgroundColor = [UIColor clearColor];
 label.textColor = [UIColor whiteColor];
 label.font = [UIFont fontWithName:@"Zapfino" size:16];
 [self.contentView addSubview:label];

// initial values
 roundTop = NO;
 roundBottom = NO;
// set layer background color (= cell background color)
 self.layer.backgroundColor = normalColor.CGColor;

Still within the initWithStyle-method, we set the initial cell style without round top or bottom corners and set the cell’s background color:

roundTop = NO;
roundBottom = NO;
self.layer.backgroundColor = normalColor.CGColor;

Our custom drawRect method will draw our round corners, depending on the defined corner radius. Then the round corners are “covered” by drawing a CALayer for every corner:

- (void) drawRect:(CGRect)rect{
	CGRect fr = rect;

	fr.size.width = fr.size.width-2*rad;
	fr.size.height = fr.size.height-1;
	fr.origin.x = rad;

	// draw round corners layer
	bglayer = [CALayer layer];
    bglayer.backgroundColor = normalColor.CGColor;
	bglayer.cornerRadius = rad;
	bglayer.frame = fr;
	bglayer.zPosition = -5;	// important, otherwise delete button does not fire / is covered
	[self.layer addSublayer:bglayer];

	// set label size (adjust to heightForRowAtIndexPath..)
	label.frame = CGRectMake(rad, 5, fr.size.width, fr.size.height);

	// corner layer top left
	topleft = [CALayer layer];
    topleft.backgroundColor = normalColor.CGColor;
	CGRect tl = CGRectMake(rad, 0, rad, rad);
	topleft.frame = tl;
	topleft.zPosition = -4;
	if(roundTop){
		topleft.hidden = YES;
	}else {
		topleft.hidden = NO;
	}
    [self.layer addSublayer:topleft];

	// corner layer top right
	topright = [CALayer layer];
    topright.backgroundColor = normalColor.CGColor;
	topright.frame = CGRectMake(fr.size.width, 0, rad, rad);
	topright.zPosition = -3;
	if(roundTop){
		topright.hidden = YES;
	}
	else {
		topright.hidden = NO;
	}
    [self.layer addSublayer:topright];

	// corner layer bottom left
	bottomleft = [CALayer layer];
    bottomleft.backgroundColor = normalColor.CGColor;
	bottomleft.frame = CGRectMake(rad, fr.size.height-rad, rad, rad);
	bottomleft.zPosition = -2;
	if(roundBottom){
		bottomleft.hidden = YES;
	}else {
		bottomleft.hidden = NO;
	}
    [self.layer addSublayer:bottomleft];

	// corner layer bottom right
	bottomright = [CALayer layer];
	bottomright.backgroundColor = normalColor.CGColor;
	bottomright.frame = CGRectMake(fr.size.width, fr.size.height-rad, rad, rad);
	bottomright.zPosition = -1;
	if(roundBottom){
		bottomright.hidden = YES;
	}else {
		bottomright.hidden = NO;
	}
    [self.layer addSublayer:bottomright];

	[super drawRect:rect];

}

Now we implement both methods to show round corners on top or bottom of the cell by hiding the appropriate CALayers:

-(void) drawRoundTop{
roundTop = YES;
topleft.hidden = YES;
topright.hidden = YES;
}

For the cell bottom:

-(void) drawRoundBottom{
roundBottom = YES;
bottomleft.hidden = YES;
bottomright.hidden = YES;
}

Ok, our custom UITableViewCell class is ready for use. Therefore we open our UITableViewController file (.m). In the viewDidLoad method we have to implement at least the first line of the following code (if not, the standard table background view will hide our new cells).

// important! without this line it does not work!
[self.tableView setBackgroundView:[[[UIView alloc] init] autorelease]];
// set plain background color
 [self.tableView setBackgroundColor:[UIColor colorWithRed:0.69 green:0.81 blue:0.79 alpha:1.0]];
// remove seperator color
 self.tableView.separatorStyle = UITableViewCellSeparatorStyleSingleLine;
 [self.tableView setSeparatorColor:[UIColor clearColor]];

In my case I have defined two sections, one with normal cells and one with rounded cells, like a separate block. The cell type is defined in the cellForRowAtIndexPath method like this:

if (indexPath.section == SECTION_NORMAL) {

 static NSString *CellIdentifier = @"Cell";

 NormalTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
 if (cell == nil) {
 cell = [[[NormalTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
 }
 cell.label.text = @"normal cell";
 return cell;

 } else if (indexPath.section == SECTION_ROUNDED) {
// define round cell
 static NSString *CellRoundedIdentifier = @"RoundedTableViewCell";
 RoundedTableViewCell *cell = (RoundedTableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellRoundedIdentifier];
 if (cell == nil) {
 cell = [[[RoundedTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellRoundedIdentifier] autorelease];
 }

 // Configure the cell.
 [cell.label setText:[NSString stringWithFormat:@"my round cell No.%d",(indexPath.row+1)]];
 cell.selectionStyle = UITableViewCellSelectionStyleNone;
 // draw round top corners in first row
 if(indexPath.row == 0){
 [cell drawRoundTop];
 }
// draw round corners in last row
if (indexPath.row == [self.tableView  numberOfRowsInSection:indexPath.section]-1) {
 [cell drawRoundBottom];
 }

 return cell;
 }

In order to set a margin between both sections, use the heightForHeaderInSection and the viewForHeaderInSection methods:

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {

 UIView* header = nil;
 if(section == SECTION_ROUNDED){
 CGRect rect = CGRectMake(0, 0, self.tableView.frame.size.width, [self tableView:(tableView) heightForHeaderInSection:section]);
 header = [[UIView alloc] initWithFrame:rect];

 }
 return header;
}

- (CGFloat) tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
 CGFloat h = 0;
 if(section == SECTION_ROUNDED){
 h = 15;
 }
 return h;
}

You can download the zipped XCode example project from github.

When developing Apps for the Android OS you might end up in the situation where you have common Activities or Services which could be reused in multiple Apps with just a little modification. As you don’t want to copy these classes into every single project – which would lead to a hardly maintainable code – you would seek a way to reference the source of these classes from multiple projects. For non-android applications an approach for this problem would be to break up the code into multiple libraries so that the required functionality can be referenced from multiple projects. As long as you are not interacting with external resources this attempt is also possible in Android projects (build a jar and reference it from the projects). But if you are using external resources these classes can’t be used within a library. This is caused by the fact that the Android SDK won’t generate matching ids within the “R” class for external resources which are included in a referenced jar file. In this post I want to show you different solutions for this problem which can avoid the necessity to copy the source code into the projects.

About a year ago we decided to give the Bean Validation API a try and in the beginning we were really exited about the easy to use, annotation based interface. But soon we had to do cross-field validation which lead us to revise our first impression. Unfortunately the Bean validation API offers no out of the box way of validating a field based on the value of another field and since we wanted to stay consistent with the API design we decided to go down the rocky road of writing our own custom class-level validation annotations and custom validators which really is a boring, repetitive chore and involves heavy use of reflection.

Of course boring, repetitive chores really cry for simplification and automation and therefore I soon started doing research on how others solved this problem. In this article I will outline and analyze some of the solutions I came across.

The standard approach

Creating new validation logic involves two steps. A constraint annotation and a validator which contains the validation logic have to be created. To keep things simple we will implement a class-level constraint which can be used to assert that the value of one field is greater than the value of another field of the object to be validated.

This is the annotation definition:

/**
* Compares two of the fields of an object.
*/
@Target({ TYPE, ANNOTATION_TYPE })
@Retention(RUNTIME)
@Constraint(validatedBy = GreaterThanValidator.class)
public @interface GreaterThan {

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};

    String field();

    String greaterThan();

    /**field > greaterThan*/
    Class<? extends Comparator<Object>> comparator();

    @Target({ TYPE, ANNOTATION_TYPE })
    @Retention(RUNTIME)
    @interface List {
        GreaterThan [] value();
    }
}

The “field” and “greaterThan” fields contain the names of the bean properties which will be compared. For this comparison we also need a comparator. Finally, we add a “List” field so that we can use more than one instance of the annotation at the class-level.

This annotation definition – already a lot of work for the humble task of comparing two values – pales in comparison to the validator:

/**
* Validates the GreaterThan constraint
*/
public class GreaterThanValidator implements
ConstraintValidator<GreaterThan, Object> {

    /** field > greaterThan ? */
    private String field;
    private String greaterThan;
    private Comparator<Object> comparator;

    /**
    * This will be called before isValid to initialize the validator
    */
    @Override
    public void initialize(GreaterThan ann) {

        field = ann.field();
        greaterThan = ann.greaterThan();
        Class<? extends Comparator<Object>> comparatorClass = ann.comparator();
        try {
            comparator = comparatorClass.newInstance();
        } catch (Exception e) {
            throw new IllegalArgumentException("Can't instantiate comparator",e);
        }
    }

    /**
    * This will be called to validate an object
    */
    @Override
    public boolean isValid(Object validateThis, ConstraintValidatorContext ctx) {
        if (validateThis == null) {
            throw new IllegalArgumentException("validateThis is null");
        }
        Field fieldObj = null;
        Field greaterThanObj = null;
        // Find getters the properties
        try {
            fieldObj=validateThis.getClass().getDeclaredField(field);
        } catch (Exception e) {
            throw new IllegalArgumentException("Invalid field name",e);
        }
        try {
            greaterThanObj = validateThis.getClass().getDeclaredField(greaterThan);
        } catch (Exception e) {
            throw new IllegalArgumentException("Invalid greaterThan name",e);
        }
        if (fieldObj == null || greaterThanObj == null) {
            throw new IllegalArgumentException("Invalid field names");
        }

        try {
            fieldObj.setAccessible(true);
            greaterThanObj.setAccessible(true);
            // get field values
            Object fieldVal = fieldObj.get(validateThis);
            Object largerThanVal = greaterThanObj.get(validateThis);
            // compare
            return fieldVal == null && largerThanVal == null
            || fieldVal != null && largerThanVal != null
            && comparator.compare(fieldVal, largerThanVal) > 0;
        } catch (Exception e) {
            throw new IllegalArgumentException("Can't validate object", e);
        }

    }

}

A lot of work for a simple greater than comparison and it isn’t even production quality code; you would have to add a few more lines for using it in your projects. Of course you could save some work by pushing some of the details into super classes but there are faster ways to achieve the same results. Another problem with this annotation is that it offers no compile-time type safety. Typos in the field names or supplying the wrong comparator class will lead to runtime errors. The following approach solves some of those problems and comes from a forum discussion on the topic (see http://stackoverflow.com/questions/1972933/cross-field-validation-with-hibernate-validator-jsr-303).

The @AssertTrue approach

The @AssertTrue annotation is one of the annotations of the Bean Validation API which are also applicable to methods. It simply asserts that the return value of the annotated method is true when called during validation. So if we just added a public method called isConstraint1Satisfied and annotated it like so:

public class AssertTrueExample {

public int i=0;
public int j=0;

@AssertTrue(message="Constraint 1 is not satisfied")
public boolean isConstraint1Satisfied()
{
return i==j;
}
}

…we could validate our object without breaking into sweat. Let’s see what the authors of the JSR-303 specification have to say about this.

Validating data is a common task that occurs throughout an application, from the presentation layer to the persistence layer. Often the same validation logic is implemented in each layer, proving to be time consuming and error-prone. To avoid duplication of these validations in each layer, developers often bundle validation logic directly into the domain model, cluttering domain classes with validation code that is, in fact, metadata about the class itself. […]

Well, the @AssertTrue solution obviously violates this separation of concerns the Bean Validation API is all about and puts the validation logic into the model class. You might disagree, but in my opinion very often, too little is to be gained by separating those concerns when it comes to internal dependencies. Sometimes it is even harmfull. I will give you one example.

In one of our projects we had to encapsulate the valid parameters for a call to a legacy statistics library into an object. The validity of the parameters for this call is highly dependent on the value of other parameters and there was no way those constraints could have been factored into separate reusable constraint annotations. We created one annotation, one validator and used it once and there is no chance this annotation could ever be reused. The authors of the JSR-303 specification are of the opinion that validation logic in the domain model is often or always clutter, but I would hesitate to call this special kind of validation code clutter. Sure, validation code for an email address and the likes can safely be considered clutter because email addresses are really abundant in most information systems and everyone knows what an email address is and what it should look like; hence the validation logic contains little information for someone reading the code. The validation logic for the parameter class is a totally different topic. It really belongs to the model class, is not reusable and contains a lot of important information. It more or less IS the class and therefore extracting it into an annotation makes little sense. I think the @AssertTrue approach (and also the @ScriptAssert approach) fits this use case much better than any other approach I have come across so far.

The @ScriptAssert approach

Hibernate Validator 4.1 brought us the @ScriptAssert class-level annotation. It is an ingenious application of the Java Scripting API. Instead of writing your custom validation code in java it lets you use one of many supported scripting languages. It more or less shares the strengths and weaknesses of the @AssertTrue approach but is even more concise and has the added advantage of not cluttering the interface of the class with validation methods. This is what the last example would look like if we used the @ScriptAssert annotation:

@ScriptAssert(lang="javascript",script="_this.i==_this.j")
public static class ScriptAssertExample
{

int i=0;
int j=0;

}

The big disadvantage compared to the @AssertTrue approach is of course that using a scripting language comes at the cost of losing compile-time safety.

Conclusion

The most important aspect of the three approaches to cross-field validation considered here is where they put the validation logic; into the model class or into an external validator class. In this article I mainly outlined why it is a bad idea to create a custom validator and annotation every time the Bean Validation API supplied annotations don’t fit your needs. But don’t get me wrong, I am not saying that putting the validation logic into the model class is always a good idea. There are at least two things that have to be considered:

  • Is it unlikely that the validation logic can be reused?
  • Does it contain important information that really belongs in the model class?

I think that if you can answer any of those questions with a ‘yes’ you can really put the validation logic into the model class without having to suffer a bad conscience.

In the next article I will present a hybrid approach based on the strategy pattern. This approach makes it possible to easily implement new reusable constraints without the need for a validator per constraint. It will let you choose where to implement validation logic and allow you to target not only types but also fields.