API Android 4.3

Cấp độ API: 18

Android 4.3 (JELLY_BEAN_MR2) là bản cập nhật cho bản phát hành Jelly Bean, 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.3 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.3 để kiểm thử ứng dụng, hãy sử dụng ảnh hệ thống Android 4.3 để 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.3 để 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 hiệu quả hơn cho các thiết bị chạy Android 4.3, bạn nên đặt targetSdkVersion thành "18", cài đặt ứng dụng trên ảnh hệ thống Android 4.3, 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.3 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.

Nhiều API cũng có trong Thư viện hỗ trợ Android cho phép bạn triển khai các tính năng mới trên các phiên bản nền tảng cũ.

Để 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.3 có thể ảnh hưởng đến ứng dụng của bạn.

Nếu ứng dụng của bạn sử dụng ý định ngầm ẩn...

Ứng dụng của bạn có thể hoạt động không chính xác trong môi trường hồ sơ bị hạn chế.

Người dùng trong môi trường hồ sơ bị hạn chế có thể không có sẵn mọi ứng dụng Android tiêu chuẩn. Ví dụ: một hồ sơ bị hạn chế có thể bị tắt trình duyệt web và ứng dụng máy ảnh. Vì vậy, ứng dụng của bạn không nên đưa ra giả định về ứng dụng nào có sẵn, vì nếu bạn gọi startActivity() mà không xác minh xem ứng dụng có sẵn để xử lý Intent hay không, ứng dụng của bạn có thể gặp sự cố trong hồ sơ bị hạn chế.

Khi sử dụng ý định ngầm ẩn, bạn phải luôn xác minh rằng ứng dụng có thể xử lý ý định đó bằng cách gọi resolveActivity() hoặc queryIntentActivities(). Ví dụ:

Kotlin

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()
}

Java

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();
}

Nếu ứng dụng của bạn phụ thuộc vào tài khoản...

Ứng dụng của bạn có thể hoạt động không chính xác trong môi trường hồ sơ bị hạn chế.

Theo mặc định, người dùng trong môi trường hồ sơ bị hạn chế không có quyền truy cập vào tài khoản người dùng. Nếu ứng dụng của bạn phụ thuộc vào một Account, thì ứng dụng của bạn có thể gặp sự cố hoặc hoạt động không mong muốn khi sử dụng ở hồ sơ bị hạn chế.

Nếu bạn hoàn toàn muốn ngăn các hồ sơ bị hạn chế sử dụng ứng dụng của mình vì ứng dụng phụ thuộc vào thông tin tài khoản mang tính nhạy cảm, hãy chỉ định thuộc tính android:requiredAccountType trong phần tử <application> của tệp kê khai.

Nếu muốn cho phép các hồ sơ bị hạn chế tiếp tục dùng ứng dụng của mình ngay cả khi họ không thể tạo tài khoản riêng, thì bạn có thể tắt các tính năng của ứng dụng yêu cầu tài khoản hoặc cho phép hồ sơ bị hạn chế truy cập vào tài khoản do người dùng chính tạo. Để biết thêm thông tin, hãy xem phần dưới đây về Hỗ trợ tài khoản trong hồ sơ bị hạn chế.

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

Video của bạn có thể hiển thị nhỏ hơn trên Android 4.3.

Trên các phiên bản Android trước, tiện ích VideoView đã tính toán không chính xác giá trị "wrap_content" cho layout_heightlayout_width giống với "match_parent". Vì vậy, mặc dù việc sử dụng "wrap_content" cho chiều cao hoặc chiều rộng có thể đã cung cấp bố cục video mong muốn trước đó, nhưng nếu bạn làm như vậy, video có thể sẽ nhỏ hơn nhiều trên Android 4.3 trở lên. Để khắc phục vấn đề này, hãy thay thế "wrap_content" bằng "match_parent" và xác minh rằng video của bạn xuất hiện như mong đợi trên Android 4.3 cũng như trên các phiên bản cũ hơn.

Hồ sơ bị hạn chế

Trên máy tính bảng Android, người dùng hiện có thể tạo hồ sơ bị hạn chế dựa trên người dùng chính. Khi tạo hồ sơ bị hạn chế, người dùng có thể bật các hạn chế như ứng dụng nào được cung cấp cho hồ sơ đó. Bộ API mới trong Android 4.3 cũng cho phép bạn tạo các chế độ cài đặt hạn chế hạt nhỏ cho các ứng dụng mà bạn phát triển. Ví dụ: bằng cách sử dụng các API mới, bạn có thể cho phép người dùng kiểm soát loại nội dung sẽ có trong ứng dụng khi chạy trong môi trường hồ sơ bị hạn chế.

Giao diện người dùng để người dùng kiểm soát các quy tắc hạn chế mà bạn đã tạo được quản lý bằng ứng dụng Cài đặt của hệ thống. Để chế độ cài đặt hạn chế của ứng dụng cho người dùng thấy, bạn phải khai báo các hạn chế mà ứng dụng đưa ra bằng cách tạo một BroadcastReceiver nhận ý định ACTION_GET_RESTRICTION_ENTRIES. Hệ thống sẽ gọi ý định này để truy vấn tất cả ứng dụng về các quy tắc hạn chế hiện có, sau đó tạo giao diện người dùng để cho phép người dùng chính quản lý các quy định hạn chế đối với từng hồ sơ bị hạn chế.

Trong phương thức onReceive() của BroadcastReceiver, bạn phải tạo RestrictionEntry cho từng hạn chế mà ứng dụng đưa ra. Mỗi RestrictionEntry xác định một tiêu đề hạn chế, nội dung mô tả và một trong các kiểu dữ liệu sau:

  • TYPE_BOOLEAN cho một quy tắc hạn chế true hoặc false.
  • TYPE_CHOICE cho một quy tắc hạn chế có nhiều lựa chọn loại trừ lẫn nhau (lựa chọn nút chọn).
  • TYPE_MULTI_SELECT cho một quy định hạn chế có nhiều lựa chọn không loại trừ lẫn nhau (các lựa chọn trong hộp đánh dấu).

Sau đó, bạn đặt tất cả đối tượng RestrictionEntry vào một ArrayList rồi đặt đối tượng đó vào kết quả của broadcast receiver làm giá trị cho phần bổ sung EXTRA_RESTRICTIONS_LIST.

Hệ thống sẽ tạo giao diện người dùng cho các hạn chế của ứng dụng trong ứng dụng Cài đặt và lưu từng hạn chế bằng khoá duy nhất mà bạn đã cung cấp cho mỗi đối tượng RestrictionEntry. Khi người dùng mở ứng dụng, bạn có thể truy vấn mọi hạn chế hiện tại bằng cách gọi getApplicationRestrictions(). Thao tác này sẽ trả về một Bundle chứa các cặp khoá-giá trị cho từng quy tắc hạn chế mà bạn đã xác định bằng các đối tượng RestrictionEntry.

Nếu muốn đưa ra các hạn chế cụ thể hơn không thể xử lý được bằng các giá trị boolean, một lựa chọn và nhiều lựa chọn, thì bạn có thể tạo một hoạt động trong đó người dùng có thể chỉ định các hạn chế và cho phép người dùng mở hoạt động đó từ chế độ cài đặt hạn chế. Trong broadcast receiver của bạn, hãy đưa EXTRA_RESTRICTIONS_INTENT bổ sung vào kết quả Bundle. Phần bổ sung này phải chỉ định một Intent cho biết lớp Activity sẽ khởi chạy (sử dụng phương thức putParcelable() để truyền EXTRA_RESTRICTIONS_INTENT cùng với ý định). Khi người dùng chính nhập hoạt động của bạn để đặt các quy tắc hạn chế tuỳ chỉnh, hoạt động phải trả về một kết quả chứa các giá trị hạn chế trong một dữ liệu bổ sung bằng cách sử dụng khoá EXTRA_RESTRICTIONS_LIST hoặc EXTRA_RESTRICTIONS_BUNDLE, tuỳ thuộc vào việc bạn chỉ định đối tượng RestrictionEntry hay cặp khoá-giá trị tương ứng.

Tài khoản hỗ trợ trong hồ sơ bị hạn chế

Mọi tài khoản được thêm vào người dùng chính đều hoạt động trong hồ sơ bị hạn chế, nhưng theo mặc định, bạn không thể truy cập vào các tài khoản đó qua các API AccountManager. Nếu cố gắng thêm tài khoản bằng AccountManager khi đang ở hồ sơ bị hạn chế, bạn sẽ nhận được kết quả không thành công. Do những hạn chế này, bạn có 3 lựa chọn sau:

  • Cho phép truy cập vào tài khoản của chủ sở hữu từ hồ sơ bị hạn chế.

    Để có quyền truy cập vào một tài khoản từ hồ sơ bị hạn chế, bạn phải thêm thuộc tính android:restrictedAccountType vào thẻ <application>:

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

    Thận trọng: Việc bật thuộc tính này sẽ cấp cho ứng dụng của bạn quyền truy cập vào tài khoản của người dùng chính từ các hồ sơ bị hạn chế. Vì vậy, bạn chỉ nên cho phép việc này nếu thông tin mà ứng dụng của bạn hiển thị không tiết lộ thông tin nhận dạng cá nhân (PII) được coi là nhạy cảm. Chế độ cài đặt hệ thống sẽ thông báo cho người dùng chính rằng ứng dụng của bạn cấp hồ sơ bị hạn chế cho tài khoản của họ. Vì vậy, người dùng phải biết rõ rằng quyền truy cập vào tài khoản rất quan trọng đối với chức năng của ứng dụng. Nếu có thể, bạn cũng nên cung cấp đầy đủ các chế độ kiểm soát hạn chế cho người dùng chính để xác định mức độ truy cập vào tài khoản được cho phép trong ứng dụng của bạn.

  • Tắt một số chức năng khi không thể sửa đổi tài khoản.

    Nếu muốn sử dụng tài khoản nhưng không thực sự cần tài khoản cho chức năng chính của ứng dụng, bạn có thể kiểm tra khả năng sử dụng tài khoản và tắt các tính năng khi không có. Trước tiên, bạn nên kiểm tra xem đã có tài khoản nào chưa. Nếu không, hãy truy vấn xem có thể tạo tài khoản mới hay không bằng cách gọi getUserRestrictions() và kiểm tra thêm DISALLOW_MODIFY_ACCOUNTS trong kết quả. Nếu giá trị là true, thì bạn nên tắt mọi chức năng của ứng dụng yêu cầu quyền truy cập vào tài khoản. Ví dụ:

    Kotlin

    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
    }
    

    Java

    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
    }
    

    Lưu ý: Trong trường hợp này, bạn không nên khai báo bất kỳ thuộc tính mới nào trong tệp kê khai.

  • Tắt ứng dụng khi không thể truy cập vào tài khoản riêng tư.

    Thay vào đó, nếu ứng dụng của bạn không được cung cấp cho các hồ sơ bị hạn chế vì ứng dụng đó phụ thuộc vào thông tin cá nhân nhạy cảm trong một tài khoản (và vì hồ sơ bị hạn chế hiện không thể thêm tài khoản mới), hãy thêm thuộc tính android:requiredAccountType vào thẻ <application>:

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

    Ví dụ: ứng dụng Gmail sử dụng thuộc tính này để tự tắt đối với các hồ sơ bị hạn chế vì email cá nhân của chủ sở hữu sẽ không được cung cấp cho các hồ sơ bị hạn chế.

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

    Bluetooth năng lượng thấp (Sẵn sàng thông minh)

    Android hiện hỗ trợ Bluetooth năng lượng thấp (LE) với các API mới trong android.bluetooth. Với các API mới, bạn có thể tạo ứng dụng Android giao tiếp với các thiết bị ngoại vi Bluetooth năng lượng thấp, chẳng hạn như máy đo nhịp tim và máy đếm bước.

    Vì Bluetooth LE là một tính năng phần cứng không có trên một số thiết bị chạy Android, nên bạn phải khai báo phần tử <uses-feature> cho "android.hardware.bluetooth_le" trong tệp kê khai:

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

    Nếu bạn đã quen thuộc với API Bluetooth cổ điển của Android, hãy lưu ý rằng việc sử dụng API Bluetooth LE có một số điểm khác biệt. Quan trọng nhất là hiện có một lớp BluetoothManager mà bạn nên sử dụng cho một số thao tác cấp cao, chẳng hạn như thu nạp BluetoothAdapter, lấy danh sách thiết bị đã kết nối và kiểm tra trạng thái của thiết bị. Ví dụ: dưới đây là cách bạn sẽ nhận được BluetoothAdapter:

    Kotlin

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

    Java

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

    Để khám phá các thiết bị ngoại vi Bluetooth LE, hãy gọi startLeScan() trên BluetoothAdapter, truyền vào đó phương thức triển khai giao diện BluetoothAdapter.LeScanCallback. Khi bộ chuyển đổi Bluetooth phát hiện thiết bị ngoại vi Bluetooth LE, quá trình triển khai BluetoothAdapter.LeScanCallback của bạn sẽ nhận được lệnh gọi đến phương thức onLeScan(). Phương thức này cung cấp cho bạn một đối tượng BluetoothDevice đại diện cho thiết bị đã phát hiện, giá trị RSSI cho thiết bị và một mảng byte chứa bản ghi quảng cáo của thiết bị.

    Nếu chỉ muốn quét để tìm các loại thiết bị ngoại vi cụ thể, bạn có thể gọi startLeScan() và thêm một mảng các đối tượng UUID chỉ định các dịch vụ GATT mà ứng dụng của bạn hỗ trợ.

    Lưu ý: Bạn chỉ có thể quét tìm thiết bị Bluetooth LE hoặc quét tìm thiết bị Bluetooth cổ điển bằng các API trước. Bạn không thể quét tìm cả thiết bị Bluetooth LE và cổ điển cùng một lúc.

    Sau đó, để kết nối với một thiết bị ngoại vi Bluetooth LE, hãy gọi connectGatt() trên đối tượng BluetoothDevice tương ứng, truyền vào đó phương thức triển khai BluetoothGattCallback. Quá trình triển khai BluetoothGattCallback sẽ nhận các lệnh gọi lại liên quan đến trạng thái kết nối với thiết bị và các sự kiện khác. Chính trong lệnh gọi lại onConnectionStateChange(), bạn có thể bắt đầu giao tiếp với thiết bị nếu phương thức này chuyển STATE_CONNECTED dưới dạng trạng thái mới.

    Để truy cập các tính năng Bluetooth trên thiết bị, ứng dụng của bạn cũng phải yêu cầu một số quyền của người dùng Bluetooth. Để biết thêm thông tin, hãy xem hướng dẫn về API Bluetooth năng lượng thấp.

    Chế độ chỉ quét tìm Wi-Fi

    Khi cố gắng xác định vị trí của người dùng, Android có thể sử dụng Wi-Fi để giúp xác định vị trí bằng cách quét các điểm truy cập lân cận. Tuy nhiên, người dùng thường tắt Wi-Fi để tiết kiệm pin, dẫn đến dữ liệu vị trí kém chính xác hơn. Android hiện có chế độ chỉ quét cho phép Wi-Fi của thiết bị quét các điểm truy cập để giúp lấy thông tin vị trí mà không cần kết nối với điểm truy cập, nhờ đó giúp giảm đáng kể mức sử dụng pin.

    Nếu bạn muốn lấy thông tin vị trí của người dùng nhưng Wi-Fi hiện đang tắt, bạn có thể yêu cầu người dùng bật chế độ chỉ quét tìm Wi-Fi bằng cách gọi startActivity() bằng thao tác ACTION_REQUEST_SCAN_ALWAYS_AVAILABLE.

    Cấu hình Wi-Fi

    API WifiEnterpriseConfig mới cho phép các dịch vụ dành cho doanh nghiệp tự động hoá cấu hình Wi-Fi cho các thiết bị được quản lý.

    Trả lời nhanh cho các cuộc gọi đến

    Kể từ Android 4.0, tính năng "Phản hồi nhanh" cho phép người dùng trả lời các cuộc gọi đến bằng tin nhắn văn bản ngay lập tức mà không cần nhấc máy hoặc mở khoá thiết bị. Trước đây, các tin nhắn nhanh này luôn được ứng dụng Nhắn tin mặc định xử lý. Giờ đây, mọi ứng dụng đều có thể khai báo khả năng xử lý những tin nhắn này bằng cách tạo một Service có bộ lọc ý định cho ACTION_RESPOND_VIA_MESSAGE.

    Khi người dùng trả lời cuộc gọi đến bằng tính năng phản hồi nhanh, ứng dụng Điện thoại sẽ gửi ý định ACTION_RESPOND_VIA_MESSAGE với URI mô tả người nhận (phương thức gọi) và EXTRA_TEXT bổ sung kèm theo tin nhắn mà người dùng muốn gửi. Khi nhận được ý định, dịch vụ của bạn sẽ gửi thông báo và tự dừng lại ngay lập tức (ứng dụng không được hiển thị hoạt động).

    Để nhận được ý định này, bạn phải khai báo quyền SEND_RESPOND_VIA_MESSAGE.

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

    Cải tiến MediaExtractor và MediaCodec

    Android nay giúp bạn dễ dàng viết trình phát Truyền phát thích ứng động của riêng mình qua HTTP (DASH) theo tiêu chuẩn ISO/IEC 23009-1, sử dụng các API hiện có trong MediaCodecMediaExtractor. Khung cơ bản của những API này đã được cập nhật để hỗ trợ phân tích cú pháp các tệp MP4 phân mảnh, nhưng ứng dụng của bạn vẫn chịu trách nhiệm phân tích cú pháp siêu dữ liệu MPD và truyền từng luồng riêng lẻ đến MediaExtractor.

    Nếu bạn muốn sử dụng DASH với nội dung được mã hoá, hãy lưu ý rằng phương thức getSampleCryptoInfo() sẽ trả về siêu dữ liệu MediaCodec.CryptoInfo mô tả cấu trúc của từng mẫu nội dung nghe nhìn được mã hoá. Ngoài ra, phương thức getPsshInfo() đã được thêm vào MediaExtractor để bạn có thể truy cập vào siêu dữ liệu PSSH cho nội dung nghe nhìn DASH của mình. Phương thức này trả về bản đồ các đối tượng UUID thành các byte, trong đó UUID chỉ định lược đồ mã hoá và các byte là dữ liệu dành riêng cho lược đồ đó.

    DRM của nội dung nghe nhìn

    Lớp MediaDrm mới cung cấp giải pháp mô-đun cho việc quản lý quyền kỹ thuật số (DRM) với nội dung nghe nhìn bằng cách tách biệt các mối lo ngại về DRM khỏi việc phát nội dung nghe nhìn. Ví dụ: việc phân tách API này cho phép bạn phát lại nội dung được mã hoá Widevine mà không cần phải sử dụng định dạng nội dung nghe nhìn của Widevine. Giải pháp DRM này cũng hỗ trợ Quy trình mã hoá phổ biến DASH để bạn có thể sử dụng nhiều lược đồ DRM cho nội dung phát trực tuyến.

    Bạn có thể sử dụng MediaDrm để lấy thông báo yêu cầu khoá mờ và xử lý thông báo phản hồi khoá từ máy chủ để thu thập và cấp phép. Ứng dụng của bạn chịu trách nhiệm xử lý giao tiếp mạng với máy chủ; lớp MediaDrm chỉ cung cấp khả năng tạo và xử lý thông báo.

    Bạn có thể dùng các API MediaDrm cùng với các API MediaCodec đã ra mắt trong Android 4.1 (API cấp 16), bao gồm MediaCodec để mã hoá và giải mã nội dung, MediaCrypto để xử lý nội dung đã mã hoá và MediaExtractor để trích xuất và giải mã nội dung của bạn.

    Trước tiên, bạn phải tạo các đối tượng MediaExtractorMediaCodec. Sau đó, bạn có thể truy cập vào UUID giúp nhận dạng lược đồ DRM, thường là từ siêu dữ liệu trong nội dung và sử dụng đối tượng này để tạo một bản sao của đối tượng MediaDrm bằng hàm khởi tạo.

    Mã hoá video qua một Nền tảng

    Android 4.1 (API cấp 16) đã thêm lớp MediaCodec để mã hoá và giải mã nội dung nghe nhìn cấp thấp. Khi mã hoá video, Android 4.1 yêu cầu bạn cung cấp nội dung nghe nhìn bằng một mảng ByteBuffer. Tuy nhiên, giờ đây, Android 4.3 cho phép bạn sử dụng Surface làm dữ liệu đầu vào cho bộ mã hoá. Ví dụ: tuỳ chọn này cho phép bạn mã hoá dữ liệu đầu vào từ tệp video hiện có hoặc sử dụng các khung hình được tạo qua OpenGL ES.

    Để sử dụng Surface làm dữ liệu đầu vào cho bộ mã hoá, trước tiên, hãy gọi configure() cho MediaCodec của bạn. Sau đó, hãy gọi createInputSurface() để nhận Surface mà bạn có thể truyền trực tuyến nội dung nghe nhìn của mình qua đó.

    Ví dụ: bạn có thể sử dụng Surface đã cho làm cửa sổ cho ngữ cảnh OpenGL bằng cách truyền nó vào eglCreateWindowSurface(). Sau đó, trong khi kết xuất nền tảng, hãy gọi eglSwapBuffers() để truyền khung hình đến MediaCodec.

    Để bắt đầu mã hoá, hãy gọi start() trên MediaCodec. Khi hoàn tất, hãy gọi signalEndOfInputStream() để chấm dứt quá trình mã hoá rồi gọi release() trên Surface.

    Kết hợp nội dung nghe nhìn

    Lớp MediaMuxer mới cho phép ghép kênh giữa một luồng âm thanh và một luồng video. Các API này đóng vai trò là phiên bản tương ứng với lớp MediaExtractor được thêm vào Android 4.2 để giải phóng nội dung đa phương tiện (demuxing).

    Các định dạng đầu ra được hỗ trợ được xác định trong MediaMuxer.OutputFormat. Hiện tại, MP4 là định dạng đầu ra duy nhất được hỗ trợ và MediaMuxer hiện chỉ hỗ trợ một luồng âm thanh và/hoặc một luồng video tại một thời điểm.

    MediaMuxer chủ yếu được thiết kế để hoạt động với MediaCodec, nhờ đó bạn có thể xử lý video thông qua MediaCodec rồi lưu đầu ra thành tệp MP4 thông qua MediaMuxer. Bạn cũng có thể sử dụng MediaMuxer kết hợp với MediaExtractor để chỉnh sửa nội dung nghe nhìn mà không cần mã hoá hoặc giải mã.

    Tiến trình phát và tua cho RemoteControlClient

    Trong Android 4.0 (API cấp 14), RemoteControlClient đã được thêm để bật bộ điều khiển chế độ phát nội dung nghe nhìn trên các ứng dụng điều khiển từ xa, chẳng hạn như bộ điều khiển có trên màn hình khoá. Android 4.3 hiện cho phép các bộ điều khiển đó hiển thị vị trí phát và các bộ điều khiển để tua quá trình phát. Nếu đã bật tính năng điều khiển từ xa cho ứng dụng đa phương tiện bằng API RemoteControlClient, thì bạn có thể cho phép tua qua nội dung phát bằng cách triển khai hai giao diện mới.

    Trước tiên, bạn phải bật cờ FLAG_KEY_MEDIA_POSITION_UPDATE bằng cách truyền cờ này vào setTransportControlsFlags().

    Sau đó, hãy triển khai hai giao diện mới sau đây:

    RemoteControlClient.OnGetPlaybackPositionListener
    Quy trình này bao gồm cả lệnh gọi lại onGetPlaybackPosition(). Lệnh gọi lại này yêu cầu vị trí hiện tại của nội dung nghe nhìn khi điều khiển từ xa cần cập nhật tiến trình trong giao diện người dùng.
    RemoteControlClient.OnPlaybackPositionUpdateListener
    Quy trình này bao gồm cả lệnh gọi lại onPlaybackPositionUpdate(). Lệnh này sẽ cho ứng dụng biết mã thời gian mới cho nội dung nghe nhìn khi người dùng tua nội dung phát bằng giao diện điều khiển từ xa.

    Sau khi bạn cập nhật vị trí phát mới cho chế độ phát, hãy gọi setPlaybackState() để cho biết trạng thái, vị trí và tốc độ phát mới.

    Khi xác định các giao diện này, bạn có thể thiết lập cho RemoteControlClient bằng cách gọi setOnGetPlaybackPositionListener()setPlaybackPositionUpdateListener() tương ứng.

    Đồ hoạ

    Hỗ trợ OpenGL ES 3.0

    Android 4.3 thêm giao diện Java và hỗ trợ gốc cho OpenGL ES 3.0. Các chức năng chính mới được cung cấp trong OpenGL ES 3.0 bao gồm:

    • Tăng tốc hiệu ứng hình ảnh nâng cao
    • Nén kết cấu ETC2/EAC chất lượng cao dưới dạng tính năng tiêu chuẩn
    • Phiên bản mới của ngôn ngữ tô bóng GLSL ES có hỗ trợ số nguyên và dấu phẩy động 32 bit
    • Kết xuất hoạ tiết nâng cao
    • Tiêu chuẩn hoá rộng hơn kích thước hoạ tiết và định dạng vùng đệm kết xuất

    Giao diện Java cho OpenGL ES 3.0 trên Android được cung cấp GLES30. Khi sử dụng OpenGL ES 3.0, hãy nhớ khai báo phương thức này trong tệp kê khai bằng thẻ <uses-feature> và thuộc tính android:glEsVersion. Ví dụ:

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

    Đồng thời, hãy nhớ chỉ định ngữ cảnh OpenGL ES bằng cách gọi setEGLContextClientVersion(), chuyển 3 làm phiên bản.

    Để biết thêm thông tin về cách sử dụng OpenGL ES, bao gồm cả cách kiểm tra phiên bản OpenGL ES được hỗ trợ trong thời gian chạy, hãy xem hướng dẫn về API OpenGL ES.

    Ánh xạ mip cho đối tượng có thể vẽ

    Sử dụng mipmap làm nguồn cho bitmap hoặc đối tượng có thể vẽ là một cách đơn giản để cung cấp hình ảnh chất lượng và nhiều tỷ lệ hình ảnh. Điều này có thể đặc biệt hữu ích nếu bạn muốn hình ảnh của mình được điều chỉnh theo tỷ lệ trong ảnh động.

    Android 4.2 (API cấp 17) đã thêm tính năng hỗ trợ cho mipmap trong lớp Bitmap – Android sẽ hoán đổi các hình ảnh mip trong Bitmap khi bạn đã cung cấp nguồn mipmap và bật setHasMipMap(). Hiện tại trong Android 4.3, bạn cũng có thể bật mipmap cho đối tượng BitmapDrawable bằng cách cung cấp một thành phần mipmap và đặt thuộc tính android:mipMap trong tệp tài nguyên bitmap hoặc bằng cách gọi hasMipMap().

    Giao diện người dùng

    Lớp phủ thành phần hiển thị

    Lớp ViewOverlay mới cung cấp một lớp trong suốt ở trên View mà bạn có thể thêm nội dung hình ảnh và lớp này không ảnh hưởng đến hệ phân cấp bố cục. Bạn có thể nhận ViewOverlay cho bất kỳ View nào bằng cách gọi getOverlay(). Lớp phủ luôn có cùng kích thước và vị trí với khung hiển thị máy chủ (khung hiển thị mà từ đó khung hiển thị được tạo), cho phép bạn thêm nội dung xuất hiện trước khung hiển thị máy chủ lưu trữ, nhưng không thể mở rộng ranh giới của khung hiển thị máy chủ lưu trữ đó.

    Việc sử dụng ViewOverlay đặc biệt hữu ích khi bạn muốn tạo ảnh động, chẳng hạn như trượt một khung hiển thị ra ngoài vùng chứa hoặc di chuyển các mục xung quanh màn hình mà không ảnh hưởng đến hệ phân cấp khung hiển thị. Tuy nhiên, vì khu vực có thể sử dụng của lớp phủ bị giới hạn ở cùng một khu vực với khung hiển thị máy chủ, nên nếu muốn tạo ảnh động cho một khung hiển thị di chuyển ra ngoài vị trí của nó trong bố cục, bạn phải sử dụng lớp phủ của khung hiển thị mẹ có giới hạn bố cục mong muốn.

    Khi tạo một lớp phủ cho khung hiển thị tiện ích như Button, bạn có thể thêm các đối tượng Drawable vào lớp phủ đó bằng cách gọi add(Drawable). Nếu bạn gọi getOverlay() cho thành phần hiển thị bố cục, chẳng hạn như RelativeLayout, thì đối tượng được trả về là ViewGroupOverlay. Lớp ViewGroupOverlay là lớp con của ViewOverlay, lớp này cũng cho phép bạn thêm các đối tượng View bằng cách gọi add(View).

    Lưu ý: Tất cả các đối tượng có thể vẽ và khung hiển thị bạn thêm vào lớp phủ chỉ là hình ảnh. Chúng không thể nhận tiêu điểm hoặc sự kiện nhập.

    Ví dụ: Mã sau đây tạo ảnh động cho một khung hiển thị trượt sang phải bằng cách đặt khung hiển thị đó vào lớp phủ của khung hiển thị mẹ, sau đó thực hiện dịch chuyển động trên khung hiển thị đó:

    Kotlin

    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()
    }
    

    Java

    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();
    

    Bố cục ranh giới quang học

    Đối với các khung hiển thị chứa hình nền 9-patch, giờ đây, bạn có thể chỉ định rằng các khung hiển thị này phải được căn chỉnh với các khung hiển thị lân cận dựa trên giới hạn "quang học" của hình nền thay vì ranh giới "clip" của khung hiển thị.

    Ví dụ: hình 1 và hình 2 cho thấy cùng một bố cục, nhưng phiên bản trong hình 1 sử dụng giới hạn đối với đoạn video (hành vi mặc định), còn hình 2 sử dụng giới hạn quang học. Vì hình ảnh 9-patch được dùng cho nút và khung ảnh có khoảng đệm xung quanh các cạnh, nên có vẻ như chúng không thẳng hàng hoặc với văn bản khi sử dụng giới hạn cắt.

    Lưu ý: Ảnh chụp màn hình trong hình 1 và 2 đã bật chế độ cài đặt "Show layout limit" (Hiện giới hạn bố cục) dành cho nhà phát triển. Đối với mỗi thành phần hiển thị, các đường màu đỏ biểu thị ranh giới quang học, các đường màu xanh dương biểu thị ranh giới của đoạn video và màu hồng biểu thị lề.

    Hình 1. Bố cục sử dụng giới hạn cắt (mặc định).

    Hình 2. Bố cục sử dụng giới hạn quang học.

    Để căn chỉnh khung hiển thị dựa trên giới hạn quang học, hãy đặt thuộc tính android:layoutMode thành "opticalBounds" trong một trong các bố cục mẹ. Ví dụ:

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

    Hình 3. Chế độ xem thu phóng của nút Holo 9-patch với các giới hạn quang học.

    Để làm được điều này, hình ảnh 9-patch được áp dụng cho nền của khung hiển thị phải chỉ định giới hạn quang học bằng cách sử dụng các đường màu đỏ dọc theo phần dưới cùng và bên phải của tệp 9-patch (như minh hoạ trong hình 3). Các đường màu đỏ biểu thị khu vực cần được trừ vào ranh giới của đoạn video, để lại các ranh giới quang học của hình ảnh.

    Khi bạn bật giới hạn quang học cho ViewGroup trong bố cục, tất cả thành phần hiển thị con đều kế thừa chế độ bố cục giới hạn quang học, trừ phi bạn ghi đè chế độ đó cho một nhóm bằng cách đặt android:layoutMode thành "clipBounds". Tất cả các thành phần bố cục cũng tuân theo các giới hạn quang học của thành phần hiển thị con, điều chỉnh các giới hạn riêng dựa trên giới hạn quang học của các thành phần hiển thị bên trong đó. Tuy nhiên, các phần tử bố cục (lớp con của ViewGroup) hiện không hỗ trợ giới hạn quang học cho hình ảnh 9-patch được áp dụng cho nền riêng của các phần tử đó.

    Nếu bạn tạo khung hiển thị tuỳ chỉnh bằng cách phân lớp con View, ViewGroup hoặc bất kỳ lớp con nào trong đó, thì khung hiển thị của bạn sẽ kế thừa các hành vi ràng buộc quang học này.

    Lưu ý: Tất cả tiện ích được giao diện Holo hỗ trợ đều đã được cập nhật với các giới hạn quang học, bao gồm cả Button, Spinner, EditText và các giới hạn khác. Vì vậy, bạn có thể hưởng lợi ngay lập tức bằng cách đặt thuộc tính android:layoutMode thành "opticalBounds" nếu ứng dụng của bạn áp dụng chủ đề Holo (Theme.Holo, Theme.Holo.Light, v.v.).

    Để chỉ định giới hạn quang học cho hình ảnh 9-patch của riêng bạn bằng công cụ Draw 9-patch, giữ phím Control khi nhấp vào điểm ảnh đường viền.

    Ảnh động cho các giá trị Rect

    Giờ đây, bạn có thể tạo ảnh động giữa hai giá trị Rect bằng RectEvaluator mới. Lớp mới này là một phương thức triển khai của TypeEvaluator mà bạn có thể truyền đến ValueAnimator.setEvaluator().

    Trình nghe tập trung và đính kèm cửa sổ

    Trước đây, nếu bạn muốn theo dõi thời điểm khung hiển thị được đính kèm/tách riêng với cửa sổ hoặc khi tiêu điểm của khung hiển thị thay đổi, bạn cần ghi đè lớp View để triển khai onAttachedToWindow(), onDetachedFromWindow() hoặc onWindowFocusChanged() tương ứng.

    Bây giờ, để nhận các sự kiện đính kèm và tách rời, bạn có thể triển khai ViewTreeObserver.OnWindowAttachListener và đặt nó trên một khung hiển thị bằng addOnWindowAttachListener(). Để nhận các sự kiện tiêu điểm, bạn có thể triển khai ViewTreeObserver.OnWindowFocusChangeListener và đặt trên một khung hiển thị bằng addOnWindowFocusChangeListener().

    Hỗ trợ quét quá mức cho TV

    Để đảm bảo ứng dụng lấp đầy toàn bộ màn hình trên mọi TV, giờ đây, bạn có thể bật tính năng quét quá mức cho bố cục ứng dụng của mình. Chế độ quét quá mức được xác định bằng cờ FLAG_LAYOUT_IN_OVERSCAN. Bạn có thể bật cờ này bằng các giao diện nền tảng như Theme_DeviceDefault_NoActionBar_Overscan hoặc bằng cách bật kiểu windowOverscan trong một giao diện tuỳ chỉnh.

    Hướng màn hình

    Thuộc tính screenOrientation của thẻ <activity> hiện hỗ trợ các giá trị bổ sung để đáp ứng lựa chọn ưu tiên của người dùng về chế độ xoay vòng tự động:

    "userLandscape"
    Hoạt động giống như "sensorLandscape", ngoại trừ trường hợp người dùng tắt chế độ tự động xoay thì chế độ này sẽ khoá theo hướng ngang thông thường và sẽ không lật.
    "userPortrait"
    Hoạt động giống như "sensorPortrait", ngoại trừ trường hợp người dùng tắt chế độ tự động xoay, thì chế độ này sẽ khoá ở hướng dọc thông thường và sẽ không lật.
    "fullUser"
    Hoạt động giống như "fullSensor" và cho phép xoay ở cả 4 hướng, ngoại trừ nếu người dùng tắt chế độ tự động xoay thì chế độ này sẽ khoá theo hướng ưu tiên của người dùng.

    Ngoài ra, giờ đây, bạn cũng có thể khai báo "locked" để khoá hướng của ứng dụng theo hướng hiện tại của màn hình.

    Ảnh động xoay

    Trường rotationAnimation mới trong WindowManager cho phép bạn chọn một trong ba ảnh động bạn muốn sử dụng khi hệ thống chuyển đổi hướng màn hình. Ba ảnh động này là:

    Lưu ý: Những ảnh động này chỉ xuất hiện nếu bạn đã đặt hoạt động ở chế độ "toàn màn hình" mà bạn có thể bật bằng các giao diện như Theme.Holo.NoActionBar.Fullscreen.

    Ví dụ: dưới đây là cách bạn có thể bật ảnh động "chuyển hướng":

    Kotlin

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

    Java

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

    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_GAME_ROTATION_VECTOR mới cho phép bạn phát hiện hướng xoay của thiết bị mà không cần lo lắng về hiện tượng nhiễu từ. Không giống như cảm biến TYPE_ROTATION_VECTOR, TYPE_GAME_ROTATION_VECTOR không dựa trên từ tính bắc.

    Cảm biến TYPE_GYROSCOPE_UNCALIBRATEDTYPE_MAGNETIC_FIELD_UNCALIBRATED mới cung cấp dữ liệu cảm biến thô mà không xem xét đến việc ước tính độ lệch. Điều này nghĩa là các cảm biến TYPE_GYROSCOPETYPE_MAGNETIC_FIELD hiện có cung cấp dữ liệu cảm biến có tính đến độ chệch ước tính của con quay hồi chuyển và vật sắt cứng trong thiết bị tương ứng. Trong khi phiên bản "chưa hiệu chỉnh" mới của các cảm biến này cung cấp dữ liệu cảm biến thô và cung cấp riêng các giá trị độ chệch ước tính. Các cảm biến này cho phép bạn cung cấp dữ liệu hiệu chuẩn tuỳ chỉnh của riêng mình cho dữ liệu cảm biến bằng cách tăng cường độ chệch ước tính dựa trên dữ liệu bên ngoài.

    Trình tiếp nhận thông báo

    Android 4.3 thêm một lớp dịch vụ mới là NotificationListenerService, cho phép ứng dụng của bạn nhận thông tin về các thông báo mới khi hệ thống đăng thông báo đó.

    Nếu ứng dụng của bạn đang sử dụng API dịch vụ hỗ trợ tiếp cận để truy cập vào thông báo hệ thống, thì bạn nên cập nhật ứng dụng để sử dụng các API này.

    Trình cung cấp danh bạ

    Truy vấn "thông tin liên hệ"

    Truy vấn mới của Trình cung cấp danh bạ, Contactables.CONTENT_URI, cung cấp một cách hiệu quả để nhận một Cursor chứa tất cả địa chỉ email và số điện thoại của tất cả người liên hệ khớp với truy vấn đã chỉ định.

    Truy vấn delta danh bạ

    Các API mới đã được thêm vào Trình cung cấp danh bạ cho phép bạn truy vấn các thay đổi gần đây đối với dữ liệu danh bạ một cách hiệu quả. Trước đây, ứng dụng của bạn có thể được thông báo khi có điểm nào đó trong dữ liệu danh bạ thay đổi. Tuy nhiên, bạn sẽ không biết chính xác điều gì đã thay đổi và cần truy xuất tất cả mục liên hệ, sau đó lặp lại qua các mục liên hệ đó để khám phá thay đổi.

    Để theo dõi các thay đổi đối với các lượt chèn và cập nhật, giờ đây, bạn có thể thêm tham số CONTACT_LAST_UPDATED_TIMESTAMP vào lựa chọn của mình để chỉ truy vấn những người liên hệ đã thay đổi kể từ lần gần đây nhất bạn truy vấn nhà cung cấp này.

    Để theo dõi các địa chỉ liên hệ đã bị xóa, bảng mới ContactsContract.DeletedContacts cung cấp nhật ký các địa chỉ liên hệ đã bị xóa (nhưng mỗi địa chỉ liên hệ đã xóa sẽ được lưu giữ trong bảng này trong một khoảng thời gian có hạn). Tương tự như CONTACT_LAST_UPDATED_TIMESTAMP, bạn có thể sử dụng tham số lựa chọn mới, CONTACT_DELETED_TIMESTAMP để kiểm tra xem người liên hệ nào đã bị xoá kể từ lần gần đây nhất bạn truy vấn nhà cung cấp. Bảng này cũng chứa hằng số DAYS_KEPT_MILLISECONDS chứa số ngày (tính bằng mili giây) mà nhật ký sẽ được lưu giữ.

    Ngoài ra, Trình cung cấp danh bạ giờ đây sẽ truyền hành động CONTACTS_DATABASE_CREATED khi người dùng xoá bộ nhớ danh bạ thông qua trình đơn cài đặt hệ thống, giúp tạo lại cơ sở dữ liệu Trình cung cấp danh bạ một cách hiệu quả. Thông báo này nhằm báo hiệu các ứng dụng cần xoá tất cả thông tin liên hệ mà chúng đã lưu trữ và tải lại bằng một truy vấn mới.

    Để xem mã mẫu sử dụng các API này để kiểm tra các thay đổi đối với mục liên hệ, hãy xem trong mẫu Apidemos có trong tệp SDK Mẫu để tải xuống.

    Localization

    Cải thiện hỗ trợ cho văn bản hai chiều

    Các phiên bản Android trước hỗ trợ ngôn ngữ và bố cục từ phải sang trái (RTL), nhưng đôi khi không xử lý đúng cách văn bản theo hướng hỗn hợp. Vì vậy, Android 4.3 sẽ thêm các API BidiFormatter giúp bạn định dạng văn bản đúng cách với nội dung theo hướng ngược lại mà không làm xáo trộn bất kỳ phần nào của văn bản đó.

    Ví dụ: khi muốn tạo một câu có biến chuỗi, chẳng hạn như "Ý của bạn là 15 Bay Street, Laurel, CA?", bạn thường truyền tài nguyên chuỗi đã bản địa hoá và biến đó đến String.format():

    Kotlin

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

    Java

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

    Tuy nhiên, nếu ngôn ngữ là tiếng Do Thái, thì chuỗi được định dạng sẽ có dạng như sau:

    Văn phòng Văn học, Văn phòng, Thành phố Hồ Chí Minh, Việt Nam?

    Tên đó sai vì "15" phải nằm trong "Bay Street". Giải pháp là sử dụng BidiFormatter và phương thức unicodeWrap(). Ví dụ: mã trên sẽ trở thành:

    Kotlin

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

    Java

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

    Theo mặc định, unicodeWrap() sử dụng phương pháp phỏng đoán ước tính hướng-mạnh nhất. Phương pháp này có thể gây ra vấn đề nếu tín hiệu đầu tiên về hướng văn bản không thể hiện hướng thích hợp cho toàn bộ nội dung. Nếu cần, bạn có thể chỉ định một cách phỏng đoán khác bằng cách truyền một trong các hằng số TextDirectionHeuristic từ TextDirectionHeuristics sang unicodeWrap().

    Lưu ý: Các API mới này cũng có sẵn cho các phiên bản Android trước thông qua Thư viện hỗ trợ Android, cùng với lớp BidiFormatter và các API liên quan.

    Dịch vụ hỗ trợ tiếp cận

    Xử lý sự kiện chính

    AccessibilityService hiện có thể nhận lệnh gọi lại cho các sự kiện nhập khoá bằng phương pháp gọi lại onKeyEvent(). Điều này cho phép dịch vụ hỗ trợ tiếp cận của bạn xử lý phương thức nhập cho các thiết bị đầu vào dựa trên phím (chẳng hạn như bàn phím) và dịch các sự kiện đó thành các thao tác đặc biệt mà trước đây có thể chỉ thực hiện được bằng phương thức nhập bằng cách chạm hoặc bàn phím di chuyển của thiết bị.

    Chọn văn bản và sao chép/dán

    AccessibilityNodeInfo hiện cung cấp các API cho phép AccessibilityService chọn, cắt, sao chép và dán văn bản trong một nút.

    Để chỉ định lựa chọn văn bản cần cắt hoặc sao chép, dịch vụ hỗ trợ tiếp cận của bạn có thể sử dụng thao tác mới (ACTION_SET_SELECTION), truyền kèm theo vị trí bắt đầu và kết thúc lựa chọn bằng ACTION_ARGUMENT_SELECTION_START_INTACTION_ARGUMENT_SELECTION_END_INT. Ngoài ra, bạn có thể chọn văn bản bằng cách thao tác với vị trí con trỏ bằng thao tác hiện có, ACTION_NEXT_AT_MOVEMENT_GRANULARITY (trước đây chỉ dùng để di chuyển vị trí con trỏ) và thêm đối số ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN.

    Sau đó, bạn có thể cắt hoặc sao chép bằng ACTION_CUT, ACTION_COPY rồi dán bằng ACTION_PASTE.

    Lưu ý: Các API mới này cũng có sẵn cho các phiên bản Android trước thông qua Thư viện hỗ trợ Android, với lớp AccessibilityNodeInfoCompat.

    Khai báo bộ tính năng hỗ trợ tiếp cận

    Kể từ Android 4.3, dịch vụ hỗ trợ tiếp cận phải khai báo bộ tính năng hỗ trợ tiếp cận trong tệp siêu dữ liệu để sử dụng một số tính năng hỗ trợ tiếp cận. Nếu chức năng không được yêu cầu trong tệp siêu dữ liệu, thì tính năng này sẽ không hoạt động. Để khai báo các chức năng hỗ trợ tiếp cận của dịch vụ, bạn phải sử dụng các thuộc tính XML tương ứng với các hằng số "chức năng" khác nhau trong lớp AccessibilityServiceInfo.

    Ví dụ: nếu một dịch vụ không yêu cầu tính năng flagRequestFilterKeyEvents, thì dịch vụ đó sẽ không nhận được các sự kiện chính.

    Kiểm tra và gỡ lỗi

    Kiểm thử giao diện người dùng tự động

    Lớp UiAutomation mới cung cấp các API cho phép bạn mô phỏng hành động của người dùng để kiểm thử tự động. Bằng cách sử dụng các API AccessibilityService của nền tảng, API UiAutomation cho phép bạn kiểm tra nội dung trên màn hình cũng như chèn các sự kiện chạm và bàn phím tuỳ ý.

    Để nhận một thực thể của UiAutomation, hãy gọi Instrumentation.getUiAutomation(). Để chế độ này hoạt động, bạn phải cung cấp tuỳ chọn -w cùng với lệnh instrument khi chạy InstrumentationTestCase trên adb shell.

    Với thực thể UiAutomation, bạn có thể thực thi các sự kiện tuỳ ý để kiểm thử ứng dụng bằng cách gọi executeAndWaitForEvent(), chuyển Runnable vào đó để thực hiện, khoảng thời gian chờ cho hoạt động và triển khai giao diện UiAutomation.AccessibilityEventFilter. Ngay trong quá trình triển khai UiAutomation.AccessibilityEventFilter, bạn sẽ nhận được một lệnh gọi cho phép lọc các sự kiện mà bạn quan tâm và xác định mức độ thành công hay thất bại của một trường hợp kiểm thử nhất định.

    Để quan sát tất cả sự kiện trong quá trình kiểm thử, hãy tạo một phương thức triển khai của UiAutomation.OnAccessibilityEventListener và truyền nó vào setOnAccessibilityEventListener(). Sau đó, giao diện trình nghe của bạn sẽ nhận được lệnh gọi đến onAccessibilityEvent() mỗi khi một sự kiện xảy ra, nhận một đối tượng AccessibilityEvent mô tả sự kiện đó.

    Có nhiều thao tác khác mà API UiAutomation hiển thị ở cấp rất thấp để khuyến khích phát triển các công cụ kiểm thử giao diện người dùng, chẳng hạn như uiautomator. Ví dụ: UiAutomation cũng có thể:

    • Chèn sự kiện đầu vào
    • Thay đổi hướng của màn hình
    • Chụp ảnh màn hình

    Và quan trọng nhất đối với các công cụ kiểm thử giao diện người dùng, API UiAutomation hoạt động trên các ranh giới của ứng dụng, không giống như các API trong Instrumentation.

    Sự kiện Systrace cho ứng dụng

    Android 4.3 thêm lớp Trace có 2 phương thức tĩnh là beginSection()endSection(), cho phép bạn xác định các khối mã để đưa vào báo cáo systrace. Bằng cách tạo các phần mã có thể truy vết trong ứng dụng, nhật ký systrace cung cấp cho bạn bản phân tích chi tiết hơn về vị trí xảy ra tình trạng chậm thanh toán trong ứng dụng.

    Để biết thông tin về cách sử dụng công cụ Systrace, hãy đọc bài viết Phân tích màn hình và hiệu suất bằng Systrace.

    Bảo mật

    Kho khoá Android cho khoá riêng tư trong ứng dụng

    Android hiện cung cấp một Trình cung cấp bảo mật Java tuỳ chỉnh trong cơ sở KeyStore, được gọi là Android Key Store, cho phép bạn tạo và lưu các khoá riêng tư mà chỉ ứng dụng của bạn mới có thể xem và sử dụng. Để tải Kho khoá Android, hãy truyền "AndroidKeyStore" đến KeyStore.getInstance().

    Để quản lý thông tin xác thực riêng tư của ứng dụng trong Kho khoá Android, hãy tạo một khoá mới bằng KeyPairGenerator thông qua KeyPairGeneratorSpec. Trước tiên, hãy tải một thực thể của KeyPairGenerator bằng cách gọi getInstance(). Sau đó, hãy gọi initialize(), truyền vào đó một thực thể của KeyPairGeneratorSpec mà bạn có thể sử dụng KeyPairGeneratorSpec.Builder. Cuối cùng, hãy nhận KeyPair bằng cách gọi generateKeyPair().

    Bộ nhớ thông tin xác thực phần cứng

    Android hiện cũng hỗ trợ bộ nhớ dựa trên phần cứng cho thông tin đăng nhập KeyChain của bạn, giúp tăng cường bảo mật bằng cách không cho phép các khoá để trích xuất. Nghĩa là, sau khi các khoá đã được lưu trữ trong kho khoá dựa trên phần cứng (Secure Element, TPM hoặc TrustZone), bạn có thể sử dụng các khoá đó cho hoạt động mã hoá nhưng không thể xuất nội dung khoá riêng tư. Ngay cả nhân hệ điều hành cũng không thể truy cập vào nội dung khoá này. Mặc dù không phải thiết bị chạy Android nào cũng hỗ trợ bộ nhớ trên phần cứng, nhưng bạn có thể kiểm tra trong thời gian chạy xem có bộ nhớ dựa trên phần cứng hay không bằng cách gọi KeyChain.IsBoundKeyAlgorithm().

    Khai báo tệp kê khai

    Các tính năng bắt buộc có thể khai báo

    Các giá trị sau đây hiện đã được hỗ trợ trong phần tử <uses-feature> để bạn có thể đảm bảo rằng ứng dụng chỉ được cài đặt trên các thiết bị cung cấp các tính năng mà ứng dụng cần.

    FEATURE_APP_WIDGETS
    Khai báo rằng ứng dụng của bạn cung cấp tiện ích ứng dụng và chỉ nên được cài đặt trên các thiết bị có Màn hình chính hoặc vị trí tương tự nơi người dùng có thể nhúng tiện ích ứng dụng. Ví dụ:
    <uses-feature android:name="android.software.app_widgets" android:required="true" />
    
    FEATURE_HOME_SCREEN
    Khai báo rằng ứng dụng của bạn hoạt động như một ứng dụng thay thế Màn hình chính và chỉ nên được cài đặt trên những thiết bị hỗ trợ các ứng dụng của bên thứ ba trên Màn hình chính. Ví dụ:
    <uses-feature android:name="android.software.home_screen" android:required="true" />
    
    FEATURE_INPUT_METHODS
    Khai báo rằng ứng dụng của bạn cung cấp phương thức nhập tuỳ chỉnh (bàn phím tích hợp InputMethodService) và chỉ nên được cài đặt trên những thiết bị hỗ trợ phương thức nhập của bên thứ ba. Ví dụ:
    <uses-feature android:name="android.software.input_methods" android:required="true" />
    
    FEATURE_BLUETOOTH_LE
    Khai báo rằng ứng dụng của bạn sử dụng API Bluetooth Low Energy và chỉ nên cài đặt trên các thiết bị có khả năng giao tiếp với các thiết bị khác qua Bluetooth năng lượng thấp. Ví dụ:
    <uses-feature android:name="android.software.bluetooth_le" android:required="true" />
    

    Quyền của người dùng

    Các giá trị sau hiện đã được hỗ trợ trong <uses-permission> để khai báo các quyền mà ứng dụng của bạn cần để truy cập vào một số API nhất định.

    BIND_NOTIFICATION_LISTENER_SERVICE
    Bắt buộc khi sử dụng các API NotificationListenerService mới.
    SEND_RESPOND_VIA_MESSAGE
    Đây là thông tin bắt buộc để nhận ý định ACTION_RESPOND_VIA_MESSAGE.

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