Android - 'android' module

1,992 views
Skip to first unread message

yorv...@gmail.com

unread,
Mar 19, 2013, 9:21:51 AM3/19/13
to kivy-...@googlegroups.com
I'm running an application on a Nexus 7 using the kivy launcher. Under certain exception conditions I want to display a message INSTEAD of starting the UI app, before aborting. On Linux I just use 'print' but on Android that's invisible - except on the debug log.

So I tried what I would do when running python in sl4a:

import android
droid = android.Android()
droid.dialogCreateAlert("something")

The import seems to work but the next line gives this error
AttributeError: 'module' object has no attribute 'Android'

Why is this?

(And if I can't use that, what's the simplest way of displaying such an error message before the UI runs?)

Ben Rousch

unread,
Mar 19, 2013, 9:24:27 AM3/19/13
to kivy-...@googlegroups.com
You could use pyjnius to get access to Toast. https://github.com/kivy/pyjnius
> --
> You received this message because you are subscribed to the Google Groups
> "Kivy users support" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to kivy-users+...@googlegroups.com.
> For more options, visit https://groups.google.com/groups/opt_out.
>
>



--
Ben Rousch
bro...@gmail.com
http://clusterbleep.net/

com...@motaj.com

unread,
Mar 19, 2013, 7:30:33 PM3/19/13
to kivy-...@googlegroups.com
A simple solution would be to use the `on_start` method wherein you can setup a popup to display the message. Once the message is read you could then exit the app (through a button for example) before loading the app UI.

yorv...@gmail.com

unread,
Mar 20, 2013, 4:49:13 PM3/20/13
to kivy-...@googlegroups.com
Thanks for the suggestions.

"You could use pyjnius..." I expect I could, but it looks like a slegehammer to crack a nut. And I don't know java (I'm struggling with python!) But something to look at in future.

"A simple solution would be to use the `on_start` method wherein you can setup a popup..." I see that 'on_start' happens when the kivy GUI app is first called. How does that help me?  What do I use to do the popup? I don't want to add more widgets into my GUI just for this error condition. I'm really looking for something like 'alert' in javascript.

But what I really want to know is why kivy behaves differently to Py4a/SL4A. I assumed that they were using the same modules but this suggests that they're not - the 'android' module in kivy and the one in Py4A behave differently. (But some are the same - there is the same bug I found in dumbdbm.) And I can't import kivy in Py4A. Presumably this is Android's sandbox model getting in the way. I'd like to understand whether and how the two python environments are connected.

I tried this code - works in Py4A, doesn't in kivy-launcher:

import android
droid = android.Android()
droid.dialogCreateAlert("No new images")
droid.dialogSetPositiveButtonText("OK")
droid.dialogShow()

Is this a bug in the kivy version of the android module, do you think?

Ben Rousch

unread,
Mar 20, 2013, 4:52:33 PM3/20/13
to kivy-...@googlegroups.com
Kivy's Python for Android and SL4A's Python for Android are not
related in any way. They are entirely different projects, but with the
same name (unfortunately).

yorv...@gmail.com

unread,
Mar 24, 2013, 12:53:30 PM3/24/13
to kivy-...@googlegroups.com
On Wednesday, March 20, 2013 8:52:33 PM UTC, Ben Rousch wrote:
Kivy's Python for Android and SL4A's Python for Android are not
related in any way. They are entirely different projects, but with the
same name (unfortunately).

It's very confusing - well. I'm confused, anyway.  I posted on the Py4A user support forum
https://groups.google.com/forum/#!topic/python-for-android/NCC16Z4g4Dc
But no answer there, yet. (Seems a bit quiet there.)

My tentative conclusion is that the problem is with kivy's version of the android module. So I raised an issue:
https://github.com/kivy/kivy/issues/1040
But it may be a misunderstanding on my part.

I have several Py4A/SL4A progs that use similar dialogs for getting params - I originally wrote them for maemo and converted them to Py4A - so I'd like to continue using and add a kivy GUI for the output.

I took a look at pyjnius but couldn't understand it - maybe 'cos I've never used java. Care to suggest some code to put up a notification? I can't find a suitable code snippit.

Anyway, thanks for your answers so far, Ben. (I read your recent presentation slides.)

Dave

Ben Rousch

unread,
Mar 24, 2013, 1:37:59 PM3/24/13
to kivy-...@googlegroups.com

I also started with SL4A, so I have some idea where you're coming from. Kivy doesn't have an 'android' module like Py4A. We have just started work on the 'plyers' project which will serve a similar purpose. For now, you have to access the Java API manually via pyjnius.

I spent some time trying to get Toast to work via pyjnius, but have not been successful yet. Your best bet for now is to use a Kivy pop-up inside of your Kivy app.

--

yorv...@gmail.com

unread,
Mar 24, 2013, 3:35:24 PM3/24/13
to kivy-...@googlegroups.com
On Sunday, March 24, 2013 5:37:59 PM UTC, Ben Rousch wrote:

...Kivy doesn't have an 'android' module like Py4A. ..

It must have a module called 'android' module though - or it's appropriated the name. If it didn't it would give this error:
 ImportError: No module named abcdef

I found a source for a module called android (can't find it now) and it includes 'Android'

So is this a different module with the same name? If that's true we're all in trouble!

Dave

Ben Rousch

unread,
Mar 24, 2013, 4:27:39 PM3/24/13
to kivy-...@googlegroups.com
There may be an 'android' module available to Kivy, but it is not the
same as the SL4A or Py4A 'android' module. The projects are completely
unrelated.

The Kivy python-for-android project is available at
https://github.com/kivy/python-for-android
What you are probably seeing is the android.renpy.org module
https://github.com/kivy/python-for-android/tree/master/src/src/org/renpy/android

This is totally different and unrelated to the Py4A android module
from https://code.google.com/p/python-for-android/source/browse/#hg%2Fandroid

To access the Android functions in Kivy that you would access in Py4A,
you need to use pyjnius https://github.com/kivy/pyjnius
There are some examples on GitHub, some at
http://pyjnius.readthedocs.org/en/latest/android.html
And I have an abstraction layer for TTS at
https://github.com/brousch/saythis-kivy-intro-app/tree/master/saythis/components
> --
> You received this message because you are subscribed to the Google Groups
> "Kivy users support" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to kivy-users+...@googlegroups.com.
> For more options, visit https://groups.google.com/groups/opt_out.
>
>



yorv...@gmail.com

unread,
Mar 24, 2013, 5:20:53 PM3/24/13
to kivy-...@googlegroups.com
I suspect this is the 'android' module Py4A use:
http://android-scripting.googlecode.com/hg/python/ase/android.py

I wonder who controls module names to avoid duplicates and ensure portability?

Anyway, that's clearly the problem. Thanks for making it clear.

Dave

yorv...@gmail.com

unread,
Mar 25, 2013, 9:00:22 AM3/25/13
to kivy-...@googlegroups.com
I looked again but couldn't see how to use pyjnius for dialogs like I'm used to in Py4A. Maybe someone could add to the existing examples sometime. Just the ability to issue an error message, in the event that the app can't be launched, would be useful. (I also found some IRC logs which explain some of the background to the kivy/Py4A situation.)

Anyway, the easiest way I found to solve my original problem - how to display an error message - was to add another App with just a message and a button. Clunky - but it'll do.

Dave

Yurij Mikhassiak

unread,
Mar 25, 2013, 9:24:56 AM3/25/13
to kivy-...@googlegroups.com
Why it's not possible to port sl4a android module to kivy?
I think all this python fackades are so usefull, you need only two lines of code to send sms or email..
Maybe there can be any hack?

Ben Rousch

unread,
Mar 25, 2013, 9:37:13 AM3/25/13
to kivy-...@googlegroups.com

I think it is possible - the Qpython Android IDE seems to have done it - but no one has made a solution publicly available. Also, Kivy is focusing on a consistent platform abstraction layer (the plyers project) so the same interface can be used on any OS.

Anyone who would like to have the Py4A 'android' interface on Kivy is welcome to take a crack at it. I personally would use it until plyers is mature, but I lack the time and knowledge to port it right now.

Message has been deleted

Yurij Mikhassiak

unread,
Mar 26, 2013, 4:36:05 AM3/26/13
to kivy-...@googlegroups.com
I see Qpython plus supports  both  SL4A and  kivy libraries import. Showcase from kivy worked ok for me. But still as I know we can't create apk with qpython. And also I am not sure that qpython unicode  support was correct.

yorv...@gmail.com

unread,
Mar 26, 2013, 6:36:01 AM3/26/13
to kivy-...@googlegroups.com
On Tuesday, March 26, 2013 8:36:05 AM UTC, Yurij Mikhassiak wrote:
I see Qpython plus supports  both  SL4A and  kivy libraries import.

That's useful to know, Yurij - I'll try it. I don't want to package my programs - they're just things I've developed over the years and want to run on whatever device I have.  They started off as bash scripts and grew!

What I like about kivy is I can test on a Linux desktop and deploy on Android. (So I wouldn't use the Android facades if I had something more portable for dialogues.)

What I don't like about kivy on Android (i.e. via the kivy launcher) is that I can't see the console. Hence my original problem - I couldn't see the output from print.  SL4A is better for that. If I get a failure - the internet connection fails, say - I can see it.

I also ported my programs to an iPad, initially under Python for iOS and now under Pythonista. Both give me a console - you swipe left/right to switch between the GUI and the console. If kivy/python-for-android/launcher could do that it would be better.

Yurij Mikhassiak

unread,
Mar 27, 2013, 11:22:44 AM3/27/13
to kivy-...@googlegroups.com
You can write own log handler and start  subprocess that opens log for you if trouble occured. I use multiprocessing module so i am not using kivy logger because it can't handle multiprocess output.  My handler write logs and sends emails or SMS on critical errors, so we need fackades for that purpose. I think we can reread  our log every time new record arrives. Logreader can be run as subprocess by main script. As I know in linux (so in android) you can open same copy of file in different programs. If anybody would like to write such code it will be nice. In future I plan to write such script if i'll have time. By the way I think luncher should have config option to open kivy log on time we start our scripts.

What do you think?

Regards, Yurij


Вівторок, 26 березня 2013 р. 12:36:01 UTC+2 користувач yorv...@gmail.com написав:

yorv...@gmail.com

unread,
Mar 27, 2013, 1:52:02 PM3/27/13
to kivy-...@googlegroups.com
On Wednesday, March 27, 2013 3:22:44 PM UTC, Yurij Mikhassiak wrote:
You can write own log handler and start  subprocess that opens log for you ...

What do you think?

Hmmm. That's very ingenious.

But 'over the top' for my problem. I foresee that, if I start using kivy more on Android, I will occasionally launch a kivy app and .... nothing will happen. It may be something simple like I forgot to turn the mobile data on, or it may be a problem with a webserver it accesses. These aren't published apps - I don't program for every eventuality. I use them when travelling so I don't have a laptop or any diagnostic tools to hand. But if I can see the console the problem is usually obvious.

I once wrote a program that used tkinter for GUI. I included a log area at the bottom of the display and used a 'StdoutRedirector' to show progress and error messages. I expect something similar would work with kivy -  I might try that next time.

Yurij Mikhassiak

unread,
Mar 27, 2013, 2:42:02 PM3/27/13
to kivy-...@googlegroups.com

If it's possible to add button and popup to your app it can solve all problems. Just read log to popup content. I think it's the easiest way and saves scren for more usefull tasks. Use try blocks and multiprocessing to protect from situations were your app will not start or FC. Also you can add status bar but it will need some more coding depending on type of output of your task. Good luck! Give us updates of your solution.

--
You received this message because you are subscribed to a topic in the Google Groups "Kivy users support" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/kivy-users/QkmdLmdY-bI/unsubscribe?hl=en.
To unsubscribe from this group and all its topics, send an email to kivy-users+...@googlegroups.com.

yorv...@gmail.com

unread,
Mar 28, 2013, 5:12:09 AM3/28/13
to kivy-...@googlegroups.com
Well, yes I can redirect stdout to a label widgit. Doing a couple of minor mods to my tkinter code I found this works:

        self.text_area = Label(text='', size_hint=(1, .3))
        layout.add_widget(self.text_area)       

        class IORedirector(object):
# A general class for redirecting I/O to this Text widget.
            def __init__(self,text_area):
                self.text_area = text_area

        class StdoutRedirector(IORedirector):
# A class for redirecting stdout to this Text widget.
            def write(self,str):
                self.text_area.text = self.text_area.text + str

        import sys
        sys.stdout = StdoutRedirector( self.text_area )

It doesn't scroll, but I expect it could.

BUT it wouldn't solve my original problem - because the GUI wasn't up when I wanted to show my error message. And it doesn't show me python errors either because those shut down the GUI window. So it maybe has some utility in displaying debug messages but otherwise it's not much use!

To see python errors I need to be outside the GUI - perhaps using a log handler as you suggested, Yurij, or by the kivy launcher allowing me to see the console or log, like SL4A does.

Yurij Mikhassiak

unread,
Mar 28, 2013, 9:39:27 AM3/28/13
to kivy-...@googlegroups.com
Why are you afraid of log handlers? I see there https://github.com/kivy/buildozer project wich will help debugging of the software in future if you could connect it to the laptop. 
If you know there only few possible exceptions you can arrange error handling by raising popup with traceback info. It will not kill the app. 

My alfa logging code is like that as for now ( I plan to use email logger only on critical errors in future) :

'''MODULE: loggers.py
This module is special logger handler for sending emails and SMS on logger event. For use on android.
 needs testing. Please edit Usage: handler=maillog.Notifier()'''

import logging
import time
import logging.handlers as handlers
from threading import Thread
from logging.handlers import TimedRotatingFileHandler
import multiprocessing as mp

email = 'yo...@gmail.com'
topic = '[TOPIC]'
phonenumber= '+38063000000'



class SizedTimedRotatingFileHandler(handlers.TimedRotatingFileHandler):
    """
    Handler for logging to a set of files, which switches from one file
    to the next when the current file reaches a certain size, or at certain
    timed intervals 
        
    """
    def __init__(self, filename, mode='a', maxBytes=1000000, backupCount=0, encoding=None,
                 delay=0, when='h', interval=1, utc=False):
        # If rotation/rollover is wanted, it doesn't make sense to use another
        # mode. If for example 'w' were specified, then if there were multiple
        # runs of the calling application, the logs from previous runs would be
        # lost if the 'w' is respected, because the log file would be truncated
        # on each run.
        if maxBytes > 0:
            mode = 'a'
        handlers.TimedRotatingFileHandler.__init__(
            self, filename, when, interval, backupCount, encoding, delay, utc)
        self.maxBytes = maxBytes

    def shouldRollover(self, record):
        """
        Determine if rollover should occur.

        Basically, see if the supplied record would cause the file to exceed
        the size limit we have.
        """
        if self.stream is None:                 # delay was set...
            self.stream = self._open()
        if self.maxBytes > 0:                   # are we rolling over?
            msg = "%s\n" % self.format(record)
            self.stream.seek(0, 2)  #due to non-posix-compliant Windows feature
            if self.stream.tell() + len(msg) >= self.maxBytes:
                return 1
        t = int(time.time())
        if t >= self.rolloverAt:
            return 1
        return 0



def sendmail(record):
    try:
        import android
        droid = android.Android()
        droid.sendEmail(email, topic+str(record)[0:30], record)#sending first 30 chars of message in topic
    except Exception as err:
        logging.exception(err)
        
def sendsms(record):
    try:
        import android
        droid = android.Android()
        droid.smsSend(phonenumber ,record)
    except Exception as err:
        logging.exception(err)


class Notifier(logging.Handler):
    
    def emit(self, record):
        try:

            '''PUT HERE YOUR CODE TO WRITE LOG AND THEN OPEN LOG IN FILE OR TO SHOW POPUP USING KIVY OR P4A FACADE.
               IF USING MULTIPROCESSING IT'S MUCH HARDER TO KILL YOUR PROGRAM BY UNHANDLED ERROR IF ERROR IS
               NOT IN MAIN THREAD.''' 

            thread = Thread(target=sendmail, args=(record))
            thread.start()
            thread = Thread(target=sendsms, args=(record))
            thread.start()
        except (KeyboardInterrupt, SystemExit):
            raise
        except:
            self.handleError(record)
            
class loopchekerFilter(logging.Filter):
    '''prevents from logoverflow on continuous error log'''
    oldrecord = None
    i = None

    def filter(self, record):
        if self.i > 10:
            return False

        if self.i == 10:
            # I use another optional handler here to record message (you can put your own action)
            you need to create "critical" handler before using next line: 
            critical.error('Entered logger continuous loop..aborting logging')
            self.i+=1
            return False
        
        if str(record) == str(self.oldrecord):
            self.i+=1
            self.oldrecord = record
            return True
        
        if str(record) != str(self.oldrecord): 
            self.i=0
            self.oldrecord = record
            return True
        
        
        
        

    


logger = mp.log_to_stderr(logging.DEBUG)
hdlr1  = SizedTimedRotatingFileHandler('logs/program.log', when='d', backupCount=7, maxBytes=1000000)#filename, interval = each day, delete 7 days old files
format1 = logging.Formatter('%(asctime)s--- %(processName)-12s %(levelname)-8s>> %(message)s')
hdlr1.setFormatter(format1)
logger.addHandler(hdlr1)
logger.addFilter(loopchekerFilter())




Hope that will help.  Please share your code with us. Perhaps it's usefull for everyone to include such handler in all production software. I think user should have solution to send error log to developer too. 
You can also filter log record on special text like when aplications is leaving with error code to open log in this situation.  Is there any small kivy script to open logs? 

Regards, Yurij

Yurij Mikhassiak

unread,
Mar 28, 2013, 9:42:34 AM3/28/13
to kivy-...@googlegroups.com
'''PUT HERE YOUR CODE TO WRITE LOG AND THEN OPEN LOG IN FILE OR TO SHOW POPUP USING KIVY OR P4A FACADE.
               IF USING MULTIPROCESSING IT
S MUCH HARDER TO KILL YOUR PROGRAM BY UNHANDLED ERROR IF ERROR IS
               NOT IN MAIN THREAD.'''



            thread
= Thread(target=sendmail, args=(record))

yorv...@gmail.com

unread,
Mar 28, 2013, 1:49:19 PM3/28/13
to kivy-...@googlegroups.com
Thanks for sharing that.

But I found an easy solution - aLogcat - an app that displays the log. It can filter on kivy & python.

(What I need now is kivy on Pythonista for iOS too, then I could adopt it on all platforms. I'll ask over there.)
Reply all
Reply to author
Forward
0 new messages