Interfejsy API Androida 4.4

Poziom API: 19

Android 4.4 (KITKAT) to nowa wersja na platformę Androida oferująca nowe funkcje dla użytkowników i deweloperów aplikacji. Ten dokument zawiera wprowadzenie do najbardziej znanych nowych interfejsów API.

Deweloper aplikacji powinien jak najszybciej pobrać obraz systemu Android 4.4 i platformę SDK z Menedżera SDK. Jeśli nie masz urządzenia z Androidem 4.4, na którym chcesz przetestować aplikację, użyj obrazu systemu Android 4.4, by przetestować aplikację w emulatorze Androida. Następnie skompiluj aplikacje na platformie Androida 4.4, aby zacząć korzystać z najnowszych interfejsów API.

Aktualizowanie docelowego poziomu interfejsu API

Aby lepiej zoptymalizować aplikację pod kątem urządzeń z Androidem 4.4, ustaw targetSdkVersion na "19", zainstaluj ją na obrazie systemu Androida 4.4, przetestuj ją, a następnie opublikuj aktualizację z tą zmianą.

Możesz używać interfejsów API w Androidzie 4.4, a jednocześnie obsługiwać starsze wersje. W tym celu dodaj do kodu warunki, które przed wykonaniem interfejsów API nieobsługiwanych przez minSdkVersion sprawdzają poziom interfejsu API systemu. Więcej informacji o utrzymywaniu zgodności wstecznej znajdziesz w artykule Obsługa różnych wersji platformy.

Więcej informacji o tym, jak działają poziomy interfejsu API, znajdziesz w artykule Co to jest poziom interfejsu API?.

Ważne zmiany w działaniu

Jeśli masz już opublikowaną aplikację na Androida, pamiętaj, że zmiany w Androidzie 4.4 mogą na nią wpływać.

Jeśli aplikacja odczytuje dane z pamięci zewnętrznej...

Aplikacja nie może odczytywać plików udostępnionych w pamięci zewnętrznej na Androidzie 4.4, chyba że ma uprawnienie READ_EXTERNAL_STORAGE. Oznacza to, że pliki w katalogu zwróconym przez funkcję getExternalStoragePublicDirectory() nie są już dostępne bez tego uprawnienia. Jeśli jednak chcesz uzyskać dostęp tylko do katalogów aplikacji udostępnionych przez getExternalFilesDir(), nie potrzebujesz uprawnienia READ_EXTERNAL_STORAGE.

Jeśli aplikacja korzysta z komponentu WebView...

Aplikacja może działać inaczej na Androidzie 4.4, zwłaszcza gdy zaktualizujesz targetSdkVersion aplikacji do wersji „19” lub nowszej.

Kod będący podstawą klasy WebView i powiązanych z nimi interfejsów API został uaktualniony, by opierał się na nowoczesnym zrzucie kodu źródłowego Chromium. Zapewniają różne ulepszenia wydajności, obsługę nowych funkcji HTML5 i obsługę zdalnego debugowania treści w WebView. Zakres tego uaktualnienia oznacza, że jeśli aplikacja korzysta z funkcji WebView, w niektórych przypadkach może to mieć wpływ na jej działanie. Znane zmiany w działaniu są dokumentowane i w większości przypadków mają wpływ na aplikację tylko wtedy, gdy zaktualizujesz targetSdkVersion aplikacji do poziomu „19” lub nowszego, ale nowy WebView działa w „trybie osobliwości”, udostępniając niektóre starsze funkcje w aplikacjach kierowanych na interfejs API na poziomie 18 lub niższym. Może to wynikać z nieznanych zachowań występujących w poprzedniej wersji WebView.

Jeśli więc istniejąca aplikacja korzysta z WebView, jak najszybciej przetestuj ją na Androidzie 4.4 i zapoznaj się z informacjami na temat migracji do WebView w Androidzie 4.4, aby dowiedzieć się, jak zmiana wersji targetSdkVersion na „19” lub nowszą może wpłynąć na aplikację.

Jeśli aplikacja używa AlarmManagera...

Gdy ustawisz w aplikacji targetSdkVersion wartość „19” lub wyższą, alarmy utworzone za pomocą parametru set() lub setRepeating() będą nieprecyzyjne.

Aby zwiększyć wydajność energetyczną, Android grupuje teraz alarmy ze wszystkich aplikacji, które występują w podobnych godzinach. System wybudza urządzenie raz, a nie kilka razy, aby odpowiedzieć na każdy alarm.

Jeśli alarm nie jest powiązany z dokładną godziną zegara, ale ważne jest, aby alarm został wywołany w określonym przedziale czasu (np. między 14:00 a 16:00), możesz użyć nowej metody setWindow(), która akceptuje „najwcześniejszą” godzinę alarmu i „okno” następujących po najwcześniejszej godzinie, w której system ma wywołać alarm.

Jeśli alarm musi być przypięty do dokładnej godziny zegara (np. w celu przypomnienia o wydarzeniu w kalendarzu), możesz użyć nowej metody setExact().

To niedokładne zachowanie grupowania dotyczy tylko zaktualizowanych aplikacji. Jeśli dla aplikacji targetSdkVersion ustawisz wartość „18” lub mniej, w Androidzie 4.4 alarmy będą działać tak samo jak w poprzednich wersjach.

Jeśli aplikacja synchronizuje dane za pomocą narzędzia ContentAssignr...

Gdy ustawisz w polu targetSdkVersion aplikacji wartość „19” lub wyższą, synchronizacja za pomocą usługi addPeriodicSync() będzie wykonywać operacje synchronizacji w domyślnym przedziale elastycznym wynoszącym około 4% wybranego okresu. Jeśli na przykład częstotliwość odpytywania to 24 godziny, operacja synchronizacji może odbywać się w ciągu godziny, a nie codziennie o tej samej godzinie.

Aby określić własny interwał elastyczny dla operacji synchronizacji, zacznij używać nowej metody requestSync(). Więcej informacji znajdziesz w sekcji Adaptery do synchronizacji poniżej.

To zachowanie interwału elastycznego dotyczy tylko zaktualizowanych aplikacji. Jeśli ustawisz targetSdkVersion na „18” lub mniej, dotychczasowe żądania synchronizacji będą działać tak samo jak w poprzednich wersjach systemu Android 4.4.

Struktura drukowania

Android zawiera teraz pełną platformę pozwalającą na drukowanie dowolnych dokumentów na drukarce połączonej przez Wi-Fi, Bluetooth lub inne usługi. System obsługuje transakcję między aplikacją, która chce wydrukować dokument, a usługami dostarczającymi zadania drukowania do drukarki. Platforma android.print zapewnia wszystkie interfejsy API niezbędne do określenia wydrukowanego dokumentu i przesłania go do systemu do wydrukowania. To, które interfejsy API są potrzebne do zadania drukowania, zależy od treści.

Drukowanie treści ogólnych

Jeśli chcesz wydrukować treść z interfejsu jako dokument, musisz najpierw utworzyć podklasę PrintDocumentAdapter. W ramach tych zajęć musisz zaimplementować kilka metod wywołania zwrotnego, w tym metodę onLayout(), która określa układ na podstawie podanych właściwości drukowania, i metodę onWrite(), by szeregować treści do druku w typie ParcelFileDescriptor.

Aby zapisywać treści w usłudze ParcelFileDescriptor, musisz je przesłać w formacie PDF. Nowe interfejsy API PdfDocument pozwalają to łatwo zrobić, udostępniając obiekt Canvas z usługi getCanvas(), który umożliwia rysowanie treści do druku. Następnie zapisz PdfDocument w elemencie ParcelFileDescriptor, korzystając z metody writeTo().

Po zdefiniowaniu implementacji dla PrintDocumentAdapter możesz wykonywać zadania drukowania na żądanie użytkownika przy użyciu metody PrintManager (print()), która pobiera PrintDocumentAdapter jako jeden z argumentów.

Drukowanie zdjęć

Jeśli chcesz wydrukować tylko zdjęcie lub inną bitmapę, wszystkie zadania wykona za Ciebie pomocnicze interfejsy API dostępne w bibliotece pomocy. Po prostu utwórz nowe wystąpienie obiektu PrintHelper, ustaw tryb skalowania za pomocą setScaleMode(), a następnie przekaż Bitmap do printBitmap(). To wszystko. Biblioteka obsługuje całą pozostałą interakcję z systemem, aby dostarczyć bitmapę do drukarki.

Usługi drukarskie budowlane

Jako producent OEM możesz korzystać z platformy android.printservice, aby zapewnić współdziałanie drukarek z urządzeń z Androidem. Usługi drukowania możesz tworzyć i rozpowszechniać w postaci plików APK, które użytkownicy mogą instalować na swoich urządzeniach . Aplikacja usługi drukowania działa głównie jako usługa bez interfejsu graficznego – w tym celu podklasyfikuje klasę PrintService, która odbiera zadania drukowania z systemu i przekazuje je do drukarek za pomocą odpowiednich protokołów.

Więcej informacji o drukowaniu zawartości aplikacji znajdziesz w artykule Drukowanie treści.

Dostawca SMS-ów

Dostawca treści Telephony („Dostawca SMS-ów”) umożliwia aplikacjom odczytywanie i zapisywanie wiadomości SMS i MMS na urządzeniu. Znajdują się w nim tabele SMS-ów i MMS-ów odebranych, utworzonych w wersji roboczej, wysłanych, oczekujących itp.

Począwszy od Androida 4.4, ustawienia systemowe pozwalają użytkownikom wybrać „domyślną aplikację do obsługi SMS-ów”. Po wybraniu tej opcji tylko domyślna aplikacja do obsługi SMS-ów będzie mogła wysyłać SMS-y do dostawcy SMS-ów i tylko domyślna aplikacja do obsługi SMS-ów będzie otrzymywać komunikaty SMS_DELIVER_ACTION, gdy użytkownik otrzyma SMS-a, lub komunikat WAP_PUSH_DELIVER_ACTION, gdy użytkownik otrzyma MMS-a. Domyślna aplikacja do obsługi SMS-ów odpowiada za zapisywanie informacji dostawcy SMS-ów w momencie odebrania lub wysłania nowej wiadomości.

Inne aplikacje, które nie zostały wybrane jako domyślna aplikacja do obsługi SMS-ów, mogą tylko odczytywać dane dostawcy SMS-ów, ale mogą też otrzymywać powiadomienia o nowych SMS-ach, nasłuchując komunikatu SMS_RECEIVED_ACTION, czyli komunikatu, którego nie można przerwać i może być dostarczany do wielu aplikacji. Ta funkcja jest przeznaczona dla aplikacji, które – choć nie zostały wybrane jako domyślna aplikacja do obsługi SMS-ów – wymagają odczytywania specjalnych wiadomości przychodzących, na przykład weryfikacji numeru telefonu.

Więcej informacji znajdziesz w poście Jak przygotować aplikacje do SMS-ów w wersji KitKat.

Łączność bezprzewodowa

Emulacja karty hosta

Aplikacje na Androida mogą teraz emulować karty NFC w standardzie ISO14443-4 (ISO-DEP), które używają APDU do wymiany danych (zgodnie z normą ISO7816-4). Dzięki temu urządzenie obsługujące komunikację NFC z Androidem 4.4 może jednocześnie emulować kilka kart NFC oraz umożliwia zainicjowanie transakcji przez terminal płatniczy NFC lub inny czytnik NFC na podstawie identyfikatora aplikacji (AID).

Jeśli chcesz emulować kartę NFC, która używa tych protokołów w aplikacji, utwórz komponent usługi na podstawie klasy HostApduService. Jeśli zamiast tego Twoja aplikacja używa bezpiecznego elementu do emulacji karty, musisz utworzyć usługę na podstawie klasy OffHostApduService, która nie będzie bezpośrednio brać udziału w transakcjach, ale jest niezbędna do zarejestrowania identyfikatorów AID, które powinny być obsługiwane przez ten element.

Więcej informacji znajdziesz w przewodniku Emulacja kart NFC.

Tryb czytnika NFC

Nowy tryb czytnika NFC umożliwia ograniczenie aktywności NFC do odczytu tylko tych typów tagów, których dana aktywność dotyczy na pierwszym planie. Możesz włączyć tryb czytnika w swojej aktywności w usłudze enableReaderMode(), udostępniając implementację interfejsu NfcAdapter.ReaderCallback, która otrzymuje wywołanie zwrotne po wykryciu nowych tagów.

Ta nowa funkcja, w połączeniu z emulacją karty hosta, pozwala systemowi Android działać po obu stronach interfejsu płatności mobilnych: jedno urządzenie działa jako terminal płatniczy (urządzenie obsługujące aktywność w trybie czytnika), a drugie jako klient płatności (urządzenie emulujące kartę NFC).

Nadajniki podczerwieni

Gdy korzystasz z urządzenia zawierającego nadajnik podczerwieni (IR), możesz teraz przesyłać sygnały podczerwieni za pomocą interfejsów API ConsumerIrManager. Aby uzyskać wystąpienie typu ConsumerIrManager, wywołaj funkcję getSystemService(), podając jako argument CONSUMER_IR_SERVICE. Następnie możesz wysyłać zapytania o częstotliwości podczerwień obsługiwane przez urządzenie getCarrierFrequencies() i przesyłać sygnały, przekazując żądaną częstotliwość i wzorzec sygnału za pomocą funkcji transmit().

Najpierw sprawdź, czy urządzenie zawiera nadajnik podczerwieni, wywołując hasIrEmitter(). Jeśli jednak Twoja aplikacja jest zgodna tylko z urządzeniami, które go mają, dodaj element <uses-feature> do pliku manifestu dla "android.hardware.consumerir" (FEATURE_CONSUMER_IR).

Multimedia

Odtwarzanie adaptacyjne

Interfejsy API MediaCodec obsługują teraz adaptacyjne odtwarzanie wideo, co pozwala na płynną zmianę rozdzielczości podczas odtwarzania na urządzeniu Surface. Możesz przesyłać klatki wejściowe dekodera o nowej rozdzielczości, a rozdzielczość buforów wyjściowych nie spowoduje istotnych przerw.

Aby włączyć odtwarzanie adaptacyjne, dodaj do MediaFormat 2 klawisze, które określają maksymalną rozdzielczość wymaganą przez aplikację z kodeka: KEY_MAX_WIDTH i KEY_MAX_HEIGHT. Po dodaniu tych komponentów do: MediaFormat przekaż MediaFormat do instancji MediaCodec za pomocą configure().

Kodek płynnie przełącza się między rozdzielczościami równymi lub mniejszymi. Kodek może też obsługiwać rozdzielczości większe niż określone maksymalne (o ile mieści się w granicach obsługiwanych profili), ale przejście na większe rozdzielczości może nie być płynne.

Aby zmienić rozdzielczość podczas dekodowania filmu w standardzie H.264, nadal dodawaj klatki do kolejki za pomocą MediaCodec.queueInputBuffer(), ale pamiętaj, by podać nowe wartości zestawu parametrów sekwencji (SPS) i PPS (PPS) wraz z ramką natychmiastowego odświeżania dekodera (IDR) w jednym buforze.

Zanim jednak spróbujesz skonfigurować kodek pod kątem odtwarzania adaptacyjnego, musisz sprawdzić, czy urządzenie obsługuje tę funkcję, wywołując isFeatureSupported(String) z metodą FEATURE_AdaptivePlayback.

Uwaga: obsługa odtwarzania adaptacyjnego zależy od dostawcy. Niektóre kodeki mogą wymagać więcej pamięci, aby wyświetlać wskazówki dotyczące większej rozdzielczości. Dlatego maksymalne rozdzielczości należy ustawiać na podstawie dekodowanego materiału źródłowego.

sygnatury czasowe ścieżki dźwiękowej na żądanie;

Aby ułatwić synchronizację dźwięku i obrazu, nowa klasa AudioTimestamp zawiera szczegółowe informacje o osi czasu konkretnej „klatki” w strumieniu audio obsługiwanym przez usługę AudioTrack. Aby uzyskać najnowszą dostępną sygnaturę czasową, utwórz instancję obiektu AudioTimestamp i przekaż go do getTimestamp(). Jeśli żądanie sygnatury czasowej się powiedzie, instancja AudioTrack zostanie uzupełniona o pozycję w jednostkach klatek razem z szacowanym czasem przedstawienia lub zatwierdzenia tej klatki.

Możesz użyć wartości nanoTime w AudioTimestamp (czyli monotonicznej), aby znaleźć najbliższą powiązaną klatkę wideo w porównaniu z framePosition. Dzięki temu możesz pomijać, powielać lub interpolować klatki wideo w celu dopasowania ich do dźwięku. Możesz też określić czas różnicy między wartością nanoTime a oczekiwanym czasem przyszłej klatki wideo (z uwzględnieniem częstotliwości próbkowania), aby przewidzieć, która klatka dźwiękowa powinna pojawić się w tym samym momencie co klatka wideo.

Czytnik obrazów płaszczyzn

Nowy interfejs API ImageReader zapewnia bezpośredni dostęp do buforów obrazów renderowanych w interfejsie Surface. ImageReader możesz uzyskać za pomocą metody statycznej newInstance(). Następnie wywołaj polecenie getSurface(), aby utworzyć nowy obiekt Surface i przesłać dane obrazu z pomocą producenta, takiego jak MediaPlayer lub MediaCodec. Aby otrzymywać powiadomienia, gdy na platformie pojawią się nowe obrazy, wdróż interfejs ImageReader.OnImageAvailableListener i zarejestruj go w usłudze setOnImageAvailableListener().

Teraz podczas rysowania treści na urządzeniu Surface ImageReader.OnImageAvailableListener otrzymuje wywołanie onImageAvailable(), gdy każda nowa ramka obrazu jest dostępna. Dzięki temu otrzymujesz odpowiedni ImageReader. Możesz użyć interfejsu ImageReader, aby pobrać dane obrazu ramki jako obiekt Image, wywołując acquireLatestImage() lub acquireNextImage().

Obiekt Image zapewnia bezpośredni dostęp do sygnatury czasowej, formatu, wymiarów i danych pikseli obrazu w elemencie ByteBuffer. Aby jednak klasa Image zinterpretowała obrazy, muszą one być sformatowane zgodnie z jednym z typów zdefiniowanych za pomocą stałych w polu ImageFormat lub PixelFormat.

Pomiar szczytu i wartości RMS

Możesz teraz wysyłać zapytania o wartości szczytowe i RMS bieżącego strumienia audio z usługi Visualizer. Aby to zrobić, utwórz nowe wystąpienie obiektu Visualizer.MeasurementPeakRms i przekaż go do usługi getMeasurementPeakRms(). Gdy wywołujesz tę metodę, wartości szczytowe i RMS danego obiektu Visualizer.MeasurementPeakRms są ustawiane na najnowsze zmierzone wartości.

Wzmacniacz głośności

LoudnessEnhancer to nowa podklasa języka AudioEffect, która pozwala zwiększyć głośność dźwięku urządzenia MediaPlayer lub AudioTrack. Może to być szczególnie przydatne w połączeniu z opisaną wcześniej nową metodą getMeasurementPeakRms(), gdy chcesz zwiększyć głośność czytanych ścieżek audio, gdy są odtwarzane inne multimedia.

Kontrolery zdalne

W Androidzie 4.0 (poziom interfejsu API 14) wprowadzono interfejsy API RemoteControlClient, które umożliwiają aplikacjom do multimediów korzystanie ze zdarzeń kontrolera multimediów z klientów zdalnych, takich jak sterowanie multimediami na ekranie blokady. Teraz dzięki nowym interfejsom API RemoteController możesz stworzyć własny zdalny kontroler, co pozwala na tworzenie innowacyjnych aplikacji i urządzeń peryferyjnych, które mogą sterować odtwarzaniem z dowolnych aplikacji do multimediów zintegrowanych z RemoteControlClient.

Aby utworzyć kontroler zdalny, możesz w dowolny sposób zaimplementować swój interfejs. Jednak aby przesyłać zdarzenia przycisku multimediów do aplikacji multimedialnej użytkownika, musisz utworzyć usługę, która rozszerza klasę NotificationListenerService i implementuje interfejs RemoteController.OnClientUpdateListener. Użycie parametru NotificationListenerService jako podstawy jest ważne, ponieważ zapewnia odpowiednie ograniczenia dotyczące prywatności. Zgodnie z nimi użytkownicy muszą włączyć Twoją aplikację jako detektor powiadomień w ustawieniach zabezpieczeń systemu.

Klasa NotificationListenerService zawiera kilka abstrakcyjnych metod, które musisz zaimplementować, ale jeśli interesuje Cię tylko obsługa odtwarzania multimediów przez zdarzenia kontrolera multimediów, możesz pozostawić implementację pustą i skupić się na metodach RemoteController.OnClientUpdateListener.

Oceny kontrolerów zdalnych

Android 4.4 uzupełnia istniejące możliwości klientów zdalnego sterowania (czyli aplikacji, które odbierają zdarzenia sterowania multimediami za pomocą interfejsu RemoteControlClient), dodając możliwość oceniania bieżącej ścieżki za pomocą kontrolera zdalnego.

Nowa klasa Rating zawiera informacje o ocenach użytkowników. Ocena jest określana przez styl oceny (RATING_HEART, RATING_THUMB_UP_DOWN, RATING_3_STARS, RATING_4_STARS, RATING_5_STARS lub RATING_PERCENTAGE) oraz wartość oceny odpowiednią dla danego stylu.

Aby umożliwić użytkownikom ocenianie utworów za pomocą kontrolera zdalnego:

Aby otrzymać wywołanie zwrotne, gdy użytkownik zmieni ocenę na kontrolerze zdalnym, zaimplementuj nowy interfejs RemoteControlClient.OnMetadataUpdateListener i przekaż instancję do setMetadataUpdateListener(). Gdy użytkownik zmieni ocenę, RemoteControlClient.OnMetadataUpdateListener otrzyma wywołanie do onMetadataUpdate(), przekazując RATING_KEY_BY_USER jako klucz i obiekt Rating jako wartość.

Napisy

Podczas odtwarzania filmów w ramach transmisji na żywo przez HTTP (HLS) VideoView obsługuje teraz ścieżki napisów WebVTT, które są wyświetlane zgodnie z ustawieniami napisów określonymi przez użytkownika w ustawieniach systemu.

Możesz też dodać VideoView do ścieżek napisów WebVTT za pomocą metody addSubtitleSource(). Ta metoda akceptuje obiekt InputStream, który przenosi dane napisów, oraz obiekt MediaFormat określający format danych napisów, który możesz określić za pomocą metody createSubtitleFormat(). Pojawią się one również nad filmem zgodnie z preferencjami użytkownika.

Jeśli nie używasz VideoView do wyświetlania treści wideo, zadbaj o to, aby nakładki napisów były jak najbardziej zgodne z preferencjami użytkownika. Nowy interfejs API CaptioningManager umożliwia wysyłanie zapytań dotyczących preferencji użytkownika dotyczących napisów, w tym stylów zdefiniowanych przez CaptioningManager.CaptionStyle, takich jak krój i kolor. Jeżeli użytkownik zmieni ustawienia już po rozpoczęciu odtwarzania filmu, zarejestruj wystąpienie CaptioningManager.CaptioningChangeListener, by otrzymać oddzwonienie po zmianie ustawień. W razie potrzeby zaktualizuj napisy.

Animacja i grafika

Sceny i przejścia

Nowa platforma android.transition udostępnia interfejsy API umożliwiające tworzenie animacji między różnymi stanami interfejsu. Najważniejszą cechą jest możliwość definiowania różnych stanów interfejsu (tzw. „scen”) przez utworzenie dla każdego z nich osobnego układu. Jeśli chcesz animować jedną scenę do drugiej, wykonaj „przejście”, które obliczy animację niezbędną do zmiany układu z bieżącej sceny do kolejnej.

Aby przejść między dwiema scenami, zwykle musisz wykonać te czynności:

  1. Określ ViewGroup zawierający komponenty interfejsu, które chcesz zmienić.
  2. Określ układ reprezentujący wynik końcowy zmiany (następna scena).
  3. Określ typ przejścia, które ma animować zmianę układu.
  4. Wykonaj przejście.

Do wykonania kroków 1 i 2 możesz użyć obiektu Scene. Element Scene zawiera metadane opisujące właściwości układu, które są niezbędne do wykonania przejścia, w tym widok nadrzędny sceny i układ sceny. Scene możesz utworzyć przy użyciu konstruktora klas lub metody statycznej getSceneForLayout().

Następnie musisz użyć narzędzia TransitionManager, aby wykonać kroki 3 i 4. Jednym ze sposobów jest przekazanie Scene do metody statycznej go(). Powoduje to znalezienie widoku nadrzędnego sceny w bieżącym układzie i wykonanie przejścia do widoków podrzędnych, aby osiągnąć układ zdefiniowany przez zasadę Scene.

Nie musisz też w ogóle tworzyć obiektu Scene. Zamiast tego możesz wywołać metodę beginDelayedTransition(), określając obiekt ViewGroup zawierający widoki, które chcesz zmienić. Następnie dodaj, usuń lub zmień konfigurację widoków docelowych. Gdy system odpowiednio zastosuje zmiany, rozpocznie się animowanie wszystkich widoków, których dotyczy zmiana.

Aby uzyskać dodatkową kontrolę, możesz zdefiniować zestawy przejść między wstępnie zdefiniowanymi scenami, używając pliku XML w katalogu res/transition/ projektu. W elemencie <transitionManager> określ co najmniej 1 tag <transition>, który określa scenę (odniesienie do pliku układu) oraz przejście, które ma być stosowane przy otwarciu lub zamknięciu sceny. Następnie powiększ ten zestaw przejść za pomocą funkcji inflateTransitionManager(). Użyj zwróconego TransitionManager, aby wykonać każde przejście z transitionTo(), przekazując wartość Scene reprezentowaną przez jeden z tagów <transition>. Zestawy przejść możesz też definiować automatycznie za pomocą interfejsów API TransitionManager.

Podczas określania przejścia możesz użyć kilku wstępnie zdefiniowanych typów zdefiniowanych przez podklasy Transition, takich jak Fade i ChangeBounds. Jeśli nie określisz typu przejścia, system domyślnie użyje elementu AutoTransition, który w razie potrzeby automatycznie zanika, przesuwa i zmienia rozmiar widoków. Możesz też tworzyć własne przejścia, rozszerzając dowolne z tych klas, aby można było wykonywać animacje w dowolny sposób. Przejście niestandardowe może śledzić dowolne zmiany właściwości i tworzyć dowolną animację wykorzystującą te zmiany. Możesz np. podać podklasę typu Transition, która wykrywa zmiany właściwości „rotacja” widoku, a potem animuje te zmiany.

Więcej informacji znajdziesz w dokumentacji TransitionManager.

Wstrzymywanie animatora

Interfejsy API Animator umożliwiają teraz wstrzymywanie i wznawianie trwającej animacji za pomocą metod pause() i resume().

Aby śledzić stan animacji, możesz zaimplementować interfejs Animator.AnimatorPauseListener, który udostępnia wywołania zwrotne w przypadku wstrzymania i wznawiania animacji: pause() i resume(). Następnie dodaj odbiornik do obiektu Animator za pomocą addPauseListener().

Możesz też utworzyć podklasę klasy abstrakcyjnej AnimatorListenerAdapter, która zawiera puste implementacje do wstrzymywania i wznawiania wywołań zwrotnych zdefiniowanych przez Animator.AnimatorPauseListener.

Mapy bitowe wielokrotnego użytku

Możesz teraz ponownie użyć dowolnej zmiennej bitmapy w BitmapFactory, aby zdekodować dowolną inną bitmapę – nawet wtedy, gdy nowa bitmapa ma inny rozmiar – o ile wynikowa liczba bajtów zdekodowanej bitmapy (dostępnej w getByteCount()) jest mniejsza od lub równa przydzielonej liczbie bajtów ponownie używanej mapy bitowej (dostępnej od getAllocationByteCount()). Więcej informacji: inBitmap.

Nowe interfejsy API dla: Bitmap umożliwiają podobną zmianę konfiguracji na potrzeby ponownego użycia poza BitmapFactory (na potrzeby ręcznego generowania map bitowych lub niestandardowego dekodowania). Możesz teraz ustawić wymiary bitmapy za pomocą metod setHeight() i setWidth() oraz określić nowy obiekt Bitmap.Config za pomocą parametru setConfig() bez wpływu na bazowy przydział bitmapy. Metoda reconfigure() także pozwala w wygodny sposób łączyć te zmiany w jednym wywołaniu.

Nie należy jednak zmieniać konfiguracji bitmapy, która jest obecnie używana przez system widoku, ponieważ bazowy bufor pikseli nie zostanie zmapowany w przewidywalny sposób.

Treści użytkowników

Platforma dostępu do pamięci

Jeśli chcesz, aby aplikacja pobierała określony typ pliku z innej aplikacji w poprzednich wersjach Androida, musi wywołać intencję z działaniem ACTION_GET_CONTENT. To działanie nadal jest odpowiednim sposobem na przesłanie prośby o plik, który chcesz zaimportować do aplikacji. Android 4.4 wprowadza jednak działanie ACTION_OPEN_DOCUMENT pozwalające użytkownikowi wybrać plik określonego typu i przyznać aplikacji długoterminowy dostęp do odczytu bez importowania pliku (prawdopodobnie z uprawnieniami do zapisu).

Jeśli tworzysz aplikację udostępniającą usługi przechowywania plików (np. usługę Cloud Save), możesz korzystać z tego ujednoliconego interfejsu do wybierania plików, implementując dostawcę treści jako podklasę nowej klasy DocumentsProvider. Twoja podklasa klasy DocumentsProvider musi zawierać filtr intencji, który akceptuje działanie PROVIDER_INTERFACE ("android.content.action.DOCUMENTS_PROVIDER"). Następnie musisz zaimplementować 4 metody abstrakcyjne w obiekcie DocumentsProvider:

queryRoots()
Musi ona zwrócić zadanie Cursor, które opisuje wszystkie katalogi główne miejsca na dokumenty przy użyciu kolumn zdefiniowanych w zasadzie DocumentsContract.Root.
queryChildDocuments()
To musi zwrócić Cursor opisujący wszystkie pliki w określonym katalogu z użyciem kolumn zdefiniowanych w katalogu DocumentsContract.Document.
queryDocument()
Musi ona zwracać element Cursor opisujący określony plik z użyciem kolumn zdefiniowanych w zasadzie DocumentsContract.Document.
openDocument()
Musi zwrócić parametr ParcelFileDescriptor reprezentujący określony plik. System wywołuje tę metodę, gdy użytkownik wybierze plik, a aplikacja kliencka poprosi o dostęp do niego, wywołując metodę openFileDescriptor().

Więcej informacji znajdziesz w przewodniku Storage Access Framework.

Dostęp do pamięci zewnętrznej

Teraz możesz odczytywać i zapisywać pliki związane z aplikacjami na dodatkowym nośniku zewnętrznym – na przykład wtedy, gdy urządzenie ma zarówno emulowaną pamięć masową, jak i kartę SD. Nowa metoda getExternalFilesDirs() działa tak samo jak dotychczasowa metoda getExternalFilesDir(), z tym że zwraca tablicę obiektów File. Przed odczytaniem lub zapisaniem w dowolnej ścieżce zwróconej przez tę metodę przekaż obiekt File do nowej metody getStorageState(), aby sprawdzić, czy pamięć jest obecnie dostępna.

Inne metody uzyskiwania dostępu do katalogu pamięci podręcznej i katalogu OBB także mają teraz odpowiednie wersje zapewniające dostęp do dodatkowych urządzeń pamięci masowej: odpowiednio getExternalCacheDirs() i getObbDirs().

Pierwszy wpis w zwróconej tablicy File jest uważany za podstawową pamięć zewnętrzną urządzenia, która jest taka sama jak wartość File zwracana przez istniejące metody, takie jak getExternalFilesDir().

Uwaga: od Androida 4.4 platforma nie wymaga już, aby aplikacja uzyskała WRITE_EXTERNAL_STORAGE lub READ_EXTERNAL_STORAGE, gdy potrzebujesz dostępu tylko do określonych dla aplikacji regionów pamięci zewnętrznej w sposób opisany powyżej. Te uprawnienia są jednak wymagane, jeśli chcesz korzystać z udostępnianych przez getExternalStoragePublicDirectory() regionów pamięci zewnętrznej.

Adaptery synchronizacji

Nowa metoda requestSync() w ContentResolver upraszcza niektóre procedury definiowania żądania synchronizacji dla ContentProvider przez umieszczanie żądań w nowym obiekcie SyncRequest, który można utworzyć za pomocą metody SyncRequest.Builder. Właściwości w SyncRequest zapewniają te same funkcje co dotychczasowe wywołania synchronizacji ContentProvider, ale dodają możliwość określenia, że synchronizacja ma zostać pominięta, jeśli sieć jest objęta pomiarem – wystarczy włączyć setDisallowMetered().

Dane wejściowe użytkownika

Nowe typy czujników

Nowy czujnik TYPE_GEOMAGNETIC_ROTATION_VECTOR dostarcza wektory obrotowe oparte na magnetometrze, który jest przydatną alternatywą dla czujnika TYPE_ROTATION_VECTOR, gdy żyroskop jest niedostępny lub gdy jest używany w połączeniu ze zbiorczymi zdarzeniami z czujnika do rejestrowania orientacji urządzenia, gdy telefon jest uśpiony. Ten czujnik zużywa mniej energii niż urządzenie TYPE_ROTATION_VECTOR, ale może być podatny na zakłócenia danych zdarzeń i działa najskuteczniej, gdy użytkownik znajduje się na zewnątrz.

Android obsługuje teraz też wbudowane sprzętowe czujniki kroków:

TYPE_STEP_DETECTOR
Ten czujnik wyzwala zdarzenie za każdym razem, gdy użytkownik robi krok. Po każdym kroku użytkownika czujnik wysyła zdarzenie o wartości 1,0 i sygnaturze czasowej wskazującej, kiedy miał on miejsce.
TYPE_STEP_COUNTER
Ten czujnik również wywołuje zdarzenie po każdym wykrytym kroku, ale zamiast tego przekazuje łączną liczbę kroków od momentu zarejestrowania czujnika przez aplikację.

Pamiętaj, że te dwa czujniki krokowe nie zawsze dają takie same wyniki. Zdarzenia TYPE_STEP_COUNTER występują z większym opóźnieniem niż w przypadku zdarzeń TYPE_STEP_DETECTOR, ale wynika to z faktu, że algorytm TYPE_STEP_COUNTER przeprowadza więcej przetwarzania, aby wyeliminować wyniki fałszywie pozytywne. Dlatego wywołanie zdarzenia TYPE_STEP_COUNTER może trwać dłużej, ale jego wyniki powinny być dokładniejsze.

Oba czujniki krokowe są zależne od sprzętu (Nexus 5 jest pierwszym urządzeniem, które je obsługuje), więc sprawdź dostępność za pomocą hasSystemFeature(), używając stałych FEATURE_SENSOR_STEP_DETECTOR i FEATURE_SENSOR_STEP_COUNTER.

Zbiorcze zdarzenia z czujników

Aby lepiej zarządzać zasilaniem urządzenia, interfejsy API SensorManager pozwalają teraz określać częstotliwość, z jaką system ma przesyłać do aplikacji partie zdarzeń z czujników. Nie zmniejsza to liczby rzeczywistych zdarzeń związanych z czujnikami dostępnych dla aplikacji w danym okresie, ale zmniejsza częstotliwość, z jaką system wywołuje metodę SensorEventListener, przeprowadzając aktualizacje czujnika. Oznacza to, że zamiast przesyłać do aplikacji każde zdarzenie od razu, gdy następują, system zapisuje wszystkie zdarzenia, które wystąpiły w danym okresie, a potem wysyła je do aplikacji naraz.

W celu umożliwienia grupowania klasa SensorManager dodaje 2 nowe wersje metody registerListener(), które umożliwiają określenie „maksymalnego czasu oczekiwania na odpowiedź na raport”. Ten nowy parametr określa maksymalne opóźnienie, jakie SensorEventListener będzie tolerować w przypadku dostarczania nowych zdarzeń związanych z czujnikiem. Jeśli na przykład określisz opóźnienie wsadu wynoszące 1 minutę, system będzie dostarczać ostatni zestaw zdarzeń zbiorczych w przedziale nie dłuższym niż 1 minutę, wykonując kolejne wywołania metody onSensorChanged() – raz dla każdego zdarzenia w grupie. Zdarzenia związane z czujnikami nigdy nie będą opóźnione dłużej niż wartość maksymalnego opóźnienia raportu, ale mogą nastąpić wcześniej, jeśli inne aplikacje zażądały krótszego opóźnienia dla tego samego czujnika.

Pamiętaj jednak, że czujnik dostarczy aplikacji zdarzenia grupowe na podstawie opóźnienia raportu tylko wtedy, gdy procesor jest aktywny. Chociaż czujnik sprzętowy obsługujący grupy, będzie nadal zbierać zdarzenia z czujników, gdy procesor jest uśpiony, nie wybudzi procesora w celu dostarczenia aplikacji zdarzeń zbiorczych. Gdy w pamięci czujnika zabraknie pamięci, czujnik zacznie pomijać najstarsze zdarzenia, aby zapisać najnowsze. Aby uniknąć utraty zdarzeń, wybudź urządzenie, zanim czujnik wypełni pamięć, a następnie wywołaj flush(), aby przechwycić najnowszą grupę zdarzeń. Aby oszacować, kiedy pamięć będzie zapełniona i powinien zostać opróżniona, wywołaj funkcję getFifoMaxEventCount(), aby uzyskać maksymalną liczbę zdarzeń z czujników, które może zapisać, i podziel tę liczbę przez szybkość, z jaką aplikacja ma żądać każdego zdarzenia. Użyj tych obliczeń, aby ustawić alarmy pobudki za pomocą funkcji AlarmManager, które wywołują metodę Service (która implementuje funkcję SensorEventListener) w celu opróżnienia czujnika.

Uwaga: nie wszystkie urządzenia obsługują grupowe zdarzenia z czujnika, ponieważ wymaga to obsługi czujnika sprzętowego. Jednak od Androida 4.4 należy zawsze używać nowych metod registerListener(), ponieważ jeśli urządzenie nie obsługuje grupowania, system płynnie ignoruje argument opóźnienia wsadu i dostarcza zdarzenia z czujników w czasie rzeczywistym.

Tożsamości kontrolera

Android identyfikuje teraz każdy połączony kontroler za pomocą unikalnej liczby całkowitej, do której można wysłać zapytanie za pomocą getControllerNumber(). Ułatwia to powiązanie każdego kontrolera z innym graczem w grze. Liczba każdego kontrolera może się zmienić w zależności od tego, czy użytkownik odłącza, podłączy lub ponownie skonfiguruje kontrolery, dlatego warto śledzić numer kontrolera InputManager.InputDeviceListener, aby śledzić, który numer kontrolera odpowiada poszczególnym urządzeniom wejściowym. Następnie wywołaj getControllerNumber() dla każdego elementu InputDevice, gdy zajdzie zmiana.

Połączone urządzenia zawierają też identyfikatory usług i dostawców, które są dostępne z getProductId() i getVendorId(). Jeśli musisz zmienić mapowania klawiszy na podstawie zestawu kluczy dostępnego na urządzeniu, możesz wysłać do urządzenia zapytanie, aby sprawdzić, czy w usłudze hasKeys(int...) dostępne są określone klucze.

Interfejs

Pojemny tryb pełnoekranowy

Aby aplikacja miała układ, który wypełnia cały ekran, nowa flaga SYSTEM_UI_FLAG_IMMERSIVE dla setSystemUiVisibility() (w połączeniu z SYSTEM_UI_FLAG_HIDE_NAVIGATION) włącza nowy pełny tryb pełnoekranowy. Po włączeniu trybu pełnoekranowego Twoja aktywność nadal będzie otrzymywać wszystkie zdarzenia dotyku. Użytkownik może odsłonić paski systemowe, przesuwając palcem do wewnątrz w obszarze, w którym normalnie pojawiają się paski systemu. Ta opcja usuwa flagę SYSTEM_UI_FLAG_HIDE_NAVIGATION (i flagę SYSTEM_UI_FLAG_FULLSCREEN, jeśli została zastosowana), dzięki czemu paski systemowe pozostają widoczne. Jeśli jednak chcesz, by paski systemowe były ponownie ukryte po kilku chwilach, możesz użyć flagi SYSTEM_UI_FLAG_IMMERSIVE_STICKY.

Przezroczyste paski systemowe

Dzięki nowym motywom Theme.Holo.NoActionBar.TranslucentDecor i Theme.Holo.Light.NoActionBar.TranslucentDecor paski systemu mogą być teraz częściowo półprzezroczyste. Gdy włączysz półprzezroczyste paski systemowe, układ wypełni obszar za paskami systemowymi. Musisz też włączyć fitsSystemWindows w tej części układu, która nie powinna być zasłonięta przez paski systemowe.

Jeśli tworzysz motyw niestandardowy, ustaw jeden z tych motywów jako motyw nadrzędny lub dodaj do niego właściwości stylu windowTranslucentNavigation i windowTranslucentStatus.

Ulepszony detektor powiadomień

Do Androida 4.3 dodano interfejsy API NotificationListenerService, które umożliwiają aplikacjom otrzymywanie informacji o nowych powiadomieniach w miarę ich publikowania przez system. W Androidzie 4.4 detektory powiadomień mogą pobierać dodatkowe metadane powiadomienia i uzupełniać szczegóły jego działań:

Nowe pole Notification.extras zawiera pole Bundle, które umożliwia przesyłanie do kreatora powiadomień dodatkowych metadanych, takich jak EXTRA_TITLE i EXTRA_PICTURE. Nowa klasa Notification.Action definiuje parametry działania dołączonego do powiadomienia. Dane te można pobrać za pomocą nowego pola actions.

rysowalne odbicia lustrzane w układach RTL,

Jeśli w poprzednich wersjach Androida aplikacja zawiera obrazy, które powinny odwrócić ich orientację poziomą w przypadku układów od prawej do lewej, obraz lustrzany należy dodać do katalogu zasobów drawables-ldrtl/. Teraz system może automatycznie powielać obrazy, włączając atrybut autoMirrored w zasobie rysowalnym lub wywołując metodę setAutoMirrored(). Po włączeniu tej opcji element Drawable jest automatycznie powielany, gdy kierunek układu to od prawej do lewej.

Ułatwienia dostępu

Klasa View umożliwia teraz zadeklarowanie „aktywnych regionów” w przypadku tych części interfejsu, które dynamicznie aktualizują się o nową zawartość tekstową przez dodanie nowego atrybutu accessibilityLiveRegion do układu XML lub wywołanie setAccessibilityLiveRegion(). Na przykład ekran logowania z polem tekstowym, które wyświetla powiadomienie o nieprawidłowym haśle, powinien być oznaczony jako aktywny, aby czytnik ekranu odczytał wiadomość po zmianie.

Aplikacje udostępniające usługę ułatwień dostępu mogą teraz wzbogacić swoje możliwości o nowe interfejsy API, które udostępniają informacje o kolekcjach widoków, takich jak widoki listy lub siatki za pomocą AccessibilityNodeInfo.CollectionInfo i AccessibilityNodeInfo.CollectionItemInfo.

Uprawnienia aplikacji

Oto nowe uprawnienia, o które Twoja aplikacja musi poprosić za pomocą tagu <uses-permission>, aby móc korzystać z nowych interfejsów API:

INSTALL_SHORTCUT
Pozwala aplikacji na zainstalowanie skrótu w Menu z aplikacjami
UNINSTALL_SHORTCUT
Umożliwia aplikacji odinstalowanie skrótu w Menu z aplikacjami
TRANSMIT_IR
Zezwala aplikacji na używanie nadajnika podczerwieni urządzenia, jeśli jest dostępny

Uwaga: od Androida 4.4 platforma nie wymaga już, aby aplikacja uzyskała WRITE_EXTERNAL_STORAGE lub READ_EXTERNAL_STORAGE, gdy chcesz uzyskać dostęp do określonych dla aplikacji regionów pamięci zewnętrznej przy użyciu metod takich jak getExternalFilesDir(). Te uprawnienia są jednak wymagane, jeśli chcesz korzystać z udostępnianych przez getExternalStoragePublicDirectory() regionów pamięci zewnętrznej.

Funkcje urządzenia

Oto nowe funkcje urządzenia, które możesz zadeklarować za pomocą tagu <uses-feature>, aby określić wymagania aplikacji oraz włączyć filtrowanie w Google Play lub sprawdzać w czasie działania:

FEATURE_CONSUMER_IR
Urządzenie może komunikować się z konsumenckimi urządzeniami IR.
FEATURE_DEVICE_ADMIN
Urządzenie obsługuje egzekwowanie zasad dotyczących urządzeń przez administratorów urządzeń.
FEATURE_NFC_HOST_CARD_EMULATION
Urządzenie obsługuje emulację karty NFC na serwerze hosta.
FEATURE_SENSOR_STEP_COUNTER
Urządzenie zawiera sprzętowy licznik kroków.
FEATURE_SENSOR_STEP_DETECTOR
Urządzenie zawiera sprzętowy detektor kroków.

Szczegółowe informacje o wszystkich zmianach w interfejsach API w Androidzie 4.4 znajdziesz w raporcie o różnicach w interfejsach API.