MIUI lockscreen készítési segédlet

Alapok

A MIUI témázásának (nagyon) alapjai
Bizonyára sokakban felötlött már a gondolat a stock alapú romokon, vagy akár CM7-en is, hogy a gyári feloldóképernyők helyett valami újat, egyénit látnának a telefonjukon, ha bekapcsolják a kijelzőt. Nekik ugye ott van a WidgetLocker, vagy más hasonló appok, viszont itt van a MIUI egyik előnye: a szinte korlátlan testre szabhatóság.

Ami a fenti appok nélkül kemény fejlesztési munka lenne, a MIUIban a végfelhasználó által is könnyen szerkeszthető formában valósítható meg.

Mi is ennek az alapja? A MIUI témázhatósági rendszere, amit az jellemez, hogy egy-egy témában igen sokmindent lefedhetünk, ugyanakkor megvan a lehetőségünk, hogy az UI egyes elemeit a nekünk tetsző témákból összelegózhassuk, ezzel alkotva meg az egyedi képet. (Hogy lássuk, hogy a userek mi mindent hoznak ki a saját MIUIjukból, ajánlom a következő topikot: XDA What does your MIUI look like?)

Ráadásul a MIUI lockscreenek használatáról ráadásul már nem kell lemondaniuk azoknak sem, akik bár nem MIUI romot használnak, de legalább FroYo romot használnak, ha feltelepítik a MIUI fejlesztők által írt MiLocker programot.

Hogyan is épülnek fel a témák: minden témát egy .mtz fájlban lehet telepíteni a fájlkezelőn vagy a theme manageren keresztül, pofonegyszerűen. Kiválasztjuk, hogy az adott témából mit óhajtunk telepíteni, és azt néhány másodpercnyi fájlmásolás után a rendszer alkalmazza is.

Tehát minden téma egy .mtz fájlból áll (MIUI Theme Zip). Ezek az mtz fájlok tartalmaznak minden fájlt és xml fájlt, amit módosítani akarunk a rendszer bármelyik appjában. (A rendszer figyeli a resource-kéréseket és a megfelelő fájlokra irányuló kéréseket átirányítja a témánkban lévőkre) Az mtz fájl lényegében egy zip fájl, aminek a kiterjesztését megváltoztatjuk mtz-re. De mit is kell zippelnünk? Ehhez célszerű megnéznünk egy téma tartalmát belülről.

Kétféle formátummal találkozhatunk: az egyik az úgynevezett „old format”, azaz az mtzben különböző mappákat találunk, amik különböző másik mappákat és ezekben képeket és xml fájlokat rejtenek. A másik lehetőség a „new format”, azaz ilyenkor az mtzben különböző kiterjesztés nélküli fájlokat fogunk találni. (Valójában ezek is újabb zipfájlok, csak jelen esetben kiterjesztés nélkül) Ilyen mappák lehetnek a következők a teljesség igénye nélkül, mindnek beszédes a neve is, hogy mire való: preview, ringtones, icons, wallpaper, icons, lockscreen és különböző mappák a témázandó appok process neveivel. (Tehát például a gmail az nem gmail, hanem com.google.android.gm). Ezen kívül található még egy description.xml fájl, ami a téma azonosításában segít (szerző, téma neve, verziószáma, stb.)
Az appok témázásába most nem mennék bele, az egy következő írás témája is lehet majd.
(Elnézést az olvasótól, hogy következetesen az angol szót használom a feloldóképernyőre, de nem áll a számra [ujjamra] a szó, így maradok a lockscreennél vagy az ls rövidítésnél.)

A lockscreenek témázásáról
Tehát a ls-eket a lockscreen nevű mappába kell majd belepakolnunk. De ez hogyan néz ki belülről? Található benne egy advance mappa, amiben pedig egy manifest.xml és egy adag képfájl. A manifest.xml az a fájl, ami a lényegi részt kódolja le, azaz hogy mi hogyan legyen elrendezve, milyen funkciókat tudjon, stb, míg a képfájlok a lock grafikus dizájnjához kellenek. (Kivitelezhető text-only ls is, ilyenkor persze nincsenek képfájlok.)

Hogyan kezdjünk neki a lockscreenek készítésének? Legyen valami elképzelésünk arról, hogy mi az, amit létre akarunk hozni, készítsünk szkeccseket, amiből aztán valamilyen képszerkesztővel (mindenkinek tudásának és pénztárcájának megfelelően az egyszerűbb Paint.nettől kezdve a GIMP/Photoshop párosig bármivel, amit az ember ismer és elér, a Windows Paintet azért nem ajánlom) készítsünk el egy koncepciótervet. Ez nem csak azért hasznos, mert ugye a lockhoz minden képfájlt így is, úgy is el kell készítenünk később mindenképp, hanem azért is, mert könnyebbé teszi a kódolást, ha a koordinátákat nem fejben tervezzük csak kódolás közben, hanem mondjuk Photoshopból tudunk lesni. Ezután kellene elkezdenünk a kódolást.

Ehhez több segítségünk is lehet: megpróbálunk egy már kész ls-t módosítani, vagy pedig az alapoktól építjük újra, esetleg mások által használt kisebb-nagyobb kódrészletek átemelésével. A kód megírásánál valamennyire meg van kötve a kezünk, mivel fix utasításkészlettel dolgozik a miui, ugyanakkor ez jól dokumentált, példákkal ellátva, valamint már minden utasításra elérhető működő lock is, amikhez szükség esetén nyúlhatunk. És ez a dokumentáció hol található? Az xda-n a következő topikban: miui lockscreen manifest (egyébként is érdemes az xda-t forgatni annak, aki még nem ismeri, irdatlan mennyiségű tudásanyag van ott felhalmozva)
Ennek a dokumentációnak a magyar változatát fogom lentebb bemutatni.

Az alapokról
Tehát a kódot a manifest.xml tartalmazza, ezt kell megírnunk általunk választott normális szövegszerkesztőben (én notepad++ -t használok, mások másra esküsznek, winword nem ajánlott). A kód alapvetően xml alapú, így nem kell nagyon bonyolult több oldalnyi kódra számítani, viszonylag egyszerűen írhatunk manifestet.
Hogyan is kellene majd kinéznie egy ilyen fájlnak: minden manifest fájl <Lockscreen> taggel kezdődik (a kód kisbetű/nagybetűre érzékeny), aminek még megadhatunk különböző paramétereket, mint pl. frame rate (ami ha 0, akkor csak érintésre frissít). Ezután helyezzük el sorban az általunk kívánt elemeket az xml fájlban (képek, szövegek, órák, feloldógombok, zenelejátszó), ezek megjelenítési sorrendje fentről lefelé fog történni, a legelső elemek a háttérben jelennek meg, míg a legutolsó elemek a felszínen lesznek. Végül majd az egészet le kell zárnunk a </Lockscreen> taggel. Minden elemet le kell zárnunk, különben a rendszer hibát hoz. Ez történhet kétféle módon: (1) a html-kódokból is ismert módon, azaz pl. <Image></Image>, vagy pedig (2) egysoros kódelemek esetén a következő módon: <Image ……… />
Milyen elemeket használhatunk fel a ls-ekben? Képeket, szöveges adatokat, dátumot és időt elég sokféle formátum mellett, beállíthatunk különböző feloldógombokat, zenelejátszót valamint néhány rendszerszintű változó értékét is kiírathatjuk a képernyőre (akkumulátor állapota: merül, töltődik, stb., töltöttsége százalékban, elmulasztott hívások száma, olvasatlan smsek száma, valamint az 1.9.30-as verzió óta a legközelebbi ébresztés ideje is kiíratható). Hiányossága a rendszernek, hogy csengetési módot nem lehet még váltani, azaz az aosp lock egyik fele pl. még nem kivitelezhető. (Még. A fejlesztők már dolgoznak az ügyön. Ráadásul igen jó a support, a fejlesztők bármikor hajlandóak segíteni, meghallgatják az új ötleteket, jó párat be is vezettek már közülük.)

És akkor végre következzen a kód részletes dokumentációja a tovább után.

Állandók, képek, animációk

1. Használható állandók/kifejezések

Lehetőségünk van különböző matematikai műveleteket használni, valamint rendelkezésünkre áll néhány állandó, amit használhatunk bárhol, ahova számot kell írni.

A következő matematikai műveletek használhatók:
+, -, *, /, %, (, ), sin, cos, tan, asin, acos, atan, sinh, cosh, sqrt, abs, min, max (itt a % jel a maradékos osztást jelenti valószínűleg, bár azt sose használtam, de elvileg pl. 10%3=1)

Használható néhány más operátor még:
len(szám): megmondja, hogy az adott szám hány jegyű. Pl. len(1234)=4
digit(szám,pozíció): megadja adott számnak megfelelő pozícióján lévő számjegyét. Figyelem: az egyesektől kezdi a számolást, azaz jobbról. Pl.: digit(1234,2)=3

A következő állandók használhatók:
Minden számformátumú változó # jellel kezdődik. A következők használhatók, az egyszerűség kedvéért néhány csoportba foglalva:

Dátum/idő:
#ampm – eredménye: 0:am, 1:pm
#hour12 – az óra 12 órás formátumban
#hour24 – ugyanez 24-esben
#minute – a percek száma
#second
#year
#month – az adott hónap sorszáma, ahol 0 a január és 11 a december
#date – a nap sorszáma a hónapban
#day_of_week – milyen nap van ma, ahol 1 a vasárnap és 7 a szombat

Képernyő:
#screen_width – eredménye a képernyő szélessége pixelben
#screen_height – eredménye a képernyő magassága pixelben
Mindkettő hasznos, amennyiben bármit úgy akarunk elhelyezni, hogy nem abszolút pontokhoz viszonyítjuk helyzetét, hanem mondjuk a képernyő közepéhez, így könnyebb használni más méretű kijelzőkön.

Rendszerszintű értékek:
#time – az aktuális idő értékét adja vissza, unix timestamp formában
#touch_x, #touch_y – az aktuálisan megérintett pont koordinátái
#battery_level – az akku töltöttségi szintje 0-tól 100-ig
#sms_unread_count – olvasatlan sms-ek száma
#call_missed_count – nem fogadott hívások száma
#battery_state – az akku állapota. Értékei lehetnek: 0: normál használat, 1: töltés, 2: akkufeszültség alacsony, 3: akku teljesen töltött.

A feloldóhoz köthető értékek:
Ezeket mind a feloldó nevével kell bevezetni, azaz „unlocker” nevű feloldó esetén
#unlocker.move_x – a feloldó x irányú mozgása, lehet negatív is.
#unlocker.move_y – a feloldó y irányú mozgása, lehet negatív is.
#unlocker.move_dist – a feloldáskori elmozdulás mértéke
#unlocker.state – a feloldó állapota: 0: normál, 1: megnyomott, 2: feloldott.

Egyéb, később bevezetett változók:
#tt.text_width – a „tt” nevű szövegdobozban lévő szöveg szélességét adja meg. Hasznos akkor, ha nem fix szöveget teszünk bele, hanem változó által kirakottat, de mellé tennénk mást is, ilyenkor pontosan tudunk a szövegdoboz mellé pozicionálni. (1.10.21)
#actual_x, #actual_y – egy elem aktuális pozíciójának meghatározására (pl animáció közben jól használható). Használata: „img” nevű elem aktuális helyzetének meghatározása: #img.actual_x (1.10.21)
@next_alarm_time – ez a többitől eltérően szöveges változó (ezért kezdődik kukaccal és nem kettőskereszttel), megadja a következő ébresztés idejét. Használata: <Text text="@next_alarm_time" .../> (1.9.23)
#music.state – zenelejátszás állapota, értékei: 1: lejátszás, 0: nincs lejátszás
#music_control.visibility – a „music_control” nevű zenelejátszó láthatósága (igen/nem). Sajnos csak a zenelejátszó láthatósága kérdezhető így le.
#time_sys – a rendszeridő unix timestamp formában (1.10.23)

Egy példa: a kép csak akkor látható, ha nincsen konnektoron és nem alacsony a feszültség, a feloldó elhúzásával fokozatosan átlátszó lesz.
<Image x="162" y="#screen_height-84" src="hs_path_bg.png" alpha="(255-#unlocker.move_x/100*255)*min(1, abs(1-#battery_state))"/>

Logikai műveletek (1.10.23-mal bevezetett elemek):
eq(x, y) – ha a két elem egyenlő, értéke 1, különben 0 (equal)
ne(x, y) – ha a két elem nem egyenlő, értéke 1, különben 0 (not equal)
ge(x, y) – ha x>=y, értéke 1, különben 0 (greater or equal)
gt(x, y) – ha x>y, értéke 1, különben 0 (greater than)
le(x, y) – ha x<=y, értéke 1, különben 0 (less or equal)
lt(x, y) – ha x<y , értéke 1, különben 0 (less than)
isnull(x) – ha x értéke null, akkor az eredmény 1, különben 0 (arra használható pl, hogy a kinyert változó vesz-e fel értéket)
not(x) – ha a benne lévő elem nem teljesül, értéke 1, különben 0
ifelse(x, y, z) – ha x teljesül, akkor y értéket veszi fel, különben z értéket

2. Képek

Képek beszúrásánál ami a leglényegesebb, hogy alapesetben a kép bal-felső sarkához képest kell viszonyítani a koordinátákat. (Ez igaz ugyanúgy minden más beszúrható elemre is.)
Használata: <Image x="" y="" w="" h="" align="" centerX="" centerY="" angle="" src="" srcid="" alpha="" antiAlias=""/>

És akkor a magyarázat:
<Image> és </Image> vagy <Image …. /> tagbe kell tennünk a képet, ami png formátumú lehet.

Az x és y a kép koordinátáit adja meg x és y tengelyen. Ez ugye alapesetben a bel-felső sarok koordinátáit jelenti.
A w és h a kép szélességét (width) és magasságát (height) mutatja meg.
Ezek után jön egy érdekes tag, az align, amivel változtathatunk a viszonyítási pontokon. Amennyiben nem írjuk ki, úgy „left” értéket vesz fel, de lehetséges értékei: „left”, „right”, „center”. Right állapotban a jobb-felső pont a vizsonítási pont, center esetben a középső-felső pont.
A centerX és centerY pontokat akkor érdemes használnunk, amennyiben a képet forgatni akarjuk, ilyenkor a viszonyítási ponthoz képest megadhatjuk a forgástengely helyét. (elhagyása esetén a kép x és y pontja a forgástengely)
Az angle taggel pedig megadhatjuk a forgatás mértékét is.
Talán a legfontosabb az src tag, amivel a képfájl forrását adhatjuk meg. Ami fontos, hogy a fájlnak muszáj a lockscreen/advance mappában lennie (a manifesttel egy szintben). A kód nem kezel almappákat.
Amennyiben olyan képet használunk, aminél lényeges, hogy valamilyen változó értékétől függően változtassa a képet, úgy használhatjuk az srcid taget, ahol értéknek a kívánt változót adjuk meg. A fájlt ilyenkor xxxyy_123.png néven kell elnevezni. Ilyenkor az alulvonás előtti rész lesz az src, azaz src=”xxxyy.png” az srcid pedig srcid=”123”.(Hasznos lehet pl. óra esetén)
Az alpha az átlátszatlanságot kódolja, 0 és 255 között (0 teljesen átlátszó, míg 255 teljesen átlátszatlan).
Erre használható egy másik tag is, a visibility, aminek értékétől függően változik a láthatóság. Amennyiben értéke 1-nél kisebb, úgy nem látható, amennyiben 1 vagy nagyobb, úgy látható a kép. (tehát itt nincs fokozatosság)
Az antiAlias magáért beszél, értéke lehet „true” vagy „false”. Bekapcsolt antiAlias szebb képet ad, főleg, ha méretezni kell a képet.

a. ImageNumber
Elemi képekből ír ki egy hosszabb számot. Használata: <ImageNumber number="" src="">
number – a kiíratandó szám
src – az elemi képek fájlneve (ha src=”number.png”, akkor number_0.png, number_1.png, … number_9.png fájlokat használ)

3. Animációk

A képek és szövegek rendelkezhetnek különböző animációkkal, ezek típusa lehet: forrás (source), pozíció, méret (size), forgás (rotation) és átlátszósági (alpha). Mind független egymástól és a maga idejében lejátszódik, majd loopol.

Minden animációnak tartalmazni kell néhány kulcskockát (keyframe), ami megadja az animáció tulajdonságait, a többit ezek alapján a miui interpolálja. Amennyiben az első keyframe nem 0 időpontú, úgy a 0 időpont a kép eredeti tulajdonágait jelenti. Az idő egysége ms. Amennyiben nem szeretnénk, hogy loopoljon az animáció, úgy az utolsó keyframe idejének adjuk meg egy tetszőlegesen nagy számot (sok 0-val végén). (azaz lényegében kellően sokáig elnyújtjuk a loop kezdetét)
Az <Image> és </Image> tagek közé kell tenni.

Pozíció:
A keyframe-ekben megadott pozíció a befoglaló kép koordinátáihoz képest relatív.
<PositionAnimation>
<Position x="" y="" time=""/>
<Position x="" y="" time=""/>
</PositionAnimation>

Forgás:
A forgás a kép xy pozíciójához vagy a centerX és centerY pozícióhoz relatív.
<RotationAnimation>
<Rotation angle="" time=""/>
<Rotation angle="" time=""/>
</RotationAnimation>

Méret:
Ez a kép xy pontjából fixen kiinduló méretezést jelent.
<SizeAnimation>
<Size w="" h="" time=""/>
<Size w="" h="" time=""/>
</SizeAnimation>

Átlátszóság:
0-255 (0: átlátszó, 255: átlátszatlan)
<AlphaAnimation>
<Alpha a="" time=""/>
<Alpha a="" time=""/>
</AlphaAnimation>

Forrás:
Itt alapértelmezetten a 0 időpontbeli forrás a befoglaló kép, de megadható más 0 keyframe segítségével. A keyframe-ekben található x és y tag elhagyható, de segítségükkel az Image xy-hoz képest relatívan lehet eltolni a frame-et. (a példában 123 ms időben pic1 látható, míg 1100 ms időpontban már pic2)
<SourcesAnimation>
<!-- optional: x y -->
<Source x="" y="" src="pic1.png" time="100"/>
<Source x="" y="" src="pic2.png" time="1000"/>
</SourcesAnimation>

Példa:
A képet egy helyzeti animációval a kép bal oldaláról a jobb oldalára mozgatjuk 1 mp alatt, ezalatt az átlátszósága 175-ről a megérkezéskor 0.5 mp alatt 255 lesz, majd másik 0.5 mp alatt eltűnik. Ezután újrakezdődik.

<Image x="0" y="#screen_height-177" src="charging_light.png" category="Charging">
<PositionAnimation>
<Position x="480" y="0" time="1000"/>
<Position x="480" y="0" time="2000"/>
</PositionAnimation>
<!— a 0 időpont az eredeti pozíció, 1 mp alatt a jobb oldalra megy, ott 1 mpt időzik, majd újrakezdődik -->
<AlphaAnimation>
<Alpha a="175" time="0"/>
<Alpha a="175" time="1000"/>
<Alpha a="255" time="1500"/>
<Alpha a="0" time="2000"/>
</AlphaAnimation>
</Image>

Maszkok, Kategóriák, szöveg, dátum, idő

4. Maszkok

A maszkok segítségével ilyen effekteket hozhatunk létre:

Az image az eredeti kép, mask a maszk, és result a végeredmény, amit megkapunk. A mask.png-ben a fekete az, amit látni akarunk az eredeti képből, míg a többit nem fogjuk látni (a maszkon átlátszón kell hagyni). Az a rész, amit nem fed le a maszk, érintetlen marad.

Használata:
<Mask x="" y="" src="" centerX="" centerY="" angle="" align=""></Mask>
Mindig egy adott képhez kell kötni, az az az <Image> és </Image> közé kell tenni.

x,y: a maszk helyzete
align: értékei lehetnek: „absolute”, ilyenkor a képernyőhöz viszonított, és lehet „relative”, ilyenkor a befoglaló képhez viszonyított.
A maszknak is lehet ugyanúgy mindenféle animációja, ilyenkor ez a <mask> és </Mask> közé kell tenni.

A fentebbi képes példa megvalósítása (a végeredmény a „result” lesz)
<Image src="image.png" x="" y="">
<Mask src="mask.png" align="relative=" x="0" y="0"/> </Image>
Az alábbi példában egy fénylő pont vándorlása mutatja a feloldási irányt:
<Image x="444" y="#screen_height-92" src="hs_path_light.png">
<PositionAnimation>
<Position x="-438" y="0" time="2000"/>
</PositionAnimation>
<Mask x="0" y="#screen_height-92" src="hs_path_mask_r.png" align="absolute"/>
</Image>

5. Kategóriák

A feloldó kivételével minden elem beosztható kategóriákba. Ez négyféle lehet: Charging (azaz töltéskor), BatteryLow (ha akkufesz. alacsony, ez az érték a beállítások menüben változtatható), BatteryFull (teljes töltöttség), Normal.
Az adott elem csak a megfelelő állapotban fog látszani. Hasznos pl. töltéskor kirandó szövegekhez.

Példa: a kép csak töltéskor látható.
<Image x="100" y="100" src="pic.png" category="Charging"/>

6. Szöveg

A kijelzőn szöveges elemet ír ki. Támogat dinamikus adatokat.
Használata:
<Text x="" y="" text="" color="" size="" format="" paras="#x,#y" align="" marqueeSpeed="" angle=””>

x,y
align – left, right, center
color – hexa formában, AARRGGBB módon (2 digit alpha, utána rgb)
size – betűméret pixelben
text – statikus szövegnél használható (ha pl. azt akarjuk kiírni, hogy „szia”, ilyenkor text=”szia”)
format – dinamikus szövegeknlél használandó. Használata: format="szöveg %d %s", ahol a szöveg az bármi szöveg lehet, a %d számformátumú változót, míg a %s szöveges formátumú változót takar. Ezekből többet is lehet használni, jelentésüket definiálni kell a paras tagben.
paras – a formatban használt változók. Számformátumú változók esetén # jellel kezdődik, mígy szöveges változóknál @ jellel. (pl. #battery_level kiírja a töltöttségi szintet)
marqueeSpeed – fényújságfunkció, az align irányába, megadja a sebességét, amennyiben adtunk szélességet a szövegnek (w tulajdonággal) és a szöveg szélessége meghaladja a megadott szélességet.
angle – az 1.9.2-es verziótól fogva a szöveg és dátum tudja használni a forgatást, értékét fokban kell megadni.

Példa:
Kiírja töltéskor a következőt: „Charging xxx%”
<Text x="240" y="130+#unlocker.move_y" category="Charging" color="#AAFFFFFF" alpha="200" size="24" format="Charging (%d%%)" paras="#battery_level" align="center"/>

7. Idő és dátum

Ez kétféle módon oldható meg.

(a) Grafikus óra:
<Time x="10" y="10" src="time.png"></Time>
Ez a következőt végzi: az aktuális időt a rendszerbeállítások szerint kiírja hh:mm formában, ha a forrás „time.png”. A fájlokat a következő módon kell elnevezni: time_0.png, time_1.png, ... time_9.png, time_dot.png

(b) Szöveges óra:
<DateTime x="" y="" align="" color="" size="" format="" value=”” angle=""></DateTime>
Ez szövegesen jeleníti meg az időt. Tulajdonságainak nagy része megegyezik a szöveg moduléval.
value – nem kötelezen megadadandó. Elhagyásakor az aktuális időt írja ki, ám megadható bármilyen más időpont unix timestamp formátumban, olyankor azt alakítja át.
format – dátum formátuma
Szöveges elemek esetén a reprezentáló betű ismétlése részletesebben írja ki a megfelelő egységet.pl.
M 9
MM 09
MMM Sep
MMMM September

Számalapú elemek esetén az ismétlés több számjegyet jelent. pl.
m 7
mm 07
mmm 007
mmmm 0007

Használható betűkódok:
E – nap neve betűvel
M – hónap
d – nap számmal
y – évszám
h – óra 12 órás formátumban
k – óra 24 órás formátumban
m – percek
aa – am/pm
NNNN – lunar naptár (kínaiak használják)

Példák a következő napra: 1970 április 6, reggel 3:23
MM/dd/yy h:mmaa 04/06/70 3:23am
MMM dd, yyyy h:mmaa Apr 6, 1970 3:23am
MMMM dd, yyyy h:mmaa April 6, 1970 3:23am
E, MMMM dd, yyyy h:mmaa Mon, April 6, 1970 3:23am
EEEE, MMMM dd, yyyy h:mmaa Monday, April 6, 1970 3:23am
Jeles nap: M/d/yy Jeles nap: 4/6/70

kk:mm 13:34 (24h formátum)

Feloldók

8. Feloldók

Elértünk a lockscreen legfontosabb eleméhez, a feloldóhoz. Ezt az <Unlocker></Unlocker> tagek közé kell tenni.

Két részre tagolandó:
a. kezdőpont, azaz ahol a feloldó akkor látható, amikor nem kattintott, valamint innen kell indítani a feloldást.
b. végpont, azaz itt fejeződik be a feloldás és vált vissza a telefon használható állapotába.
Mindkét résznek megvan a saját tagje, mégpedig <StartPoint> és <EndPoint>. Ezen kívül mind a kezdő-, mind a végpontnak 3 állapota lehet: normál, azaz nem kattintott, kattintott (pressed) és végponti (reached). Ennek akkor van jelentősége, ha valamilyen animációt akarunk beállítani, pl. nyomáskor váltson színt, végpontban tűnjön el, stb.

a. StartPoint használata:
<StartPoint x="" y="" w="" h="">
x,y – a feloldási mező bal-felső koordinátája
w,h – a feloldási mező kattintható részének szélessége és magassága

b. az állapotok használata:
Mindhárom állapot tartalmazhat minden másik elemet (kép, szöveg, dátum, óra, wallpaper)
NormalState: <NormalState> és </NormalState> tagek közé téve normál, nem kattintott állapotban mutatja az elemeket.
PressedState: <PressedState> és </PressedState> tagek között, kattintási állapotban látható. Amennyiben aktív, úgy elrejti a NormalState elemeit.
ReachedState: <ReachedState> és </ReachedState> tagek között, akkor látható, ha a feloldó a végponti zónába ér. Amennyiben aktív, úgy rejti a NormalState és PressedState elemeit.
Minden, amit a StartPointon belül helyezünk el, az feloldáskor a feloldóval együtt mozog.

c. EndPoint használata:
<EndPoint x="" y="" w="" h="">
x,y – a végponti mező bal-felső koordinátája
w,h – a végponti mező feloldásra alkalmas részének szélessége és magassága

A feloldás akkor indul el, ha a mozgó unlocker bal-felső pontja beleér az EndPoint területére, ekkor a telefon ezt rezgéssel is jelzi.
Az EndPointon belülre tett elemek nem mozognak a feloldóval. Ennél is használható a 3 állapot, a StartPointnál ismertetett módon.

d. fix feloldópálya alkalmazása
Alapértelmezetten a feloldó mozgása nem limitált, azaz az egész képernyőt bejárhatjuk a feloldóval. Időnként azonban elófordulhat olyan projekt, amikor jobban szeretnénk, ha a feloldó csak egy adott fix pályát járhatna be. Ilyenkor kell használnunk a Path taget, amit az EndPointon belül használhatunk. Ez az elem opcionális, elhagyása esetén az alapeset lép életbe.

Használata:
<Path x="" y="" tolerance="">
<Position x="" y="" />
<Position x="" y="" />
</Path>

<Path> és </Path> tagek között kell lennie.
x,y - a kezdőpont x és y koordinátái, később a pozíciókat ehhez viszonyítva adjuk meg. Én személy szerint általában a StartPoint koordinátáit adom itt meg, így az első pozíció 0,0 koordinátával fog rendelkezni, de használható a képernyő 0,0 is a Path pontjaiként, ilyenkor abszolút koordinátákat használhatunk.
tolerance – az a távolság pixelben, amennyivel elmozdítva az adott pontról a feloldót megszakítjuk a feloldási folyamatot. (tehát pl. 50 px toleranciával az endpointtól max 50 pixellel húzhatjuk odébb a feloldót, 51 után már nem old fel.) Minél kisebb értéket adunk meg, annál pontosabban kell a végállásba húzni a feloldót (elhagyása 0-s értéket ér).

e. adott programba unlockolás
Ilyenkor az EndPointba kell tennünk egy <Intent> taget, ami megadja, hogy melyik programba szeretnénk feloldani a telefont (pl. híváslista, smsek, kamera, stb.)

Használata:
<Intent action="" type="" category="" package="" class=""/>
Ezt az adott apnnak megfelelően kell kitölteni.

Példa:

híváslista:
<Intent action="android.intent.action.VIEW" type="vnd.android.cursor.dir/calls"/>

Sms-ek listája:
<Intent action="android.intent.action.MAIN" type="vnd.android-dir/mms-sms" category="android.intent.category.DEFAULT"/>

f. néhány egyéb megjegyzés
Egy Unlockernek akármennyi EndPointja lehet, egy de csak egy StartPointja. Egy lockscreenen akármennyi Unlockert elhelyezhetünk. Minden Unlockert célszerű elnevezni: <Unlocker name="xxx">. Később ugyani ezen a néven lehet rá hivatkozni változókkal. (pl. az xxx nveű unlocker state lekérdezésének helyes használata #xxx.state)

g. „unlocker bounce”
Ezt a feature-t az 1.10.21 verzióval vezették be, lényege az, hogy amennyiben elengedik a feloldót, az nem hirtelen pattan vissza a startpontra, hanem fokozatosan , megadott sebességgel.

Használata:
<Unlocker name="unlocker" bounceInitSpeed="10" bounceAcceleration="1500">

bounceInitSpeed – kezdeti sebesség (pixelben)
bounceAcceleration – mennyi idő alatt érje el a kezdőpontot (millisec)

h. egy példa:
<Unlocker name="unlocker">
<StartPoint x="31" y="#screen_height-117" w="90" h="90">
<NormalState>
<Image x="31" y="#screen_height-117" src="unlock_button.png">
</Image>
</NormalState>
</StartPoint>
<EndPoint x="359" y="#screen_height-117" w="90" h="90">
<PressedState>
<Image x="359" y="#screen_height-117" src="unlock_target.png">
</Image>
</PressedState>
<Path x="0" y="#screen_height-117">
<Position x="31" y="0" />
<Position x="359" y="0" />
</Path>
</EndPoint>
</Unlocker>

Fájlstruktúra, gombok, wallpaper

9. Általános fájlstruktúra

Lehet, hogy ezzel kellett volna kezdeni, de itt már szinte minden elemet ismerünk, így ide tettem.

<Lockscreen version="1" frameRate="" displayDesktop=" " >
<Image />
<Image />
<Unlocker/>
<Unlocker/>
<Time/>
<DateTime/>
<Text/>
</Lockscreen>

<Lockscreen> és </Lockscreen> tagek közé kell tenni az egészet. Verzió mindig 1.
frameRate – az animációk sebességét, „szmúszságát” adja meg fpsben (minél nagyobb, annál "szmúszabb", de többet is eszik (mondjuk elvileg a képernyő kikapcsolt állapotában nem fut a renderelés, tehát nem számottevő). Általában 30 körüli érték elég szokott lenni, 50 fölé nem érdemes menni. 0-ra állítva csak érintésre frissít. (max érték 100)
displayDesktop – mutassa-e a hátteret. Alapesetben értéke „false”.
A kép renderelése fentről lefelé történik, ami a manifest alján van, az lesz legfelül, míg az elején lévők a háttérben.

10. Wallpaper

<Wallpaper> tagben. Használata az Image taghez hasonló, csak forrást nem lehet megadni. Ha nincsen kitéve a tag a manifestben, akkor nem kezeli a cserélhető háttérképet.

11. Gombok

Leginkább arra használtak, hogy a zenelejátszót rejtsék/mutassák.

Használata:
<Button name="" x="" y="" w="" h="" listener="">
<Triggers>
<Trigger action="" target="" property="" value=""/>
</Triggers>
</Button>

x,y – bal felső pontja
w,h – szélessége és magassága
listener – elhagyható elem, én még nem találtam olyan helyzetet, ahova kellett volna
trigger action – értéke lehet: „double” (duplaklikk), „down” (lenyomás), „up” (elengedés), „long” (hosszú klikk lenne, de nem használható tag, csak elméletileg támogatott). Megszabja, hogy milyen akcióval használható a gomb. Több különböző akció is megadható, így pl. ugyanaz a gomb mást adhat ki szimpla és dupla kattintásra.
target – annak az elemnek a neve, amit befolyásolni akarunk
property – a befolyásolni próbált elem megfelelő tulajdonságnak neve (támogatott: visibility)
value – a befolyásolandó tulajdonság által felvevendő érték, lehet konkrét szám, vagy logikai elem esetén (pl. visibility) „true”/”false”/”toggle” (váltás aktuális állapottól függően)

Minden gombnak lehet két állapota: normál és lenyomott állapot, ezek használata az unlockerhez teljesen hasonló, csak itt <Normal></Normal> és <Pressed></Pressed> tageket kell használni.
Bármilyen elemet tartalmazhat egy gomb (azaz képet, szöveget, dátumot, órát, wallpapert).

Zenelejátszó, tippek

12. Zenelejátszó

Képes irányítani bármilyen lejátszót, ugyanakkor az aktuális zeneszámok címét és borítóját csak a MIUI Music programból képes kinyerni.

Használata:
<MusicControl> és </MusicControl> tagek között.
Tartalmazhat négy fix funkciójú gombot (play/pause/rew/fwd) és egy képet (albumborító), melyek elnevezése fix, ezen kívül bármi más is belefoglalható.

<MusicControl name="music_control" x="" y="" autoShow=””>
<Image name="music_album_cover"/>
<Text name="music_display"/>
<Button name="music_prev"/>
<Button name="music_next"/>
<Button name="music_play"/>
<Button name="music_pause"/>
</MusicControl>

x,y – a lejátszó koordinátáit adja meg, a többi elemet ehhez relatívan kell kezelni.
music_abum_cover – a lemezborítót tartalmazó kép, használata a normális Image taghez megfelelő, csak forrást nem kell megadni.
music_display – az aktuális zeneszám címe „számcím – előadó” formában (nem változtatható), a normális Text taghez megfelelően formázható, text mezőt nem kell megadni.
music_prev, music_next, music_play, music_pause – nevüknek megfelelő funkcióval rendelkező gombok, bármilyen elem elhelyezhető bennük, akár számcím és borító is. Meg kell adni a nyomási mechanizmust (dupla/szimpla katt).
autoShow – értéke lehet „false” és „true”. Igaz esetben zenelejátszás esetén automatikusan felbukkan, míg ha lezáráskor nem megy zene, úgy nem bukka fel.

a. Zenelejátszó előhívása:
Történhet az autoshow elemmel, valamint gombbal. Gomb használata:

<Button x="" y="" w="" h="">
<Triggers>
<Trigger action="double" target="music_control" property="visibility" value="toggle"/>
</Triggers>
</Button>

A target neve a zenelejátszó neve (célszerű „music_control”-nak meghagyni), az action a kívánt érték.

Példa:
<MusicControl x="0" y="300" name="music_control" visibility="false">
<Image name="music_album_cover" x="240" y="40" alpha="150" align="center" alignV="center" />
<!-- background image -->
<Image src="music_bg.png" x="40" y="0" alpha="100" />
<!-- Text added marquee feature, if specified width and marqueeSpeed, it will marquee text when text is wider than width -->
<Text name="music_display" x="240" y="10" w="300" marqueeSpeed="30" size="24" color="#FFFFFF" alpha="150" align="center"/>
<Button name="music_prev" x="40" y ="40" w="108" h="84">
<Normal>
<Image src="music_previous_n.png" x="40" y="40" />
</Normal>
<Pressed>
<Image src="music_previous_p.png" x="40" y="40" />
</Pressed>
</Button>
<Button name="music_next" x="332" y ="40" w="108" h="84">
<Normal>
<Image src="music_next_n.png" x="332" y="40" />
</Normal>
<Pressed>
<Image src="music_next_p.png" x="332" y="40" />
</Pressed>
</Button>
<Button name="music_play" x="186" y ="40" w="108" h="84">
<Normal>
<Image src="music_play_n.png" x="186" y="40" />
</Normal>
<Pressed>
<Image src="music_play_p.png" x="186" y="40" />
</Pressed>
</Button>
<Button name="music_pause" x="186" y ="40" w="108" h="84">
<Normal>
<Image src="music_pause_n.png" x="186" y="40" />
</Normal>
<Pressed>
<Image src="music_pause_p.png" x="186" y="40" />
</Pressed>
</Button>
</MusicControl>

13. Egyéb tippek

Különböző esetekben való megjelenítésre az alpha taget vagy a visibility taget használhatjuk.
Minden állapotban a max alpha legyen 255, amennyiben az állapotok közötti kapcsolat ÉS, akkor szorzással, ha VAGY, akkor összeadással érhetjük el a kellő állapotban megjelenítést. (Zárójelek alkalmazása hasznos lehet)

Példa:
kép mutatása, ha a telefon nem töltött állapotban van, vagy ha a telefon teljesen feltöltött, vagy ha a feloldó normalállapotban van (azaz nem megnyomási vagy végponti állapotban)

<Image src="pic.png" alpha="max(0,(1-#battery_state))*255 + max(0,(#battery_state-2))*255 + max(0,(1-#unlocker.state))*255">

Content Providerek

14. Content Providerek használata

Ez a feature egy külön cikket is megérhetne akár, de lényege röviden: amennyiben egy adott app kódja tartalmaz ContentProvider elemet, úgy az abban szolgáltatott információt kiírathatjuk a lockscreenre. Első alkalommal az 1.10.23 verzióval volt elérhető.
Leggyakrabban időjárási információkra használják a lockscreenkészítők, de különböző más funckiókra is használható, amennyiben a szükséges app a telepítve van a rendszerre: naptár adatok (események), gmail adatok, operátor, smsek szövege, hívók adatai, stb.
Használata:
Szükséges, hogy legyen egy olyan app, ami támogatja a ContentProvider használatát. (néhány rendszerfolyamat támogatja, valamint néhány külső alkalmazás is).

<VariableBinders>
<ContentProviderBinder uri="content://sample/test" uriFormat="" uriParas="" columns="col1,col2" where="" args="" order="" countName="count_name">
<Variable name="variable_name1" type="int" column="col1" row="0"/>
<Variable name="variable_name2" type="string" column="col2" row="0"/>
</ContentProviderBinder>
</VariableBinders>

VariableBinders tagbe kell foglalni a definiáló blokkot, amiben megdajuk a kinyerni szükséges változókat. Ezeket a redszer szám vagy szöveg természetű változókba fogja kiadni, amit bárhova felhasználhatunk. (szövegként kiírathatjuk, lehet forrása képnek, stb.)

ContentProviderBinder – definiál egy ContentProvidert.
változói:
uri – a contentprovider elérési útja
uriFormat – amennyiben változót is szükséges az uriba tenni, úgy a textnél használtak szerint használható az uriFormat (szám alapú változók %d, szöveges változók %s kóddal jelölendők, több is megadható)
uriParas – az uriFormat párja, a változók definiálására (szám alapú változók # jellel, szöveges változók @ jellel kezdődnek, az uriFormatban lévő kódok sorrendjében)
columns: az adatbázis melyik oszlopait akarjuk lekérdezni, vesszővel elválasztva
where – sql-hez hasonló módon, pl. where="type=3 AND new=1". Kisebb/nagyobb jelből csak a „>” jel használható, úgy kell az egyenletet forgatni, hogy így alakuljon viszonyuk.
whereFormat, whereParas – amennyiben változókat kell használnunk a where modulban
order – sqlhez hasonló módon, az adatok rendezése. Lehet ASC vagy DESC. Pl. order="date DESC"
countName – az eredmények számát egy adott nevű szám alapú változóba rögzíti

Variable – a kinyerendő változó, egy contentproviderbinderben többet is megadhatunk
változói:
name – a változó neve, később ezen a néven fogunk rá hivatkozni
type – a változó típusa. Értéke lehet: „int” (integer–számalapú), „string” (szöveg), „double”, „float”, „long” (ezt unix timestampeknél érdemes használni)
column – melyik lekérdezett oszlopból akarjuk kinyerni az adatokat
row – melyik sorból nyerjük ki az adatokat. A legelső sor a 0 szűmú. Amennyiben nem adjuk meg, úgy a 0 számú sorból nyeri ki.

Egy ContentProviderBinderben csak egy urit adhatunk meg, viszont több variable-t.
Egy manifestben egy VariableBinder tömb lehet, ebbe kell az összes ContentProverBindert betenni. Ezekből akármennyit betehetünk a tömbbe, mindben egy urival és akármennyi változóval.

Az adatok kiíratása a következő módon történik: amennyiben szöveges (string) alapú a változónk (a példa kedvéért legyen „valtozo1”), úgy @valtozo1-ként kell rá hivatkoznunk, míg ha szám alapú (int, long, float, double), úgy #valtozo1-ként. Ezt az értéket felhasználhatjuk a következőkre: használhatjuk számításokhoz változónak, kiírathajuk Text taggel, amennyiben unix timestamp, úgy DateTime taggel átlakíthatjuk tetszőleges dátumformátumba, használhatjuk kép forrásának (src) vagy számozott forrásának (srcid).

Példa: Google GenieWidget használata időjárás kiiratására (News&Weather widget)
<!-- content provider binder for google weather -->
<VariableBinders>
<ContentProviderBinder
uriFormat="content://com.google.android.apps.genie.geniewidget.weather/weather/current/%d"
uriParas="#time_sys"
columns="iconResId,location,temperature,lowTempera ture,highTemperature,description"
countName="hasweather">
<Variable name="weather_id" type="int" column="iconResId"/>
<Variable name="weather_location" type="string" column="location"/>
<Variable name="weather_temperature" type="int" column="temperature"/>
<Variable name="weather_lowTemperature" type="int" column="lowTemperature"/>
<Variable name="weather_highTemperature" type="int" column="highTemperature"/>
<Variable name="weather_description" type="string" column="description"/>
</ContentProviderBinder>
</VariableBinders>

<!-- weather info display -->
<Text visibility="#hasweather" x="240" y="60" w="360" size="24" color="#FFFFFF" alpha="200" align="center"
format="%s %s %d°C"
paras="@weather_location,@weather_description,#wea ther_temperature" />
<Text visibility="#hasweather*not(isnull(#weather_lowTem perature))*not(isnull(#weather_highTemperature))" x="240" y="85" w="360" size="22" color="#FFFFFF" alpha="200" align="center"
format="%d°C / %d°C " paras="#weather_lowTemperature,#weather_highTemper ature"/>
<Text visibility="#hasweather*isnull(#weather_lowTempera ture)*not(isnull(#weather_highTemperature))" x="240" y="85" w="360" size="22" color="#FFFFFF" alpha="200" align="center"
format="--°C / %d°C " paras="#weather_highTemperature"/>
<Text visibility="#hasweather*not(isnull(#weather_lowTem perature))*isnull(#weather_highTemperature)" x="240" y="85" w="360" size="22" color="#FFFFFF" alpha="200" align="center"
format="%d°C / --°C " paras="#weather_lowTemperature" />

<Image src="weather.png" visibility="#hasweather" x="240" y="100" srcid="#weather_id" align="center">
<PositionAnimation>
<Position x="-10" y="0" time="1000"/>
<Position x="10" y="0" time="3000"/>
<Position x="0" y="0" time="4000"/>
</PositionAnimation>
</Image>

Összefoglalás

Összefoglalás

Bár bonyolultnak tűnik, annyira nem nehéz a lockscreenek programozása, ráadásul az újabb elemekkel szinte korlátlan az alkalmazási területek száma.

A content providerek használata megér egy külön cikket, valószínűleg arról fogok is írni még egyet a közeljövőben. (Dátumot nem ígérek.)

Remélem, ezzel a „rövid kis szösszenettel” sikerült bevezetni néhányakat a lockscreenkészítés rejtelmeibe és majd látunk szép lockokat itt: Témázgatunk, témázgatunk!? ..avagy mutasd a HomeScreen-ed! (Android).

Hibajavításokat, észrevételeket, kérdéseket szívesen várom a hozzászólásokban.
-fodi (aka picard666)