ฟีเจอร์และ API

Android 17 มาพร้อมฟีเจอร์และ API ใหม่ๆ ที่ยอดเยี่ยมสำหรับนักพัฒนาแอป ส่วนต่อไปนี้ จะสรุปฟีเจอร์เหล่านี้เพื่อช่วยให้คุณเริ่มต้นใช้งาน API ที่เกี่ยวข้องได้

หากต้องการดูรายการ API ใหม่ที่มีการแก้ไขและนำออกโดยละเอียด โปรดอ่านรายงานความแตกต่างของ API ดูรายละเอียดเกี่ยวกับ API ใหม่ได้ที่เอกสารอ้างอิง Android API โดยเราจะไฮไลต์ API ใหม่เพื่อให้มองเห็นได้ชัดเจน

นอกจากนี้ คุณควรตรวจสอบส่วนที่การเปลี่ยนแปลงของแพลตฟอร์มอาจส่งผลต่อแอปด้วย ดูข้อมูลเพิ่มเติมได้ที่หน้าต่อไปนี้

ฟังก์ชันหลัก

Android 17 เพิ่มฟีเจอร์ใหม่ต่อไปนี้ที่เกี่ยวข้องกับฟังก์ชันหลักของ Android

ทริกเกอร์ ProfilingManager ใหม่

Android 17 เพิ่มทริกเกอร์ระบบใหม่หลายรายการลงใน ProfilingManager เพื่อ ช่วยคุณรวบรวมข้อมูลเชิงลึกเพื่อแก้ไขข้อบกพร่องด้านประสิทธิภาพ

ทริกเกอร์ใหม่มีดังนี้

  • TRIGGER_TYPE_COLD_START: ทริกเกอร์จะเกิดขึ้นระหว่างการเริ่มแอปแบบเย็น โดยจะ ให้ทั้งตัวอย่างสแต็กการเรียกใช้และการติดตามระบบในการตอบกลับ
  • TRIGGER_TYPE_OOM: ทริกเกอร์จะเกิดขึ้นเมื่อแอปส่งOutOfMemoryError และให้ Java Heap Dump เป็นการตอบกลับ
  • TRIGGER_TYPE_KILL_EXCESSIVE_CPU_USAGE: ทริกเกอร์จะเกิดขึ้นเมื่อระบบปิดแอปเนื่องจากมีการใช้งาน CPU มากเกินไปและผิดปกติ และจะแสดงตัวอย่างสแต็กการเรียกใช้เพื่อตอบสนอง

หากต้องการทำความเข้าใจวิธีตั้งค่าทริกเกอร์ของระบบ โปรดดูเอกสารประกอบเกี่ยวกับการสร้างโปรไฟล์ตามทริกเกอร์และวิธีดึงและวิเคราะห์เอกสารประกอบข้อมูลการสร้างโปรไฟล์

API ของ JobDebugInfo

Android 17 เปิดตัว JobDebugInfo API ใหม่เพื่อช่วยนักพัฒนาแอปในการแก้ไขข้อบกพร่องของงาน JobScheduler เช่น เหตุผลที่งานไม่ทำงาน ระยะเวลาที่งานทำงาน และข้อมูลรวมอื่นๆ

วิธีแรกของ JobDebugInfo API ที่ขยายแล้วคือ getPendingJobReasonStats() ซึ่งจะแสดงแผนที่ของเหตุผลที่งานอยู่ใน สถานะการดำเนินการที่รอดำเนินการและระยะเวลาที่รอดำเนินการสะสมที่เกี่ยวข้อง วิธีนี้จะรวมกับวิธี getPendingJobReasonsHistory() และ getPendingJobReasons() เพื่อให้ข้อมูลเชิงลึกเกี่ยวกับสาเหตุที่งานที่กำหนดเวลาไว้ไม่ทำงานตามที่คาดไว้ แต่จะลดความซับซ้อนในการดึงข้อมูลโดยการทำให้ทั้งระยะเวลาและเหตุผลของงานพร้อมใช้งานในวิธีเดียว

เช่น สำหรับ jobId ที่ระบุ เมธอดอาจแสดงผล PENDING_JOB_REASON_CONSTRAINT_CHARGING และระยะเวลา 60000 มิลลิวินาที ซึ่งบ่งชี้ว่า งานอยู่ในสถานะรอดำเนินการเป็นเวลา 60000 มิลลิวินาทีเนื่องจากข้อจำกัดในการชาร์จไม่เป็นไปตาม เงื่อนไข

ความเป็นส่วนตัว

Android 17 มีฟีเจอร์ใหม่ต่อไปนี้เพื่อปรับปรุงความเป็นส่วนตัวของผู้ใช้

เครื่องมือเลือกรายชื่อติดต่อ Android

เครื่องมือเลือกรายชื่อติดต่อของ Android เป็นอินเทอร์เฟซที่ได้มาตรฐานและเรียกดูได้สำหรับผู้ใช้ในการ แชร์รายชื่อติดต่อกับแอปของคุณ เครื่องมือเลือกนี้พร้อมใช้งานในอุปกรณ์ที่ใช้ Android 17 ขึ้นไป และเป็นทางเลือกที่ช่วยรักษาความเป็นส่วนตัวแทนREAD_CONTACTSสิทธิ์แบบกว้าง แทนที่จะขอสิทธิ์เข้าถึงสมุดที่อยู่ทั้งหมดของผู้ใช้ แอปจะระบุฟิลด์ข้อมูลที่ต้องการ เช่น หมายเลขโทรศัพท์หรืออีเมล และผู้ใช้จะเลือกรายชื่อติดต่อที่ต้องการแชร์ได้ ซึ่งจะให้สิทธิ์การเข้าถึงแบบอ่านแก่แอปของคุณเฉพาะข้อมูลที่เลือก เพื่อให้ควบคุมได้อย่างละเอียดพร้อมมอบประสบการณ์การใช้งานที่สอดคล้องกันด้วย ความสามารถในการค้นหาในตัว การสลับโปรไฟล์ และการเลือกหลายรายการโดยไม่ต้อง สร้างหรือดูแลรักษา UI

ดูข้อมูลเพิ่มเติมได้ที่เอกสารประกอบของเครื่องมือเลือกรายชื่อติดต่อ

ความปลอดภัย

Android 17 เพิ่มฟีเจอร์ใหม่ต่อไปนี้เพื่อปรับปรุงความปลอดภัยของอุปกรณ์และแอป

โหมดการปกป้องขั้นสูงของ Android (AAPM)

โหมดการปกป้องขั้นสูงของ Android มอบฟีเจอร์ด้านความปลอดภัยชุดใหม่ที่ทรงพลังให้แก่ผู้ใช้ Android ซึ่งถือเป็นก้าวสำคัญในการปกป้องผู้ใช้ โดยเฉพาะผู้ที่มีความเสี่ยงสูงจากการโจมตีที่ซับซ้อน AAPM ออกแบบมาให้เป็นฟีเจอร์ที่เลือกใช้ได้ โดยจะเปิดใช้งานด้วยการตั้งค่าเดียวที่ผู้ใช้เปิดได้ทุกเมื่อ เพื่อใช้ชุดการป้องกันความปลอดภัยที่กำหนดไว้

การกำหนดค่าหลักเหล่านี้รวมถึงการบล็อกการติดตั้งแอปจากแหล่งที่มาที่ไม่รู้จัก (การโหลดจากแหล่งที่ไม่รู้จัก) การจำกัดการส่งสัญญาณข้อมูลผ่าน USB และการกำหนดให้สแกนด้วย Google Play Protect ซึ่งจะช่วยลดพื้นที่ผิวการโจมตีของอุปกรณ์ได้อย่างมาก นักพัฒนาแอปสามารถผสานรวมกับฟีเจอร์นี้ได้โดยใช้ API AdvancedProtectionManager เพื่อตรวจหาสถานะของโหมด ซึ่งจะช่วยให้แอปพลิเคชันใช้ท่าทีด้านความปลอดภัยที่เข้มงวดขึ้นโดยอัตโนมัติ หรือจำกัดฟังก์ชันการทำงานที่มีความเสี่ยงสูงเมื่อผู้ใช้เลือกใช้

การเชื่อมต่อ

Android 17 เพิ่มฟีเจอร์ต่อไปนี้เพื่อปรับปรุงการเชื่อมต่อ อุปกรณ์และแอป

เครือข่ายดาวเทียมที่มีข้อจำกัด

ใช้การเพิ่มประสิทธิภาพเพื่อให้แอปทำงานได้อย่างมีประสิทธิภาพผ่านเครือข่ายดาวเทียมที่มีแบนด์วิดท์ต่ำ

ประสบการณ์ของผู้ใช้และ UI ของระบบ

Android 17 มีการเปลี่ยนแปลงต่อไปนี้เพื่อปรับปรุงประสบการณ์ของผู้ใช้

Handoff

Handoff เป็นฟีเจอร์และ API ใหม่ที่จะพร้อมใช้งานใน Android 17 ซึ่งนักพัฒนาแอป สามารถผสานรวมเพื่อมอบความต่อเนื่องข้ามอุปกรณ์ให้แก่ผู้ใช้ ซึ่งช่วยให้ผู้ใช้เริ่มกิจกรรมในแอปบนอุปกรณ์ Android เครื่องหนึ่งและ เปลี่ยนไปใช้อุปกรณ์ Android อีกเครื่องหนึ่งได้ Handoff จะทำงานในเบื้องหลังของอุปกรณ์ผู้ใช้และแสดงกิจกรรมที่พร้อมใช้งานจากอุปกรณ์อื่นๆ ที่อยู่ใกล้เคียงของผู้ใช้ผ่านจุดแรกเข้าต่างๆ เช่น ตัวเรียกใช้และแถบงานในอุปกรณ์ที่รับ

แอปสามารถกำหนดให้ Handoff เปิดแอป Android แบบเนทีฟเดียวกันได้ หากมีการ ติดตั้งและพร้อมใช้งานในอุปกรณ์ที่รับ ในขั้นตอนการทำงานจากแอปหนึ่งไปยังอีกแอปหนึ่งนี้ ระบบจะทำ Deep Link ผู้ใช้ไปยังกิจกรรมที่กำหนด หรือจะเสนอการส่งต่อจากแอปไปยังเว็บเป็นตัวเลือกสำรองหรือติดตั้งใช้งานโดยตรงด้วยการส่งต่อ URL ก็ได้

การรองรับ Handoff จะใช้งานได้ตามกิจกรรม หากต้องการเปิดใช้ Handoff ให้เรียกใช้เมธอด setHandoffEnabled() สำหรับกิจกรรม คุณอาจต้องส่งข้อมูลเพิ่มเติมพร้อมกับการส่งต่อเพื่อให้กิจกรรมที่สร้างขึ้นใหม่ในอุปกรณ์ที่รับสามารถกู้คืนสถานะที่เหมาะสมได้ ใช้onHandoffActivityRequested()การเรียกกลับเพื่อส่งคืนออบเจ็กต์ HandoffActivityData ซึ่งมีรายละเอียดที่ระบุวิธีที่ Handoff ควรจัดการและสร้างกิจกรรมใหม่ ในอุปกรณ์ที่รับ

การอัปเดตแบบเรียลไทม์ - API สีเชิงความหมาย

ใน Android 17 Live Update จะเปิดตัว Semantic Coloring API เพื่อ รองรับสีที่มีความหมายสากล

คลาสต่อไปนี้รองรับการระบายสีเชิงความหมาย

เกมระบายสี

  • สีเขียว: เกี่ยวข้องกับความปลอดภัย สีนี้ควรใช้ในกรณีที่ต้องการให้ผู้อื่นทราบว่าคุณอยู่ในสถานการณ์ที่ปลอดภัย
  • สีส้ม: สำหรับ ระบุข้อควรระวังและทำเครื่องหมายอันตรายทางกายภาพ ควรใช้สีนี้ในกรณีที่ผู้ใช้ต้องให้ความสนใจกับการตั้งค่าการปกป้องที่ดีขึ้น
  • สีแดง: โดยทั่วไปหมายถึงอันตราย หยุด ควรใช้ในกรณีที่ต้องการดึงดูดความสนใจของผู้คนอย่างเร่งด่วน
  • สีน้ำเงิน: สีที่เป็นกลางสำหรับเนื้อหาที่ให้ข้อมูลและควรโดดเด่นจากเนื้อหาอื่นๆ

ตัวอย่างต่อไปนี้แสดงวิธีใช้รูปแบบเชิงความหมายกับข้อความในการแจ้งเตือน

  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 สำหรับ Android 17

การวัดระยะโดยใช้ความแตกต่างของเวลาที่มาถึงของดาวน์ลิงก์ (DL-TDoA) ช่วยให้อุปกรณ์ระบุ ตำแหน่งของตนเองที่สัมพันธ์กับจุดยึดหลายจุดได้โดยการวัดเวลาที่สัญญาณมาถึง ที่สัมพันธ์กัน

ข้อมูลโค้ดต่อไปนี้แสดงวิธีเริ่มต้นเครื่องมือจัดการการวัดระยะ ยืนยันความสามารถของอุปกรณ์ และเริ่มเซสชัน 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.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)

ข้อมูลต่อไปนี้เป็นตัวอย่างข้อมูลการกำหนดค่า OOB ของ DL-TDoA สำหรับ Wi-Fi และ 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
};

หากใช้การกำหนดค่า OOB ไม่ได้เนื่องจากไม่มี หรือหากต้องการเปลี่ยนค่าเริ่มต้นที่ไม่ได้อยู่ในค่ากำหนด OOB คุณสามารถสร้างพารามิเตอร์ด้วย DlTdoaRangingParams.Builder ดังที่แสดงในข้อมูลโค้ดต่อไปนี้ คุณใช้พารามิเตอร์ต่อไปนี้แทน 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();