test

Test

>>> a = 1
>>> b = 2
>>> print(a)
1
>>> print(b)
2
>>> print(a+b)
3
>>> print(b-a)
1
>>> print(a<b)
True

Advertisements

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

Kivy – Problems with on_new_intent in Apps

In an earlier post I wrote about the wonderful on_new_intent hook which allows your application to receive intents from other apps on an Android device.  When the other app sends an intent your app will process it in whatever callback you bound to on_new_intent (which I will call on_new_intent() for the sake of simplicity).  To receive an intent from another app will probably mean that the user is actively using that other app.  That means that your app has been paused.  So, when Android passes the intent to your app it’s going to want to on_resume your app.   Can you see where this is going?

The problem with using on_new_intent in an app is that on_resume() and on_new_intent() are both fired at more or less the same time.  There is no guarantee that one of them will be called first and no guarantee that the one called first will return before the second one is called (in my experiments they can fire in either order and can fire in the middle of the other).  In other contexts  this might not be a problem.  Here it is.  The purpose of on_resume is to reinitialise the App state to where it was as at the last call to on_pause().  The purpose of on_new_intent is to initialise or update the App state based on the data provided by the intent.   This is not a problem for services because services are running in the background and on_resume need not be called.

The future solution is that I’ve logged an issue.  My current solution is a hackish workaround – delay the execution of on_new_intent to give on_resume a chance to start, and use flags for on_new_intent to wait for it to finish.  If the timing is bad, this will fail, but seems to be ok in practice so far (ie last 24 hours).

Sample code (init the attributes to False when you instantiate the app too btw):

class GridderApp(App):
#[stuff deleted]
    def on_resume(self):
        if self.on_new_intenting: # let it run, don't bother about initialising to saved
            return
        self.resuming = True
        self.uiwidget.load(path=".",   filename=PAUSE_FILE_NAME,  store_save= False)
        self.resuming = False

    def on_new_intent(self, intent):
        self.on_new_intenting = True
        sleep(0.25) # give on_resume a chance to fire
        # if it fires after on_new_intent has finished, it will reinitialise to the saved state
        # and we want to avoid that!
        while self.resuming:
            sleep(0.1)

        intent_data = intent.getData()
        try:
            file_uri= intent_data.toString()
        except AttributeError:
            file_uri = None
        if file_uri is None:
            return
        else:
            if file_uri[:7]=="file://":
                self.uiwidget.load(path="",  filename=url2pathname(file_uri[7:]))
            else:
                return
        self.on_new_intenting= False

Kivy – Receiving Android Intents

In theory Kivy has a way to receive intents generated from other apps on Android – it’s the on_new_intent callback hook.  To use it you first need to write a method to handle the intent.  The method will be passed the intent, but you’re going to have to unpack data from it.  What data is to be unpacked and how you go about it will be different depending on the intent.  You’ll need to dig into the Android Java docs/stack exchange to get details.  This is a sample unpacking of a file uri which has been provided by a file manager app.  The file uri is not in a format that Kivy can use so it’s got to first be unescaped (here I use url2pathname from urllib2):

class GridderApp(App):
# [stuff deleted]
    def on_new_intent(self, intent):
        intent_data = intent.getData()
        try:
            file_uri= intent_data.toString() # isn't Java awesome?
        except AttributeError:
            file_uri = None
        if file_uri is None:
            return # give up
        else:
            if file_uri[:7]=="file://":
                self.uiwidget.load(path="",  filename=url2pathname(file_uri[7:]))
            else:
                return # again, give up

That’d all be lovely if that’s how it actually worked. Unfortunately on_new_intent seems to be designed on the assumption that it’s being run as the method of a Service not an app. This code won’t work for an app for reasons to be covered in a later post.

After you’ve defined this method you need to bind it:

if __name__ == "__main__":
    if platform=="android":
        import android.activity
        app = GridderApp(file_uri=file_uri)
        android.activity.bind(on_new_intent=app.on_new_intent)

After which, you’re good to go! Except that apps suffer from a problem with receiving intents – see my next post.

Apparently (as at July 2014) on_new_intent does not work on the application’s first start, so you can’t get (eg) a file uri from an intent if your app has not been run before or has been run, but stopped.  I’m told this is a bug so it may be fixed in the future.