Controlling Sozi remotely from an Android phone

Posted in:

I'm due to give a talk next Sunday evening, and I've created a presentation using the very cool Sozi. Sozi is quite like Prezi, but open source and free, and its output is a standard SVG file (with a bit of Javascript), so it can be displayed in several web browsers.

(On the other hand, for many people Sozi is probably a lot harder to use for simple presentations than Prezi, as it works as a plugin to Inkscape, a general purpose drawing program, but, to me, it is simply unacceptable to depend on the continued existence of a company, and a subscription fee, to be able to continue to view/edit your presentations).

One problem with not using ‘standard’ software like Powerpoint is that proprietary tools like hand-held remote controls for Powerpoint won't work, or won't work easily (and I don't want to find out that it won't work when I turn up) [EDIT: it looks like Sozi now has good compatibility with many wireless presenter tools, but I don't have one anyway]. But I've found a solution that works for me:

  1. On my Android phone, I installed Coversal, which is an app designed for controlling media players, but allows custom commands to be executed, so actually works fine for presentations.

  2. Within Coversal, I installed the ‘SSH Custom’ plugin.

  3. On my Linux laptop, I installed openssh-server to allow the app to log in to my machine. To avoid putting my laptop password on the phone, I created an SSH keypair for this app, transferred to private key to the phone, and added the public key to ~/.ssh/authorized_keys.

  4. I created a script on my laptop that can control Sozi running in Chrome:

    #!/usr/bin/env python
    # controlsozi
    import os
    import subprocess
    import sys
    import logging
    from datetime import datetime
    logging.basicConfig(level=logging.DEBUG, filename='/tmp/controlsozi.log', filemode="a")
    def get_window():
        # Assumes that there is just a single Google Chrome window open, and this
        # has the presentation in it.
        windows = subprocess.check_output("DISPLAY=:0 wmctrl -l -x | egrep 'google-chrome|gnome-www-browser'", shell=True)
        return windows.strip().split()[0]
    def send_text(text):
        os.system("DISPLAY=:0 xvkbd -window %s -text '%s'" % (get_window(), text))
    ACTIONS = {
        'previous':      "\[Left]",
        'next':          "\[Right]",
        'fullscreen':    "\[F11]",
        'previous_fast': "\[Up]",
        'next_fast':     "\[Down]",
        'start':         "\[Home]",
        'end':           "\[End]",
        'launch':        None,
    def log_uncaught_exceptions(*exc_info):
        logging.critical('Unhandled exception:', exc_info=exc_info)
    sys.excepthook = log_uncaught_exceptions
    if __name__ == '__main__':
        if len(sys.argv) < 2:
            print "Usage: "
            for k in ACTIONS.keys():
                print "  " + k
            action = sys.argv[1]
            logging.debug("Action = %s" % action)
            if action == "launch":
                os.system("DISPLAY=:0 nohup google-chrome '%s' &" % sys.argv[2])
                text = ACTIONS[action]
                logging.debug("Text = %s" % text)

    This relies on command-line tools wmctrl and xvkbd. With only small modifications it should work for Firefox too. It is not 100% reliable, as it works by sending keypresses to windows, but it works fine for me.

  5. I set up a profile in Coversal to connect to my laptop and use this script.

    Coversal allows you to define the commands for certain actions – the list of actions includes things like up, right, next etc., but you can add your own. You then assign actions to buttons, as desired.

    So I simply I had to set commands like "/path/to/controlsozi next", and then assign these actions to the buttons I wanted to use.

    By setting the start_playback command to "/path/to/controlsozi launch '%s'", I could even use the file browser built in to Coversal to select the presentation file to view, which is pretty neat.

    The one thing I was really missing was physical buttons – with a touch screen, it's so easy to hit the wrong place, and I wanted something to rest my finger or thumb on.

    I then realised that my phone does have a couple of physical buttons - the volume control buttons on the side. By enabling the 'volume_up' and 'volume_down' buttons in Coversal and mapping them to the 'next' and 'previous' commands, the physical volume buttons get mapped to the same actions, and they do the job just fine. I can use the rest of the controls on the screen for the less common tasks.

    Screen shot of Coversal

For my phone to be able to connect to my laptop over SSH, there is one more piece of configuration that must be done – the IP address of the laptop has to be entered. If you have a local wifi, this is no problem – just connect the two devices to the same wifi and they will be able to talk. My phone has a more reliable option, though – it can itself operate as a wifi hotspot, creating a wifi network that the laptop can connect to.


  1. Linux is awesome.

  2. Smart phones are awesome.

  3. Free Android apps are awesome (and I think it is the Linux culture which encourages this).

  4. Python is awesome.

  5. Being a programmer and being able to plug all this stuff together is awesome.

Comments §

Comments should load when you scroll to here...