API-интерфейсы Android 4.4

Уровень API: 19

Android 4.4 ( KITKAT ) — это новая версия платформы Android, предлагающая новые функции для пользователей и разработчиков приложений. Этот документ представляет собой введение в наиболее известные новые API.

Как разработчик приложения, вам следует как можно скорее загрузить образ системы Android 4.4 и платформу SDK из диспетчера SDK . Если у вас нет устройства под управлением Android 4.4, на котором можно протестировать приложение, используйте образ системы Android 4.4, чтобы протестировать приложение на эмуляторе Android . Затем создайте свои приложения для платформы Android 4.4, чтобы начать использовать новейшие API.

Обновите целевой уровень API

Чтобы лучше оптимизировать свое приложение для устройств под управлением Android 4.4, вам следует установить для targetSdkVersion значение "19" , установить его в образ системы Android 4.4, протестировать его, а затем опубликовать обновление с этим изменением.

Вы можете использовать API в Android 4.4, одновременно поддерживая более старые версии, добавив в код условия, которые проверяют уровень системного API перед выполнением API, не поддерживаемых вашим minSdkVersion . Чтобы узнать больше о обеспечении обратной совместимости, прочтите раздел «Поддержка различных версий платформы» .

Дополнительные сведения о том, как работают уровни API, см. в статье Что такое уровень API?

Важные изменения в поведении

Если вы ранее публиковали приложение для Android, имейте в виду, что на ваше приложение могут повлиять изменения в Android 4.4.

Если ваше приложение читает из внешнего хранилища...

Ваше приложение не может читать общие файлы во внешнем хранилище при работе на Android 4.4, если у вашего приложения нет разрешения READ_EXTERNAL_STORAGE . То есть файлы в каталоге, возвращенном методом getExternalStoragePublicDirectory() больше не доступны без разрешения. Однако если вам нужен доступ только к каталогам вашего приложения, предоставленным getExternalFilesDir() , вам не нужно разрешение READ_EXTERNAL_STORAGE .

Если ваше приложение использует WebView...

Ваше приложение может вести себя по-другому при работе на Android 4.4, особенно если вы обновите targetSdkVersion вашего приложения до «19» или выше.

Код, лежащий в основе класса WebView и связанных с ним API, был обновлен и основан на современном снимке исходного кода Chromium. Это обеспечивает множество улучшений производительности, поддержку новых функций HTML5 и поддержку удаленной отладки содержимого WebView . Объем этого обновления означает, что если ваше приложение использует WebView , в некоторых случаях это может повлиять на его поведение. Хотя известные изменения поведения документированы и в основном влияют на ваше приложение только тогда, когда вы обновляете targetSdkVersion вашего приложения до «19» или выше — новый WebView работает в «режиме совместимости», чтобы обеспечить некоторые устаревшие функции в приложениях, ориентированных на уровень API 18 и ниже — это возможно, ваше приложение зависит от неизвестного поведения из предыдущей версии WebView .

Поэтому, если ваше существующее приложение использует WebView , важно как можно скорее протестировать его на Android 4.4 и обратиться к разделу Миграция на WebView в Android 4.4 для получения информации о том, как на ваше приложение может повлиять обновление targetSdkVersion до «19» или выше.

Если ваше приложение использует AlarmManager...

Если вы установите targetSdkVersion вашего приложения значение «19» или выше, сигналы тревоги, создаваемые вами с помощью set() или setRepeating() будут неточными.

Чтобы повысить энергоэффективность, Android теперь объединяет сигналы тревоги от всех приложений, которые возникают в примерно одинаковое время, поэтому система пробуждает устройство один раз, а не несколько раз, для обработки каждого сигнала тревоги.

Если ваш будильник не связан с точным временем на часах, но по-прежнему важно, чтобы ваш будильник вызывался в течение определенного периода времени (например, между 14:00 и 16:00), тогда вы можете использовать новый метод setWindow() , который принимает " самое раннее» время подачи сигнала тревоги и «окно» времени, следующее за самым ранним временем, в течение которого система должна активировать сигнал тревоги.

Если ваш будильник должен быть привязан к точному времени (например, для напоминания о событии календаря), вы можете использовать новый метод setExact() .

Такое неточное поведение пакетной обработки применимо только к обновленным приложениям. Если вы установили targetSdkVersion на «18» или ниже, ваши сигналы тревоги будут продолжать вести себя так же, как и в предыдущих версиях, при работе на Android 4.4.

Если ваше приложение синхронизирует данные с помощью ContentResolver...

Если вы установите targetSdkVersion вашего приложения значение «19» или выше, создание синхронизации с помощью addPeriodicSync() будет выполнять ваши операции синхронизации в пределах гибкого интервала по умолчанию, составляющего примерно 4 % от указанного вами периода. Например, если частота опроса составляет 24 часа, то операция синхронизации может выполняться примерно в течение одного часа каждый день, а не в одно и то же время каждый день.

Чтобы указать собственный гибкий интервал для операций синхронизации, вам следует начать использовать новый метод requestSync() . Более подробную информацию см. в разделе об адаптерах синхронизации ниже.

Такое поведение гибкого интервала применяется только к обновленным приложениям. Если вы установили для targetSdkVersion значение «18» или ниже, существующие запросы синхронизации будут продолжать вести себя так же, как и в предыдущих версиях при работе на Android 4.4.

Печать Рамок

Android теперь включает в себя полноценную платформу, которая позволяет пользователям распечатывать любые документы с помощью принтера, подключенного через Wi-Fi, Bluetooth или другие службы. Система обрабатывает транзакцию между приложением, которое хочет распечатать документ, и службами, доставляющими задания на печать на принтер. Платформа android.print предоставляет все API, необходимые для указания документа для печати и доставки его в систему для печати. Какие API-интерфейсы вам действительно нужны для конкретного задания на печать, зависит от вашего контента.

Печать общего контента

Если вы хотите распечатать содержимое своего пользовательского интерфейса в виде документа, вам необходимо сначала создать подкласс PrintDocumentAdapter . В этом классе вы должны реализовать несколько методов обратного вызова, включая onLayout() для создания макета на основе предоставленных свойств печати и onWrite() для сериализации содержимого, пригодного для печати, в ParcelFileDescriptor .

Чтобы записать контент в ParcelFileDescriptor вы должны передать ему PDF-файл. Новые API-интерфейсы PdfDocument предлагают удобный способ сделать это, предоставляя Canvas из getCanvas() , на котором вы можете рисовать содержимое для печати. Затем запишите PdfDocument в ParcelFileDescriptor используя метод writeTo() .

После того как вы определили реализацию PrintDocumentAdapter , вы можете выполнять задания печати по запросу пользователя с помощью метода PrintManager print() , который принимает PrintDocumentAdapter в качестве одного из своих аргументов.

Печать изображений

Если вы хотите распечатать только фотографию или другое растровое изображение, то вспомогательные API в библиотеке поддержки сделают всю работу за вас. Просто создайте новый экземпляр PrintHelper , установите режим масштабирования с помощью setScaleMode() , затем передайте Bitmap в printBitmap() . Вот и все. Библиотека выполняет все остальное взаимодействие с системой для доставки растрового изображения на принтер.

Создание полиграфических услуг

Как производитель принтеров, вы можете использовать платформу android.printservice для обеспечения совместимости ваших принтеров с устройствами Android. Вы можете создавать и распространять службы печати в виде APK-файлов, которые пользователи могут устанавливать на свои устройства. Приложение службы печати работает в основном как автономная служба, являясь подклассом класса PrintService , который получает задания на печать из системы и передает задания на свои принтеры с использованием соответствующих протоколов.

Дополнительные сведения о том, как распечатать содержимое приложения, см. в разделе Печать содержимого .

СМС-провайдер

Поставщик контента Telephony («Поставщик SMS») позволяет приложениям читать и записывать SMS- и MMS-сообщения на устройстве. Он включает таблицы для полученных, составленных, отправленных, ожидающих SMS- и MMS-сообщений и т. д.

Начиная с Android 4.4, системные настройки позволяют пользователям выбирать «приложение для SMS по умолчанию». После выбора только приложение SMS по умолчанию сможет писать поставщику SMS, и только приложение SMS по умолчанию получает широковещательную рассылку SMS_DELIVER_ACTION , когда пользователь получает SMS, или широковещательную рассылку WAP_PUSH_DELIVER_ACTION , когда пользователь получает MMS. Приложение SMS по умолчанию отвечает за запись данных поставщику SMS при получении или отправке нового сообщения.

Другие приложения, которые не выбраны в качестве приложения SMS по умолчанию, могут только читать поставщика SMS, но также могут получать уведомления о прибытии нового SMS, прослушивая широковещательную рассылку SMS_RECEIVED_ACTION , которая представляет собой непрекращаемую широковещательную рассылку, которая может быть доставлена ​​нескольким приложениям. Эта рассылка предназначена для приложений, которым, хотя они и не выбраны в качестве приложения SMS по умолчанию, необходимо читать специальные входящие сообщения, например, для проверки номера телефона.

Для получения дополнительной информации прочитайте публикацию в блоге « Подготовка ваших SMS-приложений к KitKat» .

Беспроводная связь и подключение

Эмуляция хост-карты

Приложения Android теперь могут эмулировать NFC-карты ISO14443-4 (ISO-DEP), которые используют APDU для обмена данными (как указано в ISO7816-4). Это позволяет устройству с поддержкой NFC под управлением Android 4.4 одновременно эмулировать несколько карт NFC, а также позволяет платежному терминалу NFC или другому считывателю NFC инициировать транзакцию с соответствующей картой NFC на основе идентификатора приложения (AID).

Если вы хотите эмулировать в своем приложении карту NFC, использующую эти протоколы, создайте компонент службы на основе класса HostApduService . Принимая во внимание, что если вместо этого ваше приложение использует безопасный элемент для эмуляции карты, вам необходимо создать службу на основе класса OffHostApduService , который не будет напрямую участвовать в транзакциях, но необходим для регистрации AID, которые должны обрабатываться безопасным элементом.

Для получения дополнительной информации прочтите руководство по эмуляции NFC-карты .

Режим чтения NFC

Новый режим чтения NFC позволяет действию ограничивать всю активность NFC чтением только тех типов тегов, которые интересуют действие, находясь на переднем плане. Вы можете включить режим чтения для своей активности с помощью enableReaderMode() , предоставляя реализацию NfcAdapter.ReaderCallback , которая получает обратный вызов при обнаружении новых тегов.

Эта новая возможность в сочетании с эмуляцией хост-карты позволяет Android работать на обоих концах интерфейса мобильных платежей: одно устройство работает как платежный терминал (устройство, работающее в режиме считывания), а другое устройство работает как платежный клиент (устройство, работающее в режиме считывания). устройство, эмулирующее карту NFC).

Инфракрасные передатчики

При работе на устройстве, оснащенном инфракрасным (ИК) передатчиком, теперь вы можете передавать ИК-сигналы с помощью API-интерфейсов ConsumerIrManager . Чтобы получить экземпляр ConsumerIrManager , вызовите getSystemService() с CONSUMER_IR_SERVICE в качестве аргумента. Затем вы можете запросить поддерживаемые устройством ИК-частоты с помощью getCarrierFrequencies() и передать сигналы, передав желаемую частоту и шаблон сигнала с помощью transmit() .

Вы всегда должны сначала проверить, имеет ли устройство ИК-передатчик, вызвав hasIrEmitter() , но если ваше приложение совместимо только с устройствами, у которых он есть, вам следует включить элемент <uses-feature> в свой манифест для "android.hardware.consumerir" ( FEATURE_CONSUMER_IR ).

Мультимедиа

Адаптивное воспроизведение

Поддержка адаптивного воспроизведения видео теперь доступна с помощью API-интерфейсов MediaCodec , что обеспечивает плавное изменение разрешения во время воспроизведения на Surface — вы можете подавать входные кадры декодера с новым разрешением, и разрешение выходных буферов изменится без значительного разрыва.

Вы можете включить адаптивное воспроизведение, добавив в MediaFormat два ключа, которые определяют максимальное разрешение, которое ваше приложение требует от кодека: KEY_MAX_WIDTH и KEY_MAX_HEIGHT . Добавив их в свой MediaFormat , передайте MediaFormat в экземпляр MediaCodec с помощью configure() .

Кодек плавно переключается между разрешениями, которые равны или меньше этих значений. Кодек также может поддерживать разрешения, превышающие указанные максимальные значения (при условии, что они находятся в пределах поддерживаемых профилей), но переход к более высоким разрешениям может не быть плавным.

Чтобы изменить разрешение при декодировании видео H.264, продолжайте ставить кадры в очередь с помощью MediaCodec.queueInputBuffer(), но убедитесь, что вы предоставили новые значения набора параметров последовательности (SPS) и набора параметров изображения (PPS) вместе с мгновенным обновлением декодера. (IDR) кадр в одном буфере.

Однако прежде чем пытаться настроить кодек для адаптивного воспроизведения, необходимо убедиться, что устройство поддерживает адаптивное воспроизведение, вызвав isFeatureSupported(String) с FEATURE_AdaptivePlayback .

Примечание. Поддержка адаптивного воспроизведения зависит от поставщика. Некоторым кодекам может потребоваться больше памяти для подсказок большего разрешения. Поэтому вам следует установить максимальное разрешение в зависимости от исходного материала, который вы декодируете.

Временные метки аудио по требованию

Чтобы облегчить синхронизацию аудио-видео, новый класс AudioTimestamp предоставляет сведения о временной шкале для определенного «кадра» в аудиопотоке, обрабатываемом AudioTrack . Чтобы получить самую последнюю доступную временную метку, создайте экземпляр объекта AudioTimestamp и передайте его в getTimestamp() . Если запрос метки времени успешен, экземпляр AudioTrack заполняется позицией в единицах кадра, а также расчетным временем, когда этот кадр был представлен или был зафиксирован для представления.

Вы можете использовать значение nanoTime в AudioTimestamp (который является монотонным), чтобы найти ближайший связанный видеокадр по сравнению с framePosition , чтобы вы могли удалять, дублировать или интерполировать видеокадры в соответствии со звуком. Альтернативно, вы можете определить разницу времени между значением nanoTime и ожидаемым временем будущего видеокадра (с учетом частоты дискретизации), чтобы предсказать, какой аудиокадр ожидается в тот же момент, что и видеокадр.

Считыватель изображений поверхности

Новый API ImageReader предоставляет вам прямой доступ к буферам изображений при их рендеринге в Surface . Вы можете получить ImageReader с помощью статического метода newInstance() . Затем вызовите getSurface() чтобы создать новую Surface и доставить данные изображения с помощью такого производителя, как MediaPlayer или MediaCodec . Чтобы получать уведомления о появлении новых изображений с поверхности, реализуйте интерфейс ImageReader.OnImageAvailableListener и зарегистрируйте его с помощью setOnImageAvailableListener() .

Теперь, когда вы рисуете контент на Surface , ваш ImageReader.OnImageAvailableListener получает вызов onImageAvailable() , когда каждый новый кадр изображения становится доступным, предоставляя вам соответствующий ImageReader . Вы можете использовать ImageReader для получения данных изображения кадра в виде объекта Image , вызвав acquireLatestImage() acquireNextImage() .

Объект Image обеспечивает прямой доступ к метке времени, формату, размерам и пиксельным данным изображения в ByteBuffer . Однако, чтобы класс Image мог интерпретировать ваши изображения, они должны быть отформатированы в соответствии с одним из типов, определенных константами в ImageFormat или PixelFormat .

Измерение пиковых и среднеквадратичных значений

Теперь вы можете запросить пиковое и среднеквадратичное значение текущего аудиопотока из Visualizer , создав новый экземпляр Visualizer.MeasurementPeakRms и передав его в getMeasurementPeakRms() . При вызове этого метода пиковые и среднеквадратические значения данного Visualizer.MeasurementPeakRms устанавливаются в соответствии с последними измеренными значениями.

Усилитель громкости

LoudnessEnhancer — это новый подкласс AudioEffect , который позволяет увеличивать громкость звука вашего MediaPlayer или AudioTrack . Это может быть особенно полезно в сочетании с новым методом getMeasurementPeakRms() , упомянутым выше, чтобы увеличить громкость произносимых звуковых дорожек во время воспроизведения другого мультимедиа.

Пульты дистанционного управления

В Android 4.0 (уровень API 14) появились API-интерфейсы RemoteControlClient , которые позволяют мультимедийным приложениям использовать события медиа-контроллера от удаленных клиентов, например элементы управления мультимедиа на экране блокировки. Теперь новые API-интерфейсы RemoteController позволяют вам создавать собственный пульт дистанционного управления, что позволяет создавать новые инновационные приложения и периферийные устройства, которые могут управлять воспроизведением любого мультимедийного приложения, интегрируемого с RemoteControlClient .

Чтобы создать удаленный контроллер, вы можете реализовать свой пользовательский интерфейс любым способом, но для доставки событий мультимедийных кнопок в мультимедийное приложение пользователя вы должны создать службу, которая расширяет класс NotificationListenerService и реализует интерфейс RemoteController.OnClientUpdateListener . Использование NotificationListenerService в качестве основы важно, поскольку оно обеспечивает соответствующие ограничения конфиденциальности, которые требуют от пользователей включить ваше приложение в качестве прослушивателя уведомлений в настройках безопасности системы.

Класс NotificationListenerService включает в себя пару абстрактных методов, которые необходимо реализовать, но если вас интересуют только события медиа-контроллера для обработки воспроизведения мультимедиа, вы можете оставить свою реализацию для них пустой и вместо этого сосредоточиться на методах RemoteController.OnClientUpdateListener .

Рейтинги пультов дистанционного управления

Android 4.4 основывается на существующих возможностях клиентов удаленного управления (приложений, которые получают события управления мультимедиа с помощью RemoteControlClient ), добавляя пользователям возможность оценивать текущую дорожку с удаленного контроллера.

Новый класс Rating инкапсулирует информацию о рейтинге пользователя. Рейтинг определяется его стилем оценки ( RATING_HEART , RATING_THUMB_UP_DOWN , RATING_3_STARS , RATING_4_STARS , RATING_5_STARS или RATING_PERCENTAGE ) и значением рейтинга, соответствующим этому стилю.

Чтобы разрешить пользователям оценивать ваши треки с пульта дистанционного управления:

Чтобы получить обратный вызов, когда пользователь меняет рейтинг с удаленного контроллера, реализуйте новый интерфейс RemoteControlClient.OnMetadataUpdateListener и передайте экземпляр в setMetadataUpdateListener() . Когда пользователь меняет рейтинг, ваш RemoteControlClient.OnMetadataUpdateListener получает вызов onMetadataUpdate() , передавая RATING_KEY_BY_USER в качестве ключа и объект Rating в качестве значения.

Субтитры

VideoView теперь поддерживает дорожки субтитров WebVTT при воспроизведении видео HTTP Live Stream (HLS), отображая дорожку субтитров в соответствии с настройками скрытых субтитров, которые пользователь определил в настройках системы.

Вы также можете предоставить VideoView дорожки субтитров WebVTT, используя метод addSubtitleSource() . Этот метод принимает InputStream , содержащий данные субтитров, и объект MediaFormat , определяющий формат данных субтитров, который можно указать с помощью createSubtitleFormat() . Эти субтитры также появляются поверх видео в соответствии с предпочтениями пользователя.

Если вы не используете VideoView для отображения видеоконтента, вам следует сделать так, чтобы наложение субтитров максимально соответствовало предпочтениям пользователя в отношении скрытых субтитров. Новый API CaptioningManager позволяет запрашивать настройки скрытых субтитров пользователя, включая стили, определенные CaptioningManager.CaptionStyle , такие как шрифт и цвет. Если пользователь изменяет некоторые настройки после того, как ваше видео уже началось, вам следует прослушивать изменения в настройках, зарегистрировав экземпляр CaptioningManager.CaptioningChangeListener , чтобы получать обратный вызов при изменении каких-либо предпочтений, а затем обновлять субтитры по мере необходимости.

Анимация и графика

Сцены и переходы

Новая платформа android.transition предоставляет API, которые облегчают анимацию между различными состояниями вашего пользовательского интерфейса. Ключевой особенностью является возможность определять отдельные состояния вашего пользовательского интерфейса, известные как «сцены», создавая для каждого отдельный макет. Если вы хотите перейти от одной сцены к другой, выполните «переход», который вычисляет необходимую анимацию для изменения макета текущей сцены на следующую.

Для перехода между двумя сценами обычно необходимо выполнить следующее:

  1. Укажите ViewGroup содержащую компоненты пользовательского интерфейса, которые вы хотите изменить.
  2. Укажите макет, представляющий конечный результат изменения (следующую сцену).
  3. Укажите тип перехода, который должен анимировать изменение макета.
  4. Выполните переход.

Вы можете использовать объект Scene для выполнения шагов 1 и 2. Scene содержит метаданные, описывающие свойства макета, необходимые для выполнения перехода, включая родительское представление сцены и макет сцены. Вы можете создать Scene используя конструктор класса или статический метод getSceneForLayout() .

Затем вы должны использовать TransitionManager для выполнения шагов 3 и 4. Один из способов — передать Scene статическому методу go() . Это находит родительское представление сцены в текущем макете и выполняет переход к дочерним представлениям, чтобы достичь макета, определенного Scene .

В качестве альтернативы вам вообще не нужно создавать объект Scene , а вместо этого можно вызвать beginDelayedTransition() , указав ViewGroup , содержащую представления, которые вы хотите изменить. Затем добавьте, удалите или перенастройте целевые представления. После того, как система вносит необходимые изменения, переход начинает анимировать все затронутые виды.

Для дополнительного контроля вы можете определить наборы переходов, которые должны происходить между заранее определенными сценами, используя XML-файл в каталоге res/transition/ вашего проекта. Внутри элемента <transitionManager> укажите один или несколько тегов <transition> , каждый из которых определяет сцену (ссылку на файл макета) и переход, который будет применяться при входе в эту сцену и/или выходе из нее. Затем раздуйте этот набор переходов с помощью inflateTransitionManager() . Используйте возвращенный TransitionManager для выполнения каждого перехода с transitionTo() , передавая Scene , представленную одним из тегов <transition> . Вы также можете определять наборы переходов программно с помощью API TransitionManager .

При указании перехода вы можете использовать несколько предопределенных типов, определенных подклассами Transition , таких как Fade и ChangeBounds . Если вы не укажете тип перехода, система по умолчанию использует AutoTransition , который автоматически плавно затухает, перемещается и изменяет размеры изображений по мере необходимости. Кроме того, вы можете создавать собственные переходы, расширяя любой из этих классов для выполнения анимации по своему усмотрению. Пользовательский переход может отслеживать любые изменения свойств и создавать любую анимацию на основе этих изменений. Например, вы можете предоставить подкласс Transition , который прослушивает изменения свойства «поворот» представления, а затем анимирует любые изменения.

Дополнительные сведения см. в документации TransitionManager .

Аниматор делает паузу

API-интерфейсы Animator теперь позволяют приостанавливать и возобновлять текущую анимацию с помощью методов pause() и resume() .

Чтобы отслеживать состояние анимации, вы можете реализовать интерфейс Animator.AnimatorPauseListener , который обеспечивает обратные вызовы при приостановке и возобновлении анимации: pause() и resume() . Затем добавьте прослушиватель к объекту Animator с помощью addPauseListener() .

В качестве альтернативы вы можете создать подкласс абстрактного класса AnimatorListenerAdapter , который теперь включает пустые реализации для обратных вызовов паузы и возобновления, определенных Animator.AnimatorPauseListener .

Многоразовые растровые изображения

Теперь вы можете повторно использовать любое изменяемое растровое изображение в BitmapFactory для декодирования любого другого растрового изображения — даже если новое растровое изображение имеет другой размер — при условии, что результирующее количество байтов декодированного растрового изображения (доступное из getByteCount() ) меньше или равно к количеству выделенных байтов повторно используемого растрового изображения (доступно из getAllocationByteCount() . Для получения дополнительной информации см. inBitmap .

Новые API для Bitmap позволяют аналогичную реконфигурацию для повторного использования за пределами BitmapFactory (для ручной генерации растровых изображений или пользовательской логики декодирования). Теперь вы можете установить размеры растрового изображения с помощью методов setHeight() и setWidth() и указать новый Bitmap.Config с помощью setConfig() не затрагивая базовое распределение растрового изображения. Метод reconfigure() также предоставляет удобный способ объединить эти изменения одним вызовом.

Однако не следует перенастраивать растровое изображение, которое в настоящее время используется системой представления, поскольку базовый буфер пикселей не будет переназначен предсказуемым образом.

Пользовательский контент

Платформа доступа к хранилищу

В предыдущих версиях Android, если вы хотите, чтобы ваше приложение получало файл определенного типа из другого приложения, оно должно было вызвать намерение с помощью действия ACTION_GET_CONTENT . Это действие по-прежнему является подходящим способом запроса файла, который вы хотите импортировать в свое приложение. Однако в Android 4.4 появилось действие ACTION_OPEN_DOCUMENT , которое позволяет пользователю выбрать файл определенного типа и предоставить вашему приложению долгосрочный доступ для чтения к этому файлу (возможно, с доступом для записи) без импорта файла в ваше приложение.

Если вы разрабатываете приложение, предоставляющее услуги хранения файлов (например, службу сохранения в облаке), вы можете участвовать в этом едином пользовательском интерфейсе для выбора файлов, реализовав поставщика контента в качестве подкласса нового класса DocumentsProvider . Ваш подкласс DocumentsProvider должен включать фильтр намерений, который принимает действие PROVIDER_INTERFACE ( "android.content.action.DOCUMENTS_PROVIDER" ). Затем вы должны реализовать четыре абстрактных метода в DocumentsProvider :

queryRoots()
Это должно возвращать Cursor , который описывает все корневые каталоги вашего хранилища документов, используя столбцы, определенные в DocumentsContract.Root .
queryChildDocuments()
Это должно возвращать Cursor , который описывает все файлы в указанном каталоге, используя столбцы, определенные в DocumentsContract.Document .
queryDocument()
Он должен возвращать Cursor , который описывает указанный файл, используя столбцы, определенные в DocumentsContract.Document .
openDocument()
Он должен возвращать ParcelFileDescriptor представляющий указанный файл. Система вызывает этот метод, когда пользователь выбирает файл, и клиентское приложение запрашивает доступ к нему, вызывая openFileDescriptor() .

Дополнительные сведения см. в руководстве Storage Access Framework .

Доступ к внешнему хранилищу

Теперь вы можете читать и записывать файлы, специфичные для приложения, на вторичном внешнем носителе, например, когда устройство предоставляет как эмулируемое хранилище, так и SD-карту. Новый метод getExternalFilesDirs() работает так же, как существующий метод getExternalFilesDir() за исключением того, что он возвращает массив объектов File . Прежде чем читать или записывать любой из путей, возвращаемых этим методом, передайте объект File новому методу getStorageState() , чтобы убедиться, что хранилище доступно в данный момент.

Другие методы доступа к каталогу кэша вашего приложения и каталогу OBB теперь также имеют соответствующие версии, обеспечивающие доступ к дополнительным устройствам хранения: getExternalCacheDirs() и getObbDirs() соответственно.

Первая запись в возвращаемом массиве File считается основным внешним хранилищем устройства, которое совпадает с File , возвращаемым существующими методами, такими как getExternalFilesDir() .

Примечание. Начиная с Android 4.4, платформа больше не требует, чтобы ваше приложение получало WRITE_EXTERNAL_STORAGE или READ_EXTERNAL_STORAGE когда вам нужно получить доступ только к специфичным для вашего приложения областям внешнего хранилища, используя описанные выше методы. Однако разрешения необходимы, если вы хотите получить доступ к общим областям внешнего хранилища, предоставляемым getExternalStoragePublicDirectory() .

Адаптеры синхронизации

Новый метод requestSync() в ContentResolver упрощает некоторые процедуры определения запроса синхронизации для вашего ContentProvider путем инкапсуляции запросов в новый объект SyncRequest , который вы можете создать с помощью SyncRequest.Builder . Свойства в SyncRequest предоставляют ту же функциональность, что и существующие вызовы синхронизации ContentProvider , но добавляют возможность указать, что синхронизация должна быть прекращена, если сеть измеряется, путем включения setDisallowMetered() .

Пользовательский ввод

Новые типы датчиков

Новый датчик TYPE_GEOMAGNETIC_ROTATION_VECTOR предоставляет данные вектора вращения на основе магнитометра, что является полезной альтернативой датчику TYPE_ROTATION_VECTOR , когда гироскоп недоступен или когда он используется с пакетными событиями датчика для записи ориентации устройства, пока телефон находится в спящем режиме. Этот датчик требует меньше энергии, чем TYPE_ROTATION_VECTOR , но может быть подвержен зашумленным данным о событиях и наиболее эффективен, когда пользователь находится на открытом воздухе.

Android также теперь поддерживает аппаратные встроенные датчики шагов:

TYPE_STEP_DETECTOR
Этот датчик запускает событие каждый раз, когда пользователь делает шаг. При каждом шаге пользователя этот датчик выдает событие со значением 1,0 и меткой времени, указывающей, когда произошел этот шаг.
TYPE_STEP_COUNTER
Этот датчик также запускает событие при каждом обнаруженном шаге, но вместо этого передает общее накопленное количество шагов, поскольку этот датчик был впервые зарегистрирован приложением.

Имейте в виду, что эти два датчика шагов не всегда дают одинаковые результаты. События TYPE_STEP_COUNTER происходят с более высокой задержкой, чем события TYPE_STEP_DETECTOR , но это потому, что алгоритм TYPE_STEP_COUNTER выполняет больше обработки для устранения ложных срабатываний. Таким образом, TYPE_STEP_COUNTER может медленнее доставлять события, но его результаты должны быть более точными.

Оба датчика шагов зависят от оборудования (Nexus 5 — первое устройство, поддерживающее их), поэтому вам следует проверить доступность с помощью hasSystemFeature() , используя константы FEATURE_SENSOR_STEP_DETECTOR и FEATURE_SENSOR_STEP_COUNTER .

Пакетные события датчиков

Чтобы лучше управлять питанием устройства, API-интерфейсы SensorManager теперь позволяют вам указать частоту, с которой вы хотите, чтобы система доставляла пакеты событий датчиков в ваше приложение. Это не уменьшает количество фактических событий датчиков, доступных вашему приложению за определенный период времени, но вместо этого уменьшает частоту, с которой система вызывает ваш SensorEventListener с обновлениями датчиков. То есть вместо того, чтобы доставлять каждое событие в ваше приложение в момент его возникновения, система сохраняет все события, произошедшие за определенный период времени, а затем доставляет их в ваше приложение все сразу.

Для обеспечения пакетной обработки класс SensorManager добавляет две новые версии метода registerListener() , которые позволяют указать «максимальную задержку отчета». Этот новый параметр определяет максимальную задержку, которую ваш SensorEventListener будет допускать для доставки новых событий датчика. Например, если вы укажете задержку пакета в одну минуту, система будет доставлять последний набор пакетных событий с интервалом не более одной минуты, выполняя последовательные вызовы вашего метода onSensorChanged() — один раз для каждого пакетного события. События датчика никогда не будут задерживаться дольше, чем максимальное значение задержки отчета, но могут поступать раньше, если другие приложения запросили меньшую задержку для того же датчика.

Однако имейте в виду, что датчик будет доставлять вашему приложению пакетные события на основе задержки вашего отчета только тогда, когда процессор активен . Хотя аппаратный датчик, поддерживающий пакетную обработку, будет продолжать собирать события датчиков, пока ЦП находится в спящем режиме, он не будет будить ЦП для доставки пакетных событий вашему приложению. Когда у датчика в конечном итоге заканчивается память для событий, он начинает удалять самые старые события, чтобы сохранить самые новые события. Вы можете избежать потери событий, выведя устройство из спящего режима до того, как датчик заполнит его память, а затем вызвать flush() , чтобы захватить последнюю порцию событий. Чтобы оценить, когда память будет заполнена и ее следует очистить, вызовите getFifoMaxEventCount() , чтобы получить максимальное количество событий датчиков, которые он может сохранить, и разделите это число на скорость, с которой ваше приложение желает получить каждое событие. Используйте этот вычисление, чтобы установить тревоги с тревожностью с помощью AlarmManager , который вызывает вашу Service (которая реализует SensorEventListener ), чтобы промыть датчик.

Примечание: не все устройства поддерживают события пакетирования датчиков, потому что это требует поддержки с помощью аппаратного датчика. Тем не менее, начиная с Android 4.4, вы всегда должны использовать новые методы registerListener() , потому что, если устройство не поддерживает партии, то система изящно игнорирует аргумент пакетной задержки и обеспечивает события датчиков в режиме реального времени.

Контроллер идентичности

Теперь Android идентифицирует каждый подключенный контроллер с уникальным целым числом, которое вы можете запросить с помощью getControllerNumber() , что облегчает вам связывать каждого контроллера с другим игроком в игре. Номер для каждого контроллера может измениться из-за отключения, подключенных контроллеров, подключений или повторного сфигурации пользователем, поэтому вы должны отслеживать, какой номер контроллера соответствует каждому устройству ввода, зарегистрировав экземпляр InputManager.InputDeviceListener . Затем вызовите getControllerNumber() для каждого InputDevice , когда происходит изменение.

Подключенные устройства также теперь предоставляют идентификаторы продукта и поставщиков, которые доступны от getProductId() и getVendorId() . Если вам нужно изменить свои счета клавиш на основе доступного набора клавиш на устройстве, вы можете запросить устройство, чтобы проверить, доступны ли определенные ключи с hasKeys(int...) .

Пользовательский интерфейс

Погруженный полноэкранный режим

Чтобы предоставить ваше приложение с макетом, который заполняет весь экран, новый флаг SYSTEM_UI_FLAG_IMMERSIVE для setSystemUiVisibility() (в сочетании с SYSTEM_UI_FLAG_HIDE_NAVIGATION ) позволяет новым захватывающим полноэкранированным режимом. В то время как иммерсивный полноэкранный режим включен, ваша активность продолжает получать все события прикосновения. Пользователь может раскрыть системные стержни с внутренним промахом вдоль региона, где обычно появляются системы. Это очищает флаг SYSTEM_UI_FLAG_HIDE_NAVIGATION (и флаг SYSTEM_UI_FLAG_FULLSCREEN , если применяется), поэтому системы системы остаются видимыми. Однако, если вы хотите, чтобы системы системной стержни снова были спрятаться через несколько мгновений, вы можете вместо этого использовать флаг SYSTEM_UI_FLAG_IMMERSIVE_STICKY .

Полупрозрачные системы

Теперь вы можете сделать системные стержни частично полупрозрачными с новыми темами, Theme.Holo.NoActionBar.TranslucentDecor и Theme.Holo.Light.NoActionBar.TranslucentDecor . Включив полупрозрачные планки системы, ваш макет заполнит область за системными стержнями, поэтому вы также должны включить fitsSystemWindows для части вашего макета, которая не должна быть покрыта системными стержнями.

Если вы создаете индивидуальную тему, установите одну из этих тем в качестве родительской темы или включите в свою тему свойства windowTranslucentNavigation и windowTranslucentStatus .

Увеличенное слушатель уведомлений

Android 4.3 добавил API NotificationListenerService , позволяя приложениям получать информацию о новых уведомлениях, как они публикуются в системе. В Android 4.4 слушатели уведомлений могут получить дополнительные метаданные для уведомления и полных сведений о действиях уведомления:

Новое поле Notification.extras включает в себя Bundle для доставки дополнительных метаданных уведомлений, таких как EXTRA_TITLE и EXTRA_PICTURE . Новый класс Notification.Action Акция определяет характеристики действия, прикрепленного к уведомлению, которое вы можете получить из поля «Новые actions .

Возможность рисования зеркального отображения для макетов RTL

В предыдущих версиях Android, если ваше приложение включает в себя изображения, которые должны обратить вспять их горизонтальную ориентацию для макетов правого налегания, вы должны включить зеркальное изображение в каталог drawables-ldrtl/ ресурсов. Теперь система может автоматически отражать изображения для вас, включив атрибут autoMirrored в ресурсе Drawable или вызовом setAutoMirrored() . При включении, Drawable автоматически отражается, когда направление макета прямо налево.

Доступность

Класс View теперь позволяет вам объявлять «живые регионы» для участков вашего пользовательского интерфейса, которые динамически обновляются с новым текстовым контентом, добавив новый атрибут accessibilityLiveRegion к вашему макету XML или вызову setAccessibilityLiveRegion() . Например, экран входа с текстовым полем, в котором отображается уведомление «Неправильный пароль», должен быть помечен как живой регион, поэтому считыватель экрана будет повторять сообщение при его изменении.

Приложения, которые предоставляют услугу доступности, теперь могут также расширить свои возможности с помощью новых API, которые предоставляют информацию о сборах просмотров, таких как виды List или Grid с использованием AccessibilityNodeInfo.CollectionInfo и AccessibilityNodeInfo.CollectionItemInfo .

Разрешения приложения

Ниже приведены новые разрешения, которые ваше приложение должно запросить с помощью тега <uses-permission> для использования определенных новых API:

INSTALL_SHORTCUT
Позволяет приложению установить ярлык в пусковой установке
UNINSTALL_SHORTCUT
Позволяет приложению удалить ярлык в пусковой установке
TRANSMIT_IR
Позволяет приложению использовать ИК -передатчик устройства, если доступно

ПРИМЕЧАНИЕ. Начиная с Android 4.4, платформа больше не требует, чтобы ваше приложение получило WRITE_EXTERNAL_STORAGE или READ_EXTERNAL_STORAGE когда вы хотите получить доступ к вашим приложениям областей внешней хранилища, используя такие методы, как getExternalFilesDir() . Тем не менее, разрешения все еще требуются, если вы хотите получить доступ к совместным регионам внешней памяти, предоставленные getExternalStoragePublicDirectory() .

Особенности устройства

Ниже приведены новые функции устройства, которые вы можете объявить с помощью тега <uses-feature> , чтобы объявить требования вашего приложения и включить фильтрацию в Google Play или проверить для выполнения:

FEATURE_CONSUMER_IR
Устройство способно общаться с потребительскими ИК -устройствами.
FEATURE_DEVICE_ADMIN
Устройство поддерживает обеспечение соблюдения политики устройства с помощью администраторов устройств.
FEATURE_NFC_HOST_CARD_EMULATION
Устройство поддерживает эмуляцию карт NFC на основе хоста.
FEATURE_SENSOR_STEP_COUNTER
Устройство включает в себя аппаратный счетчик.
FEATURE_SENSOR_STEP_DETECTOR
Устройство включает в себя аппаратный детектор.

Подробное представление о всех изменениях API в Android 4.4 см. В отчете API Differences .