Mobilne aplikacje multimedialne Laboratorium 1 Wyznaczanie orientacji urządzenia względem lokalnego układu odniesienia autor: Krzysztof Bruniecki Gdańsk, 2013-10-08 wersja 12
Wprowadzenie Platforma Android jest opartym na Linuxie systemem operacyjnym przeznaczonym dla urządzeń mobilnych. Platforma Android wspiera programowanie aplikacji w języku Java z użyciem standardowych bibliotek Javy oraz bibliotek wyspecjalizowanych wchodzących w skład Android Software Development Kit (SDK). W skład narzędzi Android SDK wchodzą między innymi: Android Development Tools Plugin plugin dla tworzenia aplikacji w Eclipce IDE Android Emulator emulator urządzenia z systemem android Android Virtual Devices (AVDs) narzędzie służące do konfiguracji cech wirtualnego urządzenia dla emulatora Dalvik Debug Monitor Service (ddms) narzędzie pozwala na zarządzanie procesem uruchamianym na urządzeniu lub, przykładowo: wgląd w zawartość stosu, zabicie procesu, zrzut ekranu Android Debug Bridge (adb) narzędzie adb pozwala instalować pliki.apk na emulatorze lub urządzeniu oraz zapewnia dostęp do niego z linii poleceń. Android Asset Packaging Tool (aapt) narzędzie aapt pozwala tworzyć pliki.apk zawierające binaria i zasoby aplikacji Androida. android skrypt pozwalający na zarządzanie urządzeniami AVD, oraz umożliwiający wygenerowanie szkieletu projektu możliwego do zbudowania z narzędziem Ant. Szkielet aplikacji na platformie Android Activity Klasą bazową dla dowolnej funkcjonalności jaką można zaimplementować w aplikacji na platformie Android jest Activity. Obiekt klasy Activity jest podstawową jednostką cyklu życia aplikacji. Z punktu widzenia programisty najważniejsze są metody, które najczęściej są przeciążane dla podklasy Activity oncreate, onpause oraz onresume. Xml Język xml jest szeroko wykorzystywany do definiowania stałych cech tworzonej aplikacji. Przykładowo jest on zastosowany do zdefiniowania wyglądu okna aplikacji (/res/layout/), wartości stałych stosowanych w programie (/res/values/), ale również do konfiguracji uprawnień oraz funkcjonalności aplikacji (AndroidManifest.xml). 2/10
R Klasa R jest automatycznie wygenerowaną umożliwiającą uzyskanie dostępu do elementów okna oraz stałych zdefiniowanych w plikach xml w czasie działania aplikacji (runtime).aplikacja Eclipse Eclipse IDE Utwożenie i uruchomienie aplikacji Android z użyciem Eclipse IDE wymaga następujących czynności: 1. Utworzyć aplikację Android Project (File > New > Other) 2. Utworzyć konfigurację - Debug Configuration 3. Kliknąć przycisk Debug 3/10
4. Ewentualnie jeśli mamy więcej niż jedno podłączone urządzenie / emulator wybrać na jakim ma zostać przeprowadzona instalacja i uruchomienie Modyfikacja interfejsu użytkownika i zachowania aplikacji Modyfikacja aplikacji z użyciem Eclipse IDE polegająca na dodaniu przycisku 1. Do standardowego, niemal pustego, wyglądu okna dodać przycisk. a. W pliku res/layout/main.xml można wprowadzić następującą treść (plik ten jest metaopisem wyglądu okna aplikacji i odwołuje się do niego funkcja setcontentview(r.layout.main);) Należy zwrócić uwagę na identyfikator dodany do obiektu TextView oraz Button dzięki niemu będzie możliwe uzyskanie programistycznego dostępu do tego obiektu w trakcie działania aplikacji. 2. Zmodyfikować właściwe źródło dodając prostą obsługę przycisku Button01. a. W tym celu należy przy użyciu metody findviewbyid(r.id.button01); uzyskać referencję do przycisku, a następnie zarejestrować obiekt OnClickListener używając metody Button.setOnClickListener(...). 4/10
b. Przykładowa zawartość metody oncreate zapewniająca obsługę przycisku znajduje się na poniższym listingu: Wykorzystanie sensorów Android.hardware.SensorManager zawiera kilka stałych, które reprezentują różne aspekty systemu czujników Androida, w tym: Sensor type Orientacja, akcelerometr, światło, pole magnetyczne, zbliżeniowe, temperatury, itp. Sampling rate Accuracy Najszybsza, gry, normalny, interfejs użytkownika. Gdy aplikacja żąda określonej częstotliwości próbkowania, to tak naprawdę tylko podpowiedź, czy sugestia, do podsystemu czujnika. Wysoki, niski, średni, niewiarygodne. Interfejs SensorEventListener zapewnia dwie wymagane metody: 1. onsensorchanged(sensorevent event) metoda jest wywoływana zawsze, gdy wartość mierzona przez sensor uległa zmianie. Metoda jest wywoływana tylko dla sensorów, które są monitorowane przez określony listener. Argumenty metody to obiekt, który reprezentuje zdarzenie. Obekt ten zawiera m.in. informację na temat wybranego sensora oraz tablicę typu float reprezentującą dane z sensora. Niektóre sensory dostarczają tylko jedną wartość, podczas gdy inne dostarczają trzy wartości. Sensory takie jak akcelerometr, sensor pola geomagnetycznego dostarczają trzy wartości. 2. onaccuracychanged(sensor sensor, int accuracy) metoda jest wywoływana, gdy dokładność sensora została zmieniona. Argumenty metody to obiekt reprezentujący sensor oraz liczba reprezentująca dokładność danego sensora. 5/10
Aby odczytać dane z sensora, aplikacja musi zarejestrować się w celu wykrywania działalności jednego lub więcej sensorów. Rejestracja odbywa się za pomocą metody registerlistener z klasy SensorManager. Pamiętaj, nie każde urządzenie wyposażone w Androida obsługuje wszystkie rodzaje sensorów określone w SDK. Przykład odczytu sensorów Demonstracja odczytu danych z sensorów zawartych w urządzeniu. Aplikacja ma wyświetlać dostępne sensory i umożliwiać wyświetlenie informacji z wybranego sensora w postaci natywnej czyli jako wartości liczbowe wektora (najczęściej trójwymiarowego). 1. W Eclipse należy utworzyć nowy projekt wybierając File New Project z polecenia menu. 2. Wybierz Android Project z szablonów. 3. Uzupełnij Project name nazwą względem swojego wyboru. 4. Wybierz platformę: np. Android 2.3 5. Uzupełnij Application Name oraz Package Name. 6. Kliknij Finish. Zostanie utworzony nowy projekt. 7. W res layout main.xml, stwórz odpowiedni widok dla aplikacji, np.: Wykorzystanie typu LinearLayout: android:text="accelerometer" android:text="x Value" android:id="@+id/xbox" android:text="y Value" 6/10
android:id="@+id/ybox" android:text="z Value" android:id="@+id/zbox" android:text="orientation" android:text="x Value" android:id="@+id/xboxo" android:text="y Value" android:id="@+id/yboxo" android:text="z Value" android:id="@+id/zboxo" Rys 1. Widok main.xml 1. Utworzona klasa typu Activity powinna także implementować interfejs SensorEventListener. Importuj klasy i zadeklaruj zmienne: import android.hardware.*; import android.widget.*; [...] 7/10
SensorManager sm = null; //elementy widoku w których będą wyświetlane dane z sensorów TextView xviewa = null; TextView yviewa = null; TextView zviewa = null; TextView xviewo = null; TextView yviewo = null; TextView zviewo = null; W celu wykonania ćwiczenia należy posłużyć się klasą SensorManager której instancję można uzyskać wywołując Context.getSystemService() z argumentem SENSOR_SERVICE. Należy to uczynić w metodzie oncreate: sm = (SensorManager) getsystemservice(sensor_service); W oncreate należy też określić odniesienia do sześciu widgetów TextView w których następować będzie aktualizacja wartości danych z czujnika. yviewa = (TextView) findviewbyid(r.id.ybox); zviewa = (TextView) findviewbyid(r.id.zbox); xviewo = (TextView) findviewbyid(r.id.xboxo); yviewo = (TextView) findviewbyid(r.id.yboxo); zviewo = (TextView) findviewbyid(r.id.zboxo); xviewa = (TextView) findviewbyid(r.id.xbox); 2. Nadpisz metodę onresume, w metodzie wykorzystaj odniesienie do SensorManager do rejestracji obiektu implementującego interfejs SensorEventListener z metody registerlistener: pierwszy parametr jest instancją klasy, która implementuje interfejs SensorEventListener, czyli tej w której obecnie pracujemy, drugi parametr jest obiektem reprezentującym wybrany sensor, trzeci parametr określa, jak często zgłaszane mają być aktualizacje pomiarów z sensora do obiektu listenera. msensormanager.registerlistener(this, maccelerometer, SensorManager.SENSOR_DELAY_NORMAL); 3. Klasa implementująca interfejs SensorEventListener musi implementować dwie metody onsensorchange i onaccuracychanged. Metoda onsensorchanged wywoływana jest stale, jak akcelerometr i czujnik orientacji wysyłają dane. Pierwszy parametr określa, który czujnik wysyła dane. Gdy czujnik wysyła zostanie zidentyfikowany, wtedy odpowiednie elementy interfejsu 8/10
użytkownika są aktualizowane z danych zawartych w tablicy typu float przekazywanej jako drugi argument do metody. Tak wygląda jej przykładowa implementacja: { { public void onsensorchanged(sensorevent event) { synchronized (this) { if (event.sensor.gettype() == Sensor. TYPE_ACCELEROMETER) xviewo.settext("accel X: " + event.values[0]); yviewo.settext("accel Y: " + event.values[1]); zviewo.settext("accel Z: " + event.values[2]); if (event.sensor.gettype() == Sensor.TYPE_MAGNETIC_FIELD) xviewa.settext("mag. X: " + event.values[0]); yviewa.settext("mag. Y: " + event.values[1]); zviewa.settext("mag. Z: " + event.values[2]); public void onaccuracychanged(sensor sensor, int accuracy) { 4. W metodzie onpause należy wyrejestrować obiekt klasy implementującej interfejs SensorListener (w naszym przypadku to klasa w której właśnie pracujemy) za pomocą metody unregisterlistener klasy SensorManager. protected void onpause() { super.onpause(); sm.unregisterlistener(this); Rys 2. Przykładowe działanie programu 9/10
Przykładowe zadania do samodzielnego rozwiązania Zadanie 1 (2p) Utworzyć program typu Hello World i uruchomić na rzeczywistym urządzeniu lub emulatorze. Następnie zrealizować odczyt danych z sensorów zgodnie z podejściem opisanym w sekcji Wykorzystanie sensorów i przedstawić rozwiązanie w urządzeniu rzeczywistym. Należy wyświetlić pomiary z sensorów pola magnetycznego oraz grawitacyjnego (ewentualnie akceleracji). Zadanie 2 (2p) Z wykorzystaniem metody public static boolean getrotationmatrix (float[] R, float[] I, float[] gravity, float[] geomagnetic) zaimplementować mechanizm przeliczania dowolnego wektora wyrażonego w układzie odniesienia związanym z urządzeniem (b-frame) do lokalnego układu odniesienia związanego z bieżącym położeniem względem Ziemi. Wektor wejściowy powinien być podawany przy użyciu interfejsu użytkownika zbudowanego ze standardowych kontrolek (3 x EditText + Button). Wektor wyjściowy powinien być wyświetlany w polu TextView. Graficzny wygląd aplikacji może być postaci: Zadanie 3 (1p) Podczas prezentowania rozwiązania zadania 2 zinterpretować wyniki widoczne na ekranie. 10/10