Posts tagged Android

Custom ROM a Samsung Galaxy S2

0

Už je to rok a půl, co jsem majitelem v nadpise uvedené hračky. Mimo úvodních pár měsíců, kdy jsem byl nadšen rychlostí systému (v porovnání s G1), jsem na telefon permanentně nadával a v poslední době to gradovalo do takových extrémů (touha rozmlátit telefon, komunitu i google), že jsem se konečně přinutil věnovat odpoledne nahrání Custom ROMky, zprovoznění ROOTa a image s recovery. A protože jsem ne všechny potřebné informace a nástroje našel na jednom místě a navíc se potýkal s drobnými problémy, přijde mi vhod udělat tímto postem takový malý rozcestník.

Když jsem svého času přehrával systém v G1 (CyanogenMod a později SuperD), byly všechny kroky popsány pěkně pod sebou přímo na stránkách s danou ROMkou, u Toshiby se daly rozumně dohledat po fórech. Co se však týká SG2, našel jsem víceméně kulové. Všechny návody (oficiální) počítají s tím, že už požívám nějakou jinou ROMku a přestože někdy úvod a nadpis vypadá, že bude dále řeč o vanilla Samsung paskvilu androidu, nebylo tomu tak. Mimo jiné se tyto návody specializují spíše na Windows, já však potřeboval update provést z Macka (a obecně by to mělo fungovat i pro GNU Linux).

Miui

Miui

Pokusím se tyto kroky sepsat níže, spolu se zdrojem, odkud jsem čerpal. Uváděná čísla verzí (pokud je uvedu) se samozřejmě časem změní, takže v mnoha případech zůstanu pouze u uvedení názvu daného nástroje a strýček google jistě poradí. Ještě bych na úvod poznamenal, že nenesu žádné riziko, pokud si někdo následujícím postupem s telefonem něco provede.

1. Instalace obrazu zavaděče – postupoval jsem podle howto ve wiki Cyanogen modu, který mě nasměroval na Heimdal Suite, což je multiplatformní nástroj pro flashování obrazů do Samsung Galaxy S zařízení, jak tvrdí oficiální FAQ. Z výše uvedené wiki jsem se dostal i ke ClockworkMod Recovery. Heimdal jsem stáhnul ve formě instalačního balíčku a hned tady jsem měl první problém – instalátor umně skryl okno s informací o potřebě restartu pod všechna okna a já se chvíli trápil s tím, proč se mi nedaří aplikace použít. Po restartu však vše šlo jako po másle a bylo možné nahrát image do zařízení (nejprve nutno zapnout USB debugging a nastartovat telefon do „download režimu“ pomocí trojhmatu volume down, home a power):

sudo heimdall flash --kernel zImage

2. Povolení superuživatele – spočívající v nahrání binárky su a aplikace Superuser. Na tuto aplikaci mě odkázal miculog, kterého jsem se ale zase tak moc nedržel a ze stránek stáhl zip archivy, které jsem nahrál na kartu, nabootoval do recovery (tentokrát volume up, home a power) a odtud je pomocí „Install zip from sdcard“ nainstaloval.

3. Provedení zálohy – stále v recovery režimu je možné provést zálohu systémových oddílů v nabídce „backup and restore“.

4. Stažení vlastního obrazu s ROM – a následné nahrání na kartu (nebo interní úložiště) v telefonu. Já se rozhodl pro MIUI ROM, takže jsem stahoval nejnovější build a snažil se postupovat podle oficiálního návodu. Bohužel jsem v rámci minulého kroku zároveň začal mazat i cache, data a další místa, takže mi telefon odmítl nabootovat a nemohl jsem tak do něj nahrát zip soubor s updatem. Po chvíli googlení jsem problém vyřešil a pomocí adb z Android SDK namountoval „ramdisk“ jako externi úložiště (telefon v recovery režimu) a nahrál tam požadovaný image:

shmoula $ adb shell
# mount -t tmpfs none /sdcard
# exit
shmoula $ adb push miuiandroid_GT-I9100_ics-2.11.23.zip /sdcard/
. . . . .

5. Instalace custom ROM – po předchozím vymazání „wipe data/factory reset“, „wipe cache partition“, „advanced – Wipe Dalvik Cache“ a konečně „Mounts and Storage – Format/System“ následuje opět „Install zip from SD card“ a výběr v předchozím kroku nahraného zazipovaného image. Po chvíli akce a napětí následuje restart telefonu pomocí výběru „restart system now“ a s největší pravděpodobností naběhnutí nového systému (a drobné rozčarování z jiného rozložení a následujícího kroku).

6. Instalace Google aplikací – protože nesmějí být bundlovány s custom ROMkama. MIUI už však části těchto aplikací obsahuje, navíc má vlastní market a další drobnosti, takže je nutné tyto služby nejprve povypínat, jak radí začátek tohoto vlákna.

shmoula $ adb shell
# mount -o remount,rw -t ext4 /dev/block/mmcblk0p1 /system
# mv /system/app/NetworkLocation.apk /system/app/MiuiNetworkLocation.bak
# pm disable com.miui.cloudservice
# pm disable com.xiaomi.xmsf
# exit

Teď už je možné stáhnout balíček s google apps a nahrát jej na kartu v telefonu. Instaluje se opět jako update v recovery režimu volbou „Install zip from SD card“.

7. Aktivování Mass usb režimu – od jisté verze tydlidrojdu není povolen USB Mass storage režim, takže je nutné jej aktivovat ručně:

shmoula $ adb shell
# setprop persist.sys.usb.config mass_storage

8. Závěrečný restart telefonu a přihlášení se ke svému google účtu a následný komentář s pochvalou pod tímto návodem.

Android MapView a onTouch

0

Nemálo mě, a nejenom mě, štve absence něčeho, jako je onTouch() v mapách na Androidu, protože potřebuju vytvořit dynamické načítání overlayů. MapView sice má onTouchEvent(), ale že by bylo možné jej použít nějakým mnou zamýšleným způsobem, to zrovna ne. Zkoušel jsem pár způsobů, které tu nastíním a taky jsem zkusil jedno ne zrovna dvakrát moc fér řešení. Ale zoufalí lidé se uchylují k zoufalým věcem, však to znáte… Jen to vezmu hodně hopem, protože mám moře jiných věcí na dělání, ale pár lidem jsem to slíbil a sliby se mají plnit a to nejen o Vánocích ;-).

Zatímco natahování je poměrně jasné (AsyncTask, který bude natahovat data ve čtverci, jehož směrem jsem se posunul – na základě kolize souřadnic tohoto čtverce a viewportu – aby to pořád netahalo jak blbé), taková trivialita jako je onTouch už tak jasná není.

Nejprve jsem se snažil přimět k rozumu metodu onTouchEvent() jak na MapView, tak i na Overlayi, bohužel bezúspěšně. Zajímalo by mě, jestli je tento event pozůstatek něčeho zaniklého, nebo se na něj jenom nějak zapomnělo. Tento způsob by měl fungovat nějak takto, což vypadá poměrně prakticky a použitelně – ve switchi checkovat eventy:

public boolean onTouchEvent(MotionEvent ev) {
        int action = ev.getAction();
        switch (action) {
            . . .
        }
    return super.onTouchEvent(ev);
}

Bohužel – z nějakého důvodu tato metoda vůbec nebyla volána. Po nějakém googlení jsem narazil na blog Juriho Strumpflohnera, který řešil stejný problém a vyšpekuloval ho následovně: na mapView navěsit vlastní OnTouchListener(), čili přidat jednoduchou anonymní třídu:

mapView.setOnTouchListener(new OnTouchListener() {
    public boolean onTouch(View v, MotionEvent ev) {
        return false;
    }
});

Pokud teda dojde k eventu Touch, jsou procházeny všechny views a případné implementace listenerů v nich. V listeneru implementovaná metoda onTouch je volána nejméně jednou v závislosti na tom, zda vrátí true či false. Pokud vrací false, provede se pouze poprvé a systém je tak chytrý, že už jde příště rovnou na jistotu (aka přímo po metodě, která vrátila true), což je zároveň i kámen úrazu: je nutné zajistit, aby byla volána i metoda „níže“, protože se při true mapa nepohybuje (ale náš onTouch je volaný vždycky). Je teda nutné předat „nižšímu view“ tento event. Nejprve jsem volal dispatchTouchEvent() na view, který přišel do onTouch, ale to je blbost, protože tento view je vlastně onen MapEvent, nad kterým byl navěšen tento listener, takže došlo k zacyklení a StackOverflowError. Takže jsem třídu odanonymizoval a předávám si do ní Context, což je aktivita, uvnitř které je mapView:

public class MyTouchListener implements View.OnTouchListener {
    private Activity activity;

    public MyTouchListener(Activity activity) {
        super();
        this.activity = activity;
    }

    public boolean onTouch(View v, MotionEvent ev) {
        activity.dispatchTouchEvent(ev);
        return true;
    }
}

Taky to ovšem nejede, ale oproti dispatchování do view to vydrží o chvíli déle (a pak to stejně přeteče zásobník a zdechne).

Jak už to bývá, funkční řešení bývají ta nejjednodušší, takže dneska tenhle blogpost konečně dorazím!

Ono totiž stačí rozšířit map view a přepsat v něm onTouchEvent, nebo onInterceptTouchEvent (jak je popsáno tady). V čem je zakopán pudl? V ničem, opravdu to funguje. Předchozí Class Cast Exception se dá zbavit velice jednoduše – definovat správný typ v layoutu! Pojďme tedy na to, nejprve vlastní mapView:

package cz.shmoula.pat;

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;

import com.google.android.maps.MapView;

public class AreaMapView extends MapView {
	private Context mContext;

	public AreaMapView(Context context, AttributeSet attributeSet) {
		super(context, attributeSet);
		mContext = context;
	}

	public boolean onTouchEvent(MotionEvent ev) {
		if (ev.getAction() == MotionEvent.ACTION_MOVE) {
			Log.i("!!!!!", "Pohyb!");
		}
		return super.onTouchEvent(ev);
	}
}

Teď následuje onen výše zmíněný kámen úrazu, který dříve hulákal Class Cast výjimkou a je to docela logické, ale nevěděl jsem, že je možné vkládat do layoutů vlastní komponenty. Teď už to vím, tak je možné psát něco zhruba takového:

<?xml version="1.0" encoding="utf-8"?>

<cz.shmoula.pat.AreaMapView
    xmlns:android="http://schemas.android.com/apk/res/android"

    android:id="@+id/areaMapView"

    android:layout_width="fill_parent"
    android:layout_height="fill_parent"

    android:clickable="true"
    android:apiKey="api_klíč"
/>

No a v aktivitě se tato komponenta dohledá každému známým způsobem:

AreaMapView mapView = (AreaMapView) findViewById(R.id.areaMapView);

Toť vše! Opravdu, v jednoduchosti je síla. Takže teď přidat nějaké spočítání delta a pokud bylo pohnuto viewportem více, než je výše uvedený čtverec v onu stranu, tak načíst další. Na závěr se ještě musím přiznat, že toto řešení jsem nevyplodil sám, ale sprostě se nechal inspirovat OpenCachingem od Garmina, který mě nakopl na správnou cestu směrem k výsledku. Při pídění se po řešení jsem taky narazil na projekt mapview-overlay-manager, ve kterém se nachází Lazy loading a který si nechávám k dalšímu prostudování a hádám, že nebudu sám.

Dekompilace androidích aplikací

0

Někdo se rád pídí po tom, jak věci fungují, někdo se rád občas nechává inspirovat cizími kusy kódu a někdo prachsprostě krade (možná by se to dalo nazvat nějakou IT kleptomanií). Všem těmto skupinám by ovšem mohl přijít vhod tento blogpost, protože v několika krocích popisuje operaci jednoduchou (tu jednoduchost myslím vážně, zabývat se dedexerem, aka android disassemblerem opravdu nehodlám, z toho už jsem vyrostl a zpohodlněl) – a sice rozbalování a dekompilaci androidí aplikace.

Jak je tvořena androidí aplikace asi každý vývojář ví, takže tuto část vypustíme a přejděme blíže k věci, což by mohl být aapt, neboli Android Asset Packing Tool, který je součástí nástrojů v SDK. Tento nástroj je jednak zodpovědný za parsování všemožných souborů (včetně manifestu) uvnitř projektu a následné přetváření takových properties do R.java souboru, ale především i za proces opačný, čili dolování informací z již hotových .apk souborů a to i podepsaných a zarovnaných. Nebudeme chodit kolem horké kaše a skočme rovnou do nějakého příkladu. Půjčil jsem si APKčko z mého rozdělaného projektu a provedl nad ním následující kouzlo:

vbalak@vbalak-desktop:~/develop/workspace.sts/PlantATree/client/target$ aapt l -a pat-client.apk
res/layout/area_map.xml
res/layout/main.xml
res/layout/tree_details.xml
res/layout/tree_list.xml
res/layout/tree_list_item.xml
res/menu/map_menu.xml
AndroidManifest.xml
resources.arsc
res/drawable-hdpi/icon.png
res/drawable-ldpi/icon.png
res/drawable-mdpi/icon.png
classes.dex
org/codehaus/jackson/map/VERSION.txt
org/codehaus/jackson/impl/VERSION.txt
META-INF/MANIFEST.MF
META-INF/CERT.SF
META-INF/CERT.RSA

Nejprve je vidět seznam souborů nacházejících se v archivu (.apk je obyčejný zip soubor, takže je možné jej jednoduše rozbalit, v tom není žádná věda). Další část (resource table) je zajímavější – jedná se o identifikátory zdrojů, neboli to, co je v souboru R.java – to jsou ty hexa čísla uvedená bezprostředně za spec resource a dále typ tohoto zdroje – layout, string, drawable, id…

Resource table:
Package Groups (1)
Package Group 0 id=127 packageCount=1 name=cz.shmoula.pat
  Package 0 id=127 name=cz.shmoula.pat typeCount=6
    type 0 configCount=0 entryCount=0
    type 1 configCount=3 entryCount=1
      spec resource 0x7f020000 cz.shmoula.pat:drawable/icon: flags=0x00000100
      spec resource 0x7f04000a cz.shmoula.pat:string/menu_toggle_view: flags=0x00000000
. . .

Nejzajímavější je ovšem část poslední, což je sám velký manifest. Kdo měl možnost nahlédnout do AndroidManifest.xml a teď kouká na tento výpis, všímá si velké podobnosti (pokud potlačí rozdílný způsob zobrazení – tohle není xml ;-)). Jsou zde krásně vidět využívaná oprávnění, je zde vidět, jakou program používá ikonu (to je ten hexa kód, který se dá dohledat v části se zdroji – Resources Table). Jsou zde vidět jednotlivé aktivity, parametry aktivit a definované intent-filtry a také využívané knihovny – prostě kompletní manifest, akorát jinak formátovaný. Pro naše další potřeby potřebujeme vstupní bod do aplikace, což bude LAUNCHER a ten je nastaven pro třídu MainActivity, která je v balíčku cz.shmoula.pat, bude se nám hodit za chvíli. Za zmínku ještě stojí anotherMapProcess v poslední aktivitě – dvě mapy se v jedné aplikaci nesnesou, tudíž je nutné je spouštět v rámci jiného procesu, tento parametr tohle zajišťuje (taky jsem nad tím tenkrát dlouho koumal).

Android manifest:
N: android=http://schemas.android.com/apk/res/android
  E: manifest (line=2)
    A: android:versionCode(0x0101021b)=(type 0x10)0x1
    A: android:versionName(0x0101021c)="0.1" (Raw: "0.1")
    A: package="cz.shmoula.pat" (Raw: "cz.shmoula.pat")
    E: uses-permission (line=5)
      A: android:name(0x01010003)="android.permission.INTERNET" (Raw: "android.permission.INTERNET")
    E: application (line=7)
      A: android:label(0x01010001)=@0x7f040001
      A: android:icon(0x01010002)=@0x7f020000
      E: activity (line=8)
        A: android:name(0x01010003)=".MainActivity" (Raw: ".MainActivity")
        E: intent-filter (line=9)
          E: action (line=10)
            A: android:name(0x01010003)="android.intent.action.MAIN" (Raw: "android.intent.action.MAIN")
          E: category (line=11)
            A: android:name(0x01010003)="android.intent.category.LAUNCHER" (Raw: "android.intent.category.LAUNCHER")
      E: activity (line=15)
        A: android:name(0x01010003)=".LookAroundActivity" (Raw: ".LookAroundActivity")
. . .
      E: activity (line=16)
        A: android:theme(0x01010000)=@0x1030006
        A: android:name(0x01010003)=".ShowAreaMapActivity" (Raw: ".ShowAreaMapActivity")
        A: android:process(0x01010011)=":anotherMapProcess" (Raw: ":anotherMapProcess")
      E: uses-library (line=22)
        A: android:name(0x01010003)="com.google.android.maps" (Raw: "com.google.android.maps")

V této fázi tedy máme hrubý přehled o struktuře aplikace, bylo by vhodné se dostat ke třídám. Ty jsou zabalené uvnitř souboru classes.dex, který se nacházi uvnitř APKčka, takže bych prosil rozzipovat tento archiv. Tento soubor je víceméně nějakým způsobem rozsypaný Java ARchive a pro jeho sesypání do použitelného formátu slouží utilitka dex2jar, která se spouští jednoduchým způsobem:

vbalak@vbalak-desktop:~/develop/stuff/dex2jar-0.0.7.8-SNAPSHOT$ ./dex2jar.sh classes.dex
version:0.0.7.8-SNAPSHOT
3 [main] INFO pxb.android.dex2jar.v3.Main - dex2jar classes.dex -&gt; classes.dex.dex2jar.jar
Done.

Získali jsme tedy opravdový archiv .jar, který je opět možné rozzipovat a koukat na jednotlivé zkompilované třídy. Také je možné udělat víc – pomocí některého java dekompileru je možné se podívat dovnitř, já volil Java Decompiler. Pomocí něj je možné otevřít získaný .jar soubor a v levé části otevřít požadovanou třídu (výše jsme zjistili, že vstupním bodem je MainActivity) a užívat pocitu vítězství, nebo začít vykrádat se začít inspirovat cizím kódem. Toď vše, pro ilustraci ještě přikládám shot JavaDecompileru.

JavaDecompiler - screenshot

JavaDecompiler - screenshot

Google I/O Extended Brno

0

Jsa pln dojmů z dvouhodinové návštěvy akce Brněnské GUG s promítáním live streamu z Google I/O si asi budu nucen ublognout nějaké postřehy a komentáře, i když je jasné, že zítra toho bude plné podhoubí (twittosféra je nasycena už teď). Protože ale paralelně sleduju další stream, tak to bude jen velmi stručně.

Akce začala v 18 hodin našeho času, dostali jsme k ní nějaké doughnuty, pitivo a heslo na wifi, pak se již mohlo začít. Nutno poznamenat, že slibovaní hosté zřejmě nedorazili (utekl jsem dřív pryč a koukám, že Jakub Čížek se nechecknul na Gowalle, spot jsem dokonce musel vytvářet já :-)).

První uvedenou novinkou byly Google Movies (pokud se to fakt tak jmenuje) – služba umožňující pronájem videa a jeho spuštění na jakémkoliv zařízení svázaném s vaším google accountem. Pronájmem mám na mysli opravdu pronájem – za pár dolarů si koupíte práva na zkouknutí filmu, na což dostanete nějakých 30 dní, po započetí sledování 24 hodin. Pro android by měla existovat nová aplikace Movies a jak se dalo čekat, je to US only.

Dalším uvedeným produktem byl Google Music, v betaverzi. Funguje stejně, jako Amazon cloud player – (pouze ve státech) nedá se nakupovat hudba, ale je možné hudbu si tam skrze aplikaci (zmíněna platforma Windows a Mac) nahrát a odtud z jakéhokoliv zařízení se stejným google účtem streamovat. Ano, streamovat – aby se prostor nedal využít k pirátským aktivitám. (pouze bych rád dodal, že doufám v brzké chcípnutí Sony, EMI a dalších ne zkostnatělých institucí, ale rovnou zkamenělých, které by si měly uvědomit, že hudbu nezabíjí kopírování, ale ony!) Pro streaming opět existuje aplikace na marketu, ale na žádném mém zařízení nejde stáhnout :-(.

US Only

US Only

Vývojáři také byli ujištěni, že svoje aplikace budou vyvíjet pouze jednou pro všechna zařízení – i Google TV bude mít android market. Znamená to teda zřejmě, že se vývoj neforkne pro tablety (a další zařízení) a telefony, jak to vypadalo doteď. Neznamená to ale samozřejmě zpětnou kompatibilitu, pořád bude samozřejmě existovat minimalSDK v manifestu.

Další peckou je vydání Accessory development kitu založeného na Arduinu (samozřejmě je vše otevřené, takže je možné očekávat boom hardwarových serepatiček, jako příklad bylo uvedeno sportovní náčiní) a vůbec větší podpora dalšího hardwaru, mimo jiné bude USB fungovat jako host, takže bude možné připojit klávesnice, gamepady a další věcičky. Demonstrace proběhla na gigantickém bludišti ovládaném tabletem s akcelerometry.

Bludiště

S tím souvisí představení dalšího produktu – Android@home – Androidu jakožto centrálního bodu pro ovládání inteligentních domů. A to počínaje nastavováním termostatu, zhášením světel, ale také multimédii – demonstrována byla výše zmíněná služba Music, kdy zakoupenou hudbu bylo možné pomocí telefonu pustit a jako výstupní zařízení nastavit hifi v obýváku a přehrávač v kuchyni.

Android@home

Android@home

To je víceméně vše, na co si z úvodu vzpomínám a teď mi běží ve streamu další android novinky a jsou to takové pecky, že se omlouvám a jdu sledovat! Jasné je, že je možné se v dohledné době těšit na obrovský boom gadgetů a všemožných více či méně praktických zařízení připojitelných k androidu a také samozřejmě S androidem. Jako třeba tablet Galaxy Tab, který dostali účastníci konference jako dárek.

PS. pomocí Moderátoru je možné pokládat otázky pro jednotlivá témata.

PlantATree

0

Tak nějak jsem se naučil, že nejzajímavější a nejpoužívanější jsou ty úplně nejjednodušší aplikace, o kterých by člověk při návrhu nějakého sofistikovaného systému (aka švýcarského nože) řekl, že jsou úplně na nic. Před časem jsme vymysleli úplně dokonalý tajný projekt, který měl mít množství funkcí a měl být napsaný hned a hned vržen do světa. Napsal jsem množství prototypů, které teˇd samostatně živoří bez frontendu a defakto bez vzájemné propojenosti. Proč? Možná je toho na jednoho člověka hodně, nebo spíš je to hrozně rozprostřené do šířky a něco takového poskládat dohromady, nedejbože udržovat a upravovat…fuj! Proto jsem si to soukromě (potají) ořezal, pouze na části základní funkčnosti a už to bylo lepší, prototypy se začaly skládat dohromady jako skládačka. Ovšem lepidla je málo (času – přece jenom když člověk dělá na několika rozdílných projektech, z nichž na některé se soustředí více, na některé pouze ve zbytcích času, potom zjistí, že se ve větší míře pouze seznamuje s tím, co že to před těmi čtrnácti vlastně udělal a čím by teˇd měl pokračovat). Proto jsem to ořezal ještě více a stvořím jenom drobnost, kterou budu vidět, že funguje a na jádro budu moct postupem času lepit další kousky. Drobnost, která nebude potřebovat moc lepidla, protože nebude mít téměř žádné funkce a dohromady nebude dělat téměř nic. Takže se, drahý světe, nechej překvapit, tímhle blogpostem jsem si dal jakýsi závazek, tak to budu muset udělat :-).

A cožeto? Geolokační hříčka – nebo spíš platforma postavená na SpringMVC, která bude nabízet RESTful rozhraní pro jistý druh „checkinů“. K tomu spytlíkuju Android aplikaci a celé to poběží na CloudFoundry, které bych tímto projektem rád vyzkoušel. GAE asi definitivně hážu za hlavu díky nemožnosti ukládání polymorfů :-).

Go to Top