AROMA – podstawowy opis instalatora i „szybki” skrypt konfiguracyjny

Przemysław Sierechan Porady 2013-01-18

Wstęp


Niniejszy przewodnik autorstwa naszego forumowicza Artura Wąsowskiego (Wall-E) stworzy prosty skrypt instalacyjny i opisze podstawowe zasady rządzące instalatorem AROMA – bez głębokiego wnikania w zawiłości i konstrukcję instalatora.

W tym tutorialu zajmę się zagadnieniami podstawowymi pozwalającymi stworzyć instalator o… powiedzmy, że o średnim stopniu skomplikowania ale jednocześnie pozwalający na wykorzystanie najużyteczniejszych – dla kucharza nie-informatyka – opcji.

Sam skrypt konfiguracyjny będzie w miarę prosty, jednak proszę nie dać zwieść się pozorom – tekstu do przeczytania w niniejszym opisie jest dużo… bardzo dużo. Dodatkowo będą używane „trudne” słowa, określenia i pojęcia…
W związku z powyższym zastanawiam się kto przeczyta taką ilość – bądź co bądź – trudnego tekstu… Ale cóż, z opisem to tak jak z kobietą: jak się zaczęło to trzeba skończyć bo w innym przypadku mogą się przyplątać symptomy nerwicy.

Na pierwszy rzut oka może się wydawać, że tematyka rozdziałów jest rozłożona nieco bałaganiarsko i nie po kolei z punktu widzenia pragmatyki tworzenia naszego skryptu… Takie wrażenie faktycznie można odnieść.
Niestety, temat jest dosyć skomplikowany i na dobrą sprawę każdy krok opisu wynika z kroku wcześniejszego albo jest z nim dosyć mocno związany. Dlatego też starałem się umieszczać informacje w kolejności logicznej – tak by następowały one po sobie i nie trzeba było ich szukać po całym opisie. Np. z tej właśnie przyczyny praktycznie na samym początku znalazły się informacje o zmiennych i formatowaniu tekstu – w dalszym opisie są one dosyć mocno wykorzystywane więc umieszczenie takich informacji zgodnie z ich „praktyczną kolejnością” wprowadziłoby bałagan informacyjny i konieczność „skakania” po treści opisu…

Tyle straszenia. Zapraszam do lektury.

[strona=”Kilka słów o AROMIE, czyli tak zwany „Ebałt””]
Kilka słów o AROMIE, czyli tak zwany „Ebałt”


AROMA Instaler to produkt autorstwa kolegi amarullz z XDA.
Jest to pierwszy na świecie, w pełni dotykowy konfigurator preinstalacji Androidowego ROMu. Oznacza to, że w zależności od chęci i ambicji twórcy skryptu instalacyjnego możesz w stopniu większym lub mniejszym dopasować instalowany ROM do swoich preferencji. Taki twór podobny do, zapewne znanych Ci, kreatorów instalacji programów w Windowsie.

Jedną z zalet instalatora jest fakt, że działa on w ROMie jako „wartość dodana” a nie wbudowana na stałe raz i na zawsze. Oznacza to, że:
– Instalator możesz dodać do praktycznie każdego posiadanego już customowego ROMu.
– Instalator możesz usunąć z ROMu jeśli takowy posiada ów instalator.
– Instalator możesz modyfikować wedle swoich potrzeb.

Warto również dodać, że instalator jest wspólny dla wszystkich urządzeń… no, przynajmniej dla większości i nie wymaga mieszania w kodzie by dostosować go do konkretnego urządzenia.

Obcowanie z AROMĄ zacząć trzeba oczywiście od samego początku.
Za „początek” rozumiem przynajmniej podstawową zdolność do rozkminiania struktury customowego ROMu (plik zip). Bardzo przydatne będzie też rozumienie nazw używanych w ROMowej kuchni oraz orientowanie się w strukturze i działaniu kilku podstawowych plików zip-owego instalatora ROMu.
Tego wszystkiego nie będę opisywał – na forum są materiały dotyczące tych zagadnień i sugeruję je przestudiować.

W tym miejscu pokuszę się o założenie, że powyższa wiedza jest w Twoim posiadaniu…

[strona=”Przygotowania”]
Przygotowania


Instalator AROMA ma służyć przede wszystim do opcjonalnej instalacji elementów naszego potencjalnego ROMu. Dlatego też w pierwszym rzędzie należy przygotować sobie ogólny zarys tego co chcemy uzyskać.
Przede wszystkim należy zastanowić się co i w jaki sposób chcemy instalować – czy będzie to program instalowany opcjonalnie, czy będzie to program instalowany wymiennie z innym, czy może będzie to jakiś inny sposób operacji na plikach.
Ukierunkowanie na konkretne rozwiązania uzyskasz po przestudiowaniu całego opisu, ale już teraz warto wspomnieć o rzeczach, które można zrobić na samym początku.

[strona=”Plikowa struktura instalacji opcjonalnej”]
Plikowa struktura instalacji opcjonalnej

Całe domyślne i interesujące nas oprogramowanie zawarte w ROMie zostało zgromadzone w folderze \system\app – dla pokazania zasady zajmijmy się tylko tym folderem.
W przedmiotowym folderze wyszukujemy pliki programów lub funkcji, które będziemy chcieli instalować opcjonalnie i przenosimy je do osobnego folderu/folderów w strukturze ROMu – nie „kopiujemy” a „całkowicie przenosimy”. Sposób rozmieszczenia owych folderów w strukturze ROMu jest całkowicie dowolny i zależy on od wyobraźni twórcy jednak ja zalecam zachowanie jakiejś elementarnej systematyki i porządku.
Oczywiście trzeba mieć pojęcie co się robi i jakie pliki wydziela się z ogólnej struktury ROMu.

Tym samym sposobem można instalować programy na zasadzie zamienności (albo taka wersja albo inna wersja) jak również dodawać programy zewnętrzne, nie będące oryginalnie częścią ROMu – np. własne programy.

Jako przykład…

W root zipa z ROMem tworzymy sobie folder… np. „Instalacje” i w nim umieścimy całą instalację opcjonalną. Może to wyglądać tak jak na poniższym przykładowym drzewku:


Instalacje/
|-Talk/
|  |-talk.apk
|-Opera/
|  |-opera.apk
|-Program_X/
|  |-Wersja_1/
|  |  |-program_X_wersja_1.apk
|  |-Wersja_2/
|     |-program_X_wersja_2.apk
|-Kernele/
|  |-Kernel_1/
|  |  |-kernel_1
|  |-Kernel_2/
|     |-kernel_2
|-Modemy/
|  |-Modem_1/
|  |  |-modem_1.bin
|  |-Modem_2
|     |-modem_2.bin
...

Powyższa struktura to tylko przykład dla zobrazowania zasady. Ową strukturę można sobie komplikować zgodnie z własnym życzeniem i potrzebami.

[strona=”Przygotowanie plików instalatora”]
Przygotowanie plików instalatora

Na początek należy pobrać binaria instalatora, które znajdziesz tutaj:

[MOD][2.56] AROMA Installer :: 121004-031 :: Open Source – post 2

Pobrany zip należy oczywiście wypakować.
W tym momencie jeszcze nie zapodajemy instalatora do ROMu – póki co skupiamy się na jego poznawaniu i edycji zawartości. Tutaj warto również zapoznać się ze strukturą instalatora (opisaną w następnym rozdziale) i zdecydować czego użyjemy do realizacji naszych planów a co usuniemy.

[strona=”Struktura instalatora”]
Struktura instalatora


Oryginalna struktura instalatora po jego wypakowaniu wygląda następująco:


aroma/
|-exec_demo/
|  |-displaycapture
|  |-exec_demo1.sh
|  |-exec_demo2.sh
|  |-sleep
|-fonts/
|  |-big.png
|  |-small.png
|-icons/
|  |-agreement.png
|  |-alert.png
|  |-apps.png
|  |-confirm.png
|  |-customize.png
|  |-default.png
|  |-info.png
|  |-install.png
|  |-license.png
|  |-personalize.png
|  |-update.png
|  |-welcome.png
|-langs/
|  |-ar.lang
|  |-cn.lang
|  |-de.lang
|  |-....lang
|-splash/
|  |-a1.png
|  |-a2.png
|  |-a3.png
|  |-....png
|-themes/
|  |-ics/
|  |-miui/
|  |-miui4/
|  |-sense/
|-ttf/
|  |-DroidSans.ttf
|  |-DroidSansArabic.ttf
|  |-DroidSansFallback.ttf
|  |-Roboto-Regular.ttf
|-unicode/
|  |-arabic.txt
|  |-chinesse.txt
|  |-russian_latin.txt
|-ams_sample.txt
|-changelog.txt
|-license.txt
|-sample.png
aroma-config
update-binary
update-binary-installer
updater-script

Ta struktura to w pewnym sensie gotowy instaler. Pakując tą strukturę do testowego zipa i uruchamiając ją poprzez CWM (tak jak ROM) będziesz miał możliwość poznanie możliwości AROMY bez dokonywania zmian na urządzeniu… Ot, taki przykład działania instalatora, demo.

Pogadajmy teraz o tym co widać na powyższym drzewku. Co nas w nim interesuje…

\aroma\
To podfolder w głównym drzewie instalatora – zawiera to co widać na powyższej rozpisce i co opisane jest nieco niżej – czyli prawie całą zawartość instalatora.

aroma-config
Główny skrypt konfiguracyjny instalatora, właśnie jego strukturę będziemy tworzyć.

update-binary
Plik binarny odpowiadający za instalację ROMu – znajduje się w każdym ROMie. W przypadku AROMY tym właśnie plikiem należy zastąpić oryginalny plik w instalacyjnym zipie ROMu. Będzie on odpowiadał za inicjalizację instalatora i jego dalsze działanie – więcej informacji na ten temat będzie później.

update-binary-installer
W oryginalnej strukturze AROMY jest to „pomocniczy plik instalacyjny” dla dema. W ROMie do którego AROMA zostanie dodana jest to oryginalny plik update-binary o nazwie zmienionej do powyższej postaci – więcej informacji na ten temat będzie później.

updater-script
Skrypt instalacyjny zawierający polecenia wykonywane podczas instalacji ROMu. To drugi plik, którego strukturę będziemy modyfikować.

\aroma\exec_demo\
Folder zawierający „silnik” pokazu dema, prezentacji, którą możemy sobie obejżeć uruchamiając oryginalną strukturę instalatora.

\aroma\fonts\
Folder zawierający kroje czcionek w postaci graficznej. Są to dwa pliki *.png z naniesionym zestawem czcionek danego kroju. Jeden plik odnosi się do czcionek o dużym rozmiarze (np. dla nagłówków), drugi dla czcionki zwykłego tekstu.
Uczciwie się przyznam, że nie wiem co na myśli miał autor kiedy stworzył to, co stworzył. Najprawdopodobniej jest to alternatywny sposób używania (również niestandardowych) krojów czcionek w tekstach wyświetlanych przez instalator. Jednak z naszego – polskiego – punktu widzenia, sposób ten może okazać się niedoskonały. Ów zestaw nie posiada naszych rodzimych znaków diakrytycznych.
Wiecej szczegółów odnośnie tego elementu znajdziesz na podanej wcześniej stronie domowej projektu.

\aroma\icons\
Folder zawierający ikonki/symbole/obrazki, które nieco przyozdobią nam wygląd UI instalatora. Ikonki umieszcza się (albo i nie) by również w sposób graficzny opisać widoczny na ekranie panel. Można używać ikonek standardowych a można je również podmienić na własne. Jeśli brakuje ikonek, można dodać własne.

\aroma\langs\
Folder zawierający pliki językowe instalatora. Pliki językowe tłumaczą tylko podstawowe elementy instalatora – przyciski, niektóre polecenia i komunikaty. Nie jest tego dużo. Oryginał nie zawiera translacji PL, ale nic nie stoi na przeszkodzie by takową sobie wyprodukować samemu. Ten sposób translacji instalatora jest jednak na tyle niedoskonały, że w praktyce nie nadaje się do tworzenia instalatorów wielojęzykowych. Głównym powodem jest to, że translacja instalatora nie ma wpływu na wpisywane przez nasz teksty, nazwy elementów wyboru, etc… Dodatkowo, na dobrą sprawę, wszystkie teksty, elementy i komunikaty możemy sobie opisać w rodzimym języku już w samym skrypcie – jeśli tworzymy instalator jednojęzykowy.
Jeśli ktoś ma dużo czasu i samozaparcia może (najprawdopodobniej) sam uzupełnić sobie pliki językowe o odpowiednie wpisy i używając odpowiednich zmiennych lub odwołań wstawiać owe teksty do paneli instalatora. Jednak nawet ten sposób nie da całkowicie przetłumaczonej treści instalatora jak się domyślam.
Na ile i w jakim stopniu można przetłumaczyć UI instalatora? Nie wiem – nie próbowałem tej metody. Ja tworzyłem instalator z założenia w języku Polskim i umieszczanie w nim innych języków generalnie mnie nie interesowało. Ograniczyłem się tylko do stworzenia pliku pl.lang poprzez przetłumaczenie istniejącej tam oryginalnie zawartości. Tyle.

\aroma\splash\
Folder zawierający obrazek wyświetlany na starcie instalatora – taki ekran powitalny. W oryginalnej strukturze tych przykładowych obrazków jest kilka do wyboru – w praktyce wystarczy jeden (wybrany z istniejących albo własny).
Splash-obrazek można sobie zrobić samemu. Co do jego zawartości nie wnikam, ważne by jego rozmiar był zgodny z rozmiarem ekranu (w pikselach).

\aroma\themes\
Folder zawierający tzw. themesy, tematy, skórki czy jak kto tam to nazywa. Każdy temat to osobny folder zawierający pliki graficzne UI i plik konfiguracyjny (theme.prop). Jeśli ktoś chce to może sobie w tym pogrzebać. Modyfikacjami tego elementu nie będziemy się zajmować.

\aroma\ttf\
Folder zawierający czcionki, których będziemy używać do wyświetlania tekstu w instalatorze. W oryginale czcionki są jakie są, ale nic nie stoi na przeszkodzie by je zmienić na swoje.

\aroma\unicode\
Folder zawierający pliki z przykładowymi tekstami w językach „krzaczkowatych” – arabskim, chińskim i rosyjskim.

\aroma\ams_sample.txt
\aroma\changelog.txt
\aroma\license.txt
\aroma\sample.png

Cztery pliki wykorzystywane w pokazowym demo a jednocześnie przykład użycia plików tekstowych w instalatorze (o tym będzie nieco dalej). Plik sample.png to splashscreen użyty w demo instalatora.

[strona=”Kilka podstawowych zmiennych”]
Kilka podstawowych zmiennych


Zagadnienie wybiegające nieco do przodu, ale pewnych określeń które zawiera będziemy musieli użyć za chwil kilka, więc warto je ogarnąć na samym początku.
Ta część nie ma na celu opisania wszystkich zmiennych, które możemy użyć przy konstruowaniu kodu skryptu AROMY. Tutaj opiszę tylko kilka z nich – tych z którymi będziemy mieli do czynienia w dalszym opisie elementów instalatora.

Zmienne globalne (dla ułatwienia i orientacji, bloki pierwszej zmiennej zostały pokolorowane)

ini_set(„rom_name”,”RononDex AtypicalROM”);
ini_set(„rom_version”,”1.0.90″);
ini_set(„rom_author”,”RononDex”);
ini_set(„rom_device”,”Samsung Galaxy S2″);
ini_set(„rom_date”,”30 grudnia 2012″);

– Opis elementów:

ini_set()
Polecenie „ustawiające” zmienną dla całego instalatora i otwarcie funkcji.

„rom_xxxx”
Nazwa zmiennej do której będziemy się odwoływać w treści kodu instalatora.

,
Przecinek rozdzielający parametry funkcji/polecenia.

„….”
Wartość wyświetlana dla zmiennej – czyli to, co zobaczymy po wywołaniu zmiennej.

Powyższe pięć linii to zmienne, które możemy zastosować podczas budowy skryptu instalacyjnego AROMY. Nie są to wartości ważne i na dobrą sprawę można ich w ogóle w ciele skryptu nie używać.
Nie mniej dla własnej wygody warto je posiadać. Przydają się w miejscach gdzie odwołujemy się do nazwy naszej produkcji, autora produkcji, daty produkcji etc… Zamiast ciągle pisywać konkretny tekst zapodajemy zmienną i po ptokach. Ma to spore znaczenie przy częstych modyfikacjach naszego ROMu. Nie musimy szukać w całym skrypcie konkretnych wartości by je zmienić – zmieniamy tylko wartości zmiennych i pozamiatane.

W treści skryptu owe zmienne wywołujemy jako:

ini_get(„rom_xxxx”)

[strona=”Możliwości edycji wyświetlanej treści”]
Możliwości edycji wyświetlanej treści


Drugi z rozdziałów wybiegających w przyszłość. Podobnie jak poprzedni zawiera on informacje użyte w dalszej części opisu.
Mimo, że to jeszcze nie jest sedno sprawy, jednak wspomnieć należy, że podczas tworzenia/edycji skryptu instalacyjnego AROMY mamy do dyspozcji – niewielki bo niewielki, ale zawsze – zestaw upiększaczy tekstu zawartego/wprowadzanego w panelach instalatora.

Format tekstu
Do formatowania tekstu służą dwa tagi:

<b> … </b> – tekst pogrubiony
<u> … </u> – tekst podkreślony

Kolor tekstu
Tagi służące do kolorowania tekstu zawierają oznaczenie wybranego koloru w postaci HEX (szesnastkowej) i występują w dwóch formach:

– tagi HEX 6-znakowe:

<#000000> … </#> – czarny
<#ffffff> … </#> – biały
<#888888> … </#> – szary
<#ff0000> … </#> – czerwony
<#00ff00> … </#> – zielony
itd…

– tagi HEX 3-znakowe:

<#000> … </#> – czarny
<#fff> … </#> – biały
<#888> … </#> – szary
<#f00> … </#> – czerwony
<#0f0> … </#> – zielony
itd…

Kolorować tekst można również za pomocą zestawów kolorów co jest bardzo przydatne jeśli nie chcemy zaburzać konwencji kolorystycznej używanego tematu.
Zestawy kolorów określone są w pliku konfiguracyjnym każdego tematu (theme.prop) znajdującym się w folderze danego tematu i ze swojej natury odpowiadają za domyślny kolor elementów interfejsu – zgodnie z konwencją kolorystyczną tematu. Nic jednak nie stoi na przeszkodzie by owe wartości użyć do własnych celów.

W pliku tematu wyglądają one tak:

color.winbg = #000
color.winbg_g = #444
color.winfg = #fff

itd…

Użycie w skrypcie jako tag:

<#winbg> … </#>
<#winbg_g> … </#>
<#winfg> … </#>

itd…

Łamanie tekstu
W standardowych panelach instalatora nie używa się klawisza „ENTER”.
Nową linię tekstu tworzy się używając znaku:

\n

– Przykład pojedynczej nowej linii:

„Zdanie jest podzielone na\ndwie części.”

Zdanie jest podzielone na
dwie części.

Sposób stosowany do wymuszenia podziału jednej linii tekstu. Co prawda tekst jest automatycznie zawijany w oknie, jednak czasami nie musi to być optymalny sposób jego podziału.

– Przykład tekstu z wieloma osobnymi liniami (blok tekstu):

„Linia 1\n”+
„Linia 2\n\n”+
„Linia 3\n”+
„Linia 4.”

Linia 1
Linia 2

Linia 3
Linia 4.

Sposób stosowany do tworzenia tzw. akapitów w całym bloku tekstu. Tekst nadal jest jedną całością ale użycie odnośnych tagów pozwala na wstawienie pomiędzy wybrane fragmenty „wolnej linii” – jednej lub więcej, w zależności od potrzeb i ilości użytych tagów.

Przykład zastosowania będzie można przeanalizować przy okazji opisu paneli AROMY.

Tworzenie list
Tworzeniu list służy tag:

<*> … </*>

– Lista prosta:

<*>element1</*>
<*>element2</*>
<*>elementX</*>

  • element1
  • element2
  • elementX

– Lista wielopoziomowa:

<*>element1</*>
<*>element2
<*>element2a</*>
<*>element2b</*></*>
<*>elementX</*>

  • element1
  • element2
    • element2a
    • element2b
  • elementX

To właściwie tyle.
Bardziej zaawansowanego formatowania tekstów AROMA niestety nie obsługuje. Ale i to co jest w zupełności wystarcza.

Przejdźmy teraz do wizualizacji naszych życzeń, czyli do typów paneli instalatora… albo jak kto woli – typów okien. Ja będę używał określenia „panele”.

[strona=”Panele – wstęp”]
Panele – wstęp


To, co finalnie zobaczymy na ekranie swojego urządzenia podczas działania instalatora to nic innego jak zwizualizowanie efektu działania FUNKCJI zawartych w skrypcie konfiguracyjnym AROMY. Wspominam ten fakt dlatego, że każde okno, które w instalatorze wywołamy to właśnie nic innego jak funkcja interpretowana i wizualizowana na ekranie przez język programistyczny wykorzystany do napisania „silnika” całego instalatora.
Co za tym idzie, zapis „kodowy” każdego panelu instalatora w pliku konfiguracyjnym musi być zgodny ze składnią odnośnych funkcji.

Składnia funkcji w instalatorze AROMA (wizualizacja paneli/okien):

typ_panela(„parametr1”, „parametr2”, „parametrX”);

Tym samym proszę się nie przestraszyć „dziwnej” budowy niektórych fragmentów (parametrów) – to wszystko jest podporządkowane ogólnym zasadom działania konkretnej funkcji.
Jednocześnie nie ukrywam, że aby zrozumieć konstrukcję niektórych parametrów należy mieć wiedzę dotyczącą podstaw aplikowania parametrów do ogólnie rozumianych funkcji ewentualnie dokładnie przeanalizować przykłady (czy to z tego opisu czy z gotowych skryptów konfiguracyjnych) i na ich podstawie budować własne konstrukcje.
Uwierzcie… to nie jest trudne. Odrobina analizy, porównań, logicznego myślenia to klucz do własnego skryptu.

Aha… jeszcze jeden ważny szczegół…
Wszystkie przykłady funkcji są przedstawione w formie funkcjonalnej, czyli w miarę możliwości zobrazowana jest kolejność następowania/wyświetlania na ekranie parametrów funkcji:

typ_panela(
„parametr1”,
„parametr2”,
„parametrX”
);

Proszę o tym pamiętać czytając i analizując budowę każdego z paneli instalatora AROMA.

Wybaczcie… Konstrukcja i zasada działania instalatora ociera się o sporą ilość dość zaawansowanych (jak dla zwykłego „zjadacza chleba”) zagadnień – a ja nie jestem w stanie opisać WSZYSTKIEGO krok-po-kroku bo bym musiał zacząć od opisywania podstaw języka C…

[strona=”Panele – „VIEWBOX()””]
Panele – „VIEWBOX()”


Panel służący tylko do wyświetlania tekstu. Zwykły panel komunikacyjny w którym można umieścić dowolny tekst przekazujący dowolne informacje – nic więcej.

– Kod dla panela (dla ułatwienia i orientacji, wszystkie jego bloki zostały pokolorowane):

viewbox(
„Welcome”,
„You are to Installing RunnyMede AIO for HTC Desire GSM (bravo).\n\n” +
„RunnyMede All In One ROM for HTC Desire GSM, Bring your old Desire Hardware Into Stunning RunnyMede’s (Sensation XL HTC Sense 3.5 With Beats Audio, yet Powerfull, Stable and Fastest HTC Sense 3.5 ROM for HTC Desire.\n\n\n” +
”  VERSION:” + ini_get(„rom_version”) + ” Special Edition\n” +
”  UPDATED:” + ini_get(„rom_date”) + „\n\n\n” +
„Press Next to continue the installation…”,
„icons/info”
);

– Opis elementów:

(1) viewbox()
Określenie typu panela i otwarcie funkcji – to pozwala instalatorowi na wyświetlenie konkretnego wyglądu panela i przypisanie mu właściwych funkcjonalności.

(2) „Welcome”,
Tekst wyświetlany w nagłówku panela, tytuł panela.

(3) „You are to Installing RunnyMede AIO for HTC Desire GSM (bravo).\n\n” +
„RunnyMede All In One ROM for HTC Desire GSM, Bring your old Desire Hardware Into Stunning RunnyMede’s (Sensation XL HTC Sense 3.5 With Beats Audio, yet Powerfull, Stable and Fastest HTC Sense 3.5 ROM for HTC Desire.\n\n\n” +
”  VERSION:” + ini_get(„rom_version”) + ” Special Edition\n” +
”  UPDATED:” + ini_get(„rom_date”) + „\n\n\n” +
„Press Next to continue the installation…”,

Informacje/tekst wyświetlane w panelu.
Cały powyższy tekst, w brew pozorom, jest jedną całością, jednym spójnym blokiem. Podział na osobne linie jaki został zastosowany w zapisie, wynika li-tylko z potrzeby wizualnego uporządkowania treści w skrypcie – ułatwia to autorowi połapanie się w tym co napisał.
Powyższy blok można również zapisać w jednej linii – którą de facto jest:

„You are to Installing RunnyMede AIO for HTC Desire GSM (bravo).\n\n” + „RunnyMede All In One ROM for HTC Desire GSM, Bring your old Desire Hardware Into Stunning RunnyMede’s (Sensation XL HTC Sense 3.5 With Beats Audio, yet Powerfull, Stable and Fastest HTC Sense 3.5 ROM for HTC Desire.\n\n\n” +  ”  VERSION:” + ini_get(„rom_version”) + ” Special Edition\n” + ”  UPDATED:” + ini_get(„rom_date”) + „\n\n\n” + „Press Next to continue the installation…”,

Dzięki użyciu tagu(ów) \n, wyświetlany tekst zostanie podzielony na osobne wiersze i całość będzie wyglądała jak na obrazku powyżej.
Jednocześnie należy pamiętać o pewnych ograniczeniach co do ilości wyświetlanego tekstu. Oczywiście wprowadzić tutaj można każdą ilość tekstu – nie ma ograniczenia – niemniej, typ panelu nie przewiduje elementu o nazwie „pasek przewijania” – powoduje to tą niedogodność, że tekst który nie zmieści się w obszarze roboczym (wyświetlanym) panelu będzie schowany pod dolną krawędzią okna, czyli będzie niewidoczny. Tym samym wymusza to oszczędne szafowanie swoimi przemyśleniami.

(4) „icons/info”
Element graficzny (ikonka), która nieco upiększy nam wygląd panelu.
Odwołanie do ikony ma formę: „folder/plik_ikony”,
gdzie:
„folder” – Jest nazwą foldera zawierającego ikony. Tu został użyty standardowy folder „icons” podfolder w folderze „aroma” (popatrz na strukturę AROMY).
„plik_ikony” – Jest nazwą pliku graficznego ikony z pominięciem jego rozszerzenia.

[strona=”Panele – „AGREEBOX()””]
Panele – „AGREEBOX()”


Panel poza wyświetlaniem zawartości pliku tekstowego oferuje również element checkbox (pole „zaptaszalne”) oraz funkcjonalność kontrolowania jego stanu. Jeśli checkbox nie jest zaznaczony, instalator wyświetla okno z powiadomieniem o tym stanie i żąda jego zmiany.
Ten panel używany jest najczęściej jako tzw. „lajsens agriment” – czyli wyświetlanie treści licencji… ewentualnie czegoś podobnego co wymaga interakcji użytkownika (np. zaakceptowania warunków).

– Kod dla panela (dla ułatwienia i orientacji, wszystkie jego bloki zostały pokolorowane):

agreebox(
„Terms of Use”,
„Please read carefully The RunnyMede\nAIO Terms of Use Below…”,
„icons/agreement”,
resread(„license.txt”),
„I Agree with this Terms Of Use…”,
„Please check the agreement…”
);

– Opis elementów:

(1) agreebox()
Określenie typu panela i otwarcie funkcji – to pozwala instalatorowi na wyświetlenie konkretnego wyglądu panela i przypisanie mu właściwych funkcjonalności.

(2) „Terms of Use”,
Tekst wyświetlany w nagłówku panela, tytuł panela.

(3) „Please read carefully The RunnyMede AIO Terms of Use Below…”,
Tekst wyświetlany pod nagłówkiem panelu.

(4) „icons/agreement”,
Element graficzny (ikonka), która nieco upiększy nam wygląd panelu.
Odwołanie do ikony ma formę: „folder/plik_ikony”,
gdzie:
„folder” – Jest nazwą foldera zawierającego ikony. Tu został użyty standardowy folder „icons” podfolder w folderze „aroma” (popatrz na strukturę AROMY).
„plik_ikony” – Jest nazwą pliku graficznego ikony z pominięciem jego rozszerzenia.

(5) resread(„license.txt”)
Polecenie odczytania treści pliku tekstowego, którego nazwa podana została w nawiasie.
Wiedzieć trzeba, że treść pliku tekstowego można formatować w ten sam sposób co tekst wpisywany bezpośrednio w skrypt instalacyjny – obowiązują te same tagi – jednak w przeciwieństwie do panelu viewbox, tutaj by uzyskać nowy wiersz należy stosować klawisz „ENTER”.
Jeśli w pliku tekstowym chcemy używać znaków diakrytycznych, plik musi zawierać kodowanie znaków UTF8 z sygnaturą – w innym przypadku znaki z ogonkami nie będą wyświetlane w instalatorze.
Przykładowy plik changelog.txt znajduje się w folderze „aroma” (popatrz na strukturę AROMY).

(6) „I Agree with this Terms Of Use…”,
Tekst wyświetlany obok checkboxa

(7) „Please check the agreement…”
Treść komunikatu wyświetlanego w przypadku próby przejścia do następnego kroku instalatora bez „zaptaszenia” checkboxa.

[strona=”Panele – „TEXTBOX()””]
Panele – „TEXTBOX()”


Panel, podobnie jak viewbox(), służy do wyświetlaniu tekstu. Zwykły panel komunikacyjny w którym można umieścić dowolny tekst przekazujący dowolne informacje – nic więcej.
Tym co różni go od viewbox() jest fakt, że treść wyświetlana pobierana jest z wcześniej utworzonego pliku tekstowego (tak jak w agreebox(), z tą jednak różnicą, że nie posiada on kontrolki checkbox). Tym samym ten panel jest w stanie wyświetlić praktycznie nieograniczoną ilość tekstu, którą można przewijać za pomocą paska przewijania.
Ten panel używany jest najczęściej jako tzw. „czenczlog”.

Tu nie ma obrazka. Panel wygląda prawie tak samo jak agreebox() – z tym, że nie ma checkboxa.

– Kod dla panela (dla ułatwienia i orientacji, wszystkie jego bloki zostały pokolorowane):

textbox(
„Changelog”,
„ROM Changelog”,
„icons/info”,
resread(„changelog.txt”)
);

– Opis elementów:

(1) textbox()
Określenie typu panela i otwarcie funkcji – to pozwala instalatorowi na wyświetlenie konkretnego wyglądu panela i przypisanie mu właściwych funkcjonalności.

(2) „Changelog”,
Tekst wyświetlany w nagłówku panela, tytuł panela.

(3) „ROM Changelog”,
Tekst wyświetlany pod nagłówkiem panelu.

(4) „icons/info”,
Element graficzny (ikonka), która nieco upiększy nam wygląd panelu.
Odwołanie do ikony ma formę: „folder/plik_ikony”,
gdzie:
„folder” – Jest nazwą foldera zawierającego ikony. Tu został użyty standardowy folder „icons” podfolder w folderze „aroma” (popatrz na strukturę AROMY).
„plik_ikony” – Jest nazwą pliku graficznego ikony z pominięciem jego rozszerzenia.

(5) resread(„changelog.txt”)
Polecenie odczytania treści pliku tekstowego, którego nazwa podana została w nawiasie.
Wiedzieć trzeba, że treść pliku tekstowego można formatować w ten sam sposób co tekst wpisywany bezpośrednio w skrypt instalacyjny – obowiązują te same tagi – jednak w przeciwieństwie do panelu viewbox(), tutaj by uzyskać nowy wiersz należy stosować klawisz „ENTER”.
Jeśli w pliku tekstowym chcemy używać znaków diakrytycznych, plik musi zawierać kodowanie znaków UTF8 z sygnaturą – w innym przypadku znaki z ogonkami nie będą wyświetlane w instalatorze.
Przykładowy plik changelog.txt znajduje się w folderze „aroma” (popatrz na strukturę AROMY).

[strona=”Panele – „SELECTBOX()” i „CHECKBOX()””]
Panele – „SELECTBOX()” i „CHECKBOX()”


Oba panele opiszę w jednym rozdziale gdyż różnice pomiędzy nimi są minimalne i dotyczą tylko jednego zagadnienia funkcjonalnego – poza tym, ich konstrukcja jest niemalże identyczna.
Panele te pozwalają na wybór (zaznaczenie) elementów, które zostaną zainstalowane razem z ROMem.

selectbox() – pozwala na wybór w trybie pojedynczej opcji – inaczej mówiąc możemy wybrać tylko jeden element ze wszystkich dostępnych w grupie lub dostępnych generalnie.

checkbox() – pozwala na wybór wszystkich dostępnych elementów – tak w każdej grupie jak i generalnie.

– Kod dla panela na przykładzie obrazka selectbox() – dla panela checkbox() należy zmienić: nazwę panela, teksty wyświetlane oraz zawartość listy (dla ułatwienia i orientacji, wszystkie jego bloki zostały pokolorowane):

selectbox(
„Select Main Mods”,
„Please Select ROM Mods Below:”,
„icons/apps”,
„mods.prop”,
„Boot Animation”, „”, 2,
„Galaxy Nexus”, „Boot animation from Galaxy Nexus ROM.”, 1,
„Generic HTC”, „Generic White HTC Quietly Brillant Boot Animation.”, 0,
„Camera”, „”, 2,
„HTC Camera 3.5 – New”, „New and No FC Error, but No 720p Video Recording.”, 1,
„HTC Camera 3.0 – Old”, „Old Camera With 720p Video Recording, but FC Error in Preview”, 0,
…..
);

– Opis elementów:

(1) selectbox()
Określenie typu panela i otwarcie funkcji – to pozwala instalatorowi na wyświetlenie konkretnego wyglądu panela i przypisanie mu właściwych funkcjonalności.

(2) „Select Main Mods”,
Tekst wyświetlany w nagłówku panela, tytuł panela.

(3) „Please Select ROM Mods Below:”,
Tekst wyświetlany pod nagłówkiem panelu.

(4) „icons/apps”,
Element graficzny (ikonka), która nieco upiększy nam wygląd panelu.
Odwołanie do ikony ma formę: „folder/plik_ikony”,
gdzie:
„folder” – Jest nazwą foldera zawierającego ikony. Tu został użyty standardowy folder „icons” podfolder w folderze „aroma” (popatrz na strukturę AROMY).
„plik_ikony” – Jest nazwą pliku graficznego ikony z pominięciem jego rozszerzenia.

(5) „mods.prop”,
Nazwa i rozszerzenie tymczasowego pliku, który zostanie automatycznie utworzony przez instalator. Plik ten będzie zawierał nasze wybory dokonane w tym panelu.
Podana tutaj nazwa pliku jest przykładowa. Może ona przybrać dokładnie dowolną formę w zależności od naszych potrzeb. Dosyć wygodną i powszechnie stosowaną zasadą jest tworzenie nazwy pliku zgodnej z typem instalowanych elementów – np. jeśli panel dotyczy instalowania kerneli, nazwa pliku może brzmieć: kernels.prop, przy instalowaniu modemów: modems.prop, aplikacji: apps.prop etc.
Jest to o tyle wygodne, że do nazw tych plików odwoływać będziemy się w innym, później modyfikowanym pliku a taka zasada nazewnictwa może dość mocno ułatwić pracę.

(6) Elementy listy – opis tworzenia znajduje się w jednym z następnych rozdziałów.

„Boot Animation”, „”, 2,
„Galaxy Nexus”, „Boot animation from Galaxy Nexus ROM.”, 1,
„Generic HTC”, „Generic White HTC Quietly Brillant Boot Animation.”, 0,
„Camera”, „”, 2,
„HTC Camera 3.5 – New”, „New and No FC Error, but No 720p Video Recording.”, 1,
„HTC Camera 3.0 – Old”, „Old Camera With 720p Video Recording, but FC Error in Preview”, 0,
…..

[strona=”Panele – „INSTALL()”””]
Panele – „INSTALL()””


Na wygląd tego panela niestety nie mamy zbyt dużego wpływu. Panel ten służy jedynie do pokazania postępu instalacji naszego ROMu – mówiąc krótko, wyświetla on efekt działania pliku updater-script. Proces instalacji, jak i jego zakończenie widoczne jest na poniższych screenach.
Najczęściej jest to przedostatni w kolejności panel instalatora.

install(
„Installing”,
„Installing RunnyMede AIO…\nPleade Wait Until it Finished…”,
„icons/info”
);

– Opis elementów:

(1) install()
Określenie typu panela i otwarcie funkcji – to pozwala instalatorowi na wyświetlenie konkretnego wyglądu panela i przypisanie mu właściwych funkcjonalności.

(2) „Installing”,
Tekst wyświetlany w nagłówku panela, tytuł panela.

(3) „Installing RunnyMede AIO…\nPleade Wait Until it Finished…”,
Tekst wyświetlany pod nagłówkiem panelu.

(4) „icons/info”
Element graficzny (ikonka), która nieco upiększy nam wygląd panelu.
Odwołanie do ikony ma formę: „folder/plik_ikony”,
gdzie:
„folder” – Jest nazwą foldera zawierającego ikony. Tu został użyty standardowy folder „icons” podfolder w folderze „aroma” (popatrz na strukturę AROMY).
„plik_ikony” – Jest nazwą pliku graficznego ikony z pominięciem jego rozszerzenia.

Jak na powyższych screenach widać, panel zawiera pasek postępu instalacji. Owszem jest takowy i nawet fajnie wygląda jeśli działa. Właśnie – „jeśli działa”. Niestety nie jest to automat i tylko od nas zależy czy będzie on działał czy nie. Pasek postępu jest „napędzany” poleceniami z pliku updater-script i tylko od nas zależy jak zostanie wyskalowany – ale o tym przy okazji edycji updater-scripta, czyli w jednym z kolejnych rozdziałów.

[strona=”Panele – „CHECKVIEWBOX()””]
Panele – „CHECKVIEWBOX()”


Panel viewbox() z polem „zaptaszalnym”, czyli checkboxem. Stosowany najczęściej jako ostatni w kolejności panel instalatora, czyli powiadomienie o zakończeniu instalowania ROMu na urządzeniu. Jednak jeśli ktoś mocno rozkminił wszystkie możliwości AROMY, to może go użyć wcześniej do własnych niecnych celów.

checkviewbox(
„Installation completed”,
„<#selectbg_g>Congratulations…</#>\n\nThe selected components have been installed on your device.”,
„icons/info”
„Reboot your device now.”,
„0”,
„rebot_it”
);

– Opis elementów:

(1) checkviewbox()
Określenie typu panela i otwarcie funkcji – to pozwala instalatorowi na wyświetlenie konkretnego wyglądu panela i przypisanie mu właściwych funkcjonalności.

(2) „Installation completed”,
Tekst wyświetlany w nagłówku panela, tytuł panela.

(3) „<#selectbg_g>Congratulations…</#>\n\nThe selected components have been installed on your device.”,
Tekst wyświetlany pod nagłówkiem panelu.

(4) „icons/info”
Element graficzny (ikonka), która nieco upiększy nam wygląd panelu.
Odwołanie do ikony ma formę: „folder/plik_ikony”,
gdzie:
„folder” – Jest nazwą foldera zawierającego ikony. Tu został użyty standardowy folder „icons” podfolder w folderze „aroma” (popatrz na strukturę AROMY).
„plik_ikony” – Jest nazwą pliku graficznego ikony z pominięciem jego rozszerzenia.

(5) „Reboot your device now.”,
Tekst wyświetlany obok checkboxa.

(6) „0”,
Stan checkboxa: 0 – niezaznaczony, 1 – zaznaczony.

(7) „reboot_it”
Nazwa checkboxa. Tutaj przykładowa. Ten element możesz nazwać dowolnie.

Jednak taka konstrukcja daje nam w sumie niewiele bo jest niepełna.
Używając takiego zapisu osiągniemy tylko to, że po wciśnięciu przycisku „Dalej” (czy jak on tam będzie się nazywał) wyjdziemy do trybu Recovery – w tym przypadku oczywiście. I dobrze to i źle. „Dobrze”, bo jeśli komuś to pasuje, to może zostawić sobie taką niedoróbkę w czym sensu generalnie nie widzę, „źle”, bo jak ktoś chce cieszyć się pełnią funkcjonalności tego panela to musi dopisać sobie jeszcze co nieco.
Owo „co nieco” to polecenie lub funkcja, która zostanie wywołana po naciśnięciu przycisku „Dalej” (czy jak on tam będzie się nazywał) w przypadku gdy checkbox będzie miał status 1 (będzie zaznaczony).
W naszym przypadku potrzebna będzie funkcja, która w zależności od stanu checkboxa przeniesie nas do trybu Recovery (0) albo spowoduje automatyczny restart urządzenia (1) – czyli poniższy kod, który umieścimy zaraz po znaczniku zamknięcia panelu checkviewbox() (1b):

if
getvar(„reboot_it”)==”1″
then
reboot(„now”);
endif;

Nie będę rozkładał tej funkcji na części a opiszę tylko jej zasadę działania, która jest prosta jak miecz Jagiełły:
– jeśli checkbox będzie zaznaczony (1) to naciśnięcie przycisku „Dalej” (czy jak on tam będzie się nazywał) spowoduje automatyczny restart urządzenia.
– jeśli checkbox będzie niezaznaczony (0) to naciśnięcie przycisku „Dalej” (czy jak on tam będzie się nazywał) spowoduje powrót do trybu Recovery.
Ot, cała filozofia tej funkcji.
Jak to będzie wyglądało w skrypcie konfiguracyjnym AROMY zobaczymy już niebawem.

[strona=”Lista elementów dla paneli „SELECTBOX()” i „CHECKBOX()””]
Lista elementów dla paneli „SELECTBOX()” i „CHECKBOX()”


Zasady ogólne

– Konwencja zapisu:

„Galaxy Nexus”, „Boot animation from Galaxy Nexus ROM.”, 1,

– Opis elementów:

„Galaxy Nexus”,
Nazwa elementu.

„Boot animation from Galaxy Nexus ROM.”,
Opis elementu (nie jest wymagany, ale usuwając jego treść należy pozostawić oba cudzysłowy).

1,
Znacznik, który wskazuje instalatorowi typ danego elementu lub czynność którą ma w stosunku do niego wykonać.

I tak:
„0” – element domyślnie odznaczony (zostanie wyświetlony jako niezaznaczony i nie będzie instalowany jeśli go nie zaznaczymy)
„1” – element domyślnie zaznaczony (zostanie wyświetlony jako zaznaczony i będzie instalowany jeśli tego nie zmienimy)
„2” – oznaczenie grupy elementów (o tym za chwilę)
„3” – element ukryty

W tym miejscu proszę zwrócić uwagę na przecinek następujący po cyfrze znacznika. Występuje on we wszystkich pozycjach listy za wyjątkiem ostatniej pozycji listy – tej przed nawiasem zamykającym funkcję (1b).

Tworzenie listy elementów
Tworzenie listy możemy zrealizować na dwa sposoby:

– Lista prosta/ciągła:

„Galaxy Nexus”, „Boot animation from Galaxy Nexus ROM.”, 1,
„Generic HTC”, „Generic White HTC Quietly Brillant Boot Animation.”, 0,
„HTC Camera 3.5 – New”, „New and No FC Error, but No 720p Video Recording.”, 1,
„HTC Camera 3.0 – Old”, „Old Camera With 720p Video Recording, but FC Error in Preview”, 0,
….

W tym przypadku mamy do czynienia z jednorodną i ciągłą listą elementów. Przykład takiej listy mamy na screenie dla panela checkbox() – eliminując oczywiście belkę z napisem Applications.

– Lista pogrupowana:

„Boot Animation”, „”, 2,
„Galaxy Nexus”, „Boot animation from Galaxy Nexus ROM.”, 1,
„Generic HTC”, „Generic White HTC Quietly Brillant Boot Animation.”, 0,
„Camera”, „”, 2,
„HTC Camera 3.5 – New”, „New and No FC Error, but No 720p Video Recording.”, 1,
„HTC Camera 3.0 – Old”, „Old Camera With 720p Video Recording, but FC Error in Preview”, 0,
…..

W powyższym przykładzie widzimy dwie linie ze znacznikiem 2, które w tym przypadku tworzą nam dwie grupy programów: „Boot Animation” i „Camera„.

O ile w przypadku panela checkbox() ów podział ma znaczenie czysto kosmetyczne – pozwala na bardziej przejrzyste ułożenie listy, o tyle w przypadku panela selectbox() takowy podział tworzy nam niezależne grupy wyboru opcjonalnego – w każdej z nich mamy do wyboru zawarte w tej konkretnej grupie opcje.

Jak to wygląda w praktyce można zobaczyć na screenie dla panela selectbox().

Obie powyższe metody tworzenia list elementów można stosować dla paneli selectbox() i checkbox() – w zależności od potrzeb.

O ile sama konstrukcja paneli nie różni się znacząco, o tyle „oznaczenie” – a co za tym idzie i odwołania do poszczególnych elementów obu paneli różnią się zdecydowanie.

Należy mieć świadomość, że każde zaznaczenie/wybranie/zaptaszenie elementu na liście wyboru jest przenoszone do tymczasowego pliku *.prop tworzonego przez instalator dla każdego panela oferującego wybór elementów. Na tej podstawie przeprowadzana jest instalacja odpowiednich elementów.

Oznaczanie elementów dla „SELECTBOX()”
Jak wspomniałem wcześniej panel może zwierać dwa rodzaje list elementów do instalacji – prostą i pogrupowaną. Pomijając nawet ten szczegół, należy wspomnieć, że „systemowe” oznaczenie wyboru konkretnego elementu różni się od tego stosowanego w panelu checkbox()

– Oznaczanie dla listy prostej (dla uproszczenia zapis elementu został zredukowany a oznaczenie następuje po znaku „#”):

„Galaxy Nexus”, „…”, 1, # selected.0 == 1
„Generic HTC”, „…”, 0, # selected.0 == 2
„HTC Camera 3.5 – New”, „…”, 1, # selected.0 == 3
„HTC Camera 3.0 – Old”, „…”, 0, # selected.0 == 4

Oczywiście wyrażenia selected.X == Y nie umieszczamy w skrypcie konfiguracyjnym. Ten zapis generowany jest automatycznie i trafia do tymczasowego pliku *.prop – do takiego oznaczenia elementu będziemy się odwoływali w innych plikach.

I tak:
„selected” – Oznacza, że jest to element listy wyboru opcjonalnego – można wybrać tylko jeden element z listy lub grupy.
„X” – Oznacza kolejny numer grupy elementów (1, 2, 3…). W tym przypadku lista nie jest pogrupowana, więc użyte zostało 0 (zero).
„== Y” – Oznacza kolejny numer elementu w grupie lub na liście – w tym przypadku jest to numer kolejny elementu na całej liście (brak grupowania).

– Oznaczanie dla listy pogrupowanej (dla uproszczenia zapis elementu został zredukowany a oznaczenie następuje po znaku „#”):

„Boot Animation”, „”, 2, # selected.1
„Galaxy Nexus”, „…”, 1, # selected.1 == 1
„Generic HTC”, „…”, 0, # selected.1 == 2
„Camera”, „”, 2, # selected.2
„HTC Camera 3.5 – New”, „…”, 1, # selected.2 == 1
„HTC Camera 3.0 – Old”, „…”, 0, # selected.2 == 2

Oczywiście wyrażenia selected.X == Y nie umieszczamy w skrypcie konfiguracyjnym. Ten zapis generowany jest automatycznie i trafia do tymczasowego pliku *.prop – do takiego oznaczenia elementu będziemy się odwoływali w innych plikach.

I tak:
„selected” – Oznacza, że jest to element listy wyboru opcjonalnego – można wybrać tylko jeden element z listy lub grupy.
„X” – Oznacza kolejny numer grupy elementów (1, 2, 3…). W powyższym przykładzie „Boot Animation” jest grupą nr 1, „Camera” jest grupą nr 2, kolejna linia ze znacznikiem 2 będzie grupą nr 3 itd.
„== Y” – Oznacza kolejny numer elementu w grupie lub na liście – w tym przypadku jest to numer kolejny elementu w grupie.

Oznaczanie elementów dla „CHECKBOX()”

– Oznaczanie dla listy prostej (dla uproszczenia zapis elementu został zredukowany a oznaczenie następuje po znaku „#”):

„Galaxy Nexus”, „…”, 1, # item.1.1 == Z
„Generic HTC”, „…”, 0, # item.1.2 == Z
„HTC Camera 3.5 – New”, „…”, 1, # item.1.3 == Z
„HTC Camera 3.0 – Old”, „…”, 0, # item.1.4 == Z

Oczywiście wyrażenia item.X.Y == Z nie umieszczamy w skrypcie konfiguracyjnym. Ten zapis generowany jest automatycznie i trafia do tymczasowego pliku *.prop – do takiego oznaczenia elementu będziemy się odwoływali w innych plikach.

I tak:
„item” – Oznacza, że jest to element listy wielokrotnego wyboru – można wybrać dowolną ilość elementów z listy.
„X” – Oznacza kolejny numer grupy elementów (1, 2, 3…). W tym przypadku lista nie jest pogrupowana, więc każdy element tej listy posiada w tym miejscu 1.
„Y” – Oznacza kolejny numer elementu w grupie lub na liście – w tym przypadku jest to numer kolejny elementu na całej liście (brak grupowania).
„== Z” – Oznacza czy element jest „zaznaczony” (wybrany do instalacji) czy „odznaczony”. W tym miejscu wystąpi tylko wartość 1 – w przypadku zaznaczenia elementu na liście. Wartości 0 (zero) nie stosuje się w odwołaniu do elementów z prostej przyczyny… 0 (zero) to wartość domyślna każdego niezaznaczonego (nie wybranego) elementu – jeśli element nie jest zaznaczony (nie jest wybrany) to jest pomijany przez instalator.

– Oznaczanie dla listy pogrupowanej (dla uproszczenia zapis elementu został zredukowany a oznaczenie następuje po znaku „#”):

„Boot Animation”, „”, 2, # item.1
„Galaxy Nexus”, „…”, 1, # item.1.1 == Z
„Generic HTC”, „…”, 0, # item.1.2 == Z
„Camera”, „”, 2, # item.2
„HTC Camera 3.5 – New”, „…”, 1, # item.2.1 == Z
„HTC Camera 3.0 – Old”, „…”, 0, # item.2.2 == Z

Oczywiście wyrażenia item.X.Y == Z nie umieszczamy w skrypcie konfiguracyjnym. Ten zapis generowany jest automatycznie i trafia do tymczasowego pliku *.prop – do takiego oznaczenia elementu będziemy się odwoływali w innych plikach.

I tak:
„item” – Oznacza, że jest to element listy wielokrotnego wyboru – można wybrać dowolną ilość elementów z listy.
„X” – Oznacza kolejny numer grupy elementów (1, 2, 3…). W powyższym przykładzie „Boot Animation” jest grupą nr 1, „Camera” jest grupą nr 2, kolejna linia ze znacznikiem 2 będzie grupą nr 3 itd.
„Y” – Oznacza kolejny numer elementu w grupie lub na liście – w tym przypadku jest to numer kolejny elementu w grupie.
„== Z” – Oznacza czy element jest „zaznaczony” (wybrany do instalacji) czy „odznaczony”. W tym miejscu wystąpi tylko wartość 1 – w przypadku zaznaczenia elementu na liście. Wartości 0 (zero) nie stosuje się w odwołaniu do elementów z prostej przyczyny… 0 (zero) to wartość domyślna każdego niezaznaczonego (nie wybranego) elementu – jeśli element nie jest zaznaczony (nie jest wybrany) to jest pomijany przez instalator.

[strona=”Skrypt – podstawy konstrukcji”]
Skrypt – podstawy konstrukcji


Rozdział jeden, ale konkretny…
Na samym początku nadmienię, że wszystko co można (i jak można) zrobić w skrypcie konfiguracyjnym instalatora znajduje się w pliku skryptu w pobranym przez nas wcześniej zipie z AROMĄ. Jednak uprzedzam – treści w pliku jest od cholery i trochę…
Tak czy owak, na samym początku umawialiśmy się na prosty skrypt i taki też on będzie.

Proszę się nie obawiać, bo właśnie teraz doszliśmy do zagadnień najprostszych i najprzyjemniejszych. Tak właśnie, najprzyjemniejszych. Dysponowanie wiedzą nabytą w poprzednich postach powoduje, że tworzenie skryptu instalatora staje się czystą (choć nieco perwersyjną – nie ukrywajmy tego) przyjemnością.

Dla celów prezentacyjnych posłużę się tutaj własnym skryptem, który wyprodukowałem dla ROMu RononDex AtypicalROM.
W tym miejscu podziękowania dla Ryrzego, który w dużym stopniu pomógł mi doprowadzić te wszystkie czary do formy strawnej dla przeciętnego dłubacza.

Przykładowy skrypt – tak dla ułatwienia i orientacji – podzielę na części, a treść opatrzę komentarzami w miejscach tego wymagających. Tym samym większość kodu nie zostanie opisana bo wszystkie odnośne opisy znajdują się w poprzednich rozdziałach tutoriala.
Mam nadzieję, że posiadając wiedzę zawartą w częściach poprzednich nie będzie problemu z rozkminieniem poniższego przykładu.

# 1. Skrypt rozpoczynamy znanymi już wcześniej pięcioma zmiennymi:

ini_set(„rom_name”, „RononDex AtypicalROM”);
ini_set(„rom_version”, „1.0.90”);
ini_set(„rom_author”, „RononDex”);
ini_set(„rom_device”, „Samsung Galaxy S2”);
ini_set(„rom_date”, „30 grudnia 2012”);

# 2. Jeśli chcemy użyć splashscreena – a pewnie chcemy użyć – umieszczamy w skrypcie poniższą linię:

splash(4000, „atypical”);

# gdzie:
splash() – Funkcja odpowiadająca za wyświetlenie ekranu powitalnego.
4000, – Czas wyświetlania splashscreena (w ms)
„atypical” – Nazwa pliku graficznego splashscrena. W tym konkretnym przypadku grafika ma nazwę atypical.png i jest zlokalizowana bezpośrednio w folderze „aroma”. W przypadku innej lokalizacji należy podać również folder zawierający ową grafikę np. „splash/atypical”

# 3. Jeśli chcemy używać translacji interfejsu instalatora, musimy załadować odpowiedni język UI. Realizujemy to poniższą funkcją:

loadlang(„langs/pl.lang”);

# W tym miejscu może przyjść pomysł pójścia na łatwiznę i przetłumaczenia pliku en.lang – zdawałoby się domyślnego dla AROMY – co niby załatwi nam sprawę translacji UI instalatora. Nic bardziej błędnego. Domyślnie instalator nie korzysta z tych plików i trzeba mu paluchem pokazać, że takowego pliku ma używać.
Myślę, że składnia funkcji jest już zrozumiała.
Tego typu wywołanie sprawdzi się dla mono-językowego instalatora. Jeśli chcemy stworzyć instalator typu multi-lingłidż to musimy sięgnąć do przykładowego skryptu instalacyjnego o którym była mowa wcześniej.

# 4. Aby załadować kroje czcionek których ma używać instalator do wyświetlania treści, używamy poniższej funkcji:

fontresload(„0”, „ttf/Roboto-Regular.ttf”, „12”);
fontresload(„1”, „ttf/Roboto-Regular.ttf”, „18”);

# gdzie:
fontresload() – Nazwa funkcji ładująca kroje czcionek.
„0”, lub „1”,0 dla czcionki mającej wyświetlać „normalny” tekst, 1 dla czcionki tekstów nagłówkowych (dużych).
„ttf/Roboto-Regular.ttf”, – Lokalizacja i nazwa pliku czcionki (*.ttf). Plik czcionki jak i jego lokalizacja jest tutaj tylko przykładem i każdy dobierze je sobie wg własnego widzi-mu-się.
„12” lub „18” – Rozmiar czcionki którą ma być wyświetlany tekst odpowiednio dla tekstów „zwykłych” i nagłówkowych. Obie liczby są tutaj tylko przykładem i każdy dobierze je sobie wg własnego widzi-mu-się.
Proste? Proste.

# 5. Wygląd graficzny całego UI instalatora załatwiamy funkcją:

theme(„ics”);

# gdzie:
theme() – Nazwa funkcji ładującej temat.
„ics” – Nazwa foldera z wybranym tematem.

# Jeśli chcemy stworzyć instalator z możliwością wyboru tematu to musimy sięgnąć do przykładowego skryptu instalacyjnego o którym była mowa wcześniej.

# 6. I wreszcie to, co zobaczymy na ekranie, czyli panele. Mając w pamięci informacje z poprzednich postów, proszę o uważne prześledzenie i analizę poniższego przykładu. Panele będą wyświetlane zgodnie z kolejnością ich umieszczenia w skrypcie.
Jeszcze jedna drobna uwaga. W swoim skrypcie wolałem używać paneli textbox() zamiast viewbox() ze względu na ilość użytego przeze mnie tekstu – panele viewbox() nie pomieściłyby tyle.

textbox(
„PODZIĘKOWANIA”,
„Bez nich ten ROM by nie powstał. Doceniam ich wiedzę, chęci i cierpliwość. Chylę czoła…”,
„icons/greets”,
resread(„greets.txt”)
);

textbox(
„WSTĘP”,
„Podstawowe informacje o ROMie: <b>” + ini_get(„rom_name”)</b>”,
„icons/info”,
resread(„info.txt”)
);

agreebox(
„KILKA ZASAD…”,
„Na co się zgadzam i o co proszę…”,
„icons/agreement”,
resread(„agree.txt”),
„Zgadzam się.”,
„Proszę zaakceptować zasady.”
);

textbox(
„LISTA ZMIAN”,
„Zmiany w kolejnych wersjach” + ini_get(„rom_name”),
„icons/info”,
resread(„changelog.txt”)
);

selectbox(
„METODA PREINSTALACJI”,
„<b><#f00>WAŻNE:</#></b>\n”+”<b><#f00>Robiąc FULL WIPE NA STOCKOWYM KERNELU możesz zabić urządzenie !!!</#></b>\n\n”+
„Upewnij się, że Twoje urządzenie posiada <b><#0f0>bezpieczny kernel</#></b>.”,
„icons/alert”,
„wipe.prop”,
„Bez FULL WIPE systemu”, „Ustawienia i dane użytkownika pozostaną na urządzeniu.\n” + „<b><#f00>TYLKO WTEDY, GDY WIESZ CO ROBISZ</#></b>”, 0,
„FULL WIPE systemu”, „Ustawienia ROMu i dane użytkownika zostaną usunięte.\n” + „<b><#0f0>ZALECANE</#></b>”, 1,
„FULL WIPE systemu i baterii”, „Ustawienia ROMu, baterii i dane użytkownika zostaną usunięte.\n” + „<b><#0f0>ZALECANE (bateria w pełni naładowana)</#></b>”, 0
);

selectbox(
„KERNELE”,
„Wybierz kernel do zaflashowania na urządzeniu.”,
„icons/apps”,
„kernels.prop”,
„Philz 3.81”, „Modyfikowany z <b>Touch-Recovery</b>.”, 1,
„Jeboo 1.1a”, „Modyfikowany bez <b>Touch-Recovery</b>.\n” + „Zawiera fix dla Exynos Exploit i buga LS.”, 0
);

selectbox(
„MODEMY”,
„Wybierz modem do zaflashowania na urządzeniu.”,
„icons/apps”,
„modems.prop”,
„XXLS6”, „Oryginalny z romu XXLSJ.”, 1,
„BVLP7”, „Alternatywny z Androida 4.0.x.”, 0,
„XXLQ6”, „Alternatywny z Androida 4.0.x.”, 0,
„NELP4”, „Alternatywny z Androida 4.0.x.”, 0
);

selectbox(
„MODYFIKACJE”,
„Drobne modyfikacje niektórych elementów…”,
„icons/apps”,
„mods.prop”,
„APARAT/GALERIA”, „”, 2,
„Brak”, „Aparat i galeria nie zostaną zainstalowane.”, 1,
„Android 4.1 Stock”, „Oryginalny aparat, oryginalna galeria.”, 0,
„Android 4.1 Mod”, „Oryginalny aparat, galeria z NOTE2.”, 0,
„Android 4.2 Stock”, „Aparat i galeria z Androida 4.2.”, 0,
„Android 4.1 i 4.2”, „Obie stockowe wersje – z 4.1 i 4.2.”, 0,
„ZEGAR/BUDZIK/STOPER”, „”, 2,
„Brak”, „Zegar nie zostanie zainstalowany.”, 1,
„Android 4.1”, „Oryginalny zegar/budzik/stoper.”, 0,
„Android 4.2”, „Zegar/budzik/stoper z Androida 4.2.”, 0,
„Android 4.1 i 4.2”, „Obie stockowe wersje – z 4.1 i 4.2.”, 0,
„ODTWARZACZ WIDEO”, „”, 2,
„Brak”, „Odtwarzacz nie zostanie zainstalowany.”, 1,
„Oryginalny”, „Oryginalny odtwarzacz wideo.”, 0,
„Modyfikowany”, „Modyfikowany odtwarzacz wideo.\n” + „Animowany podgląd miniatur.”, 0,
„WIDŻET POGODOWY ACCUWEATHER”, „”, 2,
„Brak”, „Widżet nie zostanie zainstalowany.”, 1,
„Oryginalny”, „Oryginalny widżet pogodowy.”, 0,
„Modyfikowany”, „Modyfikowany widżet pogodowy.\n” + „Półprzeźroczysty widżet.”, 0
);

checkbox(
„INSTALACJA ELEMENTÓW”,
„Elementy instalacji spersonalizowanej”,
„icons/apps”,
„customize.prop”,
„NARZĘDZIA”, „”, 2,
„Note My Files”, „Systemowy menedżer plików.”, 0,
„Total Commander”, „Menedżer plików oraz pluginy.”, 1,
„ES FileExplorer”, „Menedżer plików.”, 0,
„Hide It Pro”,”Ukrywanie wybranych danych.”, 0,
„ZArchiver”, „Zarządzanie archiwami danych.”, 0,
„GO Backup”, „Tworzenie kopii zapasowych danych użytkownika.”, 1,
„ELEMENTY EKRANU I WIDŻETY (system)”, „”, 2,
„Analog Clock Simple”, „Prosty zegar analogowy.”, 1,
„Analog Clock Unique”, „Ozdobny zegar analogowy.”, 0,
„Days”, „Widżet podglądu zdarzeń i notatek.”, 0,
„Digital Clock”, „Zegar cyfrowy.”, 1,
„Dual Clock Analog”, „Podwójny zegar analogowy.”, 0,
„Dual Clock Digital”, „Podwójny zegar cyfrowy.”, 0,
„GenieWidget”, „Newsy i pogoda.”, 0,
„Planner Widget”, „Widżet terminarza.”, 1,
„Samsung Widget FavoriteApp”, „Widżet ulubionych aplikacji i ustawień.”, 1,
„Samsung Widget ProgramMonitor”, „Widżet systemowego menedżera zadań.”, 1,
„Simple Favorites Widget”, „Widżet ulubionych kontaktów.”, 1,
„Simple Alarm Clock”, „Widżet budzika i alarmów.”, 1,
„Yahoo News Widget”, „Widżet newsów Yahoo.”, 0,
„Yahoo Stock Widget”, „Widżet Yahoo.”, 0,
„MULTIMEDIA, HUBY, CZYTNIKI (system)”, „”, 2,
„Odtwarzacz muzyki”, „Systemowy odtwarzacz muzyki.”, 1,
„Allshare”, „Udostępnianie mediów innym urządzeniom DLNA.”, 0,
„FlashPlayer”, „Wsparcie odtwarzania animacji Flash.”, 1,
„Game Hub”, „Hub gier.”, 0,
„Music Hub”, „Hub muzyczny.”, 0,
„Video Hub”, „Hub Wideo.\n” + „Działa tylko w wybranych regionach.”, 0,
„Help Hub”, „Hub pomocy.”, 0,
„Readers Hub”, „Hub czytników.”, 0,
„Zinio”, „Czytnik czasopism\n” + „Wymaga Readers Huba.”, 0,
„PressReader”, „Czytnik prasy.\n” + „Wymagany przez Readers Hub.”, 0,
„Kobo”, „Czytnik ebooków\n” + „Wymagany przez Readers Hub.”, 0,
„Polaris Viewer”, „Przeglądarka plików Office.\n” + „Pliki DOC, XLS etc.”, 1,
„SIECI I KOMUNIKACJA (system)”, „”, 2,
„ChatON”, „Komunikator by Samsung.”, 0,
„Talk”, „Komunikator peer-to-peer\n” + „Tylko dla urządzeń Samsung.”, 0,
„Dropbox”, „Obsługa konta i usługi Dropbox.”, 0,
„Google Plus”, „Sieć społecznościowa Google.”, 0,
„SNS”, „Sieć społecznościowa Facebook.”, 0,
„sCloud”, „Implementacja i obsługa usług chmury.”, 0,
„GroupCast”, „Rozsyłanie grupowe.”, 0,
„MobilePrint”, „Wsparcie drukowania sieciowego.\n” + „Tylko dla drukarek Samsung.”, 0,
„Youtube”, „Przeglądarka YouTube.”, 1,
„ELEMENTY SAMSUNGA (system)”, „”, 2,
„Samsung Kies”, „Kies, Kies WiFi, Kies Air.”, 1,
„Samsung Services”, „DataCreate, FactoryTest, lcdtest, SelfTestMode.”, 0,
„Samsung Update”, „Aktualizacja oprogramowania pokładowego OTA (Over The Air).”, 0,
„Samsung Apps”, „Market z aplikacjami prowadzony przez Samsunga.”, 0,
„Samsung Fonts”, „Dodatkowe czcionki systemowe.\n” + „Choco, Cool, Rose, Helvetica.”, 0,
„Samsung TTS”, „Funkcje rozpoznawania mowy i obsługi głosowej.”, 0,
„INNE ELEMENTY (system)”, „”, 2,
„Tapety animowane”, „Systemowe tapety animowane.\n” + „Mikroby, Nexus, Ocean, Trawa etc.”, 0,
„Tapety animowane, dodatkowe”, „Dwie dodatkowe tapety animowane.\n” + „Tablica zdjęć, S3 Dandelion.”, 1,
„Talkback”, „Opcje lepszej dostępności dla osób niedowidzących.”, 0,
„Voice Recorder”, „Rejestrator głosu.”, 0,
„Mini Diary”, „Mini pamiętnik.”, 0,
„Facelock”, „Blokada ekranu – rozpoznawanie twarzy.”, 0,
„KLAWIATURY EKRANOWE”, „”, 2,
„Klawiatura Swype”, „Systemowa klawiatura Swype.”, 0,
„Klawiatura Android”, „Klawiatura Android z obsługą gestów.\n” + „Port z Androida 4.2.”, 0,
„Klawiatura Emoji”, „Klawiatura ze wsparciem Emoji.\n” + „Port z Androida 4.2.”, 0,
„PRZYWRACANIE ELEMENTÓW SYSTEMOWYCH”, „”, 2,
„Języki systemowe”, „Wszystkie języki CSC (wybierane przy prekonfiguracji systemu).\n”+”Wymaga przywrócenia SŁOWNIKÓW systemowych.”, 0,
„Słowniki i układy systemowe”, „Wszystkie słowniki i układy klawiatur.\n” + „Bez przywracania języków systemowych są zbędne.”, 0,
„Czcionki systemowe”, „Wszystkie nie-europejskie czcionki.\n” + „(arabskie, hebrajskie, tajskie, etiopskie, chińskie etc.)”, 0,
„Dźwięki systemowe”, „Wszystkie dźwięki systemowe.\n” + „Dzwonki, powiadomienia, alarmy.”, 0,
„Tutoriale systemowe”, „Dwa minitutoriale – użycie funkcji ruchu, użycie klawiatury.\n” + „Jeśli są Ci potrzebne…”, 0
);

viewbox(
„INSTALACJA”,
„Kreator jest gotowy do rozpoczęcia instalacji ROMu.\n\n” +
„Kliknij przycisk <b>Dalej</b> by rozpocząć instalację.\n\n” +
„Jeśli chcesz przejrzeć lub zmienić jakieś ustawienia instalacji, użyj przycisku <b>Wstecz</b>.\n\n” +
„Kliknij <b>lewy przycisk sprzętowy</b> jeśli chcesz zakończyć instalację i wyjść z kreatora.\n\n\n” +
„<b><#f00>Sprawdź elementy wybrane do instalacji przed jej rozpoczęciem.</#></b>”,
„icons/info”
);

install(
„INSTALOWANIE ROMU”,
„Instalowanie <b>” + ini_get(„rom_name”)+”</b>.\n\n” +
„To może potrwać kilka minut…”,
„icons/install”
);

ini_set(„text_next”, „Zakończ”);
checkviewbox(
„INSTALACJA ZAKOŃCZONA”,
„<#selectbg_g><b>Super !!!</b></#>\n\n” +
„<b>”+ini_get(„rom_name”) + „</b> <b>” + ini_get(„rom_version”) + „</b> został zainstalowany na Twoim urządzeniu.\n\n” +
„Kliknij przycisk <b>Zakończ</b> by zakończyć proces instalacji i ponownie uruchomić urządzenie.”,
„icons/info”,
„Restartuj urządzenie (odznaczenie przeniesie do trybu <b>Recovery</b>)”,
„1”,
„restart”
);
if
getvar(„restart”)==”1″
then
reboot(„now”);
endif;

Czy w świetle nabytych wcześniej informacji potrzebny jest dodatkowy opis?

Niemniej, warto zwrócić uwagę na jeden niewielki szczegół, którym jest użyta funkcja:

ini_set(„text_next”, „Zakończ”);

W kodzie została ona wykolorowana.
Pozwala ona na dowolny opis przycisków zawartych w panelach. Domyślnie przyciski przyjmują dwie nazwy: „Back” (Cofnij/Wstecz) i „Next” (Dalej). Jednak używając powyższej funkcji możemy ten opis dowolnie zmieniać – oczywiście tylko opis, funkcja przycisku pozostaje bez zmian.
Jej działanie ogranicza się tylko do panela nad którego kodem została umieszczona.
Enyłej… jest to – może nieco kulawy – ale działający sposób alternatywnej translacji UI instalatora – wspominałem o tym przy okazji opisu struktury instalatora.

I tak:
– dla przycisku „NEXT”
ini_set(„text_next”, „Własna_nazwa”);

– dla przycisku „BACK”:
ini_set(„text_back”, „Własna_nazwa”);

Ową funkcję można użyć dla każdego panelu zawartego w skrypcie konfiguracyjnym. Zasada jej użycia i lokalizacji przedstawiona została w przykładzie skryptu.

[strona=”Pozostałe pliki – „updater-script””]
Pozostałe pliki – „updater-script”


No i powolutku finiszujemy.

Aby ten cały nabój w postaci funkcjonalnego instalatora nam wypalił musimy zająć się edycją i dostosowaniem jeszcze jednego pliku.

Konfiguracyjny skrypt instalacyjny mamy poniekąd załatwiony, teraz zajmijmy się skryptem wykonującym całą instalację. Jednym słowem przejdźmy do modyfikacji pliku updater-script.
Gwoli wyjaśnienia… Nie będę zajmował się w tym miejscu opisem całości struktury i zasad działania skryptu instalacyjnego – są w sieci, a nawet i na tym forum materiały rozkładające ów skrypt na czynniki pierwsze – warto się z nimi zapoznać.

Cała edycja pliku updater-script polega na dodaniu w odpowiednich miejscach odpowiednich wpisów, które spowodują efekt jaki chcemy osiągnąć, czyli instalację wybranych w instalatorze elementów. Ale zacznijmy od początku…

Opcjonalna instalacja programów i elementów ROMu
Jeśli pozwolicie, przykłady oprę o wcześniejsze opisy tworzenia list instalacji opcjonalnej oraz o zarys własnego skryptu AROMY – czyli… zasada z opisów a konkrety z przykładowego skryptu (tworzenie i oznaczanie listy instalacji opcjonalnej była omawiane we wcześniejszych rozdziałach).

Odwołania do instalacji programów realizujemy poprzez kod omówiony nieco dalej.
Cały kod (jeden element listy = jeden blok kodu) umieszczamy zaraz po poleceniach instalacji systemu (ROMu) na urządzeniu. I nie ma znaczenia czy dany element chcemy instalować czy nie. Ile elementów umieścimy w panelu tyle bloków kodu musimy zapodać w updater-script… Rajt?
No i tu jest niejaki problem bo owo polecenie może mieć na różnych urządzeniach różną formę.
Ja, jako samsungowiec – siłą rzeczy – oprę się na strukturze samsungowej. Kto wie, może ta część jest wspólna, lub bardzo podobna dla innych urządzeń? W sumie to jeden Android, ale cholera wie jak to na innych urządzeniach jest… Szczerze mówiąc to nie sprawdzałem…

Niemniej… szanujący się kucharz rozpisuje skrypt na kolejne „kroki” i owe kroki opatruje w odnośne komentarze… Liczmy, że nasz kucharz (albo my sami) tak postąpiliśmy…
Jeśli tak postąpiliśmy to wyznacznikiem dla nas jest tekst (komentarz) typu: „Installing system files” lub jakiś do niego podobny. Tak na marginesie… Jeszcze nie spotkałem się z ROMem, który nie miałby wydzielonej jakkolwiek tej części instalacji.
Dla ułatwienia dodam kilka charakterystycznych poleceń identyfikujących ten właśnie blok:

ui_print(„Installing system …”);
package_extract_dir(„system”, „/system”);
package_extract_dir(„data”, „/data”);

ui_print(„Copying System Files …”);
ui_print(„++++++++++++++++++++”);
package_extract_dir(„system”, „/system”);
package_extract_dir(„preload”, „/preload”);
package_extract_dir(„data”, „/data”);

ui_print(„Installing system files…”);
mount(„ext4”, „EMMC”, „/dev/block/mmcblk0p9”, „/system”);
package_extract_dir(„system”, „/system”);

lub generalnie szukamy linii:

package_extract_dir(„system”, „/system”);

… i analizujemy gdzie nasz kod umieścić.
Wybaczcie, ale możliwości jest sporo. W tym miejscu liczę na Waszą przenikliwość.

– Wywołania elementów listy panela CHECKBOX()

if
file_getprop(„/tmp/aroma/customize.prop”,”item.1.1″) == „1”
then
ui_print(„@ Systemowy menedzer plikow”);
package_extract_dir(„RDex/apps/NoteMyFiles/app”, „/system/app”);
endif;

– Opis elementów

if
Funkcja IF() (jeżeli).

file_getprop(„/tmp/aroma/customize.prop”,”item.1.1″) == „1”
Polecenie realizuje dodanie wybranego programu/elementu do struktury ROMu na podstawie zapisów w pliku *.prop (była o tym mowa przy okazji tworzenia list elementów).

gdzie:
„/tmp/aroma/customize.prop” – Nazwa i lokalizacja tymczasowego pliku źródłowego (była o tym mowa przy okazji tworzenia list elementów). O ile nazwa pliku jest wyprodukowana przez nas, o tyle jego lokalizacja jest automatycznie tworzona przez system.
„item.1.1” – Oznaczenie elementu (była o tym mowa przy okazji tworzenia list elementów).
== „1” – „ma wartość 1” (checkbox w panelu został zaznaczony)… Zgodnie z konwencją działania funkcji „IF” jest to warunek do spełnienia.

then
Część funkcji IF().

ui_print(„@ Systemowy menedzer plikow”);
Funkcja wyświetlająca na ekranie dany tekst/wynik działania/cokolwiek jej każemy.
W tym przypadku polecenie wyświetli tekst zawarty w jej parametrach, czyli to, co umieścimy w nawiasach.
Warto dodać, że użyty w zapisie znak „@” automatycznie pokoloruje i wyróżni dalszą treść.

package_extract_dir(„RDex/apps/NoteMyFiles/app”, „/system/app”)
To polecenie jest kluczowe bowiem bezpośrednio realizuje dodanie elementu do struktury ROMu.

gdzie:
„RDex/apps/NoteMyFiles/app” – Źródłowy folder plików, które zostaną dodane do struktury ROMu.
„/system/app” – Miejsce gdzie zostaną owe pliki zlokalizowane docelowo, czyli zainstalowane.

Każda umieszczona funkcja package_extract_dir() odnosi się do jednej lokalizacji. Jeśli zestaw plików naszego programu/elementu podzielony jest na kilka lokalizacji (np. dodatkowo /system/lib, /system/fonts etc.) to  funkcję należy wywołać dla każdej lokalizacji osobno. Takie „kilkukrotne” zastosowanie tej funkcji będzie można znaleźć w przykładowym kodzie updater-scriptu zapodanym nieco dalej.

endif;
Koniec funkcji IF.

W wolnym tłumaczeniu powyższa funkcja może mieć brzmienie:

Jeżeli…
„item.1.1” zapisany w pliku customize.prop ma wartość 1 to:
Wyświetl na ekranie komunikat Systemowy menedzer plikow, pobierz pliki z lokalizacji RDex/apps/NoteMyFiles/app i zainstaluj je w lokalizacji /system/app
.

Jeżeli wyrażenie „item.1.1” będzie miało wartość 0 (zero) – czyli nie zostanie wybrane (zaptaszone) w odpowiednim panelu – zostanie przez instalator pominięte.

I tyle na dobrą sprawę.

– Wywołania elementów listy panela SELECTBOX()

if
file_getprop(„/tmp/aroma/mods.prop”,”selected.1″) == „1”
then
ui_print(„@  Aparat i galeria – stock”);
package_extract_dir(„RDex/mods/Camera/41common/app”, „/preload/symlink/system/app”);
package_extract_dir(„RDex/mods/Camera/41std/app”, „/preload/symlink/system/app”);
endif;

– Opis elementów

file_getprop(„/tmp/aroma/mods.prop”,”selected.1″) == „1”[/color]

Opis elementów jest prawie dokładnie taki sam jak w przypadku viewbox(). Różnicę tu stanowi drugi parametr funkcji („selected.1”) oraz warunek spełnienia funkcji (== „1”).
Te dwa elemeny – jako, że pełnią nieco odmienną rolę w przypadku tego panela – opiszę:

„selected.1”
Jest oznaczeniem grupy, która zawiera naszą opcję. Zgodnie z wcześniejszym opisem, może ona przybierać wartości: „selected.0” – w przypadku listy niepogrupowanej,
„selected.1”, „selected.2”, „selected.X” – w przypadku listu grupowanej…
Myślę, że w świetle poprzednich opisów jest to oczywiste.

== „1”
W przeciwieństwie do panela checkbox() ta wartość oznacza KOLEJNY ELEMENT W GRUPIE (lub na liście elementów w przypadku braku grupowania).

Dla dokładniejszego wyjaśnienia…
W przypadku panela checkbox() (czyli instalacji dowolnej ilości elementów z listy lub grupy), zapis w tymczasowym pliku *.prop ma postać mniej-więcej taką:

– Dla listy prostej:

„Element nr 1 ma znacznik 1, więc będzie zainstalowany” # (item1.1) == 1
„Element nr 5 ma znacznik 1, więc będzie zainstalowany” # (item1.5) == 1
„Element nr 8 ma znacznik 1, więc będzie zainstalowany” # (item1.8) == 1

– Dla listy grupowanej:

„Element nr 1 w grupie 1 ma znacznik 1, więc będzie instalowany” # (item1.1) == 1
„Element nr 2 w grupie 1 ma znacznik 1, więc będzie instalowany” # (item1.2) == 1
„Element nr 3 w grupie 1 ma znacznik 1, więc będzie instalowany” # (item1.3) == 1
„Element nr 4 w grupie 2 ma znacznik 1, więc będzie instalowany” # (item2.4) == 1
„Element nr 5 w grupie 2 ma znacznik 1, więc będzie instalowany” # (item2.5) == 1
„Element nr 6 w grupie 2 ma znacznik 1, więc będzie instalowany” # (item2.6) == 1
„Element nr 7 w grupie 3 ma znacznik 1, więc będzie instalowany” # (item3.7) == 1
„Element nr 8 w grupie 3 ma znacznik 1, więc będzie instalowany” # (item3.8) == 1
„Element nr 9 w grupie 3 ma znacznik 1, więc będzie instalowany” # (item3.9) == 1

W przypadku panela selectbox() (czyli instalacji tylko jednego elementu z listy lub grupy) wygląda to nieco inaczej:

– Dla listy prostej:

„Będzie instalowany element nr 6 z listy” # (selected.0) == 6

– Dla listy grupowanej:

„Będzie instalowany element nr 3 z grupy 1” # (selected.1) == 3
„Będzie instalowany element nr 5 z grupy 2” # (selected.2) == 5
„Będzie instalowany element nr 7 z grupy 3” # (selected.3) == 7

Widać różnice i zależności?
Jeśli nie widać to ja nie wiem jak to bardziej łopatologicznie wyłożyć…

Każdy taki blok powtarzamy dla każdego elementu umieszczonego w panelach selectbox() i viewbox() – oczywiście stosując odpowiednią konwencję zapisu dla każdego rodzaju panela.

Ponizej przykładowy zapis instalacji opcjonalnej na podstawie wcześniejszego przykładu skryptu instalatora AROMA – zawiera on wszystkie elementy instalacji opcjonalnej (programy) zawarte w sktypcie konfiguracyjnym AROMY.
Kilkadziesiąt pierwszych IF-ów to kod elementów checkbox(), 10 ostatnich bloków kodu dotyczy panela selectbox(). Całość do własnej analizy.

ui_print(„Instalowanie wybranych plikow …”);

if
file_getprop(„/tmp/aroma/customize.prop”,”item.1.1″) == „1”
then
ui_print(„@ Systemowy menedzer plikow”);
package_extract_dir(„RDex/apps/NoteMyFiles/app”, „/system/app”);
endif;

if
file_getprop(„/tmp/aroma/customize.prop”,”item.1.2″) == „1”
then
ui_print(„@ Total Commander”);
package_extract_dir(„RDex/apps/TotalCmd/app”, „/system/app”);
endif;

if
file_getprop(„/tmp/aroma/customize.prop”,”item.1.3″) == „1”
then
ui_print(„@ ES FileExplorer”);
package_extract_dir(„RDex/apps/ESFileExplorer/app”, „/system/app”);
endif;

if
file_getprop(„/tmp/aroma/customize.prop”,”item.1.4″) == „1”
then
ui_print(„@ Hide It Pro”);
package_extract_dir(„RDex/apps/HideItPro/app”, „/system/app”);
endif;

if
file_getprop(„/tmp/aroma/customize.prop”,”item.1.5″) == „1”
then
ui_print(„@ ZArchiver”);
package_extract_dir(„RDex/apps/ZArchiver/app”, „/system/app”);
endif;

if
file_getprop(„/tmp/aroma/customize.prop”,”item.1.6″) == „1”
then
ui_print(„@ GO Backup”);
package_extract_dir(„RDex/apps/GOBackup/app”, „/system/app”);
endif;

if
file_getprop(„/tmp/aroma/customize.prop”,”item.2.1″) == „1”
then
ui_print(„@ Analog Clock Simple”);
package_extract_dir(„RDex/apps/AnalogClockSimple/app”, „/system/app”);
endif;

if
file_getprop(„/tmp/aroma/customize.prop”,”item.2.2″) == „1”
then
ui_print(„@ Analog Clock Unique”);
package_extract_dir(„RDex/apps/AnalogClockUnique/app”, „/system/app”);
endif;

if
file_getprop(„/tmp/aroma/customize.prop”,”item.2.3″) == „1”
then
ui_print(„@ Days”);
package_extract_dir(„RDex/apps/Days/app”, „/system/app”);
endif;

if
file_getprop(„/tmp/aroma/customize.prop”,”item.2.4″) == „1”
then
ui_print(„@ DigitalClock”);
package_extract_dir(„RDex/apps/DigitalClock/app”, „/system/app”);
endif;

if
file_getprop(„/tmp/aroma/customize.prop”,”item.2.5″) == „1”
then
ui_print(„@ Dual Clock Analog”);
package_extract_dir(„RDex/apps/DualClockAnalog/app”, „/system/app”);
endif;

if
file_getprop(„/tmp/aroma/customize.prop”,”item.2.6″) == „1”
then
ui_print(„@ Dual Clock Digital”);
package_extract_dir(„RDex/apps/DualClockDigital/app”, „/system/app”);
endif;

if
file_getprop(„/tmp/aroma/customize.prop”,”item.2.7″) == „1”
then
ui_print(„@ GenieWidget”);
package_extract_dir(„RDex/apps/GenieWidget/app”, „/system/app”);
endif;

if
file_getprop(„/tmp/aroma/customize.prop”,”item.2.8″) == „1”
then
ui_print(„@ Planner Widget”);
package_extract_dir(„RDex/apps/SPlannerAppWidget/app”, „/system/app”);
endif;

if
file_getprop(„/tmp/aroma/customize.prop”,”item.2.9″) == „1”
then
ui_print(„@ Samsung Widget FavoriteApp”);
package_extract_dir(„RDex/apps/SamsungWidgetFavoriteApp/app”, „/system/app”);
endif;

if
file_getprop(„/tmp/aroma/customize.prop”,”item.2.10″) == „1”
then
ui_print(„@ SamsungWidget ProgramMonitor”);
package_extract_dir(„RDex/apps/SamsungWidgetProgramMonitor/app”, „/system/app”);
endif;

if
file_getprop(„/tmp/aroma/customize.prop”,”item.2.11″) == „1”
then
ui_print(„@ Simple Favorites Widget”);
package_extract_dir(„RDex/apps/SimpleFavoritesWidget/app”, „/system/app”);
endif;

if
file_getprop(„/tmp/aroma/customize.prop”,”item.2.12″) == „1”
then
ui_print(„@ Simple Alarm Clock”);
package_extract_dir(„RDex/apps/SimpleAlarmClock/app”, „/system/app”);
endif;

if
file_getprop(„/tmp/aroma/customize.prop”,”item.2.13″) == „1”
then
ui_print(„@ Yahoo News Widget”);
package_extract_dir(„RDex/apps/YahooNewsWidget/app”, „/system/app”);
endif;

if
file_getprop(„/tmp/aroma/customize.prop”,”item.2.14″) == „1”
then
ui_print(„@ Yahoo Stock Widget”);
package_extract_dir(„RDex/apps/YahooStockWidget/app”, „/system/app”);
endif;

if
file_getprop(„/tmp/aroma/customize.prop”,”item.3.1″) == „1”
then
ui_print(„@ Music Player”);
package_extract_dir(„RDex/apps/MusicPlayer/app”, „/system/app”);
endif;

if
file_getprop(„/tmp/aroma/customize.prop”,”item.3.2″) == „1”
then
ui_print(„@ Allshare”);
package_extract_dir(„RDex/apps/Allshare/app”, „/system/app”);
endif;

if
file_getprop(„/tmp/aroma/customize.prop”,”item.3.3″) == „1”
then
ui_print(„@ Flash Player”);
package_extract_dir(„RDex/apps/Flashplayer/app”, „/system/app”);
package_extract_dir(„RDex/apps/Flashplayer/lib”, „/system/lib”);
endif;

if
file_getprop(„/tmp/aroma/customize.prop”,”item.3.4″) == „1”
then
ui_print(„@ Game Hub”);
package_extract_dir(„RDex/apps/GameHub/app”, „/system/app”);
endif;

if
file_getprop(„/tmp/aroma/customize.prop”,”item.3.5″) == „1”
then
ui_print(„@ Music Hub”);
package_extract_dir(„RDex/apps/MusicHub/app”, „/system/app”);
endif;

if
file_getprop(„/tmp/aroma/customize.prop”,”item.3.6″) == „1”
then
ui_print(„@ Video Hub”);
package_extract_dir(„RDex/apps/VideoHub/app”, „/system/app”);
package_extract_dir(„RDex/apps/VideoHub/lib”, „/system/lib”);
endif;

if
file_getprop(„/tmp/aroma/customize.prop”,”item.3.7″) == „1”
then
ui_print(„@ Help Hub”);
package_extract_dir(„RDex/apps/HelpHub/app”, „/system/app”);
endif;

if
file_getprop(„/tmp/aroma/customize.prop”,”item.3.8″) == „1”
then
ui_print(„@ Readers Hub”);
package_extract_dir(„RDex/apps/ReadersHub/app”, „/system/app”);
endif;

if
file_getprop(„/tmp/aroma/customize.prop”,”item.3.9″) == „1”
then
ui_print(„@ Zinio”);
package_extract_dir(„RDex/apps/Zinio/app”, „/system/app”);
package_extract_dir(„RDex/apps/Zinio/lib”, „/system/lib”);
endif;

if
file_getprop(„/tmp/aroma/customize.prop”,”item.3.10″) == „1”
then
ui_print(„@ PressReader”);
package_extract_dir(„RDex/apps/PressReader/app”, „/system/app”);
package_extract_dir(„RDex/apps/PressReader/lib”, „/system/lib”);
endif;

if
file_getprop(„/tmp/aroma/customize.prop”,”item.3.11″) == „1”
then
ui_print(„@ Kobo”);
package_extract_dir(„RDex/apps/Kobo/app”, „/system/app”);
endif;

if
file_getprop(„/tmp/aroma/customize.prop”,”item.3.12″) == „1”
then
ui_print(„@ PolarisViewer”);
package_extract_dir(„RDex/apps/PolarisViewer/app”, „/system/app”);
package_extract_dir(„RDex/apps/PolarisViewer/lib”, „/system/lib”);
endif;

if
file_getprop(„/tmp/aroma/customize.prop”,”item.4.1″) == „1”
then
ui_print(„@ ChatON”);
package_extract_dir(„RDex/apps/ChatON/app”, „/system/app”);
package_extract_dir(„RDex/apps/ChatON/lib”, „/system/lib”);
endif;

if
file_getprop(„/tmp/aroma/customize.prop”,”item.4.2″) == „1”
then
ui_print(„@ Talk”);
package_extract_dir(„RDex/apps/Talk/app”, „/system/app”);
endif;

if
file_getprop(„/tmp/aroma/customize.prop”,”item.4.3″) == „1”
then
ui_print(„@ Dropbox”);
package_extract_dir(„RDex/apps/Dropbox/app”, „/system/app”);
endif;

if
file_getprop(„/tmp/aroma/customize.prop”,”item.4.4″) == „1”
then
ui_print(„@ SNS Google Plus”);
package_extract_dir(„RDex/apps/GooglePlus/app”, „/system/app”);
package_extract_dir(„RDex/apps/GooglePlus/lib”, „/system/lib”);
endif;

if
file_getprop(„/tmp/aroma/customize.prop”,”item.4.5″) == „1”
then
ui_print(„@ SNS Facebook”);
package_extract_dir(„RDex/apps/SNS/app”, „/system/app”);
endif;

if
file_getprop(„/tmp/aroma/customize.prop”,”item.4.6″) == „1”
then
ui_print(„@ sCloud”);
package_extract_dir(„RDex/apps/sCloud/app”, „/system/app”);
endif;

if
file_getprop(„/tmp/aroma/customize.prop”,”item.4.7″) == „1”
then
ui_print(„@ GroupCast”);
package_extract_dir(„RDex/apps/GroupCast/app”, „/system/app”);
endif;

if
file_getprop(„/tmp/aroma/customize.prop”,”item.4.8″) == „1”
then
ui_print(„@ Mobile Print”);
package_extract_dir(„RDex/apps/MobilePrint/app”, „/system/app”);
endif;

if
file_getprop(„/tmp/aroma/customize.prop”,”item.4.9″) == „1”
then
ui_print(„@ YouTube”);
package_extract_dir(„RDex/apps/YouTube/app”, „/system/app”);
endif;

if
file_getprop(„/tmp/aroma/customize.prop”,”item.5.1″) == „1”
then
ui_print(„@ Kies”);
package_extract_dir(„RDex/apps/Kies/app”, „/system/app”);
package_extract_dir(„RDex/apps/Kies/lib”, „/system/lib”);
package_extract_dir(„RDex/apps/KiesAir/app”, „/system/app”);
endif;

if
file_getprop(„/tmp/aroma/customize.prop”,”item.5.2″) == „1”
then
ui_print(„@ Samsung Services”);
package_extract_dir(„RDex/apps/SamsungServices/app”, „/system/app”);
endif;

if
file_getprop(„/tmp/aroma/customize.prop”,”item.5.3″) == „1”
then
ui_print(„@ Samsung Update”);
package_extract_dir(„RDex/apps/SamsungUpdate/app”, „/system/app”);
package_extract_dir(„RDex/apps/SamsungUpdate/lib”, „/system/lib”);
endif;

if
file_getprop(„/tmp/aroma/customize.prop”,”item.5.4″) == „1”
then
ui_print(„@ SamsungApps”);
package_extract_dir(„RDex/apps/SamsungApps/app”, „/system/app”);
endif;

if
file_getprop(„/tmp/aroma/customize.prop”,”item.5.5″) == „1”
then
ui_print(„@ Sansung Fonts”);
package_extract_dir(„RDex/apps/SansungFonts/app”, „/system/app”);
endif;

if
file_getprop(„/tmp/aroma/customize.prop”,”item.5.6″) == „1”
then
ui_print(„@ Sansung TTS”);
package_extract_dir(„RDex/apps/SansungTTS/app”, „/system/app”);
package_extract_dir(„RDex/apps/SansungTTS/lib”, „/system/lib”);
package_extract_dir(„RDex/apps/SansungTTS/tts”, „/system/tts”);
package_extract_dir(„RDex/apps/SansungTTS/wakeupdata”, „/system/wakeupdata”);
endif;

if
file_getprop(„/tmp/aroma/customize.prop”,”item.6.1″) == „1”
then
ui_print(„@ Animowane tapety 1”);
package_extract_dir(„RDex/apps/LiveWallpapers1/app”, „/system/app”);
endif;

if
file_getprop(„/tmp/aroma/customize.prop”,”item.6.2″) == „1”
then
ui_print(„@ Animowane tapety 2”);
package_extract_dir(„RDex/apps/LiveWallpapers2/app”, „/system/app”);
endif;

if
file_getprop(„/tmp/aroma/customize.prop”,”item.6.3″) == „1”
then
ui_print(„@ Talkback”);
package_extract_dir(„RDex/apps/Talkback/app”, „/system/app”);
endif;

if
file_getprop(„/tmp/aroma/customize.prop”,”item.6.4″) == „1”
then
ui_print(„@ Voice Recorder”);
package_extract_dir(„RDex/apps/VoiceRecorder/app”, „/system/app”);
endif;

if
file_getprop(„/tmp/aroma/customize.prop”,”item.6.5″) == „1”
then
ui_print(„@ Mini Diary”);
package_extract_dir(„RDex/apps/MiniDiary/app”, „/system/app”);
endif;

if
file_getprop(„/tmp/aroma/customize.prop”,”item.6.6″) == „1”
then
ui_print(„@ FaceLock”);
package_extract_dir(„RDex/apps/Facelock/app”, „/system/app”);
package_extract_dir(„RDex/apps/Facelock/lib”, „/system/lib”);
package_extract_dir(„RDex/apps/Facelock/vendor”, „/system/vendor”);
endif;

if
file_getprop(„/tmp/aroma/customize.prop”,”item.7.1″) == „1”
then
ui_print(„@ Swype Keyboard”);
package_extract_dir(„RDex/apps/SwypeKeyboard/app”, „/system/app”);
package_extract_dir(„RDex/apps/SwypeKeyboard/lib”, „/system/lib”);
endif;

if
file_getprop(„/tmp/aroma/customize.prop”,”item.7.2″) == „1”
then
ui_print(„@ Keyboard Android 4.2”);
package_extract_dir(„RDex/apps/KeyboardAndroid/app”, „/system/app”);
package_extract_dir(„RDex/apps/KeyboardAndroid/lib”, „/system/lib”);
endif;

if
file_getprop(„/tmp/aroma/customize.prop”,”item.7.3″) == „1”
then
ui_print(„@ EmojiKeyboard Android 4.2”);
package_extract_dir(„RDex/apps/EmojiKeyboardAndroid42/app”, „/system/app”);
package_extract_dir(„RDex/apps/EmojiKeyboardAndroid42/lib”, „/system/lib”);
endif;

if
file_getprop(„/tmp/aroma/customize.prop”,”item.8.1″) == „1”
then
ui_print(„@ Jezyki systemowe CSC”);
package_extract_dir(„RDex/apps/SystemLng/csc”, „/system/csc”);
package_extract_dir(„RDex/apps/SystemLng/recovery”, „/system/recovery”);
package_extract_dir(„RDex/apps/SystemLng/other”, „/system”);
endif;

if
file_getprop(„/tmp/aroma/customize.prop”,”item.8.2″) == „1”
then
ui_print(„@ Slowniki systemowe”);
package_extract_dir(„RDex/apps/SystemDict/hdic”, „/system/hdic”);
package_extract_dir(„RDex/apps/SystemDict/T9DB”, „/system/T9DB”);
endif;

if
file_getprop(„/tmp/aroma/customize.prop”,”item.8.3″) == „1”
then
ui_print(„@ Czcionki systemowe”);
package_extract_dir(„RDex/apps/SystemFonts/etc”, „/system/etc”);
package_extract_dir(„RDex/apps/SystemFonts/fonts”, „/system/fonts”);
endif;

if
file_getprop(„/tmp/aroma/customize.prop”,”item.8.4″) == „1”
then
ui_print(„@ Dzwieki systemowe”);
package_extract_dir(„RDex/apps/SystemSound/alarms”, „/system/media/audio/alarms”);
package_extract_dir(„RDex/apps/SystemSound/notifications”, „/system/media/audio/notifications”);
package_extract_dir(„RDex/apps/SystemSound/ringtones”, „/system/media/audio/ringtones”);
endif;

if
file_getprop(„/tmp/aroma/customize.prop”,”item.8.5″) == „1”
then
ui_print(„@ Tutoriale”);
package_extract_dir(„RDex/apps/SystemApps/app”, „/system/app”);
endif;

ui_print(„Instalowanie wybranych modyfikacji …”);

if
file_getprop(„/tmp/aroma/mods.prop”,”selected.1″) == „1”
then
ui_print(„@ Aparat i galeria – stock”);
package_extract_dir(„RDex/mods/Camera/41common/app”, „/system/app”);
package_extract_dir(„RDex/mods/Camera/41std/app”, „/system/app”);
endif;

if
file_getprop(„/tmp/aroma/mods.prop”,”selected.1″) == „2”
then
ui_print(„@ Aparat stock i galeria z Note2”);
package_extract_dir(„RDex/mods/Camera/41common/app”, „/system/app”);
package_extract_dir(„RDex/mods/Camera/41mod/app”, „/system/app”);
package_extract_dir(„RDex/mods/Camera/41mod/lib”, „/system/lib”);
endif;

if
file_getprop(„/tmp/aroma/mods.prop”,”selected.1″) == „3”
then
ui_print(„@ Aparat i galeria – 4.2”);
package_extract_dir(„RDex/mods/Camera/42/app”, „/system/app”);
package_extract_dir(„RDex/mods/Camera/42/lib”, „/system/lib”);
endif;

if
file_getprop(„/tmp/aroma/mods.prop”,”selected.1″) == „4”
then
ui_print(„@ Aparat i galeria – 4.1 i 4.2”);
package_extract_dir(„RDex/mods/Camera/41common/app”, „/system/app”);
package_extract_dir(„RDex/mods/Camera/41std/app”, „/system/app”);
package_extract_dir(„RDex/mods/Camera/42/app”, „/system/app”);
package_extract_dir(„RDex/mods/Camera/42/lib”, „/system/lib”);
endif;

if
file_getprop(„/tmp/aroma/mods.prop”,”selected.2″) == „1”
then
ui_print(„@ Zegary – stock”);
package_extract_dir(„RDex/mods/Clock/41/app”, „/system/app”);
endif;

if
file_getprop(„/tmp/aroma/mods.prop”,”selected.2″) == „2”
then
ui_print(„@ Zegary – 4.2”);
package_extract_dir(„RDex/mods/Clock/42/app”, „/system/app”);
package_extract_dir(„RDex/mods/Clocl/42/fonts”, „/system/fonts”);
endif;

if
file_getprop(„/tmp/aroma/mods.prop”,”selected.2″) == „3”
then
ui_print(„@ Zegary – 4.1 i 4.2”);
package_extract_dir(„RDex/mods/Clock/41/app”, „/system/app”);
package_extract_dir(„RDex/mods/Clock/42/app”, „/system/app”);
package_extract_dir(„RDex/mods/Clocl/42/fonts”, „/system/fonts”);
endif;

if
file_getprop(„/tmp/aroma/mods.prop”,”selected.3″) == „1”
then
ui_print(„@ Odtwarzacz wideo – stock”);
package_extract_dir(„RDex/mods/VideoPlayer/41common/lib”, „/system/lib”);
package_extract_dir(„RDex/mods/VideoPlayer/41std/app”, „/system/app”);
endif;

if
file_getprop(„/tmp/aroma/mods.prop”,”selected.3″) == „2”
then
ui_print(„@ Odtwarzacz wideo – mod”);
package_extract_dir(„RDex/mods/VideoPlayer/41common/lib”, „/system/lib”);
package_extract_dir(„RDex/mods/VideoPlayer/41mod/app”, „/system/app”);
package_extract_dir(„RDex/mods/VideoPlayer/41mod/lib”, „/system/lib”);
endif;

if
file_getprop(„/tmp/aroma/mods.prop”,”selected.4″) == „1”
then
ui_print(„@ Widzet pogodowy – stock”);
package_extract_dir(„RDex/mods/AccuweatherWidget/41common/app”, „/system/app”);
package_extract_dir(„RDex/mods/AccuweatherWidget/41std/app”, „/system/app”);
endif;

if
file_getprop(„/tmp/aroma/mods.prop”,”selected.4″) == „2”
then
ui_print(„@ Widzet pogodowy – mod”);
package_extract_dir(„RDex/mods/AccuweatherWidget/41common/app”, „/system/app”);
package_extract_dir(„RDex/mods/AccuweatherWidget/41mod/app”, „/system/app”);
endif;

To jest ta łatwiejsza część łatwiejszej części – dotycząca oprogramowania.
Częścią trudniejszą jest opcjonalna instalacja elementów typu kernel albo modem. Zasada dokładnie taka sama jak ta stosowana dla panela selectbox(). Jedyną i zasadniczą różnicą jest to, że w tym przypadku musimy użyć całego bloku kodu odpowiedzialnego za instalację kernela czy modemu.

Opcjonalna instalacja kerneli i modemów

Całe szczęście, że ta część instalacji ROMu jest opisywana w skrypcie. Jest to o tyle ważne, że musimy namierzyć całą część kodu odpowiadającą za instalację kernela czy modemu – a ta może się mniej lub bardziej różnić w zależności od ROMu, urządzenia czy urodzaju na ogórki.
Interesującą nas a wcześniej namierzoną część kodu usuwamy ze skryptu i przenosimy do funkcji IF() każdego kernela czy modemu, który przewidujemy instalować.
Poniżej przykład opcjonalnej instalacji dwóch kerneli i dwóch modemów. Dla ułatwienia, część kodu odpowiedzialna a instalację kernela/modemu (ta oryginalna) została pokolorowana:

ui_print(„Flaszowanie kernela …”);

if
file_getprop(„/tmp/aroma/kernels.prop”,”selected.0″) == „1”
then
ui_print(„@ PhilZ 3.81”);
package_extract_file(„RDex/flash_image”, „/tmp/flash_image”);
set_perm(0, 0, 0777, „/tmp/flash_image”);
assert(package_extract_file(„RDex/kernels/philz/zImage”, „/tmp/zImage”),
run_program(„/tmp/flash_image”, „/dev/block/mmcblk0p5”, „/tmp/zImage”),
delete(„/tmp/zImage”));
endif;

if
file_getprop(„/tmp/aroma/kernels.prop”,”selected.0″) == „2”
then
ui_print(„@ Jeboo 1.1a”);
package_extract_file(„RDex/flash_image”, „/tmp/flash_image”);
set_perm(0, 0, 0777, „/tmp/flash_image”);
assert(package_extract_file(„RDex/kernels/jeboo/zImage”, „/tmp/zImage”),
run_program(„/tmp/flash_image”, „/dev/block/mmcblk0p5”, „/tmp/zImage”),
delete(„/tmp/zImage”));
endif;

ui_print(„Flaszowanie modemu …”);

if
file_getprop(„/tmp/aroma/modems.prop”,”selected.0″) == „1”
then
ui_print(„@ XXLS6”);
assert(package_extract_file(„RDex/modems/xxls6/modem.bin”, „/tmp/modem.bin”),
run_program(„/tmp/flash_image”, „/dev/block/mmcblk0p8”, „/tmp/modem.bin”),
delete(„/tmp/modem.bin”));
endif;

if
file_getprop(„/tmp/aroma/modems.prop”,”selected.0″) == „2”
then
ui_print(„@ BVLP7”);
assert(package_extract_file(„RDex/modems/bvlp7/modem.bin”, „/tmp/modem.bin”),
run_program(„/tmp/flash_image”, „/dev/block/mmcblk0p8”, „/tmp/modem.bin”),
delete(„/tmp/modem.bin”));
endif;

Dało się coś z tego zrozumieć? :huh:

Aplikacja gotowego instalatora do ROMu


Kiedy już mamy w miarę gotową AROMĘ i updater-script, dobrze by było zapakować to wszystko do ROMu.

Procedura jest prosta, to kilka kroków:

W zipie ROMu otwieramy lokalizację:

\META-INF\com\google\android\

i…

1. Zmieniamy nazwę pliku update-binary na update-binary-installer.
2. Kopiujemy tam cały folder aroma oraz pliki aroma-config i update-binary.
3. Kopiujemy tam zmodyfikowany plik updater-script zastępując nim istniejący…

To wszystko.

[strona=”Uruchomienie instalatora i potencjalne błędy”]
Uruchomienie instalatora i potencjalne błędy


Aby solidnie przetestować działanie instalatora, zapewne nie obejdzie się bez kilkakrotnego romowania urządzenia.
Myślę, że nie muszę wspominać, iż wskazane jest bardzo dokładne przejrzenie swojego dzieła a przede wszystkim:

  • Skonfrontowanie kolejności elementów instalacji umieszczonych w aroma-config i updater-script – kolejność musi być identyczna. W innym przypadku co innego będziemy zaznaczali a co innego będzie instalowane.
  • Dokładne przejrzenie całego kodu obu plików w poszukiwaniu „zagubionych” przecinków, nawiasów, tagów lub ogólnie nieścisłości w kodzie.

Na tym etapie nie zrobimy nic więcej.

Drugim etapem jest próba zaromowania ROMem zawierającym instalator.

W tym momencie możemy trafić na kilka zasadniczych błędów:

  • Błędy w kodzie pliku aroma-config – krok 1
    Jeśli w pliku wystąpią błędy kodu to instalator się nie uruchomi, urządzenie zawibruje a w konsoli Recovery pojawi się komunikat opisujący bład. Najczęściej będzie to numer linii i numer znaku. Ten komunikat będzie dotyczył najczęściej „zgubionych” znaków – np. przecinek czy średnik.
    W tym przypadku musimy przejrzeć skrypt aromy, poprawić błąd i romować ponownie. I tak aż do momentu poprawnego startu instalatora.
  • Błędy w kodzie pliku aroma-config – krok 2
    Jeśli nasz instalator uruchomi się poprawnie to dokładnie przeglądamy zawartość jego paneli w poszukiwaniu błędów wizualnych takich jak niezamknięte tagi, logiczność instalatora, błędy w tekstach etc.
  • Błędy w kodzie pliku aroma-config – krok 3
    Wiedząc co dolega naszemu instalatorowi wizualnie możemy przejść do testów poprawności instalowania elementów.
    W tym celu wybieramy nie więcej niż kilka elementów i finalizujemy instalację ROMu a po romowaniu – jeśli przebiegło poprawnie – sprawdzamy czy wybrane elementy zostały dodane do ROMu. Tą procedurę powtarzamy kilkakrotnie, aż do uzyskania pewności, że wszystkie elementy instalują się poprawnie.
  • Błędy finalizowania instalacji ROMu
    Owe błędy zaobserwujemy w panelu INSTALL gdzie będziemy mieli podgląd na procedurę instalacji ROMu.
    Błędy mogą tu być różne i zależą od „wad” naszego pliku updater-script.

Autorem poradnika jest Artur Wąsowski Wall-E






Przewiń stronę, by przeczytać kolejny wpis
Przewiń stronę, by przeczytać kolejny wpis
x