ระดับ API: 18
Android 4.3 (JELLY_BEAN_MR2
) เป็นเวอร์ชันอัปเดตของ Jelly Bean ที่มีฟีเจอร์ใหม่ๆ สำหรับผู้ใช้และนักพัฒนาแอป เอกสารนี้ให้ข้อมูลเบื้องต้นเกี่ยวกับ API ใหม่ที่โดดเด่นที่สุด
ในฐานะนักพัฒนาแอป คุณควรดาวน์โหลดภาพระบบ Android 4.3 และแพลตฟอร์ม SDK จาก SDK Manager โดยเร็วที่สุด หากไม่มีอุปกรณ์ที่ใช้ Android 4.3 ในการทดสอบแอป ให้ใช้ภาพระบบ Android 4.3 เพื่อทดสอบแอปในโปรแกรมจำลอง Android จากนั้นสร้างแอปสำหรับแพลตฟอร์ม Android 4.3 เพื่อเริ่มใช้ API เวอร์ชันล่าสุด
อัปเดตระดับ API เป้าหมาย
หากต้องการเพิ่มประสิทธิภาพแอปสำหรับอุปกรณ์ที่ใช้ Android 4.3 ได้ดียิ่งขึ้น
คุณควรตั้งค่า targetSdkVersion
เป็น
"18"
ให้ติดตั้งในอิมเมจระบบ Android 4.3
แล้วเผยแพร่อัปเดตที่มีการเปลี่ยนแปลงนี้
คุณสามารถใช้ API ใน Android 4.3 ไปพร้อมกับรองรับเวอร์ชันเก่าได้ด้วยการเพิ่มเงื่อนไขลงในโค้ดที่ตรวจสอบระดับ API ของระบบก่อนที่จะเรียกใช้ API ที่ minSdkVersion
ไม่รองรับ
ดูข้อมูลเพิ่มเติมเกี่ยวกับการคงความเข้ากันได้ย้อนหลังได้ที่การรองรับเวอร์ชันแพลตฟอร์มที่แตกต่างกัน
นอกจากนี้ API ต่างๆ ยังพร้อมใช้งานในคลังการสนับสนุนของ Android ซึ่งช่วยให้คุณใช้ฟีเจอร์ใหม่ๆ ในแพลตฟอร์มเวอร์ชันเก่าได้
ดูข้อมูลเพิ่มเติมเกี่ยวกับวิธีการทำงานของระดับ API ได้ที่ระดับ API คืออะไร
การเปลี่ยนแปลงที่สำคัญเกี่ยวกับลักษณะการทำงาน
หากคุณเคยเผยแพร่แอปสำหรับ Android โปรดทราบว่าแอปของคุณอาจได้รับผลกระทบจากการเปลี่ยนแปลงใน Android 4.3
หากแอปใช้ Intent แบบไม่เจาะจงปลายทาง...
แอปของคุณอาจทำงานผิดพลาดในสภาพแวดล้อมโปรไฟล์ที่จำกัด
ผู้ใช้ในสภาพแวดล้อมโปรไฟล์ที่ถูกจำกัดอาจไม่สามารถ
มีแอป Android มาตรฐานทั้งหมดที่ใช้ได้ เช่น โปรไฟล์ที่จำกัดอาจปิดใช้เว็บเบราว์เซอร์และแอปกล้อง ดังนั้นแอปของคุณไม่ควรคาดเดาว่าแอปใดพร้อมใช้งาน เนื่องจากหากคุณเรียกใช้ startActivity()
โดยไม่ตรวจสอบว่ามีแอปใดพร้อมจัดการ Intent
หรือไม่ แอปอาจขัดข้องในโปรไฟล์ที่จํากัด
เมื่อใช้ Intent ที่ไม่ชัดแจ้ง คุณควรตรวจสอบเสมอว่าแอปพร้อมที่จะจัดการ Intent ดังกล่าวโดยการเรียก resolveActivity()
หรือ queryIntentActivities()
เช่น
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(); }
หากแอปใช้บัญชี
แอปของคุณอาจทำงานผิดพลาดในสภาพแวดล้อมโปรไฟล์ที่จำกัด
ผู้ใช้ในสภาพแวดล้อมโปรไฟล์ที่ถูกจำกัดจะไม่มีสิทธิ์เข้าถึงบัญชีผู้ใช้โดยค่าเริ่มต้น
หากแอปของคุณใช้ Account
แอปอาจขัดข้องหรือทำงานผิดปกติเมื่อใช้ในโปรไฟล์ที่จํากัด
หากต้องการป้องกันไม่ให้โปรไฟล์ที่จำกัดใช้แอปทั้งหมดเนื่องจาก
แอปขึ้นอยู่กับข้อมูลบัญชีที่มีความละเอียดอ่อน ให้ระบุแอตทริบิวต์ android:requiredAccountType
ใน <application>
ของไฟล์ Manifest
หากต้องการอนุญาตให้โปรไฟล์ที่ถูกจํากัดใช้แอปต่อไปแม้ว่าจะสร้างบัญชีของตนเองไม่ได้ คุณสามารถปิดใช้ฟีเจอร์ของแอปที่ต้องใช้บัญชี หรืออนุญาตให้โปรไฟล์ที่ถูกจํากัดเข้าถึงบัญชีที่สร้างโดยผู้ใช้หลัก สำหรับข้อมูลเพิ่มเติม โปรดดูที่ส่วน ด้านล่างเกี่ยวกับการสนับสนุนบัญชีในโปรไฟล์ที่ถูกจำกัด
หากแอปใช้ VideoView
วิดีโอของคุณอาจมีขนาดเล็กลงใน Android 4.3
ใน Android เวอร์ชันก่อนหน้า วิดเจ็ต VideoView
ไม่ถูกต้อง
คำนวณค่า "wrap_content"
สำหรับ layout_height
และ layout_width
ให้เหมือนกับ "match_parent"
ดังนั้นในขณะที่ใช้ "wrap_content"
สำหรับความสูงหรือความกว้างอาจมีเลย์เอาต์วิดีโอที่คุณต้องการก่อนหน้านี้แล้ว
ซึ่งอาจทำให้วิดีโอมีขนาดเล็กลงมากบน Android 4.3 และเวอร์ชันที่สูงกว่า หากต้องการแก้ไขปัญหา ให้แทนที่ "wrap_content"
ด้วย "match_parent"
และตรวจสอบว่าวิดีโอปรากฏตามที่คาดไว้บน Android 4.3 และเวอร์ชันเก่า
โปรไฟล์ที่ถูกจำกัด
ในแท็บเล็ต Android ผู้ใช้สามารถสร้างโปรไฟล์แบบจำกัดโดยอิงตามผู้ใช้หลักได้แล้ว เมื่อสร้างโปรไฟล์ที่จำกัด ผู้ใช้สามารถเปิดใช้ข้อจำกัดต่างๆ เช่น แอปใดบ้างที่ ใช้ได้กับโปรไฟล์ นอกจากนี้ API ชุดใหม่ใน Android 4.3 ยังช่วยให้คุณสร้างชิ้นงานที่ละเอียดขึ้นได้ การตั้งค่าการจำกัดสำหรับแอปที่คุณพัฒนา ตัวอย่างเช่น เมื่อใช้ API ใหม่ คุณจะทำสิ่งต่อไปนี้ได้ ช่วยให้ผู้ใช้ควบคุมประเภทเนื้อหาที่พร้อมใช้งานภายในแอปเมื่อเรียกใช้ สภาพแวดล้อมโปรไฟล์ที่จำกัด
UI สำหรับผู้ใช้ในการควบคุมข้อจำกัดที่คุณสร้างขึ้นจะจัดการโดยแอปพลิเคชันการตั้งค่าของระบบ หากต้องการให้การตั้งค่าข้อจำกัดของแอปปรากฏต่อผู้ใช้
คุณต้องประกาศการจำกัดที่แอปกำหนดโดยการสร้าง BroadcastReceiver
ที่ได้รับ Intent ACTION_GET_RESTRICTION_ENTRIES
ระบบจะเรียกใช้ Intent นี้เพื่อค้นหาข้อจำกัดที่มีในแอปทั้งหมด จากนั้นสร้าง UI เพื่ออนุญาตให้ผู้ใช้หลักจัดการข้อจำกัดสำหรับโปรไฟล์ที่ถูกจำกัดแต่ละรายการ
ในเมธอด onReceive()
ของ
BroadcastReceiver
คุณต้องสร้าง RestrictionEntry
สำหรับข้อจำกัดแต่ละรายการที่แอปมีให้ RestrictionEntry
แต่ละรายการจะกำหนดชื่อ คำอธิบาย ข้อจำกัด และข้อมูลประเภทใดประเภทหนึ่งต่อไปนี้
TYPE_BOOLEAN
สำหรับข้อจำกัดที่เป็นจริงหรือเท็จTYPE_CHOICE
สำหรับข้อจำกัดที่มี ตัวเลือกที่หลากหลายซึ่งไม่เกี่ยวข้องกัน (ตัวเลือกปุ่มตัวเลือก)TYPE_MULTI_SELECT
สำหรับข้อจำกัดที่มีตัวเลือกหลายรายการที่ไม่เป็นตัวเลือกที่เฉพาะตัวเหมือนกัน (ตัวเลือกช่องทำเครื่องหมาย)
จากนั้นใส่ออบเจ็กต์ RestrictionEntry
ทั้งหมดลงใน ArrayList
แล้วใส่ลงในผลลัพธ์ของผู้รับการออกอากาศเป็นค่าสำหรับข้อมูลเพิ่มเติม EXTRA_RESTRICTIONS_LIST
ระบบจะสร้าง UI สําหรับข้อจํากัดของแอปคุณในแอปการตั้งค่า และบันทึกข้อจํากัดแต่ละรายการด้วยคีย์ที่ไม่ซ้ำกันที่คุณระบุสําหรับRestrictionEntry
ออบเจ็กต์แต่ละรายการ เมื่อผู้ใช้เปิดแอป คุณสามารถค้นหาข้อจํากัดปัจจุบันได้โดยเรียกใช้ getApplicationRestrictions()
การดำเนินการนี้จะแสดงผล Bundle
ที่มีคู่คีย์-ค่าสำหรับข้อจำกัดแต่ละรายการ
ที่คุณกำหนดด้วยออบเจ็กต์ RestrictionEntry
หากต้องการระบุข้อจํากัดที่เฉพาะเจาะจงมากขึ้นซึ่งค่าบูลีน ค่าตัวเลือกเดียว และค่าตัวเลือกหลายรายการจัดการไม่ได้ คุณสามารถสร้างกิจกรรมที่ผู้ใช้ระบุข้อจํากัดได้ และอนุญาตให้ผู้ใช้เปิดกิจกรรมนั้นจากการตั้งค่าข้อจํากัด ใน
Broadcast Receiver รวม EXTRA_RESTRICTIONS_INTENT
เพิ่มเติม
ในผลลัพธ์ Bundle
ส่วนเกินนี้ต้องระบุ Intent
กำลังระบุคลาส Activity
ที่จะเปิดตัว (ใช้
putParcelable()
เพื่อส่ง EXTRA_RESTRICTIONS_INTENT
พร้อม Intent)
เมื่อผู้ใช้หลักเข้าสู่กิจกรรมเพื่อตั้งค่าข้อจํากัดที่กําหนดเอง กิจกรรมของคุณจะต้องแสดงผลลัพธ์ที่มีค่าข้อจํากัดในส่วนเพิ่มเติมโดยใช้คีย์ EXTRA_RESTRICTIONS_LIST
หรือ EXTRA_RESTRICTIONS_BUNDLE
ทั้งนี้ขึ้นอยู่กับว่าคุณระบุออบเจ็กต์ RestrictionEntry
หรือคู่คีย์-ค่าตามลําดับ
การสนับสนุนบัญชีในโปรไฟล์ที่ถูกจำกัด
บัญชีที่เพิ่มลงในผู้ใช้หลักจะใช้ได้กับโปรไฟล์ที่มีข้อจำกัด แต่บัญชีดังกล่าวจะเข้าถึงจาก AccountManager
API ไม่ได้โดยค่าเริ่มต้น
หากพยายามเพิ่มบัญชีด้วย AccountManager
ขณะอยู่ในโปรไฟล์ที่มีข้อจำกัด คุณจะได้ผลลัพธ์ที่ไม่สำเร็จ และเนื่องจากข้อจำกัดเหล่านี้ คุณจึงมีสิ่งต่อไปนี้
สามตัวเลือก:
หากต้องการเข้าถึงบัญชีจากโปรไฟล์ที่ถูกจำกัด คุณต้องเพิ่มแอตทริบิวต์ android:restrictedAccountType
ลงในแท็ก <application> ดังนี้
<application ... android:restrictedAccountType="com.example.account.type" >
ข้อควรระวัง: การเปิดใช้แอตทริบิวต์นี้จะทำให้ สิทธิ์เข้าถึงของแอปเพื่อเข้าถึงบัญชีของผู้ใช้หลักจากโปรไฟล์ที่ถูกจำกัด คุณจึงควรอนุญาตเฉพาะในกรณีที่แอปแสดงข้อมูลที่ไม่ได้เปิดเผยข้อมูลส่วนบุคคลที่ระบุตัวบุคคลนั้นได้ (PII) ซึ่งถือว่ามีความละเอียดอ่อน การตั้งค่าระบบจะแจ้ง ว่าแอปของคุณให้สิทธิ์โปรไฟล์ที่จำกัดกับบัญชีของตน ดังนั้นจึงควรแจ้งให้ผู้ใช้ทราบอย่างชัดเจน การเข้าถึงบัญชีนั้นสำคัญต่อฟังก์ชันการทำงานของแอป นอกจากนี้ คุณควรจัดให้มีการควบคุมการจํากัดที่เพียงพอสําหรับผู้ใช้หลักเพื่อกําหนดระดับการเข้าถึงบัญชีที่อนุญาตในแอปด้วย หากทําได้
หากต้องการใช้บัญชี แต่ไม่ได้กำหนดว่าต้องใช้กับบัญชีหลักของแอป
คุณสามารถตรวจสอบความพร้อมใช้งานของบัญชี
และปิดใช้ฟีเจอร์เมื่อไม่พร้อมใช้งาน
คุณควรตรวจสอบก่อนว่าบัญชีที่มีอยู่ใช้งานได้หรือไม่ หากไม่เป็นเช่นนั้น ให้ค้นหาว่า
คุณสร้างบัญชีใหม่ได้โดยโทรไปที่ getUserRestrictions()
และตรวจสอบส่วน DISALLOW_MODIFY_ACCOUNTS
เพิ่มเติมในผลลัพธ์ หากเป็นtrue
คุณควรปิดใช้ฟังก์ชันใดก็ตามของแอปที่จำเป็นต้องเข้าถึงบัญชี
เช่น
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 }
หมายเหตุ: ในกรณีนี้ คุณไม่ควรประกาศแอตทริบิวต์ใหม่ในไฟล์ Manifest
หากแต่เป็นเรื่องสำคัญที่แอปจะไม่สามารถใช้ได้กับโปรไฟล์ที่ถูกจำกัดเนื่องจาก
แอปของคุณต้องใช้ข้อมูลส่วนบุคคลที่มีความละเอียดอ่อนในบัญชี (และเนื่องจากโปรไฟล์ที่ถูกจำกัด
ขณะนี้ไม่สามารถเพิ่มบัญชีใหม่) เพิ่ม
แอตทริบิวต์ android:requiredAccountType
เป็นแท็ก <application>
<application ... android:requiredAccountType="com.example.account.type" >
เช่น แอป Gmail ใช้แอตทริบิวต์นี้เพื่อปิดใช้ตัวเองสำหรับโปรไฟล์ที่ถูกจำกัด เนื่องจากอีเมลส่วนตัวของเจ้าของไม่ควรอยู่ในโปรไฟล์ที่ถูกจำกัด
ระบบไร้สายและการเชื่อมต่อ
บลูทูธพลังงานต่ำ (พร้อมใช้งานแบบอัจฉริยะ)
ตอนนี้ Android รองรับบลูทูธพลังงานต่ำ (LE) ด้วย API ใหม่ใน android.bluetooth
API ใหม่นี้จะช่วยให้คุณสร้างแอป Android ที่สื่อสารกับอุปกรณ์ต่อพ่วงบลูทูธพลังงานต่ำได้ เช่น เครื่องวัดอัตราการเต้นของหัวใจและเครื่องนับก้าว
เนื่องจากบลูทูธ LE เป็นฟีเจอร์ฮาร์ดแวร์ที่พร้อมใช้งานในอุปกรณ์ Android บางรุ่นเท่านั้น คุณจึงต้องประกาศองค์ประกอบ <uses-feature>
ของ "android.hardware.bluetooth_le"
ในไฟล์ Manifest ดังนี้
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true" />
หากคุณคุ้นเคยกับ API บลูทูธแบบคลาสสิกของ Android ดีอยู่แล้ว ให้สังเกตว่าการใช้
Bluetooth LE API มีความแตกต่างกันอยู่บ้าง สิ่งสำคัญที่สุดคือตอนนี้มีคลาส BluetoothManager
ที่คุณควรใช้สำหรับการดำเนินการระดับสูงบางอย่าง
เช่น การรับ BluetoothAdapter
การรับรายการที่เชื่อมโยง
อุปกรณ์ และการตรวจสอบสถานะของอุปกรณ์ ตัวอย่างเช่น ตอนนี้คุณควรรับ
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();
หากต้องการค้นหาอุปกรณ์ต่อพ่วงบลูทูธ LE ให้เรียก startLeScan()
ใน BluetoothAdapter
โดยส่งการใช้งานอินเทอร์เฟซ BluetoothAdapter.LeScanCallback
เมื่อบลูทูธ
อะแดปเตอร์ตรวจพบอุปกรณ์ต่อพ่วง Bluetooth LE การใช้งาน BluetoothAdapter.LeScanCallback
ได้รับสายเรียกเข้า
onLeScan()
วิธี วิธีการนี้จะแสดงออบเจ็กต์ BluetoothDevice
ที่แสดงถึงอุปกรณ์ที่ตรวจพบ ค่า RSSI ของอุปกรณ์ และอาร์เรย์ไบต์ที่มีระเบียนการโฆษณาของอุปกรณ์
หากต้องการสแกนเฉพาะอุปกรณ์ต่อพ่วงบางประเภท ให้เรียกใช้ startLeScan()
และใส่อาร์เรย์ของออบเจ็กต์ UUID
ที่ระบุบริการ GATT ที่แอปรองรับแทน
หมายเหตุ: คุณจะสแกนหาได้เฉพาะอุปกรณ์บลูทูธ LE หรือสแกนหาอุปกรณ์บลูทูธคลาสสิกโดยใช้ API เวอร์ชันก่อนหน้า คุณจะสแกนหาทั้งอุปกรณ์บลูทูธ LE และบลูทูธคลาสสิกพร้อมกันไม่ได้
แล้วโทรหา connectGatt()
ที่อุปกรณ์ที่เกี่ยวข้อง เพื่อเชื่อมต่อกับอุปกรณ์ต่อพ่วง Bluetooth LE
BluetoothDevice
ออบเจ็กต์ผ่านการติดตั้งใช้งาน
BluetoothGattCallback
การติดตั้งใช้งาน BluetoothGattCallback
ของคุณจะได้รับการเรียกกลับเกี่ยวกับสถานะการเชื่อมต่อกับอุปกรณ์และเหตุการณ์อื่นๆ อยู่ในช่วง onConnectionStateChange()
Callback ที่คุณจะเริ่มสื่อสารกับอุปกรณ์ได้หากเมธอดผ่าน STATE_CONNECTED
เป็นสถานะใหม่
การเข้าถึงฟีเจอร์บลูทูธในอุปกรณ์ยังกำหนดให้แอปของคุณขอสิทธิ์บางอย่างจากผู้ใช้บลูทูธด้วย โปรดดูข้อมูลเพิ่มเติมในคู่มือ Bluetooth Low Energy API
โหมดสแกน Wi-Fi เท่านั้น
เมื่อพยายามระบุตำแหน่งของผู้ใช้ Android อาจใช้ Wi-Fi เพื่อช่วยระบุ ตำแหน่งได้โดยการสแกนจุดเข้าใช้งานใกล้เคียง อย่างไรก็ตาม ผู้ใช้มักปิด Wi-Fi ไว้เพื่อประหยัดแบตเตอรี่ ซึ่งส่งผลให้ข้อมูลตำแหน่งมีความแม่นยำน้อยลง ตอนนี้ Android มี โหมดสแกนเท่านั้นที่อนุญาตให้ Wi-Fi ของอุปกรณ์สแกนจุดเข้าใช้งานเพื่อรับตำแหน่ง โดยไม่ต้องเชื่อมต่อจุดเข้าใช้งาน ซึ่งจะลดการใช้งานแบตเตอรี่ลงอย่างมาก
หากต้องการทราบตำแหน่งของผู้ใช้แต่ Wi-Fi ปิดอยู่ คุณสามารถขอให้ผู้ใช้เปิดใช้โหมดสแกน Wi-Fi เท่านั้นได้โดยเรียกใช้ startActivity()
ด้วยการดำเนินการ ACTION_REQUEST_SCAN_ALWAYS_AVAILABLE
การกำหนดค่า Wi-Fi
WifiEnterpriseConfig
API ใหม่ช่วยให้บริการแบบองค์กรทำสิ่งต่อไปนี้ได้
กำหนดค่า Wi-Fi สำหรับอุปกรณ์ที่มีการจัดการโดยอัตโนมัติ
การตอบกลับอย่างรวดเร็วสำหรับสายเรียกเข้า
ตั้งแต่ Android 4.0 ฟีเจอร์ชื่อ "คำตอบด่วน" ช่วยให้ผู้ใช้สามารถตอบสนองต่อ
ด้วยการส่งข้อความทันที โดยไม่จำเป็นต้องรับสายหรือปลดล็อกอุปกรณ์
ก่อนหน้านี้แอปรับส่งข้อความเริ่มต้นจะจัดการข้อความด่วนเหล่านี้เสมอ แต่ตอนนี้แอปใดก็ได้สามารถประกาศความสามารถของตนในการจัดการข้อความเหล่านี้ได้โดยการสร้าง Service
ที่มีตัวกรอง Intent สำหรับ ACTION_RESPOND_VIA_MESSAGE
เมื่อผู้ใช้ตอบกลับสายเรียกเข้าด้วยการตอบกลับอย่างรวดเร็ว แอปโทรศัพท์จะส่ง Intent ACTION_RESPOND_VIA_MESSAGE
พร้อม URI ที่อธิบายผู้รับ (ผู้โทร) และ EXTRA_TEXT
เพิ่มเติมพร้อมข้อความที่ผู้ใช้ต้องการส่ง เมื่อบริการได้รับความตั้งใจ บริการควรส่งมอบ
ข้อความและหยุดตัวเองทันที (แอปของคุณไม่ควรแสดงกิจกรรม)
หากต้องการรับ Intent นี้ คุณต้องประกาศสิทธิ์ SEND_RESPOND_VIA_MESSAGE
มัลติมีเดีย
การปรับปรุง MediaExtractor และ MediaCodec
ตอนนี้ Android ให้คุณเขียน Dynamic Adaptive เองได้ง่ายขึ้น
การสตรีมผ่านโปรแกรมเล่น HTTP (DASH) ตามมาตรฐาน ISO/IEC 23009-1
ใช้ API ที่มีอยู่ใน MediaCodec
และ MediaExtractor
เฟรมเวิร์กที่อยู่เบื้องหลัง API เหล่านี้ได้รับการอัปเดตให้รองรับการแยกวิเคราะห์ไฟล์ MP4 ที่กระจัดกระจาย แต่แอปของคุณยังคงต้องรับผิดชอบในการแยกวิเคราะห์ข้อมูลเมตา MPD และส่งสตรีมแต่ละรายการไปยัง MediaExtractor
หากต้องการใช้ DASH กับเนื้อหาที่เข้ารหัส โปรดทราบว่าเมธอด getSampleCryptoInfo()
จะแสดงผลข้อมูลเมตา MediaCodec.CryptoInfo
ที่อธิบายโครงสร้างของตัวอย่างสื่อที่เข้ารหัสแต่ละรายการ นอกจากนี้ เรายังได้เพิ่มเมธอด getPsshInfo()
ลงใน MediaExtractor
เพื่อให้คุณเข้าถึงข้อมูลเมตา PSSH สำหรับสื่อ DASH ได้
เมธอดนี้จะแสดงผลแผนที่ของออบเจ็กต์ UUID
เป็นไบต์ โดยที่ UUID
จะระบุรูปแบบการเข้ารหัส และไบต์จะเป็นข้อมูลที่เจาะจงสำหรับรูปแบบนั้น
DRM ของสื่อ
คลาส MediaDrm
ใหม่เป็นโซลูชันแบบโมดูลสำหรับการจัดการสิทธิ์ดิจิทัล (DRM) กับเนื้อหาสื่อของคุณโดยแยกข้อกังวลเกี่ยวกับ DRM ออกจากการเล่นสื่อ สำหรับ
ตัวอย่างเช่น การแยก API นี้ช่วยให้คุณเล่นเนื้อหาที่เข้ารหัส Widevine ได้โดยไม่ต้อง
เพื่อใช้รูปแบบสื่อ Widevine โซลูชัน DRM นี้ยังรองรับการเข้ารหัสทั่วไป DASH คุณจึง
สามารถใช้แผน DRM ที่หลากหลายกับเนื้อหาสตรีมมิงของคุณ
คุณสามารถใช้ MediaDrm
เพื่อรับข้อความคําขอคีย์แบบทึบ และประมวลผลข้อความการตอบกลับคีย์จากเซิร์ฟเวอร์สําหรับการขอใบอนุญาตและการจัดสรร แอปของคุณเป็นแบบ
รับผิดชอบการจัดการการสื่อสารของเครือข่ายกับเซิร์ฟเวอร์ คลาส MediaDrm
จะให้ความสามารถในการสร้างและประมวลผลข้อความเท่านั้น
API ของ MediaDrm
มีวัตถุประสงค์เพื่อใช้ร่วมกับ
MediaCodec
API ที่เปิดตัวใน Android 4.1 (API ระดับ 16)
ซึ่งรวมถึง MediaCodec
สำหรับการเข้ารหัสและถอดรหัสเนื้อหา MediaCrypto
สำหรับจัดการเนื้อหาที่เข้ารหัส และ MediaExtractor
ในการแยกและแยกส่วนเนื้อหาไม่ได้
ก่อนอื่น คุณต้องสร้าง MediaExtractor
และ
MediaCodec
ออบเจ็กต์ จากนั้นคุณจะเข้าถึง UUID
ที่ระบุรูปแบบ DRM ได้ ซึ่งโดยปกติแล้วมาจากข้อมูลเมตาในเนื้อหา และใช้เพื่อสร้างอินสแตนซ์ของออบเจ็กต์ MediaDrm
ด้วยคอนสตรัคเตอร์
การเข้ารหัสวิดีโอจาก Surface
Android 4.1 (API ระดับ 16) เพิ่มคลาส MediaCodec
สำหรับระดับต่ำ
การเข้ารหัสและถอดรหัสของเนื้อหาสื่อ เมื่อเข้ารหัสวิดีโอ Android 4.1 กำหนดให้คุณระบุสื่อด้วยอาร์เรย์ ByteBuffer
แต่ตอนนี้ Android 4.3 อนุญาตให้คุณใช้ Surface
เป็นอินพุตให้กับโปรแกรมเข้ารหัส ตัวอย่างเช่น วิธีนี้ให้คุณเข้ารหัสอินพุต
จากไฟล์วิดีโอที่มีอยู่หรือใช้เฟรมที่สร้างจาก OpenGL ES
หากต้องการใช้ Surface
เป็นอินพุตให้กับโปรแกรมเปลี่ยนไฟล์ ให้เรียกใช้ configure()
สำหรับ MediaCodec
ก่อน
จากนั้นโทรไปที่ createInputSurface()
เพื่อรับ Surface
ซึ่งคุณจะสตรีมสื่อได้
ตัวอย่างเช่น คุณสามารถใช้ Surface
ที่ระบุเป็นหน้าต่างสำหรับบริบท OpenGL โดยส่งผ่านไปยัง eglCreateWindowSurface()
จากนั้นขณะแสดงภาพพื้นผิว ให้เรียก eglSwapBuffers()
เพื่อส่งเฟรมไปยัง MediaCodec
หากต้องการเริ่มเข้ารหัส โปรดโทรหา start()
ใน MediaCodec
เมื่อเสร็จแล้ว ให้โทรหา signalEndOfInputStream()
เพื่อสิ้นสุดการเข้ารหัส แล้วโทรหา release()
ใน Surface
การรวมสื่อ
คลาส MediaMuxer
ใหม่ช่วยให้สามารถมัลติเพล็กซ์ระหว่างสตรีมเสียง 1 รายการกับสตรีมวิดีโอ 1 รายการ API เหล่านี้ทำหน้าที่เป็นสิ่งที่เหมือนกับ MediaExtractor
ที่เพิ่มใน Android 4.2 สำหรับสื่อการแยกสัญญาณ (Demuxing) สื่อ
รูปแบบเอาต์พุตที่รองรับจะกำหนดไว้ใน MediaMuxer.OutputFormat
ปัจจุบัน
MP4 เป็นรูปแบบเอาต์พุตเดียวที่รองรับและขณะนี้ MediaMuxer
รองรับ
สตรีมเสียงครั้งละ 1 รายการและ/หรือ 1 สตรีมเท่านั้น
MediaMuxer
ได้รับการออกแบบมาให้ทำงานกับ MediaCodec
เป็นส่วนใหญ่
เพื่อให้คุณสามารถประมวลผลวิดีโอผ่าน MediaCodec
จากนั้นบันทึก
ออกเป็นไฟล์ MP4 จนถึง MediaMuxer
คุณยังสามารถใช้ MediaMuxer
ร่วมกับ MediaExtractor
เพื่อดำเนินการได้อีกด้วย
แก้ไขสื่อได้โดยไม่ต้องเข้ารหัสหรือถอดรหัส
ความคืบหน้าในการเล่นและการสครับสำหรับ RemoteControlClient
ใน Android 4.0 (API ระดับ 14) ระบบได้เพิ่ม RemoteControlClient
ลงใน
เปิดใช้งานตัวควบคุมการเล่นสื่อจากไคลเอ็นต์รีโมตคอนโทรล เช่น ตัวควบคุมที่มีใน
ล็อกหน้าจอ ตอนนี้ Android 4.3 ช่วยให้ตัวควบคุมดังกล่าวแสดงตำแหน่งการเล่นและตัวควบคุมสำหรับการกรอเล่นได้ ถ้าคุณเปิดใช้งานรีโมตคอนโทรลสำหรับ
แอปสื่อที่มี API ของ RemoteControlClient
คุณจะสามารถอนุญาตการเล่น
โดยใช้อินเทอร์เฟซใหม่ 2 แบบ
ก่อนอื่น คุณต้องเปิดใช้ Flag FLAG_KEY_MEDIA_POSITION_UPDATE
โดยส่ง Flag นั้นให้กับ
setTransportControlsFlags()
จากนั้นติดตั้งใช้งานอินเทอร์เฟซใหม่ 2 รายการต่อไปนี้
RemoteControlClient.OnGetPlaybackPositionListener
- รวมถึง Callback
onGetPlaybackPosition()
ที่ขอตำแหน่งปัจจุบัน ของสื่อเมื่อรีโมตคอนโทรลจำเป็นต้องอัปเดตความคืบหน้าใน UI RemoteControlClient.OnPlaybackPositionUpdateListener
- รวมถึง Callback
onPlaybackPositionUpdate()
ที่ จะบอกรหัสเวลาใหม่สำหรับสื่อของคุณแก่แอปของคุณเมื่อผู้ใช้สครับการเล่นด้วย UI ของรีโมตคอนโทรลเมื่ออัปเดตการเล่นด้วยตำแหน่งใหม่แล้ว ให้เรียกใช้
setPlaybackState()
เพื่อระบุสถานะการเล่น ตำแหน่ง และความเร็วใหม่
เมื่อกำหนดอินเทอร์เฟซเหล่านี้แล้ว คุณจะตั้งค่าอินเทอร์เฟซสำหรับ RemoteControlClient
ได้โดยเรียกใช้ setOnGetPlaybackPositionListener()
และ
setPlaybackPositionUpdateListener()
ตามลำดับ
กราฟิก
การรองรับ OpenGL ES 3.0
Android 4.3 เพิ่มอินเทอร์เฟซ Java และการรองรับ OpenGL ES 3.0 ในตัว ฟังก์ชันใหม่ที่สำคัญ ที่มีให้ใน OpenGL ES 3.0 รวมถึง
- การเร่งเอฟเฟกต์ภาพขั้นสูง
- การบีบอัดพื้นผิว ETC2/EAC คุณภาพสูงเป็นฟีเจอร์มาตรฐาน
- ภาษาการจัดแสง GLSL ES เวอร์ชันใหม่ที่รองรับจำนวนเต็มและทศนิยม 32 บิต
- การแสดงผลพื้นผิวขั้นสูง
- การกำหนดมาตรฐานขนาดพื้นผิวและรูปแบบบัฟเฟอร์การแสดงผลที่กว้างขึ้น
อินเทอร์เฟซ Java สำหรับ OpenGL ES 3.0 บน Android ให้มาพร้อมกับ GLES30
เมื่อใช้ OpenGL ES 3.0 โปรดประกาศในไฟล์ Manifest ที่มีเมธอด
<uses-feature>
และแอตทริบิวต์ android:glEsVersion
เช่น
<manifest> <uses-feature android:glEsVersion="0x00030000" /> ... </manifest>
และอย่าลืมระบุบริบท OpenGL ES โดยเรียก setEGLContextClientVersion()
กำลังส่ง 3
เป็นเวอร์ชัน
ดูข้อมูลเพิ่มเติมเกี่ยวกับการใช้ OpenGL ES รวมถึงวิธีตรวจสอบเวอร์ชัน OpenGL ES ที่รองรับของอุปกรณ์ขณะรันไทม์ได้ที่คู่มือ API ของ OpenGL ES
Mipmapping สําหรับ Drawable
การใช้ mipmap เป็นแหล่งที่มาของบิตแมปหรือ Drawable เป็นวิธีที่ง่ายในการสร้างรูปภาพที่มีคุณภาพและปรับขนาดรูปภาพได้หลายแบบ ซึ่งจะมีประโยชน์อย่างยิ่งในกรณีที่คุณต้องการปรับขนาดรูปภาพระหว่างภาพเคลื่อนไหว
Android 4.2 (API ระดับ 17) เพิ่มการรองรับ MIPMAP ในคลาส Bitmap
โดย Android จะสลับรูปภาพ MIP ใน Bitmap
เมื่อคุณระบุแหล่งที่มาของ MIPMAP และเปิดใช้ setHasMipMap()
ขณะนี้ใน Android 4.3 คุณสามารถเปิดใช้ mipmaps สำหรับออบเจ็กต์ BitmapDrawable
ได้เช่นกัน โดยจัดทำเนื้อหา mipmap และ
การตั้งค่าแอตทริบิวต์ android:mipMap
ในไฟล์ทรัพยากรบิตแมปหรือโดยการเรียกใช้ hasMipMap()
อินเทอร์เฟซผู้ใช้
ดูการวางซ้อน
คลาส ViewOverlay
ใหม่จะสร้างเลเยอร์โปร่งใสเหนือ View
ซึ่งคุณสามารถเพิ่มเนื้อหาที่เป็นภาพได้โดยไม่ส่งผลต่อลําดับชั้นของเลย์เอาต์ คุณรับ ViewOverlay
สำหรับ View
ใดก็ได้โดยโทรไปที่ getOverlay()
การวางซ้อน
จะมีขนาดและตำแหน่งเดียวกับมุมมองโฮสต์เสมอ (มุมมองที่ใช้สร้างมุมมองนี้)
ซึ่งทำให้คุณสามารถเพิ่มเนื้อหาที่ปรากฏด้านหน้ามุมมองโฮสต์ แต่ขยายไม่ได้
ขอบเขตของมุมมองโฮสต์นั้น
การใช้ ViewOverlay
จะมีประโยชน์อย่างยิ่งเมื่อคุณต้องการสร้างภาพเคลื่อนไหว เช่น การเลื่อนมุมมองออกจากคอนเทนเนอร์หรือย้ายรายการไปรอบๆ หน้าจอโดยไม่ส่งผลต่อลําดับชั้นของมุมมอง อย่างไรก็ตาม เนื่องจากพื้นที่ที่ใช้งานได้ของการวางซ้อนถูกจำกัดไว้ในพื้นที่เดียวกับวิวโฮสต์ หากต้องการแสดงภาพเคลื่อนไหวของวิวที่เคลื่อนไหวนอกตำแหน่งในเลย์เอาต์ คุณต้องใช้การวางซ้อนจากวิวหลักที่มีขอบเขตเลย์เอาต์ที่ต้องการ
เมื่อคุณสร้างโฆษณาซ้อนทับสำหรับมุมมองวิดเจ็ต เช่น Button
คุณจะ
สามารถเพิ่มวัตถุ Drawable
รายการลงในการวางซ้อนโดยเรียก
add(Drawable)
หากคุณเรียกใช้ getOverlay()
สำหรับมุมมองเลย์เอาต์ เช่น RelativeLayout
ระบบจะแสดงผลออบเจ็กต์เป็น ViewGroupOverlay
คลาส ViewGroupOverlay
เป็นคลาสย่อยของ ViewOverlay
ซึ่งช่วยให้คุณเพิ่มออบเจ็กต์ View
ได้ด้วยโดยการเรียกใช้ add(View)
หมายเหตุ: เนื้อหาที่ถอนออกได้และมุมมองทั้งหมดที่คุณเพิ่มไปยังการวางซ้อน เป็นภาพเท่านั้น แต่จะรับเหตุการณ์โฟกัสหรืออินพุตไม่ได้
ตัวอย่างเช่น โค้ดต่อไปนี้จะแสดงภาพเคลื่อนไหวของมุมมองที่เลื่อนไปทางขวาโดยวางมุมมองนั้นไว้ในการวางซ้อนของมุมมองหลัก จากนั้นทำภาพเคลื่อนไหวของการแปลในมุมมองนั้น
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();
เลย์เอาต์ขอบเขตแบบออปติคัล
สำหรับมุมมองที่มีรูปภาพพื้นหลังแบบ 9 ส่วน ตอนนี้คุณระบุได้แล้วว่าจะให้จัดแนวมุมมองดังกล่าวให้สอดคล้องกับมุมมองที่อยู่ใกล้เคียงโดยอิงตามขอบเขต "ภาพที่เห็น" ของรูปภาพพื้นหลังแทนขอบเขต "คลิป" ของมุมมอง
ตัวอย่างเช่น รูปที่ 1 และ 2 แต่ละรายการแสดงเลย์เอาต์เหมือนกัน แต่เวอร์ชันในรูปที่ 1 คือ โดยใช้ขอบเขตคลิป (ลักษณะการทำงานเริ่มต้น) ในขณะที่รูปที่ 2 ใช้ขอบเขตแบบออปติคัล เนื่องจาก รูปภาพ 9 เส้นที่ใช้สำหรับปุ่ม และกรอบรูปมีระยะห่างจากขอบรอบขอบ ดูเหมือนจะไม่ปรับเข้าหากันหรือข้อความเมื่อใช้ขอบเขตของคลิป
หมายเหตุ: ภาพหน้าจอในรูปที่ 1 และ 2 เปิดใช้การตั้งค่าสำหรับนักพัฒนาซอฟต์แวร์ "แสดงขอบเขตเลย์เอาต์" สำหรับมุมมองแต่ละมุมมอง เส้นสีแดงจะแสดงขอบเขตเชิงแสง เส้นสีน้ำเงินจะแสดงขอบเขตคลิป และสีชมพูจะแสดงระยะขอบ

รูปที่ 1 เลย์เอาต์ที่ใช้ขอบเขตคลิป (ค่าเริ่มต้น)

รูปที่ 2 เลย์เอาต์โดยใช้ขอบเขตแบบออปติคัล
หากต้องการจัดแนวมุมมองตามขอบเขตเชิงแสง ให้ตั้งค่าแอตทริบิวต์ android:layoutMode
เป็น "opticalBounds"
ในเลย์เอาต์หลักรายการใดรายการหนึ่ง เช่น
<LinearLayout android:layoutMode="opticalBounds" ... >

รูปที่ 3 มุมมองแบบซูมของภาพ 9 ช่องของปุ่ม Holo พร้อมขอบเขตการมองเห็น
เพื่อให้สามารถใช้งานได้ ภาพ 9 จุดที่ใช้กับพื้นหลังของมุมมองของคุณต้องระบุ ขอบเขตแบบออปติคัลที่ใช้เส้นสีแดงที่ด้านล่างและด้านขวาของไฟล์ 9 แพตช์ (ตาม แสดงในรูปที่ 3) เส้นสีแดงแสดงขอบเขตที่ควรหักออกจากขอบเขตคลิปเพื่อให้เหลือขอบเขตเชิงแสงของรูปภาพ
เมื่อคุณเปิดใช้ขอบเขตออปติคัลสำหรับ ViewGroup
ในเลย์เอาต์
มุมมองสืบทอดจะสืบทอดโหมดการออกแบบขอบเขตออปติคัล เว้นแต่ว่าคุณจะลบล้างโหมดนี้สำหรับกลุ่มตาม
การตั้งค่า android:layoutMode
เป็น "clipBounds"
องค์ประกอบเลย์เอาต์ทั้งหมดจะยึดตามขอบเขตการมองเห็นของมุมมองย่อยด้วย โดยปรับขอบเขตของตัวเองตามขอบเขตการมองเห็นของมุมมองภายใน อย่างไรก็ตาม ขณะนี้องค์ประกอบเลย์เอาต์ (คลาสย่อยของ ViewGroup
) ยังไม่รองรับขอบเขตเชิงแสงสำหรับรูปภาพ 9 ส่วนที่ใช้กับพื้นหลังของตนเอง
หากคุณสร้างมุมมองที่กำหนดเองโดยการแยกคลาสย่อยของ View
, ViewGroup
หรือคลาสย่อยใดๆ ของคลาสดังกล่าว มุมมองของคุณจะรับค่าลักษณะการเชื่อมโยงแบบออปติคอลเหล่านี้
หมายเหตุ: วิดเจ็ตทั้งหมดที่ธีม Holo รองรับได้รับการอัปเดตให้มีขอบเขตเชิงแสงแล้ว ซึ่งรวมถึง Button
, Spinner
, EditText
และอื่นๆ คุณจึงได้รับประโยชน์ทันทีโดยการตั้งค่า
แอตทริบิวต์ android:layoutMode
เป็น "opticalBounds"
หากแอปใช้ธีม Holo
(Theme.Holo
, Theme.Holo.Light
ฯลฯ)
หากต้องการระบุขอบเขตแบบออปติคัลสำหรับรูปภาพ 9 เส้นของคุณเองด้วยเครื่องมือวาด 9 เส้น ให้กด "ควบคุม" ค้างไว้ คลิกพิกเซลเส้นขอบ
ภาพเคลื่อนไหวสำหรับค่าสี่เหลี่ยมผืนผ้า
ตอนนี้คุณสามารถสร้างภาพเคลื่อนไหวระหว่างค่า Rect
2 ค่าด้วย RectEvaluator
ใหม่ คลาสใหม่นี้เป็นการใช้งาน TypeEvaluator
ที่คุณส่งไปยัง ValueAnimator.setEvaluator()
ได้
การแนบหน้าต่างและโฟกัส Listener
ก่อนหน้านี้ หากต้องการฟังเมื่อมุมมองแนบ/เลิกแนบกับหน้าต่างหรือเมื่อโฟกัสของมุมมองเปลี่ยนไป คุณจะต้องลบล้างคลาส View
เพื่อติดตั้งใช้งาน onAttachedToWindow()
และ onDetachedFromWindow()
หรือ onWindowFocusChanged()
ตามลำดับ
ตอนนี้ หากต้องการรับเหตุการณ์การแนบและถอดออก คุณสามารถใช้ ViewTreeObserver.OnWindowAttachListener
และตั้งค่าในมุมมองด้วย
addOnWindowAttachListener()
แทน
หากต้องการรับเหตุการณ์ที่มีโฟกัส ให้ติดตั้งใช้งาน ViewTreeObserver.OnWindowFocusChangeListener
และตั้งค่าในมุมมองด้วย addOnWindowFocusChangeListener()
รองรับโอเวอร์สแกนทีวี
ตอนนี้คุณเปิดใช้การเลื่อนขอบภาพสำหรับเลย์เอาต์แอปได้แล้วเพื่อให้แอปแสดงเต็มหน้าจอบนทีวีทุกเครื่อง โหมดการเลื่อนออกจะกำหนดโดย Flag FLAG_LAYOUT_IN_OVERSCAN
ซึ่งคุณเปิดใช้ได้กับธีมของแพลตฟอร์ม เช่น Theme_DeviceDefault_NoActionBar_Overscan
หรือเปิดใช้สไตล์ windowOverscan
ในธีมที่กำหนดเอง
การวางแนวหน้าจอ
ตอนนี้แอตทริบิวต์ screenOrientation
ของแท็ก <activity>
รองรับค่าเพิ่มเติมเพื่อปฏิบัติตามค่ากําหนดของผู้ใช้สำหรับการหมุนอัตโนมัติแล้ว ดังนี้
"userLandscape"
- ทำงานเหมือนกับ
"sensorLandscape"
เว้นแต่ผู้ใช้ปิดใช้การหมุนอัตโนมัติ อุปกรณ์จะล็อกในแนวนอนตามปกติและไม่พลิก "userPortrait"
- มีลักษณะการทำงานเหมือนกับ
"sensorPortrait"
ยกเว้นในกรณีที่ผู้ใช้ปิดใช้การหมุนอัตโนมัติ ระบบจะล็อกไว้ในแนวตั้งปกติและจะไม่พลิก "fullUser"
- ทํางานเหมือนกับ
"fullSensor"
และอนุญาตให้หมุนได้ 4 ทิศทาง ยกเว้นในกรณีที่ผู้ใช้ปิดใช้การหมุนอัตโนมัติ ระบบจะล็อกการวางแนวที่ผู้ใช้ต้องการ
นอกจากนี้ คุณยังประกาศ "locked"
เพื่อล็อกการวางแนวของแอปได้ด้วย
การวางแนวปัจจุบันของหน้าจอ
ภาพเคลื่อนไหวการหมุน
ช่อง rotationAnimation
ใหม่ใน
WindowManager
ให้คุณเลือกภาพเคลื่อนไหว 1 แบบจาก 3 แบบ
ที่ต้องการใช้เมื่อระบบเปลี่ยนการวางแนวหน้าจอ ภาพเคลื่อนไหวทั้ง 3 แบบมีดังนี้
หมายเหตุ: ภาพเคลื่อนไหวเหล่านี้จะพร้อมใช้งานเมื่อคุณตั้งค่ากิจกรรมให้ใช้ "เต็มหน้าจอ" ซึ่งคุณสามารถเปิดใช้กับธีมอย่างเช่น Theme.Holo.NoActionBar.Fullscreen
ตัวอย่างเช่น วิธีเปิดใช้ภาพเคลื่อนไหว "การซ้อนทับ" มีดังนี้
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); ... }
ข้อมูลจากผู้ใช้
เซ็นเซอร์ประเภทใหม่
เซ็นเซอร์ TYPE_GAME_ROTATION_VECTOR
ใหม่ช่วยให้คุณตรวจจับการหมุนของอุปกรณ์ได้โดยไม่ต้องกังวลเกี่ยวกับสัญญาณรบกวนแม่เหล็ก TYPE_GAME_ROTATION_VECTOR
ไม่เหมือนกับเซ็นเซอร์ TYPE_ROTATION_VECTOR
ตรงที่ไม่อ้างอิงทางแม่เหล็กเหนือ
เซ็นเซอร์ TYPE_GYROSCOPE_UNCALIBRATED
และ TYPE_MAGNETIC_FIELD_UNCALIBRATED
ใหม่ให้ข้อมูลดิบของเซ็นเซอร์โดยไม่มี
การประเมินการให้อคติ กล่าวคือ เซ็นเซอร์ TYPE_GYROSCOPE
และ TYPE_MAGNETIC_FIELD
ที่มีอยู่จะให้ข้อมูลเซ็นเซอร์ที่พิจารณาความเบี่ยงเบนโดยประมาณจากการส่ายของไจโรและเหล็กแข็งในอุปกรณ์ตามลำดับ ขณะที่เซ็นเซอร์เหล่านี้เวอร์ชัน "ไม่ได้ปรับเทียบ" ใหม่จะให้ข้อมูลเซ็นเซอร์ดิบและค่าความเบี่ยงเบนโดยประมาณแยกกัน เซ็นเซอร์เหล่านี้ช่วยให้คุณทำการสอบเทียบข้อมูลเซ็นเซอร์ที่กำหนดเองได้โดยการปรับปรุงค่าเบี่ยงเบนโดยประมาณด้วยข้อมูลภายนอก
บริการฟังการแจ้งเตือน
Android 4.3 เพิ่มคลาสบริการใหม่ NotificationListenerService
ซึ่งช่วยให้แอปได้รับข้อมูลเกี่ยวกับการแจ้งเตือนใหม่เมื่อระบบโพสต์การแจ้งเตือน
หากปัจจุบันแอปของคุณใช้ API บริการการช่วยเหลือพิเศษเพื่อเข้าถึงการแจ้งเตือนของระบบ คุณควรอัปเดตแอปให้ใช้ API เหล่านี้แทน
Contacts Provider
การค้นหา "รายชื่อติดต่อ"
คำค้นหาใหม่ของผู้ให้บริการรายชื่อติดต่อชื่อ Contactables.CONTENT_URI
เป็นวิธีที่มีประสิทธิภาพในการรับ Cursor
1 รายการที่มีอีเมลและหมายเลขโทรศัพท์ทั้งหมดที่เป็นของรายชื่อติดต่อทั้งหมดที่ตรงกับคำค้นหาที่ระบุ
ค้นหาข้อมูล Delta ของรายชื่อติดต่อ
เราได้เพิ่ม API ใหม่ลงในผู้ให้บริการรายชื่อติดต่อ ซึ่งจะช่วยให้คุณค้นหาการเปลี่ยนแปลงล่าสุดของข้อมูลรายชื่อติดต่อได้อย่างมีประสิทธิภาพ ก่อนหน้านี้ แอปจะได้รับการแจ้งเตือนเมื่อมีการเปลี่ยนแปลงข้อมูลรายชื่อติดต่อ แต่คุณจะไม่ทราบว่ามีอะไรเปลี่ยนแปลงไปบ้าง และจะต้องดึงข้อมูลรายชื่อติดต่อทั้งหมดออกมาแล้วเรียกดูทีละรายการเพื่อค้นหาการเปลี่ยนแปลง
หากต้องการติดตามการเปลี่ยนแปลงในการแทรกและอัปเดต ตอนนี้คุณสามารถใส่พารามิเตอร์ CONTACT_LAST_UPDATED_TIMESTAMP
ลงในส่วนที่เลือกเพื่อค้นหาเฉพาะรายชื่อติดต่อที่มีการเปลี่ยนแปลงตั้งแต่ครั้งล่าสุดที่คุณค้นหาผู้ให้บริการได้แล้ว
หากต้องการติดตามว่ารายชื่อติดต่อใดถูกลบแล้ว ตารางใหม่ ContactsContract.DeletedContacts
จะแสดงบันทึกรายชื่อติดต่อที่ถูกลบไปแล้ว (แต่รายชื่อติดต่อที่ลบแต่ละรายการจะเก็บไว้ในตารางนี้ในระยะเวลาจำกัด) เช่นเดียวกับ CONTACT_LAST_UPDATED_TIMESTAMP
คุณสามารถใช้พารามิเตอร์การเลือกใหม่ CONTACT_DELETED_TIMESTAMP
เพื่อตรวจสอบว่ามีการลบรายชื่อติดต่อใดบ้างนับตั้งแต่ที่คุณค้นหาผู้ให้บริการครั้งล่าสุด นอกจากนี้ ตารางยังมี DAYS_KEPT_MILLISECONDS
คงที่ซึ่งมีจำนวนวัน (เป็นมิลลิวินาที) ที่จะเก็บรักษาบันทึกไว้
นอกจากนี้ ตอนนี้ Contacts Provider จะออกอากาศการดำเนินการ CONTACTS_DATABASE_CREATED
เมื่อผู้ใช้ล้างพื้นที่เก็บข้อมูลรายชื่อติดต่อผ่านเมนูการตั้งค่าระบบ ซึ่งจะสร้างฐานข้อมูล Contacts Provider ขึ้นมาใหม่ได้อย่างมีประสิทธิภาพ การดำเนินการนี้มีไว้เพื่อส่งสัญญาณให้แอปต้องทิ้งข้อมูลติดต่อทั้งหมดที่เก็บไว้และโหลดข้อมูลนั้นอีกครั้งด้วยข้อความค้นหาใหม่
สำหรับโค้ดตัวอย่างที่ใช้ API เหล่านี้เพื่อตรวจสอบการเปลี่ยนแปลงในรายชื่อติดต่อ โปรดดูใน ApiDemos ตัวอย่างที่มีอยู่ในการดาวน์โหลดตัวอย่าง SDK
การแปล
ปรับปรุงการรองรับข้อความแบบ 2 ทิศทาง
Android เวอร์ชันเก่ารองรับภาษาและเลย์เอาต์แบบขวาไปซ้าย (RTL) แต่บางครั้งอาจจัดการข้อความแบบผสมทิศทางไม่ถูกต้อง ดังนั้น Android 4.3 จึงเพิ่ม BidiFormatter
API ที่ช่วยคุณจัดรูปแบบข้อความที่มีเนื้อหาในทิศทางตรงข้ามอย่างเหมาะสมโดยไม่ทำให้ข้อความส่วนใดส่วนหนึ่งอ่านไม่ออก
เช่น เมื่อต้องการสร้างประโยคที่มีตัวแปรสตริง เช่น "หรือคุณหมายถึง
15 Bay Street, Laurel, CA?" โดยปกติแล้วคุณจะส่งแหล่งข้อมูลสตริงที่แปลแล้วและตัวแปรไปยัง
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);
อย่างไรก็ตาม ถ้าภาษาเป็นภาษาฮีบรู สตริงรูปแบบจะมีลักษณะดังนี้
האם התכוונת ל 15 Bay Street, Laurel, CA?
ไม่ถูกต้องเนื่องจาก "15" ควรอยู่บนถนน "Bay Street" วิธีแก้ไขคือใช้ BidiFormatter
และเมธอด unicodeWrap()
ตัวอย่างเช่น โค้ดด้านบนจะเป็นดังนี้
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));
โดยค่าเริ่มต้น unicodeWrap()
จะใช้เมธอด
การคาดการณ์ทิศทางแรกอย่างแม่นยำ ซึ่งอาจทําให้เกิดข้อผิดพลาดหาก
สัญญาณสำหรับทิศทางของข้อความไม่ได้แสดงถึงทิศทางที่เหมาะสมสำหรับเนื้อหาโดยรวม
หากจำเป็น คุณสามารถระบุวิธีการเรียนรู้แบบอื่นโดยการส่งผ่านค่าคงที่ TextDirectionHeuristic
ค่าใดค่าหนึ่งจาก TextDirectionHeuristics
ไปยัง unicodeWrap()
หมายเหตุ: API ใหม่เหล่านี้ยังพร้อมใช้งานสำหรับ Android เวอร์ชันก่อนหน้าผ่านคลังการสนับสนุนของ Android ด้วยคลาส BidiFormatter
และ API ที่เกี่ยวข้อง
บริการการช่วยเหลือพิเศษ
จัดการเหตุการณ์สําคัญ
ตอนนี้ AccessibilityService
สามารถรับการเรียกกลับสําหรับเหตุการณ์การป้อนข้อมูลหลักด้วยเมธอดการเรียกกลับ onKeyEvent()
ซึ่งจะช่วยให้บริการการช่วยเหลือพิเศษจัดการอินพุตสำหรับอุปกรณ์อินพุตแบบปุ่มกด เช่น แป้นพิมพ์ และแปลเหตุการณ์เหล่านั้นเป็นการดําเนินการพิเศษที่ก่อนหน้านี้อาจทำได้ด้วยอินพุตแบบสัมผัสหรือปุ่มบังคับทิศทางของอุปกรณ์เท่านั้น
เลือกข้อความและคัดลอก/วาง
ตอนนี้ AccessibilityNodeInfo
มี API ที่ช่วยให้ AccessibilityService
เลือก ตัด คัดลอก และวางข้อความในโหนดได้
ในการระบุการเลือกข้อความที่จะตัดหรือคัดลอก บริการการเข้าถึงสามารถใช้
การดำเนินการ, ACTION_SET_SELECTION
, ผ่าน
แล้วเลือกตำแหน่งเริ่มต้นและสิ้นสุดด้วย ACTION_ARGUMENT_SELECTION_START_INT
และ ACTION_ARGUMENT_SELECTION_END_INT
หรือจะเลือกข้อความด้วยการปรับตำแหน่งเคอร์เซอร์โดยใช้การดำเนินการที่มีอยู่ ACTION_NEXT_AT_MOVEMENT_GRANULARITY
(ก่อนหน้านี้มีไว้สำหรับการย้ายตำแหน่งเคอร์เซอร์เท่านั้น) และเพิ่มอาร์กิวเมนต์ ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
ก็ได้
จากนั้นคุณสามารถตัดหรือคัดลอกด้วย ACTION_CUT
ACTION_COPY
แล้ววางในภายหลังด้วย
ACTION_PASTE
หมายเหตุ: API ใหม่เหล่านี้จะพร้อมใช้งานสำหรับเวอร์ชันก่อนหน้าด้วยเช่นกัน
ของ Android ผ่านทางการสนับสนุนของ Android
คลัง โดยมีAccessibilityNodeInfoCompat
ประกาศฟีเจอร์การช่วยเหลือพิเศษ
เริ่มตั้งแต่ Android 4.3 บริการการช่วยเหลือพิเศษจะต้องประกาศความสามารถในการเข้าถึง
ในไฟล์ข้อมูลเมตาเพื่อใช้ฟีเจอร์การช่วยเหลือพิเศษบางอย่าง หากไม่ได้ขอความสามารถดังกล่าวในไฟล์ข้อมูลเมตา ฟีเจอร์จะไม่ทำงาน หากต้องการประกาศความสามารถด้านการช่วยเหลือพิเศษของบริการ คุณต้องมีแอตทริบิวต์ XML ที่สอดคล้องกับค่าคงที่ "capability" ต่างๆ ในคลาส AccessibilityServiceInfo
ตัวอย่างเช่น หากบริการไม่ได้ขอความสามารถ flagRequestFilterKeyEvents
บริการดังกล่าวจะไม่ได้รับการแจ้งเตือนเหตุการณ์สำคัญ
การทดสอบและการแก้ไขข้อบกพร่อง
การทดสอบ UI อัตโนมัติ
คลาส UiAutomation
ใหม่มี API ที่ให้คุณจำลองผู้ใช้ได้
การดำเนินการสำหรับการทดสอบอัตโนมัติ การใช้ AccessibilityService
API ของแพลตฟอร์มจะทำให้UiAutomation
API ช่วยให้คุณตรวจสอบเนื้อหาบนหน้าจอและแทรกแป้นพิมพ์และเหตุการณ์การแตะได้ตามต้องการ
หากต้องการรับอินสแตนซ์ของ UiAutomation
ให้เรียกใช้ Instrumentation.getUiAutomation()
อยู่ในคำสั่งซื้อ
คุณต้องใส่ตัวเลือก -w
พร้อมกับคำสั่ง instrument
เพื่อให้ดำเนินการนี้ได้
เมื่อเรียกใช้ InstrumentationTestCase
จาก adb shell
เมื่อใช้อินสแตนซ์ UiAutomation
คุณจะเรียกใช้เหตุการณ์ที่กําหนดเองเพื่อทดสอบแอปได้โดยการเรียก executeAndWaitForEvent()
โดยส่ง Runnable
ให้ดำเนินการ ระยะเวลาหมดเวลาสําหรับการดำเนินการ และการใช้งานอินเทอร์เฟซ UiAutomation.AccessibilityEventFilter
คุณจะได้รับการเรียกใช้ภายในการติดตั้งใช้งาน UiAutomation.AccessibilityEventFilter
ซึ่งช่วยให้คุณกรองเหตุการณ์ที่สนใจและระบุความสําเร็จหรือความล้มเหลวของกรณีทดสอบหนึ่งๆ ได้
หากต้องการสังเกตเหตุการณ์ทั้งหมดระหว่างการทดสอบ ให้สร้างการใช้งาน UiAutomation.OnAccessibilityEventListener
และส่งไปยัง setOnAccessibilityEventListener()
จากนั้นอินเทอร์เฟซโปรแกรมฟังจะได้รับการเรียกใช้ onAccessibilityEvent()
ทุกครั้งที่เกิดเหตุการณ์ โดยจะได้รับออบเจ็กต์ AccessibilityEvent
ที่อธิบายเหตุการณ์
UiAutomation
API ยังมีการดำเนินการอื่นๆ อีกมากมายที่แสดงในระดับต่ำมากเพื่อส่งเสริมการพัฒนาเครื่องมือทดสอบ UI เช่น uiautomator ตัวอย่างเช่น
UiAutomation
ยังสามารถ:
- แทรกเหตุการณ์อินพุต
- เปลี่ยนการวางแนวของหน้าจอ
- ถ่ายภาพหน้าจอ
และที่สำคัญที่สุดสำหรับเครื่องมือทดสอบ UI คือ UiAutomation
API จะทำงานข้ามขอบเขตแอปพลิเคชัน ต่างจากใน Instrumentation
เหตุการณ์ Systrace สำหรับแอป
Android 4.3 เพิ่มคลาส Trace
ที่มีเมธอดแบบคงที่ 2 รายการ ได้แก่ beginSection()
และ endSection()
ซึ่งช่วยให้คุณกำหนดบล็อกโค้ดที่จะรวมไว้ในรายงาน systrace ได้ โดยการสร้าง
ส่วนของโค้ดที่ตรวจสอบย้อนกลับได้ในแอปของคุณ บันทึกของ systrace จะแสดงรายละเอียดเพิ่มเติม
การวิเคราะห์ตำแหน่งที่เกิดการชะลอตัวภายในแอป
อ่านข้อมูลเกี่ยวกับการใช้เครื่องมือ Systrace ได้ที่การวิเคราะห์การแสดงผลและประสิทธิภาพด้วย Systrace
ความปลอดภัย
แหล่งเก็บคีย์ Android สำหรับคีย์ส่วนตัวของแอป
ตอนนี้ Android มีผู้ให้บริการความปลอดภัย Java ที่กําหนดเองในKeyStore
สถานะที่เรียกว่า Android Key Store ซึ่งช่วยให้คุณสร้างและบันทึกคีย์ส่วนตัวที่แอปของคุณเท่านั้นที่จะเห็นและใช้ได้ หากต้องการโหลด Android Key Store ให้ส่ง"AndroidKeyStore"
ไปยัง KeyStore.getInstance()
ในการจัดการข้อมูลเข้าสู่ระบบส่วนตัวของแอปใน Android Key Store ให้สร้างคีย์ใหม่ด้วย
KeyPairGenerator
ด้วย KeyPairGeneratorSpec
ก่อนอื่น ให้รับอินสแตนซ์ของ KeyPairGenerator
โดยการเรียกใช้ getInstance()
จากนั้นโทร
initialize()
ส่งอินสแตนซ์
KeyPairGeneratorSpec
ซึ่งคุณใช้ได้ใน
KeyPairGeneratorSpec.Builder
สุดท้าย รับ KeyPair
ด้วยการโทรหา generateKeyPair()
ที่เก็บข้อมูลเข้าสู่ระบบฮาร์ดแวร์
ขณะนี้ Android รองรับพื้นที่เก็บข้อมูลแบบฮาร์ดแวร์สำหรับ KeyChain
แล้ว
ข้อมูลเข้าสู่ระบบของคุณ เพื่อเพิ่มความปลอดภัยโดยทำให้คีย์ไม่สามารถใช้ดึงข้อมูลได้ กล่าวคือ เมื่อคีย์อยู่ในที่เก็บคีย์ที่รองรับฮาร์ดแวร์ (องค์ประกอบที่ปลอดภัย, TPM หรือ TrustZone) จะใช้คีย์ดังกล่าวสําหรับการดำเนินการเข้ารหัสได้ แต่จะส่งออกเนื้อหาคีย์ส่วนตัวไม่ได้ แม้แต่เคอร์เนลของระบบปฏิบัติการก็ไม่สามารถเข้าถึงข้อมูลคีย์นี้ได้ แม้ว่าอุปกรณ์ที่ใช้ Android บางรุ่นจะไม่รองรับพื้นที่เก็บข้อมูลบน
คุณสามารถตรวจสอบขณะรันไทม์ว่าพื้นที่เก็บข้อมูลที่ใช้ฮาร์ดแวร์พร้อมใช้งานหรือไม่โดยการเรียกใช้
KeyChain.IsBoundKeyAlgorithm()
การประกาศไฟล์ Manifest
ฟีเจอร์ที่จำเป็นซึ่งประกาศได้
ตอนนี้ <uses-feature>
รองรับค่าต่อไปนี้แล้ว
องค์ประกอบเพื่อให้มั่นใจได้ว่าแอปของคุณจะติดตั้งเฉพาะในอุปกรณ์ที่มีฟีเจอร์
ที่แอปของคุณต้องใช้
FEATURE_APP_WIDGETS
- ประกาศว่าแอปของคุณมีวิดเจ็ตแอปและควรติดตั้งในอุปกรณ์ที่มีหน้าจอหลักหรือตำแหน่งที่คล้ายกันซึ่งผู้ใช้สามารถฝังวิดเจ็ตแอปได้เท่านั้น
ตัวอย่าง
<uses-feature android:name="android.software.app_widgets" android:required="true" />
FEATURE_HOME_SCREEN
- ประกาศว่าแอปของคุณทำงานเหมือนเป็นอุปกรณ์ทดแทนหน้าจอหลักและควรติดตั้งเฉพาะใน
อุปกรณ์ที่สนับสนุนแอปหน้าจอหลักของบุคคลที่สาม
ตัวอย่าง
<uses-feature android:name="android.software.home_screen" android:required="true" />
FEATURE_INPUT_METHODS
- ประกาศว่าแอปของคุณมีวิธีการป้อนข้อมูลที่กำหนดเอง (แป้นพิมพ์ที่สร้างด้วย
InputMethodService
) และควรติดตั้งในอุปกรณ์ที่รองรับวิธีการป้อนข้อมูลของบุคคลที่สามเท่านั้น ตัวอย่าง<uses-feature android:name="android.software.input_methods" android:required="true" />
FEATURE_BLUETOOTH_LE
- ประกาศว่าแอปของคุณใช้ Bluetooth Low Energy API และควรติดตั้งในอุปกรณ์ที่สื่อสารกับอุปกรณ์อื่นๆ ผ่านบลูทูธพลังงานต่ำได้เท่านั้น
ตัวอย่าง
<uses-feature android:name="android.software.bluetooth_le" android:required="true" />
สิทธิ์ของผู้ใช้
ตอนนี้ระบบรองรับค่าต่อไปนี้ใน <uses-permission>
เพื่อประกาศสิทธิ์ที่จําเป็นต่อแอปในการเข้าถึง API บางรายการ
BIND_NOTIFICATION_LISTENER_SERVICE
- จำเป็นสำหรับการใช้
NotificationListenerService
API ใหม่ SEND_RESPOND_VIA_MESSAGE
- ต้องระบุเพื่อรับ
ACTION_RESPOND_VIA_MESSAGE
Intent
สำหรับมุมมองโดยละเอียดของการเปลี่ยนแปลง API ทั้งหมดใน Android 4.3 โปรดดูที่ รายงานความแตกต่างของ API