Fitur dan API

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:

Fungsi inti

Android 17 menambahkan fitur baru berikut yang terkait dengan fungsi Android inti.

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 memunculkan OutOfMemoryError dan 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.
  • TRIGGER_TYPE_ANOMALY: Mendeteksi anomali performa sistem seperti panggilan binder yang berlebihan dan penggunaan memori yang berlebihan.

Untuk memahami cara menyiapkan pemicu sistem, lihat dokumentasi tentang pembuatan profil berbasis pemicu dan cara mengambil dan menganalisis data pembuatan profil.

Pemicu pembuatan profil untuk anomali aplikasi

Android 17 memperkenalkan layanan deteksi anomali di perangkat yang memantau perilaku yang menggunakan banyak resource dan potensi regresi kompatibilitas. Layanan ini terintegrasi dengan ProfilingManager, sehingga aplikasi Anda dapat menerima artefak pembuatan profil yang dipicu oleh peristiwa tertentu yang terdeteksi sistem.

Gunakan pemicu TRIGGER_TYPE_ANOMALY untuk mendeteksi masalah performa sistem seperti panggilan binder yang berlebihan dan penggunaan memori yang berlebihan. Jika aplikasi melanggar batas memori yang ditentukan OS, pemicu anomali memungkinkan developer menerima heap dump khusus aplikasi untuk membantu mengidentifikasi dan memperbaiki masalah memori. Selain itu, untuk spam binder yang berlebihan, pemicu anomali menyediakan profil pengambilan sampel tumpukan pada transaksi binder.

Callback API ini terjadi sebelum penegakan yang diberlakukan sistem. Misalnya, hal ini dapat membantu developer mengumpulkan data debug sebelum aplikasi dihentikan oleh sistem karena melampaui batas memori.

val profilingManager =
    applicationContext.getSystemService(ProfilingManager::class.java)
val triggers = ArrayList<ProfilingTrigger>()
triggers.add(ProfilingTrigger.Builder(ProfilingTrigger.TRIGGER_TYPE_ANOMALY))
val mainExecutor: Executor = Executors.newSingleThreadExecutor()
val resultCallback = Consumer<ProfilingResult> { profilingResult ->
    if (profilingResult.errorCode != ProfilingResult.ERROR_NONE) {
        // upload profile result to server for further analysis
        setupProfileUploadWorker(profilingResult.resultFilePath)
    }
    profilingManager.registerForAllProfilingResults(mainExecutor,
                                                    resultCallback)
    profilingManager.addProfilingTriggers(triggers)
}

JobDebugInfo API

Android 17 memperkenalkan JobDebugInfo API baru untuk membantu developer men-debug tugas JobScheduler mereka—alasan tugas tidak berjalan, durasi tugas berjalan, dan informasi gabungan lainnya.

Metode pertama dari JobDebugInfo API yang diperluas adalah getPendingJobReasonStats(), yang menampilkan peta alasan mengapa tugas berada dalam status eksekusi yang tertunda dan durasi tertunda kumulatifnya. Metode ini bergabung dengan metode getPendingJobReasonsHistory() dan getPendingJobReasons() untuk memberi Anda insight tentang alasan tugas terjadwal tidak berjalan seperti yang diharapkan, tetapi menyederhanakan pengambilan informasi dengan menyediakan durasi dan alasan tugas dalam satu metode.

Misalnya, untuk jobId yang ditentukan, metode ini dapat menampilkan PENDING_JOB_REASON_CONSTRAINT_CHARGING dan durasi 60.000 md, yang menunjukkan bahwa tugas tertunda selama 60.000 md karena batasan pengisian daya tidak terpenuhi.

Mengurangi penguncian layar saat aktif dengan dukungan pemroses untuk alarm yang diizinkan saat perangkat dalam kondisi tidak aktif

Android 17 memperkenalkan varian baru AlarmManager.setExactAndAllowWhileIdle yang menerima OnAlarmListener, bukan PendingIntent. Mekanisme baru berbasis callback ini ideal untuk aplikasi yang saat ini mengandalkan wakelock berkelanjutan untuk melakukan tugas berkala, seperti aplikasi pesan yang mempertahankan koneksi soket.

Privasi

Android 17 menyertakan fitur baru berikut untuk meningkatkan privasi pengguna.

Dukungan platform Encrypted Client Hello (ECH)

Android 17 introduces platform support for Encrypted Client Hello (ECH), a significant privacy enhancement for network communications. ECH is a TLS 1.3 extension that encrypts the Server Name Indication (SNI) during the initial TLS handshake. This encryption helps protect user privacy by making it more difficult for network intermediaries to identify the specific domain an app is connecting to.

The platform now includes the necessary APIs for networking libraries to implement ECH. This includes new capabilities in DnsResolver to query for HTTPS DNS records containing ECH configurations, and new methods in Conscrypt's SSLEngines and SSLSockets to enable ECH by passing in these configurations when connecting to a domain. Developers can configure ECH preferences, such as enabling it opportunistically or mandating its use, through the new <domainEncryption> element within the Network Security Configuration file, applicable globally or on a per-domain basis.

Popular networking libraries such as HttpEngine, WebView, and OkHttp are expected to integrate these platform APIs in future updates, making it easier for apps to adopt ECH and enhance user privacy.

For more information, see the Encrypted Client Hello documentation.

Pemilih kontak Android

Pemilih Kontak Android adalah antarmuka standar yang dapat dijelajahi bagi pengguna untuk membagikan kontak ke aplikasi Anda. Tersedia di perangkat yang menjalankan Android 17 (level API 37) atau yang lebih tinggi, pemilih ini menawarkan alternatif yang menjaga privasi untuk izin READ_CONTACTS yang luas. Daripada meminta akses ke seluruh buku alamat pengguna, aplikasi Anda menentukan kolom data yang diperlukan, seperti nomor telepon atau alamat email, dan pengguna memilih kontak tertentu untuk dibagikan. Hal ini memberi aplikasi Anda akses baca hanya ke data yang dipilih, sehingga memastikan kontrol terperinci sekaligus memberikan pengalaman pengguna yang konsisten dengan kemampuan penelusuran, pengalihan profil, dan pemilihan ganda bawaan tanpa harus membuat atau memelihara UI.

Untuk mengetahui informasi selengkapnya, lihat dokumentasi pemilih kontak.

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.

Penandatanganan APK PQC

Android now supports a hybrid APK signature scheme to future-proof your app's signing identity against the potential threat of attacks that make use of quantum computing. This feature introduces a new APK Signature Scheme, which lets you pair a classical signing key (such as RSA or EC) with a new post-quantum cryptography (PQC) algorithm (ML-DSA).

This hybrid approach ensures your app remains secure against future quantum attacks while maintaining full backward compatibility with older Android versions and devices that rely on classical signature verification.

Impact on developers

  • Apps using Play App Signing: If you use Play App Signing, you can wait for Google Play to give you the option to upgrade a hybrid signature using a PQC key generated by Google Play, ensuring your app is protected without requiring manual key management.
  • Apps using self-managed keys: Developers who manage their own signing keys can utilize updated Android build tools (like apksigner) to rotate to a hybrid identity, combining a PQC key with a new classical key. (You must create a new classical key, you cannot reuse the older one.)

Konektivitas

Android 17 menambahkan fitur berikut untuk meningkatkan konektivitas perangkat dan aplikasi.

Jaringan satelit yang dibatasi

Menerapkan pengoptimalan agar aplikasi dapat berfungsi secara efektif melalui jaringan satelit dengan bandwidth rendah.

Pengalaman pengguna dan UI sistem

Android 17 menyertakan perubahan berikut untuk meningkatkan pengalaman pengguna.

Aliran volume Asisten khusus

Android 17 introduces a dedicated Assistant volume stream for Assistant apps, for playback with USAGE_ASSISTANT. This change decouples Assistant audio from the standard media stream, providing users with isolated control over both volumes. This enables scenarios such as muting media playback while maintaining audibility for Assistant responses, and the other way around.

Assistant apps with access to the new MODE_ASSISTANT_CONVERSATION audio mode can further improve the volume control consistency. Assistant apps can use this mode to provide a hint to the system about an active Assistant session, ensuring the Assistant stream can be controlled outside of the active USAGE_ASSISTANT playback or with connected Bluetooth peripherals.

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 onHandoffActivityDataRequested() untuk menampilkan objek HandoffActivityData yang berisi detail yang menentukan cara Handoff harus menangani dan membuat ulang aktivitas di perangkat penerima.

Pembaruan Langsung - Semantic color API

Dengan Android 17, Update Langsung meluncurkan Semantic Coloring API untuk mendukung warna dengan makna universal.

Class berikut mendukung pewarnaan semantik:

Mewarnai

  • Hijau: Terkait dengan keselamatan. Warna ini harus digunakan untuk kasus yang memberi tahu orang lain bahwa Anda berada dalam situasi yang aman.
  • Oranye: Untuk menunjukkan kehati-hatian dan menandai bahaya fisik. Warna ini harus digunakan dalam situasi saat pengguna perlu memperhatikan untuk menyetel 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 pada 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

Pengukuran Downlink Time Difference of Arrival (DL-TDoA) memungkinkan perangkat menentukan posisinya relatif terhadap beberapa anchor dengan mengukur waktu kedatangan sinyal relatif.

Cuplikan berikut menunjukkan cara menginisialisasi Pengelola Pengukuran, memverifikasi kemampuan perangkat, dan memulai sesi DL-TDoA:

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.RangingCapabilitiesCallback {
            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 = byteArrayOf(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.RangingCapabilitiesCallback() {
            @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());
        byte[] rangingRoundIndexes = new byte[] {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
        }
    }
}

Konfigurasi Out-of-Band (OOB)

Cuplikan berikut memberikan contoh data konfigurasi OOB DL-TDoA untuk Wi-Fi dan 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
};

Jika Anda tidak dapat menggunakan konfigurasi OOB karena tidak ada, atau jika Anda perlu mengubah nilai default yang tidak ada dalam konfigurasi OOB, Anda dapat membuat parameter dengan DlTdoaRangingParams.Builder seperti yang ditunjukkan dalam cuplikan berikut. Anda dapat menggunakan parameter ini sebagai pengganti 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();