Tuesday, February 7, 2012

The Playbook Games

It's been over 75 hours since I registered to be a Blackberry App Vendor and I still don't have an account. Hrmm.

I'm still trying to get the app working like it should (and does on Android). But there are some new problems:

Want to work on some code and test it when you don't have an internet connection? Forget about it. The blackberry signing process fails if you are not connected to the internet. And you will likely have to restart your IDE. Guess I won't work on the plane tonight.

What about google ads? For some reason (and maybe it's just me) they won't show up, but a blank spot is reserved on the screen for the view. Works fine, though, in the google tablet simulator (Android 3.1) and on handsets. Actually works much better- no flickering, weird display problems, etc.

I tried to run a video player app (it's been downloaded thousands of times and runs well on many platforms. I know since I wrote it). It complains that there is no Internet connection, while it successfully loads youtube's website. But videos won't play, so I can't port that app or add video to the one I was trying to port.

How about adb connectivity? I have not seen it at all. This means no logs. Here is some adb output:

C:\Users\erich>adb logcat
adb server is out of date. killing...
* daemon started successfully *
- waiting for device -
error: protocol fault (no status)
* daemon not running. starting it now on port 5037 *
* daemon started successfully *
- waiting for device -
error: protocol fault (no status)

C:\Users\erich>adb connect 192.168.170.130:5555
adb server is out of date. killing...
* daemon started successfully *
** daemon still not runningerror: cannot connect to daemon

C:\Users\erich>adb devices
adb server is out of date. killing...
* daemon started successfully *
List of devices attached


C:\Users\erich>

and so on. I tried lots of things and many searches and found nothing. I even searched the Blackberry Android Micro-site as they call it for 'adb' and got this:

Your search - adb - did not match any documents.
So how do you develop and troubleshoot an app? The process is this:
  1. write your app for Android (the first-class citizen)
  2. if the app is successful, port to Blackberry and hope it works (an after-thought)
  3. if it doesn't work, don't waste your time trying to get it running right. The tools are insufficient.

It reminds me of trying to run Java on a Windows PocketPC over 10 years ago.



Saturday, February 4, 2012

RIM Offers Free PlayBook to Piss-Off Android Developers

See the tweet that started it all: https://twitter.com/#!/asaunders/statuses/165097598624075777

Sounds great, huh? Here's my ordeal so far.

Tried to sign up using iPhone- fail
Tried again from desktop- where's my email confirmation registration? who knows...
3 separate legal agreements to go through if trying to sell apps- really cumbersome process.

Tried to get blackberry tablet simulator- web link text was correct on the page but wrong in the html code. I figured it out. Just an extra challenge.

Crazy how much stuff to install- vmplayer, vm for tablet simulator, extra plugins for eclipse, certs to download, etc

Then you have to configure the plugin for eclipse- requires new process and legal agreements to get RIM software signing certificates (which come within 2 hours! oh boy!) Just another roadblock. Note to RIM: on android, I can make my own certs.

So I get my certs, try them out, and get another error. Not yet registered to create debug tokens. How many registrations do I need, seriously? Another note to RIM: easier to sign up for Android.

Got another email about cert registration. It says it succeeded and "the client has 2147483647 code signing request(s) left." Wow! This number looked familiar. Wikipedia says:
The number 2,147,483,647 (two billion one hundred forty-seven million four hundred eighty-three thousand six hundred forty-seven) is the eighth Mersenne prime, equal to 231 − 1
I'm guessing this is an error.

You can't install any apps without the cert. Need debug tokens, too, which also require the cert and to be registered. 3rd note to RIM: ever hear of self-signed certificates?

Almost an hour into the process. Still no verification from RIM I've even signed up as a developer!

3 hours after registering I finally get an email from requesting proof of identity. And it says it'll be another 24-48 hours (I'm guessing Sunday won't count) until the process is over. Well, no development for me anytime soon. I doubt I'll even get anything done now before the app submission window closes, since this is the last (and only weekend) during the Playbook giveaway promotion.

Does anyone wonder why no one wants to write apps for Blackberry devices? Such a horrible process just to get started. Something is clearly wrong with Canadian laws and/or RIM. No surprise there.

After over 3 hours of trying I have:
  • extra software installed, but none will work since my registration is not complete
  • a tablet simulator, but no way to install software on it
  • 24-48 hours more to wait

RIM does not allow you to use the tools to simply load unsigned applications on the simulator. This is absurd. I can't even try to convert my apps to their format. But I did change my icon from 96x96 to 86x86.


Friday, July 15, 2011

Profiles for Netflix streaming content control? NOT

I can't believe how bad Netflix is at managing who can watch what using instant streaming. You would think they would address some fundamental problems before dumping DVD mailings and trying to go pure streaming. I have 3 little kids and to protect them from the garbage (including hard-core porn) on Netflix I would love to be able to give them their own profile with content restrictions. Netflix allows profiles, but not for streaming. That is idiotic.

Between computers, a 3DS, the Wii, my android phone, and a roku how do you keep your kids from viewing the wrong thing, especially on a portable gadget like a 3DS or a phone? You can't be everywhere, so deactivation of the device is the only choice Netflix offers today, and they even made that hard.

What is needed
Profiles must support instant streaming with parental controls
Profiles must be able to be linked to a device
Profiles must list the devices that are linked
You must be able to individually manage device deactivation (it is all or nothing)
Profiles must be able to be deleted (duh!)


Other gripes
Why do movies already in my queue show up in my search results?
Why can't you save a movie category (ie, Cerebral Comedies)? Every now and then they get it right, but you never see the category again!
Why are genres so few, yet they have all the other categories you can't use in a search?
Why are searches limited to 10 results on a Roku?
Why can't viewing history be deleted?
And finally, why does Toy Story 3 show up in 90% of the searches I do? (Disney payola!)

Netflix is headed for trouble if they don't get in front of these problems.

Wednesday, May 18, 2011

Sony's Security Problems

We now know, thanks to Howard Stringer, no network is secure. Thanks for the tip. Here's what I can't understand about Sony and its subscription services. Once I pay for the service, I can't delete my credit card from their system (except maybe by cancelling service altogether). It stays locked in your Station Account, ready to be hacked.

Given the inability of Sony to secure my personal data, I would prefer the option of paying with my credit card as I need to, but never storing it with them. Why doesn't Sony allow this? It makes it easier for them to collect payments. But if you don't have the data, you can't lose it.

Please, Sony, let me remove my credit card info from your 'safe' hands.

Saturday, March 12, 2011

Nintendo's next gen Wii-sh list

The Wii is a lot of fun, but it needs to be much more to sell a next gen product. Total home entertainment is the goal. Here's how.

Faster processor. Duh.
Wireless N. Streaming HDTV, anyone?
1080p graphics for gaming and Internet browser
Better internet video support- no Hulu, no Espn. What's up with that?
Need a wireless keyboard/mouse accessory (preferably from nintendo)
Platform should essentially be a google tv
Disc player should play movies (DVD, blu-ray)
More channels- where's music? Pictures? Facebook? You get the idea.
News channel is weak- suffers from very poor editorializing. Top 'tech' story (out of 2) was the Pope now has a Facebook account. That is not tech, that is pop fluff.
News channel uses NASA for map images, while Google Earth is the standard. NASA graphics suck.
The news channel cat must die, too. What kind of hold over from alpha code is that, anyway?
You must be able to print an email photos/pictures from the Wii. I have a Udraw. Makes great pictures no one will ever see unless I save to sd card and move it to a computer.
Other channels, like weather, need an overhaul, too. Better weather reports, too. I don't even trust it.
Fan inlet clogs up too much causing overheating and freeze of the Wii. Should be located higher on the case.
Decent games for the motion plus would be nice.

Wow. I think this just means I need a ps3 with better games for kids.

So what will nintendo really do? Let's get crazy.

Play your mii in everything- that would be funny
Inject your face into the mii creator or ANY game
Support face and voice recognition
Really good body movement sensing- must support a karate style game.
Open system for developers to work on. No more home brew required.
mmorpg support
Introduce creativity enhancing software with special controllers
Augmented reality games
Built-in video conferencing
in game audio chat for mmorpg
real world mii toy that looks like you and integrates with the Wii (adventures with Mii games)
music creation vice dumbed down music copying/fake play back (through Wii adapter to synth module)
Wii publishing to social networks

Friday, March 4, 2011

Maven Archetype Usage with SVN

I've been creating Maven2 archetypes for use with projects involving Spring3 and JBoss AS 5.1. They are not trivial to configure, so creating a reusable archetype improves developer efficiency. The archetypes are hosted on google code. Go here to get the URL needed for accessing them: https://code.google.com/p/clear-maven-archetypes/source/checkout (no, I haven't added to a regular maven repository nor do I intend to).

An archetype is just another maven project so installing a new one and using it is simple. The name of the archetype for this example is "shellJBoss-archetype".

[This is all geared to Eclipse, so you need m2eclipse installed and subclipse for working with SVN]

You need to checkout "shellJBoss-archetype" from the trunk. You will need to add a new location to your repositories; namely,
https://clear-maven-archetypes.googlecode.com/svn/trunk.

Once you have done this, explore the new trunk and you will see the projects below. You need to right-click "shellJBoss-archetype" and choose "checkout..."




This creates a new Eclipse project for you called"shellJBoss-archetype". Switch to a Java development perspective in Eclipse. Now you need to add the new archetype to your local repository. Right-click the new project and choose "Run As". Choose "Maven Install" and that will do it for you.




You will notice in the console output this key line just before Build Success:

[INFO] --- maven-archetype-plugin:2.0:update-local-catalog (default-update-local-catalog) @ shellJBoss-archetype ---

The "shellJBoss-archetype" is now usable by the Maven new project wizard. Choose File:New:Other:Maven Project. As you work through the wizard you will get to the archetype selection screen. Choose the "Default Local" catalog and you will see the new archetype.



Critical Step
Maven does some stupid text find/replace operations that can really mess a project up. You need to set version equal to 1.0 as shown below when using the wizard. If you don't, your XML files will all be invalid.


After you have made the project, you can go into the POM.xml file and change the version to whatever you like. Also note that the archetype will name your new project and the resulting deployment *.war file using the artifactId you specify in the wizard. You can also change this in POM.xml if you like.

After you create your project, take a look and see what is in it. There are sample files showing a simple webflow with spring security and some tests written using TestNG. In fact, the project is ready to deploy to JBoss AS 5.1 (using the maven command "jboss:hard-deploy").


Selecting "Maven Build..." lets you type in whatever maven goal (command) you want. Assuming a default JBoss install, go to this url (but using your artifactId) to see the project in action:

http://localhost:8080/your-artifactId


Tuesday, February 15, 2011

NokiSoft (pronounced NookieSoft, I believe)

Microsoft has finally figured out what to do with all of its money- give billions to a competitor to quit using their mobile OS, and use Windows 7 Mobile instead. Hey, if you can't get market share by making a superior product I guess buying it is the next best thing.

I think there is a problem, though. I (perhaps naively) believe the best product(s) should get the market share. I believe this is a basic tenet of capitalism and I also think it will win out in this situation in a surprising fashion. By eliminating Nokia's Mobile OS (Symbian), a vacuum is being created that Microsoft presumes to fill with Nokia devices running Windows 7 Mobile. They believe these devices will be an equal competitor to Google Android and Apple iOS.

I don't think so. Microsoft has more or less failed for a decade and squandered any opportunity they had at taking the lead at making good mobile devices people will buy. (They do have the cutest little fuzzy creatures in their phone commercials, but three year olds don't buy phones). The only thing their money is going to do is make it easier for Google and Apple to increase market share- exactly the opposite of what they are hoping for. Nokia will lose market share, but at least they are getting paid for it. Microsoft will get nothing.

As for what they should really do, it has been obvious for years that the winning divisions at Microsoft carry the loosing ones. It is time to split into 4 or 5 separate companies. Some will fail, as they should, and some will succeed. More capitalism.

Tuesday, December 14, 2010

I've been Gawked!

Lessons on security in light of Gawker Media breach, resulting in hundreds of thousands of compromised email accounts.

Never deal with Gawker again. I found I could not even delete my account on Gizmodo. That's pathetic- they let it get hacked and you can't even sever ties. Oh, and I couldn't log in to Gizmodo- I think my account was inactive, implying these clowns were keeping my data for no reason (and insecurely) or someone changed my password. Frankly, I hope someone is using my account to harass Gawker. Just remember, it's not me! Hahaha.

For lame things like commenting on websites (such as Gawker runs), create an email account you use for absolutely nothing but commenting on websites.

Don't use only one password for everything, or even variations on a theme. It's hard, but think about it. "One ring to rule them all..."

Delete things (everything, really) from your email frequently that may provide pointers to parties you do business with. These email leave a trail of what other websites you have accounts with. And if these accounts use your compromised email address and password, you are in trouble.

Don't save your credit card info on any website. Really, who can you trust? Just type it in each time. Even then it is still not completely safe, but less likely to be sent out through bittorrent.

Use passwords of at least 16 characters. Yes, you can remember it!




Friday, December 3, 2010

Netflix Movies for only $30, brought to you by Verizon

Yes, you read it right! You really can watch a Netflix movie in HD for only $30. That is, of course, if you have Verizon 4G service and a 5GB data plan. You see, after using up your 5GB watching 2 movies in HD on Netflix, you start paying $10 per GB. A 2 hour movie uses about 3.3GB, so that is a whopping $30 in overage fees.

Of course, Verizon will send you an email or text message to warn you when you hit your data cap a few days into the month. Please be sure to check frequently while watching a movie. Nice!

Thursday, October 21, 2010

Keeping up with 4G networks and LBS

Do you have LBS applications and is there a chance they will ever run on a 4G network? If the answer is yes to both (and I hope it is), then you need to start adding location capabilities to your apps so they continue to work properly when connected via 4G. Some of this is already taken care of. For example, if using a Sprint 3G/4G device and their location services, you will receive location data from Clearwire (the 4G provider) when on 4G.

Not all situations work this easily, however. Consider this case. You have customers using a location-aware app on a laptop embedded with Wimax. You app needs to know location to about a half mile accuracy. If you do not change your app to use a 4G location service, your customers can only get IP-based location- which is often only good enough to tell you what city you are in and likely NOT meeting the requirements of your application. As more and more people use 4G, this will become a real problem for you, especially as people start calling your care line. The solution? Integrate 4G location services now. It is not hard and will be worth the investment. See http://developer.clear.com/projects/activity/location-based-serv/ for how to do this.

In the future, 4G location will be available the way wi-fi and 3G location are today, but that will take awhile as 4G networks are and will continue to be built out over the next several years. In the meantime, don't be left behind.


Thursday, September 9, 2010

Apple? Android? NINTENDO!

I am glad to see Apple reacting to the Android threat by opening its door a little more to developers. This is great news for all developers since it helps spur innovation. Here's the basic story, but you can find much more on the web about it.

Now is this enough? No. It still costs more to develop for Apple devices than for Android. You need a Mac (although maybe that just changed with Flash becoming an option, but Adobe tools are the costliest of all) and you still pay yearly developer fees of $99. Not much, but compared to zero it is significant for lone developers.

But let's talk about what would really shake things up. There are over 115 million Nintendo DS (and variant) devices floating around the world. That's a big party to crash. Wouldn't it be interesting to have an open developer community around that? Could the little guys compete? Well, no one thought they could on smartphones and now look at it. Nintendo could use something big and this could be it.

Sunday, July 25, 2010

Youtube and Android

Youtube is great and has a wealth of API's. On mobile, though, I just want simple playback. Up until around July 22, 2010, you could pass a url like this:

http://www.youtube.com/get_video?video_id=6Yd5DQykZow&t=some_token&fmt=17

into an Android VideoView and it would play the video. This used progressive download meaning the video would play once it had buffered enough, then keep downloading as play progressed. It also provided very good quality, since fmt (format) controlled whether it was a low-bandwidth or high-bandwidth data connection. In case you are wondering, if on WiFi or Wimax, use high bandwidth. Then something changed and this type of url does not work anymore. I would love to know what happened. I suspect it was just too easy to download content from Youtube this way and save it to a file and go build your own site.

You still play videos a variety of ways on Android. Here are some options found by using the gdata API's for Youtube (see http://code.google.com/apis/youtube/2.0/developers_guide_protocol.html)

Using this url
you get an XML feed about a given video. Here's the part relevant to playback:

<media:content url='http://www.youtube.com/v/6Yd5DQykZow?f=videos&app=youtube_gdata' type='application/x-shockwave-flash' medium='video' isDefault='true' expression='full' duration='322' yt:format='5'/>

<media:content url='rtsp://v1.cache8.c.youtube.com/CiILENy73wIaGQmMZqQMDXmH6RMYDSANFEgGUgZ2aWRlb3MM/0/0/0/video.3gp' type='video/3gpp' medium='video' expression='full' duration='322' yt:format='1'/>

<media:content url='rtsp://v3.cache4.c.youtube.com/CiILENy73wIaGQmMZqQMDXmH6RMYESARFEgGUgZ2aWRlb3MM/0/0/0/video.3gp' type='video/3gpp' medium='video' expression='full' duration='322' yt:format='6'/>

Format 1 = h.263, 5= flash video, and 6 = mp4. Formats 1 and 6 are low quality and meant for old cell phones on slow networks (176 x 144 resolution), but they work fine when passed to VideoView.setVideoURI(uri)

What's more interesting is the flash url (don't ask where html5 video comes in- I don't know). You can play this in a browser or in the Youtube application on HTC Hero and EVO and many more phones. Clicking the link will bring up the chooser for you to pick how to handle the video link. You don't need a VideoView; in fact, it won't work if you try one- go figure. Google is definitely having some struggle with all of this. Froyo (Android 2.2) will support flash, also, so lots of phones will work with the flash option.

There is still a question of quality of the playback- I want more control (i.e., flash video parameters for what I want) or the ability to give hints via SDP to the RTSP server, but no dice.

There is more mystery
This link
retrieves a different info feed entirely. It is all url-encoded name/value pairs, easy enough to decode and see that there are urls in it. In fact, you can download videos using them. The content type is flash, so if you download the video and save it as an *.flv file you could play the video with VLC (http://www.videolan.org)


Friday, July 16, 2010

Secure file distribution with apache, openssl, and curl

This is a long post. Be warned.
I have a problem to solve. I need to share a file on a regular basis with a small group of users. It has to be done securely and upload and download must be automated. It also has to be cheap and simple.

The plan is to layer HTTP Basic and SSL Client Auth for directory access to the BSA files. This provides encryption, strong authentication, and with HTTP Basic, the ability to disable an account easily (even though their client certificate may still be good. I didn't want to deal with certificate revocation lists). For retrieval, curl is a great option and meets all requirements.

Tools and assumptions
I used Ubuntu (8.04 or later), apache2 (2.2), and the latest curl and openssl packages. You know some *nix.

Apache2 configuration

The BSA file will be placed in a directory called 'bsa', so create this in /var/www (the default)

Add the following to the /etc/apache2/httpd.conf file to protect your new directory.

<Directory /var/www/bsa>

AuthType Basic

AuthName "Approved BSA users"

AuthUserFile /usr/local/apache/passwd/passwords

AuthGroupFile /usr/local/apache/passwd/groups

Require group BsaUsers

</Directory>

Note that this will be changed later for the final solution. I am just showing how to do this in general.

You will need to create the directories apache and passwd so that the path /usr/local/apache/passwd exists. Here is how to create the files 'passwords' and 'groups'.

group file creation

You simply make a text file (called 'groups') with an entry like this:

BsaUsers: user1 user2 user3

Everything after "BsaUsers:" are the user names for who has access. Each will need a password.

passwords file creation

For this you must use an apache tool for creating password files, htpasswd. The command below creates the passwords file (-c option) and adds one user, user1. You will be prompted to add their password.

>htpasswd -c /usr/local/apache/passwd/passwords user1

Adding more users to the password file

>htpasswd /usr/local/apache/passwd/passwords user2

>htpasswd /usr/local/apache/passwd/passwords user3

(each time you are prompted for the password for the user)

Note: htpasswd is in /usr/local/apache2/bin in case that location is not on your path.

Adding a new user

  1. add the user name to the 'group's file.
  2. add a password for the new user as above

Now test that http basic auth is working for the direcory 'bsa' in the root of the web server. After writing to the httpd.conf file you may need to restart the server.

TIP: apache2 service name is not httpd, it is apache2. So restart is this:

>service apache2 restart

Now on to how to access an http basic protected directory using curl. First, when you try curl against the protected directory it will appear to work. If you look at what you downloaded, though, it will be a 401 Authentication Required file.

Here is how to use curl on a resource (URL) requiring http basic authentication:

>curl -u name:password www.example.com

So for my example, the command is this:

>curl -u user1:password1 -O localhost/bsa/testfile.zip

This will send the credentials to the server and download and save the requested file. It's that simple.

Now for the main event: SSL CLient authentication set up

(see http://httpd.apache.org/docs/2.2/ssl/ssl_howto.html and http://httpd.apache.org/docs/2.2/ssl/ssl_faq.html for complete details)

Enabling SSL

>a2enmod ssl

>service apache2 restart

You can verify that /etc/apache2/mods-enabled now has the ssl.conf and ssl.load symbolic links in it.

Creating Certs and Keys

I tried CA.pl, a script for working with openssl for creating server certificates and it caused no end of problems arround the private key not being found. I believe it is all due to a format issue but not worth hassling with. By using openssl directly, as follows, I got it working easily.

Create a RSA private key for your server (will be Triple-DES encrypted and PEM formatted):

>openssl genrsa -des3 -out server.key 1024

Please backup this host.key file and the pass-phrase you entered in a secure location. You can create a stronger key by changing 1024 to something like 4096.

You can see the details of this RSA private key by using the command:

>openssl rsa -noout -text -in server.key

Create a self-signed Certificate (X509 structure) with the RSA key you just created (output will be PEM formatted):

>openssl req -new -x509 -nodes -sha1 -days 365 -key server.key -out server.crt

This signs the server CSR and results in a server.crt file. Set 'days' to whatever you like.

Copy the server.crt file and the server.key file to a directory under /etc/apache2. You can make your own- just don't use conf.d since that will cause other errors.

You must set up apache2 so your server uses SSL and your new certs. I did this using a virtual host for SSL. You will find these under /etc/apache2/sites-enabled/000-default (I tried using the main config file, but ran into problems. Using a virtual host works.)

Add the following to 000-default:

<VirtualHost *:443>

DocumentRoot /var/www

SSLEngine on

SSLCertificateFile /etc/apache2/conf/ssl/ca.crt

SSLCertificateKeyFile /etc/apache2/conf/ssl/server.key

<Directory /var/www/bsa>

#ssl client auth set up

SSLVerifyClient require

SSLVerifyDepth 1

SSLCACertificateFile conf/ssl/ca.crt

# http basic auth set up

AuthType Basic

AuthName "Approved BSA users"

AuthUserFile /usr/local/apache/passwd/passwords

AuthGroupFile /usr/local/apache/passwd/groups Require group BsaUsers

</Directory>

</VirtualHost>

Second, I ensure you can only access the private area using https with this:

<Directory /var/www/bsa>

Deny from all

</Directory>

This goes in the virtual host for port 80 (in 000-default) and blocks all access except through port 443. At this point, you have a web server that supports both http and https traffic with a protected directory (bsa) that can only be accessed as follows:

  • https
  • with username and password
  • and a client certificate

Now when I try to run the server, here's what I get. Note that the cert private key is found, as evidenced by being challenged for its passphrase.

>/etc/apache2# service apache2 restart

* Restarting web server apache2 Apache/2.2.12 mod_ssl/2.2.12 (Pass Phrase Dialog)

Some of your private key files are encrypted for security reasons.

In order to read them you have to provide the pass phrases.

Server localhost:443 (RSA)

Enter pass phrase:

OK: Pass Phrase Dialog successful.

When accessing using a browser I am getting the message I want- the server certificate is untrusted. This confirms apache is using my self-signed cert.

I accept the 'untrusted' cert, and get the following error in Firefox:

An error occurred during a connection to localhost.

SSL peer was unable to negotiate an acceptable set of security parameters.

(Error code: ssl_error_handshake_failure_alert)

This is also expected, since I am requiring client authentication, but my client has no certificate. Just to confirm, I removed the requirement for client auth from httpd.conf, and restarted the server. Now when I use https, I can get to the web page after accepting the cert. This is all good.

Next step- use a client cert for authentication

First, create a sample client certificate using own CA created earlier (and stored in 'selfCA').

Create a private key

>openssl genrsa -des3 -out server.key 1024

Create a CSR using your new key

>openssl req -new -key server.key -out server.csr

Sign CSR using your own CA

>openssl x509 -req -days 1100 -in server.csr -CA ../selfCA/server.crt -CAkey ../selfCA/server.key -set_serial 01 -out test.crt

You will be asked for the passphrase for server.key.

Now to use test.crt and the key. To work with curl, the cert and key need to be in the same file.

>cat test.crt server.key > client.crt

This just combines the files into one text file. Take a look.

Here's the finished curl command to download the file using client authentication and basic authentication.

>curl -u user1:password1 -k https://localhost/bsa/testfile.zip -E client.crt:passphrase1 -O https://localhost/bsa/testfile.zip

The explanation of everything

  • -u username and password set up on the server for http basic authentication
  • -k ignore certificate warnings from my server (since using self-signed CA with mismatched CN and hostname)
  • -E specifies file with the client cert and key to use plus the key passphrase
  • -O download and save the file from give URL and using the filename in the URL

Pretty cool, huh?

Thursday, July 1, 2010

Location-aware Twitter search app for Android


I just wrote and published a new free app for android. It is called Locobird and a chunk of the code is below. It uses your location to search twitter around you. What's new about this app is that it uses the Clearwire Location Platform to get your rough location when you are connected to the 4G network. Now you are wondering, how do I connect to that? Simple, you get an EVO.









This app uses the new static map API from Google and a java Twitter API from http://www.winterwell.com/software/jtwitter.php

Here's the code for using the Clearwire Location Platform (CLP)

package com.thehopemachine.locobird;

import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.util.Date;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONObject;
import org.json.JSONStringer;

import android.location.Location;
import android.util.Log;

public class WimaxLocationProvider {

private static String CLP_ADDRESS = "http://testlocation.clearwire-wmx.net:8000/json/";
private static Long STALE = 60000l; //one minutes worth of milliseconds
private static String HOST = "host";
private static String VERSION = "version";
private static String VERSION_VAL = "1.1.0";
private static String LATITUDE = "latitude";
private static String LONGITUDE = "longitude";
private static String ACCURACY = "accuracy";
private static String LOCATION = "location";
private static String ERROR = "error";
private static String QUERYARG = "/?app_id=";
private Location mLastFix = null;
public static String WIMAX = "the Clear 4G Network";
private String mHost = null;
private String mAppID = null;
private Date mLastCall = null;
public WimaxLocationProvider (String host, String appID)
{
mHost = host;
mAppID = appID;
}
public Location getLocation() throws Exception
{
//www.example.com/?app_id=freiu4898fhjrh4yshefheoiuhr
//do we have a last fix? is it still good?
String hostValue = mHost + QUERYARG + mAppID;
if (mLastFix != null && !isStale())
{
Log.d("locobird", "returning last fix");
return mLastFix;
}
//now test if called too quick
if (mLastCall != null && (new Date().getTime() - mLastCall.getTime() <= Locobird.SPURIOUS_FILTER))
{
//this implies we've been getting errors since we have no last fix but do have a last call
throw new CLPException("unable to provide location from CLP");
}
//else get a fix
Location l = null;
DefaultHttpClient httpclient = new DefaultHttpClient();
HttpPost post = new HttpPost(CLP_ADDRESS);
HttpResponse response = null;
HttpEntity entity = null;
InputStream input = null;
//create a json request (basic)
String request = null;
try
{
request = new JSONStringer().object().key(HOST).value(hostValue).key(VERSION).value(VERSION_VAL).endObject().toString();
post.setEntity(new StringEntity(request));
JSONObject locationData = null;
StringBuffer data = new StringBuffer(512);
//send the request (POST it)
response = httpclient.execute(post);
entity = response.getEntity();
//get IO stream from entity and turn into JSON object
input = entity.getContent();
//look at response code
if (response.getStatusLine().getStatusCode() >= HttpURLConnection.HTTP_BAD_REQUEST)
{
//400 bad request, 404 not found, 500 server error ,etc
//do not try to parse json- will cause error
l = null;
}
else if (response.getStatusLine().getStatusCode() == HttpURLConnection.HTTP_OK)
{
byte[] buffer = new byte[512];
int x = 0;
while ((x = input.read()) != -1)
{
data.append((char)x);
}
//create location from the response
Log.d("locobird", "CLP response= " + data.toString());
locationData = new JSONObject(data.toString());
//test for location object in the json (if you just query you will get an exception)
if (!locationData.has(LOCATION))
{
//get the error object and examine it for cause
//{"error":"server error"}
if (locationData.has(ERROR))
{
String errorCause = locationData.getString(ERROR);
//could return error message in a bundle or just throw an error
throw new CLPException(errorCause);
}
else
{
//neither location nor error so a clp problem
throw new CLPException("Missing location and error objects from CLP response");
}
}
else
{
JSONObject jsonLocation = locationData.getJSONObject(LOCATION);
//we have a good location object from the CLP
//load the location object with the locationData
l = new Location(WIMAX);
l.setLatitude(jsonLocation.getDouble(LATITUDE));
l.setLongitude(jsonLocation.getDouble(LONGITUDE));
l.setAccuracy((float) jsonLocation.getDouble(ACCURACY));
}
}
}
finally
{
//ensure call time is recorded
mLastCall = new Date();
try
{
if (entity != null)
{
entity.consumeContent();
input.close(); //may not be needed
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//can return null in case of error. if this happens, do not update the fix- keep old one.
if (l == null)
{
throw new CLPException("unable to provide location from CLP");
}
else
{
mLastFix = l;
mLastFix.setTime(new Date().getTime());
Log.d("locobird", "returning new fix");
return l;
}
}
//if time since last fix exceed STALE, the fix is stale so get a new one.
private boolean isStale()
{
return ((new Date().getTime() - mLastFix.getTime()) > STALE);
}
}


For checking if you are on 4G, here's the code.

public static boolean onWimax(ConnectivityManager cm)
{
NetworkInfo info = cm.getActiveNetworkInfo();
if (info == null)
{
//no active network=
return false;
}
int networkType = cm.getActiveNetworkInfo().getType();
//type = 6 means wimax

if((networkType == 6) && (cm.getActiveNetworkInfo().getDetailedState().compareTo(DetailedState.CONNECTED)) == 0)
{
return true;
}
else
{
return false;
}
}
You will need these imports:

import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.NetworkInfo.DetailedState;


Saturday, June 26, 2010

Dalvik ate my projects

I got too clever and wrote a script to build my Android apps. I added the android\tools directory to my system path to help with this.

The script worked fine but problems started when I opened Eclipse. I was patching a file and the build failed with these details:

Problems occurred building the selected resources.
Errors running builder 'Java Builder' on project 'xyz'.
java.lang.NullPointerException
These errors were in the Problems tab:
  • Conversion to Dalvik format failed with error 1
  • R cannot be resolved to a variable

All I had done was add the android tools directory to the system path Troubleshooting 101- even if you don't understand how your change might have caused a problem, undo the change anyway. I undid my path change.

When I tried to build my projects (yes all had the same errors), I still had the Dalvik error listed.
I deleted the error (yes you can! Errors can get stuck and sometimes have to be deleted) from the Problems tab and rebuilt. Then I got:
Could not find xyz.apk!
I manually exported an unsigned apk from the project. This finally fixed things. I had to do similar steps on all my projects.

Thursday, June 24, 2010

Preparing an Android app for publishing ($$)

Writing apps isn't so hard. Writing apps with high usability is another matter. Making the step from one to the other is critical, since you will have better ratings and hence make more money.

First, Wikipedia has a nice definition of usability and it forms a pretty good basis for my purpose. This is the quality of a product as seen by the end-user. I will address each point of the definition in the context of Android but you should be able to see how this applies to devices like the iPhone as well.
  1. Is the user interface intuitive (self-explanatory/self-documenting)? Keep it simple. Mobile devices are powerful, but are best at a limited range of functions per app. Please don't create 20 menu items and a UI that is some complex and detailed that you can't tell what can be clicked.
  2. Is it easy to perform simple operations? Again, keep it simple. The most used functions should not require going into a menu to make them work. If you followed rule one, you might not even need a menu, except for a help file.
  3. Is it feasible to perform complex operations? No. Never.
  4. Does the software give sensible error messages? Use Dialogs or Toast to give good user feedback (and not just for errors). Keep the users in a box so that many errors are precluded by the design of your app. When they do happen, tell the user what they can do about it (if anything). If they can't do anything about the error, keep the message simple: "Please try again later," is just fine. Don't use error codes- this is not Windows development.
  5. Do widgets behave as expected? Use standard widgets, unless you are really good. There is a reason for them. Don't make things hard to use on a touchscreen. Don't make the user guess how something works.
  6. Is the software well documented? Always create a Help or About file. A demo video on YouTube that your app can play is great. I just use a regular html page and load it into a WebView in a Dialog. This is simple and easy to make look good since you can use css. Just put the html and css in the assets directory of your project.
  7. Is the user interface responsive or too slow? Slow apps are bad. Whenever you are doing IO or complex functions, wrap the code in a separate thread so that you can avoid the Application Not Responding message. Web sites do not always respond quickly, different phones runs at different speeds, so help your user out. Eliminate the chance of an ANR and your users will think your app runs like a dream.

Enough motherhood and apple pie. On to some real lessons learned.

Have a kid test your app. they will try all kinds of things you won't and find bugs.

You are going to need to use try/catch/finally a lot, so just get used to it. And you are going to be catching errors you have never even heard of. You will also need to catch some runtime errors (those not declared as thrown, like NullPointerException) since you can't account for everything.

Pay attention to a new feature in the Android Market- errors. Your app listings now show you weekly error reports with stack traces from some phones. This is great! Thousands of people testing your code for you and google reporting the problems. They are not too hard to fix (you usually end up catching some weird error and saying try again).

You can get errors when the handset is rotated unless you prepare your app for working that way. Here's what I put in the Application Manifest to prevent these errors. Include this in your main activity element in the manifest:

android:configChanges="orientation|keyboardHidden"

Don't forget to stop listening for updates to sensors, location services, etc. when your app is paused (unless you need these things). It is simple to turn these back on in onResume.

You may need to catch this: android.view.WindowManager.BadTokenException
It can occur when launching a new activity that wants to put something on screen but you quickly hit 'back'. Basically, you can pull the rug out from under the new activity and cause this error. I have a video app that catches this.

Avoid the ANR by putting IO (and 'expensive' code) into an inner class that extends Thread and uses a Handler to provide data back to the main UI. Other than the main activity Thread, no thread can write data to the screen. You have to use a mechanism like a Handler.

Watch out for window leaks. The fix is to call dismiss() on any Dialog objects in onDestroy(). You are overriding key life cycle events in your Activity, right?

I'm even going so far as to try an work out a scheme to watch memory usage during onCreate to ensure an app can start successfully. On older phones with less memory this can be a problem when a user is running too many apps (and Android fails to shut them down).

That's all for now. Got any more tips to share?