API Android 4.4

Cấp độ API: 19

Android 4.4 (KITKAT) là một bản phát hành mới dành cho nền tảng Android, cung cấp các tính năng mới cho người dùng và nhà phát triển ứng dụng. Tài liệu này giới thiệu các API mới đáng chú ý nhất.

Là nhà phát triển ứng dụng, bạn nên tải hình ảnh hệ thống và nền tảng SDK Android 4.4 xuống qua Trình quản lý SDK càng sớm càng tốt. Nếu bạn không có thiết bị chạy Android 4.4 để kiểm thử ứng dụng, hãy sử dụng ảnh hệ thống Android 4.4 để kiểm thử ứng dụng trên trình mô phỏng Android. Sau đó, hãy xây dựng ứng dụng dựa trên nền tảng Android 4.4 để bắt đầu sử dụng các API mới nhất.

Cập nhật cấp độ API mục tiêu của bạn

Để tối ưu hoá ứng dụng của bạn một cách hiệu quả hơn cho các thiết bị chạy Android 4.4, bạn nên đặt targetSdkVersion thành "19", cài đặt ứng dụng này trên ảnh hệ thống Android 4.4, kiểm thử rồi phát hành bản cập nhật với thay đổi này.

Bạn có thể sử dụng API trong Android 4.4 trong khi vẫn hỗ trợ các phiên bản cũ hơn bằng cách thêm điều kiện vào mã để kiểm tra cấp độ API hệ thống trước khi thực thi các API không được minSdkVersion của bạn hỗ trợ. Để tìm hiểu thêm về cách duy trì khả năng tương thích ngược, hãy đọc phần Hỗ trợ nhiều phiên bản nền tảng.

Để biết thêm thông tin về cách hoạt động của các cấp độ API, hãy đọc bài viết Cấp độ API là gì?

Thay đổi quan trọng về hành vi

Nếu bạn từng phát hành một ứng dụng dành cho Android, hãy lưu ý rằng các thay đổi trong Android 4.4 có thể ảnh hưởng đến ứng dụng của bạn.

Nếu ứng dụng của bạn đọc từ bộ nhớ ngoài...

Ứng dụng của bạn không thể đọc các tệp được chia sẻ trên bộ nhớ ngoài khi chạy trên Android 4.4, trừ khi ứng dụng có quyền READ_EXTERNAL_STORAGE. Tức là không thể truy cập vào các tệp trong thư mục do getExternalStoragePublicDirectory() trả về nữa nếu không có quyền. Tuy nhiên, nếu chỉ cần truy cập vào các thư mục dành riêng cho ứng dụng do getExternalFilesDir() cung cấp, thì bạn không cần quyền READ_EXTERNAL_STORAGE.

Nếu ứng dụng của bạn dùng WebView...

Ứng dụng của bạn có thể hoạt động theo cách khác khi chạy trên Android 4.4, đặc biệt là khi bạn cập nhật targetSdkVersion của ứng dụng lên "19" trở lên.

Mã cơ sở cho lớp WebView và các API liên quan đã được nâng cấp để dựa trên bản tổng quan nhanh hiện đại của mã nguồn Chromium. Tính năng này mang đến nhiều điểm cải tiến về hiệu suất, khả năng hỗ trợ các tính năng HTML5 mới và hỗ trợ gỡ lỗi từ xa đối với nội dung WebView của bạn. Phạm vi của bản nâng cấp này có nghĩa là nếu ứng dụng của bạn sử dụng WebView, thì trong một số trường hợp, hành vi của ứng dụng đó có thể bị ảnh hưởng. Mặc dù các thay đổi về hành vi đã biết được ghi nhận và phần lớn chỉ ảnh hưởng đến ứng dụng của bạn khi bạn cập nhật targetSdkVersion của ứng dụng lên "19" trở lên, WebView mới hoạt động ở "chế độ tương thích" để cung cấp một số chức năng cũ trong ứng dụng nhắm đến API cấp 18 trở xuống. Có thể ứng dụng của bạn phụ thuộc vào các hành vi không xác định trong phiên bản WebView trước.

Vì vậy, nếu ứng dụng hiện tại của bạn sử dụng WebView, bạn cần thử nghiệm trên Android 4.4 càng sớm càng tốt và tham khảo bài viết Di chuyển sang WebView trong Android 4.4 để biết thông tin về việc ứng dụng của bạn có thể bị ảnh hưởng như thế nào khi cập nhật targetSdkVersion lên "19" trở lên.

Nếu ứng dụng của bạn sử dụng AlarmManager...

Khi bạn đặt targetSdkVersion của ứng dụng thành "19" trở lên, các chuông báo mà bạn tạo bằng set() hoặc setRepeating() sẽ không chính xác.

Để cải thiện hiệu quả sử dụng pin, giờ đây, Android sẽ gộp nhóm chuông báo của tất cả ứng dụng vào những thời điểm tương tự nhau một cách hợp lý. Nhờ đó, hệ thống sẽ đánh thức thiết bị một lần thay vì nhiều lần để xử lý từng chuông báo.

Nếu chuông báo của bạn không liên kết với giờ đồng hồ chính xác, nhưng vẫn cần phải gọi chuông báo trong một khoảng thời gian cụ thể (chẳng hạn như từ 2 giờ chiều đến 4 giờ chiều), thì bạn có thể sử dụng phương thức setWindow() mới. Phương thức này chấp nhận thời điểm "sớm nhất" của chuông báo và một "khoảng thời gian" sau khoảng thời gian sớm nhất mà hệ thống nên gọi chuông báo.

Nếu bạn phải ghim chuông báo vào thời gian đồng hồ chính xác (chẳng hạn như lời nhắc sự kiện trên lịch), thì bạn có thể sử dụng phương thức setExact() mới.

Hành vi tạo lô không chính xác này chỉ áp dụng cho các ứng dụng đã cập nhật. Nếu bạn đặt targetSdkVersion thành "18" trở xuống, chuông báo sẽ tiếp tục hoạt động như trên các phiên bản trước khi chạy trên Android 4.4.

Nếu ứng dụng của bạn đồng bộ hoá dữ liệu bằng ContentResolver...

Khi bạn đặt targetSdkVersion của ứng dụng thành "19" trở lên, việc tạo quy trình đồng bộ hoá với addPeriodicSync() sẽ thực hiện các hoạt động đồng bộ hoá trong khoảng thời gian linh hoạt mặc định là khoảng 4% khoảng thời gian mà bạn chỉ định. Ví dụ: nếu tần suất thăm dò ý kiến là 24 giờ, thì hoạt động đồng bộ hoá của bạn có thể diễn ra trong khoảng thời gian khoảng một giờ mỗi ngày, thay vì vào cùng một thời điểm chính xác mỗi ngày.

Để chỉ định khoảng thời gian linh hoạt của riêng bạn cho các hoạt động đồng bộ hoá, bạn nên bắt đầu sử dụng phương thức requestSync() mới. Để biết thêm thông tin chi tiết, hãy xem phần bên dưới về Bộ điều hợp đồng bộ hoá.

Hành vi khoảng thời gian linh hoạt này chỉ áp dụng cho các ứng dụng đã cập nhật. Nếu bạn đã đặt targetSdkVersion thành "18" trở xuống, các yêu cầu đồng bộ hóa hiện có của bạn sẽ tiếp tục hoạt động như có trên các phiên bản trước khi chạy trên Android 4.4.

Khung in

Android hiện có một khung hoàn chỉnh cho phép người dùng in bất kỳ tài liệu nào bằng máy in kết nối qua Wi-Fi, Bluetooth hoặc các dịch vụ khác. Hệ thống này xử lý giao dịch giữa một ứng dụng muốn in tài liệu và các dịch vụ gửi lệnh in tới máy in. Khung android.print cung cấp tất cả API cần thiết để chỉ định tài liệu in và gửi tài liệu đó đến hệ thống để in. Những API mà bạn thực sự cần cho một lệnh in nhất định sẽ tuỳ thuộc vào nội dung của bạn.

In nội dung chung chung

Nếu muốn in nội dung trên giao diện người dùng dưới dạng tài liệu, trước tiên, bạn cần tạo một lớp con của PrintDocumentAdapter. Trong lớp này, bạn phải triển khai một số phương thức gọi lại, bao gồm cả onLayout() để thiết lập bố cục dựa trên các thuộc tính in được cung cấp và onWrite() để chuyển đổi tuần tự nội dung có thể in thành ParcelFileDescriptor.

Để ghi nội dung vào ParcelFileDescriptor, bạn phải chuyển nội dung đó ở dạng PDF. Các API PdfDocument mới giúp bạn thực hiện việc này một cách thuận tiện bằng cách cung cấp Canvas từ getCanvas(), nơi bạn có thể vẽ nội dung có thể in trên đó. Sau đó, ghi PdfDocument vào ParcelFileDescriptor bằng phương thức writeTo().

Sau khi xác định phương thức triển khai cho PrintDocumentAdapter, bạn có thể thực thi các lệnh in theo yêu cầu của người dùng bằng cách sử dụng phương thức PrintManager (print()) để lấy PrintDocumentAdapter làm một trong các đối số của phương thức này.

In hình ảnh

Nếu bạn chỉ muốn in ảnh hoặc các bitmap khác, thì các API trợ giúp trong thư viện hỗ trợ sẽ làm mọi việc cho bạn. Bạn chỉ cần tạo một thực thể mới của PrintHelper, đặt chế độ tỷ lệ bằng setScaleMode(), sau đó truyền Bitmap đến printBitmap(). Vậy là xong. Thư viện này xử lý tất cả hoạt động tương tác còn lại với hệ thống để phân phối bitmap đến máy in.

Dịch vụ in xây dựng

Là nhà sản xuất thiết bị gốc (OEM) máy in, bạn có thể sử dụng khung android.printservice để cung cấp khả năng tương tác với máy in trên thiết bị Android. Bạn có thể xây dựng và phân phối dịch vụ in dưới dạng tệp APK mà người dùng có thể cài đặt trên thiết bị của họ . Ứng dụng dịch vụ in hoạt động chủ yếu dưới dạng dịch vụ không có giao diện người dùng bằng cách phân lớp con lớp PrintService. Lớp này nhận lệnh in từ hệ thống rồi truyền lệnh đó đến máy in của ứng dụng đó bằng giao thức thích hợp.

Để biết thêm thông tin về cách in nội dung ứng dụng, hãy đọc bài viết In nội dung.

Nhà cung cấp dịch vụ SMS

Nhà cung cấp nội dung Telephony ("Nhà cung cấp SMS") cho phép các ứng dụng đọc và ghi tin nhắn SMS và MMS trên thiết bị. Dữ liệu này bao gồm các bảng chứa tin nhắn SMS và MMS đã nhận, đã soạn, đã gửi, đang chờ xử lý và nhiều tin nhắn khác.

Kể từ Android 4.4, phần cài đặt hệ thống cho phép người dùng chọn "ứng dụng SMS mặc định". Sau khi được chọn, chỉ ứng dụng SMS mặc định mới có thể ghi vào Nhà cung cấp dịch vụ SMS và chỉ ứng dụng SMS mặc định mới nhận được thông báo SMS_DELIVER_ACTION khi người dùng nhận một tin nhắn SMS hoặc WAP_PUSH_DELIVER_ACTION khi người dùng nhận được tin nhắn MMS. Ứng dụng SMS mặc định chịu trách nhiệm ghi thông tin chi tiết cho Nhà cung cấp tin nhắn SMS khi nhận được hoặc gửi một tin nhắn mới.

Các ứng dụng khác không được chọn làm ứng dụng SMS mặc định chỉ có thể đọc Nhà cung cấp tin nhắn SMS nhưng cũng có thể được thông báo khi có tin nhắn SMS mới bằng cách nghe thông báo SMS_RECEIVED_ACTION. Đây là một tin truyền không thể huỷ được mà có thể được gửi đến nhiều ứng dụng. Thông báo này dành cho các ứng dụng---trong khi không được chọn làm ứng dụng SMS mặc định---cần đọc các tin nhắn đến đặc biệt chẳng hạn như để thực hiện xác minh số điện thoại.

Để biết thêm thông tin, hãy đọc bài đăng trên blog Chuẩn bị ứng dụng SMS của bạn sẵn sàng cho KitKat.

Không dây và kết nối

Mô phỏng thẻ dựa trên máy chủ

Giờ đây, các ứng dụng Android có thể mô phỏng thẻ NFC ISO14443-4 (ISO-DEP) sử dụng APDU để trao đổi dữ liệu (như quy định trong ISO7816-4). Điều này cho phép thiết bị hỗ trợ NFC chạy Android 4.4 mô phỏng nhiều thẻ NFC cùng lúc và cho phép thiết bị thanh toán NFC hoặc đầu đọc NFC khác bắt đầu giao dịch bằng thẻ NFC phù hợp dựa trên giá trị nhận dạng ứng dụng (AID).

Nếu bạn muốn mô phỏng một thẻ NFC đang sử dụng các giao thức này trong ứng dụng, hãy tạo một thành phần dịch vụ dựa trên lớp HostApduService. Ngược lại, nếu ứng dụng dùng một phần tử bảo mật để mô phỏng thẻ, thì bạn cần tạo một dịch vụ dựa trên lớp OffHostApduService. Lớp này sẽ không trực tiếp tham gia vào các giao dịch nhưng cần đăng ký các AID mà phần tử bảo mật cần phải xử lý.

Để biết thêm thông tin, hãy đọc hướng dẫn Mô phỏng thẻ NFC.

Chế độ đọc NFC

Chế độ đọc NFC mới cho phép một hoạt động giới hạn mọi hoạt động NFC thành chỉ đọc các loại thẻ mà hoạt động quan tâm khi ở nền trước. Bạn có thể bật chế độ đọc cho hoạt động của mình bằng enableReaderMode(), cho phép triển khai NfcAdapter.ReaderCallback để nhận lệnh gọi lại khi phát hiện thấy các thẻ mới.

Khả năng mới này, cùng với quy trình mô phỏng thẻ máy chủ, cho phép Android hoạt động trên cả hai đầu giao diện thanh toán di động: Một thiết bị hoạt động như một thiết bị thanh toán (thiết bị chạy hoạt động ở chế độ đọc) và một thiết bị khác hoạt động như máy khách thanh toán (một thiết bị mô phỏng thẻ NFC).

Bộ phát hồng ngoại

Giờ đây, khi chạy trên một thiết bị có bộ phát hồng ngoại (IR), bạn có thể truyền tín hiệu IR bằng các API ConsumerIrManager. Để nhận một thực thể của ConsumerIrManager, hãy gọi getSystemService() với đối số là CONSUMER_IR_SERVICE. Sau đó, bạn có thể truy vấn tần số hồng ngoại được hỗ trợ của thiết bị bằng getCarrierFrequencies() và truyền tín hiệu bằng cách truyền tần số và mẫu tín hiệu mong muốn bằng transmit().

Trước tiên, bạn phải luôn kiểm tra xem thiết bị có bộ phát IR hay không bằng cách gọi hasIrEmitter(). Tuy nhiên, nếu ứng dụng của bạn chỉ tương thích với các thiết bị có bộ phát này, thì bạn nên thêm phần tử <uses-feature> vào tệp kê khai cho "android.hardware.consumerir" (FEATURE_CONSUMER_IR).

Nội dung đa phương tiện

Phát thích ứng

Giờ đây, các API MediaCodec có thể hỗ trợ tính năng phát video thích ứng, cho phép thay đổi liền mạch độ phân giải trong khi phát trên Surface – bạn có thể cung cấp khung đầu vào của bộ giải mã có độ phân giải mới và độ phân giải của vùng đệm đầu ra thay đổi mà không có khoảng trống đáng kể.

Bạn có thể bật tính năng phát thích ứng bằng cách thêm hai phím vào MediaFormat để chỉ định độ phân giải tối đa mà ứng dụng của bạn yêu cầu trong bộ mã hoá và giải mã: KEY_MAX_WIDTHKEY_MAX_HEIGHT. Sau khi thêm những giá trị này vào MediaFormat, hãy truyền MediaFormat vào thực thể MediaCodec bằng configure().

Bộ mã hoá và giải mã sẽ chuyển đổi liền mạch giữa các độ phân giải bằng hoặc nhỏ hơn các giá trị này. Bộ mã hoá và giải mã cũng có thể hỗ trợ các độ phân giải lớn hơn mức tối đa đã chỉ định (miễn là nằm trong giới hạn của cấu hình được hỗ trợ), nhưng việc chuyển đổi sang độ phân giải lớn hơn có thể không liền mạch.

Để thay đổi độ phân giải trong khi giải mã video H.264, hãy tiếp tục xếp các khung hình vào hàng đợi bằng MediaCodec.queueInputBuffer(), nhưng hãy chắc chắn rằng bạn cung cấp các giá trị Sequence Parameter Set (SPS) và hình ảnh Set (PPS) mới cùng với khung làm mới bộ giải mã tức thì (IDR) trong một bộ đệm duy nhất.

Tuy nhiên, trước khi định cấu hình bộ mã hoá và giải mã cho tính năng phát thích ứng, bạn phải xác minh rằng thiết bị hỗ trợ tính năng phát thích ứng bằng cách gọi isFeatureSupported(String) bằng FEATURE_AdaptivePlayback.

Lưu ý: Tính năng hỗ trợ phát lại thích ứng tuỳ thuộc vào từng nhà cung cấp. Một số bộ mã hoá và giải mã có thể cần nhiều bộ nhớ hơn đối với các gợi ý có độ phân giải lớn hơn. Do đó, bạn nên đặt độ phân giải tối đa dựa trên tài liệu nguồn mà bạn đang giải mã.

Dấu thời gian của âm thanh theo yêu cầu

Để tạo điều kiện đồng bộ hoá âm thanh và video, lớp AudioTimestamp mới cung cấp thông tin chi tiết về dòng thời gian của một "khung hình" cụ thể trong luồng âm thanh do AudioTrack xử lý. Để có được dấu thời gian mới nhất, hãy tạo thực thể cho đối tượng AudioTimestamp rồi truyền đối tượng đó đến getTimestamp(). Nếu yêu cầu dấu thời gian thành công, thực thể AudioTrack sẽ được điền vào một vị trí trong đơn vị khung hình, cùng với thời gian ước tính khi khung hình đó được trình bày hoặc được cam kết hiển thị.

Bạn có thể sử dụng giá trị của nanoTime trong AudioTimestamp (là đơn điệu) để tìm khung hình video liên kết gần nhất so với framePosition. Nhờ vậy, bạn có thể thả, sao chép hoặc nội suy khung hình video cho khớp với âm thanh. Ngoài ra, bạn có thể xác định thời gian delta giữa giá trị của nanoTime và thời gian dự kiến của khung hình video trong tương lai (có cân nhắc tốc độ lấy mẫu) để dự đoán khung âm thanh nào được mong đợi tại cùng thời điểm với khung hình video.

Trình đọc hình ảnh trên nền tảng

API ImageReader mới cho phép bạn truy cập trực tiếp vào vùng đệm hình ảnh khi chúng được kết xuất vào Surface. Bạn có thể lấy ImageReader bằng phương thức tĩnh newInstance(). Sau đó, hãy gọi getSurface() để tạo Surface mới và phân phối dữ liệu hình ảnh qua một nhà sản xuất như MediaPlayer hoặc MediaCodec. Để nhận thông báo khi có hình ảnh mới trên nền tảng, hãy triển khai giao diện ImageReader.OnImageAvailableListener và đăng ký giao diện đó với setOnImageAvailableListener().

Bây giờ, khi bạn vẽ nội dung vào Surface, ImageReader.OnImageAvailableListener sẽ nhận được lệnh gọi đến onImageAvailable() khi mỗi khung hình ảnh mới có sẵn, cung cấp cho bạn ImageReader tương ứng. Bạn có thể sử dụng ImageReader để lấy dữ liệu hình ảnh của khung dưới dạng đối tượng Image bằng cách gọi acquireLatestImage() hoặc acquireNextImage().

Đối tượng Image cung cấp quyền truy cập trực tiếp vào dấu thời gian, định dạng, kích thước và dữ liệu pixel của hình ảnh trong ByteBuffer. Tuy nhiên, để lớp Image diễn giải hình ảnh của bạn, hình ảnh phải được định dạng theo một trong các kiểu được xác định bằng các hằng số trong ImageFormat hoặc PixelFormat.

Đo lường giá trị cao nhất và RMS

Giờ đây, bạn có thể truy vấn đỉnh và RMS của luồng âm thanh hiện tại qua Visualizer bằng cách tạo một thực thể mới của Visualizer.MeasurementPeakRms rồi truyền dữ liệu đó vào getMeasurementPeakRms(). Khi bạn gọi phương thức này, các giá trị cao nhất và RMS của Visualizer.MeasurementPeakRms đã cho sẽ được đặt thành các giá trị đo được mới nhất.

Chất tăng âm thanh

LoudnessEnhancer là một lớp con mới của AudioEffect cho phép bạn tăng âm lượng âm thanh của MediaPlayer hoặc AudioTrack. Tính năng này có thể đặc biệt hữu ích khi kết hợp với phương thức getMeasurementPeakRms() mới nêu trên để tăng âm lượng của bản âm thanh được nói trong khi nội dung nghe nhìn khác đang phát.

Bộ điều khiển từ xa

Android 4.0 (API cấp 14) đã ra mắt các API RemoteControlClient cho phép các ứng dụng đa phương tiện sử dụng các sự kiện của trình điều khiển nội dung nghe nhìn từ các ứng dụng từ xa, chẳng hạn như các nút điều khiển nội dung nghe nhìn trên màn hình khoá. Giờ đây, các API RemoteController mới cho phép bạn tạo bộ điều khiển từ xa của riêng mình, hỗ trợ việc tạo các ứng dụng và thiết bị ngoại vi mới, sáng tạo có thể điều khiển chế độ phát bất kỳ ứng dụng đa phương tiện nào tích hợp với RemoteControlClient.

Để tạo bộ điều khiển từ xa, bạn có thể triển khai giao diện người dùng theo bất kỳ cách nào mình muốn. Tuy nhiên, để phân phối các sự kiện nút đa phương tiện tới ứng dụng đa phương tiện của người dùng, bạn phải tạo một dịch vụ mở rộng lớp NotificationListenerService và triển khai giao diện RemoteController.OnClientUpdateListener. Việc sử dụng NotificationListenerService làm cơ sở rất quan trọng vì nó đưa ra các hạn chế thích hợp về quyền riêng tư. Theo đó, người dùng phải bật ứng dụng của bạn làm trình nghe thông báo trong phần cài đặt bảo mật của hệ thống.

Lớp NotificationListenerService bao gồm một số phương thức trừu tượng mà bạn phải triển khai, nhưng nếu chỉ quan tâm đến các sự kiện trình điều khiển nội dung đa phương tiện để xử lý việc phát nội dung đa phương tiện, thì bạn có thể để trống phương thức triển khai các phương thức đó và thay vào đó, hãy tập trung vào các phương thức RemoteController.OnClientUpdateListener.

Điểm xếp hạng của bộ điều khiển từ xa

Android 4.4 được xây dựng dựa trên các tính năng hiện có dành cho các ứng dụng điều khiển từ xa (ứng dụng nhận sự kiện điều khiển nội dung nghe nhìn thông qua RemoteControlClient) bằng cách bổ sung khả năng xếp hạng bản nhạc hiện tại trên bộ điều khiển từ xa.

Lớp Rating mới bao gồm thông tin về điểm xếp hạng của người dùng. Mức phân loại được xác định theo kiểu phân loại (RATING_HEART, RATING_THUMB_UP_DOWN, RATING_3_STARS, RATING_4_STARS, RATING_5_STARS hoặc RATING_PERCENTAGE) và giá trị phân loại phù hợp với kiểu đó.

Cách cho phép người dùng xếp hạng tuyến đường của bạn bằng bộ điều khiển từ xa:

Để nhận lệnh gọi lại khi người dùng thay đổi điểm xếp hạng trên bộ điều khiển từ xa, hãy triển khai giao diện RemoteControlClient.OnMetadataUpdateListener mới và truyền một thực thể đến setMetadataUpdateListener(). Khi người dùng thay đổi điểm xếp hạng, RemoteControlClient.OnMetadataUpdateListener của bạn sẽ nhận được lệnh gọi đến onMetadataUpdate(), truyền RATING_KEY_BY_USER làm khoá và đối tượng Rating làm giá trị.

Phụ đề

VideoView hiện hỗ trợ các bản phụ đề trên WebVTT khi phát video Luồng trực tiếp qua HTTP (HLS), hiển thị bản phụ đề theo tùy chọn phụ đề mà người dùng đã xác định trong phần cài đặt hệ thống.

Bạn cũng có thể cung cấp các bản phụ đề WebVTT cho VideoView bằng phương thức addSubtitleSource(). Phương thức này chấp nhận một InputStream chứa dữ liệu phụ đề và đối tượng MediaFormat chỉ định định dạng cho dữ liệu phụ đề. Bạn có thể chỉ định định dạng này bằng cách sử dụng createSubtitleFormat(). Những phụ đề này cũng xuất hiện trên video theo lựa chọn ưu tiên của người dùng.

Nếu không sử dụng VideoView để hiển thị nội dung video thì bạn nên tạo lớp phủ phụ đề sao cho phù hợp nhất có thể với lựa chọn ưu tiên của người dùng về phụ đề. API CaptioningManager mới cho phép bạn truy vấn các lựa chọn ưu tiên về phụ đề của người dùng, bao gồm cả các kiểu do CaptioningManager.CaptionStyle xác định, chẳng hạn như kiểu chữ và màu. Trong trường hợp người dùng điều chỉnh một số lựa chọn ưu tiên khi video đã bắt đầu, bạn nên lắng nghe những thay đổi đối với lựa chọn ưu tiên bằng cách đăng ký một phiên bản của CaptioningManager.CaptioningChangeListener để nhận lệnh gọi lại khi các lựa chọn ưu tiên thay đổi, sau đó cập nhật phụ đề nếu cần.

Ảnh động và đồ hoạ

Cảnh và hiệu ứng chuyển cảnh

Khung android.transition mới cung cấp các API hỗ trợ ảnh động giữa nhiều trạng thái của giao diện người dùng. Một tính năng chính là khả năng giúp bạn xác định các trạng thái riêng biệt của giao diện người dùng (còn gọi là "cảnh") bằng cách tạo một bố cục riêng cho mỗi trạng thái. Khi bạn muốn tạo hiệu ứng động từ cảnh này sang cảnh khác, hãy thực hiện thao tác "chuyển đổi", giúp tính toán ảnh động cần thiết để thay đổi bố cục từ cảnh hiện tại sang cảnh tiếp theo.

Để chuyển đổi giữa hai cảnh, thông thường bạn cần thực hiện những việc sau:

  1. Chỉ định ViewGroup chứa các thành phần giao diện người dùng mà bạn muốn thay đổi.
  2. Chỉ định bố cục thể hiện kết quả cuối cùng của thay đổi (cảnh tiếp theo).
  3. Chỉ định loại chuyển đổi sẽ tạo hiệu ứng ảnh động cho thay đổi về bố cục.
  4. Thực hiện hiệu ứng chuyển đổi.

Bạn có thể sử dụng đối tượng Scene để hoàn thành bước 1 và 2. Scene chứa siêu dữ liệu mô tả các thuộc tính của bố cục cần thiết để thực hiện chuyển đổi, bao gồm cả khung hiển thị mẹ và bố cục của cảnh. Bạn có thể tạo Scene bằng hàm khởi tạo lớp hoặc phương thức tĩnh getSceneForLayout().

Sau đó, bạn phải sử dụng TransitionManager để hoàn tất bước 3 và 4. Có một cách là truyền Scene sang phương thức tĩnh go(). Thao tác này sẽ tìm khung hiển thị mẹ của cảnh trong bố cục hiện tại và thực hiện hiệu ứng chuyển đổi trên các khung hiển thị con để đạt đến bố cục do Scene xác định.

Ngoài ra, bạn không cần tạo đối tượng Scene. Thay vào đó, bạn có thể gọi beginDelayedTransition(), chỉ định ViewGroup chứa các khung hiển thị mà bạn muốn thay đổi. Sau đó, hãy thêm, xoá hoặc định cấu hình lại các chế độ xem mục tiêu. Sau khi hệ thống bố trí các thay đổi nếu cần, quá trình chuyển đổi sẽ bắt đầu tạo ảnh động cho tất cả các chế độ xem bị ảnh hưởng.

Để có thêm quyền kiểm soát, bạn có thể xác định các tập hợp hiệu ứng chuyển đổi sẽ diễn ra giữa các cảnh được xác định trước bằng cách sử dụng tệp XML trong thư mục res/transition/ của dự án. Bên trong một phần tử <transitionManager>, hãy chỉ định một hoặc nhiều thẻ <transition> mà mỗi thẻ chỉ định một cảnh (tham chiếu đến tệp bố cục) và hiệu ứng chuyển đổi sẽ áp dụng khi vào và/hoặc thoát khỏi cảnh đó. Sau đó, tăng cường tập hợp hiệu ứng chuyển đổi này bằng inflateTransitionManager(). Sử dụng TransitionManager được trả về để thực thi từng hiệu ứng chuyển đổi bằng transitionTo(), truyền một Scene được biểu thị bằng một trong các thẻ <transition>. Bạn cũng có thể xác định các nhóm hiệu ứng chuyển đổi theo phương thức lập trình bằng các API TransitionManager.

Khi chỉ định hiệu ứng chuyển đổi, bạn có thể dùng một số loại định sẵn được xác định bằng các lớp con của Transition, chẳng hạn như FadeChangeBounds. Nếu bạn không chỉ định loại chuyển đổi, hệ thống sẽ sử dụng AutoTransition theo mặc định để tự động làm mờ, di chuyển và đổi kích thước khung hiển thị khi cần. Ngoài ra, bạn có thể tạo hiệu ứng chuyển đổi tuỳ chỉnh bằng cách mở rộng bất kỳ lớp nào trong số này để thực hiện ảnh động theo ý muốn. Hiệu ứng chuyển đổi tuỳ chỉnh có thể theo dõi mọi thay đổi về thuộc tính mà bạn muốn và tạo bất kỳ ảnh động nào bạn muốn dựa trên các thay đổi đó. Ví dụ: bạn có thể cung cấp một lớp con của Transition giúp theo dõi các thay đổi đối với thuộc tính "rotation" của khung hiển thị, sau đó tạo ảnh động cho mọi thay đổi.

Để biết thêm thông tin, hãy xem tài liệu TransitionManager.

Tạm dừng trình tạo hình động

API Animator hiện cho phép bạn tạm dừng và tiếp tục ảnh động đang diễn ra bằng các phương thức pause()resume().

Để theo dõi trạng thái của ảnh động, bạn có thể triển khai giao diện Animator.AnimatorPauseListener. Giao diện này cung cấp lệnh gọi lại khi một ảnh động tạm dừng và tiếp tục: pause()resume(). Sau đó, thêm trình nghe vào đối tượng Animator bằng addPauseListener().

Ngoài ra, bạn có thể phân lớp con của lớp trừu tượng AnimatorListenerAdapter, hiện bao gồm các phương thức triển khai trống cho các lệnh gọi lại tạm dừng và tiếp tục do Animator.AnimatorPauseListener xác định.

bitmap có thể sử dụng lại

Giờ đây, bạn có thể sử dụng lại bất kỳ bitmap có thể thay đổi nào trong BitmapFactory để giải mã bất kỳ bitmap nào khác, ngay cả khi bitmap mới có kích thước khác, miễn là số byte nhận được của bitmap đã giải mã (có từ getByteCount()) nhỏ hơn hoặc bằng số lượng byte được phân bổ của bitmap tái sử dụng (có từ getAllocationByteCount(). Để biết thêm thông tin, hãy xem inBitmap.

Các API mới của Bitmap cho phép định cấu hình lại tương tự để sử dụng lại bên ngoài BitmapFactory (để tạo bitmap thủ công hoặc logic giải mã tuỳ chỉnh). Giờ đây, bạn có thể đặt kích thước của bitmap bằng các phương thức setHeight()setWidth(), đồng thời chỉ định một Bitmap.Config mới bằng setConfig() mà không ảnh hưởng đến hoạt động phân bổ bitmap cơ bản. Phương thức reconfigure() cũng cung cấp một cách thuận tiện để kết hợp các thay đổi này bằng một lệnh gọi.

Tuy nhiên, bạn không nên định cấu hình lại một bitmap hiện đang được hệ thống khung hiển thị sử dụng, vì vùng đệm pixel cơ bản sẽ không được ánh xạ lại theo cách có thể dự đoán được.

Nội dung của người dùng

Khung truy cập bộ nhớ

Trên các phiên bản Android trước, nếu bạn muốn ứng dụng của mình truy xuất một loại tệp cụ thể từ một ứng dụng khác, ứng dụng đó phải gọi một ý định bằng thao tác ACTION_GET_CONTENT. Thao tác này vẫn là cách thích hợp để yêu cầu một tệp bạn muốn nhập vào ứng dụng. Tuy nhiên, Android 4.4 ra mắt thao tác ACTION_OPEN_DOCUMENT, cho phép người dùng chọn một tệp thuộc loại cụ thể và cấp cho ứng dụng của bạn quyền đọc dài hạn đối với tệp đó (có thể có quyền ghi) mà không cần nhập tệp vào ứng dụng của bạn.

Nếu đang phát triển một ứng dụng cung cấp dịch vụ lưu trữ cho tệp (chẳng hạn như dịch vụ lưu vào đám mây), thì bạn có thể tham gia giao diện người dùng hợp nhất này để chọn tệp bằng cách triển khai một nhà cung cấp nội dung làm lớp con của lớp DocumentsProvider mới. Lớp con của DocumentsProvider phải có một bộ lọc ý định chấp nhận thao tác PROVIDER_INTERFACE ("android.content.action.DOCUMENTS_PROVIDER"). Sau đó, bạn phải triển khai 4 phương thức trừu tượng trong DocumentsProvider:

queryRoots()
Hàm này phải trả về Cursor mô tả tất cả thư mục gốc của bộ nhớ tài liệu, sử dụng các cột được xác định trong DocumentsContract.Root.
queryChildDocuments()
Hàm này phải trả về Cursor mô tả tất cả các tệp trong thư mục được chỉ định, sử dụng các cột được xác định trong DocumentsContract.Document.
queryDocument()
Hàm này phải trả về Cursor mô tả tệp cụ thể, sử dụng các cột được xác định trong DocumentsContract.Document.
openDocument()
Hàm này phải trả về ParcelFileDescriptor đại diện cho tệp đã chỉ định. Hệ thống gọi phương thức này sau khi người dùng chọn một tệp và ứng dụng khách yêu cầu quyền truy cập vào tệp đó bằng cách gọi openFileDescriptor().

Để biết thêm thông tin, hãy xem hướng dẫn về Khung truy cập bộ nhớ.

Quyền truy cập vào bộ nhớ ngoài

Giờ đây, bạn có thể đọc và ghi các tệp dành riêng cho ứng dụng trên phương tiện bộ nhớ ngoài phụ, chẳng hạn như khi một thiết bị cung cấp cả bộ nhớ được mô phỏng và thẻ SD. Phương thức mới getExternalFilesDirs() hoạt động giống như phương thức getExternalFilesDir() hiện có, ngoại trừ phương thức trả về một mảng gồm các đối tượng File. Trước khi đọc hoặc ghi vào bất kỳ đường dẫn nào mà phương thức này trả về, hãy truyền đối tượng File vào phương thức getStorageState() mới để xác minh bộ nhớ hiện có sẵn.

Các phương thức khác để truy cập vào thư mục bộ nhớ đệm dành riêng cho ứng dụng và thư mục OBB hiện cũng có các phiên bản tương ứng cung cấp quyền truy cập vào các thiết bị lưu trữ phụ: getExternalCacheDirs()getObbDirs() tương ứng.

Mục nhập đầu tiên trong mảng File được trả về được coi là bộ nhớ ngoài chính của thiết bị, giống với File mà các phương thức hiện có như getExternalFilesDir() trả về.

Lưu ý: Kể từ Android 4.4, nền tảng này không còn yêu cầu ứng dụng của bạn phải có WRITE_EXTERNAL_STORAGE hoặc READ_EXTERNAL_STORAGE khi bạn chỉ cần truy cập vào các khu vực dành riêng cho ứng dụng của bộ nhớ ngoài bằng các phương thức trên. Tuy nhiên, bạn cần có quyền nếu muốn truy cập vào các khu vực có thể chia sẻ của bộ nhớ ngoài, do getExternalStoragePublicDirectory() cung cấp.

Bộ điều hợp đồng bộ hoá

Phương thức requestSync() mới trong ContentResolver giúp đơn giản hoá một số quy trình để xác định yêu cầu đồng bộ hoá cho ContentProvider bằng cách đóng gói các yêu cầu trong đối tượng SyncRequest mới mà bạn có thể tạo bằng SyncRequest.Builder. Các thuộc tính trong SyncRequest cung cấp chức năng giống như các lệnh gọi đồng bộ hoá ContentProvider hiện có nhưng thêm khả năng chỉ định việc sẽ đồng bộ hoá nếu mạng được đo lượng dữ liệu, bằng cách bật setDisallowMetered().

Dữ liệu do người dùng nhập

Các loại cảm biến mới

Cảm biến TYPE_GEOMAGNETIC_ROTATION_VECTOR mới cung cấp dữ liệu vectơ xoay dựa trên từ kế. Đây là một giải pháp thay thế hữu ích cho cảm biến TYPE_ROTATION_VECTOR khi không có con quay hồi chuyển hoặc khi được dùng cùng với các sự kiện cảm biến theo lô để ghi lại hướng của thiết bị trong khi điện thoại ở chế độ ngủ. Cảm biến này cần ít pin hơn TYPE_ROTATION_VECTOR, nhưng có thể dễ thu thập dữ liệu sự kiện ồn và hoạt động hiệu quả nhất khi người dùng đang ở ngoài trời.

Android hiện cũng hỗ trợ cảm biến bước tích hợp sẵn trong phần cứng:

TYPE_STEP_DETECTOR
Cảm biến này kích hoạt một sự kiện mỗi khi người dùng thực hiện một bước. Sau mỗi bước của người dùng, cảm biến này sẽ cung cấp một sự kiện có giá trị là 1 và dấu thời gian cho biết thời điểm bước đó diễn ra.
TYPE_STEP_COUNTER
Cảm biến này cũng kích hoạt một sự kiện mỗi bước được phát hiện, nhưng lại cung cấp tổng số bước được tích luỹ kể từ lần đầu tiên cảm biến này được một ứng dụng đăng ký.

Hãy lưu ý rằng các cảm biến 2 bước này không phải lúc nào cũng mang lại kết quả giống nhau. Các sự kiện TYPE_STEP_COUNTER xảy ra với độ trễ cao hơn so với các sự kiện từ TYPE_STEP_DETECTOR, nhưng nguyên nhân là do thuật toán TYPE_STEP_COUNTER xử lý nhiều hơn để loại bỏ kết quả dương tính giả. Vì vậy, TYPE_STEP_COUNTER có thể phân phối sự kiện chậm hơn, nhưng kết quả sẽ chính xác hơn.

Cả hai cảm biến bước đều phụ thuộc vào phần cứng (Nexus 5 là thiết bị đầu tiên hỗ trợ cảm biến này). Vì vậy, bạn nên kiểm tra tính sẵn có của hasSystemFeature(), bằng cách sử dụng các hằng số FEATURE_SENSOR_STEP_DETECTORFEATURE_SENSOR_STEP_COUNTER.

Sự kiện cảm biến hàng loạt

Để quản lý hiệu quả hơn nguồn điện của thiết bị, API SensorManager hiện cho phép bạn chỉ định tần suất mà bạn muốn hệ thống gửi các lô sự kiện cảm biến cho ứng dụng của mình. Điều này không làm giảm số sự kiện cảm biến thực tế có sẵn cho ứng dụng trong một khoảng thời gian nhất định, mà làm giảm tần suất hệ thống gọi SensorEventListener bằng bản cập nhật cảm biến. Tức là thay vì cung cấp từng sự kiện đến ứng dụng ngay tại thời điểm sự kiện đó diễn ra, hệ thống sẽ lưu lại mọi sự kiện xảy ra trong một khoảng thời gian, rồi gửi tất cả sự kiện đó đến ứng dụng cùng một lúc.

Để cung cấp tính năng tạo lô, lớp SensorManager thêm 2 phiên bản mới của phương thức registerListener(), cho phép bạn chỉ định "độ trễ tối đa của báo cáo". Tham số mới này chỉ định độ trễ tối đa mà SensorEventListener chấp nhận để gửi các sự kiện cảm biến mới. Ví dụ: nếu bạn chỉ định độ trễ của lô là 1 phút, thì hệ thống sẽ phân phối nhóm sự kiện được phân lô gần đây với khoảng thời gian không quá 1 phút bằng cách thực hiện các lệnh gọi liên tiếp đến phương thức onSensorChanged() – một lần cho mỗi sự kiện được phân lô. Các sự kiện cảm biến sẽ không bao giờ bị trễ lâu hơn giá trị độ trễ tối đa của báo cáo, nhưng có thể đến sớm hơn nếu các ứng dụng khác đã yêu cầu độ trễ ngắn hơn cho cùng một cảm biến.

Tuy nhiên, hãy lưu ý rằng cảm biến sẽ phân phối cho ứng dụng các sự kiện theo lô dựa trên độ trễ của báo cáo chỉ khi CPU đang hoạt động. Mặc dù cảm biến phần cứng hỗ trợ tính năng tạo lô sẽ tiếp tục thu thập các sự kiện cảm biến trong khi CPU ở chế độ ngủ, nhưng cảm biến này sẽ không đánh thức CPU để phân phối các sự kiện được phân lô cho ứng dụng của bạn. Khi hết bộ nhớ cho các sự kiện, cảm biến sẽ bắt đầu loại bỏ các sự kiện cũ nhất để lưu các sự kiện mới nhất. Bạn có thể tránh mất sự kiện bằng cách đánh thức thiết bị trước khi cảm biến lấp đầy bộ nhớ, sau đó gọi flush() để ghi lại lô sự kiện mới nhất. Để ước tính thời điểm bộ nhớ đầy và sẽ được đẩy xuống, hãy gọi getFifoMaxEventCount() để nhận số sự kiện cảm biến tối đa có thể lưu rồi chia số đó cho tốc độ mà ứng dụng của bạn mong muốn đối với mỗi sự kiện. Sử dụng phép tính đó để đặt chuông báo thức bằng AlarmManager gọi Service (triển khai SensorEventListener) để xả cảm biến.

Lưu ý: Không phải thiết bị nào cũng hỗ trợ việc phân lô sự kiện cảm biến theo lô vì tính năng này cần được cảm biến phần cứng hỗ trợ. Tuy nhiên, kể từ Android 4.4, bạn phải luôn sử dụng các phương thức registerListener() mới vì nếu thiết bị không hỗ trợ tính năng tạo lô, thì hệ thống sẽ linh hoạt bỏ qua đối số độ trễ của lô và phân phối các sự kiện cảm biến theo thời gian thực.

Danh tính tay điều khiển

Android giờ đây xác định từng tay điều khiển đã kết nối bằng một số nguyên duy nhất mà bạn có thể truy vấn bằng getControllerNumber(). Điều này giúp bạn dễ dàng liên kết mỗi tay điều khiển với một người chơi khác trong trò chơi. Số lượng tay điều khiển có thể thay đổi do người dùng bị ngắt kết nối, kết nối hoặc định cấu hình lại. Vì vậy, bạn nên theo dõi xem số tay điều khiển nào tương ứng với từng thiết bị đầu vào bằng cách đăng ký một thực thể của InputManager.InputDeviceListener. Sau đó, hãy gọi getControllerNumber() cho mỗi InputDevice khi có thay đổi.

Giờ đây, thiết bị đã kết nối cũng cung cấp mã sản phẩm và mã nhà cung cấp có trong getProductId()getVendorId(). Nếu cần sửa đổi sơ đồ phím dựa trên bộ phím có sẵn trên thiết bị, bạn có thể truy vấn thiết bị để kiểm tra xem hasKeys(int...) có dùng được một số phím nhất định hay không.

Giao diện người dùng

Chế độ toàn màn hình sống động

Để cung cấp cho ứng dụng một bố cục lấp đầy toàn bộ màn hình, cờ SYSTEM_UI_FLAG_IMMERSIVE mới cho setSystemUiVisibility() (khi được kết hợp với SYSTEM_UI_FLAG_HIDE_NAVIGATION) sẽ bật chế độ toàn màn hình immersed mới. Khi chế độ toàn màn hình sống động được bật, hoạt động của bạn sẽ tiếp tục nhận được tất cả các sự kiện chạm. Người dùng có thể hiển thị các thanh hệ thống bằng cách vuốt vào trong dọc theo khu vực mà các thanh hệ thống thường xuất hiện. Thao tác này sẽ xoá cờ SYSTEM_UI_FLAG_HIDE_NAVIGATION (và cờ SYSTEM_UI_FLAG_FULLSCREEN, nếu được áp dụng) để các thanh hệ thống vẫn hiển thị. Tuy nhiên, nếu muốn các thanh hệ thống ẩn lại sau vài giây, bạn có thể sử dụng cờ SYSTEM_UI_FLAG_IMMERSIVE_STICKY.

Thanh hệ thống mờ

Giờ đây, bạn có thể làm cho các thanh hệ thống trong suốt một phần với các giao diện mới, Theme.Holo.NoActionBar.TranslucentDecorTheme.Holo.Light.NoActionBar.TranslucentDecor. Khi bật thanh hệ thống mờ, bố cục của bạn sẽ lấp đầy khu vực phía sau các thanh hệ thống. Vì vậy, bạn cũng phải bật fitsSystemWindows cho phần bố cục không bị các thanh hệ thống che phủ.

Nếu bạn đang tạo một giao diện tuỳ chỉnh, hãy đặt một trong các giao diện này làm giao diện mẹ hoặc thêm các thuộc tính kiểu windowTranslucentNavigationwindowTranslucentStatus vào giao diện của bạn.

Trình nghe thông báo nâng cao

Android 4.3 đã thêm các API NotificationListenerService, cho phép ứng dụng nhận thông tin về thông báo mới khi thông báo mới được hệ thống đăng. Trong Android 4.4, trình nghe thông báo có thể truy xuất siêu dữ liệu bổ sung cho thông báo và đầy đủ thông tin chi tiết về các hành động của thông báo:

Trường Notification.extras mới bao gồm Bundle để cung cấp siêu dữ liệu bổ sung cho trình tạo thông báo như EXTRA_TITLEEXTRA_PICTURE. Lớp Notification.Action mới định nghĩa các đặc điểm của hành động đính kèm với thông báo mà bạn có thể truy xuất từ trường actions mới.

Phản chiếu đối tượng có thể vẽ cho bố cục RTL

Trên các phiên bản Android trước, nếu ứng dụng của bạn có các hình ảnh đảo ngược hướng ngang để có bố cục từ phải sang trái, thì bạn phải đưa hình ảnh được phản chiếu vào thư mục tài nguyên drawables-ldrtl/. Giờ đây, hệ thống có thể tự động phản chiếu hình ảnh cho bạn bằng cách bật thuộc tính autoMirrored trên tài nguyên có thể vẽ hoặc bằng cách gọi setAutoMirrored(). Khi được bật, Drawable sẽ tự động được phản chiếu khi hướng bố cục từ phải sang trái.

Hỗ trợ tiếp cận

Lớp View hiện cho phép bạn khai báo "khu vực trực tiếp" cho các phần trên giao diện người dùng cập nhật động theo nội dung văn bản mới, bằng cách thêm thuộc tính accessibilityLiveRegion mới vào bố cục XML hoặc gọi setAccessibilityLiveRegion(). Ví dụ: màn hình đăng nhập có trường văn bản hiển thị thông báo "mật khẩu không đúng" phải được đánh dấu là khu vực trực tiếp để trình đọc màn hình đọc lại thông báo khi thông báo thay đổi.

Giờ đây, các ứng dụng cung cấp dịch vụ hỗ trợ tiếp cận cũng có thể nâng cao chức năng bằng các API mới cung cấp thông tin về các bộ sưu tập khung hiển thị, chẳng hạn như khung hiển thị danh sách hoặc khung hiển thị lưới bằng AccessibilityNodeInfo.CollectionInfoAccessibilityNodeInfo.CollectionItemInfo.

Quyền cho ứng dụng

Sau đây là các quyền mới mà ứng dụng của bạn phải yêu cầu bằng thẻ <uses-permission> để sử dụng một số API mới:

INSTALL_SHORTCUT
Cho phép ứng dụng cài đặt lối tắt trong Trình chạy
UNINSTALL_SHORTCUT
Cho phép ứng dụng gỡ cài đặt lối tắt trong Trình chạy
TRANSMIT_IR
Cho phép ứng dụng sử dụng bộ phát IR của thiết bị (nếu có)

Lưu ý: Kể từ Android 4.4, nền tảng này không còn yêu cầu ứng dụng của bạn phải có WRITE_EXTERNAL_STORAGE hoặc READ_EXTERNAL_STORAGE khi bạn muốn truy cập vào các khu vực dành riêng cho ứng dụng của bộ nhớ ngoài bằng các phương thức như getExternalFilesDir(). Tuy nhiên, bạn vẫn cần có quyền nếu muốn truy cập vào các khu vực có thể chia sẻ của bộ nhớ ngoài, do getExternalStoragePublicDirectory() cung cấp.

Tính năng của thiết bị

Sau đây là các tính năng mới của thiết bị mà bạn có thể khai báo bằng thẻ <uses-feature> để khai báo các yêu cầu đối với ứng dụng và bật tính năng lọc trên Google Play hoặc kiểm tra trong thời gian chạy:

FEATURE_CONSUMER_IR
Thiết bị này có thể giao tiếp với các thiết bị điện tử tiêu dùng hồng ngoại.
FEATURE_DEVICE_ADMIN
Thiết bị hỗ trợ thực thi chính sách thiết bị thông qua quản trị viên thiết bị.
FEATURE_NFC_HOST_CARD_EMULATION
Thiết bị hỗ trợ quy trình mô phỏng thẻ NFC dựa trên máy chủ.
FEATURE_SENSOR_STEP_COUNTER
Thiết bị có bộ đếm bước phần cứng.
FEATURE_SENSOR_STEP_DETECTOR
Thiết bị có trình phát hiện bước phần cứng.

Để biết thông tin chi tiết về tất cả các thay đổi về API trong Android 4.4, hãy xem Báo cáo điểm khác biệt về API.