Praktikum: Spezifikation

Transcrição

Praktikum: Spezifikation
1
Seminar zum Programmierprojekt SS 2008
Uni Tübingen, Arbeitsbereich Technische Informatik
Ausgabe: 20. Mai 2008
Anleitung B5
Einführung in die MIDlet-Programmierung mit Java2ME
Allgemeines
Mit Aufgabe 5 beginnen Sie die Implementierungsphase des Praktikums. Auf den Praktikumsrechnern 2 und 3 ist Java2ME (Wireless Toolkit) und eclipse installiert. Ziel diese Aufgabe ist es, ein MIDlet zu Programmieren, welches auf Benutzereingaben reagieren kann, eine Inquiry durchführt, die Dienstabfrage an gefundene Geräte schickt und die daraufhin erhaltenen Dienste dem Nutzer präsentiert. Das Nutzen der Dienste sowohl der Host als auch
der BTnodes soll in den Aufgaben B6 und B7 implementiert werden.
Java2ME Einführung
J2ME ist eine Umsetzung der Programmiersprache Java für "embedded consumer products"
wie etwa Mobiltelefone oder PDAs. JSR 30 und JSR 37 (Java Specification Request) definieren J2ME.
Die Java Micro Edition kann in verschiedenen Konfigurationen eingesetzt werden. Eine
Konfiguration ist eine Menge von Java APIs, Klassenbibliotheken und einer virtuellen Maschine, die auf eine bestimmte Gerätefamilie mit ähnlichen Anforderungen konzipiert ist, d.h.
eine Konfiguration stellt eine Spezifikation für eine Familie von Endgeräten dar. Die Entwicklung von Konfigurationen für J2ME wird hauptsächlich durch die Firma Sun und deren
Entwicklungspartnern vorangetrieben. Derzeit existieren zwei Standardkonfigurationen, nämlich Connected Device Configuration (CDC) und Connected Limited Device Configuration
(CLDC).
Die CDC (Connected Device Configuration, JSR 218) ist eine J2ME Konfiguration, die für
Geräte bestimmt ist, die eine komplette Implementierung der JVM und eine Menge von APIs
benötigen, die durch das Hinzufügen von Profilen die gesamte Java SE Plattform API einschließen können. Typische Implementierungen benutzen nur einen Teil der SE APIs, indem
nur eine bestimmte Anzahl an Profilen eingebunden wird. Die ganze Spezifikation wird in
JSR 218 beschrieben.
Die CLDC (Connected Limited Device Configuration, JSR 30 und JSR 139) definiert die
kleinstmögliche Konfiguration einer J2ME-Laufzeitumgebung. Zu den größten Einschränkungen in Version 1.0 zählt der Verzicht auf Fließkommaberechnungen. Das betrifft sowohl
Variablen, die als float, double, als auch als java.lang.Float und java.lang.Double deklariert
sind. Weiterentwicklungen der CLDC in Version 1.1 führten u. a. zu einer Wiedereinführung
der Fließkommaunterstützung. Insbesondere Spielentwickler sind gelegentlich auf Fließkommaberechnungen angewiesen - wenngleich aus Performance-Erwägungen in vielen Fällen doch eher Festkommazahlen bevorzugt werden.
2
CLDC wird hauptsächlich in Mobilen Geräten in Verbindung mit dem "Mobile Information
Device Profile" (MIDP) benutzt.
MIDP (Mobile Information Device Profile) ist ein Profil der Java 2, Micro Edition (J2ME),
das speziell auf die Fähigkeiten kleiner mobiler Endgeräte wie Mobiltelefon oder Pager ausgelegt ist. Profile sind die APIs, die es für eine Konfiguration gibt. Sie stellen eine weitere
Art der Anpassungsmöglichkeit der Java2 API an Anforderungen für Gerätefamilien dar.
Applikationen auf Basis von MIDP nennt man kurz MIDlets (z.B. Java-Spiele für Handys).
Das MIDP umfasst Funktionen zur Ansteuerung und Abfrage von Einhandtastaturen, Miniaturbildschirmen, flüchtigen und nicht-flüchtigen Speichern im Kilobyte-Bereich etc. Es existieren bisher das MIDP 1.0 (JSR 37) und das MIDP 2.0 (JSR 118), das einige Erweiterungen aufweist. MIDP 3.0 ist bereits als JSR 271 in Bearbeitung.
Konfigurationen bieten eine breite Variabilität für verschiedene Einsatzzwecke, sind jedoch
oft nicht ausreichend, um die komplette Funktionalität verschiedener Geräte verwenden zu
können. Daher gibt es Erweiterungen, die interne Gerätefunktionen unterstützen, wie z.B.
Bluetoothfunktionalität (siehe JSR 82), die für unsere Zwecke benutzt werden wird. Abbildung 1 zeigt die in JSR 82 spezifizierte CLDC/MIDP-Architektur.
Die Entwicklung von Konfigurationen, Profilen und Erweiterungen wird im Rahmen des "Java Community Process" (JCP) durchgeführt, an denen auch namhafte Firmen wie Nokia,
Siemens oder IBM beteiligt sind.
Abbildung 1: CLDC/MIDP-Architektur, spezifiziert in JSR082
Im Praktikum verwenden wir das Mobiltelefon Nokia 6680, das MIDP 2.0 unterstützt. Eine
Übersicht über das Nokia 6680 finden Sie hier:
http://www.nokia.de/de/mobiltelefone/modelluebersicht/6680/startseite/150206.html
Folgende Konfigurationen und Erweiterungen werden vom Nokia 6680 unterstützt:
o Connection Limited Device Configuration 1.0 (CLDC 1.0)
o Connection Limited Device Configuration 1.1 (CLDC 1.1)
3
o Mobile Information Device Profile MIDP 1.0 und MIDP 2.0
o Java Technology for the Wireless Industry (JTWI), JSR 185
o Mobile Media API V1.0 (MMAPI) JSR 135
o Wireless Messaging API V1.0 (WMAPI) JSR 120
o Bluetooth API (BTAPI) JSR 82
Als Benutzeroberfläche bieten MIDP-APIs eine Menge von User-Interface-Elementen (UI).
Diese ermöglichen Interaktionen zwischen Benutzer und MIDlet und befinden sich im Paket
javax.microedition.lcdui.
Abbildung 2: High level und Low level MIDP API
Die High-Level-API (vgl. Abb.2)stellt Ein- und Ausgabefelder, wie z. B. Textfelder (TextField) oder Fortschrittsanzeigen (Gauge), zur Verfügung. Sie sind der Elternklasse Item untergeordnet. Objekte von "Item" können auf einem Formular platziert werden, sind jedoch
nur eingeschränkt positionierbar. Formulare sind Objekte der Klasse "Form". Sie können an
das aktuelle Display angehängt werden und verschiedene UI-Elemente beinhalten. Das MIDlet kann Wechsel zwischen Formularen anfordern sowie während der Laufzeit UI-Elemente
hinzufügen und auf Benutzereingaben reagieren.
Die wichtigsten UI-Elemente sind(vgl. Abb. 2):
•
Form: Container für andere UI-Elemente
•
Item: Repräsentiert einen Menüeintrag. Mehrere Items können in einem Menü zusammengefasst und an ein Formular angehängt werden
•
Alert: Popup-Nachrichten die den Benutzer über Fehler, Exceptions, Warnungen oder
über sonstige Informationen benachrichtigen
4
•
ChoiceGroup: Implementiert eine Selektionsmöglichkeit zwischen mehreren Einträgen. Die Auswahl ausschließlich einzelner (engl. "single choice") oder auch mehrerer
Einträge (engl. "multiple choice") ist möglich
•
TextBox: Einzeilige Eingabefelder, in denen der Benutzer Text einfügen bzw. editieren kann
•
TextField: Ähnlich einer TextBox, allerdings mehrzeilig
•
Gauge: Fortschrittsanzeige
•
Ticker: Anzeige von bewegtem Text
Im Gegensatz hierzu arbeitet die Low-Level-API auf Pixelebene. Die Klasse "Canvas" ist
der Eingangspunkt für graphische Zeichnungen. Sie selbst beinhaltet hierfür keine Methoden,
jedoch stellt sie die Callback-Funktion paint() bereit. Sie wird immer dann aufgerufen, wenn
der Programmmanager entscheidet, das Display neu zu zeichnen. Ihr einziger Parameter ist
ein Objekt Graphics, welches sämtliche Zeichnungsfunktionen, wie beispielsweise drawLine() zum Zeichnen einer Linie oder fillRect() zum Ausfüllen eines Rechtecks, beinhaltet.
Grundsätzlich kann man zwischen reinen Hintergrundapplikationen und jenen unterscheiden,
die mit dem Benutzer interagieren. Interaktive Applikationen können auf das Display über
ein Objekt Display zugreifen. Man erhält es als Rückgabeobjekt der statischen Methode getDisplay() mit dem MIDlet als Argument. Die Methode setCurrent() bestimmt, welches Objekt Displayable den Inhalt eines Displays darstellen soll. Displayable ist die Elternklasse von
Screen und Canvas. Ihr sind alle UI-Klassen unterstellt. Mit anderen Worten, sie definiert
sämtliche Objekte die am Display angezeigt werden können.
5
MIDLET Programmierung auf dem Mobiltelefon
In Aufgabe B4 haben Sie bereits gesehen, welche Funktionalität ein MIDlet bietet. Die Bluetooth Demo aus dem Wireless Toolkit sollte Ihnen dabei zeigen welche einzelnen Schritte für
eine Bluetooth Kommunikation nötig sind.
Nun ist es Ihre Aufgabe ein eigenes MIDlet zu entwerfen, welches den im Pflichtenheft definierten Anforderungen entspricht. Dabei soll in dieser Aufgabe das Augenmerk auf dem Starten des MIDlets, dem Suchen nach Bluetooth-Geräten in der Umgebung und der Dienstanfrage liegen. Dazu gibt es eine gute Einführung in einer Masters-Thesis von André N. Klingsheim, siehe [6]. Darin wird der Aufbau eines MIDlets Schritt für Schritt erklärt und mit beigefügtem Source-Code erläutert. Allerdings benutzt Klingsheim die „Service-Discovery“Methode, die in unserer Umgebung mit dem Nokia 6680-Telefon nicht funktioniert. (Wir
verwenden dafür das Serial Port Profile SPP).
Implementieren Sie das dort vorgestellte MIDlet und fügen Sie folgende Funktionalität hinzu:
o In der Funktion startApp() soll dem Benutzer ein Willkommensbildschirm präsentiert
werden, welcher die Möglichkeit bietet mit der DeviceSearch zu beginnen, oder das
Programm zu beenden
o In der Funktion commandAction(Command c, Displayable s) werden die Benutzereingaben verarbeitet. So soll z.B. bei Command „OK“ auf Menüeintrag „Start DeviceSearch“, welchen Sie aus dem Objekt Displayable s herauslesen können, die Inquiry gestartet werden, bzw. wie im Beispiel eine Funktion doDeviceDiscovery() ausgeführt werden.
o In der Funktion inquiryCompleted(int param) soll dem Benutzer die Liste der gefundenen Geräte präsentiert werden. Dabei müssen Sie darauf achten, dass die Liste der
Geräte auf dem Display auswählbar ist, sodass es möglich ist, ein Gerät zu selektieren
und die Service-Suche zu starten.
o Da die Service-Suche über das DiscoveryListener Interface aufgrund von Kompatibiltätsproblemen nicht einwandfrei funktioniert, können Sie die Funktionen
o public void servicesDiscovered(int transID, ServiceRecord[] serviceRecord){}
und
o public void serviceSearchCompleted(int transID, int respCode){}
leer lassen, müssen sie jedoch aufgrund des Interfaces so übernehmen.
o In der Funktion doDeviceDisocovery() soll dem Nutzer an allen Stellen an denen
// Error handling Code here
steht eine Fehlermeldung ausgegeben werden, aus welcher ersichtlich ist, an welcher
Stelle das Programm einen Fehler ausgeworfen hat.
o Zur Dienstsuche müssen Sie in der Funktion commandAction(Command c, Displayable s) bei Command „OK“ und einem ausgewählten Gerät den in der Spezifikation
definierten String an das betreffende Gerät senden.
Dienstsuche
Zur Dienstsuche können Sie folgendes Verfahren benutzen:
Zunächst benötigen Sie die Bluetooth-Adresse des betreffenden Geräts. Diese erhalten Sie
aus dem Objekt RemoteDevice in der Funktion deviceDiscovered().
Sie benötigen dann eine Verbindung zu diesem RemoteDevice:
6
StreamConnection streamConn = (StreamConnection) Connector.open(url);
Die Connector-Klasse aus javax.microedition.io.Connector öffnet eine Verbindung und gibt
ein Connection-Objekt zurück, welches in die entsprechende Verbindungsart gecastet werden
kann (hier also StreamConnection). Der url-Parameterstring muss dem URL-Format aus RFC
2396 entsprechen. Er hat die allgemeine Form wie folgt:
{scheme}:[{target}][{params}]
•
{Scheme}: Name des Protkolls, z.B. btspp oder http
•
{target}: Eine Netzwerkadresse, "bluetooth_address_of_remoteDevice:1
•
[{params}]: Weitere Parameter der Form ";x=Y", z.B. ";app-name=MobilerKnoten"
Wird das ServiceDiscoveryProtocol verwendet, dann wird hinter der {target}-Netzwerkadresse die PSM (Protocol Service Muliplexer, wichtigster Parameter der L2CAPVerbindung, siehe [14]) angegeben, um einen speziellen Dienst im Server anzusprechen.
PSM 1 (genauer 0x0001) enspricht z.B. dem ServiceDiscoveryProtocol. Da wir in unserer
Umgebung das ServiceDiscoveryProtocol nicht verwenden (können), benötigen wir auch den
PSM nicht.
Wir verwenden, abhängig vom anzusprechenden Gerät, btl2cap und btspp als {Scheme}.Die
Connectorstrings sehen dann folgendermaßen aus:
BTNode:
„btl2cap://" + [MAC-Adresse des BTN] +":0xE001”
…und für den Host:
"btspp://" + [MAC-Adresse des Hosts] + ":1;encrypt=false;authenticate=false"
Der Verbindungsaufbau zur BTNode
L2CAPConnection l2cap;
l2cap = (L2CAPConnection) Connector.open(String BTN-ConnectorString (siehe
oben));
DataInputStream in = con.openDataInputStream();
DataOutputStream out = con.openDataOutputStream();
Um eine Nachricht zu verschicken sieht die Sache jedoch etwas anders aus:
byte[] meineNachricht;
l2cap.send(meineNachricht);
und um eine Nachricht zu empfangen:
byte[] antwort;
7
l2cap.receive(msg);
Verbindungsaufbau zum Host:
Ausgehenden Stream:
DataOutputStream outStream = streamConn.openDataOutputStream();
Senden Sie nun über diese Verbindung den in der Spezifikation festgelegten String. Benutzen
Sie für Input und Output über Bluetooth die Funktionen writeUTF(String s) und readUTF()
String request = "ihrString";
outStream.writeUTF(request);
Da es sich bei der geöffneten Verbindung um eine Verbindung mit Puffer handelt, müssen
Sie diesen leeren und somit die Nachricht senden:
outStream.flush();
Schließen Sie danach den OutputSream, nicht jedoch ihre Stream Connection:
outStream.close();
Danach müssen Sie nur noch auf die Antwort der Gegenstelle warten:
Dazu öffnen Sie einen Inputstream und warten auf eine Eingehende Verbindung:
DataInputStream inDir = null;
inStream = streamConn.openDataInputStream();
String answer=null;
answer = inStream.readUTF();
Schließen Sie den InputStream und die StreamConnection
inStream.close();
streamConn.close();
Parsen Sie nun den erhaltenen answer String und präsentieren dem Benutzer die angebotenen
Dienste.
8
Literatur und URLs
[1] http://www.nokia.de/de/mobiltelefone/modelluebersicht/6680/startseite/150206.html
[2] http://jcp.org/en/jsr/all
[3] http://www.m-software.de/handy-galerie/Nokia/6680.php
[4] http://java.sun.com/products/midp/
[5] http://java.sun.com/products/cldc/
[6] http://wireless.klings.org/klings_jabwt_master_thesis.pdf
[7] http://de.wikipedia.org/wiki/MIDP
[8] http://developers.sun.com/techtopics/mobility/midp/articles/bluetooth2/
[9] http://java.sun.com/products/sjwtoolkit
[10] http://www.mobileinfo.com/
[11] http://java.sun.com/javame/reference/apis/jsr082/
[12] http://java.sun.com/javame/reference/apis/jsr139/
[13] http://java.sun.com/javame/reference/apis/jsr118/
[14] Sauter, Martin: Grundkurs Mobile Kommunikationssysteme, Kapitel 5.