Search This Blog

Tuesday, January 24, 2012

Debugging and Publishing the Blinker App


For entertainment I decided to publish a real app to the marketplace.  I wanted to see what it was like, if there were any unknown obstacles, and see if anyone used my app.   I started with my hello world blinking LED app and polished it up into something marginally useful to others.   Easiest next step was an app to completely control the LED flashlight, blink, pattern setting, speed setting, strobe light, maybe dimming.   It would be useful as a toy and as an emergency signalling device, a strobe light for video, whatever.  Here was my starting goal list of functionality:

  • Flashlight
  • Blinking light
  • Party Strobe Light
  • Warning Hazard Light
  • S.O.S. signaler 
  • Custom LED pattern modulator (for hobby use to transmit data)

I signed up for the Android market as a developer.  Google "android developer", follow the links and fill out the forms.  Done.  That cost $25. Also signed up for the Amazon market so I can publish to the Kindle.  Signed up for  https://developer.amazon.com/help/faq.html#KindleFire.  Have to watch out, amazon costs $99/year after the first year, so this may not last as a hobby.  The first year is free however.  Amazon is stricter, we will see if my hobby app can get through.  I may use ads just so I can see how that works.  I expect that I'll earn up to $1 based on my experience with the web.   No pipe dreams of wealth with this one.

To publish I felt I had to have an app that was useful, with a clean GUI, and minimal bugs.  I didn't even look to see how many other apps were there that did the same thing, that would be too depressing.   This is a hobby project so I have to let myself get excited by the creation.  Until you have worked something through to the level that others can use it, you don't learn all the lessons.

This turned out to be a trickier app than you might think.  The trouble is, you need processing power to blink the light, but you don't want to tie up the GUI thread with marking time or the phone appears hung.   So I had to learn about child processes and about other events that happen on the phone platform like randomly hitting the home or back keys, screen rotation, keyboard opening, etc that your app and it's child process have to deal with.  Asynctask would run amok if not managed well.

There is a lot of "artwork" to building an app.  You need an icon, button layouts, backgrounds, etc that make it look professional.  I probably spent as much time with this as making the code.

Implemented a GUI, in the process learned how to used radio buttons and toggle switches.   Tossed in the basic blinking functionality and then entered the "development loop" of adding functionality, debugging glitches, crossing off items on the list and adding more items as ideas, issues, etc emerge.

This would be my PCR list if this were done at work.  Since coding is not a spectator sport, I'll not write the running blog for this development as I do with hardware.  For anyone starting out, this is a simple and productive way to work on a complex task.  You make a working list of all the things to do.  Then you pick one and do it.  If anything new comes up while you are working on that task, just add it to the list and don't stress about it.  When you finish a task, mark it done, smile, and pick another task, either easy or hard depending on how much time you have and how deeply you can think at that time.  If you stumble across information for a task while working on another one, don't switch gears, just drop some notes in the list and keep rolling.  Eventually everything on the list is done or you decide you don't need to do it.

PCR working list
  • DONE - lay out GUI and hook up buttons
  • DONE - Disable editing pattern on the presets, custom field allows editing 
  • DONE - custom has no pattern, starts with whatever is there
  • DONE - Enforce hardware has a camera flash before downloading
    • Looks like i just need the uses-feature line in my manifest
    • <uses-permission android:name="android.permission.CAMERA" />
       <uses-feature android:name="android.hardware.camera" />
  • DONE remove extra permissions
  • DONE - on off button out of sync if exit and come back, need to check isOn at start
  • REJECTED - Remember the settings from use to use - Not doing, it causes too much trouble
  • DONE - Add the blink rate variable, auto set it for preset
  • DONE - Add the rate slider and figure out how to control it
  • DONE Force the screen to be vertical only because buttons go off the screen in horiz
    • Add android:screenOrientation="portrait" to the element in the manifest 
  • DONE - Set up blinking loop for any length pattern
  • DONE - Debug the thread start and stop and not lock up phone while blinking
  • DONE - Now I have to cancel the task when the user wants to stop the blinking
  • DONE - Sort out glitches with on/off toggle switch
  • DONE - If user exits without turning off blinking, it never stops - put a variable in the while loop of the child thread that kills it on exit.  
  • DONE - Add the information screen pop up text window
    • Toast is a function for doing this sort of thing
  • DONE - Add an epilepsy warning about strobe light 10Hz for less than 30 sec
  • DONE - longer text descriptions for choices on screen
  • FUTURE - Investigate brightness.   Possibly write a PWM loop to dim the LED.  Add a brightness control.
  • DONE - Make an icon - more on this below, it was a doozy
  • FUTURE - Investigate running strobe at the same time as the video recorder, either by backing out or by invoking it for strobe video.  This is an enhancement, probably for a later release, this causes all sorts of problems because the child blinking thread runs amok if I leave it going when I exit the app.  I'd need to call the camera from within my app.  Too much function for now. 
  • FUTURE - Button list is getting too long.  Can I enable scrolling for small screens?  
    • Looks like ScrollView does this, have to set up a frame
    • for now i'll leave it portrait only
  • DONE - Divide by zero on rate setting
  • Check frequency on the scope to see if it is accurate
  • DONE See if there are any color or style easy things to make it look better or different
  • DONE - Downrev app requirement to 8 (2.2) to include more devices
  • DONE!  Eliminate errror when user exits with the light still on, coming from onDestroy or figure out how to kill the child thread without any blood or warning messages.  This was a tricky one.  super.onDestroy() cleaned it up.  not really sure what this does, but it worked.
  • DONE - Screen rotation and opening keyboard is hosing the application by restarting the thread
  • DONE - Move the on button to the bottom
  • FUTURE - Look into how to make a separate horizontal layout
  • DONE - Solid pattern has some flicker - maybe make an override to skip the loop and turn it on straight - was due to double starting the thread
  • DONE - Custom pattern entry has stopped working - resent pattern to buffer when toggle pushed
  • DONE - Getting some new random crashes with monkey button pushes, possibly from spawning duplicate threads, seems to happen when going to a shorter string from a longer one.  Added the thread kill variable to the blinking loop, shuts down faster now.  Very stable.
  • DONE - maybe a cool chip photo for a background?
  • add some instructions on pattern setting in the information toast popup
  • DONE - add some info - mostly unsupported but adfree notes
  • DONE - Get the rep rate slider range and values to be realistic
    • rework here caused some divide by zero problems.  need to clean up the values of the timer and Hz and protect against out of range settings
  • DONE - Stretch the stobe light duty cycle and run it faster
  • DONE - Make the menu text a bit bigger
  • DONE - Bring down the contrast on the background picture to make it more readable
  • DONE - Simple Downrev of code level in manifest won't work, because package in source is 2.3.3.   Either change it back to 10 or figure out how to change the target in the source
  • DONE - some nasty bugs with crazy precsion being displayed from the rate calculation.  cleaned up
  • DONE - fast strobe lights you see an occasional hiccup, probably because the phone interrupted the thread and stole some milliseconds.  
Now I'm pretty happy with the app.  It's stable and it does what it is supposed to do.  I can't crash it by pushing buttons on the phone, opening the keyboard, changing settings like crazy, etc.  I'm going to try to push it to the android market now.


Requirements enforced by the Android Market server:
  1. Your application must be signed with a cryptographic private key whose validity period ends after 22 October 2033.
  2. Your application must define both an android:versionCode and an android:versionName attribute in the <manifest> element of its manifest file. The server uses the android:versionCode as the basis for identifying the application internally and handling updates, and it displays the android:versionName to users as the application's version.
  3. Your application must define both an android:icon and an android:label attribute in the <application> element of its manifest file.

Got the versionCode and versionName.  Now the icon.  Wow.  A lot of artwork to do.
http://developer.android.com/guide/practices/ui_guidelines/icon_design_launcher.html#icons_in_market
https://support.google.com/androidmarket/developer/bin/answer.py?hl=en&answer=1078870

You have to make an icon of several different resolutions.  I tried scaling a jpg photo and shapes in GIMP and it didn't work well at all.  At low resolution and on the phone screen it looked really ragged and unprofessional.   I was using GIMP and the image scaling function and saving at the lower resolutions.   Finally I tried a simple drawing with some texture in power point.  Then I scaled the picture in power point and copied it into the GIMP drawing, over and over again for each resolution.  That worked pretty well and it looks good.  On the phone screen it stands out like a little hazard flasher auto button.


Collected a couple screen shots that are required,  by doing an alt printscreen of the emulator and pasting it into gimp.



Now to figure out how to sign the app.  Found a couple links
http://developer.android.com/guide/publishing/app-signing.html
This seems like a weird and mysterious process.

However it looks like Eclipse  File->Export to an android app presents a form to fill out to make the keystore.   I made a separate directory for this since I had no idea what I was supposed to do.   It seemed to work without doing all the command line stuff.

I walked through the android developer upload page.  I had to scale my screenshots with gimp to 480x854 get them accepted.    A bit of fiddling with the pictures and up it went!

Here is a link to my app list, I will try installing it from the market and see if it works.

Available in Android Market

I published the app and it showed up on a web search the next morning.  I dont know how long it actually took since I went to bed, but it wasn't instant.  Must have been more than an hour.

I cant find the app on the android market from my phone.   When i went to the web link above from my phone, it said my phone WAS NOT COMPATIBLE!  Whaa?  I developed it on that phone.  Something is wrong with my app requirement settings.

Google made a page for the app.  It says I need Android 2.3.7 to install!!! how did that happen?  It looks like since I picked "10" as the build level, it set the requirements to the highest rev that is release 10, which is 2.3.7 not 2.3.3.

https://market.android.com/details?id=sifish.android.blinky&feature=search_result#?t=W251bGwsMSwyLDEsInNpZmlzaC5hbmRyb2lkLmJsaW5reSJd

I went back to downrev the build of the application to 2.1 in eclipse.  That should cover the vast majority of devices.  Right click on project name, Build Path->Configure Build Path->Android and the list of Project Build Targets shows up.  Change the check mark to a lower rev.  Took a while to dig that out of the GUI, but once I found it, it was easy.

Next I had trouble with the keystore, it refused to export the application again.  It turned out there were some errors in the layout.xml file, the "match_parent" keyword didn't work in Android 2.1 and had to be changed to fill_parent.  Once that was cleared up, i could re-export the app.

Discovered I forgot to update the version number when I went to publish.  Had to export again.   After that I still couldn't see the new rev in the app market.   Turns out I had to activate the new release, and de-activate the old one due to the conflict in Android rev support.  

Arrrgh.  Still can't download the app to my phone.  After about an hour, the new rev showed up when doing a web search for the the app.  But I can't see if from the phone and the label says the app is incompatible with my Motorola Droid 2 GLobal.   Whaaa?

Maybe it has something to do with my hardware permissions.  The FLASHLIGHT permission seemed odd, although it works when directly installing.  On the android dev site it seems to be
android.hardware.camera.flash
http://developer.android.com/guide/topics/manifest/uses-feature-element.html
This page showed some different syntax
http://www.linuxforu.com/2011/10/android-app-development-part-5-hardware-and-sensors/

Still going nuts.    Can't get the app to show up on the market as compatible with ANY phones.   This post had some more ideas.   This is something stupid but I don't know what it is yet.
http://stackoverflow.com/questions/5053507/my-android-app-shows-as-this-item-is-not-compatible-with-your-device  After days of fiddling I thought I finally figured out the problem.  It was the  android:screenOrientation="portrait"  line in the manifest http://forums.whirlpool.net.au/archive/1771380.  There is some bug in the compatibility that makes the market think that phones with ONLY portrait mode can use the app.   Lame.   However that STILL didn't get me past the FLASHLIGHT filter. 

The only thing i can seem to publish is a version with the FLASHLIGHT permission stripped out.  making the app totally useless.   So I have an app that works great on my phone, but I can't seem to publish it.  FAIL.   I'm going to put this on the back burner and move on to another app, since this ceases to be fun.

Update!!!!! HOoRAYYYYYYY!  W000T!  By giving up for a day and working on something else I thought of something else to try.  Not only did I have a permission line, i had the line in my manifest that says <uses-feature android:name="android.hardware.FLASHLIGHT" />.   I deleted that, to see if the android market added it back in, and it didn't!  Plus the app still works fine.  Now I show on the dev console as being compatible with 945 devices.  Hooray again, i finally can publish the app.

Amazon app store rejected my app, said that the light didn't turn on.   Lies!   However it is on market now.

In the process of looking for my app in the store, I saw that there are probably 1000 apps to do similar tasks.   So many in fact that I have to search for pub:Siliconfish to even find it amongst the clutter.  I didn't see one exactly the same, and the world probably doesn't need this app.  However I had fun, and I learned a lot, so the project is still a success.    On to bigger fish!




Saturday, January 7, 2012

Android java app - Blinking camera flash LED

I'm developing hardware control applications for the Android phone platform to replicate functionality I've previously used in gadgets for the Arduino.

Finally I achieved my goal of replicating the very first "I'm Alive!" hardware test on a new platform.  Whenever you make a new gadget, the first program you run blinks a light to show health.

I was able to get the LED used for the camera flash to blink!  Hooray!   In my earlier post I found the code and permissions needed to turn it on and off with a button press.   Then I had to find a suitable system clock to use to time the blinking, but got sidetracked generating audio tones.  So finally I put the two together and here is how I did it using the Android SDK in Eclipse.  This technique is limited to <500Hz because the system clock is milliseconds.   The next step will be to find a method to access a faster clock.  However if the goal is communicate to humans or slow serial interface, this might be good enough.

in AndroidManifest.xml you need (you may not need them all, didn't test that)

    <uses-permission android:name="android.permission.CAMERA"/>
    <uses-permission android:name="android.permission.FLASHLIGHT"/>
    <uses-permission android:name="android.permission.HARDWARE_TEST"></uses-permission>

The code I wrote looks like this (copied out the relevant bits from a larger program so hopefully I didn't leave out something critical).  This code was placed in a callback from a button press.  The actual flashing is just done with the for loops, but the rest starts it in another thread so the phone is locked up while this is running.  You don't have to do this but you might frustrate a user if you don't.  I tried it first without the additional thread.   The full app is here, but the relevant bits are below  http://code.google.com/p/arduino-java-xyzcnc/downloads/detail?name=Siliconfish%20Blink.zip&can=2&q=#makechanges
  
    //variables for light blinking
    private final int blinkrate_ms = 100;
    private long nextblink = blinkrate_ms;
        
            //blink the light
            // Use a new thread to flash as this can take a while
                final Thread thread = new Thread(new Runnable() {
                    public void run() {
                        handler.post(new Runnable() {


                            public void run() {                              
                                // loop to flash the camera LED
                                for(int q = 0; q<10; q++)  {
                            nextblink = SystemClock.elapsedRealtime() + blinkrate_ms;
                            while (SystemClock.elapsedRealtime()<nextblink) {
                            setOn(true, null);
                            }
                            nextblink = SystemClock.elapsedRealtime() + blinkrate_ms;
                            while (SystemClock.elapsedRealtime()<nextblink) {
                            setOn(false, null);
                            }
                            } //for
                                
                            }
                        });
                    } 
                }); //thread
                thread.start();
           
                  
It required these functions which turn on and off the LED
     
    // code largely copied from   http://www.java2s.com/Open-Source/Android/Tools/quick-settings/com/bwx/bequick/flashlight/Droid22Flashlight.java.htm
    // Controls the camera flash LED
    
    private Object mManager;


    public boolean isOn(Context context) {
        try {
            Object manager = getManager();
            if (manager != null) {
                Method getFlashlightEnabledMethod = manager.getClass()
                        .getMethod("getFlashlightEnabled");
                return (Boolean) getFlashlightEnabledMethod
                        .invoke(manager);
            }
        } catch (Exception e) {
            Log.e(TAG, "", e);
        }
        return false;
    }


    public void setOn(boolean on, Context context) {
        try {
            Object manager = getManager();
            if (manager != null) {
                Method setFlashlightEnabledMethod = manager.getClass()
                        .getMethod("setFlashlightEnabled",
                                boolean.class);
                setFlashlightEnabledMethod.invoke(manager, on);
            }
        } catch (Exception e) {
            Log.e(TAG, "", e);
        }
    }


    private Object getManager() {
        if (mManager == null) {
            try {
                Class<?> managerClass = Class
                        .forName("android.os.ServiceManager");
                Method methodGetService = managerClass.getMethod(
                        "getService", String.class);
                IBinder hardwareService = (IBinder) methodGetService
                        .invoke(managerClass, "hardware");


                Class<?> stubClass = Class
                        .forName("android.os.IHardwareService$Stub");
                Method asInterfaceMethod = stubClass.getMethod(
                        "asInterface", IBinder.class);
                mManager = asInterfaceMethod.invoke(stubClass,
                        hardwareService);
            } catch (Exception e) {
                Log.e(TAG, "", e);
            }
        }
        return mManager;
    }