API Android 4.3

Уровень API: 18

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

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

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

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

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

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

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

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

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

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

Ваше приложение может работать неправильно в среде с ограниченным профилем.

Пользователям в среде с ограниченным профилем могут быть недоступны все стандартные приложения Android. Например, в профиле с ограниченным доступом могут быть отключены веб-браузер и приложение камеры. Поэтому вашему приложению не следует делать предположения о том, какие приложения доступны, потому что если вы вызываете startActivity() без проверки, доступно ли приложение для обработки Intent , ваше приложение может аварийно завершить работу в профиле с ограниченным доступом.

При использовании неявного намерения всегда следует проверять, доступно ли приложение для обработки намерения, вызываяsolveActivity resolveActivity() или queryIntentActivities() . Например:

Котлин

val intent = Intent(Intent.ACTION_SEND)
...
if (intent.resolveActivity(packageManager) != null) {
    startActivity(intent)
} else {
    Toast.makeText(context, R.string.app_not_available, Toast.LENGTH_LONG).show()
}

Ява

Intent intent = new Intent(Intent.ACTION_SEND);
...
if (intent.resolveActivity(getPackageManager()) != null) {
    startActivity(intent);
} else {
    Toast.makeText(context, R.string.app_not_available, Toast.LENGTH_LONG).show();
}

Если ваше приложение зависит от учетных записей...

Ваше приложение может работать неправильно в среде с ограниченным профилем.

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

Если вы хотите полностью запретить профилям с ограниченным доступом использовать ваше приложение, поскольку ваше приложение зависит от конфиденциальной информации об учетной записи, укажите атрибут android:requiredAccountType в элементе <application> вашего манифеста.

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

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

Ваше видео может выглядеть меньше на Android 4.3.

В предыдущих версиях Android виджет VideoView неправильно рассчитывал значение "wrap_content" для layout_height и layout_width , совпадающее со "match_parent" . Таким образом, хотя использование "wrap_content" для высоты или ширины могло ранее обеспечить желаемый макет видео, это может привести к гораздо меньшему размеру видео на Android 4.3 и более поздних версиях. Чтобы устранить эту проблему, замените "wrap_content" на "match_parent" и убедитесь, что ваше видео отображается должным образом на Android 4.3, а также на более старых версиях.

Ограниченные профили

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

Пользовательский интерфейс, позволяющий пользователям управлять созданными вами ограничениями, управляется системным приложением «Настройки». Чтобы настройки ограничений вашего приложения были видны пользователю, вы должны объявить ограничения, предоставляемые вашим приложением, создав BroadcastReceiver , который получает намерение ACTION_GET_RESTRICTION_ENTRIES . Система вызывает это намерение, чтобы запросить все приложения на наличие доступных ограничений, а затем создает пользовательский интерфейс, позволяющий основному пользователю управлять ограничениями для каждого ограниченного профиля.

В методе onReceive() вашего BroadcastReceiver вы должны создать RestrictionEntry для каждого ограничения, предоставляемого вашим приложением. Каждый RestrictionEntry определяет заголовок ограничения, описание и один из следующих типов данных:

  • TYPE_BOOLEAN для ограничения, которое имеет значение true или false.
  • TYPE_CHOICE для ограничения, которое имеет несколько взаимоисключающих вариантов (выбор переключателя).
  • TYPE_MULTI_SELECT для ограничения, которое имеет несколько вариантов, которые не являются взаимоисключающими (выбор флажков).

Затем вы помещаете все объекты RestrictionEntry в ArrayList и помещаете его в результат приемника широковещательной передачи в качестве значения дополнительного параметра EXTRA_RESTRICTIONS_LIST .

Система создает пользовательский интерфейс для ограничений вашего приложения в приложении «Настройки» и сохраняет каждое ограничение с помощью уникального ключа, который вы предоставили для каждого объекта RestrictionEntry . Когда пользователь открывает ваше приложение, вы можете запросить любые текущие ограничения, вызвав getApplicationRestrictions() . Это возвращает Bundle , содержащий пары ключ-значение для каждого ограничения, которое вы определили с помощью объектов RestrictionEntry .

Если вы хотите предоставить более конкретные ограничения, которые не могут быть обработаны логическими значениями, значениями с одним выбором или несколькими вариантами выбора, вы можете создать действие, в котором пользователь может указать ограничения и разрешить пользователям открывать это действие из настроек ограничения. . В своем приемнике вещания включите дополнительный EXTRA_RESTRICTIONS_INTENT в результат Bundle . В этом дополнении должно быть указано Intent , указывающее класс Activity , который нужно запустить (используйте метод putParcelable() для передачи EXTRA_RESTRICTIONS_INTENT с намерением). Когда основной пользователь входит в вашу активность для установки пользовательских ограничений, ваша активность затем должна вернуть результат, содержащий значения ограничений в дополнительном виде, используя ключ EXTRA_RESTRICTIONS_LIST или EXTRA_RESTRICTIONS_BUNDLE , в зависимости от того, указываете ли вы объекты RestrictionEntry или пары ключ-значение соответственно.

Поддержка аккаунтов в профиле с ограниченным доступом

Любые учетные записи, добавленные к основному пользователю, доступны для профиля с ограниченным доступом, но по умолчанию эти учетные записи недоступны из API AccountManager . Если вы попытаетесь добавить учетную запись с помощью AccountManager , находясь в профиле с ограниченным доступом, вы получите неудачный результат. Из-за этих ограничений у вас есть следующие три варианта:

  • Разрешить доступ к учетным записям владельца из профиля с ограниченным доступом.

    Чтобы получить доступ к аккаунту из профиля с ограниченным доступом, необходимо добавить атрибут android:restrictedAccountType в тег <application> :

    <application ...
        android:restrictedAccountType="com.example.account.type" >

    Внимание: включение этого атрибута предоставляет вашему приложению доступ к учетным записям основного пользователя из профилей с ограниченным доступом. Поэтому вам следует разрешить это только в том случае, если информация, отображаемая вашим приложением, не раскрывает личную информацию (PII), которая считается конфиденциальной. Системные настройки сообщат основному пользователю, что ваше приложение предоставляет ограниченные профили его учетным записям, поэтому пользователю должно быть ясно, что доступ к учетной записи важен для функциональности вашего приложения. Если возможно, вам также следует предоставить адекватные элементы управления ограничениями для основного пользователя, которые определяют, какой объем доступа к учетной записи разрешен в вашем приложении.

  • Отключите определенные функции, если невозможно изменить учетные записи.

    Если вы хотите использовать учетные записи, но на самом деле они вам не нужны для основных функций вашего приложения, вы можете проверить доступность учетной записи и отключить функции, если они недоступны. Сначала вам следует проверить, доступна ли существующая учетная запись. Если нет, то запросите, можно ли создать новую учетную запись, вызвав getUserRestrictions() , и проверьте дополнительный DISALLOW_MODIFY_ACCOUNTS в результате. Если это true , вам следует отключить все функции вашего приложения, требующие доступа к учетным записям. Например:

    Котлин

    val um = context.getSystemService(Context.USER_SERVICE) as UserManager
    val restrictions: Bundle = um.userRestrictions
    if (restrictions.getBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS, false)) {
        // cannot add accounts, disable some functionality
    }

    Ява

    UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
    Bundle restrictions = um.getUserRestrictions();
    if (restrictions.getBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS, false)) {
        // cannot add accounts, disable some functionality
    }

    Примечание. В этом сценарии не следует объявлять какие-либо новые атрибуты в файле манифеста.

  • Отключите приложение, если не можете получить доступ к личным учетным записям.

    Если вместо этого важно, чтобы ваше приложение было недоступно для профилей с ограниченным доступом, поскольку ваше приложение зависит от конфиденциальной личной информации в учетной записи (и поскольку профили с ограниченным доступом в настоящее время не могут добавлять новые учетные записи), добавьте атрибут android:requiredAccountType в тег <application> :

    <application ...
        android:requiredAccountType="com.example.account.type" >

    Например, приложение Gmail использует этот атрибут для отключения профилей с ограниченным доступом, поскольку личный адрес электронной почты владельца не должен быть доступен профилям с ограниченным доступом.

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

    Bluetooth с низким энергопотреблением (Smart Ready)

    Android теперь поддерживает Bluetooth Low Energy (LE) с новыми API в android.bluetooth . С помощью новых API вы можете создавать приложения для Android, которые взаимодействуют с периферийными устройствами Bluetooth с низким энергопотреблением, такими как пульсометры и шагомеры.

    Поскольку Bluetooth LE — это аппаратная функция, доступная не на всех устройствах под управлением Android, вы должны объявить в файле манифеста элемент <uses-feature> для "android.hardware.bluetooth_le" :

    <uses-feature android:name="android.hardware.bluetooth_le" android:required="true" />

    Если вы уже знакомы с классическими API-интерфейсами Bluetooth Android, обратите внимание, что использование API-интерфейсов Bluetooth LE имеет некоторые различия. Самое главное, что теперь есть класс BluetoothManager , который вы должны использовать для некоторых операций высокого уровня, таких как получение BluetoothAdapter , получение списка подключенных устройств и проверка состояния устройства. Например, вот как теперь вам следует получить BluetoothAdapter :

    Котлин

    val bluetoothManager = getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
    bluetoothAdapter = bluetoothManager.adapter

    Ява

    final BluetoothManager bluetoothManager =
            (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
    bluetoothAdapter = bluetoothManager.getAdapter();

    Чтобы обнаружить периферийные устройства Bluetooth LE, вызовите startLeScan() в BluetoothAdapter , передав ему реализацию интерфейса BluetoothAdapter.LeScanCallback . Когда адаптер Bluetooth обнаруживает периферийное устройство Bluetooth LE, ваша реализация BluetoothAdapter.LeScanCallback получает вызов метода onLeScan() . Этот метод предоставляет объект BluetoothDevice , представляющий обнаруженное устройство, значение RSSI для устройства и массив байтов, содержащий рекламную запись устройства.

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

    Примечание. Вы можете сканировать только устройства Bluetooth LE или классические устройства Bluetooth, используя предыдущие API. Вы не можете одновременно сканировать устройства Bluetooth LE и Classic.

    Чтобы затем подключиться к периферийному устройству Bluetooth LE, вызовите connectGatt() для соответствующего объекта BluetoothDevice , передав ему реализацию BluetoothGattCallback . Ваша реализация BluetoothGattCallback получает обратные вызовы относительно состояния подключения к устройству и других событий. Именно во время обратного вызова onConnectionStateChange() вы можете начать связь с устройством, если метод передает STATE_CONNECTED в качестве нового состояния.

    Для доступа к функциям Bluetooth на устройстве также необходимо, чтобы ваше приложение запрашивало определенные разрешения пользователя Bluetooth. Дополнительную информацию см. в руководстве по Bluetooth Low Energy API.

    Режим только сканирования Wi-Fi

    При попытке определить местоположение пользователя Android может использовать Wi-Fi, чтобы определить местоположение, сканируя близлежащие точки доступа. Однако пользователи часто отключают Wi-Fi для экономии заряда батареи, в результате чего данные о местоположении становятся менее точными. Android теперь включает режим только сканирования, который позволяет устройству Wi-Fi сканировать точки доступа, чтобы определить местоположение без подключения к точке доступа, что значительно снижает расход заряда батареи.

    Если вы хотите узнать местоположение пользователя, но Wi-Fi в настоящее время отключен, вы можете попросить пользователя включить режим только сканирования Wi-Fi, вызвав startActivity() с действием ACTION_REQUEST_SCAN_ALWAYS_AVAILABLE .

    Конфигурация Wi-Fi

    Новые API-интерфейсы WifiEnterpriseConfig позволяют корпоративным сервисам автоматизировать настройку Wi-Fi для управляемых устройств.

    Быстрый ответ на входящие звонки

    Начиная с Android 4.0, функция «Быстрый ответ» позволяет пользователям отвечать на входящие вызовы немедленным текстовым сообщением без необходимости отвечать на звонок или разблокировать устройство. До сих пор эти быстрые сообщения всегда обрабатывались приложением обмена сообщениями по умолчанию. Теперь любое приложение может заявить о своей способности обрабатывать эти сообщения, создав Service с фильтром намерений для ACTION_RESPOND_VIA_MESSAGE .

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

    Чтобы получить это намерение, вы должны объявить разрешение SEND_RESPOND_VIA_MESSAGE .

    Мультимедиа

    Улучшения MediaExtractor и MediaCodec

    Android теперь упрощает написание собственных проигрывателей динамической адаптивной потоковой передачи через HTTP (DASH) в соответствии со стандартом ISO/IEC 23009-1, используя существующие API в MediaCodec и MediaExtractor . Платформа, лежащая в основе этих API, была обновлена ​​для поддержки анализа фрагментированных файлов MP4, но ваше приложение по-прежнему отвечает за анализ метаданных MPD и передачу отдельных потоков в MediaExtractor .

    Если вы хотите использовать DASH с зашифрованным содержимым, обратите внимание, что метод getSampleCryptoInfo() возвращает метаданные MediaCodec.CryptoInfo , описывающие структуру каждого зашифрованного образца мультимедиа. Кроме того, в MediaExtractor был добавлен метод getPsshInfo() , благодаря которому вы можете получить доступ к метаданным PSSH для ваших медиафайлов DASH. Этот метод возвращает карту объектов UUID в байты, при этом UUID определяет криптосхему, а байты представляют собой данные, специфичные для этой схемы.

    Медиа DRM

    Новый класс MediaDrm предоставляет модульное решение для управления цифровыми правами (DRM) на ваш медиаконтент, отделяя проблемы DRM от воспроизведения мультимедиа. Например, такое разделение API позволяет воспроизводить контент, зашифрованный Widevine, без необходимости использования медиаформата Widevine. Это решение DRM также поддерживает общее шифрование DASH, поэтому вы можете использовать различные схемы DRM для потокового контента.

    Вы можете использовать MediaDrm для получения непрозрачных сообщений с запросом ключа и обработки сообщений с ответом на ключ с сервера для получения и предоставления лицензии. Ваше приложение отвечает за сетевое взаимодействие с серверами; класс MediaDrm предоставляет только возможность генерировать и обрабатывать сообщения.

    API-интерфейсы MediaDrm предназначены для использования в сочетании с API-интерфейсами MediaCodec , которые были представлены в Android 4.1 (уровень API 16), включая MediaCodec для кодирования и декодирования вашего контента, MediaCrypto для обработки зашифрованного контента и MediaExtractor для извлечения и демультиплексирования вашего контента.

    Сначала необходимо создать объекты MediaExtractor и MediaCodec . Затем вы можете получить доступ к UUID , идентифицирующему схему DRM, обычно из метаданных в контенте, и использовать его для создания экземпляра объекта MediaDrm с его конструктором.

    Кодирование видео с Surface

    В Android 4.1 (уровень API 16) добавлен класс MediaCodec для низкоуровневого кодирования и декодирования медиаконтента. При кодировании видео Android 4.1 требовал, чтобы вы предоставили мультимедиа массиву ByteBuffer , но Android 4.3 теперь позволяет использовать Surface в качестве входных данных для кодировщика. Например, это позволяет вам кодировать входные данные из существующего видеофайла или использовать кадры, созданные из OpenGL ES.

    Чтобы использовать Surface в качестве входных данных для вашего кодера, сначала вызовите configure() для вашего MediaCodec . Затем вызовите createInputSurface() , чтобы получить Surface , на которую вы можете транслировать свои медиафайлы.

    Например, вы можете использовать данную Surface в качестве окна для контекста OpenGL, передав ее в eglCreateWindowSurface() . Затем во время рендеринга поверхности вызовите eglSwapBuffers() чтобы передать кадр в MediaCodec .

    Чтобы начать кодирование, вызовите start() в MediaCodec . Когда закончите, вызовите signalEndOfInputStream() , чтобы завершить кодирование, и вызовите release() на Surface .

    Медиа-мультиплексирование

    Новый класс MediaMuxer обеспечивает мультиплексирование между одним аудиопотоком и одним видеопотоком. Эти API служат аналогом класса MediaExtractor , добавленного в Android 4.2 для демультиплексирования (демультиплексирования) мультимедиа.

    Поддерживаемые форматы вывода определены в MediaMuxer.OutputFormat . В настоящее время MP4 является единственным поддерживаемым форматом вывода, а MediaMuxer в настоящее время поддерживает только один аудиопоток и/или один видеопоток одновременно.

    MediaMuxer в основном предназначен для работы с MediaCodec , поэтому вы можете выполнять обработку видео с помощью MediaCodec а затем сохранять выходные данные в файл MP4 с помощью MediaMuxer . Вы также можете использовать MediaMuxer в сочетании с MediaExtractor для редактирования мультимедиа без необходимости кодирования или декодирования.

    Ход воспроизведения и очистка для RemoteControlClient

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

    Во-первых, вы должны включить флаг FLAG_KEY_MEDIA_POSITION_UPDATE , передав его в setTransportControlsFlags() .

    Затем реализуйте следующие два новых интерфейса:

    RemoteControlClient.OnGetPlaybackPositionListener
    Сюда входит обратный вызов onGetPlaybackPosition() , который запрашивает текущую позицию вашего медиафайла, когда пульту дистанционного управления необходимо обновить прогресс в своем пользовательском интерфейсе.
    RemoteControlClient.OnPlaybackPositionUpdateListener
    Сюда входит обратный вызов onPlaybackPositionUpdate() , который сообщает вашему приложению новый временной код для вашего мультимедиа, когда пользователь очищает воспроизведение с помощью пользовательского интерфейса удаленного управления.

    Как только вы обновите воспроизведение новой позицией, вызовите setPlaybackState() чтобы указать новое состояние, положение и скорость воспроизведения.

    Определив эти интерфейсы, вы можете установить их для вашего RemoteControlClient , вызвав setOnGetPlaybackPositionListener() и setPlaybackPositionUpdateListener() соответственно.

    Графика

    Поддержка OpenGL ES 3.0.

    В Android 4.3 добавлены интерфейсы Java и встроенная поддержка OpenGL ES 3.0. Ключевые новые функции, представленные в OpenGL ES 3.0, включают в себя:

    • Ускорение продвинутых визуальных эффектов
    • Высококачественное сжатие текстур ETC2/EAC в стандартной комплектации.
    • Новая версия языка шейдеров GLSL ES с поддержкой целых чисел и 32-битных чисел с плавающей запятой.
    • Расширенный рендеринг текстур
    • Более широкая стандартизация размера текстур и форматов буфера рендеринга.

    Интерфейс Java для OpenGL ES 3.0 на Android предоставляется вместе с GLES30 . При использовании OpenGL ES 3.0 обязательно объявите его в файле манифеста с помощью тега <uses-feature> и атрибута android:glEsVersion . Например:

    <manifest>
        <uses-feature android:glEsVersion="0x00030000" />
        ...
    </manifest>

    И не забудьте указать контекст OpenGL ES, вызвав setEGLContextClientVersion() , передав 3 в качестве версии.

    Дополнительные сведения об использовании OpenGL ES, в том числе о том, как проверить поддерживаемую устройством версию OpenGL ES во время выполнения, см. в руководстве по OpenGL ES API.

    Мипмэппинг для чертежей

    Использование MIP-карты в качестве источника растрового изображения или объекта рисования — это простой способ обеспечить качественное изображение и различные масштабы изображения, что может быть особенно полезно, если вы ожидаете, что ваше изображение будет масштабироваться во время анимации.

    В Android 4.2 (уровень API 17) добавлена ​​поддержка MIP-изображений в классе Bitmap : Android меняет местами MIP-изображения в вашем Bitmap когда вы предоставили источник MIP-карты и включили setHasMipMap() . Теперь в Android 4.3 вы также можете включить MIP-карты для объекта BitmapDrawable , предоставив ресурс MIP-карты и установив атрибут android:mipMap в файле ресурсов растрового изображения или вызвав hasMipMap() .

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

    Просмотр наложений

    Новый класс ViewOverlay предоставляет прозрачный слой поверх View , в который можно добавлять визуальный контент и который не влияет на иерархию макета. Вы можете получить ViewOverlay для любого View , вызвав getOverlay() . Наложение всегда имеет тот же размер и положение, что и его основное представление (представление, из которого оно было создано), что позволяет добавлять контент, который появляется перед главным представлением, но не может расширять границы этого основного представления.

    Использование ViewOverlay особенно полезно, когда вы хотите создать анимацию, например, выдвижение представления за пределы его контейнера или перемещение элементов по экрану, не затрагивая иерархию представлений. Однако, поскольку полезная область наложения ограничена той же областью, что и его основной вид, если вы хотите анимировать вид, выходящий за пределы его позиции в макете, вы должны использовать наложение из родительского представления, которое имеет желаемые границы макета. .

    Когда вы создаете наложение для представления виджета, такого как Button , вы можете добавить в наложение объекты Drawable , вызвав add(Drawable) . Если вы вызываете getOverlay() для представления макета, такого как RelativeLayout , возвращаемым объектом является ViewGroupOverlay . Класс ViewGroupOverlay является подклассом ViewOverlay , который также позволяет добавлять объекты View с помощью вызова add(View) .

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

    Например, следующий код анимирует скольжение представления вправо, помещая представление в наложение родительского представления, а затем выполняя анимацию перемещения для этого представления:

    Котлин

    val view: View? = findViewById(R.id.view_to_remove)
    val container: ViewGroup? = view?.parent as ViewGroup
    
    container?.apply {
        overlay.add(view)
        ObjectAnimator.ofFloat(view, "translationX", right.toFloat())
                .start()
    }

    Ява

    View view = findViewById(R.id.view_to_remove);
    ViewGroup container = (ViewGroup) view.getParent();
    container.getOverlay().add(view);
    ObjectAnimator anim = ObjectAnimator.ofFloat(view, "translationX", container.getRight());
    anim.start();

    Расположение оптических границ

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

    Например, на рисунках 1 и 2 показан один и тот же макет, но версия на рисунке 1 использует границы обрезки (поведение по умолчанию), а на рисунке 2 используются оптические границы. Поскольку изображения с девятью фрагментами, используемые для кнопки и фоторамки, содержат отступы по краям, они не выравниваются друг с другом или с текстом при использовании границ клипа.

    Примечание. На снимках экрана на рисунках 1 и 2 включена настройка разработчика «Показать границы макета». Для каждого вида красные линии обозначают оптические границы, синие линии — границы клипа, а розовые — поля.

    Рисунок 1. Макет с использованием границ клипа (по умолчанию).

    Рисунок 2. Компоновка с использованием оптических границ.

    Чтобы выровнять представления на основе их оптических границ, установите для атрибута android:layoutMode значение "opticalBounds" в одном из родительских макетов. Например:

    <LinearLayout android:layoutMode="opticalBounds" ... >

    Рис. 3. Увеличенный вид девяти патчей кнопки Holo с оптическими границами.

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

    Когда вы включаете оптические границы для ViewGroup в своем макете, все представления-потомки наследуют режим макета оптических границ, если вы не переопределите его для группы, установив android:layoutMode в "clipBounds" . Все элементы макета также учитывают оптические границы своих дочерних представлений, адаптируя свои собственные границы на основе оптических границ представлений внутри них. Однако элементы макета (подклассы ViewGroup ) в настоящее время не поддерживают оптические границы для изображений с девятью патчами, примененных к их собственному фону.

    Если вы создаете собственное представление путем создания подкласса View , ViewGroup или любых его подклассов, ваше представление унаследует это оптическое связанное поведение.

    Примечание. Все виджеты, поддерживаемые темой Holo, были обновлены с использованием оптических границ, включая Button , Spinner , EditText и другие. Таким образом, вы можете сразу же получить выгоду, установив для атрибута android:layoutMode значение "opticalBounds" если ваше приложение применяет тему Holo ( Theme.Holo , Theme.Holo.Light и т. д.).

    Чтобы указать оптические границы для собственных изображений с девятью участками с помощью инструмента «Нарисовать 9 участков» , удерживайте Control при нажатии на пиксели границ.

    Анимация для значений Rect

    Теперь вы можете анимировать между двумя значениями Rect с помощью нового RectEvaluator . Этот новый класс представляет собой реализацию TypeEvaluator , которую вы можете передать ValueAnimator.setEvaluator() .

    Окно присоединения и фокус прослушивателя

    Раньше, если вы хотели прослушивать, когда ваше представление прикреплялось/отсоединялось от окна или когда изменялся его фокус, вам нужно было переопределить класс View для реализации onAttachedToWindow() и onDetachedFromWindow() или onWindowFocusChanged() соответственно.

    Теперь, чтобы получать события прикрепления и отсоединения, вы можете вместо этого реализовать ViewTreeObserver.OnWindowAttachListener и установить его в представлении с помощью addOnWindowAttachListener() . А чтобы получать события фокуса, вы можете реализовать ViewTreeObserver.OnWindowFocusChangeListener и установить его в представлении с помощью addOnWindowFocusChangeListener() .

    Поддержка ТВ-развертки

    Чтобы ваше приложение занимало весь экран на каждом телевизоре, теперь вы можете включить расширенное сканирование для макета вашего приложения. Режим Overscan определяется флагом FLAG_LAYOUT_IN_OVERSCAN , который можно включить с помощью тем платформы, таких как Theme_DeviceDefault_NoActionBar_Overscan , или включив стиль windowOverscan в пользовательской теме.

    Ориентация экрана

    Атрибут screenOrientation тега <activity> теперь поддерживает дополнительные значения, учитывающие предпочтения пользователя в отношении автоматического поворота:

    "userLandscape"
    Ведет себя так же, как "sensorLandscape" , за исключением того, что если пользователь отключает автоматический поворот, он фиксируется в обычной альбомной ориентации и не переворачивается.
    "userPortrait"
    Ведет себя так же, как "sensorPortrait" , за исключением того, что если пользователь отключает автоматический поворот, он фиксируется в обычной портретной ориентации и не переворачивается.
    "fullUser"
    Ведет себя так же, как "fullSensor" и допускает вращение во всех четырех направлениях, за исключением того, что если пользователь отключает автоматический поворот, он фиксирует предпочтительную ориентацию пользователя.

    Кроме того, теперь вы также можете объявить "locked" чтобы зафиксировать ориентацию вашего приложения в соответствии с текущей ориентацией экрана.

    Анимация вращения

    Новое поле rotationAnimation в WindowManager позволяет вам выбрать одну из трех анимаций, которые вы хотите использовать, когда система меняет ориентацию экрана. Три анимации:

    Примечание. Эти анимации доступны только в том случае, если вы настроили для своей активности использование «полноэкранного» режима, который можно включить с помощью таких тем, как Theme.Holo.NoActionBar.Fullscreen .

    Например, вот как можно включить анимацию «перекрестного затухания»:

    Котлин

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
    
        val params: WindowManager.LayoutParams = window.attributes
        params.rotationAnimation = WindowManager.LayoutParams.ROTATION_ANIMATION_CROSSFADE
        window.attributes = params
        ...
    }

    Ява

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    
        WindowManager.LayoutParams params = getWindow().getAttributes();
        params.rotationAnimation = WindowManager.LayoutParams.ROTATION_ANIMATION_CROSSFADE;
        getWindow().setAttributes(params);
        ...
    }

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

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

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

    Новые датчики TYPE_GYROSCOPE_UNCALIBRATED и TYPE_MAGNETIC_FIELD_UNCALIBRATED предоставляют необработанные данные датчиков без учета оценок смещения. То есть существующие датчики TYPE_GYROSCOPE и TYPE_MAGNETIC_FIELD предоставляют данные датчиков, которые учитывают предполагаемое смещение из-за гироскопического дрейфа и жесткого железа в устройстве соответственно. В то время как новые «некалиброванные» версии этих датчиков вместо этого предоставляют необработанные данные датчика и отдельно предлагают расчетные значения смещения. Эти датчики позволяют вам выполнять собственную калибровку данных датчиков, увеличивая расчетную погрешность с помощью внешних данных.

    Прослушиватель уведомлений

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

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

    Поставщик контактов

    Запрос «контактные данные»

    Новый запрос поставщика контактов Contactables.CONTENT_URI обеспечивает эффективный способ получить один Cursor , содержащий все адреса электронной почты и номера телефонов, принадлежащие всем контактам, соответствующим указанному запросу.

    Запрос дельт контактов

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

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

    Чтобы отслеживать, какие контакты были удалены, новая таблица ContactsContract.DeletedContacts предоставляет журнал удаленных контактов (но каждый удаленный контакт хранится в этой таблице в течение ограниченного времени). Подобно CONTACT_LAST_UPDATED_TIMESTAMP , вы можете использовать новый параметр выбора CONTACT_DELETED_TIMESTAMP , чтобы проверить, какие контакты были удалены с момента последнего запроса поставщика. Таблица также содержит константу DAYS_KEPT_MILLISECONDS содержащую количество дней (в миллисекундах), в течение которых будет храниться журнал.

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

    Пример кода, использующего эти API для проверки изменений в контактах, см. в образце ApiDemos, доступном в пакете загрузки примеров SDK .

    Локализация

    Улучшенная поддержка двунаправленного текста.

    Предыдущие версии Android поддерживают языки и макеты с письмом справа налево (RTL), но иногда неправильно обрабатывают текст со смешанным направлением письма. Поэтому в Android 4.3 добавлены API-интерфейсы BidiFormatter , которые помогают правильно форматировать текст с содержимым в противоположном направлении, не искажая какие-либо его части.

    Например, если вы хотите создать предложение со строковой переменной, например «Вы имели в виду 15 Bay Street, Laurel, CA?», вы обычно передаете локализованный строковый ресурс и переменную в String.format() :

    Котлин

    val suggestion = String.format(resources.getString(R.string.did_you_mean), address)

    Ява

    Resources res = getResources();
    String suggestion = String.format(res.getString(R.string.did_you_mean), address);

    Однако если языковым стандартом является иврит, то отформатированная строка будет выглядеть следующим образом:

    Место проживания: Бэй-стрит, 15, Лорел, Калифорния?

    Это неправильно, потому что цифра «15» должна оставаться слева от «Бэй-стрит». Решение — использовать BidiFormatter и его метод unicodeWrap() . Например, приведенный выше код выглядит следующим образом:

    Котлин

    val bidiFormatter = BidiFormatter.getInstance()
    val suggestion = String.format(
            resources.getString(R.string.did_you_mean),
            bidiFormatter.unicodeWrap(address)
    )

    Ява

    Resources res = getResources();
    BidiFormatter bidiFormatter = BidiFormatter.getInstance();
    String suggestion = String.format(res.getString(R.string.did_you_mean),
            bidiFormatter.unicodeWrap(address));

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

    Примечание. Эти новые API также доступны для предыдущих версий Android через библиотеку поддержки Android с классом BidiFormatter и связанными API.

    Службы доступности

    Обрабатывать ключевые события

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

    Выделите текст и скопируйте/вставьте

    AccessibilityNodeInfo теперь предоставляет API, которые позволяют AccessibilityService выбирать, вырезать, копировать и вставить текст в узле.

    Чтобы указать выбор текста для вырезания или копирования, ваша служба доступности может использовать новое действие, ACTION_SET_SELECTION , передавая с ним начало и конечную позицию выбора с помощью ACTION_ARGUMENT_SELECTION_START_INT и ACTION_ARGUMENT_SELECTION_END_INT . В качестве альтернативы вы можете выбрать текст, манипулируя позицией курсора, используя существующее действие, ACTION_NEXT_AT_MOVEMENT_GRANULARITY (ранее только для перемещения позиции курсора) и добавление аргумента ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN .

    Затем вы можете вырезать или скопировать с помощью ACTION_CUT , ACTION_COPY , а затем вставить с помощью ACTION_PASTE .

    Примечание. Эти новые API также доступны для предыдущих версий Android через библиотеку поддержки Android с классом AccessibilityNodeInfoCompat .

    Объявить функции доступности

    Начиная с Android 4.3, служба доступности должна объявить возможности доступности в своем файле метаданных для использования определенных функций доступности. Если возможность не запрашивается в файле метаданных, то функция будет безотраслевой. Чтобы объявить возможности доступности вашей услуги, вы должны использовать атрибуты XML, которые соответствуют различным константам «возможностей» в классе AccessibilityServiceInfo .

    Например, если служба не требует возможности flagRequestFilterKeyEvents , то она не будет получать ключевые события.

    Тестирование и отладка

    Автоматизированное тестирование пользовательского интерфейса

    Новый класс UiAutomation предоставляет API, которые позволяют вам моделировать действия пользователя для автоматизации тестирования. Используя API -интерфейсы платформы AccessibilityService платформы, API -интерфейсы UiAutomation позволяют осмотреть содержимое экрана и вводить произвольную клавиатуру и соприкасающиеся события.

    Чтобы получить экземпляр UiAutomation , вызовите Instrumentation.getUiAutomation() . Чтобы это работало, вы должны предоставить опцию -w с командой instrument при запуске вашего InstrumentationTestCase от adb shell .

    С помощью экземпляра UiAutomation вы можете выполнить произвольные события, чтобы протестировать свое приложение, позвонив в executeAndWaitForEvent() , передавая его Runnable для выполнения, период времени ожидания для операции и реализации интерфейса UiAutomation.AccessibilityEventFilter . Именно в рамках вашей UiAutomation.AccessibilityEventFilter .

    Чтобы наблюдать за всеми событиями во время теста, создайте реализацию UiAutomation.OnAccessibilityEventListener и передайте его в setOnAccessibilityEventListener() . Затем ваш интерфейс слушателя получает вызов для onAccessibilityEvent() каждый раз, когда происходит событие, получая объект AccessibilityEvent , который описывает событие.

    Существует множество других операций, которые API -интерфейсы UiAutomation подвергают на очень низком уровне, чтобы стимулировать разработку инструментов тестирования пользовательского интерфейса, таких как UIAutomator . Например, UiAutomation также может:

    • Внедрять события ввода
    • Измените ориентацию экрана
    • Делайте скриншоты

    И самое главное для инструментов тестирования пользовательского интерфейса, API -интерфейсы UiAutomation работают по границам применения, в отличие от тех, кто находится в Instrumentation .

    Systrace Events для приложений

    Android 4.3 добавляет класс Trace двумя статическими методами, beginSection() и endSection() , что позволяет вам определить блоки кода, чтобы включить в Systrace Report. Создавая разделы отслеживаемого кода в вашем приложении, журналы Systrace предоставляют вам гораздо более подробный анализ того, где происходит замедление в вашем приложении.

    Для получения информации об использовании инструмента SYSTRACE, прочтите анализ дисплея и производительность с помощью SYSTRACE .

    Безопасность

    Android Key Store для приложений-частных ключей

    Теперь Android предлагает пользовательского поставщика Java Security на объекте KeyStore , который называется Android Key Store, который позволяет генерировать и сохранять частные ключи, которые могут быть замечены и используются только вашим приложением. Чтобы загрузить магазин Android Key, пройти "AndroidKeyStore" в KeyStore.getInstance() .

    Чтобы управлять частными учетными данными вашего приложения в магазине Android Key, создайте новый ключ с KeyPairGenerator с KeyPairGeneratorSpec . Сначала получите экземпляр KeyPairGenerator , позвонив getInstance() . Затем вызовите initialize() , передавая его экземпляр KeyPairGeneratorSpec , который вы можете получить, используя KeyPairGeneratorSpec.Builder . Наконец, получите KeyPair , позвонив generateKeyPair() .

    Аппаратное хранилище учетных данных

    Android также теперь поддерживает хранилище, поддерживаемое оборудованием для ваших учетных данных KeyChain , обеспечивая большую безопасность, делая ключи недоступными для извлечения. То есть, как только клавиши находятся в магазине ключей, поддерживаемых оборудованием (защищенный элемент, TPM или доверие), их можно использовать для криптографических операций, но материал частного ключа не может быть экспортирован. Даже ядро ​​ОС не может получить доступ к этому ключевому материалу. Несмотря на то, что не все устройства, способствующие Android, поддерживают хранилище на оборудовании, вы можете проверить во время выполнения, если доступно хранилище оборудования, вызывая KeyChain.IsBoundKeyAlgorithm() .

    Манифестные заявления

    Объявлены требуемые функции

    Следующие значения теперь поддерживаются в элементе <uses-feature> , поэтому вы можете убедиться, что ваше приложение установлено только на устройствах, которые предоставляют функции потребности в вашем приложении.

    FEATURE_APP_WIDGETS
    Заявляет, что ваше приложение предоставляет виджет приложения и должно быть установлено только на устройствах, которые включают домашний экран или аналогичное место, где пользователи могут встраивать виджеты приложений. Пример:
    <uses-feature android:name="android.software.app_widgets" android:required="true" />
    FEATURE_HOME_SCREEN
    Объявляет, что ваше приложение ведет себя как замена домашнего экрана и должно быть установлено только на устройствах, которые поддерживают сторонние приложения домашнего экрана. Пример:
    <uses-feature android:name="android.software.home_screen" android:required="true" />
    FEATURE_INPUT_METHODS
    Обеспечивает, что ваше приложение предоставляет пользовательский метод ввода (клавиатура, созданная с помощью InputMethodService ) и должно быть установлено только на устройствах, которые поддерживают сторонние методы ввода. Пример:
    <uses-feature android:name="android.software.input_methods" android:required="true" />
    FEATURE_BLUETOOTH_LE
    Обеспечивает, что в вашем приложении используются API с низкой энергией Bluetooth и должны быть установлены только на устройствах, которые способны общаться с другими устройствами с помощью низкой энергии Bluetooth. Пример:
    <uses-feature android:name="android.software.bluetooth_le" android:required="true" />

    Разрешения пользователя

    Следующие значения теперь поддерживаются в <uses-permission> для объявления разрешений, требующих вашего приложения, чтобы получить доступ к определенным API.

    BIND_NOTIFICATION_LISTENER_SERVICE
    Требуется использовать новые API API NotificationListenerService .
    SEND_RESPOND_VIA_MESSAGE
    Требуется для получения намерения ACTION_RESPOND_VIA_MESSAGE .

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