API Android 4.4

Cấp độ API: 19

Android 4.4 (KITKAT) là một bản phát hành mới 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 về 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 Android 4.4 và nền tảng SDK xuống từ 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 hình ảnh hệ thống Android 4.4 để kiểm thử ứng dụng trên trình mô phỏng Android. Sau đó, hãy tạo ứng dụng 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

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

Bạn có thể sử dụng các API trong Android 4.4 mà vẫn hỗ trợ các phiên bản cũ bằng cách thêm các điều kiện vào mã để kiểm tra cấp độ API của hệ thống trước khi thực thi các API không được minSdkVersion 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 bài viết 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ì?

Những thay đổi quan trọng về hành vi

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

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 dùng chung trên bộ nhớ ngoài khi chạy trên Android 4.4, trừ phi ứng dụng của bạn có quyền READ_EXTERNAL_STORAGE. Tức là bạn không thể truy cập vào các tệp trong thư mục do getExternalStoragePublicDirectory() trả về 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 sử dụng WebView...

Ứng dụng của bạn có thể hoạt động 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ơ bản của 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. Điều này mang lại nhiều điểm cải tiến về hiệu suất, hỗ trợ các tính năng HTML5 mới và hỗ trợ gỡ lỗi từ xa cho nội dung WebView. 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ì hành vi của ứng dụng đó có thể bị ảnh hưởng trong một số trường hợp. Mặc dù các thay đổi về hành vi đã biết được ghi nhận và chủ yếu 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, nhưng WebView mới hoạt động ở "chế độ kỳ quặc" để cung cấp một số chức năng cũ trong các ứng dụng nhắm đến API cấp 18 trở xuống. Vì vậy, có thể ứng dụng của bạn phụ thuộc vào các hành vi không xác định từ 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 kiểm thử 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ề mức độ ảnh hưởng của việc cập nhật targetSdkVersion lên "19" trở lên đối với ứng dụng của bạ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, 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 suất pin, Android hiện gộp các chuông báo từ tất cả ứng dụng xảy ra ở những thời điểm tương tự nhau để hệ thống đá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 không liên kết với thời gian đồng hồ chính xác, nhưng điều quan trọng là chuông báo phải được gọi trong một phạm vi 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 gian "sớm nhất" cho chuông báo và "khoảng thời gian" sau thời gian sớm nhất mà hệ thống sẽ gọi chuông báo.

Nếu chuông báo phải được ghim vào thời gian 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 chế độ đồng bộ hoá với addPeriodicSync() sẽ thực hiện các thao tác đồng bộ hoá trong khoảng thời gian linh hoạt mặc định khoảng 4% của khoảng thời gian 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ó thể diễn ra trong khoảng thời gian một giờ mỗi ngày, thay vì vào cùng một thời điểm mỗi ngày.

Để chỉ định khoảng thời gian linh hoạt của riêng mình cho các thao tác đồ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ề Trình chuyển đổi đồ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, thì các yêu cầu đồng bộ hoá hiện tại 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.

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 được kết nối qua Wi-Fi, Bluetooth hoặc các dịch vụ khác. Hệ thống 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ụ phân phối công việc in đến máy in. Khung android.print cung cấp tất cả các API cần thiết để chỉ định một tài liệu in và phân phối tài liệu đó cho hệ thống để in. API nào bạn thực sự cần cho một công việc in cụ thể phụ 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 từ 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 vài phương thức gọi lại, bao gồm 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 truyền tệp PDF vào đó. API PdfDocument mới cung cấp một cách thuận tiện để thực hiện việc này bằng cách cung cấp Canvas từ getCanvas(), trên đó bạn có thể vẽ nội dung có thể in. Sau đó, ghi PdfDocument vào ParcelFileDescriptor bằng phương thức writeTo().

Sau khi xác định cách triển khai cho PrintDocumentAdapter, bạn có thể thực thi các công việc 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(), trong đó lấy PrintDocumentAdapter làm một trong các đối số.

In hình ảnh

Nếu bạn chỉ muốn in một bức ảnh hoặc bitmap khác, thì các API trợ giúp trong thư viện hỗ trợ sẽ thực hiện 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 vào printBitmap(). Vậy là xong. Thư viện này xử lý mọi hoạt động tương tác còn lại với hệ thống để phân phối bitmap cho máy in.

Xây dựng dịch vụ in

Là nhà sản xuất thiết bị gốc (OEM) của 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 của mình từ các thiết bị Android. Bạn có thể tạo 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 chủ yếu hoạt động như một dịch vụ không có giao diện người dùng bằng cách phân lớp con cho lớp PrintService. Lớp này nhận các công việc in từ hệ thống và giao tiếp các công việc đó với máy in bằng các 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ị. Trang này bao gồm các bảng cho tin nhắn SMS và MMS đã nhận, đã soạn, đã gửi, đang chờ xử lý, v.v.

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 SMS và chỉ ứng dụng SMS mặc định mới nhận được thông báo truyền tin SMS_DELIVER_ACTION khi người dùng nhận được tin nhắn SMS hoặc thông báo truyền tin 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 vào Trình cung cấp SMS khi nhận hoặc gửi 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 SMS, nhưng cũng có thể được thông báo khi có tin nhắn SMS mới đến bằng cách nghe thông báo truyền tin SMS_RECEIVED_ACTION. Đây là thông báo truyền tin không thể huỷ và có thể được gửi đến nhiều ứng dụng. Thông báo truyền tin này dành cho các ứng dụng (mặc dù 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 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ư được chỉ đị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 một lúc, đồng thời cho phép thiết bị thanh toán NFC hoặc trình đọc NFC khác bắt đầu giao dịch bằng thẻ NFC thích 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. Trong khi đó, nếu ứng dụng của bạn sử dụng một phần tử bảo mật để mô phỏng 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 thiết để đăng ký các AID mà phần tử bảo mật sẽ 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ế độ trình đọc NFC mới cho phép một hoạt động hạn chế tất cả hoạt động NFC chỉ đọc các loại thẻ mà hoạt động đó quan tâm trong khi ở nền trước. Bạn có thể bật chế độ trình đọc cho hoạt động của mình bằng enableReaderMode(), cung cấp cách triển khai NfcAdapter.ReaderCallback để nhận lệnh gọi lại khi phát hiện thẻ mới.

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

Bộ phát hồng ngoại

Khi chạy trên một thiết bị có bộ phát hồng ngoại (IR), giờ đây, bạn có thể truyền tín hiệu hồng ngoại bằng các API ConsumerIrManager. Để lấy 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 hồng ngoại 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 hồng ngoại, 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).

Đa phương tiện

Phát thích ứng

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

Bạn có thể bật tính năng phát thích ứng bằng cách thêm hai khoá vào MediaFormat để chỉ định độ phân giải tối đa mà ứng dụng yêu cầu từ bộ mã hoá và giải mã: KEY_MAX_WIDTHKEY_MAX_HEIGHT. Khi thêm các thành phần này vào MediaFormat, hãy truyền MediaFormat đến 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ợ độ phân giải lớn hơn độ phân giải tối đa được chỉ định (miễn là độ phân giải đó nằm trong giới hạn của hồ sơ được hỗ trợ), nhưng quá trình 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 đưa các khung hình vào hàng đợi bằng MediaCodec.queueInputBuffer(), nhưng hãy đảm bảo rằng bạn cung cấp các giá trị mới của Tập hợp tham số trình tự (SPS) và Tập hợp tham số hình ảnh (PPS) cùng với khung hình làm mới bộ giải mã tức thì (IDR) trong một vùng đệm.

Tuy nhiên, trước khi định cấu hình bộ mã hoá và giải mã để 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 ý: Việc hỗ trợ tính năng phát thích ứng tuỳ thuộc vào nhà cung cấp. Một số bộ mã hoá và giải mã có thể yêu cầu nhiều bộ nhớ hơn cho các gợi ý độ 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

Để hỗ trợ đồ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" cụ thể trong luồng âm thanh do AudioTrack xử lý. Để lấy dấu thời gian gần đây nhất, hãy tạo thực thể cho đối tượng AudioTimestamp và 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 bằng một vị trí trong đơn vị khung, cùng với thời gian ước tính khi khung đó được hiển thị hoặc được cam kết hiển thị.

Bạn có thể sử dụng giá trị của nanoTime trong AudioTimestamp (giá trị tăng dần) để tìm khung hình video được liên kết gần nhất so với framePosition. Nhờ đó, bạn có thể thả, sao chép hoặc nội suy khung hình video để 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ó tính đến tốc độ lấy mẫu) để dự đoán khung hình âm thanh nào sẽ xuất hiện cùng lúc với khung hình video.

Trình đọc hình ảnh trên bề mặt

API ImageReader mới cung cấp cho bạn quyền truy cập trực tiếp vào vùng đệm hình ảnh khi các vùng đệm này được kết xuất thành 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 một Surface mới và phân phối dữ liệu hình ảnh bằng 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 giao diện, 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 xuất hiện, cung cấp cho bạn ImageReader tương ứng. Bạn có thể sử dụng ImageReader để thu thập 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, bạn phải định dạng hình ảnh theo một trong các loại do hằng số xác định trong ImageFormat hoặc PixelFormat.

Đo lường đỉnh và RMS

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

Tăng âm lượng

LoudnessEnhancer là một lớp con mới của AudioEffect cho phép bạn tăng âm lượng của MediaPlayer hoặc AudioTrack. Điều này có thể đặc biệt hữu ích khi kết hợp với phương thức getMeasurementPeakRms() mới được đề cập ở trên, để tăng âm lượng của các bản âm thanh có lời 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 đa phương tiện từ các ứng dụng từ xa, chẳng hạn như các chế độ điều khiển nội dung đa phương tiện trên màn hình khoá. Giờ đây, các API RemoteController mới cho phép bạn tạo trình điều khiển từ xa của riêng mình, cho phép tạo các ứng dụng và thiết bị ngoại vi mới, sáng tạo có thể kiểm soát việc phát của bất kỳ ứng dụng đa phương tiện nào tích hợp với RemoteControlClient.

Để tạo một tay đ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 bạn muốn, nhưng để phân phối các sự kiện nút đa phương tiện đến ứ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ở là rất quan trọng vì lớp này cung cấp các quy định hạn chế quyền riêng tư thích hợp, yêu cầu người dùng 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 vài 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 của trình điều khiển nội dung nghe nhìn để xử lý chế độ phát nội dung nghe nhìn, bạn có thể để trống phương thức triển khai cho các sự kiện đó và tập trung vào các phương thức RemoteController.OnClientUpdateListener.

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

Android 4.4 xây dựng dựa trên các chức năng hiện có cho ứng dụng điều khiển từ xa (ứng dụng nhận sự kiện điều khiển nội dung đa phương tiện bằng RemoteControlClient) bằng cách thêm chức năng cho phép người dùng đánh giá bản nhạc hiện tại từ bộ điều khiển từ xa.

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

Cách cho phép người dùng đánh giá các bản nhạc của bạn từ đ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 từ tay đ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 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ụ đề WebVTT khi phát video Luồng phát trực tuyến dựa trên HTTP (HLS), hiển thị bản phụ đề theo lựa chọn ưu tiên về 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 VideoView bằng các kênh phụ đề WebVTT bằng cách sử dụng phương thức addSubtitleSource(). Phương thức này chấp nhận 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 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, bạn nên làm cho lớp phủ phụ đề khớp với lựa chọn ưu tiên về phụ đề của người dùng càng gần càng tốt. 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 sắc. Trong trường hợp người dùng điều chỉnh một số lựa chọn ưu tiên sau khi video của bạn đã bắt đầu, bạn nên theo dõi các thay đổi đối với lựa chọn ưu tiên bằng cách đăng ký một thực thể của CaptioningManager.CaptioningChangeListener để nhận lệnh gọi lại khi có bất kỳ lựa chọn ưu tiên nào 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 các trạng thái khác nhau của giao diện người dùng. Một tính năng chính là khả năng xác định các trạng thái riêng biệt của giao diện người dùng, được 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 ảnh động từ cảnh này sang cảnh khác, hãy thực thi một "hiệu ứng chuyển đổi". Hiệu ứng này sẽ 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, bạn thường 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 hiệu ứng chuyển đổi sẽ tạo ảnh động cho thay đổi về bố cục.
  4. Thực thi quá trình 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ả thành phần hiển thị mẹ của cảnh 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 thành các bước 3 và 4. Một cách là truyền Scene vào phương thức tĩnh go(). Thao tác này sẽ tìm thành phần hiển thị mẹ của cảnh trong bố cục hiện tại và thực hiện quá trình chuyển đổi trên các thành phần hiển thị con để chuyển đến bố cục do Scene xác định.

Ngoài ra, bạn không cần tạo đối tượng Scene mà có thể gọi beginDelayedTransition(), chỉ định ViewGroup chứa các thành phần 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 thành phần hiển thị 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 thành phần hiển thị bị ảnh hưởng.

Để có thêm quyền kiểm soát, bạn có thể xác định các nhóm hiệu ứng chuyển đổi sẽ xảy 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 phần tử <transitionManager>, hãy chỉ định một hoặc nhiều thẻ <transition>, mỗi thẻ chỉ định một cảnh (một tệp tham chiếu đến bố cục) và hiệu ứng chuyển đổi để áp dụng khi vào và/hoặc thoát khỏi cảnh đó. Sau đó, hãy tăng cường nhóm 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 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 chuyển đổi theo phương thức lập trình bằng API TransitionManager.

Khi chỉ định một hiệu ứng chuyển đổi, bạn có thể sử dụng một số loại được xác định trước do các lớp con của Transition xác định, chẳng hạn như FadeChangeBounds. Nếu bạn không chỉ định loại chuyển đổi, thì theo mặc định, hệ thống sẽ sử dụng AutoTransition. Loại chuyển đổi này sẽ tự động làm mờ, di chuyển và đổi kích thước thành phần hiển thị nếu 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 mọi ảnh động mà bạn muốn dựa trên những thay đổi đó. Ví dụ: bạn có thể cung cấp một lớp con của Transition để theo dõi các thay đổi đối với thuộc tính "rotation" (xoay) của một thành phần 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 về TransitionManager.

Tạm dừng ảnh động

Giờ đây, API Animator 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 ảnh động bị 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ể tạo lớp con cho lớp trừu tượng AnimatorListenerAdapter. Lớp này hiện bao gồm các phương thức triển khai trống cho 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 nào có thể thay đổi 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 kết quả của bitmap đã giải mã (có trong getByteCount()) nhỏ hơn hoặc bằng số byte được phân bổ của bitmap được sử dụng lại (có trong getAllocationByteCount(). Để biết thêm thông tin, hãy xem inBitmap.

Các API mới cho 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 theo cách 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 Bitmap.Config mới bằng setConfig() mà không ảnh hưởng đến quá trình 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 bitmap mà hệ thống thành phần hiển thị hiện đang 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.

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 truy xuất một loại tệp cụ thể từ một ứng dụng khác, thì ứ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 mà 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 một loại cụ thể và cấp cho ứng dụng 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.

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), 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 nhà cung cấp nội dung dưới dạng lớp con của lớp DocumentsProvider mới. Lớp con của DocumentsProvider phải bao gồm một bộ lọc ý định chấp nhận hành động 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ề một 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()
Thao tác này phải trả về một Cursor mô tả tất cả các tệp trong thư mụ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ề một Cursor mô tả tệp được chỉ định, sử dụng các cột được xác định trong DocumentsContract.Document.
openDocument()
Phương thức này phải trả về một 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ừ việc phương thức này trả về một mảng các đối tượng File. Trước khi đọc hoặc ghi vào bất kỳ đường dẫn nào do 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ó.

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 thiết bị bộ nhớ phụ: getExternalCacheDirs()getObbDirs() tương ứng.

Mục đầ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 như File do các phương thức hiện có trả về, chẳng hạn như getExternalFilesDir().

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 vùng bộ nhớ ngoài dành riêng cho ứng dụng bằng các phương thức ở trên. Tuy nhiên, bạn cần có các quyền này nếu muốn truy cập vào các vùng 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 đơ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 tương tự như các lệnh gọi đồng bộ hoá ContentProvider hiện có, nhưng thêm khả năng chỉ định rằng một quá trình đồng bộ hoá sẽ bị loại bỏ 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 sử dụng với 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 đang ở chế độ ngủ. Cảm biến này tiêu thụ ít năng lượng hơn TYPE_ROTATION_VECTOR, nhưng có thể dễ bị nhiễu dữ liệu sự kiện và hiệu quả nhất khi người dùng ở ngoài trời.

Android hiện cũng hỗ trợ cảm biến bước tích hợp 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. Mỗi khi người dùng thực hiện một bước, cảm biến này sẽ phân phối một sự kiện có giá trị là 1.0 và dấu thời gian cho biết thời điểm xảy ra bước đó.
TYPE_STEP_COUNTER
Cảm biến này cũng kích hoạt một sự kiện cho mỗi bước được phát hiện, nhưng thay vào đó, cảm biến này sẽ cung cấp tổng số bước tích luỹ kể từ lần đầu tiên một ứng dụng đăng ký cảm biến này.

Xin lưu ý rằng hai cảm biến bước này không phải lúc nào cũng đưa ra 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 đó 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ể chậm hơn trong việc phân phối sự kiện, nhưng kết quả của nó 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ác cảm biến này), vì vậy, bạn nên kiểm tra khả năng sử dụng với hasSystemFeature() bằng cách sử dụng hằng số FEATURE_SENSOR_STEP_DETECTORFEATURE_SENSOR_STEP_COUNTER.

Sự kiện cảm biến theo lô

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

Để cung cấp tính năng xử lý hàng loạt, lớp SensorManager sẽ thêm hai phiên bản mới của phương thức registerListener() cho phép bạn chỉ định "độ trễ báo cáo tối đa". Thông số mới này chỉ định độ trễ tối đa mà SensorEventListener của bạn sẽ chấp nhận để phân phối các sự kiện cảm biến mới. Ví dụ: nếu bạn chỉ định độ trễ theo lô là một phút, hệ thống sẽ phân phối tập hợp sự kiện theo lô gần đây trong khoảng thời gian không quá một 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 thành lô. Các sự kiện cảm biến sẽ không bao giờ bị trễ lâu hơn giá trị độ trễ báo cáo tối đa, 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ủa bạn các sự kiện theo lô dựa trên độ trễ báo cáo chỉ khi CPU đang thức. Mặc dù cảm biến phần cứng hỗ trợ tính năng xử lý hàng loạt sẽ tiếp tục thu thập các sự kiện cảm biến trong khi CPU đang ở trạng thái 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 theo lô cho ứng dụng. Khi hết bộ nhớ cho 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 các 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ớ sẽ đầy và cần được làm mới, hãy gọi getFifoMaxEventCount() để biết số lượng sự kiện cảm biến tối đa mà bộ nhớ có thể lưu, rồi chia số đó cho tốc độ mà ứng dụng của bạn muốn mỗi sự kiện. Sử dụng kết quả tính toán đó để đặt chuông báo thức bằng AlarmManager gọi Service (triển khai SensorEventListener) để xoá cảm biến.

Lưu ý: Không phải thiết bị nào cũng hỗ trợ tính năng gộp các sự kiện cảm biến vì tính năng này yêu cầu cảm biến phần cứng hỗ trợ. Tuy nhiên, bắt đầu 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 xử lý hàng loạt, thì hệ thống sẽ bỏ qua đối số độ trễ hàng loạt và phân phối các sự kiện cảm biến theo thời gian thực.

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

Android hiện 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(), giúp bạn dễ dàng liên kết từng tay điều khiển với một người chơi khác trong trò chơi. Số của mỗi tay điều khiển có thể thay đổi do người dùng ngắt kết nối, kết nối hoặc định cấu hình lại tay điều khiển. Vì vậy, bạn nên theo dõi số tay điều khiển 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, các thiết bị được kết nối cũng cung cấp mã sản phẩm và mã nhà cung cấp có sẵn từ getProductId()getVendorId(). Nếu cần sửa đổi các mối liên kết phím dựa trên tập hợp phím có sẵn trên một thiết bị, bạn có thể truy vấn thiết bị để kiểm tra xem một số phím nhất định có dùng được hasKeys(int...) 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 của bạn 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 kết hợp với SYSTEM_UI_FLAG_HIDE_NAVIGATION) sẽ bật chế độ toàn màn hình thực tế ảo 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 tất 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 phút, bạn có thể sử dụng cờ SYSTEM_UI_FLAG_IMMERSIVE_STICKY.

Thanh hệ thống trong suốt

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

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 đưa 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 hệ thống đăng thông báo. 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à hoàn tất 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 một Bundle để cung cấp thêm siêu dữ liệu cho trình tạo thông báo, chẳng hạn như EXTRA_TITLEEXTRA_PICTURE. Lớp Notification.Action mới xác định các đặc điểm của một hành động được đính kèm vào 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ó hình ảnh cần đảo ngược hướng ngang cho bố cục từ phải sang trái, thì bạn phải đưa hình ảnh 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 bật, Drawable sẽ tự động phản chiếu khi hướng bố cục là 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 "vùng trực tiếp" cho các phần của giao diện người dùng tự động cập nhật bằng 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 sẽ đọc to 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 của mình bằng các API mới cung cấp thông tin về các bộ sưu tập thành phần hiển thị, chẳng hạn như thành phần hiển thị danh sách hoặc lưới bằng cách sử dụng AccessibilityNodeInfo.CollectionInfoAccessibilityNodeInfo.CollectionItemInfo.

Quyền của ứ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 nhất định:

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 hồng ngoại 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 vùng dành riêng cho ứng dụng của mình trong bộ nhớ ngoài bằng các phương thức như getExternalFilesDir(). Tuy nhiên, bạn vẫn cần có các quyền này nếu muốn truy cập vào các vùng 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 của ứ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ị có thể giao tiếp với các thiết bị hồng ngoại dành cho người tiêu dùng.
FEATURE_DEVICE_ADMIN
Thiết bị hỗ trợ việc 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ợ tính năng 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 chân bằng phần cứng.

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