Wydział Informatyki i Zarządzania
kierunek studiów: Informatyka specjalność: Teleinformatyka
Praca dyplomowa - magisterska
Aplikacja mobilna realizująca powiadomienia głosowe
za pomocą metod Text-To-Speech
Inż. Michał Herman
słowa kluczowe:
Android, text-to-speech,
Powiadomienia android, notyfikacjię
Notyfikacje głosowe, przetwarzanie teksu na mowę
Niniejsza praca dyplomowa zawiera informacje o metodach pozyskiwania
powiadomień w systemie Android oraz przetwarzania danych zawartych w tych
powiadomieniach. Druga część pracy opisuje implementację mechanizmów
przetwarzania tekstu (powiadomień z części pierwszej) na mowę w systemie Android.
Finalnie w pracy przedstawiona została aplikacja, która przekazuje powiadomienia
systemu, takie jak wiadomości tekstowe, emaila czy informacje z portali
społecznościowych w formie głosowej dla użytkownika
opiekun pracy
dyplomowej
.................................................. ....................... ....................... Tytuł/stopień naukowy/imię i nazwisko ocena podpis
Do celów archiwalnych pracę dyplomową zakwalifikowano do:*
a) kategorii A (akta wieczyste)
b) kategorii BE 50 (po 50 latach podlegające ekspertyzie) * niepotrzebne skreślić
pieczątka Instytutu, w którym
student wykonywał pracę
Wrocław 2015
2
Spis Treści
Spis Treści .................................................................................................................................. 2
Spis Tabel ................................................................................................................................... 3
Spis Listingów ............................................................................................................................ 3
Spis Ilustracji .............................................................................................................................. 4
1. Wstęp .................................................................................................................................. 6
2. Przegląd dostępnych aplikacji ............................................................................................ 7
2.1. SMS Reader ................................................................................................................. 7
2.2. Notification Avatar ...................................................................................................... 8
2.3. Voice Notify ................................................................................................................. 9
2.4. Notification Reader .................................................................................................... 10
2.5. Speak Me .................................................................................................................... 11
2.6. Zestawienie funkcji istniejących aplikacji ................................................................. 12
3. Powiadomienia w systemie Android ................................................................................ 13
4. Metody przechwytywania powiadomień ......................................................................... 16
4.1. Accessibility Service - usługa ułatwiania dostępu ..................................................... 17
4.2. Notification Listener Service - usługa nasłuchiwana notyfikacji .............................. 19
4.3. Usługa telefonu dla systemu Android ....................................................................... 20
4.4. Podsumowanie i porównanie metod pozyskiwania notyfikacji................................. 21
5. Przetwarzanie obiektów Powiadomień ............................................................................ 21
6. Metody i implementacje silników Text-To-Speech .......................................................... 26
6.1. Text-To-Speech .......................................................................................................... 26
6.2. Budowa systemu Text-to-Speech ............................................................................... 29
7. Synteza mowy w środowisku Android ............................................................................. 31
7.1. Dragon Mobile SDK .................................................................................................. 31
7.2. iSpeech API ................................................................................................................ 35
7.3. Text To Speech API Google ...................................................................................... 37
7.4 Porównanie syntezatorów mowy ............................................................................... 40
8. Aplikacja Notification Catcher. ....................................................................................... 45
8.1. Wymagania funkcjonalne i niefunkcjonalne aplikacji .............................................. 46
8.1.1. Wymagania funkcjonalne ................................................................................... 46
8.1.2. Wymagania niefunkcjonalne .............................................................................. 47
8.2. Model aplikacji .......................................................................................................... 48
8.3. Zastosowane technologie ........................................................................................... 49
8.4. Struktura aplikacji ...................................................................................................... 49
9. Interfejs użytkownika aplikacji ........................................................................................ 53
3
10. Podsumowanie .............................................................................................................. 58
11. Bibliografia .................................................................................................................... 59
Spis Tabel
Tabela 1. Porównanie aplikacji czytających notyfikacje. ........................................................ 13 Tabela 2. Porównanie sposobów pozyskiwania notyfikacji. .................................................... 21 Tabela 3. Lista stałych klasy Notification ważnych przy odczytywaniu powiadomienia ....... 22 Tabela 4. Wyniki testu na syntezatora Dragon Mobile ............................................................ 41 Tabela 5. Wyniki testu dla syntezatora iSpeech. ...................................................................... 42
Tabela 6. Wynik testu dla syntezatora Google. ........................................................................ 43 Tabela 7. Zestawieni wyników testu syntezatorów mowy ....................................................... 44
Tabela 8. Wymagania funkcjonalne aplikacji Notification Catcher. ....................................... 46 Tabela 9. Wymagania niefunkcjonalne aplikacji Notification Catcher. .................................. 47
Spis Listingów
Listing 1. Fragment kodu realizującego wystawienie powiadomienia .................................... 15 Listing 2. Fragment kodu przechwytującego powiadomienia za pomocą Accessibility Service
.................................................................................................................................................. 18 Listing 3. Fragment kodu źródłowego realizującego pobieranie notyfikacji za pomocą
Notification Listener. ............................................................................................................... 20 Listing 4. Implementacja wydobycia obiektu Bundle z obiektu Notification .......................... 23 Listing 5. Pobieranie elementów tekstowych z klasy Bundle. ................................................. 23
Listing 6. Analiza widoku powiadomienia w celu wyodrębnienia tytułu i treści
powiadomienia. ........................................................................................................................ 25 Listing 7. Pobieranie nazwy aplikacji w przypadku użycia metody opartej na
NotifiactionListenerSercice. ..................................................................................................... 26
Listing 8. Pobieranie nazwy aplikacji wystawiającej notyfikacje w przypadku użycia metody
Accessibility Service. ............................................................................................................... 26
Listing 9. Realizacja usługi TTS korzystającej z Dragon Mobile API .................................... 34 Listing 10. Przykład implementacji syntezatora mowy opartego na API iSpeech. ................. 36
Listing 11. Przykładowy kod inicjalizujący Text-To-Speech Google API. ............................. 38
4
Spis Ilustracji
Rys. 1. Interfejs użytkownika aplikacji SMS Reader ................................................................. 7 Rys. 2. Uprawnienia aplikacji SMS Reader. .............................................................................. 8 Rys. 3. Interfejs użytkownika aplikacji Notification Avatar. ..................................................... 9
Rys. 4. Interfejs użytkownika aplikacji Voice Notify .............................................................. 10 Rys. 5. Interfejs użytkownika aplikacji Notification Reader ................................................... 11 Rys. 6. Interfejs użytkownika aplikacji Speak Me. .................................................................. 12 Rys. 7. Notyfikacja w widoku normalnym .............................................................................. 14 Rys. 8. Notyfikacja w widoku dużym ...................................................................................... 14
Rys. 9. Cykl życia notyfikacji .................................................................................................. 15 Rys. 10. Schemat budowy moduły NLP. ................................................................................. 29 Rys. 11. Architektura biblioteki Speech Kit. ........................................................................... 31
Rys. 12. Schemat działania Text-to-Speech Dragon Mobile API ............................................ 32 Rys. 13. Struktura pakietu dragon mobile API. ....................................................................... 33 Rys. 14. Struktura pakietu iSpeech API ................................................................................... 35 Rys. 15. Struktura pakietu Android TTS . ................................................................................ 37 Rys. 16. Schemat działania aplikacji Notification Catcher. ..................................................... 48 Rys. 17. Struktura pakietu aplikacji Notification Catcher........................................................ 50
Rys. 18. Ekran startowy aplikacji przy pierwszym uruchomieniu (po lewej), w trybie
normalnego działania (po prawej). ........................................................................................... 53 Rys. 19. Ekran ustawień aplikacji. ........................................................................................... 54
Rys. 20. Ekran ustawień Ułatwień dostępu z włączonymi uprawnieniami dla aplikacji
Notification Catcher. ................................................................................................................ 55
Rys. 21. Ekran Zabezpieczenia z informacją, że jedna aplikacja ma dostęp do powiadomień.
.................................................................................................................................................. 55
Rys. 22. Ekran Dostępu do powiadomień informujący prawach dostępu aplikacji Notification
Catcher do powiadomień. ......................................................................................................... 56
Rys. 23. Ekran Ustawienia Powiadomień aplikacji Notifiacation Catcher. ............................. 56 Rys. 24. Ekran Historia Powiadomień z notyfikacjami zebranymi przez aplikację. ............... 57
5
Niniejsza praca dyplomowa zawiera informacje o metodach pozyskiwania
powiadomień w systemie Android oraz przetwarzania danych zawartych w tych
powiadomieniach. W pierwszej części scharakteryzowanie zostały metody pozyskiwania
informacji o powiadomieniach z systemu Android. Opisane zostały metody używające usługi
ułatwiania dostępu, telefonii oraz usługi Notification Service. Przedstawiony został również
sposób przetwarzania pobranych informacji z notyfikacji, który umożliwia późniejsze
przeczytanie tych informacji przez lektora.
Druga część pracy opisuje implementację mechanizmów przetwarzania tekstu
(powiadomień z części pierwszej) na mowę w systemie Android. Przedstawione zostały tu
zarówno mechanizmy bazujące na natywnych aplikacjach oraz usługi oparte o platformy
oprogramowanie jako usługa. Mechanizmy przetwarzania dźwięku na mowę zostały
przetestowane i porównane pod kątem czytanie języka polskiego. Finalnie w pracy
przedstawiona została aplikacja, która przekazuje powiadomienia systemu, takie jak
wiadomości tekstowe, emaila czy informacje z portali społecznościowych w formie głosowej
dla użytkownika. Aplikacja ta korzysta z mechanizmów opisanych w niniejszej pracy,
zaimplementowane w niej obsługę kilku mechanizmów pozyskiwania powiadomień oraz
kilka mechanizmów przetwarzania tekstu na mowę.
This thesis contains information about methods of collecting notifications in Android
operating systems. It also contains information about transformation of notification data to
data format which can be handled by different part of applications. First part of this document
tells how to get notification data in Android operating systems using methods based on
Accessibility Service, Notification Listener service and Telephony Service. It also shows how
to transform data from notification to text data which can be read by lector.
Second part of this thesis shows various implementation of Text-To-Speech methods
(which can read information from notification) in Android operation system. It tells about
standalone Android Text-To-Speech solutions and also about solutions based of Software as
Service application model. Text-To-Speech solutions were tested for pronunciation of Polish
language. Finally, thesis presents Android application which can get information about
notifications (emails, incoming calls, short text messages, social portal notifications) and then
read that information using Text-To-Speech methods.
6
1. Wstęp
Przetwarzanie teksu na mowę w ostatnich latach uległo znacznemu rozwojowi.
Jeszcze kilka lat temu syntezatory imitujące ludzką mowę brzmiały sztucznie i mało kto miał
ochotę ich słuchać. Dziś TTS (Text-to-Speech) odnajdziemy w wielu dziedzinach życia:
smartphone’ach, komputerach czy samochodach. Wszystkie te urządzenia mogą
komunikować się z użytkownikiem za pomocą głosu, czy to poprzez reagowanie na
polecenia (rozpoznawanie mowy), czy też pytanie lub oznajmianie użytkownikowi
informacji(przetwarzanie tekstu na mowę). Wszystkie te urządzenia mogą czytać za
użytkownika treści stron internetowych, wiadomości czy książki. Natomiast jakość i
upodobnienie do ludzkiego głosu jest coraz to lepsze, z każdą następną wersją popularnych
silników przetwarzania teksu na mowę.
Na początku należy zaznajomić się z terminami powiadomienie i notyfikacja,
ponieważ pojęcia te będą przetaczały się przez całą pracę. Pierwsze z nich to powiadomienie,
czyli informacja pojawiająca się na pasku aktywności systemu Android w momencie, gdy
wystąpi jakieś zdarzenie. Kolejnym pojęciem jest notyfikacja, czyli zapożyczone z języka
angielskiego słowo, oznaczające to samo co powiadomienie. Oba te terminy będą w niniejszej
pracy używane zamienianie, i będą miały to samo znaczenie.
Celem niniejszej pracy dyplomowej jest analiza rozwiązań przetwarzania
powiadomień wystawianych przez aplikacje systemu Android w kontekście ich przekazania
użytkownikowi za pomocą technologii przetwarzania tekstu na mowę (Text-To-Speech). W
kolejnych rozdziałach zostaną przedstawione sposoby pozyskiwania powiadomień z aplikacji
i systemu operacyjnego w środowisku Android. Przeanalizowane w drugiej kolejności zostaną
metody Text-To-Speech dostępne w środowisku Android oraz sposoby ich użycia. Omówione
zostaną silniki przetwarzania tekstu, dostępne jako natywne programy systemu Android oraz
dostępne rozwiązania, oferowane w modelu oprogramowanie jako usługa (Software as a
Service - SaaS), wymagająca od aplikacji ciągłego połączenia internetowego.
Aby pokazać możliwości powiadomień oraz ich przekazywania użytkownikowi w
sposób nie wymagający odblokowywania ekranu, czy wyjmowania telefonu, przedstawiono
przykład aplikacji, zajmującej się przekazywaniem informacji znajdujących się w
powiadomieniach w sposób głosowy, za pomocą metod przetwarzania dźwięku na mowę.
7
2. Przegląd dostępnych aplikacji
Rynek aplikacji na urządzenia z Androidem jest ogromny. Liczba aplikacji w sklepie
Play sięga 1.3 miliona. Można jednak znaleźć tam niewiele aplikacji, które umożliwiają
czytanie wiadomości tekstowych, przychodzących maili, powiadomień z aplikacji
społecznościach czy komunikatorów. Czytających takie informacje aplikacji można policzyć
na palcach jednej ręki. W kolejnych podrozdziałach przedstawione zostały najpopularniejsze
aplikacje tego typu, dostępne dla systemu Android. Aplikacje testowane i opisane w
poniższym rozdziale, zostały wybrane na podstawie najczęściej pobieranych ze sklepu Google
Play, po podaniu frazy „czytanie powiadomień” (ang. Notification Reader ).
2.1. SMS Reader
SMS Reader jest aplikacją czytającą przychodzące wiadomości tekstowe. Dodatkowo
informuje głosowo o nadchodzącym połączeniu, czytając identyfikator dzwoniącego. W
preferencjach aplikacji można dodać ekranowy widget, umożliwiający włączenie lub
wyłączenie funkcji powiadomień głosowych. Domyślnie, z powodów bezpieczeństwa,
włączona jest opcja czytania jedynie nadawcy połączenia i wiadomości tekstowej. Działanie
aplikacji można zdefiniować korzystając z ustawień [13].
Rys. 1. Interfejs użytkownika aplikacji SMS Reader
SMS Reader oferuje jedynie bardzo podstawowe funkcje w dziedzinie notyfikacji
głosowych. Nie potrafi odczytać nic więcej, oprócz wiadomości tekstowych i identyfikacji
przyszłego rozmówcy. Powodem tak małej funkcjonalności aplikacji jest wykorzystywany
8
przez nią sposób pobierania powiadomień z systemu. SMS Reader korzysta przy
przechwytywaniu notyfikacji z usługi telefonu. Usługa ta nie jest przeznaczona do
przechwytywania powiadomień a do obsługi wiadomości tekstowych, oraz połączeń
telefonicznych. Dlatego też program ma z góry narzucone ograniczenia związane z wybraną
architekturą.
Rys. 2. Uprawnienia aplikacji SMS Reader.
Ponadto warto wspomnieć, iż instalując SMS Reader musimy nadać uprawnienia do
telefonu i wiadomości tekstowych. Jest to potencjalnie niebezpieczne, aplikacja taka może
zbierać informację z tych funkcji telefonu. Jednak w przypadku tej aplikacji nie ma takich
obaw, ponieważ program nie posiada na liście uprawnień dostępu do sieci co uniemożliwia
przesyłanie gromadzonych informacji do twórcy. Należy również wspomnieć, iż aplikacja
korzysta z systemowej implementacji silnika Text-to-Speach. Aby w pełni z niej korzystać
użytkownik musi zainstalować pakiety językowe do standardowej usługi, lub pobrać jeden z
syntezatorów mowy dostępny dla systemu Android oraz go skonfigurować.
2.2. Notification Avatar
W aplikacji Notification Avatar powiadomienia prezentowane są przez animowanego
awatara kobiety. Czyta ona wiadomości tekstowe, emaile oraz inne zdarzenia pojawiające się
w pasku notyfikacji. Aplikacja korzysta z ułatwiania dostępu, którą należy włączyć.
Informację o tym użytkownik dostaje przy pierwszym uruchomieniu programu. Następnie
zostaje przekierowany do ustawień ułatwień dostępu, aby zmienić uprawnienia. Bez tej
operacji, program nie będzie spełniał swojej funkcji. Po nadaniu uprawnień użytkownik może
cieszyć się słuchając powiadomień, a mówiąc dokładniej fragmentów powiadomień,
ponieważ aplikacja ta ma problemy z odczytywaniem całości informacji zawartych w
notyfikacjach [14]. W przypadku najpopularniejszego klienta poczty Gmail, zamiast nadawcy
i choćby tytułu maila, aplikacja przeczyta informację, że notyfikacja pochodzi z aplikacji
Gmail. Użytkownik nie usłyszy żadnych dodatkowych informacji, i aby dowiedzieć się jaka
jest treść wiadomości, zmuszony jest spojrzeć na ekran telefonu. Tu czeka go kolejna
niespodzianka: animowana postać dziewczyny czytającej notyfikację. Pojawia się on w
momencie przechwycenia przez aplikację powiadomienia, i znika dopiero po przeczytaniu
komunikatu. Jest to rozwiązanie nie praktyczne. Ponadto może irytować niektórych
użytkowników. Dobrze, że istnieje możliwość wyłączenia tej opcji w ustawieniach aplikacji.
9
Rys. 3. Interfejs użytkownika aplikacji Notification Avatar.
W ustawieniach znajduje się jeszcze kilka opcji pozwalających dostosować działanie
aplikacji do potrzeb użytkownika. Jest między innymi możliwość czytania notyfikacji tylko
gdy ekran jest wyłączony, czy opcja potrząśnięcia telefonem w celu zatrzymania czytania
notyfikacji. Na szczególną uwagę zasługuje lista uprawnień wymaganych przez aplikację. Jest
ona bardzo długa w porównaniu choćby z SMS Reader. Notification Avatar prócz
wspomnianych wcześniej uprawnień do ułatwień dostępu wymaga między innym dostępu do:
odczytywania stanu i informacji o telefonie, nagrywania dźwięków, odczytywania kontaktów,
wyłączania blokady telefonu, kont na urządzeniu, czy pełnego dostępu do sieci. Jak na
aplikację próbującą czytać powiadomienia to o wiele za dużo. Skoro aplikacja korzysta z
wbudowanego silnika Test-to-Speech i ułatwień dostępu, to te wymienione dwa uprawnienia
powinny w zupełności wystarczyć, aby Notification Avatar mógł pracować. Z punktu
widzenia bezpieczeństwa i dostępu do danych nie jest już tak oczywiste, jak w przypadku
SMS Reader, że oprogramowanie to nie zbierania ani nie przesyła poufnych informacji z
telefonu użytkownika do twórców.
2.3. Voice Notify
Voice Notify jest bardziej rozbudowaną aplikacją głoszącą powiadomienia używając
metod przetwarzania tekstu na mowę (Text-To-Speech). Posiada ona wiele funkcji:
czytanie notyfikacji toast,
widget włączający/wyłączający głosowe notyfikacje,
konfigurowalne wiadomości TTS,
wybór silnika TTS,
ustawienia czytania, gdy ekran czy zestaw słuchawkowy jest włączony/wyłączony,
lub telefon jest w trybie cichym/wibracji,
ustawienia czasu, gdy notyfikacje nie będą czytane,
opcję potrząśnij, aby wyciszyć,
konfigurowalne opóźnienia pomiędzy notyfikacjami,
powtarzanie powiadomień co określony interwał, gdy ekran jest wyłączony,
historie notyfikacji [15].
10
Rys. 4. Interfejs użytkownika aplikacji Voice Notify
Aplikacja ta, jak wynika z powyższych funkcji jest dość rozbudowana. Jednak interfejs
użytkownika nie jest czytelny i zajmuje trochę czasu za czym użytkownik przyzwyczai się do
jego obsługi. Również ta aplikacja do czytania powiadomień używa systemowego silnika
Text-to-Speech, co i w tym przypadku wymaga dodatkowej konfiguracji przez użytkownika.
Liczba funkcji aplikacji niesie to za sobą szereg uprawnień, które użytkownik musi nadać
aplikacji by mogła poprawnie funkcjonować. Voice Notify wymaga między innymi dostępu
do systemu Bluetooth, ustawień audio czy wibracji. Potrzebuje również uprawnień ułatwień
dostępu (Accessibility Service). Nadając programowi dostęp do ułatwień dostępu, może on
gromadzić wszystkie zdarzenia zachodzące w systemie, zaczynając od powiadomień, poprzez
wszystkie kliknięcia użytkownika, a kończąc na przechwytywaniu wpisywanych haseł. Z tego
powodu użytkownik powinien zastanowić się dwa razy czy aplikacja, która wymaga takich
uprawnień jest godna zaufania i pochodzi ze znanego źródła.
2.4. Notification Reader
Notification Reader to aplikacja przeznaczona do czytania powiadomień podczas
korzystania z zestawu słuchawkowego czy to Bluetooth, czy przewodowego. Twórcy
przekonują, iż jest ona idealna, gdy słucha się muzyki na urządzeniu, lub chce się po prostu
dowiedzieć o powiadomieniu, bez wyciągania telefonu z kieszeni i patrzenia na ekran.
Głównymi funkcjami aplikacji są:
wykrywanie przychodzącego połączenia, aby nie odtwarzać powiadomień podczas
rozmowy,
włączanie lub wyłączanie odpowiednich wyjść audio,
komunikacja przez Bluetooth,
czytanie tylko notyfikacji wystawianych przez wybrane aplikacje.
Aby używać tej aplikacji użytkownik musi nadać jest dostęp do notyfikacji w ustawieniach
bezpieczeństwa systemu [16]. Jako jedyna z aplikacji opisanych w tym rozdziale
wykorzystuje usługę dostępu do notyfikacji jak metodę pobierania powiadomień. Przyczyną
zapewne jest wiek aplikacji, który w momencie powstawanie tej pracy wynosi około
miesiąca. Aplikacja poprosi o włączenie tych uprawnień przy pierwszym uruchomieniu. W
11
przypadku, gdy uprawnienia nie zostaną nadane, Notification Reader nie przeczyta żadnego
powiadomienia. Aplikacja wykorzystuje standardową usługę przetwarzania tekstu na mowę
dostępną w systemie Android. Co za tym idzie, wymaga zainstalowania danych językowych,
oraz indywidualnego ich ustawienia w systemie.
Rys. 5. Interfejs użytkownika aplikacji Notification Reader
Twórca w opisie programu podaje, iż aplikacja potrafi czytać informację z różnych
programów zainstalowanych w systemie oraz jak je konfigurować pod dany program. Jednak
w rzeczywistości po zainstalowaniu aplikacji użytkownik ma możliwość słuchania
powiadomień i konfigurowania ich dla losowej liczby aplikacji znajdujących się w systemie.
Domyślnie zawartość czytanych notyfikacji zależy od ustawień pod konkretną aplikację w
ustawieniach Notification Reader. Przykładowo, odtwarzana wiadomość tekstowa będzie
zawierać tylko treść, wiadomość email natomiast informację o nadawcy i temat bez treści.
2.5. Speak Me
Speak Me pozwala telefonowi czytać notyfikacje, ale nie ze wszystkich aplikacji.
Tylko z tych, z których użytkownik chce, aby były przeczytane. Umożliwi ustawienie
długości przerwy pomiędzy powiadomieniami z tej samej aplikacji, tak aby nie przeszkadzały
one użytkownikowi. Aplikacja ta również wymaga dostępu do uprawnień ułatwień dostępu,
czyli jest kolejną w zestawieniu używającą tej metody. Text-to-Speech, z którego korzysta
aplikacja, to również systemowy silnik androida [17]. Tak naprawdę aplikacja poza
wyglądem nie różni prawie wcale od wcześniej scharakteryzowanej aplikacji Voice Notify.
Posiada bardzo podobny zestaw funkcji, i tak jak wcześniejsza aplikacja ma problemy z
przeczytaniem całego powiadomienia. Również i w tym przypadku o przychodzącym emailu
poinformuje użytkownika (jeśli w ogóle to się stanie, gdyż podczas testów nie udało się tej
aplikacji przeczytać wszystkich powiadomień z Gmail) o temacie maila. Nie zostanie
przeczytana informacja o treści ani nadawcy.
12
Rys. 6. Interfejs użytkownika aplikacji Speak Me.
Na uwagę i jedyny plus aplikacji są uprawnienia jakich wymaga do poprawnego
działania. Jako jedyna aplikacja w zestawieniu potrzebuje jedynie dostępu do ułatwień
dostępu oraz wibracji. Wypada więc pod tym względem najlepiej z opisywanych aplikacji.
2.6. Zestawienie funkcji istniejących aplikacji
Wszystkie aplikacje opisane w punktach 2.1-2.5 prócz Notification Reader korzystają
przy przechwytywaniu powiadomień z usługi ułatwień dostępu systemu Android. A tym
samym umożliwiają twórcą dostęp do wszystkiego, co wyświetlane jest na ekranie
smatphone’a oraz wszystkich informacji wprowadzanych przez użytkownika. Z punktu
widzenia bezpieczeństwa nie jest to dobra praktyka, aby aplikacja posiadała taki dostęp do
systemu. Może to zostać wykorzystane przez autora aplikacji do gromadzenia bardzo
poufnych danych o zachowaniu użytkownika. Co gorsza, daje niemalże nieograniczone
możliwości dostępu do wprowadzanych do urządzenia. Z drugiej jednak strony twórcy
systemu operacyjnego Android aż do wersji Jelly Bean (4.2) nie pomyśleli o udostępnieniu
innej metody na dostęp przez aplikacje do powiadomień pochodzących od innych aplikacji.
Dopiero w Jelly Bean programiści dostali do dyspozycji usługę nasłuchującą notyfikacje
(Notification Listener Service). Jedyną aplikacją korzystającą z tej metody dostępną w
momencie powstawania tej pracy jest Notification Reader. Odczytywanie notyfikacji przez
aplikację wykorzystując Notification Listener jest bezpieczniejsze, niż w przypadku usługi
ułatwiania dostępu. Dzieje się tak dlatego, że użytkownik zmuszony jest nadać aplikacji
uprawnienia jedynie do czytania powiadomień z paska notyfikacji i żadnych innych, o ile
aplikacja nie posiada dodatkowych innych funkcji wymagających specyficznych uprawnień.
Użyty w aplikacji mechanizm powiadomień informuje o tym, iż aplikacje korzystające z
niego, powstały jeszcze przed wydaniem Androida w wersji 4.2. Może to powodować
problemy z odczytem notyfikacji na urządzeniach wyposażonych w wersję systemu nowszą
niż Jelly Bean. Powodem tego jest rozbudowany widok powiadomień, który został
wprowadzony wraz z tą wersją systemu. A mianowicie programiści uzyskali większe
13
możliwości konfigurowania treści, i dużo większy wpływ na wygląd wystawianych przez
aplikację powiadomień.
Poniższa tabela zawiera porównanie aplikacji realizujących powiadomienia głosowe
przy użyciu metod przetwarzania tekstu na mowę.
Tabela 1. Porównanie aplikacji czytających notyfikacje.
SMS Reader Notifiaction
Avatar
Voice Notify Notification
Reader
SpeakMe
Metoda
pozyskiwania
powiadomień
Usługa
telefonu dla
systemu
Android
Accessibility
Service
Accessibility
Service
Notifiction
Listener
Accessibility
Service
Historia
powiadomień
- X x - -
Aplikacja TTS Systemowa Systemowa Systemowa Systemowa Systemowa
Rodzaje
czytanych
powiadomień
Wiadomości
tekstowe,
informację o
połączeniach
wszystkie wszystkie Wiadomości
tekstowe,
kalendarz,
system,
wszystkie
Wybór
aplikacji, z
których
powiadomienia
będą czytane
- x x X,
ograniczony
x
Podsumowując, żadna z aplikacji nie potrafi odczytać wszystkich powiadomień
systemu Android, jak również całej treści powiadomienia. Sytuacja ta wygląda lepiej dla
wiadomości tekstowych, z którymi bez problemu radzi sobie każda z aplikacji. Jednak typowe
wiadomości tekstowe nie są już tak popularne jak kilka lat temu. Dziś dużo większym
zainteresowaniem cieszą się komunikatory takie jak Facebook Messanger, Skype, Hangouts.
Z wiadomościami z takich programów aplikacje czytające notyfikacje jednak sobie w pełni
nie radzą. Jeszcze gorzej wypada choćby obsługa poczty, gdzie wypowiedziana przez
program jest tylko nazwa aplikacji nadającej powiadomienia lub sam tytuł, bądź nadawca
wiadomości.
3. Powiadomienia w systemie Android
Wszystkie informacje o zdarzeniach istotne z punktu widzenia użytkownika w
systemie Android przekazywane są za pomocą notyfikacji. Notyfikacje są skróconymi
informacjami o nowej wiadomości sms, emailu, nieodebranym połączeniu czy wiadomości z
komunikatora skocznościowego. Pojawiają się one w tak zwanym pasku stanu systemu
umieszczonym w górnej części ekranu. Wszystkie powiadomienia dla użytkowania są
zunifikowane. Wystawiane zostają zawsze przez ten sam mechanizm. Posiadają własny cykl
życia. Reprezentowane są przez klasę Notification a zarządzane przez klasę
NotificationManger.
W wersji Jelly Bean, notyfikacje zostały zaktualizowane zarówno pod względem
funkcjonalnym, jak i graficznym. Było to najpoważniejsze odświeżenie funkcjonalności od
początku Androida. Od tej pory notyfikacje mogą zawierać akcje, dzięki którym użytkownik
może wykonać czynność bezpośrednio z paska powiadomień. Wygląd stał się bardziej
elastyczny, może być rozszerzany, aby pokazać dodatkowe informacje. Wprowadzona została
również obsługa priorytetów, pomagająca sortować powiadomienia według ważności a
14
następnie wyświetlać je w kolejności od najistotniejszych, tak aby krytyczne informację były
przekazywane użytkownikowi z wyższym priorytetem. Notyfikacje mogą być wyświetlane w
jednym z dwóch styli:
Normal View(widok normalny),
Big view(duży widok).
Widok normalny to standardowy styl notyfikacji znany z starszych wersji Androida. Poniższy
rysunek przedstawia elementy notyfikacji w widoku normalnym. Układ ten zawiera takie
elementu jak:
Rys. 7. Notyfikacja w widoku normalnym
1. Tytuł/nazwę nadawcy powiadomienia.
2. Ikonę aplikacji wystawiającej powiadomienie lub zdjęcie nadawcy.
3. Treść powiadomienia.
4. Ilość podobnych wiadomości.
5. Druga ikonę identyfikującą aplikacje wysyłająca powiadomienia gdy zdjęcie nadawcy
znajduję się w miejscu. (2)
6. Czas wystąpienia notyfikacji.
Duży widok powiadomień dostarcza więcej informacji o zdarzeniu, które wystawiło
notyfikację. Jak łatwo zauważyć (rys. 7) duży widok posiada większość elementów z widoku
podstawowego. Jedyną różnicą jest oznaczona numerem 7 przestrzeń na dodatkowe
informacje. Przestrzeń ta może zawierać zarówno tekst jak i elementy graficzne.
Rys. 8. Notyfikacja w widoku dużym
Jak już wspomniano wcześniej, zaczynając od wersji Jelly Bean, Android wspiera opcjonalne
akcje wyświetlane w dolnej części notyfikacji. Dzięki akcją użytkownik ma możliwość
obsłużenia najczęstszych zadać wprost z powiadomienia bez potrzeby otwierania aplikacji
15
wystawiającej notyfikację. Przyspiesza to interakcję, a w połączeniu z opcją ‘przesuń aby
usunąć’ pomaga użytkownikowi zajmować się zdarzeniami. Notyfikacja może posiadać
maksymalnie trzy takie akcje. Natomiast każda akcją składa się z ikony oraz nazwy.
Przechodząc do tematu tworzenia powiadomień należy rozpocząć od obiektów, które
każda notyfikacja musi posiadać. Są to 3 elementy: mała ikona, tytuł i informacje dodatkowe.
Wszystkie inne obiekty są opcjonalne i ich obecność na ekranie zależy od twórcy aplikacji.
Jest to istotne z punktu widzenia późniejszego pobierania informacji z notyfikacji. Należy
mieć na uwadze, iż nie wszystkie obiekty muszą znajdować się w powiadomieniu i
zabezpieczyć się przed tym podczas zbierania informacji z powiadomienia. Poniższy
fragment kodu przedstawia tworzenie prostej notyfikacji.
Listing 1. Fragment kodu realizującego wystawienie powiadomienia
Z punktu widzenia aplikacji, która ma za zadanie zebranie informacji z notyfikacji ważnym
elementem jest cykl życia takiej notyfikacji. Ilustruje to poniższy rysunek.
Rys. 9. Cykl życia notyfikacji
Notyfikacja rozpoczyna swoje istnienie od stworzenia obiektu NotifictionCompact, który
przechowuje całą treść i wygląd notyfikacji. Gdy już taki obiekt powstanie, zostanie on
Intent intent = new Intent(this, MainActivity.class); PendingIntent pIntent = PendingIntent.getActivity(this, 0, intent, 0); Notification n = new Notification.Builder(this) .setContentTitle("Czytanie powiadomień włączone") .setContentText("Przejdź do aplikacji aby wyłączyć") .setSmallIcon(R.drawable.ic_launcher) .setContentIntent(pIntent) .setAutoCancel(true).build(); NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); notificationManager.notify(notificationID, n);
16
przekazany do obiekty klasy NotificationManager, która to zanim wyświetli notyfikację musi
uzyskać dostęp do usługi Notyfikacji czyli NotificationService. Następnie metoda notify()
klasy Notification Manager wysyła notyfikacje na ekran smartphone’a. Wtedy dopiero
użytkownik ma szansę ją zobaczyć. Wystawieniu notyfikacji na ekran może towarzyszyć
odtworzeniu dźwięku lub uruchomienie się wibracji, mających na celu przyciągnięcie uwagi
użytkownika. W przypadku, gdy użytkownik nie usunie notyfikacji do czasu nadejścia
nowego powiadomienia z tej samej aplikacji nastąpi w większości przypadków
zaktualizowanie istniejącej notyfikacji. Tej akcji również mogą towarzyszyć sygnały
odtwarzane przy publikowaniu powiadomienia.
Analizując cykl życia notyfikacji, powiadomienie powinno być pobrane w momencie
pojawienia się informacji o niej na ekranie. W najlepszym przypadku jeszcze przed
odtworzeniem dźwięki lub wibracji, albo tuż po niej z odpowiednim opóźnieniem. Należy też
wziąć po uwagę stan ekranu telefonu w momencie nadejścia wiadomości, ponieważ w tym
momencie użytkownik może zajmować się rozmową, grą lub inną czynnością, która nie
powinna zostać zakłócona odtworzeniem notyfikacji głosowej. W najprostszym przypadku
odtworzenie notyfikacji powinno być włączone gdy ekran jest wyłączony.
4. Metody przechwytywania powiadomień
Pierwszym wyzwaniem, który napotykamy przy tworzeniu aplikacji czytającej
powiadomienia jest sam dostęp aplikacji trzeciej do tych powiadomień. Jak już wspomniano
wcześniej różne aplikacje mogą wysyłać powiadomienia. System Android natomiast musi
zarządzać ich publikacją i usuwaniem. Łatwo można się domyślić, iż dostęp do notyfikacji
powinna mieć tylko aplikacja tworząca ją oraz system operacyjny. Tak też było aż do wersji
4.3 Jelly Bean, w której została wprowadzona usługa Notification Listener Service.
Umożliwia ona zarządzanie dostępem do powiadomień dla aplikacji trzecich. Usługa ta
opisana została w kolejnych rozdziałach pracy. Zanim jednak twórcy androida dodali
zarządzanie notyfikacjami do systemu, dostęp do powiadomień z innej aplikacji niż
macierzysta był trudny, ale nie niemożliwy. Aplikacyjne podglądanie notyfikacji we
wcześniejszych wersjach systemu umożliwia Accessibility Service, czyli usługa ułatwień
dostępu. Jest do usługa zaprojektowana na potrzeby ułatwienia korzystania z telefonu przez
osoby słabowidzące lub słabosłyszące. Dostęp do powiadomień poprzez Accessibility Service
nie jest jednak dostępem bezpośrednim. Korzystając z tej usługi należy wyciągnąć informację
o nadchodzącym powiadomieniu oraz jego treść z innych obiektów systemu. Temat ten
zostanie dogłębnie przeanalizowany w sekcji opisującej przechwytywanie notyfikacji za
pomocą Accessibility Service. Oprócz wyżej wymienionych Notification Service i
Accessibility Service istnieje jeszcze jedna metoda na przechwycenie powiadomień o
nadchodzących zdarzeniach w systemie, a mianowicie usługa telefonu. Jest ona najmniej
pomocna jeśli mamy zamiar gromadzić wszystkie notyfikacji, gdyż dzięki niej jest możliwe
zdobycie jedynie informacji o nadchodzących rozmowach telefonicznych i wiadomościach
tekstowych. Korzystając z usługi telefonu aplikacja może zebrać treść i nadawcę wiadomości
tekstowych, jak również identyfikator rozmówcy. Należy również wspomnieć, iż opisane
metody dostępu do notyfikacji w urządzeniach z Androidem w wersjach wcześniejszych niż
4.3 nie należą do najbezpieczniejszych z punktu widzenia użytkownika końcowego. Jednak
używając aplikacji korzystających z powiadomień należy mieć świadomość jakich uprawnień
ów program żąda od użytkownika.
17
4.1. Accessibility Service - usługa ułatwiania dostępu
Wielu użytkowników ma różne trudności, które zmuszają ich do korzystania z
urządzenia z Androidem w nieco inny sposób. Użytkownicy z fizycznymi, wizualnymi i
wiekowymi ograniczeniami mają trudności z widzeniem całego ekranu czy używaniu ekranu
dotykowego. Użytkownicy z problemami słuchowymi mogą również nie być wstanie odebrać
informacji audio czy powiadomień. Dlatego też system Android dostarcza dodatki i usługi
ułatwiania dostępu, aby pomóc tym użytkownikom operować urządzaniem w prostszy
sposób, włączając w to przetwarzanie tekstu na mowę, nawigację za pomocą gestów czy
rozpoznawanie mowy. Dzięki temu programiści mogą uczynić swoje aplikacje bardziej
dostępnymi. Usługa ułatwiania dostępu (Accessibility Service) umożliwia programiście
również bardzo duże możliwości w przechwytywaniu zdarzeń systemu Android. A
mianowicie, co najważniejsze w kontekście zbierania powiadomień dostęp do zdarzeń
notyfikacji.
Serwisem tym zarządza klasa AccessibilityService. Serwis ten działa w tle i odbiera
wszystkie sygnały z systemu operacyjnego gdy wystąpi zdarzenie AccessibilityEvent.
Wystąpienie AccessibilityEvent oznacza zmianę w interfejsie użytkownika systemu np.
zmianę podświetlenia, kliknięcie przycisku itd.. Oznaczać również może powstanie nowej
notyfikacji.
Aplikacja korzystająca z ułatwień dostępu musi posiadać odpowiednie uprawnienia. A
mianowicie wymaga w manifeście aplikacji uprawnia BIND_ACCESSIBILITY_SERVICE.
Uprawnienie to jest wymagane aby zapewnić aplikacji dostęp do usługi ułatwiania dostępu.
Oprócz uprawnień, aby program posiadał dostęp do odbierania zdarzeń, niezbędne jest
stworzenie serwisu rozszerzającego usługę Accessibility Service. Przykładowa implementacja
takiej usługi przedstawia poniższy fragment kodu.
18
Listing 2. Fragment kodu przechwytującego powiadomienia za pomocą Accessibility Service
Zawiera on niezbędne informacje, które muszą się znaleźć w pliku manifestu. Kolejnym
elementem jest zidentyfikowanie przychodzącej notyfikacji. Przychodzi tu z pomocą flaga
TYPE_NOTIFICATION_STATE_CHANGE, która informuje o tym iż nastąpiło zdarzenie
zmiany stanu notyfikacji, co z tym idzie powiadomienie dla użytkownika w pasku notyfikacji
zostało wystawione lub istniejące powiadomienie zostało aktualizowane o nowe informację.
Należy tutaj jednak wspomnieć iż flaga informująca o zmianie stanu
powiadomienia(TYPE_NOTIFICATION_STATE_CHANGE) nie informuje o tym czy
notyfikacja pojawiła się w pasku notyfikacji, czy też została wywołana przez klasę Toast
wystawiającą powiadomienia dla użytkownika w formie paska informacyjnego pojawiającego
się na tle aplikacji w dolnej części ekranu. Informacja ta jest istotna z tego powodu, iż w
większości przypadków powiadomienia w formie toast wystawiane są w trakcie działania
aplikacji na pierwszym planie i w bezpośredniej interakcji z użytkownikiem. Dlatego też
czytanie takich powiadomień nie niesie ze sobą wartości dodanej dla zwykłego użytkownika
pragnącego aplikacji do czytania notyfikacji. Co więcej, może przynieść odwrotny skutek, a
mianowicie stać się irytującym elementem programu. W związku z czym należy wprowadzić
mechanizm rozróżniania notyfikacji od powiadomienia typu Toast. Najprostszym, a zarazem
najpewniejszym sposobem rozpoznania twórcy klasy wystawiającej powiadomienie jest
wyciagnięciem tej informacji za pomocą metody getClassName klasy AccessibilityEvent.
Każde powiadomienie typu Toast będzie zawierało klasę źródłową com.android.Toast. Aby
upewnić się, że przechwycone zdarzenie zawiera treść powiadomienia, należy wyciągnąć z
obiektu event typu AccessibilityEvent obiekt Parcelable przy użyciu metody getParcelabe
public class ExampleAccessibilityService extends AccessibilityService { @Override public void onAccessibilityEvent(AccessibilityEvent event) { final int eventType = event.getEventType(); if (eventType == AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED) { if (event.getClassName().toString().contains(Toast.class.getName())) { // zdarzenie przychodzące to powiadomienie Toast } else { Parcelable parcelable = event.getParcelableData(); if (parcelable instanceof Notification) { // zdarzenie zawiera notyfikację } } } } @Override public void onInterrupt() { } @Override public void onServiceConnected() { } }
19
Data() a następnie sprawdzić czy wyłuskany obiekt jest instancją klasy Notification.
Posiadając zidentyfikowany obiekt notyfikacji można wydobyć z niego informację o treści
powiadomienia, nadawcy, czasie wystąpienia itd.. Sposób wyodrębniania informacji z
obiektów notyfikacji zostanie opisany dalszej części pracy w rozdziale Prasowanie
notyfikacji.
Mając na uwadze zagrożenia przed dostępem aplikacji trzeciej do tak wrażliwych
danych jak kliknięcia, czy zmiany interfejsu użytkownika, aby aplikacja mogła w pełni
korzystać ze swoich uprawnień zapisanych w manifeście, do użytkownika należy jeszcze
zadanie dodania uprawień do serwisu aplikacji w ustawieniach systemowych. Aby dodać te
uprawienie należy (w zależności od wersji systemu) przejść do Ustawień. Następnie odnaleźć
dział Ułatwienia dostępu. Wewnątrz tego działu odnaleźć aplikację i włączyć serwis. System
Android w momencie włączania poinformuje użytkownika o uprawnieniach jakie nadaje oraz
potencjalnym ryzyku dostarczania takich informacji dla aplikacji.
Nazwanie opisanej procedury metodą pozyskiwania powiadomień jest trochę na
wyrost, ponieważ jest ona tylko obejściem API notyfikacji, którego w starszych wersjach
Androida po prostu nie ma. Umożliwia, oprócz notyfikacji z paska powiadomień, wydobycie
również informacji przekazywanych do użytkownika przez klasę Toast. Jak już wspominano
wcześniej może być zarówna zaletą, jak i wadą rozwiązania w zależności od implementacji.
Co więcej dzięki Accessibility Service można wydobyć dużo więcej informacji o działaniu
aplikacji w systemie użytkownika, jak i o samym zachowaniu tegoż użytkownika. Tak więc
metoda ta może posłużyć do wyłuskiwania poufnych informacji z telefonu nieświadomego
użytkownika. Dlatego też trzeba mieć na uwadze uprawnienia jakie nadaję się aplikacji.
4.2. Notification Listener Service - usługa nasłuchiwana notyfikacji
Usługa Notification Listener Service została wprowadzona Androidzie 4.3 (API 18).
Serwis ten odbiera sygnały, gdy notyfikacja jest tworzona lub usuwana. Wraz z nową usługą
użytkownik dostaje dodatkową opcje w ustawieniach systemowych. Jest to dostęp do
powiadomień wewnątrz ustawień zabezpieczeń. Każda aplikacja korzystająca z Notification
Listener będzie po zainstalowaniu widoczna na liście uprawnionych do czytania notyfikacji.
Oczywiście domyślnie uprawnienia te nie są ustawiane same przez aplikację, lecz wymagają
ręcznego ustawienia przez użytkownika. Domyślnie nowa aplikacja pojawia się na liście
dostępu do powiadomień z wyłączonymi uprawnieniami. Usługa nasłuchiwania notyfikacji
daje użytkownikowi większy wpływ na dane przekazywane przez system do aplikacji trzeciej
niż ma to miejsce w przypadku usługi Accessibility Service. Jest to niewątpliwie na duży plus
dla usługi dostępu do notyfikacji w porównaniu z ułatwieniami dostępu. Również z powodów
bezpieczeństwa w systemie Android to kolejny krok do przodu. Wprowadzenie tej usługi
umożliwia programistom, bez tworzenia obejść (poprzez Accessibility Service), stworzenie
aplikacji zarządzających powiadomieniami czy przesyłającymi je do innych urządzeń,
systemów itp.. Używając Notification Listener można pracować tylko i wyłącznie z
powiadomieniami pojawiającymi się w pasku notyfikacji. Usługa ta nie dostarcza możliwości
przechwytywania powiadomień typu Toast. Nie trzeba również filtrować zdarzeń
nasłuchiwanych przez serwis ponieważ wszystkie one są notyfikacjami. Sprawia to iż użycie
tej metody jest łatwiejsze niż za pomocą Accessibility Service.
Klasą reprezentującą tą usługę jest NotificationListenerService. Posiada ona dwie
abstrakcyjne metody:
onNotifiactionPosted(),
onNotificationRemoved()
za pomocą których programista jest w stanie przechwycić informację o powstaniu lub
usunięciu notyfikacji. Oprócz tego pozwala również na programowe usunięcie
20
powiadomienia z ekranu telefonu bez angażowania użytkownika. Opcja ta jest niewątpliwie
przydatna w aplikacji czytającej notyfikacje, ponieważ dzięki niej po przeczytaniu treści
powiadomienia może zostać ono usunięte z ekranu, by nie informować użytkownika kolejny
raz o zdarzeniu, które zostało przekazane w sposób głosowy. Przykładową implementację
użycia Notification Listener Servie przedstawia poniższy listing.
Listing 3. Fragment kodu źródłowego realizującego pobieranie notyfikacji za pomocą Notification Listener.
Prosta implementacja Notification Listener musi zawierać jedynie przeciążenie dwóch
podstawowych metod serwisu. Z punktu widzenia aplikacji gromadzącej powiadomienia
najważniejsza jest metoda onNotificationPosted(), która pobiera obiekt StatusBarNotification
zawierający wszystkie informacje wyświetlone w powiadomieniu. Wewnątrz tej metody
należy zaimplementować proces ekstraktownia informacji z notyfikacji. Opisany zostanie on
w rozdziale opisującym prasowanie notyfikacji. Ważnym elementem, niezbędnym do
działania Listenera, jest nadanie odpowiednich uprawnień aplikacji w pliku manifestu. W
przypadku Notifification Listener te uprawnienia to
BIND_NOTIFICATION_LISTENER_SERVICE. Podobnie jak w przypadku wcześniejszej
metody niezbędne i w tym przypadku jest stworzenie odpowiedniej usługi w pliku manifestu.
Rozwiązanie opisane powyżej posiada jednak jedną wadę, a mianowicie dostępne jest
tylko dla systemu Android w wersji API większej lub równej 18, co w przypadku dość sporej
fragmentacji wersji sytemu zmusza twórców aplikacji do implementacji więcej niż jednej
metody pobierania notyfikacji. Z drugiej jednak strony jest to sposób przeznaczony do tego
typu działań, i w porównaniu do Accessibility Service w dużym stopniu przyśpiesza
pobieranie notyfikacji. Jest również rozwiązaniem znacznie bezpieczniejszym od
poprzednika.
4.3. Usługa telefonu dla systemu Android
Ostatnią z metod pozyskiwania informacji o powiadomieniach jest użycie usługi
telefonu systemu Android. Google udostępnia usługę telefonu jako jeden z elementów API,
dzięki niej programista ma możliwość w swojej aplikacji użyć elementów telefonu, takich jak
wysyłanie wiadomości czy wykonywania połączeń. Przy użyciu tej usługi jest również
możliwe przechwytywanie informacji o nadchodzącym połączeniu lub przychodzącej
wiadomości tekstowej. Użycie tego sposobu pozyskiwania notyfikacji ma jednak bardzo duże
ograniczenia, a mianowicie za pomocą tej usługi możliwe jest tylko pobieranie powiadomień
@SuppressLint("NewApi") public class ExampleListener extends NotificationListenerService { @Override public void onNotificationPosted(StatusBarNotification sbn) { // kod realizujący zadanie gdy notyfikacja zostaje wystawiona do paska // notyfikacji } @Override public void onNotificationRemoved(StatusBarNotification sbn) { // kod realizujący zadanie gdy notyfikacja zniknie z paska notyfikacji } }
21
o wiadomości tekstowej i nadchodzącym połączeniu. Na tle pozostałych dwóch metod, usługa
telefonii wypada dość blado.
Z uwagi na to, iż metoda ta używa funkcji telefonu do gromadzenia informacji,
aplikacja z niej korzystająca musi posiadać dość duże uprawnienia. Z przyczyn
bezpieczeństwa nie jest to optymalne rozwiązanie, ponieważ dzięki takim uprawnieniom
aplikacja może nie tylko odbierać informację o wiadomościach tekstowych, ale również
wysyłać takowe bez wiedzy użytkownika. Jest to kolejny argument za tym, iż metoda ta nie
należy do dobrych.
4.4. Podsumowanie i porównanie metod pozyskiwania notyfikacji
Przedstawione w poprzednich podrozdziałach sposoby pobierania informacji z
powiadomień wymagają porównania. W poniższej tabeli przedstawiono możliwości o raz
ograniczenia poszczególnych sposobów przechwytywania powiadomień w systemie Android.
Tabela 2. Porównanie sposobów pozyskiwania notyfikacji.
Accessibility
Service
Notification
Listener
Service
Telephony Service
Bezpośredni dostęp do powiadomień X - -
Rodzaj powiadomień, które można
odczytać za pomocą metody
Wszystkie Wszystkie Tylko wiadomości
tekstowe i informacje
o połączniu
Czytanie powiadomień typu Toast X - -
Możliwość usunięcia przechwyconego
powiadomienia z pulpitu
X - -
Dostęp do wrażliwych danych
użytkownika
Bardzo duży,
wszystkie
zdarzenia w
systemie
Tylko
powiadomienia
Wszystkie informacje
telefonu
Możliwość wyłączenia dźwięku
przychodzącego powiadomienia
- X -
Wyodrębnienie obiektu Notification z
przechwyconych informacji
X X -
Jak łatwo zauważyć analizując powyższą tabelę, najlepszą metodą okazuje się korzystanie z
Notification Listener Service. Metoda ta posiada najwięcej zalet ze wszystkich
wspomnianych, a przy tym jest najmniej skomplikowana w użyciu. Jako jedyna również
dostarcza możliwość wyłączenia dźwięku oraz usunięcia powiadomienia. Jest to bardzo duży
atut przy użyciu tej metody, gdyż pozwala na lepsze zarządzanie powiadomieniami w
aplikacji.
5. Przetwarzanie obiektów Powiadomień
Opisane we wcześniejszych rozdziałach metody pozyskiwania notyfikacji zwracają w
wyniku najczęściej obiekt Notification. Kolejnym zadaniem, które należy wykonać aby
notyfikacja mogła zostać przeczytana jest wyodrębnienie z tego obiektu informacji jakie
zawierała notyfikacja. Rozwiązanie tego problemu zostanie przedstawione właśnie w tym
rozdziale.
22
Należy zacząć od struktury obiektu Notification. Klasa ta zawiera osiem klas
odpowiedzialnych za akcje, które można wykonać na powiadomieniach oraz za generowanie
wyglądu notyfikacji, oraz interfejs obsługujący rozszerzanie notyfikacji. Oprócz tego kilka
metod oraz dużą ilość flag informujących o tym co jest treścią powiadomienia. Najważniejsze
z punktu widzenia aplikacji do przechwytywania notyfikacji przedstawia poniższa tabela.
Tabela 3. Lista stałych klasy Notification ważnych przy odczytywaniu powiadomienia
Nazwa Flagi Opis
EXTRA_TITLE_BIG Klucz klasy Extras: duży tytuł notyfikacji,
najczęściej nazwa nadawcy lub tytuł
wiadomości
EXTRA_TITLE Klucz klasy Extras: tytuł powiadomienia
ustawiony wcześniej za pomocą
metody setContentTitle(CharSequence).
EXTRA_INFO_TEXT Klucz klasy Extras: krótki kawałek tekstu
ustowiony poprzednio za pomocą
metody setContentInfo(CharSequence).
EXTRA_SUB_TEXT Klucz klasy Extras: trzecia lina tekstu
ustawiono wcześniej za pomocą
metody setSubText(CharSequence).
EXTRA_SUMMARY_TEXT Klucz klasy Extras: dodadkowa linka teskstu
wyświetlana gdy powiadominienie zostaje
rozciągnięta do dużego widoku.
EXTRA_TEXT Klucz klasy Extras: Główny tekst
powiadomienia wystawiony przez
metodę setContentText(CharSequence).
EXTRA_TEXT_LINES Klucz klasy Extras: Dodadkowe linie teskstu
wyświetlane gdy powiadomienie występuje
w rozszerzonej formie (duży widok)
wystawione przez metodę
addLine(CharSequence).
Wymienione w powyższej tabeli flagi klasy Notifiaction będą pomocne do
wyekstrahowania informacji z przechwyconej notyfikacji. Przeszukując obiekt Notification z
uwzględnieniem tych danych będzie możliwe odczytanie informacji zawartych w
powiadomieniu.
Na potrzeby wydobycia informacji z notyfikacji stworzono klasę Extractor. W jej
ciele umieszczono wszystkie niezbędne elementy służące do przetwarzania informacji
zawartych w powiadomieniu. Klasa ta składa się z trzech prywatnych metod, oraz jednej
publicznej loadTexts(Context context,StatusBarNotification sbn, NotificationDAO data), która
w wyniku zwraca obiekt NotificationDAO zawierający informacje przekazywane w
późniejszym etapie do syntezatora mowy. Należy mieć na uwadze iż informacje tekstowe
zawarte w wyświetlanej notyfikacji znajdują się w dwóch głównych obiektach: jest to
wcześniej wspomniany obiekt klasy Notification oraz obiekt klasy Bundle (Klasa Bundle
używana jest do przetrzymywania mapowania z obiektów String na różne typy Parcalable.
Najwcześniej służy do przesyłania danych między aktywnościami w systemie Android).
Należy więc rozpocząć od próby wydobycia z obiektu Notification obiekty klasy Bundle. W
przypadku najnowszej wersji Androida 4.4 Kitkat wystarczy odczytać obiekt extras. Sytuacja
komplikuje się nieco we wcześniejszych wersjach systemu. Należy więc skorzystać z
refleksji. Fragment kodu pokazujący użycie refleksji przedstawiono poniżej.
23
Listing 4. Implementacja wydobycia obiektu Bundle z obiektu Notification
W tym przypadku należy mieć na uwadze, iż sposób ten może generować niespodziewany
wyjątek, dlatego też należy się przed tym zabezpieczyć używając bloku try catch.
Podsumowując metoda getExtras() pobiera obiekt klasy Notification, zwraca obiekt typu
Bundle lub null w przypadku błędu. Dlatego też należy mieć tę własność na uwadze w
korzystaniu z tej metody.
Kolejnym krokiem jest wyekstrahowanie informacji tekstowych z obiektu extras klasy
Bundle. W tym momencie zostają użyte wymienione w tabeli 3 klucze z klasy Notification.
Na podstawie kluczy wyciągane są wartości tekstowe za pomocą metody getcharSequence()
klasy Bundle.
Listing 5. Pobieranie elementów tekstowych z klasy Bundle.
Dla usprawnienia późniejszego czytania, zdecydowano się dodatkowo na usunięcie
nadmiarowych spacji z informacji pod kluczem EXTRA_TEXT. To działanie zostało
wprowadzone z uwagi na to iż syntezator mowy może różnie interpretować spacje w tekście,
przez co wiadomość może nie być dobrze zrozumiała. W tym celu stworzono metodę
removeSpaces(), która usuwa wielokrotne spacje w tekście. Z kolei w tekście pod kluczem
EXTRA_TEXT_LINES zwykle może znajdować długa wiadomość składająca się z kilku
@SuppressLint("NewApi") private Bundle getExtras(Notification notification) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { return notification.extras; } try { Field field = Notification.class.getDeclaredField("extras"); field.setAccessible(true); return (Bundle) field.get(notification); } catch (Exception e) { Log.w(TAG, "Failed to access extras on Jelly Bean."); return null; } }
titleText = extras.getCharSequence(Notification.EXTRA_TITLE_BIG); if ( titleText == null) { titleText = extras.getCharSequence(Notification.EXTRA_TITLE); } infoText = extras.getCharSequence(Notification.EXTRA_INFO_TEXT); subText = extras.getCharSequence(Notification.EXTRA_SUB_TEXT); summaryText = extras.getCharSequence(Notification.EXTRA_SUMMARY_TEXT); messageText = Utils.removeSpaces(extras.getCharSequence(Notification.EXTRA_TEXT)); messageTextLarge = Utils.mergeLargeMessage(extras.getCharSequenceArray(Notification.EXTRA_TEXT_LINES));
24
odrębnych linii tekstu. Należy więc połączyć wszystkie linie w jeden tekst, czyli jeden obiekt
typu String. W tym celu stworzono metodę mergeLargeMessage(), która skleja pojedyncze
linie w jedną oraz usuwana z tego tekstu wielokrotne spacje. Gdyby na tym zakończyć
wydobywanie tekstu z powiadomienia w większości przypadków, szczególnie w
powiadomieniach ze stale aktualizowanych aplikacji, efektem było by otrzymanie wszystkich
informacji zawartych w notyfikacji. Niestety może się zdarzyć iż przetwarzana notyfikacja
nie zawiera obiektu typu Bundle lub metoda getExtras() zwróciła wyjątek. W takiej sytuacji
gdyby pozostać przy wyciągnięciu elementów z klasy Bundle mogłoby się okazać, iż
notyfikacja nie zostanie przetworzona i przeczytana.
Z uwagi na istniejącą możliwość utraty informacji wykorzystując element Bundle,
zdecydowano się w przypadku braku wyniku przetwarzania go wykonać jeszcze jeden krok,
który umożliwi pobranie informacji w przypadku niepowodzenia pierwszej opcji. W tym celu
wykonano analizę widoku powiadomienia, aby wyodrębnić tytuł i treść wiadomości
notyfikacji. Analizę tą przedstawia poniższy fragment kodu. Czytając go należy mieć na
uwadze, iż wprowadzona pętla while znajduję się tutaj nie z powodu wielokrotnego
przetwarzania notyfikacji, ale aby dostarczyć użyteczniej funkcji break.
25
Listing 6. Analiza widoku powiadomienia w celu wyodrębnienia tytułu i treści powiadomienia.
Wykorzystując dwie metody pobierania informacji z powiadomień osiągnięto większą
skuteczność pobierania tekstu powiadomień.
Kolejną ważna informacją, jaką można uzyskać z powiadomienia jest aplikacja, która
wystawiła powiadomienie. Informacja ta jest istotna choćby z punktu widzenia konfiguracji
aplikacji czytającej powiadomienia aby umożliwić użytkownikowi wybór powiadomień, które
mają być odczytywanie głosowo. W tym przypadku należy rozróżnić z której metody
pobierania powiadomień korzysta aplikacja, ponieważ informację o wystawiającej
while (true) { final Notification n = sbn.getNotification(); final Context contextNotify = context; final RemoteViews rvs = n.bigContentView == null ? n.contentView : n.bigContentView; if (rvs == null) { break; } LayoutInflater inflater = (LayoutInflater) contextNotify.getSystemService(Context.LAYOUT_INFLATER_SERVICE); ViewGroup view = (ViewGroup) inflater.inflate(rvs.getLayoutId(), null); if (view == null) { break; } try { rvs.reapply(contextNotify, view); } catch (Exception e) { break; } ArrayList<TextView> textViews = new RecursiveFinder<>(TextView.class).expand(view); if (textViews.size() == 0) break; TextView title = findTitleTextView(textViews); textViews.remove(title); titleText = title.getText(); if (textViews.size() == 0) break; int length = textViews.size(); CharSequence[] messages = new CharSequence[length]; for (int i = 0; i < length; i++) { messages[i] = textViews.get(i).getText(); } messageText = (String) Utils.mergeLargeMessage(messages); break; }
26
powiadomienie aplikacji będzie pobierało się w nieco inny sposób. I tak w przypadku metody
opartej na NotifiactionListenerService informacja ta znajduje się wewnątrz obiektu klasy
StatusBarNotification i pobiera się ja za pomocą metody getPackageName().
Listing 7. Pobieranie nazwy aplikacji w przypadku użycia metody opartej na NotifiactionListenerSercice.
Z kolei w przypadku korzystania z metody dostępu do powiadomień za pomocą ułatwień
dostępu (Accessibility Service) informację o aplikacji wystawiającej notyfikacje otrzymać
można za pomocą metody getPackageName() klasy AccesibilityEvent.
Listing 8. Pobieranie nazwy aplikacji wystawiającej notyfikacje w przypadku użycia metody Accessibility Service.
Informacje wyodrębnione za pomocą opisanych w powyższym rozdziale sposobów w
kolejnym kroku w łatwy sposób mogą być przekazane do komponentu aplikacji, zajmującego
się przetwarzaniem tekstu na mowę.
6. Metody i implementacje silników Text-To-Speech
6.1. Text-To-Speech
Synteza mowy (speech synthesis) jest działem przetwarzania mowy, polegającym na
mechanicznej zamianie tekstu zapisanego w postaci znakowej, na wypowiedź w postaci
dźwiękowej. Program komputerowy zamieniający tekst na mowę jest określany mianem
syntezatora mowy (speech synthesizer). Celem nowoczesnych projektów jest zapewnienie
takiej jakości syntezy mowy, aby słuchający nie był zdolny do odróżnienia dźwięku mowy
syntezowalnej od naturalnej mowy człowieka. Im bardziej synteza ta jest naturalna i płynna,
tym bardziej jest doskonała.
Moduł przetwarzania tekstu na mowę (Test-to-Speech System) odpowiada za zamianę
translacji z postaci elektronicznej do formy dźwiękowej. Zadaniem tego modułu jest
przeczytanie każdego tekstu w postaci znaków alfanumerycznych. Znacznie prostszym
systemem jest Voice Response System, czyli system, który generuje jedynie słowa, czy też
pojedyncze frazy z jakiejś dziedziny (np. informacje od odjazdach pociągów). Skala
możliwości systemów TTS jest znacznie większa, gdyż generuje pełen zakres słów.
Jak łatwo można się domyślić, nie jest możliwe stworzenie i nagranie wszystkich form
i wszystkich słów dla danego języka. Dlatego też system TTS definiuje się jako system
automatycznego generowania mowy z transkrypcja fonetyczną wraz z modułami
odpowiedzialnymi za prozodie i intonację. Może się wydawać, iż taki system nie jest trudny
do zrealizowani i wyuczenia.
Patrząc na to jednak z drugiej strony, możemy porównać taki system do czynności
czytania. Człowiek z łatwością porusza się w świecie informacji pisanych i czytanie nie
sprawia mu problemu, ale jeśli spojrzymy jak długi czas zajmuje proces zdobywania
@Override public void onNotificationPosted(StatusBarNotification sbn) { //kod został pominięty
notification.setPackageName(sbn.getPackageName()); }
notification.setPackageName((String) event.getPackageName());
27
zdolności czytelniczych i jak trudny jest na początku, dochodzimy do wniosku iż nie jest to
prosty proces.
Należy mieć na uwadze, iż system informatyczny nie nauczy się niczego, o ile nie
zostanie zaprogramowany w odpowiedni sposób. Błędnym jest stwierdzenie, że tak jak
nauczenie czytania – zaprogramowanie tego zagadnienia jest łatwe. Komputer jest tylko
mechanizmem pozbawionym inteligencji, a człowiek musi się zmierzyć z rozwiązaniem
każdego problemu w sposób algorytmiczny. Dlatego liczba dobrze działających i
wykorzystywanych systemów Text-to-Speech jest niewielka. Aby dobrze ocenić jakość i
poprawność wypowiedzi generowanych przez syntezatory mowy, należy wziąć pod uwagę
poniższe aspekty:
Zrozumiałość
Zdania generowane przez syntezator powinny być bez problemów rozumiane przez ludzi
posługujących się danym językiem.
Naturalność
Wydźwięk mowy dobrego programu czytającego powinien być jak najbardziej zbliżony
do dźwięku mowy wypowiadanej naturalnie przez człowieka.
Wymowę liczb
W zależności od programu, syntezator może wymawiać liczby literując je jako cyfry lub
składać liczby na postać mówioną.
Przykład: „1857”
Najgorszy wynik jaki można uzyskać to gdy syntezator przeczyta liczbę jako „jeden
osiem pięć siedem”, dobrym wynikiem jest „jeden tysiąc osiemset pięćdziesiąt siedem”.
Natomiast najlepszym wynikiem będzie „tysiąc osiemset pięćdziesiąt siedem”, czyli z
pominięciem zbędnego w tym przypadku słowa „jeden”.
Wymowę godzin i dat
Dobry syntezator powinien być w stanie rozpoznać w tekście format daty (z kropkami,
myślnikami lub ukośnikami jako separatory) lub godziny (z dwukropkiem jako separator) i
odczytywać go zgodnie z zasadami.
Przykład: „ Spotkanie odbędzie się 15.12.2014 o 15:20”
W najgorszym przypadku syntezator odczyta powyższe zdanie literując kolejne cyfry w
dacie i godzinie. Trochę lepszym będzie rozwiązanie, gdy w czytanym zdaniu lektor
przeczyta liczby oddzielone separatorami „Spotkanie odbędzie się piętnaście dwanaście dwa
tysiące czternaście o piętnaście dwadzieścia”. Najlepszym wynikiem będzie charakteryzował
się program, który przeczyta to zdanie uwzględniając datę i godzinę „Spotkanie odbędzie się
piętnastego grudnia dwa tysiące czternastego roku o godzinie piętnastej dwadzieścia”.
Rozpoznawanie skrótów i skrótowców
28
Kolejnym aspektem, na który należy zwrócić uwagę, jest rozpoznawanie skrótów. Dobry
syntezator mowy polskiej powinien nie mieć problemów z rozwinięciem skrótów: „inż.”,
„tel.”, „płn.”, „jw.”, „np. „, „dr”, „mgr”, „p.n.e.” do postaci „inżynier”, „telefon”, „północ”,
„jak wyżej”, „i tak dalej”, „na przykład”, „doktor”, „magister”, „przed naszą erą”.
Bardzo dobrym wynikiem było by też odczytanie przez program skrótów matematycznych
oraz podstawowych jednostek fizycznych takich jak: „sin”, „cos”, „log”, „kg”, „l”, „km” jako
: „sinus”, „kosinus”, „logarytm”, „kilogram”, „litr”, „kilometr”.
Duże znaczenie ma również sposób odczytywania skrótowców literowych i głoskowych.
Przy natrafieniu na skrótowce dobry syntezator powinien umieć rozpoznać z jakim
skrótowcem ma do czynienia i wypowiedzieć litery osobno w przypadku literowców, lub
łączenie jako suma głosek w przypadku głoskowców.
Przykład: „AGD”, „NBP”
Litery skrótowca powinny być odczytanie osobno: „a-gie-de”, „n-be-pe”
Przykład: „NATO”, „ZUS”
Litery skrótowca powinny być odczytane łącznie „nato”, „zus”
Wymowę wyjątków
W języku polskim istnieje szereg wyrazów, które odbiegają od przyjętych reguł
wymowy. Dobry syntezator mowy w przypadku napotkania takiego wyrazu powinien
odczytać go w poprawny sposób odbiegając od ogólnych zasad dla języka.
Przykład: „tarzan”, „marznąc”
Najlepszym wynikiem przy odczytaniu powyższych słów przez syntezator mowy jest nie
złożenie „r” i „z” w „rz” tylko rozdzielenie tych liter. W gorszym przypadku słowa te mogą
brzmieć bardzo nienaturalnie, lub być niezrozumiałe.
Akcentowanie
Akcent w języku polskim jest stały. Zasadniczo pada na drugą sylabę od końca. Od tej
zasady są jednak pewne wyjątki. W niektórych formach akcentowana jest sylaba trzecia od
końca (np. botanika, logika, informatyka, matematyka, komitet, ryzyko). Poprawnie
stworzony syntezator mowy powinien odpowiednio stosować się do zasad akcentowania
włączając w to wyjątki.
Reakcja na znaki interpunkcyjne
Aby czytane przez syntezatora zdania brzmiały naturalnie, powinien on reagować w
odpowiedni sposób na znaki interpunkcyjne: ‘,’’.’’?’’!’ oraz ich brak (zdania niezakończone
kropką powinno brzmieć inaczej, niż to samo zdanie zakończone kropką).
Mając na uwadze powyższe zasady oraz wiedząc, że język polski jest jednym z
najtrudniejszych języków, można stwierdzić iż dobrej klasy syntezator przetwarzający tekst
na mowę polską jest trudny do stworzenia. Szczegółowe informacje o tym jak syntezatory
mowy radzą sobie z tym językiem zostanie przedstawione w kolejnych podrozdziałach
dotykających zagadnienia Text-to-Speech.
29
6.2. Budowa systemu Text-to-Speech
System Text-to-Speech składa się zasadniczo z dwóch podstawowych elementów:
modułu NLP (Natural Language Processing) – odpowiedzialny za przetwarzanie
języka naturalnego,
modułu DSP (Digital Signal Processing) – element, który przetwarza sygnał cyfrowy.
Schemat funkcjonalny systemu przetwarzania tekstu na mowę przedstawiony jest poniżej. Na
schemacie można wyróżnić dwa odrębne moduły wchodzące z skład systemu Text-to-Speech.
Rys. 10. Schemat budowy moduły NLP.
Celem modułu NLP jest przekształcenie tekstu na zapis fonetyczny, czyli zapis słów,
wypowiedzi, przy użyciu podziału fonetycznego głosek. NLP jest odpowiedzialny również za
wygenerowanie odpowiedniej intonacji i prozodii (Brzmieniowe właściwości mowy
nakładające się na głoskowy, sylabiczny i wyrazowy ciąg wypowiedzi. Należą do nich akcent,
intonacja i iloczas) tekstu. Moduł Natural Language Processing składa się z następujących
elementów:
Pre-pocessor (normalizator tekstu) – dzieli on zdania na wyrazy. Proces podziału
dla języka polskiego jest skomplikowany, z powodu iż występuje w nim duża
30
liczba skrótów. Moduł ten wydziela z tekstu skróty, liczby, idiomy, akronimy i
rozwija je do pełnego tekstu. Po przetworzeniu takie dane są przechowywane w
wewnętrznym module struktur danych.
Analizator morfologiczny – wyznacza części mowy dla każdego ze słów
(rzeczownik, przymiotnik, czasownik). Słowa te są rozbijane na morfemy
(najmniejsza grupa fonemów, która niesie ze sobą określone znaczenie i której nie
można podzielić na mniejsze jednostki znaczeniowe) poprzez zastosowanie
gramatyk regularnych, wykorzystanie słownika, tematu wyrazów, przedrostków i
przyrostków. Zadaniem analizatora morfologicznego jest ustalanie części mowy
połączone z zorganizowaniem znormalizowanych danych z preprocesora.
Analizator kontekstowy – ogranicza znaczenia poszczególnych słów. Ograniczenie
to odbywa się na podstawie zbadania kontekstu słów znajdujących się obok siebie.
Stasuje się tutaj metodę n-gramów, która opisuje syntaktyczne zależności
pomiędzy słowami, na zasadzie badania prawdopodobieństw w skończonych
przejściach automatu. Służą to tego modele Markova lub wielowarstwowe sieci
perceptronowe, jak również metody lokalnych niestochastycznych gramatyk.
Praser syntaktyczno-prozodyczny – jego zadaniem jest utworzenie prozodii i
intonacji dla poszczególnych sekwencji fonemów. Bada on jednocześnie pozostałe
wyrażania, które nie zostały skwalifikowane. Następnie stara się znaleźć podobne
do nich struktury tekstowe, których elementy prozodyczne będą najbardziej
podobne.
Moduł konwersji liter na dźwięk – jest odpowiedzialny za konwersję głosek na
mowę oraz za utworzenie transkrypcji fonetycznej dla istniejących słów.
Generator prozodii – ma za zadanie nadanie wypowiedzi właściwości sygnału
mowy. Można je usłyszeć w postaci zmiany głośności, długości sylab, czy
sposobie intonacji. Cechy te odgrywają bardzo ważną rolę w komunikacji
językowej. Odpowiednie zaakcentowanie sylaby zmienia bowiem znaczenie całej
wypowiedzi. Odpowiedzialny jest za precyzyjne określenie czasu trwania
poszczególnych fenomów oraz intonacji w postaci wygenerowanego sygnału.
Innym słowem można powiedzieć, iż moduł ten zapewnia naturalność głosu
syntezatora mowy.
Moduł NLP realizuje szereg procesów przekształcających tekst oraz kształtujących
wypowiedź wraz z intonacją. Kolejnym etapem jest przekształcenie tych danych na sygnał w
module DSP.
Z procesem artykulacji ludzkiej związana jest praca mięśni twarzy oraz wytwarzanie sygnału
o odpowiedniej częstotliwości. W świecie komputerów za sztuczne wygenerowanie sygnału
na kształt procesu artykulacji ludzkiej odpowiada moduł Digital Signal Processing.
Jego zadaniem jest synteza mowy z danych dostarczonych przez moduł NLP. Można
wyróżnić syntezy mowy oparte na modelach:
Formantowa – model tego syntezatora sprowadza się do zaprojektowania
odpowiednich filtrów cyfrowych generujących dźwięk o charakterystycznych dla
głosek częstotliwościach. Formantowa synteza mowy generuje najgorszą jakość
dźwięku, ponieważ ograniczają go możliwości modelu, który składa się tylko z
filtrów.
Artykulacyjna – oparta jest na generowaniu sygnału mowy za pomocą reguł. Do
modelowania głoski służy około 60 parametrów. Schemat modelu artykulacyjnego
przypomina budowę ludzkiego toru głosowego, przy czym jego odpowiednikiem nie
jest aplikacja a analog elektromagnetyczny. Z tego też powodu synteza ta ma
znaczenie symboliczne i nie jest rozpowszechniana.
31
Konkatenacyjna – jest najbardziej rozpowszechnianą obecnie metoda syntezy mowy, z
uwagi na możliwość generowania bardzo naturalnej i zrozumiałej mowy w prosty
sposób. Generuje ona mowę poprzez sklejanie ze sobą elementów akustycznych
powstałych z naturalnej mowy (fony, sylaby).
Korpusowa – jest to zmodyfikowana postać konkatenacyjnej syntezy mowy.
7. Synteza mowy w środowisku Android
7.1. Dragon Mobile SDK
Dragon Mobile Software Development Kit dostarcza usługi głosowe, dzięki którym
aplikacje mogą korzystać z rozpoznawania mowy i przetwarzania tekstu na mowę. W pracy
tej uwaga zostanie skupiona tylko na funkcjach Text-To-Speech pakietu Dragon Mobile.
Pakiet ten dostarcza obsługę TTS dla wielu języków w co najważniejsze, w tym przypadku
również dla języka Polskiego. Co więcej dla języka polskiego dostępne są dwa damskie głosy
oznaczone jako „Ewa” i „Zosia”. Dragon Mobile działa w oparciu o architekturę klient-
serwer. Pakiet ten można dołączyć do tworzonej aplikacji, i jedyne czego potrzebuje do
poprawnego działania to dostęp do Internetu, który umożliwi klientowi (API) zapytanie
serwera o przetwarzanie tekstu na mowę. Biblioteka dostarcza dostęp do komponentów
przetwarzania mowy dostępnych na serwerach firmy Nounce poprzez asynchroniczną
komunikację.
Biblioteka Speech Kit jest wysoko poziomowym API, które automatycznie zarządza
niskopoziomowym dostępem do usług głosowych.
Rys. 11. Architektura biblioteki Speech Kit.
Na poziomie aplikacyjnym są dwa główne komponenty dostępne dla dewelopera:
Recognizer – służący do przetwarzania mowy na tekst
Vocalizer – służacy do przetwarzania tekstu na mowę. Wewnątrz biblioteki znajdują się
elementy odpowiedzialne za poszczególne procesy takie jak:
Zarządzanie systemem audio, aby umożliwić odtwarzanie mowy.
Komponenty sieciowe, które zarządzają połączeniem z serwerem, zestawiają
połączenie w przypadku nowego żądania czy automatycznie wznawiają połącznie
podczas wystąpienia problemów czasu oczekiwana na odpowiedź lub zerwania
połączenia.
Komponent kodowania, kompresujący i dekompresujący zawartość strumienia audio
aby zredukować ograniczania łącza oraz zmniejszyć opóźnienia.
System po stronie serwera jest odpowiedzialny za najważniejsze funkcje w cyklu
przetwarzania tekstu. Kompletna synteza tekstu wykonywana jest właśnie na serwerze, a
32
wynikiem jej jest strumień audio pobierany przez bibliotekę. Ponadto serwer zarządza
również autentykacją aplikacji wysyłającej żądanie przetwarzania tekstu [9].
Warto zaznaczyć, iż biblioteka, którą dostarcza Nuance składa się z dwóch części,
wysokopoziomowego interfejsu deweloperskiego w formie pakietu klas Java oraz natywne
elementy w postaci bibliotek języka C, z której korzysta interfejs przeznaczony dla twórców
oprogramowania.
Klasa Vocalizer dostarcza interfejs obsługujący proces przetwarzania tekstu na mowę.
Pierwszym krokiem, jaki należy wykonać przed użyciem Text-To-Speech oferowanego przez
Nuance, jest zestawienie połącznie i autentykacja z serwerem producenta. Wykonuje się to za
pomocą metody initilize() klasy SpeechKit. Kolejnym krokiem jest zainicjowanie obiekty
klasy Vovalizer oraz ustawienie języka, z jakim będzie pracować aplikacja. Ostatnim krokiem
jest wywołanie metody speakString(), która zajmie się wysłaniem potrzebnych informacji do
serwera oraz odebraniem sygnału audio, a następnie odtworzy odebrany sygnał.
Rys. 12. Schemat działania Text-to-Speech Dragon Mobile API
Jak łatwo można zauważyć na rysunku przedstawiającym schemat działania silnika Dragon
Mobile, została w nim zaimplementowana obsługa przerwania syntezy dźwięku. W
przypadku użycia metody cancel() klasy SpeechKit działanie po stronie serwera zostanie
zakończone a rezultat zwrócony w formie kodu błędu.
Usługa Text-To-Speech Dragon Mobile, jak wspominano wcześniej, działa na zasadzie
klient-serwer. Wiąże się to z możliwością długiego oczekiwania na odpowiedź zawierającą
sygnał audio w przypadku wolnego połączenia sieciowego w szczególności w przypadku
korzystania z aplikacji w miejscu o słabym zasięgu sieci komórkowej. Jest to jednym z
minusów tego rozwiązania. Kolejnym problemem może być również sytuacja, gdy serwer
realizujący zapytania syntezy mowy jest niedostępny. Dlatego też należy mieć te informacje
na uwadze implementując rozwiązanie oparte o ten syntezator mowy, i odpowiednio
zaprojektować obsługę błędów komunikacyjnych.
33
Rys. 13. Struktura pakietu dragon mobile API.
Aby użyć przetwarzania Text-To-Speech w aplikacji na Androida, należy posłużyć się
wcześniej wspomnianymi klasami SpeechKit ora Vacalizer. Prostą implementacje
wykorzystania biblioteki przedstawia poniższy fragment kodu. Należy zacząć od metody
prepereTTS(), w której ciele znajduje się inicjalizacja usług przetwarzania tekstu. Niezbędne
jest tu wywołanie metody initialize() klasy SpeechKit oraz podanie jej argumentów
połączeniowych, takich jak adres serwera realizującego przetwarzanie danych (
SpeechKitServer), port przez który ma być realizowane połączenie (SpeechKitPort) do
serwera, identyfikator aplikacji (SpeechKitAppId) oraz klucz aplikacji
(SpeechKitApplicationKey), służące do autoryzacji aplikacji korzystającej z serwera TTS.
34
Listing 9. Realizacja usługi TTS korzystającej z Dragon Mobile API
Następnie należy wywołać funkcję connect(), aby połączyć się z serwerem TTS. Kolejnym
etapem jest stworzenie i zainicjowanie obiektu klasy Vocalizer. Na tym etapie również
wybierany jest język w jakim ma odbyć się przetwarzanie tekstu. Ustawiony zostaje przez
wpisanie odpowiedniego kodu danego języka w metodzie createVocalizerWithLanguage().W
przypadku korzystania z języka polskiego jest to kod: pl_PL. Tak przygotowany silnik
przetwarzania gotowy jest do czytania tekstu. Realizuje się to poprzez wykonanie metody
spreakString() klasy Vocalizer z argumentem w postaci tekstu który ma być przetworzony na
mowę. W wyniku wykonania tej metody odtworzony zostanie tekst podany jako argument
metody.
public class DragonMobileTTS{ private Activity activity; private Vocalizer vocalizer; private static SpeechKit speechKit; public DragonMobileTTS(Activity activity){ this.activity=activity; } public void speak(String message){ vocalizer.speakString(message, new Object()); } Vocalizer.Listener vocalizerListener = new Vocalizer.Listener() { @Override public void onSpeakingBegin(Vocalizer vocalizer, String text, Object context) { } @Override public void onSpeakingDone(Vocalizer vocalizer, String text, SpeechError error, Object context) { } }; public void prepereTTS(){ activity.setVolumeControlStream(AudioManager.STREAM_MUSIC); speechKit = SpeechKit.initialize(activity, DragonMobileApiInfo.SpeechKitAppId, DragonMobileApiInfo.SpeechKitServer, DragonMobileApiInfo.SpeechKitPort, DragonMobileApiInfo.SpeechKitSsl, DragonMobileApiInfo.SpeechKitApplicationKey); speechKit.connect(); vocalizer = speechKit.createVocalizerWithLanguage("pl_PL", vocalizerListener, new Handler()); }
35
7.2. iSpeech API
iSpeech jest usługą przetwarzania tekstu na mowę w postaci Software as a Service (w
skrócie SaaS. Jest to jeden z modeli chmury obliczeniowej, polegający na dystrybucji
oprogramowania, w którym aplikacja jest przechowywana i udostępniana przez producenta
użytkownikom przez Internet). Dostęp do niego dla systemu Android dostarcza API
udostępniane przez iSpeech. Komunikacja pomiędzy urządzeniem a platformą iSpeech
odbywa się za pomocą protokołu http, przy użyciu standardowych mechanizmów GET i
POST. W standardowej wersji iSpeech Software Developer Kit pozwala na czytanie tekstu w
27 językach w tym w języku polskim.
Dla systemu Android API tego syntezatora dostarczone jest w formie zewnętrznej
biblioteki, którą programista musi dołączyć do swoje aplikacji. Posiada ono ubogą
dokumentację opisującą bardzo pobieżnie metody znajdujące się w pakiecie. Podobnie jak w
przypadku Dragon Mobile, cała synteza tekstu odbywa się na serwerach Ispeech. W kwestii
aplikacji należy tylko wysłanie odpowiednich instrukcji do serwera wraz z tekstem do syntezy
oraz odebranie informacji w postaci pliku dźwiękowego z wynikiem syntezy, który następnie
może być odtworzony użytkownikowi [11].
Rys. 14. Struktura pakietu iSpeech API
Najważniejsza klasą w pakiecie iSpeech jest SpeechSynthesis,która posiada metody
inicjujące i ustawiające parametry syntezy mowy. Aby uruchomić przetwarzanie tekstu na
mowę za pomocą iSpeech, należy zacząć od stworzenia obiektu klasy SpeechSyntesis.
Następnie należy posłużyć się statyczną metodą getInstance(Context context) zwracającą
instancję klasy SpeechSynthesis. Metoda ta sprawdza poprawność klucza licencyjnego
zapisanego w pliku manifestu aplikacji. W przypadku braku klucza lub jego wygaśnięcia
wynikiem jej jest wyjątek InvalidApiKeyException, który powinien być obsłużony przez
programistę. Wybór języka, w jakim ma odbywać się synteza, należy dokonać za pomocą
wywołania metody setVoiceType(String string), której argumentem jest łańcuch znaków
oznaczający kod danego języka. W przypadku języka polskiego kodem tym jest
36
eurpolishfemale. Kolejnym etapem konfiguracyjnym iSpeech jest wywołanie metody
setSpeechSynthesisEventLisener(SpeechSyntesisEvent event), przyjmującej jako argument
interfejs klasy SpeechSyntesisEvent, którego implementacja zależy od twórcy aplikacji.
Ostatnim krokiem jest wybór wyjścia strumienia audio, na jaki ma zostać skierowana
odpowiedź syntezatora mowy w postaci dźwiękowej. Dokonuje się tego za pomocą metody
setStreamType(int streamType), której parametrem jest jeden z strumieni audio dostępnych w
systemowej klasie AudioManager. Tak zaprogramowany silnik iSpeech gotowy jest do
przetwarzania tekstu. Należy tylko wywołać metodę speak(String text), podając jako
argument tekst, który ma zostać przetworzony. Metoda ta rozpocznie konwersję (otworzy
połączenie z serwerem iSpeech, wyślę zapytanie do serwera, przetworzy odpowiedź) a jej
wynik zostanie odtworzony poprzez wybrany wcześniej strumień wyjściowy. Na poniższym
listingu przedstawiony został opisany sposób korzystania z iSpeech API.
Listing 10. Przykład implementacji syntezatora mowy opartego na API iSpeech.
public class IspeechTTS { private SpeechSynthesis synthesis; private Context context;
public void prepareTTSEngine() { try { synthesis= SpeechSynthesis.getInstance(context); synthesis.setVoiceType("eurpolishfemale"); synthesis.setSpeechSynthesisEvent(new SpeechSynthesisEvent() { public void onPlaySuccessful() { Log.i(TAG, "onPlaySuccessful"); } public void onPlayStopped() { Log.i(TAG, "onPlayStopped"); } public void onPlayFailed(Exception e) { Log.e(TAG, "onPlayFailed"); } public void onPlayStart() { Log.i(TAG, "onPlayStart"); } @Override public void onPlayCanceled() { Log.i(TAG, "onPlayCanceled"); } }); } catch (InvalidApiKeyException e) { Log.e(TAG, "Invalid API key\n" + e.getStackTrace()); Toast.makeText(activity, "ERROR: Invalid API key", Toast.LENGTH_LONG).show(); } synthesis.setStreamType(AudioManager.STREAM_MUSIC); } }
37
7.3. Text To Speech API Google
Począwszy od wersji 1.6 środowiska Android, dostępny stał się silnik odpowiedzialny
za syntezę mowy oraz jego implementacja o nazwie Pico TTS. Dzięki niemu w aplikacjach
możliwe jest przetwarzanie ciągu znaków tekstowych na dźwięk – mowę z akcentem
typowym dla wybranego języka. Technologia przetwarzania tekstu na mowę umożliwia
użytkownikowi korzystanie z urządzenia, bez konieczności spoglądania na ekran. Syntezator
ten przeczyta za użytkownika sms, email ,wiadomości, bądź przypomni o wydarzeniu. Jest to
również niezastąpiona funkcja dla ludzi niedowidzących lub starszych, mających problem z
odczytaniem informacji z ekranu telefonu. Niestety poważnym minusem silnika Pico jest to,
iż nie obsługuje on języka Polskiego. Istnieje możliwość wyboru pomiędzy językami:
angielskim (Wielka Brytania), angielskim(Stany Zjednoczone), niemieckim, hiszpańskim
oraz włoskim. Od wersji 2.2 Androida uzyskaliśmy możliwość korzystania z mechanizmów
innych niż Pico. Uzyskujemy w ten sposób większe możliwości, ponieważ silnik Pico nie
nadaje się do wszystkich zastosowań. Nawet w przypadku posiadania kilku mechanizmów
TTS w urządzeniu znajduje się tylko jedna usługa przetwarzania mowy.
Wśród klas Test-To-Speech API znajdujących się w pakiecie android.speech.tts część
klas odpowiedzialna jest za funkcjonalność systemów syntezy mowy. Istnieje również kilka
klas programistycznych, które zajmują się dostarczaniem informacji o mechanizmach
przetwarzania mowy (Engine, EngineInfo), reakcjach na działanie TTS
(OnUtteranceCopletedListener, UtternaceProgressListener) oraz zarządzaniem obiektami
Text-To-Speech (OnInitListener).
Rys. 15. Struktura pakietu Android TTS .
W przypadku korzystania z dostarczonego przez Google pakietu android.speech.tts
cały mechanizm przetwarzania tekstu na mowę zarządzany jest przez system operacyjny.
Dostarcza również wszystkich metod i implementacji (wraz z plikami głosów) służących do
korzystania z możliwości dostarczanych przez system Android. Każda aplikacja korzystająca
z systemowego TTS musi się do niego podłączyć właśnie poprzez to API. Jednak, aby
wszystko funkcjonowało poprawie w systemie, musi być zainstalowany i ustawiony jak
główny silnik Google Text-To-Speech [12].
Inicjalizacja systemu syntezy mowy polega na utworzeniu instancji klasy
TestToSpeech. Należy przy tym wykorzystać domyślny konstruktor klasy
TextToSpeech(Context context, TextToSpeech.OnInitListener listener), który jak atrybuty
38
przyjmuje tzw. kontekst aplikacji oraz implementację interfejsu OnInitListener. Kontekst,
jest to abstrakcyjna klasa przechowywująca informacje dotyczące środowiska aplikacji. Jest
dostarczana jako natywny element systemu. Służy temu, aby programista w prosty sposób
mógł przechowywać i przekazywać informacje o aplikacji, takie jak zasoby, teksty, grafiki,
uprawnienia itd. Instancją takiego kontekstu w aplikacji jest aktywność. Aby przekazać
informacje o aktywności do innej klasy, należy posłużyć się przekazaniem właśnie kontekstu
a nie całej aktywności. Dlatego w tym przypadku zachodzi konieczność inicjalizacji klasy
TextToSpeech dla każdej aktywności osobno. Tylko w ten sposób zapewnia się przekazanie
odpowiedniego kontekstu dla instancji klasy TextToSpeech.
Listing 11. Przykładowy kod inicjalizujący Text-To-Speech Google API.
OnInitListener jest drugim elementem przekazywanym do konstruktora, specyficznym dla
API TTS. Klasa OnInitListener to interfejs, dlatego też jego implementacja zależy od
programisty. Istnieje tu dowolność w implementacji, jednak należy przestrzegać schematu
inicjalizacji systemu TextToSpeech zaprojektowanego przez twórców. Interfejs OnIniListener
zawiera tylko jedną metodę: onInit(int status), która zawsze musi być zaimplementowana.
Argument jaki przyjmuje to status inicjalizacji systemu TextToSpeech w postaci liczy
całkowitej odpowiadającej konkretnej fladze API. Wyróżnia się dwie flagi:
TextToSpeech.SUCCESS – wartość ta oznacza iż TTS został poprawnie zainicjowany.
TextToSpeech.ERROR – wartość ta oznacza iż wystąpił błąd podczas inicjalizacji.
W przypadku, gdy TTS zostanie poprawnie uruchomiony, wywoływane są dodatkowe
metody, konfigurujące instancje syntezatora mowy. Metoda setLanguage(Locale locale)
ustawia język dla syntezatora mowy, pośrednio określa które pliki głosowe zostaną użyte
podczas syntezy mowy. Efektem jej działania jest zwrócenie wartości w postaci liczby
całkowitej odpowiadającej flagom:
TextToSpeech.LANG_MISSING_DATA – oznacza, że system TTS nie posiada danych
do obsługi ustwionego języka.
TextToSpeech.LANG_NOT_SUPPORTED – oznacza, że system TTS nie obsługuje
ustawionego języka.
TextToSpeech.LANG_AVAILABLE – oznacza, że system TTS obsługuje język danego
kraju określony przez lokalizacje, ale nie dla kraju ani w określonym wariancie.
TextToSpeech.LANG_COUNTRY_AVAILABLE – oznacza, że system TTS obsługuje
język danego kraju określony przez lokalizacje.
TextToSpeech.LANG_COUNTRY_VAR_AVAILABLE,- oznacza, że język określony
jest dokładnie przez lokalizację i wariant.
public void googleTTSInit() { mTts=new TextToSpeech(activity, new TextToSpeech.OnInitListener() { @Override public void onInit(int status) { if(status != TextToSpeech.ERROR){ Locale locale = new Locale("pl"); mTts.setLanguage(locale); } } }); mTts.speak(message, TextToSpeech.QUEUE_FLUSH, null); }
39
W przypadku otrzymania flag innych niż LANG_MIISING_DATA i
LANG_NOT_SUPPORTED, język zostaje ustawiony i tym samym syntezator jest gotowy do
pracy, czyli przetwarzania otrzymanego tekstu na dźwięk.
Po inicjalizacji, gdy klasa TextToSpeech jest gotowa, korzystanie z systemu syntezy
mowy jest stosunkowo łatwe. Wszystkie metody syntezatora należą do klasy TextToSpeech i
na jej instancji trzeba je wywoływać. Najważniejszą metodą, a zarazem najpopularniejszą jest
metoda speak(String text,int queueMode, HashMap<String, String> params). Wywoływana
jest przez nią synteza mowy. Jako pierwszy argument metoda ta przyjmuje tekst, który będzie
zamieniony na mowę. Drugim parametrem jest liczba całkowita określająca sposób
kolejkowania wypowiedzi przez syntezator. Wartość ta przyjmuje jedną z dwóch flag
określonych w klasie TextToSpeech:
TextToSpeech.QUEUE_ADD – wartość ta spowoduje, iż tekst podany jako pierwszy
argument zostanie dodany do kolejki wypowiedzi syntezatora i zostanie przetworzony
dopiero, gdy zakończona zostanie synteza wszystkich tekstów znajdujących się w
kolejce syntezy przed dodawanym tekstem.
TextToSpeech.QUEUE_FLUSH - wartość ta ustawiona jako argument metody
spowoduje, że kolejka wypowiedzi zostanie opróżniona i tekst zadany jako pierwszy
argument metody zostanie zsyntezowany.
Ostatnim argumentem jest HashMap parametrów syntezatora. HashMap klucz wartość
pozwala na ustawienie zaawansowanych parametrów strumieni dźwięku w klasie
AudioManager.
Do kontroli wypowiedzi klasa TextToSpeech posiada oprócz wspomnianych powyżej
metod kolejkowania metody isSpeaking() i stop(). Pierwsza z nich zwraca wartość prawdę lub
fałsz w zależności czy tekst jest odtwarzany, czy nie. Natomiast metodą stop() można
zatrzymać aktualną syntezę mowy.
API TextToSpeech posiada również metody związane bezpośrednio z procesami
generowania wypowiedzi, służące do modyfikowania ustawień mechanizmu TTS oraz
pobierania informacji na temat tych mechanizmów, znajdujących się aktualnie w systemie
Android. Przykładem takich metod są metody:
setSpeechRate(float SpeechRate) – służy do określania szybkości wypowiedzi. Jako
argument przyjmuje liczbę typu float, im jest ona wyższa tym szybkość wypowiedzi
jest większa.
setPitch(float pitch) – określa wysokość tonu syntezatora. Jako parametr również
przyjmuje liczbę float, im większa jest ta liczba tym ton wypowiedzi jest wyższy.
Istotnym elementem API jest możliwość wybrania innego niż Google syntezatora mowy
zainstalowanego w systemie jako silnika mówiącego wprost z API. Należy jednak przed
wybraniem pakietu upewnić się, że jest on zainstalowany w systemie i obsługuje wybrany
przez programistę język. W tym celu przydatne są metody pobierające informacje o
dostępnych języka i sprawdzające ich dostępność:
getDefaultEngine() – zwraca informacje o domyślnym silniku TTS ustawionym w
systemie Android.
getLanguage() – zwraca informacje na temat domyślnego języka używanego przez
system syntezy mowy.
isLanguageAvailable(Locale loc) – sprawdza, czy podany jako argument język jest
dostępny na urządzaniu.
getEngines() – zwraca, w formie listy, informację o wszystkich mechanizmach TTS
zainstalowanych w systemie.
Podsumowując, systemowe API TextToSpeech charakteryzuje się największymi
możliwościami z pośród przedstawionych w tym rozdziale. Jedynym minusem jaki napotkano
40
był brak obsługi języka polskiego przez domyślny silnik. Można jednak zaniedbać ten
mankament, poprzez doinstalowanie jednego z dostępnych silników języka polskiego
współpracującego z tymże API. Choćby bardzo popularny silnik IVONA. Jednak w trakcie
tworzenia pracy Google wydało implementację silnika przetwarzania tekstu na mowę dla
języka polskiego, tym samym jedyny minus zniknął. Natomiast implementacja Google
przyniosła z sobą nową jakość przetwarzania tekstu na mowę, co zostanie przedstawione przy
okazji porównania syntezatorów mowy.
7.4 Porównanie syntezatorów mowy
Każdy z opisanych we wcześniejszych rozdziałach syntezator mowy posiada zalety i
wady z punktu widzenia implementacyjnego. Opisane zostały one przy charakterystyce
każdego z nich. Należy jednak spojrzeć również na syntezatory mowy z punktu widzenia
użytkownika końcowego, ponieważ to dla jego wygody tworzona jest aplikacja korzystająca z
tychże silników przetwarzania tekstu. Dla użytkownika najważniejsze jest zrozumienie tekstu
generowanego przez taki syntezator. Ważnym aspektem jest również forma, w jakiej
specjalne informacje są przekazywane.
Cechy, jakimi powinien charakteryzować się dobry syntezator tekstu zostały
szczegółowo omówione w rozdziale ‘Text-to-Speech’. Na podstawie tych informacji
przeprowadzono porównanie trzech syntezatorów mowy, opisywanych w tej pracy
dyplomowej. Porównanie zostało dokonane dla sześciu rodzajów grup znaków, jakie mogą
znaleźć się w tekście przetwarzanym przez silnik Text-To-Speech. A mianowicie stworzono
testy na podstawie poniższych kryteriów :
wymowa liczb,
wymowa godzin i dat,
wymowa skrótów i skrótowców,
wymowa wyjątków,
reagowanie na znaki interpunkcyjne,
wymowa znaków specjalnych.
Dla każdego z kryteriów stworzono po kilka testów, mających na celu sprawdzenie jak dany
syntezator mowy poradzi sobie z syntezą tekstu specjalnego. Wyniki testów zostały
przedstawione w formie tabel z rezultatami każdego testu dla poszczególnych syntezatorów
mowy. Następnie wyniki z poszczególnych syntezatorów porównano ze sobą w tabeli, aby
wyłonić najlepszy z syntezatorów które zostały przetestowane.
41
Tabela 4. Wyniki testu na syntezatora Dragon Mobile
Test Wynik testu Pkt. Suma Wynik
Wymowa Liczb 1857
„tysiąc osiemset pięćdziesiąt siedem”
1
4 0,6 123 „sto dwadzieścia trzy” 1
2,82 „dwa i osiemdziesiąt dwie setne”
1
2.8 „dwa i osiem dziesiątych” 1
Wymowa godzin i dat Spotkanie
odbędzie się 15.12.2014 o
15:20.
„Spotkanie odbędzie się piętnasty dwunasty dwa tysiące czternaście o godzinie piętnastej dwadzieścia”
3
6 1,2
Dnia 15-12-2014 o 15:30.
„Dnia piętnaście do dwanaście minus dwa tysiące czternaście o godzinie piętnastej trzydzieści”
3
Rozpoznawanie skrótów i skrótowców
tel. „telefon” 1
8,5 1,7
płn. 0
np. „en-pe” 0
dr „de-er” 0
mgr „em-gie-er” 0
AGD „a-gie-de” 1
NBP „en-be-pe” 1
NATO „nato” 1
ZUS „zus” 1
cos [cos 20®] „cos dwadzieścia stopni” 0,5
log 5 „log pięć” 0
km [5 km do centrum]
„pięć kilometrów do centrum” 1
kg [3 kg sera] „trzy kilogramy sera” 1
l [2l mleka] „dwa litry mleka” 1
wymowa wyjątków tarzan „tarzan” 1 2 0,6
marznąć „marznąć” 1
znaki interpunkcyjne Idź do domu „Idź do domu” 0 0 0
Idź do domu! „Idź do domu” 0
Idziesz do domu? „idziesz do domu” 0
Idziesz do domu? „idziesz do domu” 0
znaki specjalne @ „małpa” 1 2 0,1
$ „dolar” 1
%[25%] „25 procent” 1
Suma: 4,2
42
Tabela 5. Wyniki testu dla syntezatora iSpeech.
Test Wynik testu Pkt. Suma Wynik
Wymowa Liczb 1857
„tysiąc osiemset pięćdziesiąt siedem”
1
4 0,6 123 „sto dwadzieścia trzy” 1
2,82 „dwa i osiemdziesiąt dwie setne”
1
2.8 „dwa i osiem dziesiątych” 1
Wymowa godzin i dat Spotkanie odbędzie się 15.12.2014 o
15:20.
„Spotkanie odbędzie się piętnasty grudnia dwa tysiące czternastego roku o piętnastej dwadzieścia”
5
10 2
Dnia 15-12-2014 o 15:30.
„Dnia piętnasty grudnia dwa tysiące czternastego roku o piętnastej trzydzieści”
5
Rozpoznawanie skrótów i skrótowców
tel. „tel” 0
7 1,4
płn. „pe-eł-en” 0
np. „en-pe” 0
dr „de-er” 0
mgr „em-gie-er” 0
AGD „a-gie-de” 1
NBP „en-be-pe” 1
NATO „nato” 1
ZUS „zus” 1
cos [cos 20®] „cos dwadzieścia” 0
log 5 „Log pięć” 0
km [5 km do centrum]
„pięć kilometrów od „centrum
1
kg [3 kg sera] „trzy kilogramy sera” 1
l [2l mleka] „dwa litry mleka” 1
wymowa wyjątków tarzan „tażan” 0 0 0
marznąć „mażnąć” 0
znaki interpunkcyjne Idź do domu „Idź do domu” 0
0 0 Idź do domu! „Idź do domu” 0
Idziesz do domu? „idziesz do domu” 0
Idziesz do domu? „idziesz do domu” 0
znaki specjalne @
„małpa” [tylko w adresie email]
0,5
0 0 $ „dollar” 0
%[25%] „dwadzieścia pięć” 0
Suma: 4
43
Tabela 6. Wynik testu dla syntezatora Google.
Test Wynik testu Pkt. Suma Wynik
Wymowa Liczb 1857
„tysiąc osiemset pięćdziesiąt siedem”
1
4 0,6 123 „sto dwadzieścia trzy” 1
2,82 „dwa i osiemdziesiąt dwie setne”
1
2.8 „dwa i osiem dziesiątych” 1
Wymowa godzin i dat Spotkanie odbędzie się 15.12.2014 o
15:20.
„Spotkanie odbędzie się „piętnasty grudnia dwa tysiące czternastego roku o piętnastej dwadzieścia
5
10 2
Dnia 15-12-2014 o 15:30.
„Dnia piętnasty grudnia dwa tysiące czternastego roku o piętnastej trzydzieści”
5
Rozpoznawanie skrótów i skrótowców
tel. „telefon” 1
8,5 1,7
płn. „pe-eł-en” 0
np. „en-pe” 0
dr „de-er” 0
mgr „em-gie-er” 0
AGD „a-gie-de” 1
NBP „en-be-pe” 1
NATO „nato” 1
ZUS „zus” 1
cos [cos 20®] „cos dwadzieścia stopni” 0,5
log 5 „log pięć” 0
km [5 km do centrum]
„pięć kilometrów od „centrum
1
kg [3 kg sera] „trzy kilogramy sera” 1
l [2l mleka] ”dwa litry mleka” 1
wymowa wyjątków tarzan „tarzan” 1 2 0,6
marznąć „marznąć” 1
znaki interpunkcyjne Idź do domu „Idź do domu” 0
0 0 Idź do domu! „Idź do domu” 0
Idziesz do domu? „idziesz do domu” 0
Idziesz do domu? „idziesz do domu” 0
znaki specjalne @ „małpa” 1
2 0,1 $ „dolar” 1
%[25%] „25 procent” 1
Suma: 5
Tabela 7. Zestawieni wyników testu syntezatorów mowy
Dragon Mobile iSpeech Google
Test Pkt. Suma Suma*Waga Pkt. Suma Suma*Waga Pkt. Suma Suma*Waga Waga
Wymowa Liczb
1857 1
4 0,6
1
4 0,6
1
4 0,6 0,15 123 1 1 1
2,82 1 1 1
2.8 1 1 1
Wymowa godzin i dat Spotkanie odbędzie się 15.12.2014 o 15:20 3
6 1,2 5
10 2 5
10 2 0,2 Dnia 15-12-2014 o 15:30 3 5 5
Rozpoznawanie skrótów i skrótowców
tel. 1
8,5 1,7
0
7 1,4
1
8,5 1,7 0,2
płn. 0 0 0
np. 0 0 0
dr 0 0 0
mgr 0 0 0
AGD 1 1 1
NBP 1 1 1
NATO 1 1 1
ZUS 1 1 1
cos [cos 20*] 0,5 0 0,5
log 5 0 0 0
km [5 km do centrum] 1 1 1
kg [3 kg sera] 1 1 1
l [2l mleka] 1 1 1
wymowa wyjątków tarzan 1
2 0,6 0
0 0 1
2 0,6 0,3 marznąć 1 0 1
znaki specjalne
@ 1
2 0,1
0,5
0 0
1
2 0,1 0,05 $ 1 0 1
%[25%] 1 0 1
SUMA 23,5
4,2
21 4
26,5 5 1
Podsumowując przeprowadzone testy, wszystkie syntezatory najlepiej poradziły sobie z
wymową liczb a najgorzej w rozpoznawaniu znaków interpunkcyjnych. Wszystkie
syntezatory prawidłowo wymówiły cztery liczby testowe, uwzględniając pominięcie słowa
„jeden” w przypadku liczb zaczynających się o cyfry „1”. W przypadku wymowy godzin i dat
najlepsze rezultaty osiągnęły syntezatory iSpeech i Google. Oba silniki poprawnie przeczytały
datę i godzinę, do osiągnięcia maksymalnego wyniku zabrakło jednak użycia wyrażenia „o
godzinie” przed wymówieniem czasu. Gorzej poradził sobie Dragon Mobile, czytane przez
niego daty nie było zrozumiałe, a nawet pomylone z wyrażeniami matematycznymi. W
kategorii rozpoznawania skrótów i skrótowców syntezatory poradziły sobie dobrze z
skrótami miar i wag. Natomiast zupełnie nie były w stanie rozpoznać popularnych w języku
polskim skrótów. Syntezatory Dragon Mobile i Google osiągnęły w tej kategorii pierwsze
miejsce, ustępujący im iSpeech nie podołał tylko z rozwinięciem skrótu „tel.” Wymowa
wyjątków również okazała się dla iSpeech za trudna i w tej kategorii nie zdobył żadnego
punktu. Pozostałe silniki poradziły sobie z tym zadaniem w stu procentach. Podobne rezultaty
syntezatory osiągnęły w przypadku konwersji znaków specjalnych, tu znów iSpeech nie
rozwinął znaków specjalnych w słowa.
Na podstawie sumy punktów najlepszy okazał się syntezator Google osiągając 5
punktów na 7 możliwych. Za nim uplasowały się kolejno Dragon Mobile z 4,2 punktu oraz
iSpeech z 4 punktami. Różnica pomiędzy pierwszym a kolejnymi miejscami jest znacząca i
widać tu przewagę syntezatora Google nad innymi rozwiązaniami. Należy również mieć na
uwadze, iż przetwarzanie tekstu przez wbudowany syntezator Androida jest znacznie
łatwiejsze przy tworzeniu aplikacji, jak również dużo tańsze, gdyż jako jedyne dostępne jest
za darmo dla użytkowników Androida oraz dla programistów tworzących aplikację.
8. Aplikacja Notification Catcher.
Na podstawie przedstawionych we wcześniejszych rozdziałach rozważań dotyczących
powiadomień systemu Android oraz metod przetwarzania tekstu na mowę w tymże systemie,
zaproponowano autorską aplikację Notification Catcher, realizującą powiadomienia głosowe
dla użytkownika. W aplikacji zastosowano opisane w rozdziale o sposobach pobierania
powiadomień metody, by dostarczyć odbiorcy możliwość samodzielnego wypróbowania
każdej z nich oraz wybrania właściwej dla danego użytkownika. Zaimplementowano metody
przechwytywania notyfikacji za pomocą Notification Listener, usługi ułatwiania dostępu oraz
usługi telefonii wraz z usługą wiadomości tekstowych. Oczywiście warto mieć na uwadze
zalety i wady każdego z rozwiązań, dlatego też domyślnym sposobem pozyskiwania
powiadomień w aplikacji został moduł oparty o Notification Listener. Został on wybrany jak
podstawowy z uwagi na to, iż jest to sposób najbardziej bezpieczny z punktu widzenia
użytkownika a zarazem dostarcza największej liczy możliwości oraz jako jedyny umożliwia
odczytywanie usuwanie odczytanych powiadomień z paska stanu systemu Android. W
przypadku silników Text-To-Speech postąpiono podobnie jak w przypadku metod
przechwytywania notyfikacji. A mianowicie zaimplementowano trzy silniki przetwarzające
tekst na mowę (wszystkie opisane w rozdziale dotyczącym przetwarzania tekstu na mowę):
Google Text-To-Speech, Dragon Mobile oraz iSpeech. Umożliwi to użytkownikowi
dostosowanie lektora do własnych potrzeb. Z uwagi na to, iż został użyty w aplikacji
domyślny silnik Google, użytkownik ma również możliwość zainstalowanie dowolnie
wybranego mechanizmu współpracującego z systemem Android. Taki mechanizm jest
wspierany przez aplikację, co daje duże możliwości konfiguracyjne.
46
8.1. Wymagania funkcjonalne i niefunkcjonalne aplikacji
8.1.1. Wymagania funkcjonalne
Poniższa tabela zawiera opis najważniejszych wymagań funkcjonalnych aplikacji
Notifiaction Catcher:
Tabela 8. Wymagania funkcjonalne aplikacji Notification Catcher.
Lp. Nazwa wymagania
1 Użytkownik będzie mógł przeglądać historię notyfikacji z podziałem na przeczytane
przez system i nie przeczytane oraz oznaczone jako usunięte.
2 Użytkownik będzie mógł włączyć/wyłączyć czytanie notyfikacji w dowolnej chwili.
3 System po włączeniu będzie czytał notyfikacje pojawiąjące się w pasku stanu.
4 Użytkownik będzie mógł ustalić notyfikacje których aplikacji mają być odczytywane
przez system.
5 Użytkownik będzie mógł ustalić czy powiadomienia mają być usuwane z paska stanu
systemu Android po przeczytaniu ich przez system.
6 Użytkownik będzie miał możliwość wybrania jednego z mechanizmów pozyskiwania
powiadomień (usługa ułatwiania dostępu, usługa telefonii, Notification Listner )
7 Użytkownik będzie miał możliwość wybrania systemu syntezy mowy.
8 System będzie informował użytkownika o stanie aktywności poprzez informację na
pasku stanu systemu Android.
9 Użytkownik będzie mógł określić czy powiadomienia mają być czytane na głos gdy
telefon jest ustawiony w stanie cichym.
10 Aplikacja będzie posiadała ikonę wskazującym w jakim stanie aktualnie się znajduje
włączone/wyłączone czytanie notyfikacji.
47
8.1.2. Wymagania niefunkcjonalne
Poniższa tabela zawiera opis najważniejszych wymagań niefunkcjonalnych aplikacji
Notifiaction Catcher:
Tabela 9. Wymagania niefunkcjonalne aplikacji Notification Catcher.
Lp. Nazwa wymagania
1 Aplikacja zostanie napisana przy użyciu Android Software Development Kit.
2 Ustawienia aplikacji będą korzystać z menadżera ustawień aplikacji systemu Android.
3 Bazą danych użytą w aplikacji będzie SQLite.
4 Wszystkie dane o powiadomieniach będą trzymana w wewnętrznej bazie danych.
5 Żadne dane o powiadomieniach nie będą dostępne na zewnątrz systemu.
6 Syntezatory mowy będą mogły używać połącznia z Internetem w celu wymiany
informacji niezbędnych do przetworzenia teksu na mowę.
7 Opłaty na Internet będą naliczane zgodnie z taryfą operatora i nie wchodzą w dziedzinę
aplikacji.
8 Aplikacja będzie wymagała od użytkownika nadania uprawnień do notyfikacji w
zależności od ustawień
Aplikacja będzie wymagała od użytkownika nadania uprawnień do usług ułatwiania
dostępu w zależności od ustawień.
48
8.2. Model aplikacji
Poniższy schemat przedstawia ogólne działanie aplikacji.
Rys. 16. Schemat działania aplikacji Notification Catcher.
Jak łatwo zauważyć menu aplikacji składa się z trzech podmodułów: Ustawień, Ustawień
Powiadomień i Historii Powiadomień. Każdy z tych modułów posiada swoją aktywność
obsługującą widok oraz interakcje użytkownika. Ekran ‘Ustawiania’ pozwala dostosować
działanie aplikacji do preferencji użytkownika. Ustawienia te gromadzone są i zarządzanie
przez systemowy moduł ustawień aplikacji. Z kolei ekran ‘Ustawienia Powiadomień’ pozwala
określić, które powiadomienia mają być czytanie przez aplikację. Informacje te
przechowywane są w bazie danych aplikacji a następnie na ich podstawie silnik powiadomień
określa czy aktualna notyfikacja ma zostać przeczytana, czy też może być pominięta. Na
ekranie ‘Historia Powiadomień’ użytkownik może sprawdzić jakie powiadomienia
wystawione zostały przez aplikacje, zarządzać nimi jak również uruchamiać aplikacje
bezpośrednio z powiadomienia.
Gdy system Android wystawi notyfikację, jeden wybrany mechanizm gromadzenia
powiadomień przechwytuje ją. Następnie zostaje ona przekazana do silnika powiadomień,
gdzie następuje wyekstrahowanie pożądanych informacji o notyfikacji oraz sprawdzenie z
49
ustawieniami użytkownika czy dana notyfikacja ma zostać odczytana. Na tym etapie również
informacje zawarte w powiadomieniu zostają zapisywanie w bazie danych oraz w zależności
od ustawień notyfikacja jest usuwana z paska aktywności.. Jeśli notyfikacja ma zostać
przeczytana, informacja o tym przekazywanie są do silnika Text-To-Speech, który zamienia
za pomocą wybranego w ustawieniach syntezatora tekst powiadomienia na głos, który
odtwarzany jest przez urządzenie. Cały ten proces dzieje się w tle aplikacji i nie potrzebuje do
żadnego inicjatora ze strony użytkownika. Efektem końcowym dla użytkownika jest tekst
powiadomienia, podany w sposób głosowy, na aktualnie wybrany interfejs wyjściowy audio:
głośnik urządzenia, słuchawki czy zestaw głośnomówiący.
8.3. Zastosowane technologie
Aplikacja został stworzona na platformę Android. Wersją docelową systemu był
Android 4.4.2 KitKat, który w momencie tworzenia aplikacji był najnowszą odsłoną systemu.
Należy tutaj mieć na uwadze iż jedna z funkcjonalności pozyskiwania powiadomień, a
mianowicie metod oparta na Notification Listener nie będzie funkcjonować na urządzeniach
wyposażonych w system Android w wersji niższej niż 4.2 Jelly Bean (informację ta zawarta
jest również w menu ustawień aplikacji). Językiem programistycznym, w którym stworzono
aplikację jest Java. Użyto w tym przypadku dedykowanego SDK (Software Development Kit)
dla systemu Android. Bazę danych aplikacji oparto na domyślnym rozwiązaniu system
android SQLite. Zdecydowano się na to rozwiązanie dlatego że baza danych aplikacji nie
wymagała zaawansowanych rozwiązań i użycie SQLite było wystarczające.
8.4. Struktura aplikacji
Poniższy rysunek przedstawia strukturę pakietową aplikacji Notification Catcher.
Aplikacja składa się z kilkudziesięciu klas oraz zawiera w sobie dwa pakiety dodatkowe
odpowiadające za implementację syntezatorów mowy iSpeech (org.ispeech) oraz Dragon
Mobile (com.nuance.nmdp.speechkit).
50
Rys. 17. Struktura pakietu aplikacji Notification Catcher
Charakterystyka klas została przedstawiona w porządku alfabetycznym:
AccessService
Klasa ta odpowiedzialna jest za implementacje metody pozyskiwania notyfikacji za
pomocą usług ułatwiania dostępu. Rozszerza ona systemową klasę
AccessibilityService dostarczającą metody z zakresu ułatwień dostępu. Szczegóły
sposobu pobierania powiadomień za pomocą tej metody zostały opisane w rozdziale
dotyczącym Accessibility Service.
BaseActivity
Aktywność ta jest podstawową w aplikacji, wszystkie inne aktywności dziedziczą po
niej. Dostarcza ona podstawowy widok i obsługę górnego menu aplikacji.
CustomListAdapter
Adapter widoku listy służący do wyświetlania powiadomień w postaci listy.
DatabaseHandler
Wewnątrz tej klasy inicjowana jest baza danych przy pierwszym uruchomieniu
aplikacji.
51
DragonMobileTTS
Zawiera implementację uruchomieniową syntezatora Dragon Mobile.
Extractor
W ciele tej klasy znajduje się proces odpowiedzialny za ekstrahowanie informacji z
przechwyconej notyfikacji.
IspeechTTS
Zawiera implementaję uruchomieniową syntezatora iSpeech.
MainActivity
Głowna aktywność aplikacji. Obsługuje widok ukazujący się po starcie aplikacji oraz
odbiera sygnały od silnika notyfikacji a następnie inicjuje syntezę mowy.
NotHistoryActivity
Aktywność obsługuje widok historii powiadomień oraz wszystkie operacje na nim
przeprowadzane.
NotificationDAO
Klasa jest kontenerem encji w bazie danych odpowiedzialnej za powiadomienia.
NotificationDataStore
W tej klasie metody odpowiedzialne są za komunikację z bazą danych oraz zamianę
rekordów z tabel w bazie danych na obiekty.
NotificationEngine
W klasie tej zaimplementowany jest silnik przetwarzający powiadomienia.
Odpowiedzialny jest on za przetworzenia danych z notyfikacji do postaci obiektu typu
Notification oraz za przesłanie informacji do silnika Text-To-Speech.
NotificationTypeDAO
Klasa jest kontenerem encji w bazie danych odpowiedzialnej za typy powiadomień.
NotListener
W ciele tej klasy zaimplementowany został sposób pozyskiwania notyfikacji za
pomocą Notification Listener. Klasa ta dziedziczy po klasie NotificationListener
NotSettingsActivity
Aktywność ta odpowiedzialna jest za wyświetlanie i zarządzanie widokiem ustawień
powiadomień.
PhoneReciver
Klasa ta zawiera implementację metody pozyskiwania notyfikacji za pomocą usługi
telefonii.
PInfo
Klasa ta jest kontenerem informacji o aplikacji w systemie Android.
52
SettingsActivity
Klasa ta implementuje ustawienia systemowe aplikacji oraz interakcję użytkownika w
widoku tychże ustawień.
SMSReciver
W klasie tej jest zaimplementowana metoda pobierania powiadomień za pomocą
usługi SMS.
ShowNotificationDetailsActivity
Aktywność ta zarządza widokiem szczegółów powiadomienia oraz interakcjami w tej
aktywności.
SwipeListViewTouchListener
Klasa ta zawiera implementację mechanizmu przesuwania w prawo lub lewo na liście
notyfikacji elementu w celu jego zarchiwizowania.
TextToSpeechEngine
Klasa ta jest implementacją silnika przetwarzania tekstu na mowę. W jej ciele
wyzwalane są w zależności od ustawień aplikacji mechanizmy Text-To-Speech.
Mechanizmy użyte w tej klasie zostały opisane w rozdziale dotyczącym przetwarzania
tekstu na mowę.
TypeModel
Klasa ta jest modelem aplikacji systemowej w widoku ustawień notyfikacji.
Utils
Klasa ta zwiera dodatkowe metody używane do przetwarzania informacji z
powiadomień w klasie Extractor.
53
9. Interfejs użytkownika aplikacji
Interfejs użytkownika aplikacji został zaprojektowany tak, aby jego używanie było
intuicyjne i proste dla użytkownika. Przy tworzeniu starano się maksymalnie uprościć
interfejs, by nie utrudniał korzystania z aplikacji. Po uruchomieniu aplikacji wita główny
panel aplikacji, który umożliwia dostęp do wszystkich aplikacji.
Rys. 18. Ekran startowy aplikacji przy pierwszym uruchomieniu (po lewej), w trybie normalnego działania (po prawej).
Na głównym ekranie znajduje się przycisk informujący o stanie aplikacji (czytanie
powiadomień włączone/wyłączone) oraz przyciski prowadzące do trzech głównych paneli
aplikacji: ustawień, ustawień powiadomień oraz historii powiadomień. Ustawienia aplikacji
od ustawień powiadomień rozdzielono celowo, aby nie komplikować ekranu ustawień
aplikacji. Po kliknięciu w wybraną przycisk użytkownik zostaje przeniesiony do
odpowiedniego ekranu.
Klikając w przycisk Ustawienia, pokazuje się ekran z opcjami aplikacji na jakie może
mieć wpływ użytkownik.
54
Rys. 19. Ekran ustawień aplikacji.
Pierwszą opcją jest znana z panelu głównego opcją włączania działania aplikacji. Kolejnym
ustawieniem jest Czytaj w trybie cichym. Opcja ta włącza czytanie powiadomień, nawet gdy
telefon jest ustawiony w trybie wyciszonym lub wibracji. Następną opcją jest
włączanie/wyłączanie czytania powiadomień typu Toast. Są to powiadomienia pojawiające
się zwykle u dołu ekranu w postaci paska i znikające po kilku sekundach. Opcja ta działa
tylko z włączoną opcją ułatwienia dostępu w sekcji mechanizmów powiadomień. Odrębną
sekcją w panelu ustawień są mechanizmy powiadomień. Sekcja ta pozwala wybrać
mechanizm powiadomień, za pomocą którego aplikacja będzie pobierać notyfikacje z
systemu. Jest tu możliwość wybrania jednej z trzech opcji: ułatwienia dostępu, usługa
powiadomień lub tylko sms. Za pomocą wyboru jednej z tej opcji użytkownik może
przetestować jak działają powiadomienia przy wybraniu odpowiedniej z opcji, następnie
zdecydować która z nich jest najodpowiedniejsza. Należy tutaj również wspomnieć, iż opcja
usługi powiadomień dostępna jest dla systemów Android w wersji 4.2 lub wyższej.
Posiadacze starszej wersji systemu muszą zdecydować się na jedną z pozostałych opcji.
Poniżej opcji mechanizmu powiadomień znajduje się opcje dotyczące przetwarzania dźwięku
na mowę. I tak opcja TTS pozwala na wybranie silnika Text-To-Speech, który będzie
przetwarzał powiadomienia do formy głosowej. Mamy tutaj do wyboru dwa silniki
wbudowanie w aplikację: iSpeech, Dragon Mobile oraz trzecią opcję ustawiającą jak silnik
TTS systemowy syntezator androida. Daje do możliwość użytkownikowi podłączenia do
aplikacji dowolnego silnika syntezy mowy, dostępnego dla systemu Android. Opcja lektor
pozwala na wybór języka lub osoby lektora, jeśli takowa konfiguracja jest możliwa dla
55
wybranego wcześniej silnika TTS. Użytkownik ma tu możliwość wybrania płci lektora lub
języka. Ustawienia dźwięku pozwalają ustalić, w jaki sposób powiadomienie ma być
skorelowane z sygnałem pojawiającego się powiadomienia.
Ostatnią opcją jest możliwość zdefiniowania czy notyfikacja ma zniknąć z ekranu po
przeczytaniu jej przez aplikację. Usługa ta dostępna jest tylko wtedy, gdy mechanizmem
powiadomień został wybrany Notification Listener.
Należy tutaj wspomnieć, iż w przypadku wyboru mechanizmu powiadomień aplikacja
poinformuje użytkownika o zagrożeniach, jakie może spowodować ustawienie takiego
mechanizmu. Użytkownik zostanie następnie przekierowany do odpowiedniego ekranu
ustawień systemowych, umożliwiających włączenie mechanizmu. W przypadku Ułatwień
dostępu ekranem, który pojawi się dla użytkownika będą ustawienia Ułatwiania dostępu.
Rys. 20. Ekran ustawień Ułatwień dostępu z włączonymi uprawnieniami dla aplikacji Notification Catcher.
Na tym ekranie użytkownik do poprawnego działania aplikacji musi włączyć usługę
NotificatinCatcher. Dopiero po włączeniu tej usługi aplikacja zacznie pobierać przychodzące
notyfikację i czytać je za użytkownika. Z kolei w przypadku wybrania usługi notyfikacji z
mechanizmów powiadomień przeniesieni zostaniemy do dostępu powiadomień, gdzie
użytkownik musi nadać uprawnienia NotificationCacher jako aplikacji mogącej używać
usługi powiadomień.
Rys. 21. Ekran Zabezpieczenia z informacją, że jedna aplikacja ma dostęp do powiadomień.
56
Rys. 22. Ekran Dostępu do powiadomień informujący prawach dostępu aplikacji Notification Catcher do powiadomień.
Przechodząc do kolejnego modułu aplikacji jakim są ustawienia powiadomień, ekran, który
się otworzy będzie zawierał listę wszystkich aplikacji systemowych mogących wystawiać
powiadomienia.
Rys. 23. Ekran Ustawienia Powiadomień aplikacji Notifiacation Catcher.
Domyślnie wszystkie powiadomienia, które mają być odczytywanie przez aplikację są
włączone. Na tym ekranie użytkownik może wybrać według własnego uznania
57
powiadomienia, z jakich aplikacji mają być odczytywanie przez syntezator Text-To-Speech.
Dzięki temu łatwo można skonfigurować aplikację w zależności od upodobań.
Kolejnym modułem aplikacji jest historia powiadomień. W tym module możemy
sprawdzić jakie notyfikacje zostały wystawione przez system android. Sprawdzić czy są
jakieś nowe powiadomienia nie przeczytane przez aplikację, ponieważ telefon był w trybie
cichym, jak również przejść bezpośrednio z notyfikacji do aplikacji, która ją wystawiła
klikając w jej logo.
Rys. 24. Ekran Historia Powiadomień z notyfikacjami zebranymi przez aplikację.
Dla użytkownika prezentowana jest lista powiadomień wraz z informacjami zawartymi w nim
oraz godziną i datą pojawienia się aplikacji. Klikając na dowolny element z listy otworzy się
ekran z szczegółami notyfikacji. Przesuwając notyfikację w prawo następuje usunięcie jej z
listy.
58
10. Podsumowanie
W niniejszej pracy został przeanalizowany temat przetwarzania powiadomień systemu
Android na formę głosową za pomocą metod przetwarzania tekstu na mowę (Text-To-
Speech). Praca została podzielona na trzy główne części. W pierwszej części zostały
przeanalizowane sposoby z jakich można korzystać przy przechwytywaniu powiadomień
wystawianych przez różne aplikacje w środowisku Android. Zostały przeanalizowane,
zaimplementowane i przetestowane trzy ścieżki dostępu do notyfikacji: metoda oparta o
usługę ułatwiania dostępu, metoda oparta o usługę telefonii oraz metoda korzystająca z
Notification Listenera. Najlepsza z tych metoda okazała się ta bazująca na Notification
Listener, ponieważ za jej pomocą możliwe jest pobranie informacji o notyfikacjach z
największej liczby aplikacji oraz usuwanie powiadomień bezpośrednio z aplikacji.
Druga cześć pracy opisuje metody przetwarzania tekstu na mowę w środowisku
Android. W tym celu wybrano, scharakteryzowano a następnie zaimplementowano i
przetestowano dwie opcje silników przetwarzania tekstu na mowę. Były to rodziny
syntezatorów mowy działające w systemie Android (Google Text-To-Speech) oraz rodziny
syntezatorów pracujących na zasadzie systemów Software as a Service (iSpeech oraz
DragonMobile). Syntezatory te przetestowano pod kątem poprawności czytanego tekstu w
języku polskim. Wszystkie silniki syntezy mowy w testach poprawności wykazały się
podobną skutecznością analizowanego teksu. Najlepszy wynik został osiągnięty przez system
przetwarzania tekstu na mowę od firmy Google. Wynik ten nie zaskakuje, ponieważ od wielu
wersji Androida synteza mowy jest udoskonalana i z wersji na wersję osiąga co raz to lepsze
wyniki. Syntezatorów nie testowano pod względem jakości mowy, ponieważ była by to
ocena subiektywna i każdy użytkownik może wybrać odpowiedni dla siebie głos.
Finalną częścią pracy było połączenie części pierwszej o pozyskiwaniu notyfikacji oraz
części drugiej o przetwarzaniu tekstu na mowę. W tym celu stworzono aplikację prezentującą
możliwości odczytywania przez syntezator mowy treści powiadomień z aplikacji systemu
Android. Stworzona aplikacja jest czymś w rodzaju pomocnika, który odczytuje wiadomości
tekstowe, informacje z portali społecznościowych, maile itd.. Informacje te przekazywane są
dla użytkownika w sposób głosowy na wybrane wyjście audio urządzenia w momencie
wystąpienia określonego zdarzenia (powiadomienia) bez jakiejkolwiek potrzeby interakcji ze
strony użytkownika. Aplikacja ta może służyć zarówno osobom mającym problemy ze
wzrokiem, jak i sportowcom podczas codziennych treningów.
59
11. Bibliografia
[1] Dutoit T., An Introduction to Text-To-Speech Synthesis, Kluwer Academic Publishers,
2001
[2] Google Inc., Android delevopers guide, 2014, http://developer.android.com/index.html
[3] Gunasekera S. A., Android Apps Security, New York, Apress, 2012
[4] Hoog A, Android Forensics Investigation, Analysis and Mobile Security for Google
Android, Waltham, Elsevier Inc., 2011
[5] Jordan L. i Greyling J., Practical Android Projects, New York, Apress, 2011
[6] Komatineni S. i MacLean D., Pro Android 4, New York, Apress, 2012
[7] Milette G. i Stroud A., Professional Android Sensor Programming, Indianapolis, John
Wiley & Sons Inc., 2012
[8] Smith D. i Friesen J., Android Recipes A Problem-Solution Approach Second Edition,
New York, Apress, 2012
[9] Strona Dragon Mobile SDK dla programistów, 2014,
http://dragonmobile.nuancemobiledeveloper.com/
[10] Taylor P., Text-to-Speech Synthesis, Cambridge, Cambridge University Press, 2009
[11] Ispeech Developers Site, 2014, https://www.ispeech.org/developers
[12] Text-To-Speech Google API, 2014,
http://developer.android.com/reference/android/speech/tts/TextToSpeech.html
[13] Sms Reader, 2013,
https://play.google.com/store/apps/details?id=de.braunandroid.smsreader
[14] Notification Avatar, 2014,
https://play.google.com/store/apps/details?id=com.spicedroid.notifygirl.free
[15] Voice Notify, 2014, http://pilot51.com/wiki/Voice_Notify
[16] Notification Reader, 2014,
https://play.google.com/store/apps/details?id=com.parkpossesoftware.notificationread
er
[17] Speak Me, 2014, https://play.google.com/store/apps/details?id=com.flip.speakme