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à ứng dụng nhà phát triển. 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.3 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.3 để kiểm thử ứng dụng, hãy sử dụng hình ảnh hệ thống Android 4.3 để kiểm thử ứng dụng trên trình mô phỏng Android. Sau đó xây dựng ứng dụng của bạn 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

Để tối ưu hoá ứng dụng của bạn 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", hãy cài đặt tiện ích này trên ảnh hệ thống Android 4.3, hãy kiểm thử rồi xuất bản bản cập nhật cùng với thay đổi này.

Bạn có thể sử dụng các 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 các đ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 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ợ các 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 API là gì Cấp độ?

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.3.

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

Ứng dụng của bạn có thể hoạt động không đúng cách 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 tất cả các ứng dụng Android tiêu chuẩn. Ví dụ: một hồ sơ bị hạn chế có thể có đã 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 có ứng dụng nào có thể xử lý Intent hay không, thì ứ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 có ứng dụng để 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 đúng cách 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ó thể gặp sự cố hoặc hoạt động không mong muốn khi dùng trong hồ sơ bị hạn chế.

Nếu bạn muốn ngăn các hồ sơ bị hạn chế sử dụng ứng dụng của bạn hoàn toàn vì ứng dụng phụ thuộc vào thông tin tài khoản nhạy cảm, hãy chỉ định thuộc tính android:requiredAccountType trong <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 sử dụng ứng dụng của bạn mặc dù họ không thể tạo tài khoản của riêng mình, 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 các 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 Hỗ trợ tài khoản trong hồ sơ bị hạn chế bên dưới.

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

Video của bạn có thể xuất hiện 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, trong khi sử dụng "wrap_content" cho chiều cao hoặc chiều rộng có thể trước đó bạn đã cung cấp bố cục video mong muốn, làm như vậy có thể làm cho video 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 nhận 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.

Trang doanh nghiệp 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 có sẵn cho hồ sơ. Một bộ API mới trong Android 4.3 cũng cho phép bạn tạo hiệu ứng hạt nhỏ các chế độ cài đặt hạn chế 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 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 định 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. Để người dùng thấy được chế độ cài đặt quy định hạn chế của ứng dụng, bạn phải khai báo các hạn chế mà ứng dụng cung cấp bằng cách tạo BroadcastReceiver nhận ý định ACTION_GET_RESTRICTION_ENTRIES. Hệ thống gọi ý định này để truy vấn tất cả ứng dụng để biết các hạn chế hiện có, sau đó xây dựng 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ế cho từng hồ sơ bị hạn chế.

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

  • TYPE_BOOLEAN cho một quy tắc hạn chế có giá trị là đúng hoặc sai.
  • TYPE_CHOICE cho một quy định 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 (lựa chọn hộp đánh dấu).

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

Hệ thống sẽ tạo giao diện người dùng cho các quy tắc hạn chế của ứng dụng trong ứng dụng Cài đặt và lưu từng quy tắc bằng cách sử dụng khoá duy nhất bạn đã cung cấp cho mỗi RestrictionEntry . Khi người dùng mở ứng dụng, bạn có thể truy vấn mọi quy định 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 cung cấp các quy tắc hạn chế cụ thể hơn mà các giá trị boolean, lựa chọn đơn và lựa chọn nhiều không thể xử lý được, thì bạn có thể tạo một hoạt động mà người dùng có thể chỉ định các quy tắc hạn chế và cho phép người dùng mở hoạt động đó từ phần cài đặt quy tắc hạn chế. Trong broadcast receiver để thêm EXTRA_RESTRICTIONS_INTENT trong kết quả Bundle. Phần bổ sung này phải chỉ định một Intent cho biết lớp Activity cần 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 truy cập vào hoạt động của bạn để đặt các quy định hạn chế tuỳ chỉnh, hoạt động của bạn phải trả về kết quả chứa các giá trị hạn chế trong một phần 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.

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

Bất kỳ tài khoản nào được thêm vào người dùng chính đều có sẵn trong hồ sơ bị hạn chế, nhưng theo mặc định, không thể truy cập tài khoản qua API AccountManager. Nếu bạn cố gắng thêm tài khoản bằng AccountManager khi đang ở chế độ 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:

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

    Để 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 nên cho phép điều này chỉ khi 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 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 hiểu rõ rằng quyền truy cập vào tài khoản là 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 lượng quyền truy cập vào tài khoản được phép trong ứng dụng của bạn.

  • Vô hiệu hoá một số chức năng nhất định khi không thể sửa đổi tài khoản.

    Nếu bạn muốn sử dụng tài khoản nhưng không thực sự cần đến tài khoản đó cho phiên bản 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 sử dụng được. Trước tiên, bạn nên kiểm tra xem đã có tài khoản hay chưa. Nếu không, hãy truy vấn xem có thể tạo tài khoản mới bằng cách gọi getUserRestrictions() và kiểm tra DISALLOW_MODIFY_ACCOUNTS bổ sung trong kết quả hay không. Nếu là true, 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 mọi thuộc tính mới 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ư.

    Ngược lại, nếu bạn muốn ứng dụng của mình không được cung cấp cho các hồ sơ bị hạn chế vì ứng dụng của bạn phụ thuộc vào thông tin cá nhân nhạy cảm trong một tài khoản (và vì các 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 cho các hồ sơ bị hạn chế, vì các hồ sơ bị hạn chế không được sử dụng email cá nhân của chủ sở hữu.

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

    Bluetooth năng lượng thấp (Có sẵn tính năng thông minh)

    Android hiện hỗ trợ Bluetooth năng lượng thấp (LE) bằng các API mới trong android.bluetooth. Với các API mới, bạn có thể xây dựng các ứng dụng Android giao tiếp với các thiết bị ngoại vi Bluetooth tiết kiệm năng lượng, 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 chưa có trên tất cả các thiết bị Nếu là thiết bị chạy Android, bạn phải khai báo trong tệp kê khai một <uses-feature> cho "android.hardware.bluetooth_le":

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

    Nếu bạn đã quen với các API Bluetooth cổ điển của Android, hãy lưu ý rằng việc sử dụng Bluetooth LE API có một số điểm khác biệt. Quan trọng nhất là giờ đây đã có lớp BluetoothManager mà bạn nên dùng cho một số thao tác cấp cao chẳng hạn như lấy BluetoothAdapter, lấy danh sách người dùng đã kết nối thiết bị và kiểm tra trạng thái của thiết bị. Ví dụ: sau đây là cách bạn nên lấy 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 cho phương thức này một hoạt động triển khai giao diện BluetoothAdapter.LeScanCallback. Khi bộ chuyển đổi Bluetooth phát hiện một thiết bị ngoại vi Bluetooth LE, quá trình triển khai BluetoothAdapter.LeScanCallback sẽ nhận được lệnh gọi đến phương thức onLeScan(). Chiến dịch này phương thức cung cấp cho bạn một đối tượng BluetoothDevice biểu thị thiết bị được phát hiện, giá trị RSSI cho thiết bị và một mảng byte chứa dữ liệu của thiết bị bản ghi quảng cáo.

    Nếu chỉ muốn quét để tìm một số loại thiết bị ngoại vi cụ thể, bạn có thể gọi startLeScan() và thêm một mảng đố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 năng lượng thấp hoặc quét tìm thiết bị Bluetooth cổ điển bằng các API trước đó. Bạn không quét được cả LE và Classic Các thiết bị Bluetooth cùng 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 cho đối tượng này một phương thức triển khai BluetoothGattCallback. Việc triển khai BluetoothGattCallback sẽ nhận đượ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. Sự kiện này diễn ra trong onConnectionStateChange() lệnh gọi lại mà bạn có thể bắt đầu giao tiếp với thiết bị nếu phương thức chuyển STATE_CONNECTED dưới dạng trạng thái mới.

    Để truy cập vào 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 nhất định của người dùng đối với 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 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 bao gồm chế độ chỉ quét cho phép thiết bị Wi-Fi quét các điểm truy cập để giúp xác định vị trí mà không cần kết nối với điểm truy cập, do đó làm giảm đáng kể mức sử dụng pin.

    Nếu muốn thu thập 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 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ụ hướng đến 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 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 cuộc gọi đến bằng tin nhắn văn bản tức thì 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 do ứng dụng Nhắn tin mặc định xử lý. Giờ đây, bất kỳ ứng dụng nào có thể khai báo khả năng xử lý những thông báo này bằng cách tạo một Service bằng bộ lọc ý định cho ACTION_RESPOND_VIA_MESSAGE.

    Khi người dùng trả lời cuộc gọi đến bằng câu trả lời nhanh, ứng dụng Điện thoại sẽ gửi ý định ACTION_RESPOND_VIA_MESSAGE thông qua URI mô tả người nhận (người gọi) và EXTRA_TEXT bổ sung bằng thông điệp mà người dùng muốn gửi. Khi nhận được ý định, dịch vụ của bạn sẽ được phân phối thông báo và tự dừng ngay lập tức (ứng dụng của bạn 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.

    Đa phương tiện

    Các tính năng nâng cao MediaExtractor và MediaCodec

    Giờ đây, Android giúp bạn dễ dàng viết trình phát Truyền phát thích ứng động qua HTTP (DASH) theo tiêu chuẩn ISO/IEC 23009-1 bằng cách sử dụng các API hiện có trong MediaCodecMediaExtractor. Khung cơ bản của các API này đã được cập nhật để hỗ trợ phân tích cú pháp các tệp MP4 bị 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 đến MediaExtractor.

    Nếu bạn muốn sử dụng DASH với nội dung đã 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 đa phương tiện đã mã hoá. Ngoài ra, phương thức getPsshInfo() đã được thêm vào MediaExtractor để bạn có thể truy cập siêu dữ liệu PSSH cho nội dung đa phương tiện DASH. Phương thức này trả về tệp ánh xạ đối tượng UUID tới byte, với UUID chỉ định lược đồ mã hoá và các byte là dữ liệu cụ thể cho lược đồ đó.

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

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

    Bạn có thể sử dụng MediaDrm để nhận các thông báo và quy trình yêu cầu khoá không rõ ràng thông báo phản hồi khoá từ máy chủ để lấy giấy phép và cấp phép. Ứng dụng của bạn chịu trách nhiệm xử lý hoạt động 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.

    API MediaDrm được dùng cùng với API MediaCodec được giới thiệu 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.

    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 tính năng xác định lược đồ DRM UUID (thường là từ siêu dữ liệu trong nội dung) và sử dụng nó để tạo thực thể của đối tượng MediaDrm bằng hàm khởi tạo.

    Mã hoá video từ một Surface

    Android 4.1 (API cấp 16) thêm lớp MediaCodec cho cấp thấp mã hoá và giải mã nội dung đa phương tiện. Khi mã hoá video, Android 4.1 yêu cầu bạn cung cấp một mảng ByteBuffer cho nội dung đa phương tiện, nhưng Android 4.3 hiện cho phép bạn sử dụng Surface làm dữ liệu đầu vào cho bộ mã hoá. Chẳng hạn, phương thức này cho phép bạn mã hoá dữ liệu đầu vào từ một tệp video hiện có hoặc sử dụng khung hình tạo qua OpenGL ES.

    Để 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.

    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 cửa sổ đó đến eglCreateWindowSurface(). Sau đó, trong khi kết xuất bề mặt, hãy gọi eglSwapBuffers() để truyền khung đế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á và gọi release() trên Surface.

    Ghép nội dung đa phương tiện

    Lớp MediaMuxer mới cho phép truyền dẫn song công giữa một luồng âm thanh và một luồng video. Các API này đóng vai trò như phiên bản đối chiếu của MediaExtractor đã thêm vào Android 4.2 cho nội dung đa phương tiện tách kênh (demuxing).

    Bạn có thể xác định các định dạng đầu ra được hỗ trợ 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 để bạn có thể xử lý video thông qua MediaCodec, sau đó lưu sang tệp MP4 thông qua MediaMuxer. Bạn cũng có thể sử dụng MediaMuxer kết hợp với MediaExtractor để thực hiện chỉnh sửa nội dung đa phương tiệ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 vào bật điều khiển phát lại nội dung nghe nhìn từ ứng dụng điều khiển từ xa, chẳng hạn như các nút điều khiển có sẵn trên màn hình khóa. Android 4.3 hiện cung cấp khả năng cho các tay điều khiển như vậy hiển thị vị trí phát và các chế độ điều khiển để tua lại nội dung 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 thao tác tua lại 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 setTransportControlsFlags().

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

    RemoteControlClient.OnGetPlaybackPositionListener
    Trong đó có cả lệnh gọi lại onGetPlaybackPosition(). Lệnh gọi lại này yêu cầu thông tin 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
    Điều này bao gồm 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 vuốt để phát bằng giao diện người dùng điều khiển từ xa.

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

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

    Đồ hoạ

    Hỗ trợ OpenGL ES 3.0

    Android 4.3 thêm các giao diện Java và hỗ trợ gốc cho OpenGL ES 3.0. Các chức năng mới chính đượ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 theo 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á kích thước hoạ tiết và định dạng vùng đệm kết xuất rộng hơn

    Giao diện Java cho OpenGL ES 3.0 trên Android được cung cấp bằng GLES30. Khi sử dụng OpenGL ES 3.0, hãy nhớ khai báo 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>

    Và nhớ chỉ định ngữ cảnh OpenGL ES bằng cách gọi setEGLContextClientVersion(), truyề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 xem thiết bị có hỗ trợ hay không Phiên bản OpenGL ES trong thời gian chạy, hãy xem hướng dẫn về API OpenGL ES.

    Mipmap 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 điều chỉnh theo tỷ lệ trong ảnh động.

    Android 4.2 (API cấp 17) hỗ trợ thêm mipmap trong Bitmap lớp – Android hoán đổi hình ảnh mip trong Bitmap khi bạn đã cung cấp nguồn mipmap và đã bật setHasMipMap(). Giờ đây, 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 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

    Xem lớp phủ

    Lớp ViewOverlay mới cung cấp một lớp trong suốt ở trên cùng View mà bạn có thể thêm nội dung hình ảnh vào đó và không ảnh hưởng đến hệ phân cấp bố cục. Bạn có thể lấy 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 thành phần hiển thị lưu trữ (thành phần hiển thị mà lớp phủ được tạo từ đó), cho phép bạn thêm nội dung xuất hiện trước thành phần hiển thị lưu trữ nhưng không thể mở rộng giới hạn của thành phần hiển thị 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 thành phần hiển thị ra khỏ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 thành phần hiển thị. Tuy nhiên, vì diện tích có thể sử dụng của lớp phủ là bị hạn chế ở cùng một khu vực với khung hiển thị máy chủ, nếu bạn muốn tạo hiệu ứng động cho khung hiển thị di chuyển ra bên ngoài trong bố cục, bạn phải sử dụng lớp phủ từ khung hiển thị mẹ có ranh giới bố cục.

    Khi tạo lớp phủ cho thành phần 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 chế độ xem bố cục, chẳng hạn như RelativeLayout, đối tượng được trả về là một ViewGroupOverlay. Lớp ViewGroupOverlay là một lớp con của ViewOverlay, 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ả đối tượng có thể vẽ và thành phần hiển thị mà bạn thêm vào lớp phủ chỉ có thể nhìn thấy. Họ không thể nhận được sự kiện tiêu điểm hoặc nhập.

    Ví dụ: mã sau đây tạo ảnh động cho một thành phần hiển thị trượt sang phải bằng cách đặt thành phần hiển thị đó vào lớp phủ của thành phần hiển thị mẹ, sau đó thực hiện ảnh động dịch chuyển trên thành phần 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 thành phần hiển thị chứa hình nền 9 mảnh, giờ đây, bạn có thể chỉ định rằng các thành phần hiển thị đó phải được căn chỉnh với các thành phần 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ì giới hạn "đoạn cắt" của thành phần hiển thị.

    Ví dụ: Hình 1 và 2 đều thể hiện cùng một bố cục, nhưng phiên bản trong hình 1 là sử dụng giới hạn đoạn video (hành vi mặc định), trong khi hình 2 sử dụng giới hạn quang học. Vì hình ảnh 9-patch dùng cho nút và khung ảnh bao gồm khoảng đệm xung quanh các cạnh, chúng dường như không khớp với nhau hoặc văn bản khi sử dụng giới hạn đoạn video.

    Lưu ý: Ảnh chụp màn hình trong hình 1 và 2 đã bật chế độ cài đặt "Hiển thị giới hạn bố cục" dành cho nhà phát triển. Đối với mỗi hình ảnh, các đường màu đỏ biểu thị ranh giới, đường màu xanh dương biểu thị giới hạn đối với đ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 ranh giới quang học.

    Để căn chỉnh các thành phần hiển thị dựa trên giới hạn quang học của chúng, 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 phóng to của nút Holo 9-patch với giới hạn quang học.

    Để tính năng này hoạt động, hình ảnh 9-patch áp dụng cho nền của thành phần hiển thị phải chỉ định các 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 đỏ cho biết vùng cần bị trừ đi giới hạn đoạn video, chừa lại 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ả các khung hiển thị con kế thừa chế độ bố cục giới hạn quang học, trừ phi bạn ghi đè chế độ này cho một nhóm đang đặt android:layoutMode thành "clipBounds". Tất cả các phần tử bố cục cũng tôn trọng giới hạn quang học của khung nhìn con, điều chỉnh giới hạn của chính chúng dựa trên giới hạn quang học của chế độ xem trong các nhóm đó. Tuy nhiên, các phần tử bố cục (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.

    Nếu bạn tạo một thành phần 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 của các thành phần đó, thì thành phần 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ả các tiện ích được chủ đề Holo hỗ trợ đã được cập nhật có giới hạn quang học, bao gồm Button, Spinner, EditText và những người 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 cho "opticalBounds" nếu ứng dụng của bạn áp dụng chủ đề Holo (Theme.Holo, Theme.Holo.Light, v.v.).

    Để chỉ định các 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 (Vẽ 9-patch), hãy giữ phím Control khi nhấp vào các pixel đườ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à cách triển khai 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 lắng nghe thời điểm góc nhìn của bạn được gắn vào/nằm gần cửa sổ hoặc khi tiêu điểm của tệp 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, 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ị có addOnWindowFocusChangeListener().

    Hỗ trợ TV tràn màn hình

    Để đảm bảo ứng dụng của bạn 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 lề cho bố cục ứng dụng. Chế độ quét quá mức được xác định bằng cờ FLAG_LAYOUT_IN_OVERSCAN. Bạn có thể bật chế độ 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 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 để tuân theo lựa chọn ưu tiên của người dùng về tính năng tự động xoay:

    "userLandscape"
    Hoạt động giống như "sensorLandscape", ngoại trừ trường hợp người dùng tắt tính năng tự động xoay thì chế độ này sẽ khoá ở 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 tính năng tự động xoay, thì thuộc tính 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 theo cả bốn 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 thành 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 để muốn sử dụng khi hệ thống chuyển 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 với các chủ đề như Theme.Holo.NoActionBar.Fullscreen.

    Ví dụ: sau đây là cách bạn có thể bật ảnh động "hiệu ứng chuyển tiếp":

    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 góc xoay của thiết bị mà không 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 hướng bắc từ.

    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 ước tính độ lệch. Tức là TYPE_GYROSCOPETYPE_MAGNETIC_FIELD hiện có cảm biến cung cấp dữ liệu cảm biến có tính đến độ lệch ước tính từ con quay hồi chuyển và sắt cứng trong thiết bị. Trong khi đó, các phiên bản "chưa được hiệu chuẩn" 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ị độ lệch ước tính. Những cảm biến này cho phép bạn cung cấp hiệu chỉnh tuỳ chỉnh riêng cho dữ liệu cảm biến bằng cách tăng độ chệch ước tính nhờ 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, NotificationListenerService, cho phép ứng dụng của bạn nhận thông tin về 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 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 để dùng những API này.

    Trình cung cấp danh bạ

    Truy vấn về "đối tượng có thể liên hệ"

    Truy vấn Contactables.CONTENT_URI của Trình cung cấp danh bạ mới là một cách hiệu quả để lấy một Cursor chứa tất cả địa chỉ email và số điện thoại của tất cả những 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 hiệu quả những thay đổi gần đây đối với dữ liệu danh bạ. Trước đây, ứng dụng của bạn có thể được thông báo khi có nội dung nào đó trong dữ liệu danh bạ thay đổi, nhưng bạn sẽ không biết chính xác điều gì đã thay đổi và cần phải truy xuất tất cả liên hệ, sau đó lặp lại để khám phá thay đổi.

    Để theo dõi các thay đổi đối với nội dung chèn và nội dung cập nhật, giờ đây, bạn có thể thêm thông 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 nhất bạn truy vấn nhà cung cấp.

    Để theo dõi những địa chỉ liên hệ đã bị xoá, bảng mới ContactsContract.DeletedContacts cung cấp nhật ký các địa chỉ liên hệ đã bị xoá (nhưng mỗi địa chỉ liên hệ đã xoá sẽ được lưu giữ trong bảng này trong một khoảng thời gian giới 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 cuối cùng 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ạ hiện phát đi 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, tạo lại cơ sở dữ liệu Trình cung cấp danh bạ một cách hiệu quả. Nút này được dùng để báo hiệu cho các ứng dụng rằng ứng dụng cần bỏ tất cả người liên hệ thông tin họ đã lưu trữ và tải lại thông tin đó bằng một truy vấn mới.

    Để xem mã mẫu sử dụng những API này nhằm kiểm tra thay đổi đối với danh bạ, hãy tìm trong Apidemos mẫu có sẵn trong nội dung tải xuống Mẫu SDK.

    Bản địa hoá

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

    Các phiên bản trước của Android 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 đúng cách văn bản theo hướng ngược lại mà không cắt xén bất kỳ phần nào của nội dung.

    Ví dụ: khi bạn muốn tạo một câu có một 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:

    Không

    Đó là sai vì "15" phải nằm bên trái "Bay Street". Giải pháp là sử dụng BidiFormatter và phương thức unicodeWrap() của lớp này. 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 hướng mạnh đầu tiên. Phương pháp này có thể gây ra lỗi nếu tín hiệu đầu tiên cho hướng văn bản không thể hiện hướng phù hợp cho toàn bộ nội dung. Nếu cần, bạn có thể chỉ định một phương pháp phỏng đoán khác bằng cách truyền một trong các hằng số TextDirectionHeuristic từ TextDirectionHeuristics đến 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ợ của Android, với lớp BidiFormatter và các API liên quan.

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

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

    Giờ đây, AccessibilityService có thể nhận lệnh gọi lại cho các sự kiện nhập phím bằng phương thức gọi lại onKeyEvent(). Điều này cho phép dịch vụ hỗ trợ tiếp cận xử lý dữ liệu đầu vào 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ỉ có thể thực hiện bằng phương thức nhập bằng thao tác chạm hoặc bàn phím định hướng 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 phầ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 thuộc tính hành động, ACTION_SET_SELECTION, truyền chọn vị trí bắt đầu và kết thúc 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 cách sử dụng hành động, 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, sau đó 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ợ của 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 các chức 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 này 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 dịch vụ của bạn khả năng hỗ trợ tiếp cận, bạn phải sử dụng các thuộc tính XML tương ứng với "chức năng" hằng số trong AccessibilityServiceInfo .

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

    Kiểm thử 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 các thao tác của người dùng để tự động hoá kiểm thử. Bằng cách sử dụng các API AccessibilityService của nền tảng, UiAutomation Các API 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(). Đơn đặt hàng để tính năng 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 từ 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 của bạn bằng cách gọi executeAndWaitForEvent(), truyền cho ứng dụng một Runnable để thực hiện, thời gian chờ thời gian cho hoạt động và quá trình triển khai giao diện UiAutomation.AccessibilityEventFilter. 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 kết quả thành công hoặc không thành công 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 cách triển khai UiAutomation.OnAccessibilityEventListener và truyền cách triển khai đó đến 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 có sự kiện xảy ra, nhận được đố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 việc phát triển các công cụ kiểm thử giao diện người dùng như uiautomator. Ví dụ: UiAutomation cũng có thể:

    • Chèn sự kiện đầu vào
    • Thay đổi hướng 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, các API UiAutomation hoạt động trên các ranh giới ứ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 với hai 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ủa mã có thể theo dõi trong ứng dụng của bạn, nhật ký systrace cung cấp cho bạn thông tin chi tiết hơn bản phân tích vị trí xảy ra ùn tắc nhẹ trong ứng dụng của bạn.

    Để 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 hoạt động hiển thị và hiệu suất với Systrace.

    Bảo mật

    Kho khoá Android cho khoá riêng tư của ứ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ó tên là Kho khoá Android. Kho khoá này 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 cho thành viên KeyPairGeneratorSpec. Đầu tiên nhận một thực thể của KeyPairGenerator bằng cách gọi getInstance(). Sau đó gọi initialize(), truyền vào đó một thực thể của KeyPairGeneratorSpec mà bạn có thể dùng KeyPairGeneratorSpec.Builder. Cuối cùng, hãy lấy KeyPair bằng cách gọi generateKeyPair().

    Lưu trữ thông tin xác thực phần cứng

    Android nay cũng hỗ trợ bộ nhớ dựa trên phần cứng cho KeyChain của bạn thông tin xác thực, giúp tăng tính bảo mật bằng cách không trích xuất khoá. Tức là sau khi các khoá nằm trong kho khoá được hỗ trợ phần cứng (Secure Element, TPM hoặc TrustZone), bạn có thể sử dụng các khoá đó cho các 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 không thể truy cập vào tài liệu 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ớ được hỗ trợ phần cứng hay không bằng cách gọi KeyChain.IsBoundKeyAlgorithm().

    Nội dung khai báo trong 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 của mình 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 một tiện ích ứng dụng và chỉ nên được cài đặt trên các thiết bị bao gồm 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 các thiết bị hỗ trợ ứng dụng Màn hình chính của bên thứ ba. 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 một phương thức nhập tuỳ chỉnh (bàn phím được tạo bằng InputMethodService) và chỉ được cài đặt trên các 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 năng lượng thấp và chỉ nên được cài đặt trên 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 đây 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 phải sử dụng các API NotificationListenerService mới.
    SEND_RESPOND_VIA_MESSAGE
    Bắt buộc phải nhận được ý định ACTION_RESPOND_VIA_MESSAGE.

    Để có cái nhìn 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 khác biệt về API.