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_height
và layout_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:
Để 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.
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.
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 MediaCodec
và MediaExtractor
. 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 MediaExtractor
và MediaCodec
. 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()
và
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()
và 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_UNCALIBRATED
và TYPE_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_GYROSCOPE
và TYPE_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_INT
và ACTION_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()
và 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.