I'm back in Cape Breton enjoying the scenery of the Bras d'or Lakes (see picture at left). If you've never been to Cape Breton it is a beautiful place to step back and relax.
Friday, July 27, 2012
On Vacation
I'm back in Cape Breton enjoying the scenery of the Bras d'or Lakes (see picture at left). If you've never been to Cape Breton it is a beautiful place to step back and relax.
Wednesday, July 25, 2012
Proguarding your PhoneGap Android App
If you've ever run into the following error when trying to run Proguard against your Android application using PhoneGap:
-keep public class * extends com.phonegap.api.Plugin
-keep public class * extends org.apache.cordova.api.Plugin
-keep public class org.apache.cordova.DroidGap
-keep public class org.apache.cordova.**
-libraryjars /Path/To/PhoneGap/libs/commons-codec.jar
-dontwarn android.webkit.*
I can't take credit for this as it was passed onto me by Nasir Hussain who figured it out while trying to proguard his own app. He thought that others reading this blog may find the information useful. Thanks Nasir!
Proguard returned with error code 1. See console Warning: org.apache.cordova.CameraLauncher: can't find referenced class org.apache.commons.codec.binary.Base64 Warning: org.apache.cordova.CameraLauncher: can't find referenced class org.apache.commons.codec.binary.Base64 Warning: org.apache.cordova.CordovaWebView: can't find referenced method 'WebView(android.content.Context,android.util.AttributeSet,int,boolean)' in class android.webkit.WebView Warning: org.apache.cordova.CordovaWebViewClient: can't find referenced method 'android.webkit.WebResourceResponse shouldInterceptRequest(android.webkit.WebView,java.lang.String)' in class android.webkit.WebViewClient Warning: org.apache.cordova.CordovaWebViewClient: can't find referenced class android.webkit.WebResourceResponse Warning: org.apache.cordova.CordovaWebViewClient: can't find referenced class android.webkit.WebResourceResponse Warning: org.apache.cordova.CordovaWebViewClient: can't find referenced class android.webkit.WebResourceResponse Warning: org.apache.cordova.CordovaWebViewClient: can't find referenced class android.webkit.WebResourceResponse Warning: org.apache.cordova.CordovaWebViewClient: can't find referenced class android.webkit.WebResourceResponse Warning: org.apache.cordova.FileUtils: can't find referenced class org.apache.commons.codec.binary.Base64 Warning: org.apache.cordova.FileUtils: can't find referenced class org.apache.commons.codec.binary.Base64 Warning: there were 9 unresolved references to classes or interfaces. You may need to specify additional library jars (using '-libraryjars'). Warning: there were 2 unresolved references to program class members. Your input classes appear to be inconsistent. You may need to recompile them and try again. Alternatively, you may have to specify the option '-dontskipnonpubliclibraryclassmembers'. java.io.IOException: Please correct the above warnings first. at proguard.Initializer.execute(Initializer.java:321) at proguard.ProGuard.initialize(ProGuard.java:211) at proguard.ProGuard.execute(ProGuard.java:86) at proguard.ProGuard.main(ProGuard.java:492)It can be resolved by adding the following lines to your proguard.cfg file:
-keep public class * extends com.phonegap.api.Plugin
-keep public class * extends org.apache.cordova.api.Plugin
-keep public class org.apache.cordova.DroidGap
-keep public class org.apache.cordova.**
-libraryjars /Path/To/PhoneGap/libs/commons-codec.jar
-dontwarn android.webkit.*
Tuesday, July 24, 2012
Updates to Plugins for PhoneGap 2.0.0
I've spent a bit of time this morning updating the plugins that I'm nominally responsible for on Android so that they conform and work with the PhoneGap 2.0.0 API. You should be able to get the following plugins from the github plugins repo and just drop them into your project using the latest version of PhoneGap. I've also kept around the code from the previous versions of the plugin for folks using older PhoneGap versions.
- Application Preferences
- Barcode Scanner
- Child Browser
- IMEI
- Video Player
The next step in the plugin migration to the new API will be to conform with Andrew Lunny's proposal for a Cordova Plugin Spec. Moving to this spec will make it much easier for PhoneGap dev's to discover and install plugins. Yup, exciting things are coming down the pipe. I'm going to work on that as soon as I can but I wanted to make sure I got these updates out before my vacation.
Enjoy!
Update (2012/08/09): As of PhoneGap 2.0 the plugins.xml file has been deprecated. It has been replaced with config.xml. So if you are starting a brand new project that has config.xml in the res/xml directory you will need to add your plugin declarations to this file. If you are using an older version of PhoneGap or upgrading an older project to PhoneGap 2.0 you can still use the plugins.xml file as we've got backwards compatibility (sort of). Please note though config.xml will take precedence over plugins.xml so you should not have both files in one of your projects as you'll end up tearing your hair out.
Enjoy!
Update (2012/08/09): As of PhoneGap 2.0 the plugins.xml file has been deprecated. It has been replaced with config.xml. So if you are starting a brand new project that has config.xml in the res/xml directory you will need to add your plugin declarations to this file. If you are using an older version of PhoneGap or upgrading an older project to PhoneGap 2.0 you can still use the plugins.xml file as we've got backwards compatibility (sort of). Please note though config.xml will take precedence over plugins.xml so you should not have both files in one of your projects as you'll end up tearing your hair out.
Monday, July 23, 2012
Keeping it Weird Portland
Portland, I think I'm in love with you. I've now been out to visit you twice and I have had a great time on both occasions. This time out I started off my trip by doing my presentation on Android Speech Recognition at OSCON. I had a decent number of attendees to the presentation and some good engagement from the people who have bothered to rate my talk. I find it hard to be really informative when you only have 40 minutes to talk. I focused on imparting information and telling jokes rather then running though code. If anyone is interested you can always download my slides or check out the code of my example application on my github repo.
Next up on Thursday I got a chance to relax and enjoy the conference where I saw some great presentations. In particular the one on Hacking Your Body: Running as Performance Tuning by Dave Neary was great. Not unlike myself Dave ran into problems with IT Band Syndrome so I was interested to hear what he could do to work around the problem and the answer is something I've hit upon myself, Interval Training. Also, Mary Jane Kelly did this great talk on using an EEG monitor to mind control an Arduino robot.
Thursday night I got a chance to meet up with former Ottawa dweller and now Netflix employee Dan Menard for supper and attending the GitHub Drink Up. Much thanks for the folks at GitHub for putting on the event and for putting out such a great product in GitHub. All the PhoneGap developers were in attendance as well so it was great getting a chance to hang out for everyone again.
Friday was the extremely well attended and sold out PhoneGap Day. There were a metric ton of great presentations and if you want to check out mine on my side project Corinthian you can grab my slides. I met a bunch of folks IRL that I only know from twitter and the PhoneGap Google Group. Rather than to list everyone and accidentally insult someone by missing their name let me just say it was great to meet all of you.
Till next time Portland!
Next up on Thursday I got a chance to relax and enjoy the conference where I saw some great presentations. In particular the one on Hacking Your Body: Running as Performance Tuning by Dave Neary was great. Not unlike myself Dave ran into problems with IT Band Syndrome so I was interested to hear what he could do to work around the problem and the answer is something I've hit upon myself, Interval Training. Also, Mary Jane Kelly did this great talk on using an EEG monitor to mind control an Arduino robot.
Thursday night I got a chance to meet up with former Ottawa dweller and now Netflix employee Dan Menard for supper and attending the GitHub Drink Up. Much thanks for the folks at GitHub for putting on the event and for putting out such a great product in GitHub. All the PhoneGap developers were in attendance as well so it was great getting a chance to hang out for everyone again.
Friday was the extremely well attended and sold out PhoneGap Day. There were a metric ton of great presentations and if you want to check out mine on my side project Corinthian you can grab my slides. I met a bunch of folks IRL that I only know from twitter and the PhoneGap Google Group. Rather than to list everyone and accidentally insult someone by missing their name let me just say it was great to meet all of you.
Till next time Portland!
Monday, July 16, 2012
Anchor's Away
Okay, so I'm off to OSCON early tomorrow morning where I hope to get in to Portland in enough time to participate in the Couch to Quantified 5k Run. I figure if I exhaust myself when I land I won't wake up at 5am the next day. On Wednesday I'm doing my presentation on Speech Recognition in Android Apps. Immediately after that presentation I'm heading over to the IBM booth where folks will get a chance to play with the speech recognition app from my presentation. On Friday, I'm doing a presentation on my side project, Corinthian, at PhoneGap Day US. I understand there are still a few tickets left.
Other than that in Portland I plan on drinking plenty of coffee, visiting Powell's Books, checking out the classic arcade Ground Kontrol and catching up with some friends.
So if you are slow on getting a response on the blog or twitter or email or the PhoneGap Google Group the above is why.
Other than that in Portland I plan on drinking plenty of coffee, visiting Powell's Books, checking out the classic arcade Ground Kontrol and catching up with some friends.
So if you are slow on getting a response on the blog or twitter or email or the PhoneGap Google Group the above is why.
Friday, July 13, 2012
Books I've Read this Week
The Long Earth by Terry Pratchett and Steven Baxter is just a great, layered look at parallel earths. The crux of the book centres around the fact that a device has been developed that allows people to move east or west along the long line of parallel Earth's. The Earth's closest to ours (1 east, 1 west) are near identical to ours but unpopulated by humans. As you get further down the chain the Earth's get more and more different than ours. The only limitation when travelling between Earth's is that you cannot bring any iron. Pratchett and Baxter bring do a great job of looking at the economic impact of discovering many worlds. There is one particularly funny scene where a gold prospector slides over to a parallel Earth intent on taking advantage of the Yukon gold rush. Only to discover that many people have had exactly the same idea and then the price of gold crashes as we now have a near infinite supply. Also, as the explorers head down the chain of Earth's they run into "trolls" and "elves". It is surmised that these parallel Earth creatures once visited our own Earth giving rise to legends and fairy tales. If you know much about the fae they can't stand iron so that ties into the fact you cannot take iron to the parallel Earths. Since the trolls and elves are natural world travellers the iron would be of no use to them. I really loved this book. It was so well put together with it being funny and serious at times. This is good science fiction folks as it makes you think. |
Fables Vol. 16: Super Team by Bill Willingham. Once upon a time (see what I did there) I couldn't wait for the next instalment of Fables. The series was hitting on all cylinders up until the resolution of their war with the Adversary in volume 11. Volume 12 introduced a new big baddie in Mr. Dark but it felt like a bit of a rehash of the story they'd just got done telling. Then volume 13 took me completely out of the story with the great Fables cross over. Since then the subsequent volumes have been increasing in quality which brings us up to volume 16. Super Team is more of a commentary on super hero comics than anything else. I do like how Willingham makes fun of the regular tropes of super hero comics but the resolution of the volume should have been titled "Deus ex machina" because it didn't seem to grow organically out of the story. It just seemed like Mr. Dark needed to be removed from the board and this is how we are going to do it. So volume 17 will open up a whole new direction that I will check out but can't imagine I'll go too much past that if it is just another rehash of the original story direction. |
Thursday, July 12, 2012
PhoneGap Android Plugins: Sometimes We Screw Up
So we dropped the ball in PhoneGap 1.9.0. We got rid of a number of methods from the CordovaInterface. This was part of the ongoing work to push CordovaWebView into master.
Aside: CordovaWebView allows you to use the PhoneGap/Cordova component in a larger Android application. Extending the DroidGap class is no longer necessary if you are providing your own Activity that embeds a CordovaWebView. However, you can continue to extend the DroidGap class to give yourself a leg up.
As a result of removing those methods Plugins who were dependent on them being implemented by CordovaInterface ctx member of the Plugin class were left wondering what do I need to do to get my Plugin to compile with PhoneGap 1.9.0.
Well we are sorry for that, it could have and should have been handled better. When PhoneGap 2.0.0 drops we are changing ctx from a CordovaInterface to a LegacyContext class. LegacyContext is a new class that we've introduced that bridges the old CordovaInterface API to the new CordovaInterface API. This means that any Plugin that worked in 1.8.1 should continue to work in 2.0.0 without modification.
This doesn't mean that LegacyContext will be around forever. In fact the class is already deprecated. We will be publishing an Plugin upgrade guide to help developers update their Plugins to the new API. I'll also be going through my plugins (ChildBrowser, TTS, VideoPlayer) and updating the repo to have 1.8.1 and 1.9.0 versions of the Plugins for people to reference. The ctx member from the Plugin class will be going away in a couple of point releases as it has been replaced by a cordova member which is an instance of CordovaInterface.
For those of you who want to get a jump start on updating your plugins here is a brief guide.
Aside: CordovaWebView allows you to use the PhoneGap/Cordova component in a larger Android application. Extending the DroidGap class is no longer necessary if you are providing your own Activity that embeds a CordovaWebView. However, you can continue to extend the DroidGap class to give yourself a leg up.
As a result of removing those methods Plugins who were dependent on them being implemented by CordovaInterface ctx member of the Plugin class were left wondering what do I need to do to get my Plugin to compile with PhoneGap 1.9.0.
Well we are sorry for that, it could have and should have been handled better. When PhoneGap 2.0.0 drops we are changing ctx from a CordovaInterface to a LegacyContext class. LegacyContext is a new class that we've introduced that bridges the old CordovaInterface API to the new CordovaInterface API. This means that any Plugin that worked in 1.8.1 should continue to work in 2.0.0 without modification.
This doesn't mean that LegacyContext will be around forever. In fact the class is already deprecated. We will be publishing an Plugin upgrade guide to help developers update their Plugins to the new API. I'll also be going through my plugins (ChildBrowser, TTS, VideoPlayer) and updating the repo to have 1.8.1 and 1.9.0 versions of the Plugins for people to reference. The ctx member from the Plugin class will be going away in a couple of point releases as it has been replaced by a cordova member which is an instance of CordovaInterface.
For those of you who want to get a jump start on updating your plugins here is a brief guide.
- ctx.getContext() replaced with cordova.getContext()
- ctx.startActivity() replaced with cordova.getActivity().startActivity()
- ctx.getSystemService() replaced with cordova.getActivity().getSystemService()
- ctx.getAssets() replaced with cordova.getActivity().getAssets()
- ctx.runOnUiThread() replaced with cordova.getActivity().runOnUiThread()
- ctx.getApplicationContext() replaced with cordova.getActivity().getApplicationContext()
- ctx.getPackageManager() replaced with cordova.getActivity().getPackageManager()
- ctx.getSharedPreferences() replaced with cordova.getActivity().getSharedPreferences()
- ctx.unregisterActivity() replaced with cordova.getActivity().unregisterActivity()
- ctx.getResources() replaced with cordova.getActivity().getResources()
- import com.phonegap.api.* replaced with import org.apache.cordova.api.*
Friday, July 6, 2012
Books I've Read this Week
I've enjoyed the previous books I've read by Dan Ariely and The Honest Truth About Dishonesty continues that trend. I especially like the chapters that focus on how people deceive themselves. One interesting tid bit of information is that people who are more creative are better liars. Well that's not that surprising but they are even better than most folks about lying to themselves but lets call that rationalization instead of lying. Anyway, like all of Ariely's books it is a quick but interesting read. |
Red Seas Under Red Skies is the second book in the Gentlemen Bastards Sequence by Scott Lynch. Without giving too much away from the first book our protagonists find themselves in a new city planning their next heist. All in all this is a caper book and the interaction between the two main characters Loche and Jean is absolutely priceless. Since the main characters are lying thieving bastards it makes a perfect complement to the other book I read this week. |
Monday, July 2, 2012
Change to Camera code in PhoneGap 1.9.0
With the release of PhoneGap 1.9.0 I've checked in some improvements to the Camera.getPicture() functionality. First a bit of an explanation as to why there are so many issues with the Camera code.
One of the major causes of issues is that as new devices get released the cameras in them get better and better allowing you to take very high resolution images. Now when you specify a few parameters to our getPicture method like quality or targetWidth/targetHeight you can get out of memory errors. Why do you get out of memory errors you ask? Well in my honest opinion it is because Android does a real poor job of handling Bitmaps. In order to do any manipulation on an image like scaling or compression you need to load the entire image into memory.
Let's take a look at a real world example. My Samsung Galaxy Note has an 8MP camera with a resolution of 3264 by 2448. So in memory that picture assuming ARGB_8888 will be:
Let that sink in, approximately 30 megabytes. Considering that I read somewhere the default heap size for an app running in Dalvik is 48 megabytes you can see how you can quickly run out of memory taking pictures.
Fixing the Best Case Scenario
I've added some code to detect the best case scenario and not load the image into memory. Here is the getPicture method to call if you want to use the best case all the time.
Reducing Memory when using targetWidth/targetHeight
Okay but if you do specify a targetWidth/targetHeight the image has to be loaded into memory. Now we do a bit of math to figure out the smallest multiple of the image that can be loaded that isn't smaller than the requested width and height. You see the Bitmap.createScaledBitmap() method allows you to specify that the bitmap be load at half, quarter, etc. size. Now if you request a 900x900 image from a 2000x2000 original image it will be loaded into memory as 1000x1000 and scaled from that point. It saves about 11 megabytes of memory doing it this way.
Respects the saveToPhotoAlbum option
Up until 1.9.0 each picture taken automatically gets added to the Android photo album/gallery. As of 1.9.0 if you want that type of behaviour to continue you need to set this option to true as the default is false.
Respects the correctOrientation option
One of the other big problems with our Camera functionality is that pictures taken in portrait mode were always displayed on their side when you attempted to view them in your app. Remember your app is based off of a WebView and the web view does not care about the exif orientation parameter. Now if correctOrientation is set to true we rotate the image so that it will show up properly in the WebView and we reset the orientation parameter to normal so it'll show up properly in desktop image viewers.
If you run into problems using the Camera in 1.9.0 please raise a bug on JIRA and give a detailed reproduction scenario. I want to make sure this functionality is rock solid for the upcoming 2.0.0 release.
One of the major causes of issues is that as new devices get released the cameras in them get better and better allowing you to take very high resolution images. Now when you specify a few parameters to our getPicture method like quality or targetWidth/targetHeight you can get out of memory errors. Why do you get out of memory errors you ask? Well in my honest opinion it is because Android does a real poor job of handling Bitmaps. In order to do any manipulation on an image like scaling or compression you need to load the entire image into memory.
Let's take a look at a real world example. My Samsung Galaxy Note has an 8MP camera with a resolution of 3264 by 2448. So in memory that picture assuming ARGB_8888 will be:
3264 pixels x 2448 pixels x 4 bytes/pixel = approximately 30 megabytes
Let that sink in, approximately 30 megabytes. Considering that I read somewhere the default heap size for an app running in Dalvik is 48 megabytes you can see how you can quickly run out of memory taking pictures.
Fixing the Best Case Scenario
I've added some code to detect the best case scenario and not load the image into memory. Here is the getPicture method to call if you want to use the best case all the time.
var options = { quality: 100, destinationType : navigator.camera.DestinationType.FILE_URI, sourceType: navigator.camera.PictureSourceType.CAMERA, encodingType: navigator.camera.EncodingType.JPEG, } navigator.camera.getPicture(win, fail, options);The important part about the options is that you specify a quality of 100. This along with accepting the default width and height will skip the need to load the image in memory.
Reducing Memory when using targetWidth/targetHeight
Okay but if you do specify a targetWidth/targetHeight the image has to be loaded into memory. Now we do a bit of math to figure out the smallest multiple of the image that can be loaded that isn't smaller than the requested width and height. You see the Bitmap.createScaledBitmap() method allows you to specify that the bitmap be load at half, quarter, etc. size. Now if you request a 900x900 image from a 2000x2000 original image it will be loaded into memory as 1000x1000 and scaled from that point. It saves about 11 megabytes of memory doing it this way.
Respects the saveToPhotoAlbum option
Up until 1.9.0 each picture taken automatically gets added to the Android photo album/gallery. As of 1.9.0 if you want that type of behaviour to continue you need to set this option to true as the default is false.
Respects the correctOrientation option
One of the other big problems with our Camera functionality is that pictures taken in portrait mode were always displayed on their side when you attempted to view them in your app. Remember your app is based off of a WebView and the web view does not care about the exif orientation parameter. Now if correctOrientation is set to true we rotate the image so that it will show up properly in the WebView and we reset the orientation parameter to normal so it'll show up properly in desktop image viewers.
If you run into problems using the Camera in 1.9.0 please raise a bug on JIRA and give a detailed reproduction scenario. I want to make sure this functionality is rock solid for the upcoming 2.0.0 release.