Implementace vyhledávacího uživatelského rozhraní v Android aplikacích, zejména za použití support knihovny AppCompat, vyžaduje přesné dodržování několika kroků a pochopení souvislostí mezi aktivitami, manifestem a systémovými intent filtry. Vytvoření nové aktivity, například SearchResultActivity, která přijímá a zpracovává vyhledávací dotazy, je často preferovaným přístupem. Tato aktivita načte svůj layout, získá TextView určený k zobrazení výsledku a v metodě onCreate() rozpozná akci Intent.ACTION_SEARCH. Pomocí metody handleSearch pak nastaví text zadaného dotazu do TextView.

Klíčovým prvkem je správná konfigurace v AndroidManifest.xml, kde je potřeba definovat vyhledávací zdroj (searchable), zaregistrovat aktivitu s intent filtrem pro akci SEARCH a propojit vše v rámci aplikace. Využití atributů jako app:showAsAction nebo app:actionViewClass v menu resource, místo android namespace, je nutné pro zpětnou kompatibilitu se staršími verzemi Androidu. Tato nuance často vytváří nejednoznačnosti, protože oficiální dokumentace může preferovat framework API, zatímco support knihovna má vlastní drobné odlišnosti.

Vyhledávání samo o sobě může být následně implementováno podle specifik aplikace – zda bude dotaz zpracován lokálně, nebo zaslán na vzdálený webový server. V tomto kontextu je důležité vnímat, že SearchManager rozesílá intent SEARCH, který aktivita přijímá a zpracovává. Správné pochopení životního cyklu aktivity a práce s intenty je proto nezbytné pro funkční a uživatelsky přívětivé vyhledávání.

Současně s vyhledáváním je vhodné věnovat pozornost i režimům celé obrazovky, především tzv. Immersive Mode, který byl představen v Androidu 4.4 (API 19). Tento režim umožňuje aplikaci získat plnou kontrolu nad dotykovými událostmi a skrýt systémové uživatelské rozhraní (například navigační lištu a stavový řádek), což je žádoucí například při čtení knih, hraní her, kreslení nebo sledování videa. Immersive Mode má různé varianty, přičemž se liší míra viditelnosti systémového UI podle scénáře použití: od úplného skrytí přes částečné zobrazení po běžný režim se systémovým UI.

Uživatel může systémové prvky znovu zobrazit gestem přejetí, což zachovává intuitivní ovládání. Při implementaci tohoto režimu je nutné správně využít systémové flagy jako SYSTEM_UI_FLAG_FULLSCREEN a SYSTEM_UI_FLAG_HIDE_NAVIGATION a správně nastavit naslouchání na dotyková gesta, například pro přepínání viditelnosti UI. To umožňuje vytvořit aplikace, které nabízí skutečně pohlcující zážitek bez rušivých elementů operačního systému.

Pro úplné zvládnutí těchto konceptů je důležité sledovat rozdíly mezi framework API a support knihovnou, zejména v otázkách kompatibility, a být obezřetný při práci s XML atributy a definicemi v manifestu. Navíc je vhodné si uvědomit, že zpětná kompatibilita s nižšími verzemi Androidu často vyžaduje specifické úpravy, které nejsou vždy jasně popsané v dokumentaci. Znalost těchto detailů je klíčová pro vytvoření stabilní a funkční aplikace, která správně reaguje na uživatelský vstup a poskytuje moderní a přívětivé uživatelské prostředí.

Dále je třeba mít na paměti, že i když technické nastavení a implementace jsou základní, důležitou roli hraje i způsob, jakým vyhledávací dotazy aplikace zpracovává. V praxi se často jedná o integraci s databázemi, webovými službami nebo kombinací obojího, což ovlivňuje uživatelský komfort a efektivitu hledání. Schopnost pružně reagovat na dotazy a efektivně zobrazovat výsledky je jedním z pilířů kvalitního uživatelského zážitku.

Jak vytvářet a vykreslovat objekty v OpenGL ES na Androidu

Při práci s OpenGL ES na Androidu je důležité mít správně nastavené prostředí pro vykreslování a ovládání objektů na obrazovce. Tento proces obvykle začíná implementací vlastní třídy pro zobrazení OpenGL, pokračuje definováním základních geometrických tvarů a končí vykreslováním těchto tvarů pomocí shaderů.

Nejdříve si vytvoříme vlastní třídu, která dědí od GLSurfaceView. Tato třída poskytuje základní plochu pro vykreslování pomocí OpenGL, přičemž samotné vykreslování probíhá v rendereru. Taková implementace umožňuje snadnou integraci OpenGL do Android aplikace, aniž bychom museli pracovat přímo s nízkoúrovňovými metodami OpenGL.

java
class CustomGLSurfaceView extends GLSurfaceView { private final GLRenderer mGLRenderer; public CustomGLSurfaceView(Context context){ super(context); setEGLContextClientVersion(2); // Nastavení verze OpenGL mGLRenderer = new GLRenderer(); setRenderer(mGLRenderer); // Přiřazení rendereru pro vykreslování } }

V tomto příkladu je GLSurfaceView třída, která poskytuje povrch pro vykreslování, a setRenderer() přiřazuje renderer, který bude vykreslovat obsah. Dalším krokem je vytvoření rendereru, což je třída, která implementuje metody pro vykreslování a manipulaci s vykreslovanými objekty.

java
class GLRenderer implements GLSurfaceView.Renderer {
public void onSurfaceCreated(GL10 unused, EGLConfig config) {
GLES20.glClearColor(
0.5f, 0.5f, 0.5f, 1.0f); // Nastavení barvy pozadí } public void onDrawFrame(GL10 unused) { GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); // Vyčištění obrazovky }
public void onSurfaceChanged(GL10 unused, int width, int height) {
GLES20.glViewport(
0, 0, width, height); // Nastavení velikosti výřezu } }

Tento renderer obsahuje tři základní metody, které se volají v různých fázích vykreslování: onSurfaceCreated(), onDrawFrame() a onSurfaceChanged(). V první metodě se nastaví základní barva pozadí, ve druhé se provádí vykreslování (v našem případě je to pouze vyčištění obrazovky), a ve třetí metodě se přizpůsobí výřez obrazovky podle rozměrů zařízení.

Nyní, když máme základní prostředí připravené, můžeme se soustředit na vytváření a vykreslování geometrických tvarů. V OpenGL je velmi důležité správně definovat pořadí vrcholů, protože to určuje přední a zadní stranu objektu. Standardně se vrcholy definují proti směru hodinových ručiček.

Pro naše potřeby si vytvoříme třídu Triangle, která bude reprezentovat trojúhelník. V OpenGL je základním stavebním kamenem každý objekt tvořený trojúhelníky, ať už jde o složitější tvary nebo 3D objekty.

Pro vykreslování trojúhelníku musíme definovat dva základní shadery:

  1. Vertex shader – určuje pozici vrcholů trojúhelníku.

  2. Fragment shader – určuje barvu objektu.

Kromě těchto shaderů vytvoříme také OpenGL program, který shadery spojí a umožní jejich použití pro vykreslování objektu.

java
class Triangle {
private final String vertexShaderCode =
"attribute vec4 vPosition;" + "void main() {" + " gl_Position = vPosition;" + "}"; private final String fragmentShaderCode = "precision mediump float;" + "uniform vec4 vColor;" + "void main() {" + " gl_FragColor = vColor;" + "}";
private final int COORDS_PER_VERTEX = 3;
private float triangleCoords[] = { 0.0f, 0.66f, 0.0f, -0.5f, -0.33f, 0.0f, 0.5f, -0.33f, 0.0f }; private float color[] = { 0.63f, 0.76f, 0.22f, 1.0f }; private final int mProgram; private FloatBuffer vertexBuffer; private int mPositionHandle; private int mColorHandle; public Triangle() { int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode); int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode); mProgram = GLES20.glCreateProgram(); GLES20.glAttachShader(mProgram, vertexShader); GLES20.glAttachShader(mProgram, fragmentShader); GLES20.glLinkProgram(mProgram);
ByteBuffer bb = ByteBuffer.allocateDirect(triangleCoords.length * 4);
bb.order(ByteOrder.nativeOrder()); vertexBuffer = bb.asFloatBuffer(); vertexBuffer.put(triangleCoords); vertexBuffer.position(
0); } public int loadShader(int type, String shaderCode) { int shader = GLES20.glCreateShader(type); GLES20.glShaderSource(shader, shaderCode); GLES20.glCompileShader(shader); return shader; } public void draw() { GLES20.glUseProgram(mProgram); mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition"); GLES20.glEnableVertexAttribArray(mPositionHandle); GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, 12, vertexBuffer); mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor"); GLES20.glUniform4fv(mColorHandle, 1, color, 0); GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 3); GLES20.glDisableVertexAttribArray(mPositionHandle); } }

Tato třída definuje vertex a fragment shader, kompiluje je do OpenGL programu a následně vykresluje trojúhelník na obrazovku.

Ve třídě renderer pak voláme metodu draw(), která vykreslí trojúhelník na obrazovku.

Důležité je si uvědomit, že při práci s OpenGL na Androidu je třeba mít na paměti správné nastavení prostředí pro vykreslování, jako je výřez obrazovky nebo nastavení barev pozadí. Také je nezbytné důkladně rozumět tomu, jak fungují shadery, protože jejich správné nastavení je klíčové pro vykreslování objektů v reálném čase. Shadery definují nejen geometrickou strukturu objektu, ale i jeho vzhled a chování na obrazovce.

Pokud byste se chtěli pustit do složitějších 3D objektů, je nutné rozšířit tuto implementaci o perspektivní zobrazení a manipulaci s maticemi pro rotace, posuny nebo škálování objektů, což by už vyžadovalo komplexnější přístup k transformacím a projekcím v OpenGL.

Jak sledovat telefonní události a odesílat SMS v Android aplikaci?

Při vývoji mobilních aplikací, které interagují s telefonními funkcemi zařízení, je často nutné získat informace o stavu hovoru nebo být schopen odesílat textové zprávy. Android API poskytuje nástroje, které umožňují monitorovat telekomunikační události a aktivně s nimi pracovat. Klíčovým prvkem je zde implementace posluchače PhoneStateListener, který umožňuje sledování změn stavu hovoru, a použití SmsManager pro odesílání SMS zpráv.

Začněme monitoringem telefonního stavu. Při vytváření jednoduché aplikace stačí přidat jeden TextView do rozvržení, kde se budou vypisovat informace o změnách stavu hovoru. Zásadní je přidání oprávnění READ_PHONE_STATE do manifestu aplikace. Ve třídě MainActivity je následně vytvořen posluchač událostí PhoneStateListener, který přepisuje metodu onCallStateChanged(). V této metodě je podle hodnoty parametru state určeno, zda je hovor v klidovém režimu (CALL_STATE_IDLE), vyzvání (CALL_STATE_RINGING) nebo probíhá (CALL_STATE_OFFHOOK). Každý z těchto stavů je zaznamenán a vypsán do TextView.

Připojení posluchače probíhá prostřednictvím TelephonyManager, který se získá ze systémového kontextu. Následně se zavolá metoda listen() s definovaným posluchačem a specifikací LISTEN_CALL_STATE. Jakmile již není třeba dále sledovat události, je nutné zavolat listen() znovu, tentokrát s parametrem LISTEN_NONE, čímž se posluchač deaktivuje a předejde se zbytečnému zatížení systému.

Vedle monitorování hovorů může být aplikace rozšířena o další možnosti naslouchání, například LISTEN_DATA_CONNECTION_STATE, LISTEN_SIGNAL_STRENGTHS nebo LISTEN_CALL_FORWARDING_INDICATOR. Kompletní seznam podporovaných posluchačů je uveden v dokumentaci Androidu.

Další často využívanou funkcí je odesílání SMS zpráv. Implementace je relativně přímočará, avšak i zde je třeba nejprve požádat o příslušné oprávnění (SEND_SMS). Aplikace by měla při startu ověřit, zda uživatel již udělil potřebné oprávnění. Pokud nikoli, je třeba o něj dynamicky požádat pomocí ActivityCompat.requestPermissions() a zpracovat odpověď v metodě onRequestPermissionsResult().

Jakmile je oprávnění uděleno, aktivuje se tlačítko pro odeslání zprávy. Při stisknutí tlačítka se získají vstupní údaje – telefonní číslo a text zprávy – z příslušných EditText polí. Po jejich validaci se vytvoří instance SmsManager a zavolá se metoda sendTextMessage(), která SMS zprávu odešle. V případě, že oprávnění nebylo uděleno, aplikace informuje uživatele pomocí Toast zprávy.

Kriticky důležitým aspektem celého procesu je bezpečné a transparentní zacházení s oprávněními. Uživatel musí být informován, proč jsou oprávnění požadována, a aplikace by měla být připravena na odmítnutí těchto oprávnění. Kromě toho je třeba počítat s tím, že SMS mohou být zpoplatněny nebo omezeny operátorem. Vývojáři by proto měli při návrhu uživatelského rozhraní i logiky aplikace respektovat možné důsledky automatizovaného odesílání zpráv.

Z hlediska vývoje a testování je vhodné používat emulátory s podporou simulace hovorů i SMS zpráv. Například Android Emulator umožňuje simulovat příchozí hovory z jiného emulátoru pomocí jeho ID (např. 5556). To usnadňuje testování chování aplikace v různých situacích bez nutnosti využívat reálné SIM karty nebo zařízení.

Je třeba si také uvědomit, že chování API se může lišit v závislosti na verzi systému Android. Například od Androidu 10 (API 29) došlo ke zpřísnění politik týkajících se oprávnění a přístupu k telekomunikačním údajům. V takových případech je nutné, aby vývojář ověřil, zda je API dostupné a podporované na konkrétní verzi systému, a případně poskytl alternativní chování.

Při využití PhoneStateListener je také důležité zacházet s výsledky událostí efektivně. Například opakované stavy mohou být filtrovány, aby se předešlo redundantním zápisům do UI, a aplikace by měla vždy ověřovat, že získaná data (např. telefonní číslo)