MIDletek

Paller Gábor

1. Motiváció és bevezetés

A mobiltelefonok már régóta vonzzák az alkalmazásprogramozókat. A mobiltelefonnak számos tulajdonsága van, ami rendkívül izgalmas, új alkalmazásoknak nyithat utat. Például a mobiltelefon általában a felhasználónál van (triviális, de eléggé ritka tulajdonság), a SIM kártyán keresztül a tulajdonos nagy biztonsággal azonosítható és ez a tulajdonos számlázható is (ugyancsak nagyon ritka tulajdonság), az eszköz közel állandó kapcsolatban áll a hálózattal és azzal sokféle módon tud kommunikálni (hang, jelcsatornák, különböző minőségű adatátviteli csatornák). Ehhez járulnak különböző bővített képességek, pl. az eszköz pozíciója bemérhető (az eszköz vagy a hálózat által), az eszköz rövidtávú kapcsolatot képes létrehozni környezetében levő nem mobil eszközökkel (infravörös vagy Bluetooth kapcsolat, esetleg WLAN) és esetleg még beépített kamerával is rendelkezik. A mobiltelefonok operációs rendszere és hardvere nagyon gyártófüggő, mindeddig domináns szabvány nem alakult ki. Csak a Nokia pl. három nagyobb platformot használ a mobiltelefonjaiban és ezek közül kettő nem készült fel alkalmazói programok futtatására. A hardver és operációs rendszer különbözőségeinek áthidalására a Jáva ideálisan alkalmas, így kézenfekvő ötlet a mobiltelefonokon a Jávát tenni a közös alkalmazásplatformmá.

A mobiltelefonos Jáva nagyon régi ötlet, már a nyelv megszületésekor felmerült. Az ötlet megvalósítása azonban nem volt egyszerű. Mindenekelőtt a  mobiltelefonok nagyon sokféle platformot használnak úgy szoftverben, mind hardverben. Általában az a helyzet, hogy a készülékgyártó fejleszt egy valósidejű operációs rendszermagot, aminek képességei komponensek szeparálására és azok kommunikációjára, valamint végrehajtási szálak kezelésére szorítkoznak. Nagyon különözően használják magát a processzort, amin a Jávát futtathatnánk (a telefonokban tipikusan legalább két processzor van, egy DSP felel a hívással kapcsolatos jelfeldolgozási feladatokért, egy "szokásos" (általában ARM architektúrájú) processzor pedig a felhasználói felületért felel). Némely telefonokban a "fő" processzor aktívan részt vesz a híváskezelési feladatokban, más telefonokon csak a hívással kapcsolatos felhasználói felületkezelés a dolga. A Jáva virtuális gép integrálása a különböző telefonos környezetekbe és a JVM viselkedése telefonhívás alatt tehát nem egyszerű problémák.

Másik kézenfekvő akadály a memória: egy tipikus mobiltelefon kb. 8-16 Megabájt ROM memóriát tartalmaz, ami önmagában sem sok egy J2SE JVM kb. 10 megabájtos méretéhez képest. Nagyobb probléma azonban a RAM, különösen a nem felejtő (tipikusan flash) változata, ami garantálja, hogy a telefon nem felejti el pl. a telefonkönyvet, ha az elem kimerül. Ez drága memória és nincs is belőle sok, tehát ezzel különösen óvatosan kell bánni. A "normális", kikapcsolás esetén felejtő RAM-ból sincs sok, nem feltételezhetünk megabájtokat csak azért, hogy a JVM elinduljon (mint ahogy a J2SE-nek ez szokása). A JVM-et tehát "méretre kellett vágni", hogy beférjen a telefonokba.

Ha a JVM megvan, következő kérdés, hogy mit futtatunk rajta. A Jáva alkalmazásmodelljei közül a Jáva alkalmazás és a Jáva applet jöhet számításba, de valójában egyik se megfelelő. Jáva alkalmazás feltételez egy operációs rendszert, aminek tetején ő futhat, a mobiltelefonokban ilyen nincs. A Jáva applet modellje állandóan élő szerverkapcsolatot feltételez (hiszen a böngésző kedve szerint tölti be és ki az appleteket) ami a mobiltelefónia világában igen problémás, hiszen a felhasználó a drága és lassú kapcsolat miatt maga szeretné ellenőrzése alatt tartani, mikor és mennyit tölt le.

A fenti megfontolások vezettek a mobiltelefonos Jáva két rétegének megalkotásához.

2. A Connected, Limited Device Configuration (CLDC)

A CLDC specifikáció egy szűkített Jáva környezetet ír le. A specifikáció az alkalmazásmodellel nem foglalkozik,  csak a virtuális gép képességeit és a támogatott alap Jáva osztályokat írja le.

A CLDC-t futtató környezet hardverigényeit a következőképpen definiálták.
A szoftverkörnyezetre a rendkívül változatos mobiltelefonos operációs rendszerek miatt nagyon kevés korlátozást adtak. A CLDC implementációnak nincs szüksége arra, hogy az operációs környezet támogasson elválasztott címterületeket vagy legyen valami fájlnak megfelelő fogalma. A CLDC implementáció egyetlen végrehajtási szálban fut (tehát nincs szüksége arra, hogy Jáva végrehajtási szálakat natív végrehajtási szálaknak feleltesse meg).

Érezhető, hogy a szigorú követelmények miatt a JVM képességei jelentősen leszűkültek. A főbb megszorítások a következők:
A CLDC igyekszik független maradni az alkalmazásmodellektől, ezért csak a legalapvetőbb osztályokat definiálja. Ezek nagy része a J2SE osztályok szűkített változata, de van néhány CLDC-specifikus osztály is. A következő osztályok támogatotak,

A fejlettebb, több memóriát tartalmazó mobiltelefonok számára a CLDC 1.0 specifikációt kibővítették, ez a CLDC 1.1.
A legjelentősebb különbség, hogy a lebegőpontos típusok most támogatottak és gyenge referenciák használhatók. Ezen felül tucatnyi kisebb bővítés történt a CLDC osztályokon, amelyek közelebb hozták a CLDC API-t a J2SE-hez.

3. A Mobile Information Device Profile (MIDP)

Amint az előzőekben említettem, egy dolog, hogy van egy korlátozott képességű Jáva virtuális gépünk, arról is gondoskodnunk kell, hogy valami fusson is rajta. Az alkalmazásmodellt és a hozzá kapcsolódó csomagokat a Mobile Information Device Profile (MIDP) specifikáció tartalmazza. A specifikáció a következő nagyobb részekből áll:

3.1. A MIDlet alkalmazásmodel

A MIDlet egy menedzselt alkalmazásmodel. Ez azt jelenti, hogy van egy alkalmazásmenedzser rendszer (AMS), amelyik a MIDleteket letölti, aktiválja és deaktiválja. Ez a rendszer kívül van a specifikáció keretén, tipikusan a telefonszoftver része. Az AMS implementációjáról a specifikáció keveset szól, de a szokásos implementációban az AMS letölti a MIDletet, a készüléken tárolja (tehát nem szükséges használat előtt letölteni), kérésre aktiválja, végül a felhasználónak módja van törölni a MIDletet, ha már nincs rá szüksége.

A MIDleteket szabványos JAR fájlokba csomagolják. Több MIDlet is lehet egy JAR fájlban, ha többen vannak, akkor őket MIDlet sorozatnak (MIDlet suite) nevezzük. Egy JAR-ba csomagolt MIDletek egymástól nincsenek elválasztva, egy MIDlet a JAR bármelyik osztályát elérheti. Az alkalmazásmenedzser a JAR fájlhoz tartozó leíró (manifest) alapján találja meg a JAR-ba csomagolt MIDleteket és tudja meg a kezelésükhöz szükséges információkat.  Egy leírófájl így néz ki:

MIDlet-Name: CardGames
MIDlet-Version: 1.1.9
MIDlet-Vendor: CardsRUS
MIDlet-1: Solitaire, /Solitare.png, com.cardsrus.org.Solitare
MIDlet-2: JacksWild, /JacksWild.png, com.cardsrus.org.JacksWild
MicroEdition-Profile: MIDP-1.0
MicroEdition-Configuration: CLDC-1.0


A leírófájl a JAR manifest fájlok szokásos helyén van, tehát a JAR archívumban a neve META-INF/manifest.mf. A legtöbb fejlesztőeszköz a manifest fájlt képes létrehozni a megfelelő helyen, ha erre kérik (pl. a JDK jar programja a -m kapcsolóval utasítható erre).

A MIDlet JAR archívuma mellett kell legyen egy fájl, amit alkalmazásleírónak neveznek. Ennek a fájlnak a szokásos kiterjesztése JAD, ha webszerveren van, a szerver text/vnd.sun.j2me.app-descriptor MIME típussal kell kiszolgálja. Az alkalmazásleíró nagyon hasonlít a JAR-on belüli leírófájlra, több mező (pl. MIDlet-Name, MIDlet-Version, MIDlet-Vendor) azonos KELL legyen és szerepelnük kell mindkét fájlban. A MIDlet-x mezőket viszont mindig a JAR-ban levő fájlból veszi a az AMS, így ezek az alkalmazásleíróban nem lehetnek.

Az alkalmazásleíró tartalmazza a JAR adatait, melyek alapján a telefon már a JAD alapján eldöntheti, képes-e a JAR letöltésére (van-e hozzá elég memóriája) és megtalálhatja a JAR-t magát. A telefonnak tehát a JAD elérési útját (webes letöltés esetén URL-jét) adjuk meg, a JAD alapján a telefon eldönti, tudja-e a MIDletet fogadni, majd a JAR-t ő tölti le a JAD információi alapján. JAD példa:

MIDlet-Name: CardGames
MIDlet-Version: 1.1.9
MIDlet-Vendor: CardsRUS
MIDlet-Jar-URL: http://www.cardsrus.com/games/cardgames.jar
MIDlet-Jar-Size: 7378
MIDlet-Data-Size: 256


A MIDlet-JAR-URL mutat a JAR fájlra, a MIDlet-JAR-Size megmondja a JAR méretét bájtban, a MIDlet-Data-Size pedig a MIDlet által igényelt minimális perzisztens tárolóterületet. A MIDlet-Data-Size előfordulhat a JAR-ban levő leírófájlban is, a MIDlet-JAR-URL és a MIDlet-JAR-Size azonban nem. A MIDlet letöltésekor az AMS ellenőrzi, hogy a JAR mérete megfelel-e az alkalmazásleíróban szereplő értéknek és megszakítja a letöltést, ha különbséget észlel.

Minden MIDlethez egy osztály tartozik, amelyik a javax.microedition.midlet.MIDlet osztály leszármazottja. A MIDlet osztályt a JAR leírófájl azonosítja, a MIDlet-x sorokban ez a harmadik elem.

MIDlet-1: Solitaire, /Solitare.png, com.cardsrus.org.Solitare

A MIDlet életciklusának három állapota van. Az AMS a MIDlet osztály metódusainak hívásaival értesíti a MIDletet az életciklus-változásokról.

3.2. Felhasználói felület

A Jáva létező felhasználói felület csomagjai (pl. AWT) nem alkalmasak mobiltelefonos használatra. Egyrészt túl nagyok, másrészt általában átlapolódó ablakokkal modellezik a rendszert, ami a mobiltelefonos felhasználói felületekre nem igaz. A MIDP-t kis méretű, tömegesen használt mobiltelefonokra tervezték, amelyeknek tipikus felhasználói felület-eleme a lista. Ilyen felületekre a MIDP megalkotásának idején nem volt alkalmas Jáva könyvtár, ezért hozták létre a MIDP LCDUI  könyvtárát.

Az LCDUI tervezésekor a fő követelmények a következők voltak:
Az LCDUI központi fogalma a képernyő (screen). A képernyő egy objektum, ami a valóságos kijelzőn megjelenítendő tartalmat jelképez. Az alkalmazás élete során a felhasználó képernyőről képernyőre halad. A képernyők három fő fajtája a következő:
A képernyők megjelenítését a Display osztályon keresztül vezérelhetjük. Ennek setCurrent metódusa beállítja az aktuális képernyőt, ami ezután meg is jelenik a mobiltelefon képernyőjén.

Display.getDisplay( this ).setCurrent( f ); // f mutat a megjelenítendő képernyőre

A képernyőket alapvetően két stílus szerint kell létrehozni, ezek: Canvas és Screen (ezek egyben az ősosztályai a stílust megvalósító objektumoknak).

A Canvas stílus a következőképpen néz ki:

import javax.microedition.lcdui.*;

public class MyCanvas extends Canvas {
  public void keyPressed( int keycode ) {
// Billentyűnyomás eseménykezelő. A Canvas minden eseménykezelőhöz
// implementál üres metódusokat, úgyhogy mindegyik opcionális
    ...
  }

  public void paint( Graphics g ) {
// Meghívják, ha a Canvas-t újra kell festeni. Minthogy ez
// abstract metódus a Canvas-ban, implementálni kötelező.
  }
}

A Canvas-nak nagyjából egy tucat eseménykezelő metódusa van, a keyPressed csak egy közülük. A legérdekesebb a showNotify-hideNotify páros. A MIDlet nem egyedül fut a telefonban és általában még csak nem is a legfontosabb folyamat. Beérkezhet egy hívás, amit azonnal jelezni kell a felhasználóknak. Ilyenkor a felhasználói felület olyan lehet, hogy a MIDlet képernyőjét eltakarja egy üzenet, hogy hívás érkezett. Ekkor a MIDlet hideNotify üzenetet kap, majd ha a képernyő újra szabad, showNotify-t.

A MIDletek hívás közbeni viselkedése  a MIDlet specifikáció legzűrösebb pontja, amelyet a Nokia  és Motorola  másként implementált. Nokia telefonokon a MIDletet semmi nem akadályozza a futásban, még akkor sem, ha a telefon hívást fogad. A MIDlet háttérbe kerülhet a hívás során (pl. üzenetablak miatt), de ettől még fut. A háttérbe-előtérbe kerülési események hideNotify-showNotify események formájában jutnak el hozzá. Motorola telefonokon a hívás ideje alatt a MIDlet nem fut, hanem Paused állapotba kerül.

A másik fontos stílus a Screen. A Screen alapelve, hogy a MIDlet komplex felhasználói felület-elemek megjelenítését kéri a telefontól, melyet az kedve szerinti stílusban jelenít meg. A Screen-típusú képernyők tehát különbözőképpen jelennek meg különböző telefonokon, cserébe viszont a képernyő részletes rajzolásával nem kell bajmolódjunk.

A Screen ősosztálya két specializált leszármazotti ágnak.
Az egyszerűség kedvéért Screen-t a Canvas-tól teljesen különböző programozói stílusban kell létrehozni. Vegyünk példa kedvéért egy Form-ot! A Form konstruktorában a Form-hoz kell adni a képernyő elemeit, majd eseménykezelőket kell installálni a Listener pattern szerint. Példa:

import javax.microedition.lcdui.*;

class MyListener implements ItemStateListener {
  public void itemStateChanged( Item i ) {
// Lekezeli az i Item változásait
  }
}

class MyForm extends Form {
  TextField f1;
 
  public MyForm() {
    super( "Adder" );    // A Form címkéje, pl. a képernyő tetején jelenhet meg
// Egy TextField Item-et ad a Form-hoz
    f1 = new TextField( "Num1","", 10, TextField.NUMERIC );
    append( f1 );
// A Form változásairól a MyListener kapjon értesítést
    MyListener m = new MyListener();
    setItemStateListener( m );
  }
...
}
 
vagy egyszerűbben:

import javax.microedition.lcdui.*;

class MyForm extends Form implements ItemStateListener {
  TextField f1;
 
  public MyForm() {
    super( "Adder" );    // A Form címkéje, pl. a képernyő tetején jelenhet meg
// Egy TextField Item-et ad a Form-hoz
    f1 = new TextField( "Num1","", 10, TextField.NUMERIC );
    append( f1 );
// A Form változásairól ez a MyForm egyed kapjon értesítést
    setItemStateListener( this );
  }

  public void itemStateChanged( Item i ) {
// Lekezeli az i Item változásait
  }

...
}

Másik fontos Listener típus a CommandListener, ami Command egyedekhez kapcsolódó eseményekről küld értesítést (itt nem részletezzük, a Command osztály egyedeivel saját opciómenü vagy funkcióbillentyű-kezelést valósíthatunk meg).

3.3. Perzisztens tárolás

Minthogy a MIDleteket installálják a telefonra és hálózati kapcsolat nélkül is működőképeseknek kell maradniuk, igen jól jön egy perzisztens (=a MIDlet lelövése, sőt a telefon kikapcsolása) után is megőrződő tárolóhely. A MIDlet API egy rendkívül egyszerű rendszert kínál, ez a Record Management System (RMS) API. Az RMS funkciói a következők:
Ezen felül az RMS még néhány egyszerű szolgáltatást nyújt, pl. változásfigyelő eseménykezelőt lehet a RecordStore-hoz kötni, a rekordok utolsó változtatási idejét le lehet kérdezni, stb.

A RecordStore mérete nem túl nagy, pl. a Nokia 6310-ben csupán 20Kbájt az összes MIDlet sorozat számára. A méret azonban jelentősen nőtt az utóbbi időben, a Nokia legújabb nem Symbian telefonjaiban a teljes méret eléri az 1 MBájtot, Symbian-os telefonokban ennél nagyobb is lehet.

3.4. Hálózatkezelés

 A MIDP hálózatkezelési osztályai a CLDC GCF-re épülnek. A MIDP kötelező hálózati protokollja a HTTP, ennek megfelelően MIDP implementációknak képeseknek kell lenniük HTTP URL-t fogadni a javax.microedition.io.Connector osztály open metódusában. Maga a kommunikáció nem feltétlenül HTTP protokollon folyik, de a protokoll funkcionalitása HTTP-vel egyenértékűnek kell legyen (pl. WAP).

3.5. MIDP 2.0

Nagyon röviden teszek említést a MIDP új, 2.0-ás változatáról (JSR-118).Ez felfelé kompatibilis a MIDP 1.0-val. A legjelentősebb változások a következők: