Permission problems with Kivy/Android

Kivy is not very helpful in helping you track down permission problems.  If everything else seems working fine, make sure that you have the right Android permissions to access the relevant Android services/hardware.  This is the log file for not having the CAMERA permission:

I/python  (11009):    File “[]/android_zbar_qrcode_master/.buildozer/android/app/main.py”, line 170, in start
I/python  (11009):    File “jnius_export_class.pxi”, line 830, in jnius.jnius.JavaMultipleMethod.__call__ (jnius/jnius.c:21088)
I/python  (11009):    File “jnius_export_class.pxi”, line 561, in jnius.jnius.JavaMethod.__call__ (jnius/jnius.c:17854)
I/python  (11009):    File “jnius_export_class.pxi”, line 727, in jnius.jnius.JavaMethod.call_staticmethod (jnius/jnius.c:19696)
I/python  (11009):    File “jnius_utils.pxi”, line 43, in jnius.jnius.check_exception (jnius/jnius.c:3233)
I/python  (11009):  JavaException: JVM exception occured

Which I experienced when, last week, I added the INTERNET permission to the spec file, but mistyped a . for a ,

I forgot about it and came back to it today and nothing worked – despite me not being able to see any substantive difference between my current py file and the known good one.

Deploying Web2py apps to Google App Engine (GAE)

Last time I tried to deploy a web2py app to GAE was (apparently) years ago now.  I remember it being pretty easy at the time, so I figured I could get it up and running pretty quickly yesterday.  Not so 😦

There are a couple of tricks to it.

The process is (install the app engine sdk and copy of web2py):

1. create your application on your app engine developer Application Overview page

2. create an application skeleton using the web2py dashboard.

3. cp  examples/appengine_config.example.py ./app.yaml

Ie make a copy in the root directory of your web2py directory tree.  This is main trick #1.

4. Edit app.yaml to refer to the id that you got from creating the app on app engine (ie not the local web2py)

5. cp handlers/gaehandler.py .
So, copy the gaehandler to the root directory of web2py. This is main trick #2.

Then you should be ready to roll*

* use <path>/dev_appserver.py web2py to test,

use <path>/appcfg.py update  web2py to deploy

The app will be available from <the Google app id you registered>.appspot.com/<the local web2py name of your application>/

 

Resetting a Text Input (Kivy)

I have written an app which takes a barcode scan from a book, checks whether it is already in my book catalog[ue] and then flashes green or red depending on whether it is in or not.  I have a lot of books to catalog (about 1600) and about 90% of them are already done but I don’t know which 10%.  So I need to sort out that 10% and process them.   I scan the ISBN using a cuecat barcode reader into a Kivy textinput then check it against my list of ISBNs dumped from my existing database (maintained using Readerware).  I want to scan one book after another and separate them into two (ish) piles depending on whether it needs to be entered in the database. The Kivy textinput defaults to multiline.  In that mode you need to press a separate button to invoke a callback.  If multiline is set to False, each “enter” received will call a callback (on_text_validate).  So that means I can scan, check the book and scan again…

…or it would mean that if Kivy didn’t defocus the textinput widget whenever it calls on_text_validate.  After each can the widget needs to be refocussed. The widget can be refocussed by  setting it’s .focus attribute to True.  The trick however is to make sure that happens _after_ Kivy has defocussed the widget.  To do that you need to schedule a callback to occur after the next Kivy “frame”:

        Clock.schedule_once(self._refocus_text_input, 0)
        #from kivy.clock import Clock

    def _refocus_text_input(self,  arg1):
        self.scan_entry.focus=True

Awesome.  Now I don’t have to tap the widget to reset it after each scan.

Fetching a scan from ZXing on Android (Kivy)

Did a bit of mucking around to fetch a scan from ZXing using an intent.  Turned out to be more trouble than it was worth unfortunately because ZXing takes a long time to recognise a barcode. Intent code is:

        Intent = autoclass('android.content.Intent')
        intent = Intent()
        intent.setAction("com.google.zxing.client.android.SCAN")
        Logger.debug("build: about to start activity for result")
        PythonActivity.mActivity.startActivityForResult(intent, 0x123)

It goes without saying that you need to have ZXing already installed on the device. Apparently it will also work with other scanners, but I haven’t tried.

You also need to have a callback to handle the returned result:

    def on_activity_result(self, requestCode, resultCode, data):
        isbn = data.getStringExtra("SCAN_RESULT")
# do other stuff...

And this callback must first be bound:

    activity.bind(on_new_intent=self.on_new_intent,on_activity_result=self.on_activity_result)
# earlier: from android import activity