Saturday, June 25, 2011

How to show turn by turn directions on Android

As you can probably make out, these days I am working on an Android project.  And I will tell you one thing, I am loving it!
I have worked on iOS, BREW and Simbian OS in the past but the productivity, while developing on Android is far better than the other platforms!

Excellent job Android guys!

Coming back to the post topic, recently I in one of the Android projects, we had a requirement that we wanted to show turn by turn directions between two geo points.

We are all familier with the excellent support for Turn by turn directions on the native Google Maps application.

Although, Android API permits us embed a maps view in the application, but it does not provide a way to show turn by turn directions between two geo points.

In early days of Android (SDK 1.0), Google had provided the DrivingDirections class.  Using this class it was possible to get the driving directions between two geo points.  However, since SDK 1.1, Google removed the DrivingDirections class from the API. 

Why would they remove something as useful as this?

Because it violated some of the legal agreements made by Google.  Extract from the Google Maps terms states that
8.3 Content License. Subject to these Terms (including but not limited to Section 9 (License Requirements) and Section 10 (License Restrictions)), Google gives you a personal, worldwide, royalty-free, non-transferable, non-assignable, and non-exclusive license to access, use, publicly perform and publicly display the Content in your Maps API Implementation, as the Content is provided in the Service, and in the manner permitted by the Terms. Specifically, you understand the following:


(a) Content (including but not limited to map data, traffic, directions, and places) is provided for planning purposes only. You may find that weather conditions, construction projects, closures, or other events may cause road conditions or directions to differ from the results depicted in the Content. You should exercise judgment in your use of the Content.
(b) Certain Content is provided under license from third parties, including Tele Atlas B.V. ("Tele Atlas"), and is subject to copyright and other intellectual property rights owned by or licensed to Tele Atlas and/or such third parties. You may be held liable for any unauthorized copying or disclosure of this content. Your use of Tele Atlas map data and certain other Content (including certain business listings Content) is subject to additional restrictions located in the Legal Notices page.

 In simple terms, Google has tied up with many Third party companies to get the mapping and other information.  The terms of the agreement do not allow them to expose those functionality in an open source project.  This is the reason why they removed the DrivingDirections API since SDK 1.1

All right fine!  Google could not expose that as API's, but we sill have this requirement to fulfill.  We want to show turn by turn directions between two geo points on Android platform.

How do we do it?

As we all know that the native Google Maps application (which comes pre-installed on all Android devices) does a great job of showing Turn by Turn driving directions.  The updated application also provides a link to Google Navigate (beta) which shows 3D maps and updates the route as the user location changes.

We should definitely try and make use of this feature for our requirement.  After all, why reinvent the wheel!

Hence now, our tasks are:
  • To invoke the native google maps application
  • Show turn by turn directions between two geo points on the native google maps application
One very big plus of the Android platform is that, it has multitasking support.  Because of this, when user clicks the back button on the phone, they will come back to our application, user does not feel they are navigating away from our application.  This enhances the user experience quite a lot!

So the questions is how do we invoke the native Google Maps application to show turn by turn direction between two geo points!

Inter process/activity communication on Android platform is done via an Intent.  Hence the answer to our question is: Via an Intent!

Yes and that's the correct answer!  But what Intent, what will be the URL, what should be the parameters?

Slow down, slow down, lets tackle one problem at a time!

This is how they do it!

Looking at this URL it seems that we can invoke the native maps application using the following URLs

One line description for the above url's is
Opens the Maps application to the given location or query. The Geo URI scheme (not fully supported) is currently under development.
The z field specifies the zoom level. A zoom level of 1 shows the whole Earth, centered at the given lat,lng. A zoom level of 2 shows a quarter of the Earth, and so on. The highest zoom level is 23. A larger zoom level will be clamped to 23.
Basically, the description says that, The above URLs will show the maps application which is centered around the given geo point

Hence,

This code will actuall open up the native map application which is centered around the given geo point. We have solved one task from our task list. We have managed to invoke the native google maps application!

But wait!  We want to show two points not just one point on the map.  We also want to show turn by turn directions between those points!

Using the URL i.e. the geo:x:y in the above format, we cannot specify two geo points.  Damn!

I tried many permutations & combinations to specify the second geo point, but nothing worked.

Finally, after a lot of trials and errors I found a workaround to this problem.

This is how its actually done!

The URL geo:x,y does not support the second geo point, hence we can't use that URL.  What is the other URL we could use, which will show turn by turn directions between two geo points?

After some more googling, I found that, we might be able to use the URL format used by  maps.google.com website.  The maps.google.com follows a simple url pattern

The maps.google.com uses two parameters "saddr" (source address) and "daddr" (destination address). If we pass those two parameters correctly it shows, turn by turn directions between those points.
Web Based Turn-By-Turn Directions on Google Maps

Why are we even bothered about viewing turn by turn directions on the web?

Because guess what, we can use the same web based URL pattern on the Android platform!

What?  Yes, we can use the URL http://maps.google.com/maps?saddr=43.0054446,-87.9678884&daddr=42.9257104,-88.0508355 to open up the Google Maps application to see turn by turn directions between two geo points!

The above code surely works! It shows the user, turn by turn directions between the geo points [43.0054446,-87.9678884] and [42.9257104,-88.0508355].

There is only one problem though, Android platform identifies that the above URL can be processed by two Activities!
  • The Browser Activity - Since the URL starts with http:// 
  • The Google Maps Activity - Since the address we are opening up is maps.google.com
Whenever Android platform has more than one options to process an intent, it leaves the choice to users, gives them an option of both the applications and lets them chose the application to fulfill the intent.
User gets an option to chose the application for the processing the Maps URL
User can chose either application, both show driving directions between those two geo points.

Driving directions using the browser application

Driving directions using the Native Google Maps application

How to make this solution better:

Although we have achieved what we intended for.  But there is one extra step that user has to perform, i.e. select the application of his choice to see the driving directions.  At this point, user might notice that he is going out of the current application and into a different application.  There is nothing wrong with this approach but, it does not integrate the Google Maps application seamlessly with our application.

How do we eliminate this extra step of choosing the application to view turn by turn directions?

The answer is simple and we can do this by providing a hint in the Intent we are firing.

The line intent.setClassName("com.google.android.apps.maps", "com.google.android.maps.MapsActivity"); does the trick. We are passing additional information in the Intent. We are informing that, the class name of the activity that should fulfill the intent is "com.google.android.apps.maps/com.google.android.maps.MapsActivity"

That's it! Now Android platform knows that, user wants to see the turn by turn directions on the native google maps application and not on the browser. The extra step of chosing the application is eliminated.

User directly goes to this view
There are many advantage of this approach
  • User can choose to start navigation using Google Navigate (beta) (without us doing anything).
  • User can click back button and return to our application as well!
As we can see, Android platform is pretty awesome, when it comes to ease of development!  Something as complex as showing turn by turn driving directions between two geo points can be achieved by writing 3 lines of code!

Wednesday, June 22, 2011

How to change the text color of Android options menu

As promised in the previous post, here comes the second installment of styling the options menu.  In the previous post we saw how we could change the background color of the options menu.  This time we are going to look at how we could change the text color of Android options menu.

We already know that styling the options menu is not really easy.  As shown in the previous post, its a eight step process.  To change the text color of the options menu we need to put in another hack.  We need to add a ninth step.  Lets look at all nine steps once again.
  1. Setting the custom LayoutInflater.Factory instance.
  2. Implementing the onCreateView method that will actually set the background selector for the options menu.
  3. In the implementation of onCreateView, check if the view that is to be created is of type com.android.internal.view.menu.IconMenuItemView.  Yes, I know, its an *internal* class!
  4. If the view is of type IconMenuItemView then create the view using the LayoutInflater.
  5. At this point we have an instance of IconMenuItemView but we cannot change the background color of the view directly.  Even if we change the background color at this point, framework updates it again and our changes are overwritten
  6. We have to change the background color after the view has rendered, using the Handler API.
  7. Change the background color in run method of the Runnable instance that we pass to the Handler's post method.
  8. Change the text color using reflection.  This is the new step.  We need to change the text color using reflection.
  9. Catch all exceptions that could occur in the entire process.  Notice that, we are using an internal class there are high changes that its behavior could change without any notice.  In fact this approach does not work on Android 2.3.  In this case we have to fallback to the default menu styling.
Lets look at code to make things clear

The menu_selector.xml and colors.xml have been kept unchanged from the previous post.  The comments are embedded in the code.  One new methods has been added setTextColor.  This method does the job for us!
The above screenshot shows the menu item color changes when its pressed.

That's it!  We have successfully changed the background color and text color of Android options menu.

Saturday, June 18, 2011

How to change the background color of Android options menu

I have been trying my hand at developing apps with Android.  I have had my fair share of leanings.  Today I am going to share my experience around styling the options menu in Android.

What is the options menu?

Options menu is the menu that is shown to the user when the Menu key is pressed on the Android phone.

Lets look at an example, that will make things easier to understand.

The layout file.

The above code shows the following GUI
As you can see from the above screenshot the background color of the Activity is greenish while the default Color of the selected element of the options menu is Orange.

It definitely looks inconsistent and ugly.  This is the reason we need to style the options menu to match the rest of the application theme.

Android platform is highly configurable.  One can change all aspects of look and feel on the android platform.  Hence, when this task was given to me, I thought it would be a 2 min fix.  But unfortunately it took much longer than I expected.

All I wanted to do is change the background selector of the options menu.  Android does not provide a straight forward way to do this.  In fact, it meant writing quiet some code.  I decided to write a post on this, so that other can benefit from my learning's.

So back to the original question.  How do we change the background color of Android options menu?

How do they do it?

Now there is nothing fancy about the above code.  But to change the background color we have to write some fancy code :)

Changing the options menu background color is a 8 step process
  1. Setting the custom LayoutInflater.Factory instance.
  2. Implementing the onCreateView method that will actually set the background selector for the options menu.
  3. In the implementation of onCreateView, check if the view that is to be created is of type com.android.internal.view.menu.IconMenuItemView.  Yes, I know, its an *internal* class!
  4. If the view is of type IconMenuItemView then create the view using the LayoutInflater.
  5. At this point we have an instance of IconMenuItemView but we cannot change the background color of the view directly.  Even if we change the background color at this point, framework updates it again and our changes are overwritten
  6. We have to change the background color after the view has rendered, using the Handler API.
  7. Change the background color in run method of the Runnable instance that we pass to the Handler's post method.
  8. Catch all exceptions that could occur in the entire process.  Notice that, we are using an internal class there are high changes that its behavior could change without any notice.  In fact this approach does not work on Android 2.3.  In this case we have to fallback to the default menu styling.
Yep, I know, it looks like a lot of work and pretty complex too.  Lets look at the code to make things more clear.

The menu_selector is an XML file that choses the background color based on the state of the menu item.  My menu_selector.xml looks like this

The colors.xml file looks like

The comments are embedded in the code. One new methods has been added called setMenuBackground. This method does the job for us!

The screenshots of the styled options menu
 As we can see the Options Menu background color has been changed from Orange to greenish.

That's all folks!

We have successfully changed the background color of Android options men.  But wait a minute, how to change the default text color of the Android options menu?  If this question is bothering you stay tuned, in the next post I am going to explain exactly that!

Saturday, June 11, 2011

Visual Studio 2010 Fixing "The referenced project XX does not exist" Error

Recently one of my friend was facing a weird issue while building our application. The application was developed in C#. We were using MSBuild as the build tool.

What was the issue?

The issue was simple, she was not able to compile the application.

The issue was special in many ways because, all of us (i.e. her team members) were able to compile the project just fine. Even the continuous integration service - Jenkins (formally Hudson), was able to compile the application. We were not able to compile the application only on her machine. The build failed with the error

The project "AB.dosomeprojects.Services.FillImporter.Service.csproj" referred the project "abcdefgh.dosomeprojects.Common.csproj" which was in the path "..\..\..\abcdefgh.dosomeprojects\abcdefgh.dosomeprojects.Common". The path was relative to the Service project directory.

The directory structure was correct, Common project was correctly reffered from the Service project, but still we were not able to build the app on her machine.

Initially, we thought that there must me some local changes on her machine because of which, she was not able to run the build on her machine.  Build was not passing neither with Visual Studio 2010 nor with MSBuild and that too only on her machine.

We looked for any local changes on her machine, but unfortunately her machine was clean.  There were no local changes.  We were simply clueless!  Why does the project build fine on other developers machine while it does not build on her machine?

After some intense Googling, we found an interesting hidden treasure shipped silently by Microsoft Visual Studio 2010.  I call such issues as hidden treasure because, I can hardly believe my ears when I hear/read about such an issue.

I am sure it will come as an surprise to you as well.  The issue is:

The Real Problem:

Visual Studio 2010 fails to build the project when the following conditions are met:
  1. Solution with multiple projects exists, where there exists dependency relationships among them
  2. The sum of the following two path length is exactly added up to 259 characters (= MAX_PATH – 1) 
    1. The path of a referencing project’s directory.
    2. The relative path to a referenced project from the current directory (= a referencing project’s directory).
Hmm, cryptic information lets decrypt it.

Condition 1: We have solution with multiple projects where there exists dependency relationships among them

Yes, we do have the solution with multiple projects in it and one project depends on the other.  In our case the AB.dosomeprojects.Services.FillImporter.Service.csproj depends on the abcdefgh.dosomeprojects.Common.csproj project.  Hence, condition 1 is met.

Condition 2: The sum of the following two path length is exactly added up to 259 characters (= MAX_PATH – 1)

This one is tricky.  Which path sum are we talking about?

Condition 2.1: The path of a referencing project’s directory.

The path of the referencing project's directory, in our case the path of the AB.dosomeprojects.Services.FillImporter.Service.csproj on the file system, which was, "E:\projects\ABC\SVN\dosomeprojectsweb\trunk\AB.dosomeprojects.Services\AB.dosomeprojects.Services.FillImporter\AB.dosomeprojects.Services.FillImporter.Service" has total length of 158 chars.

Condition 2.2: The relative path to a referenced project from the current directory (= a referencing project’s directory).

The relative path of the referenced project from the current directory, in our case its the relative path of abcdefgh.dosomeprojects.Common.csproj, which is, "..\..\..\abcdefgh.dosomeprojects\abcdefgh.dosomeprojects.Common\abcdefgh.dosomeprojects.Common.csproj" has total length of 101 chars.

The sum total of these two path lengths: 158 + 101 = 259!


Wow! condition 2 is also met.

As I said, we have uncovered an hidden treasure of Visual Studio 2010.  Its unable to build the project when the path length of referencing project + path length of relative path to a referenced project = 259!

If the sum total is one less or one greater than 259 it all works fine! On other developers machine the total path length was less than or greater than 259 but was never equal to 259 and because of this reason we were all able to build the project but she was not able to build the project on her machine! Weird isn't?

This issue occurs due to a bug in the Path.GetFullPath in .NET Framework library.  This is a known issue in Visual Studio 2010.

The Fix:

The workaround is pretty straight forward, rename one of the folders a bit longer or a bit shorter and make sure that, the sum of the two path length is NOT equal to 259 chars.

For more information on the issue visit the offical Microsoft Knowledge base article here http://support.microsoft.com/kb/2516078

Now you know, we are having so much fun with .Net (sarcasm intended)!
Have some Fun!