/dev/blah

things i want to remember, things i want to share

Développeur Python et adepte Linux depuis 2005, passionné par beaucoup trop de choses. Profil Github

Entries tagged “android”

Building a background application on android with Kivy.

written by tshirtman, on 1/12/14 12:36 AM.

Kivy runs on android using the python-for-android project, which support android services. This works in a simple way, you basically bundle two main.py in your application, one for the UI, one for the service. The UI can start the services on start. From that point though, things may be a little uneasy. Why? Because you have two applications, and now you have to make them talk to each over if you want to do anything useful.

Android’s way of having an Activity and a Service talk to each other is Broadcast signals, which can be limited to part of your applications, howether, it’s not straightforward to use them with pyjnius, which is the magical interface we use to use java code from python.

Another way is to use network, i’ve been doing it with twisted in the past, setting a twisted server in the Service, and using twisted as a client in the Activity, howether, i find this to be heavy lifting for the trivial task of communicating between two programs on the same device. And including Twisted in your app, certainly add some weight to it.

Howether, in order to support TUIO, kivy ships with a simple OSC implementation, OSC is a simple connectionless network protocol, that allow you to pack messages, and send them to an ip/port/api URI, turns out we don’t need anything more, and a connectionless protocol avoid us dealing with disconnections (like the UI being closed, or the service not being started yet) that could give us some headaches (and certainly gave me some). We just need to have both part of the program listen for OSC messages, and have them send data to each other, if confirmation is needed, it’s possible to have a messages been sent back on a specific api.

So let’s get started.

getting a minimal kivy app

The usual things, let’s put a simple UI with a Button.

from kivy.app import App
from kivy.lang import Builder

kv = '''
Button:
    text: 'push me!'
'''

class ServiceApp(App):
    def build(self):
        return Builder.load_string(kv)

if __name__ == '__main__':
    ServiceApp().run()

here we just load a kv string that defines a button, and return the result, nothing fancy.

getting a minimal service

from time import sleep

if __name__ == '__main__':
    while True:
        sleep(.1)

Yeah, nothing much needed, actually, the sleep isn’t even needed, but the program have to run, and we’ll need this loop anyway.

starting the service

For your service to run, you need to tell your UI to start it.

from kivy.app import App
from kivy.lang import Builder
from kivy.utils import platform

kv = '''
Button:
    text: 'push me!'
'''

class ServiceApp(App):
    def build(self):
        if platform == 'android':
            from android import AndroidService
            service = AndroidService('my pong service', 'running')
            service.start('service started')
            self.service = service

        return Builder.load_string(kv)

if __name__ == '__main__':
    ServiceApp().run()

We make the test for android, so you can still test your app on desktop, by starting manually both parts.

Packaging them for android

both files must be named main.py, the UI one is at the root of the project, the other one is in a service directory directly under the root of the project.

├── main.py
└── service
    └── main.py

To package, i’ll be using buildozer.

As we are using network don’t forget to add the NETWORK permission when editing buildozer.spec

buildozer init
editor buildozer.spec
buildozer android debug deploy run logcat

After some time, you should see the (not very exciting) app start on your plugged android device.

setting up OSC

Whatever the side, OSC needs a port to listen on, and to have functions to call when things happen. The basic setup is simple.

from kivy.lib import osc

def some_api_callback(message, *args):
   print("got a message! %s" % message)

osc.init()
oscid = osc.listen(ipAddr='0.0.0.0', port=someport)
osc.bind(oscid, some_api_callback, '/some_api')

and then

osc.readQueue(oscid)

needs to be called regularly.

for the service, we’ll just put this call in the loop:

from time import sleep
from kivy.lib import osc

service = 3000

def some_api_callback(message, *args):
   print("got a message! %s" % message)

if __name__ == '__main__':
    osc.init()
    oscid = osc.listen(ipAddr='127.0.0.1', port=service)
    osc.bind(oscid, some_api_callback, '/some_api')

    while True:
        osc.readQueue(oscid)
        sleep(.1)

And for UI, we’ll use kivy.clock.Clock’s schedule_interval method.

from kivy.app import App
from kivy.lang import Builder
from kivy.lib import osc
from kivy.utils import platform
from kivy.clock import Clock

activityport = 3001

def some_api_callback(message, *args):
   print("got a message! %s" % message)

kv = '''
Button:
    text: 'push me!'
'''

class ServiceApp(App):
    def build(self):
        if platform == 'android':
            from android import AndroidService
            service = AndroidService('my pong service', 'running')
            service.start('service started')
            self.service = service

        osc.init()
        oscid = osc.listen(ipAddr='127.0.0.1', port=activityport)
        osc.bind(oscid, some_api_callback, '/some_api')
        Clock.schedule_interval(lambda *x: osc.readQueue(oscid), 0)

        return Builder.load_string(kv)

if __name__ == '__main__':
    ServiceApp().run()

Now, both sides can receive messages, that’s a good first step, but nothing will really happen, since none of them send any message.

sending messagse

The osc api to send message is very simple:

osc.sendMsg(api, data_list, port=someport, ipAddr=someaddress)

now, ipAddr is by default localhost, which is fine for us, so we only need to find the api we want to hit, the data list, and the port, which will be the one the other side listens on.

Let’s make our button send a message to the Service.

from kivy.app import App
from kivy.lang import Builder
from kivy.lib import osc
from kivy.clock import Clock

activityport = 3001
serviceport = 3000

def some_api_callback(message, *args):
   print("got a message! %s" % message)

kv = '''
Button:
    text: 'push me!'
    on_press: app.ping()
'''

class ServiceApp(App):
    def build(self):
        if platform == 'android':
            from android import AndroidService
            service = AndroidService('my pong service', 'running')
            service.start('service started')
            self.service = service

        osc.init()
        oscid = osc.listen(ipAddr='127.0.0.1', port=activityport)
        osc.bind(oscid, some_api_callback, '/some_api')
        Clock.schedule_interval(lambda *x: osc.readQueue(oscid), 0)

        return Builder.load_string(kv)

    def ping(self):
        osc.sendMsg('/some_api', ['ping', ], port=someotherport)


if __name__ == '__main__':
    ServiceApp().run()

Yes, at that point, you can run it, and see that when you press the button, your adb logcat on android, yay!

Now, let’s make our service answer, and our UI display the answer!

from time import sleep
from kivy.lib import osc

serviceport = 3000
activityport = 3001

def some_api_callback(message, *args):
    print("got a message! %s" % message)
    answer_message()

def answer_message():
    osc.sendMsg('/some_api', [asctime(localtime()), ], port=activityport)

if __name__ == '__main__':
    osc.init()
    oscid = osc.listen(ipAddr='127.0.0.1', port=serviceport)
    osc.bind(oscid, some_api_callback, '/some_api')

    while True:
        osc.readQueue(oscid)
        sleep(.1)

and for the UI to answer:

from kivy.app import App
from kivy.lang import Builder
from kivy.lib import osc
from kivy.utils import platform
from kivy.clock import Clock

activityport = 3001
serviceport = 3000

kv = '''
Button:
    text: 'push me!'
    on_press: app.ping()
'''

class ServiceApp(App):
    def build(self):
        if platform == 'android':
            from android import AndroidService
            service = AndroidService('my pong service', 'running')
            service.start('service started')
            self.service = service

        osc.init()
        oscid = osc.listen(ipAddr='127.0.0.1', port=activityport)
        osc.bind(oscid, some_api_callback, '/some_api')
        Clock.schedule_interval(lambda *x: osc.readQueue(oscid), 0)

        return Builder.load_string(kv)

    def ping(self):
        osc.sendMsg('/some_api', ['ping', ], port=someotherport)

    def some_api_callback(self, message, *args):
        print("got a message! %s" % message)
        self.root.text += '\n%s' % message[2]

if __name__ == '__main__':
    ServiceApp().run()

The only thing a bit confusing here is that the real message is in message[2], don’t ask me why, it’s probably explained in some documenation i didn’t care enough to search for :).

conclusion

That’s not much code! And it should be quite easy to extend to allow for more complex patterns, detecting if your service is running or not can be done by making it send pings at regular intervals, you can also make your service fetch/work on data from somewhere else in the background, and pass it to the UI when it’s ready.

A slightly more complex demo based on this can be found here.

Tip me if you like this :)

Debugging python-for-android with gdb

written by tshirtman, on 11/13/12 1:55 AM.

So i’ve been sinking a lot of time in trying to make python-for-android support multiprocessing, and for various reasons, it turns out to be a bad idea®, but in doing that, i had to go to great extents to understand more about python-for-android, about gdb, and about android itself. So, if it can save some trouble to others, i’ll try to document here the things i found how to do in this situation.

So the first thing to do is to get python-for-android compiled with debug symbols, so you can feed gdb with them, i found android-ndk-r8b to work much better after (well, to work at all), so it’s good to start with it, i put my changes in a branch of python-for-android repository, aptly called `debug` but they are not that big in fact, it’s mostly removing stripping in places, and adding -g in others.

With those changes, one can build a python-for-android distribution usable for debugging.

./distribute.sh -f -m 'kivy' -d debug

then, build your to-be-debugged application with this distribution, and install it, from then, you need a shell access to your android terminal (i use ssh, because adb over wifi is flacky but that’s another story, adb shell is good), you must then check if your terminal has the gdbserver command, if not, you can push it from the ndk to the terminal, and give it execution rights.

adb push ~/android-ndk-r8b/prebuilt/android-arm/gdbserver
adb shell
chmod 755 gdbserver

now, you can start your test program (from the UI), and tell gdbserver to attach to it,

ps | grep python
gdbserver :5050 --attach $pid

obviously using the pid found using the command, i use a shortcut though

./gdbserver :5050 --attach $(ps | grep python | tail -n 1 | tr -s " " " "| cut -d" " -f2)

This will tell gdbserver to listen on port 5050 (you can chose about any number between 1024 and 65536) and then the fun part begins

using the gdb in the ndk, load the pymodules.so file

$ ~/android-ndk-r8b/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/bin/arm-linux-androideabi-gdb\
 ~/python-for-android/dist/debug/private/libpymodules.so

of course, this path (and the following ones) will need to be adapted to your system!

once in gdb, you’ll want to attach to the gdbserver on your device, i assume you are on the same wifi network as your device, but if not, you can do a port redirection through adb link i think

(gdb) target remote transformer:5050

If everything went fine, you should get a message a bit like this

Remote debugging using transformer:5051
warning: while parsing target library list (at line 2): No segment defined for com.showgen.processcraft.freemium:python
warning: Could not load shared library symbols for 87 libraries, e.g. /system/bin/linker.
Use the "info sharedlibrary" command to see the complete listing.
Do you need "set solib-search-path" or "set sysroot"?
warning: Unable to find dynamic linker breakpoint function.
GDB will be unable to debug shared library initializers
and track explicitly loaded dynamic code.
0x400b9384 in ?? ()

as the helpful message put it, we need to tell gdb where it can load the shared libs with debug symbols. Personnaly i found this setting of `solib-search-path`to work well:

(gdb) set solib-search-path \
/home/gabriel/python-for-android/src/obj/local/armeabi/:\
/home/gabriel/python-for-android/dist/debug/private/lib/python2.7/lib-dynload/:\
/home/gabriel/python-for-android/dist/debug/libs/armeabi/

You can check the result of this by using the command `info sharedlibrary` (or `i sh` for the lazy) to see if symbols have been found, the interresting part for me is:

0x56d31348  0x56d5c148  Yes         /home/gabriel/python-for-android/src/obj/local/armeabi/libsdl.so
0x579b5400  0x579d5798  Yes         /home/gabriel/python-for-android/src/obj/local/armeabi/libsdl_image.so
0x579fa428  0x57a2c1f8  Yes         /home/gabriel/python-for-android/src/obj/local/armeabi/libsdl_ttf.so
0x56a5a6b0  0x56a69c20  Yes         /home/gabriel/python-for-android/src/obj/local/armeabi/libsdl_mixer.so
0x5b985570  0x5bbc9e90  Yes         /home/gabriel/python-for-android/dist/billing/libs/armeabi/libpython2.7.so
0x56a79a1c  0x56a79c04  Yes         /home/gabriel/python-for-android/src/obj/local/armeabi/libapplication.so
0x56dee534  0x56dee5e8  Yes         /home/gabriel/python-for-android/src/obj/local/armeabi/libsdl_main.so
0x57604450  0x5761ed40  Yes         /home/gabriel/python-for-android/dist/billing/private/lib/python2.7/lib-dynload/_io.so
0x57a7426c  0x57a77630  Yes         /home/gabriel/python-for-android/dist/billing/private/lib/python2.7/lib-dynload/unicodedata.so
0x57b5b058  0x57b97d00  Yes         /home/gabriel/python-for-android/src/obj/local/armeabi/libsqlite3.so

Interrestingly, it seems the command is only useful after connecting to the target, doing it in reverse order doesn’t seem to bring any result, so the `search` is probably done only once, whet the search-patch is set.
Now, you can use the command `continue` or set breakpoints, or other rather common usage of gdb there. There are quite some resources out there about gdb usage :)

It’s not perfect, but i found it helping to be able to backtrace things on the tablet, in the nasty case you get a crash, or some weird “OSError”, with an unhelpful message, comming from the C side of things.

For the story, my error was likely caused by memory corruption due to the way we tried to reimplement the multiprocessing use of semaphore (sem_open being not implemented in android), and there is apparently no good way to do it. So i’ll look into android services instead when i have time, and try to give an API in python for that.

Tip me if you like this :)

[Kivy] android-like pulldown menu

written by tshirtman, on 10/22/12 9:29 PM.

kivy all the things

As someone asked how to do such thing in kivy, i spent some time writting it, and as i (sadly) don’t blog on kivy often (if ever?), and since i think this example is quite telling about how kivy make such things quite easy, let’s talk a bit about this code.

To put things in context, what we want is the bar at the top of the android phones, that one can pull down to see notifications, this one is semi transparent and goes over the normal screen.

So, here is the code. first the kv part:

FloatLayout:
    FloatLayout:
        # placeholder for the "normal screen"
        Label:
            center: root.center
            text: 'test content'
            size_hint: None, None
            size: self.texture_size

    ScrollView:
        # container for the "notifications"
        y: dg.top # let's stick it to the top
        x: root.x # and to the left
        size_hint_y: None
        do_scroll_x: False # only vertical scrolling
        do_scroll_y: True
        
        # most of the magic is there, auto adjust size to follow the draggable label
        height: root.top - dg.y

        # let's put a nearly opaque black background
        canvas:
            Color:
                rgba: 0, 0, 0, .8
            Rectangle:
                pos: self.pos
                size: self.size
        
        # the actual notification container, with placeholder content
        BoxLayout:
            size_hint_y: None
            height: 1000
            orientation: 'vertical'
            Label:
                text: 'test'
            Label:
                text: 'test'
            Label:
                text: 'test'
            Label:
                text: 'test'
            Label:
                text: 'test'
            Label:
                text: 'test'
            Label:
                text: 'test'
            Label:
                text: 'test'
            Label:
                text: 'test'

    # the draggable label, which behaviour is defined in python file
    DraggableLabel:
        # some decoration behind the text
        canvas.before:
            Color:
                rgba: 0, 0, 0, 1
            Rectangle:
                pos: self.pos
                size: self.size
            Color:
                rgba: .5, .5, .5, 1
            Rectangle:
                pos: self.pos
                size: self.width, 1

        size_hint_y: None
        top: root.top
        # assign its id to "dg" so we can reference it elsewhere
        id: dg
        height: '20pt'
        text: 'drag me'

then the python part

from kivy.app import App 
from kivy.uix.label import Label
from kivy.animation import Animation


class DraggableLabel(Label):
    '''A label you can drag upside-down'''
    def on_touch_down(self, touch):
        if self.collide_point(*touch.pos):
            # assure ourselves we will get the updates of this motion
            touch.grab(self)
            return True

        return super(DraggableLabel, self).on_touch_down(touch)

    def on_touch_move(self, touch):
        if touch.grab_current is self:
            # really straightforward...
            self.y = touch.y
            return True

        return super(DraggableLabel, self).on_touch_move(touch)

    def on_touch_up(self, touch):
        if touch.grab_current is self:
            # check if the movement direction was up or down
            if touch.dy < 0:
                a = Animation(y=0) # down? put the bar all the way down
            else:
                a = Animation(top=self.parent.top) # up? put it at the top

            a.start(self) # actually start the animation
            return True

        return super(DraggableLabel, self).on_touch_up(touch)


class TabApp(App):
    pass


TabApp().run()

 

I think it doesn’t really need more explanations, the DraggableLabel is looking for touch events that are for it, first if they are on it, then if they are grabbed by itself, and move accordingly, and the kv auto adjust the size of the ScrollView to take all the distance between top of the screen and top of the DraggableLabel.

Of course, if things are not clear, feel free to ask questions :)

Tip me if you like this :)

Hacking tablette carrefour CT705

written by tshirtman, on 9/20/12 10:38 PM.

Carrefour a fait pas mal de pub sur une tablette 7″ android 4.0 à 77€, ça avait pas l’air trop mal dedans, alors pour le prix, j’en ai commandé une.

C’est pas mal, mais de base, on peut pas faire grand chose avec… J’ai vu qu’on pouvait installer cyanogenmod dessus, mais tout ne marche pas encore, donc j’ai préféré résoudre les problèmes un par un.

Installation du market:

Oui, par défaut, il n’y a pas google play… il y a un market alternatif très limité, «getjar», j’ai trouvé une procédure pour installer le market et ses dépendances à la main, en cliquant les apk, mais ça n’a jamais voulu marcher, j’avais toujours une «server error» en lançant le market, ou pire, un crash.

J’ai finit par rooter la tablette, en utilisant ce script, que j’ai trouvé sur un coins du net, et convertis de batch à bash: https://gist.github.com/3758061 (les fichiers associés sont )

Sauf que… adb ne voyait pas la tablette, ça a faillit me rendre fou… la solution, ça a été de faire :

android update adb
echo "0x2207" > ~/.android/adb_usb.ini
adb kill-server
adb root
adb start-server

La tablette est ensuite correctement visible, et `adb shell` marche (le numéro magique, 0x2207, vient d’une doc sur une tablette archos basé sur la même archi, c’était un peu du pifometre, mais ça a marché, alors…) (edit: cette solution ne marche pas tout le temps, je n’ai pas encore bien compris, un conseil, une fois que vous avez réussis et rooté, installez un serveur ssh, dropbear ssh server est très bien).

Une fois, donc, la tablette rooté, j’ai pushé buildroid-gapps-ics-20120317-signed.tgz, remonté /system en rw, et extrait le contenus dans /, puis redémarré… (procédure et archive trouvé )

Changement de DPI:

Je trouve la résolution un peu faiblarde, j’ai vu qu’on pouvait changer le DPI pour caser plus de choses dans l’interface, il y a des applications pour ça, mais celle que j’ai crashait par ce que la bonne clée n’était pas dans le fichier de conf, j’ai donc fait les changement à la main.

su
mount -o remount,rw /system
vi /system/build.prop
# ajouter "ro.sf.lcd_density=120" dans le fichier
mount -o remount,ro
reboot

J’aurais bien mis moins, mais ça faisait crasher le launcher (une division par 0, pour ce que m’ont dit les logs… huhu)

Changer le laucher (justement).

Je trouvais le launcher un peu lourdingue, donc j’ai installé trebuchet, celui de CyanogenMod. trouvé .

Le soucis, c’est qu’on ne peut pas installer l’apk normalement, enfin si, mais il ne marche pas bien, certaines permissions ne sont pas accessibles aux applications non «système», il faut donc l’installer dans /system

adb push Trebuchet.apk /sdcard/
adb shell
su mount -o remount,rw /system
cp /sdcard/Trebuchet.apk /system/app/
mount -o remount,ro
reboot

on peut maintenant reprendre la procédure précédente, et passer la DPI à 96, ça marche… il faut juste ensuite aller dans les options et passer le texte en “gros” ou “très gros”, par ce que sinon il n’est pas affiché… je pense que “très gros” est le plus raisonnable, ça reste un peu petit, sérieusement, mais je pense que c’est bien comme ça, on a bien plus de place qu’avant…

Conclusion:

Pour le prix… je suis pas déçus, on peut faire pas mal avec cette tablette, y’a un peu de bricolage pour en tirer le meilleur partis, mais c’est faisable…

Ah, et vu que c’était le but, quand même, les applications kivy marchent très bien dessus… (mais ne profitent pas du changement de dpi, elles comptent en pixels, Mathieu Virbel travaille la dessus, ça devrait arriver dans quelques temps).

Tip me if you like this :)

l'eeepad tranformer, comme plateforme de dev.

written by tshirtman, on 9/13/11 11:09 AM.

Qu’est ce que c’est?

Tout simplement une tablette android, avec un clavier en station d’accueil, ce qui permet de s’en servir aussi bien comme une tablette tactile, que comme un netbook (10″, c’est grand pour ce dont j’ai l’habitude, mais ça reste un netbook). L’écran multitouch 10″, et l’autonomie de 16h (au bas mot, je pense avoir fait bien plus hier) étant des points très forts. Cependant, le système fournis à l’interieur est android, ce qui est assez agréable pour l’utilisation en tactile, mais beaucoup, beaucoup moins pour l’utilisation au clavier, surtout pour un fanatique du raccourcis clavier et de l’interface ligne de commande comme moi.

Adaptations

Rooter et installer un chroot linux

Sous linux, le script fournis ici permet de rooter le système en quelques minutes, j’ai regardé vite fait le code avant, et c’est assez simple et clean, bon outil :) (comme d’hab basé sur le très pratique “adb” fournis par le sdk google). Ensuite, il faut installer les paquets “busybox” et “linux installer” depuis le market, lancer le premier (sinon linux installer n’arrive à rien), et le second quand c’est terminé, j’ai du m’y reprendre à plusieurs fois, mais j’ai finit par avoir un chroot ubuntu tout à fait fonctionnel.
J’ai créé un utilisateur non root afin de pouvoir travailler sereinement, que j’ai ajouté au groupe “admin”. J’ai aussi ajouté la commande “login” dans /etc/init.android/rc_enter.sh, afin qu’il me demande mon nom d’utilisateur et mon mot de passe, au lieu de me connecter en root, dans une boucle.

while true
do
    login
done

Bien sur ce n’est pas une solution parfaite, et sécuriser un tel environnement m’apparait vraiment difficile, sachant que le root de la machine ne demande pas de mot de passe, juste de cliquer un bouton a l’écran. Mais bon, la machine en elle même a un mot de passe graphique assez complexe, et en mode invisible. L’intérêt est plus d’avoir un lancement de session standard.

 

Réseau

De base, notre utilisateur n’a pas accès au réseau, celui ci ne marche que pour root, il s’agit des effets des sécurité d’accès au réseau sous android, il faut donc créer un groupe spécifique dédié à ça, avec le bon gid (correspondant à celui équivalent sous android).

sudo addgroup --gid 3003 inet

et ajouter notre utilisateur au groupe

sudo addgroup $USER inet

Si il est manquant, penser à ajouter “localhost” à la fin des deux premières lignes dans /etc/hosts, et si les requêtes sur un host ne résolvent pas, il peut être une solution de remplacer le nameserver par un autre dns dans /etc/resolv.conf . Personellement j’ai mis ceux de google.

nameserver 8.8.8.8
nameserver 8.8.4.4

La modification peut être faite de façon plus définitive dans le script linuxchroot.sh de l’os hote.

 

Nous avons maintenant un réseau parfaitement fonctionnel! Ce qui va nous permettre d’utiliser apt :D.

Programmes Ubuntu

Le strict minimum pour bosser…

sudo apt-get install git vim byobu

Je conseil de configurer byobu pour se lancer à la connexion: ‘ctrl-q @’ pour voir les options, aller sur la dernière, valider, aller à droite, pour sauter sur exit, et valider.
Il semble que les raccourcis avec ctrl soient en qwerty… je ne sais pas si c’est un bug du terminal ou pas, je regarderais si possible, c’est vivable pour l’instant.

 

Terminal

Peu satisfait du fonctionnement clavier de connectbot, je suis resté un moment sur Android Terminal Emulator, mais une fois installé mes applications, j’ai vite constaté que l’utilisation de vim dans ce context était difficile, du fait du comportement de la touche back (qui est à la place d’échap sur le clavier), qui est de fermer le terminal… même si byobu (c’est gnu screen, mais avec une config sympa en fait), rends la chose moins douloureuse, c’est quand même un peu lourd). Bref, j’ai finit par forker Android Terminal Emulator sur github, pour me faire un patch pour ça (j’ai du commenter un bout de code pour ça compile, et c’est sans doute un peu moche, mais bon, le java et moi…) edit: ce n’est plus nécessaire, android terminal emulator propose maintenant une option pour la gestion de la touche échap :). J’ai aussi salement changé les couleurs disponibles, mais pas de patch pour ça, c’est vraiment trop moche, et c’est franchement pas sorcier, enfin, maintenant j’ai le mauve ubuntu en fond d’écran :P).

sdcard dans le chroot

Afin de pouvoir éditer directement une applie android (écrite en kivy, donc c’est du python, donc je peux :)), j’ai partagé la carte sd interne avec le chroot ubuntu, avec ces commande, depuis le terminal chroot (a faire une seule fois):

sudo mkdir /sdcard
sudo addgroup sdcard_rw --gid 1015
sudo adduser $USER sdcard_rw

et depuis le shell android:

su
mount -o bind /mnt/sdcard /data/local/mnt/Linux/sdcard

 

Ce qu’il reste à faire…

 

  • Faire fonctionner la touche alt, qui serait utile pour certains programmes cli
  • Laisser la keymap en qwerty quand ctrl est appuyé.
  • avoir un meilleur accès au logs (j’ai bien trouvé une app, mais elle se met en mode portrait, même quand le clavier est branché, c’est malin…

 

Tip me if you like this :)

Tags

#FIXME 3G absurd ad_sense alterway aléatoire android animation anonymity atheism bach backlog bash bitcoins blog blogging boldness book books boulot bricolage bépo C canvas captcha captures carte SD censure christianity chroot CLI cli cloudwatt code colors comfort zone command line community company life conferences contest copwatch copwatchnord-idf core-devs cours ct705 culture deb debian debug deformation dehors dessin dev distribute distribution débutant déploiement développement ebooks eeepad eeepc effect ego empty en escher event firefly flappy bird flask fosdem foss fr fun game garden gdb geek culture git github goals graphics grrr gödel hack hackathon hacked hacking hooks i3 images IMAP inspirational install isync java jeu jeu video jinja2 jni keyboard keynav kivy kv lame learning lib libre life linux lol macosx magnet mail mailing-list mails maths mbsync meetings memory leak mesh meta mint mirroir MIT module motivational mouse museomix mutt nexus7 no-mouse notmuch nottoomuch offlineimap onycroit opencourseware osc packaging paris passphrase password patch pentacatyl people perte de données ping pip planning plugin positioning pr procrastination programmation progress project projet property proudhon proxy psf publisher/consumer pull-down pygame pyjnius pypi python pythonar qtile raid rapsberry pi reading recorder references release religion responsive review reviews réseau réseaux sociaux résurection salon screenshots script self service shows shutil shyness sizing solib sortie sousous!!! spam spritz stash status systeme système templating terminal texture texture coordinates Thomas Paine thread thème tiling time time management. tip tips tools transformer tutorial tv twitter typematrix typing ubuntu ubuntu-fr ultimate-smash-friends unity upload images useless usf utils value VDM video vie/mort vim virtualenv visite widget windows wm wmii work workflow workflow. zine études