poniedziałek, 30 kwietnia 2018

BabyPhone - zaczynamy

Powód:
Mój ukochany 2,5 letni syn uwielbia bawić się moim telefonem. Zawsze to lubił. Jego młodszy, pół roczny brat chętnie idzie w jego ślady.
Chcę przygotować aplikację, która zadba, żeby nie zrobili niczego problematycznego na moim telefonie.

Cel:
  • aplikacja dla dzieci
  • ma zaciekawić dziecko a najlepiej czegoś je nauczyć
  • ma zadbać o bezpieczeństwo telefonu

Wstępny pomysł:

Aplikacja będzie się otwierała przy zablokowanym telefonie, dzięki temu:
  • dziecko nie będzie się starało go odblokować
  • dziecko nie będzie miało dostąpu do innych aplikacji
  • dziecko nie będzie próbowało dzwonić na numery alarmowe
Oczywiście to tylko założenie... dziecko może jednak myśleć inaczej


Aplikacja musi być:
  • kolorowa
  • z interakcją
  • dźwiękowa
  • może jakiś ruch?
  • dobrze by było jakiś element nauki
  • możliwość dopasowywania przez rodzica
  • zmienna - żeby się nie nudziła

Element naukowy:
Jakiś czas temu słyszałam o metodzie uczenia dzieci czytania, matematyki i języków obcych od wieku niemowlęcego. Temat był kontrowersyjny, ostatecznie nie zdecydowałam się - wymaga od rodzica sporo pracy, czasu, poza tym ja nie chciałam moich dzieci niczego uczyć inaczej niż przez zabawę, doświaczanie, rozmowy i obserwację (mam jakieś takie przekonanie, że chcę im pokazać świat i nauczyć je cieszenia się tym światem, ciekawości świata itp.). Mniejsza o to - w każdym razie metoda jest i pomyślałam, że jest w sam raz na apkę.

Plan:
  • zacznę od ogólnej apki - BabyPhone 
  • dodam lekcję matematyki - BabyPhone Mat
  • dodam lekcję czytania - BabyPhone Read
  • dodam lekcję języka - BabyPhone Lang

czwartek, 26 kwietnia 2018

LockMe - Retro

(4L)

Liked:
  • w końcu skończyłam jakiś projekt - może mały, ale jednak
  • dużo się przy okazji nauczyłam
  • zrobiłam początkową wersję projektu i używając jej zauważyłam, że potrzebuję dodatkowej funkcji
Learned:
  • z pozoru prosty projekt może być bardzo skomplikowany
  • manifest projektu to bardzo ciekawe narzędzie
  • wiem już jak działają zadania w androidzie
Lacked:
  • czasu - choćby jednego stałego momentu w ciągu tygodnia
  • listy zadań do wykonania w projekcie (był straszny chaos)
  • blogowania na bierząco
  • nawyku commitowania codziennie
Long For:
  • mój pierwszy skończony projekt :)

Usprawnienia:
  • Zaplanowanie zadań na początku nowego projetu

LockMe - zakończenie

Pora na wydanie pierwszej wersji - LockMe 1.0

Repozytorium projektu:
Repo LockMe - GitHub

Instalka:
LockMe 1.0

czwartek, 12 kwietnia 2018

LockMe - java.lang.RuntimeException: Unable to instantiate receiver dmm.lockme.Lock$LockReceiver: java.lang.InstantiationException: java.lang.Class has no zero argument constructor

Taki mi się właśnie FATAL EXCEPTION trafił. A długo się zastanawiałam czemu mi się apka wywala zanim się jeszcze porządnie włączy, jak tylko dam jej prawa administratora, a później działa sobie normalnie i spokojnie. To przecież nie może być mój błąd, skoro później tak ładnie działa.

A jednak.
Problem wynikał z tego, że wydawało mi się, że ta aplikacja jest bardzo, bardzo prosta, na 3 linijki max. Wydawało mi się, że ja chcę tylko blokować ekran, to przecież nic ważnego, nic wielkiego, nic skomplikowanego. Dlatego z różnych przykładów brałam tylko to, co było niezbędne do uruchomienia aplikacji, nie kopiowałam wszystkiego bezmyślnie.

Aplikacja wymagała implementacji klasy, która miała rozszerzać DeviceAdminReceiver. To po to, żeby aplikacja mogła uzyskać uprawnienia administratora. Nie wiedziałam wtedy, że do manifestu nie można dodwać klas, które nie są statyczne i dlatego pojawił się ten wyjątek. Moja klasa nie miała robić nic szczególnego, dlatego mogłam spokojnie zadeklarować ją następująco:
public static class LockReceiver extends DeviceAdminReceiver{
    }


LockMe - java.lang.RuntimeException: Unable to create service dmm.lockme.FloatingWidgetService: android.view.WindowManager$BadTokenException: Unable to add window android.view.ViewRootImpl$W@9a6db9d -- permission denied for window type 2002

Mój kolejny wyjątek.
Wystąpił przy okazji przygotowywania widgetu, który umożliwiałby mi blokowanie ekranu przy otwartej dowolnej aplikacji.
Znalazłam informację, że można zrobić taki element, który działałby na zasadzie alarmu. Niestety, żeby tak było użytkownik musiał wyrazić zgodę na takie działanie aplikacji.
No i zaczęły mi się robić pętle w pętlach, okazało się, że warunek nie został spełniony a ja tu chcę alarm wyświetlać (podobnie jak w sytuacji z adminem) i tak to się pojawił wyjątek.

Wniosek: następnym razem, gdy aplikacja będzie potrzebowała specjalnych uprawnień do wykonania działania muszę się upewnić, że je ma. Nie wystarczy założyć, że gdzieś wyżej w kodzie, wcześniej, poprosiliśmy o nie - zawsze przed użyciem funkcji, która potrzebuje specjalnych uprawnień sprawdź czy je ma.

poniedziałek, 9 kwietnia 2018

LockMe - java.lang.SecurityException: No active admin owned by uid 10088 for policy #3

To miało być takie proste. Przeczytałam ze (mam nadzieję) zrozumieniem co mam zrobić, dopasowałam ustawienia do swoich potrzeb, skompilowałam i... FATAL EXCEPTION

A raczej tak mi się wydawało.

Kluczowe okazało się sprawdzenie, czy aplikacja te uprawenienia ma i wywołanie funkcji blokowania TYLKO wtedy jeśli je ma - wszystko w jednej pętli if () oraz else() - wydawało mi się, że wystarczy samo sprawdzenie czy uprawnienia są (i oczywiście nadanie ich w przypadku braku) wystarczy a funkcję blokowania mogę dodać poza pętlą. Otórz nie mogę.

sobota, 7 kwietnia 2018

Czy zawsze da się wrócić do zadania?

Ustawiając aplikacji niestandardowe atrybuty trzeba się upewnić, że do wszystkich rozpoczętych przez naszą aplikację zadań będzie można wrócić.

Czyli za każdym razem, gdy jakaś aktywność ma dla atrybutu launchMode wartość singleTask lub  singleInstance, aktywność ta powinna:
  • mieć zadeklarowane w manifeście (w tagu <intent filter>), że jest to 
    • aktywność główna - <action android:name="android.intent.action.MAIN" />
    • można się przez nią połączyć z zadaniem - <category android:name="android.intent.category.LAUNCHER" />
  • mieć ustawioną dla atrybutu finishOnTaskLaunch wartość false.

Mieszanie w zadaniu

Tryb włączania aktywności (activity) i ich powiązanie z aktualnym zadaniem (jeśli ma być jakiś nietypowy) można określić przez manifest lub przez kod aplikacji.

Żeby zmienić naturalny sposób obsługi zadania (task) można zadeklarować to w manifeście podając odpowiednie atrybuty do taga <activity>:
  • taskAffinity
  • launchMode
  • allowTaskReparenting
  • clearTaskOnLaunch
  • alwaysRetainTaskState
  • finishOnTaskLaunch
A w aplikacji można posłużyć się odpowiednimi flagami przy wywoływaniu aktywności:
  • FLAG_ACTIVITY_NEW_TASK
  • FLAG_ACTIVITY_CLEAR_TOP
  • FLAG_ACTIVITY_SINGLE_TOP
W przypadku, gdy jedna aktywność wywołuje drugą i obie mają zadeklarowane w jaki sposób ta druga aktywność ma być powiązana z zadaniem, wyższy priorytet ma informacja od aktywności wywołującej.

Ważne - android doskonale radzi sobie ze swoimi zadaniami, kiedy mu się w tym nie przeszkadza. Mieszając w zadaniach należy bardzo dokładnie przetestować wszystkie przypadki cofania z różnych aktywności - upewnić się, że stos będzie odpowiednio obsłużony i aplikacja nie przestanie działać.

Jak android czyści stos (i co na to można poradzić)?

Gdy użytkownik długo (muszę poszukać informacji ile czasu to jest długo dla androida) nie korzysta z danego zadania (task) system zamyka wszystkie aktywności (activity) w danym zadaniu poza pierwszą (root activity).

Żeby tak się nie działo należy w tej pierwszej aktywności wywołującej kolejne ustawić dla atrybutu alwaysRetainTaskState wartość true.

Żeby android nie czekał, tylko od razu po przejściu aplikacji z głównego wątku (foreground) do tła (background) zamknął wszystkie aktywności poza pierwszą należy w tej pierwszej aktywności wywołującej kolejne ustawić dla atrybutu clearTaskOnLaunch wartość true.

Żeby system po przejściu aplikacji do tła zamknął konkretną aktywność należy ustawić dla atrybutu finishOnTaskLaunch wartość true.