Android 17 memperkenalkan fitur dan API baru yang hebat untuk para developer. Bagian berikut merangkum fitur ini untuk membantu Anda mulai menggunakan API terkait.
Untuk melihat daftar mendetail tentang API yang baru, diubah, dan dihapus, baca laporan perbedaan API. Untuk mengetahui detail tentang API baru, buka referensi API Android — API baru ditandai agar lebih mudah dilihat.
Anda juga harus meninjau area tempat perubahan platform dapat memengaruhi aplikasi Anda. Untuk informasi selengkapnya, lihat halaman berikut:
- Perubahan perilaku yang memengaruhi aplikasi saat menargetkan Android 17
- Perubahan perilaku yang memengaruhi semua aplikasi terlepas dari
targetSdkVersion.
Fungsi inti
Android 17 menambahkan fitur baru berikut terkait fungsi inti Android.
Pemicu ProfilingManager baru
Android 17 menambahkan beberapa pemicu sistem baru ke ProfilingManager untuk
membantu Anda mengumpulkan data mendalam guna men-debug masalah performa.
Pemicu baru tersebut adalah:
TRIGGER_TYPE_COLD_START: Pemicu terjadi selama mulai dingin aplikasi. API ini memberikan contoh call stack dan rekaman aktivitas sistem dalam respons.TRIGGER_TYPE_OOM: Pemicuan terjadi saat aplikasi memunculkanOutOfMemoryErrordan memberikan Java Heap Dump sebagai respons.TRIGGER_TYPE_KILL_EXCESSIVE_CPU_USAGE: Pemicu terjadi saat aplikasi dihentikan karena penggunaan CPU yang tidak normal dan berlebihan, serta memberikan sampel call stack sebagai respons.
Untuk memahami cara menyiapkan pemicu sistem, lihat dokumentasi tentang pembuatan profil berbasis pemicu dan cara mengambil dan menganalisis data pembuatan profil.
JobDebugInfo API
Android 17 introduces new JobDebugInfo APIs to help developers debug
their JobScheduler jobs--why they aren't running, how long they ran for, and
other aggregated information.
The first method of the expanded JobDebugInfo APIs is
getPendingJobReasonStats(), which returns a map of reasons why the job was in
a pending execution state and their respective cumulative pending
durations. This method joins the getPendingJobReasonsHistory() and
getPendingJobReasons() methods to give you insight into why a scheduled
job is not running as expected, but simplifies information retrieval by making
both duration and job reason available in a single method.
For example, for a specified jobId, the method might return
PENDING_JOB_REASON_CONSTRAINT_CHARGING and a duration of 60000 ms, indicating
the job was pending for 60000ms due to the charging constraint not being
satisfied.
Privasi
Android 17 menyertakan fitur baru berikut untuk meningkatkan privasi pengguna.
Pemilih kontak Android
The Android Contact Picker is a standardized, browsable interface for users to
share contacts with your app. Available on devices running
Android 17 or higher, the picker offers a privacy-preserving
alternative to the broad READ_CONTACTS permission. Instead of requesting
access to the user's entire address book, your app specifies the data fields it
needs, such as phone numbers or email addresses, and the user selects specific
contacts to share. This grants your app read access to only the selected data,
ensuring granular control while providing a consistent user experience with
built-in search, profile switching, and multi-selection capabilities without
having to build or maintain the UI.
For more information, see the contact picker documentation.
Keamanan
Android 17 menambahkan fitur baru berikut untuk meningkatkan keamanan perangkat dan aplikasi.
Mode Perlindungan Lanjutan Android (AAPM)
Android Advanced Protection Mode offers Android users a powerful new set of security features, marking a significant step in safeguarding users—particularly those at higher risk—from sophisticated attacks. Designed as an opt-in feature, AAPM is activated with a single configuration setting that users can turn on at any time to apply an opinionated set of security protections.
These core configurations include blocking app installation from unknown sources
(sideloading), restricting USB data signaling, and mandating Google Play Protect
scanning, which significantly reduces the device's attack surface area.
Developers can integrate with this feature using the
AdvancedProtectionManager API to detect the mode's status, enabling
applications to automatically adopt a hardened security posture or restrict
high-risk functionality when a user has opted in.
Konektivitas
Android 17 menambahkan fitur berikut untuk meningkatkan konektivitas perangkat dan aplikasi.
Jaringan satelit yang dibatasi
Implements optimizations to enable apps to function effectively over low-bandwidth satellite networks.
Pengalaman pengguna dan UI sistem
Android 17 menyertakan perubahan berikut untuk meningkatkan pengalaman pengguna.
Handoff
Penyerahan adalah fitur dan API baru yang akan hadir di Android 17 yang dapat diintegrasikan oleh developer aplikasi untuk memberikan kontinuitas lintas perangkat bagi pengguna mereka. Fitur ini memungkinkan pengguna memulai aktivitas aplikasi di satu perangkat Android dan mentransisikannya ke perangkat Android lain. Pengalihan berjalan di latar belakang perangkat pengguna dan menampilkan aktivitas yang tersedia dari perangkat terdekat pengguna lainnya melalui berbagai titik entri, seperti peluncur dan taskbar, di perangkat penerima.
Aplikasi dapat menetapkan Handoff untuk meluncurkan aplikasi Android native yang sama, jika aplikasi tersebut diinstal dan tersedia di perangkat penerima. Dalam alur aplikasi-ke-aplikasi ini, pengguna ditautkan secara mendalam ke aktivitas yang ditentukan. Atau, Penyerahan dari aplikasi ke web dapat ditawarkan sebagai opsi penggantian atau diterapkan langsung dengan Penyerahan URL.
Dukungan Handoff diimplementasikan per aktivitas. Untuk mengaktifkan Handoff, panggil
metode setHandoffEnabled() untuk aktivitas. Data tambahan mungkin perlu diteruskan bersama dengan pengalihan sehingga aktivitas yang dibuat ulang di perangkat penerima dapat memulihkan status yang sesuai. Terapkan callback
onHandoffActivityRequested() untuk menampilkan objek HandoffActivityData
yang berisi detail yang menentukan cara Handoff harus menangani dan membuat ulang
aktivitas di perangkat penerima.
Update Langsung - Semantic color API
Dengan Android 17, Update Langsung meluncurkan Semantic Coloring API untuk mendukung warna dengan makna universal.
Class berikut mendukung pewarnaan semantik:
NotificationNotification.MetricNotification.ProgressStyle.PointNotification.ProgressStyle.Segment
Mewarnai
- Hijau: Terkait dengan keselamatan. Warna ini harus digunakan untuk kasus yang memberi tahu orang lain bahwa Anda berada dalam situasi aman.
- Oranye: Untuk menunjukkan kehati-hatian dan menandai bahaya fisik. Warna ini harus digunakan dalam situasi saat pengguna perlu memperhatikan setelan perlindungan yang lebih baik.
- Merah: Umumnya menunjukkan bahaya, berhenti. Harus ditampilkan untuk kasus yang memerlukan perhatian orang dengan segera.
- Biru: Warna netral untuk konten yang bersifat informatif dan harus terlihat berbeda dari konten lainnya.
Contoh berikut menunjukkan cara menerapkan gaya semantik ke teks dalam notifikasi:
val ssb = SpannableStringBuilder()
.append("Colors: ")
.append("NONE", Notification.createSemanticStyleAnnotation(SEMANTIC_STYLE_UNSPECIFIED), 0)
.append(", ")
.append("INFO", Notification.createSemanticStyleAnnotation(SEMANTIC_STYLE_INFO), 0)
.append(", ")
.append("SAFE", Notification.createSemanticStyleAnnotation(SEMANTIC_STYLE_SAFE), 0)
.append(", ")
.append("CAUTION", Notification.createSemanticStyleAnnotation(SEMANTIC_STYLE_CAUTION), 0)
.append(", ")
.append("DANGER", Notification.createSemanticStyleAnnotation(SEMANTIC_STYLE_DANGER), 0)
Notification.Builder(context, channelId)
.setSmallIcon(R.drawable.ic_icon)
.setContentTitle("Hello World!")
.setContentText(ssb)
.setOngoing(true)
.setRequestPromotedOngoing(true)
UWB Downlink-TDoA API untuk Android 17
Downlink Time Difference of Arrival (DL-TDoA) ranging lets a device determine its position relative to multiple anchors by measuring the relative arrival times of signals.
The following snippet demonstrates how to initialize the Ranging Manager, verify device capabilities, and start a DL-TDoA session:
Kotlin
class RangingApp {
fun initDlTdoa(context: Context) {
// Initialize the Ranging Manager
val rangingManager = context.getSystemService(RangingManager::class.java)
// Register for device capabilities
val capabilitiesCallback = object : RangingManager.CapabilitiesCallback {
override fun onRangingCapabilities(capabilities: RangingCapabilities) {
// Make sure Dl-TDoA is supported before starting the session
if (capabilities.uwbCapabilities != null && capabilities.uwbCapabilities!!.isDlTdoaSupported) {
startDlTDoASession(context)
}
}
}
rangingManager.registerCapabilitiesCallback(Executors.newSingleThreadExecutor(), capabilitiesCallback)
}
fun startDlTDoASession(context: Context) {
// Initialize the Ranging Manager
val rangingManager = context.getSystemService(RangingManager::class.java)
// Create session and configure parameters
val executor = Executors.newSingleThreadExecutor()
val rangingSession = rangingManager.createRangingSession(executor, RangingSessionCallback())
val rangingRoundIndexes = intArrayOf(0)
val config: ByteArray = byteArrayOf() // OOB config data
val params = DlTdoaRangingParams.createFromFiraConfigPacket(config, rangingRoundIndexes)
val rangingDevice = RangingDevice.Builder().build()
val rawTagDevice = RawRangingDevice.Builder()
.setRangingDevice(rangingDevice)
.setDlTdoaRangingParams(params)
.build()
val dtTagConfig = RawDtTagRangingConfig.Builder(rawTagDevice).build()
val preference = RangingPreference.Builder(DEVICE_ROLE_DT_TAG, dtTagConfig)
.setSessionConfig(SessionConfig.Builder().build())
.build()
// Start the ranging session
rangingSession.start(preference)
}
}
private class RangingSessionCallback : RangingSession.Callback {
override fun onDlTdoaResults(peer: RangingDevice, measurement: DlTdoaMeasurement) {
// Process measurement results here
}
}
Java
public class RangingApp {
public void initDlTdoa(Context context) {
// Initialize the Ranging Manager
RangingManager rangingManager = context.getSystemService(RangingManager.class);
// Register for device capabilities
RangingManager.CapabilitiesCallback capabilitiesCallback = new RangingManager.CapabilitiesCallback() {
@Override
public void onRangingCapabilities(RangingCapabilities capabilities) {
// Make sure Dl-TDoA is supported before starting the session
if (capabilities.getUwbCapabilities() != null && capabilities.getUwbCapabilities().isDlTdoaSupported) {
startDlTDoASession(context);
}
}
};
rangingManager.registerCapabilitiesCallback(Executors.newSingleThreadExecutor(), capabilitiesCallback);
}
public void startDlTDoASession(Context context) {
RangingManager rangingManager = context.getSystemService(RangingManager.class);
// Create session and configure parameters
Executor executor = Executors.newSingleThreadExecutor();
RangingSession rangingSession = rangingManager.createRangingSession(executor, new RangingSessionCallback());
int[] rangingRoundIndexes = new int[] {0};
byte[] config = new byte[0]; // OOB config data
DlTdoaRangingParams params = DlTdoaRangingParams.createFromFiraConfigPacket(config, rangingRoundIndexes);
RangingDevice rangingDevice = new RangingDevice.Builder().build();
RawRangingDevice rawTagDevice = new RawRangingDevice.Builder()
.setRangingDevice(rangingDevice)
.setDlTdoaRangingParams(params)
.build();
RawDtTagRangingConfig dtTagConfig = new RawDtTagRangingConfig.Builder(rawTagDevice).build();
RangingPreference preference = new RangingPreference.Builder(DEVICE_ROLE_DT_TAG, dtTagConfig)
.setSessionConfig(new SessionConfig.Builder().build())
.build();
// Start the ranging session
rangingSession.start(preference);
}
private static class RangingSessionCallback implements RangingSession.Callback {
@Override
public void onDlTdoaResults(RangingDevice peer, DlTdoaMeasurement measurement) {
// Process measurement results here
}
}
}
Out-of-Band (OOB) Configurations
The following snippet provides an example of DL-TDoA OOB configuration data for Wi-Fi and BLE:
Java
// Wifi Configuration
byte[] wifiConfig = {
(byte) 0xDD, (byte) 0x2D, (byte) 0x5A, (byte) 0x18, (byte) 0xFF, // Header
(byte) 0x5F, (byte) 0x19, // FiRa Sub-Element
(byte) 0x02, (byte) 0x00, // Profile ID
(byte) 0x06, (byte) 0x02, (byte) 0x20, (byte) 0x08, // MAC Address
(byte) 0x14, (byte) 0x01, (byte) 0x0C, // Preamble Index
(byte) 0x27, (byte) 0x02, (byte) 0x08, (byte) 0x07, // Vendor ID
(byte) 0x28, (byte) 0x06, (byte) 0xCA, (byte) 0xC8, (byte) 0xA6, (byte) 0xF7, (byte) 0x6F, (byte) 0x08, // Static STS IV
(byte) 0x08, (byte) 0x02, (byte) 0x60, (byte) 0x09, // Slot Duration
(byte) 0x1B, (byte) 0x01, (byte) 0x0A, // Slots per RR
(byte) 0x09, (byte) 0x04, (byte) 0xE8, (byte) 0x03, (byte) 0x00, (byte) 0x00, // Duration
(byte) 0x9F, (byte) 0x04, (byte) 0x67, (byte) 0x45, (byte) 0x23, (byte) 0x01 // Session ID
};
// BLE Configuration
byte[] bleConfig = {
(byte) 0x2D, (byte) 0x16, (byte) 0xF4, (byte) 0xFF, // Header
(byte) 0x5F, (byte) 0x19, // FiRa Sub-Element
(byte) 0x02, (byte) 0x00, // Profile ID
(byte) 0x06, (byte) 0x02, (byte) 0x20, (byte) 0x08, // MAC Address
(byte) 0x14, (byte) 0x01, (byte) 0x0C, // Preamble Index
(byte) 0x27, (byte) 0x02, (byte) 0x08, (byte) 0x07, // Vendor ID
(byte) 0x28, (byte) 0x06, (byte) 0xCA, (byte) 0xC8, (byte) 0xA6, (byte) 0xF7, (byte) 0x6F, (byte) 0x08, // Static STS IV
(byte) 0x08, (byte) 0x02, (byte) 0x60, (byte) 0x09, // Slot Duration
(byte) 0x1B, (byte) 0x01, (byte) 0x0A, // Slots per RR
(byte) 0x09, (byte) 0x04, (byte) 0xE8, (byte) 0x03, (byte) 0x00, (byte) 0x00, // Duration
(byte) 0x9F, (byte) 0x04, (byte) 0x67, (byte) 0x45, (byte) 0x23, (byte) 0x01 // Session ID
};
If you can't use an OOB configuration because it is missing, or if you need to
change default values that aren't in the OOB config, you can build parameters
with DlTdoaRangingParams.Builder as shown in the following snippet. You can use
these parameters in place of DlTdoaRangingParams.createFromFiraConfigPacket():
Kotlin
val dlTdoaParams = DlTdoaRangingParams.Builder(1)
.setComplexChannel(UwbComplexChannel.Builder()
.setChannel(9).setPreambleIndex(10).build())
.setDeviceAddress(deviceAddress)
.setSessionKeyInfo(byteArrayOf(0x01, 0x02, 0x03, 0x04))
.setRangingIntervalMillis(240)
.setSlotDuration(UwbRangingParams.DURATION_2_MS)
.setSlotsPerRangingRound(20)
.setRangingRoundIndexes(byteArrayOf(0x01, 0x05))
.build()
Java
DlTdoaRangingParams dlTdoaParams = new DlTdoaRangingParams.Builder(1)
.setComplexChannel(new UwbComplexChannel.Builder()
.setChannel(9).setPreambleIndex(10).build())
.setDeviceAddress(deviceAddress)
.setSessionKeyInfo(new byte[]{0x01, 0x02, 0x03, 0x04})
.setRangingIntervalMillis(240)
.setSlotDuration(UwbRangingParams.DURATION_2_MS)
.setSlotsPerRangingRound(20)
.setRangingRoundIndexes(new byte[]{0x01, 0x05})
.build();