Wednesday, January 30, 2013

My take on mobile hybrid apps

Some time ago I posted on Linkedin Google Android Group a comment with my take on benefits and disadvantages of PhoneGap (also known as Apache Cordova) taken from my own experience. It appears that my post attracted some attention. So I decided to re-post it here so that it can be found easier:

I've written several apps and quite a number of plugins. There are both pro's and con's to PhoneGap (now Apache Cordova) the way I see it:

Pro's:
  • Development of the UI part goes pretty fast. Mostly due to productivity you can gain with using Javascript frameworks. 
  • The 'write once run everywhere promise' holds to some extend. See con's one the same topic. Indeed you write your app in javascript html css and you can share a significant part of the app across platforms.
  • The performance is OK-ish depending what you need to do. If you write just data-driven apps - sure why not.
  • There is somewhat clear separation between the native part and the Javascript part of the application. Enables you to define an API for implementing native parts of the plugins and have the JS part of the plugins as common codebase.
  • If for whatever reason (not asking you why) you want the app look the same on all platforms - this is just for you.

Con's:

  • Don't expect native look and feel. Users will definitely are going to notice slower framerate and non-native scrolling and animation effects. So, watch out if you want to write a UX-rich application.
  • The 'write once run everywhere' promise fades with the number of plugins you have to implement. The more complex your application is the more plugins you need to write for each platform - and this is still native code.
  • Prepare to fight the browser fragmentation issues. The richer UX you want to bring to the users the more issues you are going to see. Mobile web app development frameworks still suffer from browser fragmentation. Do not forget different levels of HTML5 support across browsers (in case you think its a silver bullet).
  • Phonegap is essentially a native app a webapp in one. This means 'double' the memory footprint.
  • Talking about used resources (and to emphasize above) - did you know it actually runs a *socket server* in your app (speaking for android part here)?
  • Beware PhoneGap is not desinged to run in background (this is actually official). Which means all background processing needs to be done in native and integrated with PhoneGap via the plugin API.
  • Debugging and (automated) testing of Phonegap apps still requires a lot of improvement. Even though some tools are available they are nothing comparing to a regular in -IDE or -browser debugging.
  • Phonegap API is asynchronous which may make it cumbersome if you have a lot of integration with native plugins.
  • Native apps are *more* capable of dealing with different screen sizes and specifically screen densities and orientations. Native platforms are actually designed to deal with it.
In summary I would say it's ok to use it for business apps. For rich UX I would advise to go for native implementation.

Wednesday, July 27, 2011

Geo-location based content (content development)

In this part of the coverage of Hippo CMS Google Maps plugin I will show how to use the plugin when designing content types using Hippo CMS.

Btw, If something is not clear the source code also contains a demo project with a document that is already geo-tagged.


Dependency


First of all, in order to use the plugin we need to have the dependency added to your cms project pom:

    
        org.onehippo.plugins
        google-maps-plugin
        1.0
    
Keep in mind to use the latest available version (which is 1.0 at the time of writing).
In order for the plugin artefact to be resolved you can either build it and put it in your repository or fork the project and add it directly to your reactor pom as a module.


Document type


Once the dependency is added the plugin is ready to be used with Hippo CMS. The plugin offers custom compound type called 'Location'. The Location component can be added to the desired document type by selecting Location compound type on the Compound Field panel in the document type editor:


Upon selecting the Location component it will be added to the document type:


The rendering is done by the plugin itself while the structure is kept in the compound type. The location component contains some of the default values, such as latitudelongitude and zoom level.
When the document type is updated with the Location component it is possible to tag documents of that type with GPS coordinates.



Geo-tagging the documents



When opening document for editing the location component will be rendered by the plugin in the same fashion as shown above. Except that the data that is stored in the Latitude, Longitude and Zoom fields will be stored with the document.

The following is typical scenario how a document can be tagged with gps-location:

Let's say we want to tag current document with the location of Amsterdam. For that we could of course lookup the GPS coordinates of the city and manually put those values into the location fields.
Another possibility is to use the Search field which is only used for searching and does not store any values with the document. The plugin tries to find possible matches with as you type:


Once the desired match is selected the map automatically jumps to that place. All is left to do is to choose the right zoom level and click on the map to place a marker:


When the marker is being placed its' coordinates together with the current zoom level are recorded in the location fields:


That's it - the document is tagged! Upon saving (and closing) the document all stored location values (together with a static piece of map) will be displayed along with the rest of the document content:



In the next article I will show how to use that information on your website.

Saturday, July 23, 2011

Geo-location based content (Intro)

The deeper we go into the mobile age the more location based services surround us. Content management systems also have to keep up. In the end - location based-content always follows the location based services.
Being open source enthusiast I am using Hippo CMS for one of my hobby projects where I need to have the ability to tag content with GPS coordinates so that I could use, for example Google Maps, to show how the content is related to a certain place.

While it's certainly easy to assign a couple of meta-data fields to an article it is far from easy to find the desired coordinates and then manually enter add to the content considering you may have thousands of articles! The problem  is  was that those are exactly the requirements I needed! Coming from this an idea for an interactive CMS plugin that would make the editors' live easier was born!

First things first - I was looking for something that might already exist. Unfortunately, I couldn't find anything that was operational.
Eventually - after several evenings of coding and troubleshooting -  the initial version of the Hippo CMS Google Maps plug-in was ready and hosted on github.

In the next blog post I will show how to use the plugin on website (where the content is published) and on the CMS front-end (as content developer and author).

Thursday, January 6, 2011

Easy unit testing for Android

Testing and Mocking

Everyone who is, like me, 'spoiled'  by mocking frameworks like Mockito, EasyMock, etc know the pain of trying to write compact and readable unit tests for Android. Of course there is JUnit built-in support in Android that offers the whole battery of base classes in order to perform integration testing. And, surely, there is a number of base mock classes that are supposed to allow proper unit testing. However when it comes to writing the tests those mock classes are not really 'nice' mocks. They are not really that 'nice' because they do stuff like:

/**
 * A mock {@link android.content.Context} class.  All methods are non-functional and throw 
 * {@link java.lang.UnsupportedOperationException}.  You can use this to inject other dependencies,
 * mocks, or monitors into the classes you are testing.
 */
public class MockContext extends Context {

    @Override
    public AssetManager getAssets() {
        throw new UnsupportedOperationException();
    }

    @Override
    public Resources getResources() {
        throw new UnsupportedOperationException();
    }
...

}

As you can see it throws exceptions on every invocation, which means that if you want to use it you have to extend it. Problem is that it almost never limited by overriding just one method. And because your test cases are probably different the re-use of the extended MockContext is pretty limited and, again, if you try to create a re-usable MockContext the amount of effort will be somewhat close to re-writing the platform classes! So to go on with it you might start creating a number of subclasses of MockContext's to serve your particular needs. By the way, this is exactly what all the built-in subclasses of the MockContext do - even though they are a part of the public API if you have a closer look at them you might notice those are written for some particular cases to test the Android platform itself! But even those are not generic enough as you can see in this example:

RenamingDelegatingContext targetContextWrapper = new RenamingDelegatingContext(
                new MockContext2(), // The context that most methods are delegated to
                getContext(), // The context that file methods are delegated to
                filenamePrefix);

As you can see all sorts of compositions, extensions happen a lot.

Mockito to the rescue?

"Use a mocking framework" - many will probably think. Well, it's not as simple. The problem is that Dalvik VM is not really a Java VM. And most known pure-java mocking frameworks wont work out of the box, e.g. http://code.google.com/p/mockito/issues/detail?id=57
Some mocking frameworks require interfaces, which Android isn't really full of (for good reasons given the circumstances). Some mocking frameworks can do more than others and some have more or less ease of use.
Besides, if you base your classes on Android base TestCases it will run only on the emulator which isn't fast enough for unit testing.

So use the standard Java VM?

Right, the mocking frameworks will shine again! Not as simple again, you would need to mock every single call to classes contained in the Android platform (many of which are static!) which is probably even worse than just extending Android built-in mock classes.
Well, some (even people at Google) try to do it, but when I tried to repeat it with the real code I just gave up on the amount of work needed to be done just to perform simple testing.

Stumbled upon


And then I stumbled upon Robolectric. Robolectric is capable of either creating 'nice' stubs that don't throw RuntimeException("Stub!") (which is what happens if you use classes from distributable android.jar) or delegating calls to the classes in the Android platform. Basically, you can run unit tests outside the emulator in super-fast Java VM with all the mocking frameworks you like!

This allowed me to use my favorite Mockito without the need of having a separate test project, I simply employed maven!

There are plenty of articles on the Internet on how to mavenize android projects. My setup isn't much different from those so I will just focus on further customization. Quickly, I enabled dependencies to run Robolectric and Mockito in the test phase:


        
            com.pivotallabs
            robolectric
            0.9.5
            test
        
        
            junit
            junit
            4.8.2
            test
        
        
            org.mockito
            mockito-all
            1.8.5
            test
        
        
            com.google.android
            android-test
            test
            2.2.1
        
        
            com.google.android
            android
            2.2.1
            provided
        
    

If you notice I use a version of JUnit somewhat newer than the one bundled with Android SDK.
When we want to write a test case we annotate it with the Robolectric runner which does all the magic of running the unit test code on regular JVM:

@RunWith(RobolectricTestRunner.class)
public class HudsonViewProcessorUnitTest {

Creating Mockito mocks then is nothing but the usual:

@Before
    public void setUp() {
        contextMock = mock(Context.class);
        parserMock = mock(ViewJsonParser.class);
        hudsonStatusDaoMock = mock(HudsonStatusDAO.class);
        hudsonJobDaoMock = mock(HudsonJobDAO.class);
    }

Note, that I create a mock of the regular Context class in Android. And since Mockito creates 'nice' mocks by default in my particular case I didn't have to stub much of it!

Creating a test case is also very straight forward:

@Test
    public void testSimple() throws BuildParsingFailedException {
        HudsonViewProcessor hudsonViewProcessor = new HudsonViewProcessor(contextMock, defaultStatusBean, true);
        injectMocks(hudsonViewProcessor);
        List<HudsonJobBean> hudsonJobs = createHudsonJobs(WIDGET_ID, "blue", "yellow", "red");

        when(parserMock.parseHudsonJobs()).thenReturn(hudsonJobs);

        ...
    }

You might notice I don't use dependency injection which is, again, not supported by Android by-default. So I pass dependencies either via constructor or via setter methods (I have used both ways in this example) which allows me to reduce discomfort of not having dependency injection and still having the code testable.

My next stop would be to have a look at RoboGuice and see if dependency injection is usable and fast enough on Android after JIT was introduced.

The combination of the two frameworks Rolectric and Mockito made unit testing on Android fun again!
Published with Blogger-droid v1.6.5

Friday, October 8, 2010

A new version of Android Hudson Mood Widget


After long re-factoring, improvements and weeks of field testing a new version of the Android Hudson Mood Widget is released! The application went through almost complete overhaul! Besides a number of bug-fixes a lot o new functionality is added, such as gzip support, ability to trigger builds from the phone, etc. The version numbering jumped from 0.10 to 1.0b (yes it'll always be in beta :-). The big jump can be explained by the fact that the app went through major changes. The release notes can be found at the end of this article. Here is an overview of how the application looks like now and what it can do:

Widget and notifications

The main purpose of the application remains the same - monitor hudson instances in the background, show monitored status in a simple way by using the traffic lights colors: red, yellow, green (and unknown) as shown below:


When build status of a job on the monitored hudson view or page changes the application shows notifications with information about the status change. Upon touching the notification a built-in browser opens that will show monitored jobs and their statuses.

Main screen

In the previous version the main screen of the application was the configuration screen which is now replaced by a built-in browser (the same screen now opens when a notification icon is touched or clicked).

The title of the browser displays the name that the monitored hudson view that was given on the Settings screen. The main area displays list of hudson jobs with their status at the moment of syncing, with the support of animations in hudson-style indicating builds in progress. The main screen also contains menu options that consists of three items:

The first one (Browser) allows to see the same page but in the phone browser essentially opening that very same page in it!
The second on - refresh - allows refreshing the page which fetches the latest info on the monitored hudson view.
And, the third one - Settings menu item which basically leads us to the Settings screen where you can change the configuration of the monitored hudson instance or any of the general settings.

Job Details screen


Upon clicking/touching a job on the main screen a job details view opens. This one displays the latest status of the job which includes the job build number, it's stability level, health and description.
The options menu here also allows refreshing the job details, opening the job details in phone regular browser and, finally, you can trigger the build of that job! Of course, if the job is not build-able (which can be the case if it's disabled) - the option is grayed out.










Settings screen

The settings screen is also the one that opens when the widget is added to the home screen for the first time. It contains two tabs: one build specific and generic which are shared among all instances of Hudson Mood widget. The main options on the build specific tab are:

  • The widget name (also displayed on the home screen under the widget).
  • The hudson view URL among with a button opening another built in browser (see the next section below). Both http as well as https protocols are supported.
  • Login information, in case access to the monitored builds requires authentication.
  • 'Test build status' button that allows for quick check (before you can close the window) on whether the hudson instance can be reached and whether the build can be detected.
The second, 'General', tab contains options, shared among all instances of the widget and contain options such as ability to enable or disable sound or vibration notifications (or disable notifications altogether). One of the options also allows you to ignore such situations when the hudson status can not be read or interpreted, this can happen, for example, when you have poor connectivity with your mobile provider or if your hudson instance is only accessible via wifi and you left the coverage zone (or switched wifi it off)...
Last but not least, the update frequency for widgets. Frequencies, marked with the * are the ones that are least demanding on the battery consumption. This has to do with the way Android schedules background tasks.




Build detection browser

One and not unimportant screen is the build detection browser which is yet another built-in browser of the application, this screen can be accessed by pressing the button located to the left of the URL text field on the 'Build' tab.
Why would you need it? In case if the URL of the monitored hudson instance is too long or difficult to type, you can open up that internal browser and type-in any URL there. The browser similar to the regular Android browser and is capable of detecting whether opened page contains hudson views or jobs that can be monitored by the widget! For instance if you don't want to monitor the main page of the hudson instance but separate views or even individual jobs imagine how long and complex the URLs can be?! Well, in this case you only have to type the url of the main hudson page which is usually pretty short and then navigate to the desireable view that you want monitored! After you've naviated to the right page just click the 'save' button and the url will be automatically picked up by the Settings screen in the URL preference.



That was an overview of new features, here is the total list of changes that the last version of the application went through (the full changelog can be found on Hudson official wiki):


Version 1.0b changelog:

Bugfixes:
  • Fixed a session cookie bug preventing from detecting build statuses with the Build Detection browser on Hudson versions 1.379 and higher
  • Fixed a bug preventing from detecting job status with the 'test URL' button for individual jobs
Features:
  • New main screen with jobs overview
  • Job details view
  • 'View in browser' feature for both main screen and job details view
  • Animation support for builds in progress
  • Ability to trigger job builds
  • Support for GZIP encoding - reduces battery consumption!
  • Based in user feedback the Test URL button is renamed to 'Test build status' to be less confusing

Friday, July 2, 2010

Hudson xvnc plugin under openSuse

It took a me a bit of struggling to configure hudson xvnc plugin under openSuse in order to run android emulator.
The problem I was having is that xvnc was failing to start even if I configured it for password previously:

vncserver: Could not create /root/.vnc

what immediately seemed odd is that it tried to create files under the root while Hudson was running under its own user!

Not sure what the plugin was doing but it's fixed by giving it a tip on the correct home which is done in configuration (which is left empty by default) of the xvnc plugin in Hudson:

Command line:


env HOME=/home/hudson vncserver :$DISPLAY_NUMBER -geometry 800x600


It's probably a good idea to play with the arguments but vncserver is now starting:


Starting applications specified in /home/hudson/.vnc/xstartup
<pre style="white-space: pre-wrap; word-wrap: break-word; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; ">Log file is /home/hudson/.vnc/hudsonsrv:30.log


And after all is done we see its being termiated:


Terminating xvnc.


UPDATE: I have to give up the hudson-android plugin for a bit (until it starts working of course :) and start the emulator in /home/hudson/.vnc/xstartup (as shown in the logs) by inserting the command for launching the emulator in that script...


Thursday, October 15, 2009

Hudson Mood widget for Android

I've launched a simple Android widget which gives a simple way of monitoring builds on continuous integration server called Hudson. The main purpose of this application is to provide a simple way to monitor builds.

It takes up little space on the home screen (only one widget cell) of Android and gives a clear indication of whether builds on Hudson are stable, unstable or they are failing.

If all the builds are stable the Hudson widget is highlighted with green and Mr. Hudson is happy.
If any of the builds has become unstable the widget is highlighted with yellow and Mr. Hudson doesn't look as enthusiastic.
If there are any failing builds on the monitored page the widget gets highlighted with red and Mr. Hudson looks very upset.
And in case the build status could not be read (e.g. the server is down, authentication failed or no build information was found at the provided address) Mr. Hudson is hidden behind big question mark:


The setup screen is pretty simple at the moment (I expect to add more features in the future).


It is also possible to test the build status from the settings screen to verify whether the build status is readable in which case the state of the build will be provided next to the 'Test URL' button, otherwise 'unknown' status will be displayed (default).

At the moment widget supports monitoring only builds aggregated on the main page (either on the default 'All' view or a custom view), although, it is possible to monitor individual builds by putting them in a custom view.

To install Hudson Mood widget search for 'Hudson Mood' in the Android Market on your Android.

Update: eventual updates will be published on the Hudson Wiki !