The Ubuntu App Showdown deadline has passed. So the time has come to start a new project! I teamed up with the same developer as the showdown competition, Lemaire Nick. Let's introduce the project by demonstrating some screenshots of the application in development.
Screenshot phone
Screenshot tablet
During my internship at Philips iLab in Leuven, I had the chance to discover the development possibilities of the VLC-platform created by VideoLan. One of the possibilities is the usage of the web interface via Http protocol. By using the web interface of VLC, a developer can control a VLC-instance on the local area network by invoking simple http requests.
Current features:
Manuel connection wizard
Playback control (play, pause, loop, shuffle etc.)
When participating with a friend on the Ubuntu App Showdown, I realized that there aren't many tutorials and examples around regarding Ubuntu development with Quickly. So I got the idea to share some code I struggled with. I have extracted the necessarily code from my Quickly project to illustrate how clickable dynamic tables are constructed.
Glade
We need to create container to hold our table. For this I have chosen to use a
viewport inside a
scrolledwindow. In this example I'm using glade as an interface designer.
Tree view: user interface element that holds the data store
A Tree view is constructed out of columns. Those columns hold CellRenderers. In this example we use 2 children classes of the CellRenderer class. The first one is the CellRenderText class which is used to display text. The second one is a custom implementation of a
CellRendererPixBuff . A CellRendererPixbuff is used to display an image. We needed to extend from CellRendererPixBuff so we could make the cell that holds an icon clickable (implement the clicked signal).
Snippet Window.py
# IMPORTS USED IN THIS EXAMPLEfrom gi.repository import GdkPixbuffrom CellRendererIcon import CellRendererIconfrom gi.repository import Gtk # MAIN CODE # VIEWPORT CREATED WITH GLADE
self.viewport = self.builder.get_object('viewport')
# CREATE LISTSTORE & TREEVIEW
self.liststore = Gtk.ListStore(str, str)
self.treeview = Gtk.TreeView(self.liststore)
# COLUMNS
column_text = Gtk.TreeViewColumn("Name")
column_text.set_expand(True)
column_icon = Gtk.TreeViewColumn("Delete")
column_icon.set_expand(False)
# ADD COLUMNS
self.treeview.append_column(column_text)
self.treeview.append_column(column_icon)
# CREATE TEXTRENDERER
cellrenderer_text = Gtk.CellRendererText()
column_text.pack_start(cellrenderer_text, False)
column_text.add_attribute(cellrenderer_text, "text", 0)
# CREATE ICONRENDERER
cellrenderer_icon = CellRendererIcon()
column_icon.pack_start(cellrenderer_icon, False)
column_icon.add_attribute(cellrenderer_icon, "stock-id", 1)
# CONNECT SIGNALS FOR CALLBACK CLICK ON CELL
cellrenderer_icon.connect('clicked', self.on_custom_function)
# CONNECT LISTSTORE WITH TREEVIEW
self.treeview.set_model(self.liststore)
# FILL DATASET IN TABLE
for row in dataset:
self.liststore.append([row['name'], Gtk.STOCK_DELETE])
# SHOW & ADD treeview to viewport
self.treeview.show()
self.viewport.add(self.treeview)
Code CellRendererIcon.py
#!/usr/bin/python
# import needed for this project
from gi.repository import Gtk
from gi.repository import GObject
class CellRendererIcon(Gtk.CellRendererPixbuf):
__gsignals__ = { 'clicked' : (GObject.SIGNAL_RUN_LAST,
GObject.TYPE_NONE,
(GObject.TYPE_STRING,)), }
def __init__(self):
Gtk.CellRendererPixbuf.__init__(self)
self.set_property('mode', 1)
self.set_property('follow-state', True)
def do_activate(self, even, widget, path, background_area, cell_area, flags):
self.emit('clicked', path)
In this tutorial I will try to cover the basics steps of implementing an UPnP control point in an Android application. By doing this we can discover/integrate/control UPnP devices in our local area network. This tutorial focuses on discovering one UPnP device, invoking a control event on this device and handeling the callback event coming from the device.
Final result
What is UPnP
For a better understanding of what Universal Plug and Play is you shoud visit the websitesWikipedia and UPnP.org.
Requirements
Eclipse + Android SDK
You should have a eclipse environment installed for Android development
UPnP Developer tools by intel
By using the developer tools delivered by intel, setting up and testing with the UPnP protocol isn't that dificult. To get started download the developer tools from the intel website:
Now that we have had a simple introduction to UPnP-developer tools it's time to start working. First we need to start spying the network for UPnP-traffic. Device spy lists all UPnP enabled devices of your local area network. You can invoke events on these devices by opening an service in the treeview and double clicking an function (e.g. SetTarget).
We are using the Network Light from the developer tools as our endpoint in this setup. Intel's Network Light is a virtual lightbulb that can be enabled, disabled and dimmed.Verify that the network light is listed in the device spy. Play around with the network light from the device spy, for example you can enable/disable the lightbulb by invoking the setTarget(True) and setTarget(False) function. For more information on the Network Light module you can take a look at:
These actions will generate the source code of an Android application which developers can use to make their own Android applications.
Listing generated files
the following java files are generated in the package "be.tvn.dev.upnp.lightswitch" :
- CpDimming.java
Resembles the service : um:schemas-upnp-org:service:Dimming:1
- CpSwitchPower.java
Resembles the service : um:schemas-upnp-org:service:SwitchPower:1
- LightSwitch.java
MainActivity of our Android project
Import the generated code into Eclipse
File > Import > General tab > Existing Projects into Workspace
Select upnp as your root directory
Verify that LightSwitch-project is checked
Click Finish
Resolve Eclipse errors
Move the UPnP library to the libs folder
Right click project > New > Folder > Folder name : libs
Copy and paste UPnPLibrary.jar from the root folfer to the libs folder
Verify that UPnPLibrary.jar is referenced
Remove @Override annotations
Ctrl + F and Replace All
Fix project properties
Right click project > Android Tools > Fix Project Properties
Clean project
Project > Clean...
Run your application
If all errors are removed from the package explorer it's time to start running the application. Before continuing we should enable WiFi on our Android phone and enable debug information on the Network Light.
Network Light > right click > Debug information
enable debug information by clicking the green/orange/red icons
Eclipse > right click project > Run as > Android Application
When the application is installed you should see 2 buttons on the screen. One for starting the NetworkLight server and one for stopping the NetworkLight server. If you press the start button you should see the following debug information appear in the debug dialog.
Adding functionality to the Android application
Now that we can integrate with the Network Light is time to start adding buttons to toggle the bulb on & off. To accomplish this we only need to edit 2 files:
Reference button and add onClickListener to the button in onCreate-function
/** Called when the activity is first created. */
public void onCreate(Bundle savedInstanceState)
{
// ONCREATE AND CONTENTVIEW
// START AND STOP BUTTONS
...
// FIND REFERENCE TO BUTTON
toggleButton = (Button)findViewById(R.id.lightswitch);
// DISABLE BUTTON UNTIL INITIATED BY SERVICE
toggleButton.setEnabled(false);
// DEFINE ONCLICK EVENT
toggleButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
if((Boolean)v.getTag()){
// lightbulb is on -> switch off
mCpSwitchPower.action_SetTarget.Invoke(false, mCpSwitchPowerObject, mCpSwitchPowerInvokeHandler);
}else{
// lightbulb is off -> switch on
mCpSwitchPower.action_SetTarget.Invoke(true, mCpSwitchPowerObject, mCpSwitchPowerInvokeHandler);
}
// DISABLE BUTTON UNTIL CALLBACK
v.setEnabled(false);
}
});
}
Change implementation of OnAddedDevice(UPnPDevice device)-function
public void OnAddedDevice(UPnPDevice device)
{
//STORE REFERENCE OF INVOKE HANDLER
mCpSwitchPowerInvokeHandler = mHandler_SwitchPower;
// INITIATE SERVICE
UPnPService service;
service = device.GetService(CpSwitchPower.ServiceType).get(0);
service.userObject = new CpSwitchPower(service);
((CpSwitchPower)service.userObject).LoadSCPD(null, new CpSwitchPower.LoadedSCPDHandler()
{
/** Called when service is initated */
public void OnCpSwitchPower_LoadedSCPD(CpSwitchPower sender,boolean success, Object userObject) {
// STORE REFERENCE TO UPNP OBJECTS
mCpSwitchPower = sender;
mCpSwitchPowerObject = userObject;
// GET INITIAL STATE OF LIGHTBULB
mCpSwitchPower.action_GetTarget.Invoke(mCpSwitchPowerObject, mCpSwitchPowerInvokeHandler);
}
});
}
Change implementation of mHandler_SwitchPower
CpSwitchPower.InvokeHandler mHandler_SwitchPower = new CpSwitchPower.InvokeHandler()
{
public void OnGetStatus(int errorCode, boolean ResultStatus, Object userState)
{
}
public void OnGetTarget(int errorCode, boolean newTargetValue, Object userState)
{
final boolean value = newTargetValue;
runOnUiThread(new Runnable() {
public void run() {
// store state of lightbulb
toggleButton.setTag(value);
// enable button
toggleButton.setEnabled(true);
}
});
}
public void OnSetTarget(int errorCode, Object userState)
{
runOnUiThread(new Runnable() {
public void run() {
// switch state of lightbulb
Boolean isOn = ((Boolean)toggleButton.getTag() == true) ? false : true;
// store state of lightbulb
toggleButton.setTag(isOn);
// enable button
toggleButton.setEnabled(true);
}
});
}
};