-
Notifications
You must be signed in to change notification settings - Fork 0
Plugin system
AweRem is a plugin-based remote controller for your computer. Remotes can easily be added or removed. If you want to provide a new remote for an application, you can easily create a plugin for that.
Plugins are written in HTML5/CSS/Javascript (With additional tools such as jQuery Mobile, 960 grid and nativeDroid) for the UI and in Python 2 for the server-side application.
Plugin data is stored in folder with the name of the plugin. So as to be activated, the plugin should be in the modules
folder of awerem-computer.
plugin_name
├ __init__.py
├ plugin_name.arm
├ plugin_name.py
├ ui.html
╰ your_own_files
This hierarchy is subject to change, because all the plugin info and code is accessible from anyone. It's likely that every UI related files will be moved in a ui folder.
-
__init__.py
is used by Yapsy to know if there is Python code (and perhaps a plugin) in this folder, without it, your plugin wouldn't be loaded -
plugin_name.arm
is a file with a INI format that contains information about your plugin -
plugin_name.py
is the plugin which would be loaded by Yapsy. It must contains aAweremPlugin
class. -
ui.html
is the file that will be displayed in the AweRem phone application. It contains the UI of your plugin.
Here is a standard .arm file:
[Core]
Name = plugin_name
Module = name_of_py_file
[Documentation]
Author = Your Name
Version = 0.1
Description = This plugin is awesome
The UI displayed in the Android application is written with HTML5, CSS and Javascript. The Android application will look for the ui.html file inside your plugin folder. This file will be parsed with some additional information such as the location of jQuery Mobile files and the Awerem Javascript API. The template could be found at awerem/ressources/ui.tpl.html
Here is the boilerplate of a ui.html file:
<!DOCTYPE html>
<html>
<head>
<!-- The Theme you choose for your remote, between dark and light -->
<link rel="stylesheet" type="text/css" href="/resources/css/jquerymobile.nativedroid.light.css" id="jQMnDTheme"/>
<!-- The color you choose for your remote, between red, blue, purple, orange and yellow -->
<link rel="stylesheet" type="text/css" href="/resources/css/jquerymobile.nativedroid.color.red.css" id="jQMnDColor"/>
</head>
<body>
<div data-role="page" data-theme="b">
<div data-role="content">
<!-- Your content -->
</div>
</div>
<script type="text/javascript">
<!-- Your script -->
</script>
</body>
</html>
So as to communicate with the server, you may use the awerem
object and its sendAction
and sendActionAsync
methods.
awerem.sendAction
is a blocking method and will return its value directly. Since it's a blocking method, you shouldn't want to use it and prefer awerem.sendActionAsync
instead. It takes as arguments the name of the function you want to call, and its arguments. These arguments can only be a string, a boolean, an integer or a float.
For instance:
var tabindex = awerem.sendAction("switchTab", //The name of the function to call remotely
-1, "foo", 0.45); //The arguments of the function
awerem.sendActionAsync
is like awerem.sendAction
but the function will be called asynchronously. It takes the same arguments as awerem.sendAction
, except that if the last argument of the function call is a javascript function, then it will be used as a callback when the remote method would return its result.
Examples:
awerem.sendActionAsync("moveMouse", //The remote method name
-45, -75); //The arguments of the function
//Since the last argument is not a JS function,
// the result of this method would be dismissed
var curVolume = 0;
awerem.sendActionAsync("getData", //The remote method name
"volume", "left", //The arguments of the function
function(volume) {curVolume = volume}); //Since the last argument is a JS function,
//When getVolume returns, the callback
//will be triggered with the result
//of "getVolume" as argument
Your server-side application must contains a AweremPlugin
class in your module_name.py
. This class must override some methods.
Here is the boilerplate code for your module_name.py file:
#!/bin/python
from modules.aweremplugin import AweRemPlugin, AweRemHandler
class MyPluginHandler(AweRemHandler):
def __init__(self, myplugin):
self.myplugin = myplugin
def out_myfunc(self):
"""
Print "Triggered"
"""
print("Triggered")
return True # You must not return None
class MyPlugin(AweRemPlugin):
"""
MyPlugin is awesome
"""
def __init__(self):
self.handler = None
self.handler = None
def activate(self):
self.handler = MyPluginHandler(self)
self.info = {"title": "My Plugin", "category": "contextual",
"priority": 0}
def getHandler(self):
return self.handler
def getInfo(self):
return self.info
So as to understand this code, let's first focus on the AweremPlugin subclass, then we will focus on the AweRemHandler one.
First, the AweRemPlugin subclass must override the activate
, getInfo
and getHandler
methods (The two last methods name are subject to change so as to respect PEP-8).
The activate method is called by Yapsy once the instance of your plugin is activated. Your plugin could be loaded but might not be activated. Thus, if you must do any memory or CPU intensive action, di ut in the activate
method, and not in the __init__
one (Generally speaking, you should avoid any foreground cpu or memory intensive action).
The getInfo
method must return a dict
containing various informations:
- title: The title displayed to the user
- category: "contextual" (music player, browser, ...) or "utils" (mouse, gamepad, keyboard)
- priority:
- 0 - The app the module controls has the focus
- 1 - The app the module controls is launched
- 2 - The app the module controls is system-wide
- -1 - The app the module controls is not launched (won't be displayed)
The title or the priority of your app is subject to change. For instance, the title of the linux remote might change depending of the distribution the user is running, or the priority of the firefox remote might change depending of the application is running or not. So as to get the update of your info taken into account in the navigation drawer in your Android AweRem application, you must call self.pollmanager.updateNavigationDrawer()
in your code.
For instance, if you want to update the priority of your remote depending if the app it tracks is running or not, do:
from modules.aweremplugin import AweremPlugin
class MyPlugin(AweremPlugin):
...
def state_change(self, running):
if running:
self.info["priority"] = 1
else:
self.info["priority"] = -1
self.pollmanager.updateNavigationDrawer()
def getInfo(self):
return self.info
...
The getHandler
must return an AweremHandler instance. For more information about AweremHandler, go to the AweremHandler section.
You may want to override the getIcon(dpi)
method. This method is called to get the path of your icon depending of the dpi of the phone. By default, getIcon
will seek for 'res/icons/icon_'+dpi'+'.png'
. Yet, you may want your icon to be personalized. For instance, the linux remote's icon can follow the distribution's icon of the host.
Depending of the remote you are coding, you might want to track the lifecycle of your application. So as to do so, you can import ProcessesManagerSingleton from processesmanager. An example is worth a thousand words:
from modules.aweremplugin import AweRemPlugin
from processesmanager import ProcessesManagerSingleton
...
class MyPlugin(AweRemPlugin):
"""
My plugin
"""
def activate(self):
self.info = {"title": "MyRegex remote", "category": "contextual",
"priority": -1}
ProcessesManagerSingleton.get().addCallback(r".*myregex.*", self.callback)
def callback(self, running):
if running:
self.info["priority"] = 1
self.prepare_communication_stuff()
else:
self.info["priority"] = -1
self.free_communication_stuff()
self.pollmanager.updateNavigationDrawer()
...
You have the warranty that:
- If your application was running before your callback is added, the callback will be called as soon as possible
- Your callback will be triggered only if the state of the application changed, thus you can perform some slow computation without too much remorse.
The list of app currently running is only updated every few seconds. If you want to get the name of your app for the system, you can try to find it on linux with the top
or ps -ef
commands in a shell.