Android Q 기능 및 API

Android Q에는 사용자와 개발자를 위한 유용한 새 기능이 도입되었습니다. 이 문서에서는 개발자를 위한 새로운 기능을 소개합니다.

새로운 API에 대해 알아보려면 API 차이점 보고서를 참조하거나 Android API 참조를 방문해보세요. 새로운 API는 더 쉽게 알아볼 수 있도록 강조표시되어 있습니다. 또한 Q를 타겟팅하는 앱모든 앱에 관한 Android Q 동작 변경사항과 개인정보 보호 변경사항을 확인하여 플랫폼 변경이 앱에 영향을 줄 수 있는 분야에 관해 알아보세요.

보안 기능 향상

Android Q에는 여러 가지 보안 기능이 도입되는데, 다음에 이어지는 각 섹션에 그 내용이 요약되어 있습니다.

향상된 생체 인식 인증 대화상자

Android Q에서는 Android 9에 추가된 통합 생체 인식 인증 대화상자가 다음과 같이 개선되었습니다.

사용자 확인 요구사항 지정

이제 사용자가 암시적 생체 인식 모달리티를 사용하여 인증한 후에는 사용자 확인을 요구하지 않도록 시스템에 힌트를 제공할 수 있습니다. 예를 들어 사용자가 얼굴 인증을 사용하여 인증한 이후에는 추가 확인이 필요하지 않다고 시스템에 알릴 수 있습니다.

기본적으로 시스템에서는 사용자 확인을 요구합니다. 일반적으로 사용자는 민감하거나 위험성이 높은 작업(예: 구매)을 할 때 확인하려고 합니다. 하지만 앱과 관련하여 위험도가 낮은 특정 작업이 있는 경우 setConfirmationRequired() 메서드에 false를 전달하여 사용자 확인이 필요하지 않다는 힌트를 제공할 수 있습니다. 이 플래그는 시스템에 힌트로 전달되므로 사용자가 생체 인식 인증에 대한 시스템 설정을 변경한 경우 값이 무시될 수 있습니다.

사용자 확인이 필요하지 않은 얼굴 인증의 예

그림 1.사용자 확인이 필요하지 않은 얼굴 인증

사용자 확인이 요구되는 얼굴 인증의 예

그림 2.사용자 확인이 요구되는 얼굴 인증

기기 사용자 인증 정보를 위한 대체 지원 향상

이제 어떤 이유로든 사용자가 생체 인식 입력을 사용하여 인증할 수 없는 경우, 기기 PIN, 패턴 또는 비밀번호를 사용하여 인증하도록 허용할 수 있습니다. 이러한 대체 지원을 사용 설정하려면 setDeviceCredentialAllowed() 메서드를 사용하세요.

앱에서 현재 createConfirmDeviceCredentialIntent()를 사용해 기기 사용자 인증 정보로 대체하는 경우에는 대신 새 메서드 사용으로 전환합니다.

기기의 생체 인식 기능 확인

이제 BiometricManager 클래스의 canAuthenticate() 메서드를 사용해 BiometricPrompt를 호출하기 전에 기기에서 생체 인식 인증을 지원하는지 확인할 수 있습니다.

APK에서 직접 삽입된 DEX 코드 실행

이제 삽입된 DEX 코드를 앱의 APK 파일에서 직접 실행하도록 플랫폼에 알릴 수 있습니다. 이 옵션을 사용하면 공격자가 기기에서 로컬로 컴파일된 코드로 변조한 경우에 공격을 차단할 수 있습니다.

이 기능을 사용 설정하려면 앱 manifest 파일의 <application> 요소에서 android:useEmbeddedDex 속성의 값을 true로 설정합니다. 또한 ART에서 직접 액세스할 수 있는 압축되지 않은 DEX 코드가 포함된 APK를 빌드해야 합니다. 압축되지 않은 DEX 코드로 APK를 빌드하려면 Gradle 또는 Bazel 구성 파일에 다음 옵션을 추가합니다.

Gradle

aaptOptions {
       noCompress 'dex'
    }
    

Bazel

    android_binary(
       ...,
       nocompress_extensions = [“.dex”],
    )
    

TLS 1.3 지원

플랫폼의 TLS 구현은 이제 TLS 1.3을 지원합니다. TLS 1.3은 성능 이점과 향상된 보안을 포함하는 TLS 표준의 주 버전입니다. 벤치마킹 결과에 따르면 TLS 1.3을 사용하면 TLS 1.2에 비해 보안 연결을 최대 40% 더 빠르게 설정할 수 있습니다.

TLS 1.3은 모든 TLS 연결에 기본적으로 사용 설정됩니다. SSLContext.getInstance("TLSv1.2")를 호출하여 TLS 1.3을 사용하지 않는 SSLContext를 가져올 수 있습니다. 또한 적절한 개체에 관해 setEnabledProtocols()를 호출하여 연결별로 프로토콜 버전을 사용 또는 사용 안함으로 설정할 수 있습니다.

다음은 TLS 1.3 구현에 대한 몇 가지 중요한 세부정보입니다.

  • TLS 1.3 암호화 제품군은 맞춤설정할 수 없습니다. TLS 1.3을 사용 설정하면 지원되는 TLS 1.3 암호화 제품군이 항상 사용 설정되며, setEnabledCipherSuites() 호출을 통해 사용 안함으로 설정하려는 모든 시도가 무시됩니다.
  • TLS 1.3이 협상되면 세션이 세션 캐시에 추가되기 전에 HandshakeCompletedListeners가 호출됩니다. 이는 TLS 1.2 및 다른 이전 버전과 반대입니다.
  • SSLEngine 인스턴스는 이전에 SSLHandshakeException을 발생시킨 경우와 같은 상황에서 SSLProtocolException을 발생시킵니다.
  • 0-RTT 모드는 지원되지 않습니다.

공개 Conscrypt API

이제 Conscrypt 보안 제공자에는 TLS 기능을 위한 공개 API가 포함됩니다. 이전에는 사용자가 리플렉션을 통해 이 기능에 액세스할 수 있었습니다. 하지만 P에 추가된 비공개 API 호출에 대한 제한으로 인해 Q에서는 이 기능이 그레이리스트에 포함되었으며 이후 출시에서는 더 제한될 예정입니다.

이 업데이트에서는 일반 javax.net.ssl API에서 사용할 수 없는 기능에 액세스하는 정적 메서드가 포함된 클래스 모음이 android.net.ssl 아래에 추가되었습니다. 이러한 클래스의 이름은 연결된 javax.net.ssl 클래스의 복수로 유추될 수 있습니다. 예를 들어 javax.net.ssl.SSLSocket 인스턴스에서 작동하는 코드는 새 android.net.ssl.SSLSockets 클래스의 메서드를 사용할 수 있습니다.

연결 기능

Android Q에는 네트워킹 및 연결과 관련한 몇 가지 개선 사항이 포함되어 있습니다.

Wi-Fi 네트워크 연결 API

Android Q에서는 P2P 연결 지원이 추가되었습니다. 이 기능을 사용하면 앱에서 요청된 네트워크의 속성을 설명할 수 있는 WifiNetworkSpecifier를 사용해 기기가 연결되는 액세스 포인트를 변경하라는 메시지를 사용자에게 표시할 수 있습니다. P2P 연결은 보조 기기(예: Chromecast 및 Google Home 하드웨어)의 부트스트랩 구성과 같은 네트워크 제공 이외 목적으로 사용됩니다.

이 API를 사용할 때는 다음 플로우를 사용합니다.

  1. WifiNetworkSpecifier.Builder를 사용해 Wi-Fi 네트워크 지정자를 만듭니다.

  2. 필요한 사용자 인증 정보와 함께 연결할 네트워크와 일치하도록 네트워크 필터를 설정합니다.

  3. SSID, SSID pattern, BSSID, BSSID pattern을 결합하여 각 요청에 다음 요구사항을 충족하는 네트워크 필터를 설정합니다.

    • 각 요청은 SSID, SSID pattern, BSSID, BSSID pattern 중 하나 이상을 제공해야 합니다.
    • 각 요청은 SSID 또는 SSID pattern 중 하나만 설정할 수 있습니다.
    • 각 요청은 BSSID 또는 BSSID pattern 중 하나만 설정할 수 있습니다.
  4. 요청의 상태를 추적하도록 NetworkCallback 인스턴스와 함께 네트워크 요청에 지정자를 추가합니다.

    사용자가 요청을 수락하고 네트워크가 연결되면 콜백 개체에서 NetworkCallback.onAvailable()가 호출됩니다. 사용자가 요청을 거부하거나 네트워크가 연결되지 않으면 콜백 개체에서 NetworkCallback.onUnavailable()가 호출됩니다.

P2P 연결에는 위치 또는 Wi-Fi 권한이 필요하지 않습니다. 피어 기기 연결 요청을 시작하면 기기 사용자가 연결 요청을 수락할 수 있도록 동일한 기기에서 대화상자가 시작됩니다.

사용자 승인 우회

사용자가 특정 앱의 요청에 응답하여 네트워크 연결을 승인하면 기기에서 특정 액세스 포인트에 관한 승인을 저장합니다. 앱에서 동일한 액세스 포인트에 다시 연결하도록 특별히 요청하는 경우 기기에서는 사용자 승인 단계를 건너뛰고 자동으로 네트워크에 연결합니다. API에서 요청한 네트워크에 연결되어 있는 동안 사용자가 네트워크를 삭제하면 앱과 네트워크의 이러한 조합에 관해 저장된 승인이 삭제되며, 사용자는 이후에 그 앱에서 발생하는 모든 요청을 다시 승인해야 합니다. 앱에서 SSID 또는 BSSID 패턴 등 일반적인 요청을 하는 경우 사용자는 요청을 승인해야 합니다.

코드 샘플

다음 코드 샘플은 SSID 접두사가 'test'이고 BSSID OUI가 '10:03:23'인 개방형 네트워크에 연결하는 방법을 보여줍니다.

Kotlin

    val specifier = WifiNetworkSpecifier.Builder()
        .setSsidPattern(PatternMatcher("test", PatternMatcher.PATTERN_PREFIX))
        .setBssidPattern(MacAddress.fromString("10:03:23:00:00:00"), MacAddress.fromString("ff:ff:ff:00:00:00"))
        .build()

    val request = NetworkRequest.Builder()
        .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
        .removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
        .setNetworkSpecifier(specifier)
        .build()

    val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager

    val networkCallback = object : ConnectivityManager.NetworkCallback() {
        ...
        override fun onAvailable(network: Network?) {
            // do success processing here..
        }

        override fun onUnavailable() {
            // do failure processing here..
        }
        ...
    }
    connectivityManager.requestNetwork(request, networkCallback)
    ...
    // Release the request when done.
    connectivityManager.unregisterNetworkCallback(networkCallback)
    

자바

    final NetworkSpecifier specifier =
      new WifiNetworkSpecifier.Builder()
      .setSsidPattern(new PatternMatcher("test", PatterMatcher.PATTERN_PREFIX))
      .setBssidPattern(MacAddress.fromString("10:03:23:00:00:00"), MacAddress.fromString("ff:ff:ff:00:00:00"))
      .build();

    final NetworkRequest request =
      new NetworkRequest.Builder()
      .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
      .removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
      .setNetworkSpecifier(specifier)
      .build();

    final ConnectivityManager connectivityManager = (ConnectivityManager)
      context.getSystemService(Context.CONNECTIVITY_SERVICE);

    final NetworkCallback networkCallback = new NetworkCallback() {
      ...
      @Override
      void onAvailable(...) {
          // do success processing here..
      }

      @Override
      void onUnavailable(...) {
          // do failure processing here..
      }
      ...
    };
    connectivityManager.requestNetwork(request, networkCallback);
    ...
    // Release the request when done.
    connectivityManager.unregisterNetworkCallback(networkCallback);
    

Wi-Fi 네트워크 제안 API

Android Q에는 앱에서 기기의 네트워크 사용자 인증 정보를 추가하여 Wi-Fi 액세스 포인트에 자동 연결할 수 있는 지원이 추가되었습니다. WifiNetworkSuggestion을 사용해 연결할 네트워크를 제안할 수 있습니다. 플랫폼에서는 사용자의 앱과 다른 앱의 입력을 기반으로 수락할 액세스 포인트를 최종 선택합니다.

다음 코드 샘플은 개방형 네트워크 하나, WPA2 네트워크 하나, WPA3 네트워크 하나의 사용자 인증 정보를 제공하는 방법을 보여줍니다.

Kotlin

    val suggestion1 = WifiNetworkSuggestion.Builder()
            .setSsid("test111111")
            .setIsAppInteractionRequired() // Optional (Needs location permission)
            .build()

    val suggestion2 = WifiNetworkSuggestion.Builder()
            .setSsid("test222222")
            .setWpa2Passphrase("test123456")
            .setIsAppInteractionRequired() // Optional (Needs location permission)
            .build()

    val suggestion3 = WifiNetworkSuggestion.Builder()
            .setSsid("test333333")
            .setWpa3Passphrase("test6789")
            .setIsAppInteractionRequired() // Optional (Needs location permission)
            .build()

    val suggestionsList = listOf(suggestion1, suggestion2, suggestion3)

    val wifiManager = context.getSystemService(Context.WIFI_SERVICE) as WifiManager

    val status = wifiManager.addNetworkSuggestions(suggestionsList);
    if (status != WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS) {
        // do error handling here
    }

    // Optional (Wait for post connection broadcast to one of your suggestions)
    val intentFilter = IntentFilter(WifiManager.ACTION_WIFI_NETWORK_SUGGESTION_POST_CONNECTION);

    val broadcastReceiver = object : BroadcastReceiver() {
        override fun onReceive(context: Context, intent: Intent) {
            if (!intent.action.equals(WifiManager.ACTION_WIFI_NETWORK_SUGGESTION_POST_CONNECTION)) {
                return;
            }
            // do post connect processing here
        }
    };
    context.registerReceiver(broadcastReceiver, intentFilter);
    

자바

    final WifiNetworkSuggestion suggestion1 =
      new WifiNetworkSuggestion.Builder()
      .setSsid("test111111")
      .setIsAppInteractionRequired() // Optional (Needs location permission)
      .build()

    final WifiNetworkSuggestion suggestion2 =
      new WifiNetworkSuggestion.Builder()
      .setSsid("test222222")
      .setWpa2Passphrase("test123456")
      .setIsAppInteractionRequired() // Optional (Needs location permission)
      .build()

    final WifiNetworkSuggestion suggestion3 =
      new WifiNetworkSuggestion.Builder()
      .setSsid("test333333")
      .setWpa3Passphrase("test6789")
      .setIsAppInteractionRequired() // Optional (Needs location permission)
      .build()

    final List<wifinetworksuggestion> suggestionsList =
      new ArrayList<wifinetworksuggestion> {{
        add(suggestion1);
        add(suggestion2);
        add(suggestion3);
      }};

    final WifiManager wifiManager =
      (WifiManager) context.getSystemService(Context.WIFI_SERVICE);

    final int status = wifiManager.addNetworkSuggestions(suggestionsList);
    if (status != WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS) {
    // do error handling here…
    }

    // Optional (Wait for post connection broadcast to one of your suggestions)
    final IntentFilter intentFilter =
      new IntentFilter(WifiManager.ACTION_WIFI_NETWORK_SUGGESTION_POST_CONNECTION);

    final BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
      @Override
      public void onReceive(Context context, Intent intent) {
        if (!intent.getAction().equals(
          WifiManager.ACTION_WIFI_NETWORK_SUGGESTION_POST_CONNECTION)) {
          return;
        }
        // do post connect processing here..
      }
    };
    context.registerReceiver(broadcastReceiver, intentFilter);
    

플랫폼이 제안된 액세스 포인트에 연결하려면 사용자가 앱의 제안을 승인해야 합니다. 플랫폼에서 검색 결과 앱의 제안 중 하나와 일치하는 네트워크를 처음으로 찾은 경우에 표시되는 알림에 대한 응답으로 사용자가 이 승인을 제공합니다. 플랫폼이 네트워크 제안 중 하나에 연결되면 설정에 해당 제안 앱에 대한 네트워크 연결을 나타내는 텍스트가 표시됩니다.

사용자 연결 해제 처리

사용자가 Wi-Fi 선택도구를 사용하여 연결할 때 네트워크 제안 중 하나에서 명시적으로 연결을 해제하면 해당 네트워크가 24시간 동안 차단됩니다. 차단 기간 동안에는 앱이 이 네트워크에 해당하는 네트워크 제안을 제거했다가 다시 추가해도 이 네트워크를 자동 연결하기 위해 고려하지 않습니다.

앱 승인 상태 변경

네트워크 제안 알림을 거부하는 사용자는 앱에서 CHANGE_WIFI_STATE 권한을 제거합니다. 사용자는 나중에 Wi-Fi 제어 메뉴(설정 > 앱 및 알림 > 특수 앱 액세스 > Wi-Fi 제어 > 앱 이름)로 이동하여 이 승인을 제공할 수 있습니다.

Wi-Fi 고성능 및 짧은 지연 시간 모드 개선

Android Q를 사용하면 기본 모뎀에 지연 시간 최소화를 위한 힌트를 제공할 수 있습니다.

Android Q는 고성능 모드와 짧은 지연 시간 모드를 효과적으로 지원하기 위해 Wi-Fi 잠금 API를 확장합니다. 고성능 모드와 짧은 지연 시간 모드에서는 Wi-Fi 절전 기능이 사용 중지되며, 모뎀의 지원에 따라 짧은 지연 시간 모드에서 추가 지연 시간 최적화가 사용될 수 있습니다.

짧은 지연 시간 모드는 잠금 대상 애플리케이션이 포그라운드에서 실행 중이고 화면이 켜져 있는 경우에만 사용됩니다. 짧은 지연 시간 모드는 실시간 모바일 게임 애플리케이션에 특히 유용합니다.

DNS 리졸버에서 전문 검색

Android Q에는 DNS over TLS와 전문 DNS 조회를 위한 네이티브 지원이 추가되었습니다. 이전에는 플랫폼 DNS 리졸버에서 유형 A 해결책을 지원했습니다. 이는 IP에서 제공하는 서비스에 관한 세부 사항 없이 도메인 이름과 비교하여 IP 주소를 확인하는 방법입니다. 이제는 이 업데이트와 함께 SRVNAPTR 조회도 지원됩니다.

Android Q에서 개발자는 표준 일반 텍스트 조회와 DNS over TLS 모드를 모두 사용할 수 있습니다.

Wi-Fi 간편 연결

Android Q에서는 간편 연결을 사용해 지원 중단된 WPS 대신에 피어 기기에 대한 Wi-Fi 사용자 인증 정보를 프로비저닝할 수 있습니다. 앱에서는 ACTION_PROCESS_WIFI_EASY_CONNECT_URI 인텐트를 사용해 간편 연결을 설정과 프로비저닝 플로우에 통합할 수 있습니다. 이 인텐트에는 URI가 필요합니다. 호출 앱에서는 스티커 또는 화면에서 QR 코드를 스캔하거나 블루투스 LE 또는 NFC 광고를 스캔하는 등 다양한 방법을 통해 URI를 검색할 수 있습니다.

URI를 사용할 수 있게 되면 ACTION_PROCESS_WIFI_EASY_CONNECT_URI 인텐트로 피어 기기의 Wi-Fi 사용자 인증 정보를 프로비저닝할 수 있습니다. 그러면 사용자가 공유할 Wi-Fi 네트워크를 선택하고 사용자 인증 정보를 안전하게 전송할 수 있습니다.

간편 연결에는 위치나 Wi-Fi 권한이 필요하지 않습니다.

Wi-Fi Direct 연결 API

WifiP2pConfigWifiP2pManager API 클래스에는 Android Q에서 미리 결정된 정보를 사용하여 Wi-Fi Direct에 대한 빠른 연결 설정 기능을 지원하기 위한 업데이트가 있습니다. 이 정보는 블루투스 또는 NFC와 같은 부채널을 통해 공유됩니다.

다음 코드 샘플은 미리 결정된 정보를 사용하여 그룹을 만드는 방법을 보여줍니다.

Kotlin

    val manager = getSystemService(Context.WIFI_P2P_SERVICE) as WifiP2pManager
    val channel = manager.initialize(this, mainLooper, null)

    // prefer 5G band for this group
    val config = WifiP2pConfig.Builder()
        .setNetworkName("networkName")
        .setPassphrase("passphrase")
        .enablePersistentMode(false)
        .setGroupOperatingBand(WifiP2pConfig.GROUP_OWNER_BAND_5GHZ)
        .build()

    // create a non-persistent group on 5GHz
    manager.createGroup(channel, config, null)
    

자바

    WifiP2pManager manager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
    Channel channel = manager.initialize(this, getMainLooper(), null);

    // prefer 5G band for this group
    WifiP2pConfig config = new WifiP2pConfig.Builder()
    .setNetworkName("networkName")
    .setPassphrase("passphrase")
    .enablePersistentMode(false)
    .setGroupOperatingBand(WifiP2pConfig.GROUP_OWNER_BAND_5GHZ)
    .build();

    // create a non-persistent group on 5GHz
    manager.createGroup(channel, config, null);
    

사용자 인증 정보를 사용하여 그룹에 가입하려면 manager.createGroup()을 다음으로 바꿉니다.

Kotlin

    manager.connect(channel, config, null)
    

자바

    manager.connect(channel, config, null);
    

블루투스 LE 연결 지향 채널(CoC)

Android Q를 사용하면 앱에서 BLE CoC 연결을 통해 두 BLE 기기 간에 대형 데이터 스트림을 전송할 수 있습니다. 이 인터페이스는 블루투스 및 연결 메커니즘을 추상화하여 구현을 단순화합니다.

통신 기능

Android Q에는 통신과 관련한 몇 가지 개선 사항이 포함되어 있습니다.

통화 품질 개선

Android Q에는 기능을 지원하는 기기에서 네트워크 통신 품질을 비롯하여 지속적 IP 멀티미디어 하위 시스템(IMS) 호출의 품질에 대한 정보를 수집하는 기능이 추가되었습니다.

통화 선택 및 발신번호 표시

Android Q를 사용하면 앱에서 사용자의 주소록에 없는 통화를 잠재적 스팸 전화로 식별하고 사용자를 대신하여 스팸 전화를 자동으로 거부할 수 있습니다. 이러한 차단된 전화에 관한 정보는 통화 기록에 차단된 전화로 기록되므로 통화를 받지 못한 사용자가 이를 알 수 있도록 투명하게 표시됩니다. 이 새로운 API를 사용하면 통화 선택 및 발신번호 표시 기능을 제공하기 위해 사용자에게 READ_CALL_LOG 권한을 얻을 필요가 없습니다.

통화 리디렉션 서비스 API

Android Q에서는 통화 인텐트를 처리하는 방법이 변경되었습니다. NEW_OUTGOING_CALL 브로드캐스트는 지원 중단되고 CallRedirectionService API로 대체되었습니다. CallRedirectionService API는 Android 플랫폼에서 생성된 발신 전화를 수정할 수 있는 인터페이스를 제공합니다. 예를 들어 제3자 앱이 통화를 취소하고 VoIP를 통해 통화 경로를 변경할 수 있습니다.

외부 저장소에 파일을 만드는 기능 개선 사항

Android Q에서는 범위 지정 저장소의 개인정보 보호 동작 변경을 도입했을 뿐만 아니라 더욱 유연하게 파일을 작성할 수 있도록 지원하며 이러한 파일이 외부 저장소 기기에서 저장되는 위치에 영향을 주는 기능도 도입했습니다.

새 미디어 파일의 대기 중 상태

Android Q는 미디어 파일을 디스크에 쓸 때 해당 미디어 파일에 독점적으로 액세스할 수 있는 권한을 앱에 제공하는 IS_PENDING 플래그를 도입했습니다.

다음 코드 스니펫은 앱에서 새 이미지를 만들 때 IS_PENDING 플래그를 사용하는 방법을 보여줍니다.

Kotlin

    val values = ContentValues().apply {
        put(MediaStore.Images.Media.DISPLAY_NAME, "IMG1024.JPG")
        put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg")
        put(MediaStore.Images.Media.IS_PENDING, 1)
    }

    val resolver = context.getContentResolver()
    val collection = MediaStore.Images.Media
            .getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY)
    val item = resolver.insert(collection, values)

    resolver.openFileDescriptor(item, "w", null).use { pfd ->
        // Write data into the pending image.
    }

    // Now that we're finished, release the "pending" status, and allow other apps
    // to view the image.
    values.clear()
    values.put(MediaStore.Images.Media.IS_PENDING, 0)
    resolver.update(item, values, null, null)
    

자바

    ContentValues values = new ContentValues();
    values.put(MediaStore.Images.Media.DISPLAY_NAME, "IMG1024.JPG");
    values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
    values.put(MediaStore.Images.Media.IS_PENDING, 1);

    ContentResolver resolver = context.getContentResolver();
    Uri collection = MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY);
    Uri item = resolver.insert(collection, values);

    try (ParcelFileDescriptor pfd = resolver.openFileDescriptor(item, "w", null)) {
        // Write data into the pending image.
    } catch (IOException e) {
        e.printStackTrace();
    }

    // Now that we're finished, release the "pending" status, and allow other apps
    // to view the image.
    values.clear();
    values.put(MediaStore.Images.Media.IS_PENDING, 0);
    resolver.update(item, values, null, null);
    

저장소 위치에 미치는 영향

Android Q에는 앱이 외부 저장소에 제공하는 파일을 구성하는 데 도움을 줄 여러 기능이 있습니다.

디렉터리 힌트

앱이 Android Q를 실행하는 기기에서 미디어를 제공하는 경우 미디어는 기본적으로 유형에 따라 구성됩니다. 예를 들어 새 이미지 파일은 기본적으로 "사진" 디렉터리에 배치됩니다.

앱에서 파일이 저장되어야 하는 특정 위치(예: Pictures/MyVacationPictures)를 알고 있는 경우 MediaColumns.RELATIVE_PATH를 설정하여 새로 작성된 파일을 저장할 위치에 대한 힌트를 시스템에 제공할 수 있습니다. 마찬가지로, update() 호출 중에 MediaColumns.RELATIVE_PATH 또는 MediaColumns.DISPLAY_NAME을 변경하여 디스크의 파일을 이동할 수 있습니다.

기기 선택

Android 9(API 레벨 28) 이하에서는 외부 저장소 기기에 저장된 모든 파일이 external이라는 단일 볼륨 아래에 표시됩니다. 반면에 Android Q에서는 외부 저장소 기기마다 고유한 볼륨 이름이 지정됩니다. 이러한 새로운 이름 지정 시스템을 통해 효율적으로 콘텐츠를 구성하고 콘텐츠 색인을 생성할 수 있으며 새 콘텐츠가 저장되는 위치를 관리할 수 있습니다.

기본 공유 저장소 기기는 항상 VOLUME_EXTERNAL_PRIMARY라고 합니다. 다른 볼륨은 MediaStore.getExternalVolumeNames()를 호출하여 탐색할 수 있습니다.

특정 볼륨을 쿼리, 삽입, 업데이트 또는 삭제하려면 다음 코드 스니펫에 나와 있는 것처럼 MediaStore API에 제공된 getContentUri() 메서드 중 하나에 해당 볼륨 이름을 전달합니다.

    // Publish an audio file onto a specific external storage device.
    val values = ContentValues().apply {
        put(MediaStore.Audio.Media.RELATIVE_PATH, "Music/My Album/My Song")
        put(MediaStore.Audio.Media.DISPLAY_NAME, "My Song.mp3")
    }

    // Assumes that the storage device of interest is the 2nd one
    // that your app recognizes.
    val volumeNames = MediaStore.getExternalVolumeNames(context)
    val selectedVolumeName = volumeNames[1]
    val collection = MediaStore.Audio.Media.getContentUri(selectedVolumeName)
    val item = resolver.insert(collection, values)
    

미디어 및 그래픽

Android Q에는 다음과 같은 새로운 미디어 및 그래픽 기능과 API가 도입되었습니다.

오디오 재생 캡처

Android Q는 앱에 다른 앱의 오디오 재생을 캡처하는 기능을 제공합니다. 자세한 내용은 재생 캡처를 참조하세요.

네이티브 MIDI API

Android 네이티브 MIDI API(AMidi)를 사용하면 애플리케이션 개발자가 C/C++ 오디오/제어 로직을 긴밀하게 통합하고 JNI에 대한 필요성을 최소화하여 C/C++ 코드로 MIDI 데이터를 주고받을 수 있습니다.

자세한 내용은 Android 네이티브 MIDI API를 참조하세요.

MediaCodecInfo 개선 사항

MediaCodecInfo에는 코덱에 관한 자세한 정보를 보여주는 새로운 메서드가 있습니다.

isSoftwareOnly()
코덱이 소프트웨어에서만 실행되는 경우 true를 반환합니다. 소프트웨어 코덱은 렌더링 성능을 보장하지는 않습니다.
isHardwareAccelerated()
코덱이 하드웨어에 의해 가속화되는 경우 true를 반환합니다.
isVendor()
코덱이 기기 공급업체에 의해 제공되는 경우 true를 반환하고 Android 플랫폼에 의해 제공되는 경우 false를 반환합니다.
isAlias()
MediaCodecList에는 대체 코덱 이름(별칭)을 사용하는 동일한 기본 코덱에 대한 추가 항목이 포함될 수 있습니다. 이 항목의 코덱이 다른 코덱의 별칭인 경우 이 메서드는 true를 반환합니다.

또한 MediaCodec.getCanonicalName()에서는 별칭을 통해 만든 코덱의 기본 코덱 이름을 반환합니다.

성능 포인트

성능 포인트는 특정 높이, 너비 및 프레임 속도로 동영상을 렌더링하는 코덱의 기능을 나타냅니다. 예를 들어 UHD_60 성능 포인트는 60FPS로 렌더링되는 UHD 동영상(3,840x2,160픽셀)을 나타냅니다.

MediaCodecInfo.VideoCapabilities.getSupportedPerformancePoints() 메서드는 코덱이 렌더링하거나 캡처할 수 있는 PerformancePoint 항목의 목록을 반환합니다.

PerformancePoint.covers(PerformancePoint)를 호출하여 지정된 PerformancePoint에 다른 항목이 포함되는지 여부를 확인할 수 있습니다. 예를 들어 UHD_60.covers(UHD_50)는 true를 반환합니다.

성능 포인트 목록은 모든 하드웨어 가속 코덱에 대해 제공됩니다. 코덱이 최소 성능 포인트를 충족하지 않을 경우 빈 목록이 제공될 수 있습니다.

성능 포인트 데이터는 공급업체 HAL에서 제공되므로 공급업체 이미지를 업데이트하지 않고 Q로 업그레이드한 기기에는 성능 포인트 데이터가 없습니다. 이 경우 getSupportedPerformancePoints()는 null을 반환합니다.

ANGLE

Android Q의 출시로 Android 개발자와 파트너는 공급업체에서 제공하는 ES 드라이버를 사용하는 대신 Vulkan 위에 ES 레이어를 생성하는 Chrome 조직 내 프로젝트인 ANGLE을 사용하여 실행할 수 있습니다.

자세한 내용은 ANGLE을 참조하세요.

Thermal API

기기가 너무 뜨거워지면 CPU 및/또는 GPU가 제한될 수 있으며, 이로 인해 예상치 못한 방식으로 앱 및 게임에 영향을 줄 수 있습니다. 복잡한 그래픽이나 많은 계산, 지속적인 네트워크 활동을 사용하는 앱은 문제가 발생할 가능성이 더 높으며, 이러한 문제는 칩셋 및 코어 실행 빈도, 통합 수준, 기기 패키징 및 폼 팩터에 따라 기기에 다양하게 나타날 수 있습니다.

이제 Android Q의 앱 및 게임에서 Thermal API를 사용하여 기기에 대한 변경사항을 모니터링하고 전력 사용을 낮게 유지하여 정상 온도를 복원하도록 작업을 수행할 수 있습니다. 앱이 PowerManager리스너를 등록합니다. 시스템에서는 PowerManager를 통해 약함, 보통에서 심각, 위험, 비상, 종료에 이르기까지 진행 중인 열전달 상태를 보고합니다.

기기에서 열변형력을 보고하는 경우 앱 및 게임이 진행 중인 활동을 제한하여 다양한 방식으로 전력 사용을 줄이도록 도움을 줄 수 있습니다. 예를 들어 스트리밍 앱은 해상도/비트 전송률 또는 네트워크 트래픽을 줄일 수 있고, 카메라 앱은 플래시 또는 리소스를 많이 사용하는 이미지 보정을 사용 안함으로 설정할 수 있고, 게임은 프레임 속도 또는 다각형 테셀레이션을 줄일 수 있고, 미디어 앱은 스피커 볼륨을 줄일 수 있고, 지도 앱은 GPS를 끌 수 있습니다.

Thermal API를 사용하려면 새로운 기기 HAL 레이어가 필요합니다. 이 레이어는 현재 Android Q를 실행하는 Pixel 기기에서 지원되며 Google은 최대한 빨리 생태계에 광범위한 지원을 제공하기 위해 기기 제조업체 파트너와 협력하고 있습니다.

카메라 및 이미지

Android Q에는 다음과 같은 새로운 카메라와 이미지 관련 기능이 도입되었습니다.

흑백 카메라 지원

흑백 카메라 기능은 Android 9(API 레벨 28)에서 처음으로 도입되었습니다. Android Q에서는 흑백 카메라 지원에 대한 몇 가지 향상된 기능이 추가되었습니다.

  • 메모리 효율 향상을 위한 새로운 Y8 스트림 형식 지원
  • 흑백 RAW DNG 캡처 지원
  • 일반 흑백 카메라와 근적외선 카메라를 구별하기 위해 MONO 및 NIR CFA 열거 도입

이 기능을 사용하여 네이티브 흑백 이미지를 캡처할 수 있습니다. 논리적인 다중 카메라 기기에서는 흑백 카메라를 물리적 하위 카메라로 사용하여 저조도에서 더 나은 이미지 품질을 얻을 수 있습니다.

다이내믹 포커스 형식

Android Q부터 카메라에서 다이내믹 포커스 형식(Dynamic Depth Format, DDF)이라는 새로운 스키마를 사용하여 이미지의 깊이 데이터를 별도의 파일로 저장할 수 있습니다. 앱에서 해당 정보를 사용하여 원래 이미지 데이터를 수정하지 않고 처리 후 원하는 블러를 적용하기 위해 JPG 이미지와 깊이 메타데이터를 모두 요청할 수 있습니다.

새로운 형식의 사양은 다이내믹 포커스 형식을 참조하세요.

고효율 이미지 파일 형식

고효율 이미지 파일(HEIF) 형식은 다른 파일 형식에 비해 고품질 인코딩과 더 작은 파일 크기를 도입한 표준 이미지 및 동영상 형식입니다.

파일 형식에 관한 자세한 내용은 HEIC를 참조하세요.

다중 카메라 개선 사항

Android Q에는 Android 9(API 레벨 28)에 도입된 기능인 다중 카메라를 하나의 논리 카메라로 융합하는 기능이 개선되었습니다. Camera2 API에 다음이 추가되었습니다.

접근성 서비스 API

Android Q에서는 다음과 같은 새로운 접근성 기능 및 API가 도입되었습니다.

AccessibilityNodeInfo 입력 키 플래그

Android Q에서는 텍스트 입력 키를 나타내는지 여부를 지정하는 새로운 플래그로 AccessibilityNodeInfo를 개선했습니다. AccessibilityNodeInfo.isTextEntryKey() 메서드를 사용하여 이 플래그에 액세스할 수 있습니다.

접근성 대화상자 음성 피드백

접근성 서비스에서 사용자가 서비스를 시작하기 위해 접근성 바로가기를 반복해야 하는 경우, 서비스의 요청이 있다면 이제 텍스트 음성 변환 프롬프트를 통해 대화상자를 표시할 수 있습니다.

물리적 키보드의 접근성 바로가기

Android Q에서 사용자는 이제 물리적 키보드의 Control+Alt+Z를 눌러 접근성 바로가기를 트리거할 수 있습니다.

소프트 키보드 컨트롤러 향상

Android Q의 접근성 서비스에서는 이제 기기에 연결된 하드 키보드가 감지되더라도 소프트 키보드를 표시하도록 요청할 수 있습니다. 사용자는 이 동작을 재정의할 수 있습니다.

사용자 정의 접근성 시간 제한

Android Q에서는 대화형 및 비대화형 접근성 UI 요소에 대한 사용자 정의 시간 제한을 지원하는 AccessibilityManager.getRecommendedTimeoutMillis() API 메서드가 도입되었습니다. 반환되는 값은 사용자 환경설정과 접근성 서비스 API 모두의 영향을 받습니다.

자동 완성 향상

Android Q에서는 자동 완성 서비스가 다음과 같이 향상되었습니다.

이제 FillRequest.FLAG_COMPATIBILITY_MODE_REQUEST 플래그를 사용해 자동 완성 요청이 호환성 모드를 통해 생성되었는지 여부를 확인할 수 있습니다.

사용자 이름과 비밀번호 동시에 저장

이제 애플리케이션이 여러 활동에서 SaveInfo.FLAG_DELAY_SAVE 플래그를 사용하여 사용자 이름, 비밀번호, 기타 필드를 표시할 수 있습니다.

저장 UI와 사용자 상호작용

이제 대화상자에서 작업 리스너를 설정하고 해당 비밀번호 원격 보기의 공개 상태를 변경하여 저장 대화상자에서 비밀번호 필드를 표시하거나 숨길 수 있습니다.

데이터세트 업데이트 지원

이제 자동 완성을 통해 기존 비밀번호를 업데이트할 수 있습니다. 예를 들어 비밀번호를 이미 저장한 상태에서 새 비밀번호를 저장하면 이제 자동 완성 기능에서 새 비밀번호를 저장하는 대신 기존 비밀번호를 업데이트하라는 메시지를 표시합니다.

필드 분류 향상

Android Q에서는 필드 분류 API가 다음과 같이 향상되었습니다.

UserData.Builder 생성자

UserData.Builder 생성자가 Builder 패턴에 맞게 정렬되도록 변경되었습니다.

여러 유형의 카테고리 ID에 대한 값 매핑 허용

Android Q에서 UserData.Builder를 사용하는 경우 이제 값을 여러 유형의 카테고리 ID에 매핑할 수 있습니다. 이전 출시에서는 값을 여러 번 추가할 경우 예외가 발생했습니다.

신용카드 번호 지원 향상

이제 필드 분류에서 4자리 숫자를 신용카드 번호의 마지막 네 자리로 감지할 수 있습니다.

앱별 필드 분류 지원

Android Q에 세션 기간 동안 앱별 사용자 데이터를 설정할 수 있는 FillResponse.setUserData()가 추가되었습니다. 이 메서드는 자동 완성 서비스에서 앱별 콘텐츠가 있는 필드의 유형을 감지하는 데 도움이 됩니다.

UI 및 시스템 제어

Android Q에서는 사용자 인터페이스가 다음과 같이 향상되었습니다.

JVMTI PopFrame 한도 지원

Android Q에 Android JVMTI 구현의 can_pop_frames 기능에 대한 지원이 추가되었습니다. 디버깅할 때 이 기능을 사용하면 중단점에서 일시중지하고 기능의 로컬, 글로벌 또는 구현을 조정한 후 기능을 다시 실행할 수 있습니다. 자세한 내용은 Oracle의 Pop Frame 참조 페이지를 참조하세요.

Surface control API

Android Q에서는 시스템 컴포지터(SurfaceFlinger)에 대한 하위 수준 액세스에 사용되는 SurfaceControl API를 제공합니다. 대부분의 사용자는 SurfaceView를 사용하여 컴포지터를 올바르게 활용할 수 있습니다. SurfaceControl API는 다음과 같은 특정한 경우에 유용합니다.

  • 여러 표면 동기화
  • 크로스 프로세스 표면 임베딩
  • 하위 수준 전체 기간 관리

SurfaceControl API는 SDK 바인딩과 NDK 바인딩 둘 다에서 사용할 수 있습니다. NDK 구현에는 컴포지터를 통한 수동 버퍼 교환용 API가 포함되어 있습니다. 이 API는 BufferQueue 한계에 도달한 사용자에게 대안을 제공합니다.

WebView 중단 렌더기 감지

Android Q에는 앱에서 WebView가 응답하지 않는지 감지하는 데 사용할 수 있는 새로운 WebViewRenderProcessClient 추상 클래스가 도입되었습니다. 이 클래스를 사용하려면 다음 단계를 따르세요.

  1. 자체 서브클래스를 정의하고 그 서브클래스의 onRenderProcessResponsive()onRenderProcessUnresponsive() 메서드를 구현합니다.
  2. WebViewRenderProcessClient의 인스턴스를 하나 이상의 WebView 개체에 연결합니다.
  3. WebView가 응답하지 않으면 시스템에서 클라이언트의 onRenderProcessUnresponsive() 메서드를 호출하여 WebViewWebViewRenderProcess를 전달합니다. WebView가 단일 프로세스인 경우 WebViewRenderProcess 매개변수는 null입니다. 앱에서 적절히 조치할 수 있습니다. 예를 들어 사용자에게 렌더링 처리를 중단할지 여부를 묻는 대화상자를 표시할 수 있습니다.

WebView가 계속 응답하지 않으면 시스템에서 주기적으로(5초에 한 번 이하) onRenderProcessUnresponsive()를 호출하지만 다른 조치는 취하지 않습니다. WebView가 다시 응답하게 되면 시스템에서 onRenderProcessResponsive()를 한 번만 호출합니다.

설정 패널

Android Q에서는 앱의 맥락에서 사용자에게 설정을 표시할 수 있는 API인 설정 패널이 도입되었습니다. 따라서 사용자가 앱을 사용하기 위해 설정으로 이동하여 NFC, 모바일 데이터 등을 변경할 필요가 없습니다.

그림 1. 기기가 네트워크에 연결되지 않은 상태에서 사용자가 웹페이지를 열려고 합니다. Chrome에서 인터넷 연결 설정 패널 팝업이 표시됩니다.

그림 2. 사용자가 Chrome 앱을 종료하지 않고 Wi-Fi를 켜고 네트워크를 선택합니다.

예를 들어 기기가 비행기 모드에 있는 동안 사용자가 웹브라우저를 연다고 가정하겠습니다. Android Q 이전에는 설정을 열어 연결을 복원할지를 묻는 일반 메시지만 표시할 수 있었습니다. Android Q에서는 비행기 모드, Wi-Fi(근처 네트워크 포함), 모바일 데이터와 같은 주요 연결 설정을 보여주는 인라인 패널을 브라우저 앱에 표시할 수 있습니다. 이 패널에서 사용자는 앱을 종료하지 않고 연결을 복원할 수 있습니다.

설정 패널을 표시하려면 새 Settings.Panel 작업 중 하나를 통해 인텐트를 실행합니다.

Kotlin

    val panelIntent = Intent(Settings.Panel.settings_panel_type)
    startActivityForResult(panelIntent)
    

자바

    Intent panelIntent = new Intent(Settings.Panel.settings_panel_type);
    startActivityForResult(panelIntent);
    

settings_panel_type은 다음 중 하나일 수 있습니다.

ACTION_INTERNET_CONNECTIVITY
비행기 모드, Wi-Fi, 모바일 데이터와 같은 인터넷 연결과 관련된 설정을 표시합니다.
ACTION_WIFI:
Wi-Fi 설정을 표시합니다. 다른 연결 설정은 표시하지 않습니다. 이 기능은 대용량 업로드 또는 다운로드를 수행하기 위해 Wi-Fi 연결이 필요한 앱에 유용합니다.
ACTION_NFC
근거리 무선통신(NFC)과 관련된 모든 설정을 표시합니다.
ACTION_VOLUME
모든 오디오 스트림의 볼륨 설정을 표시합니다.

이 기능에 대해 AndroidX 래퍼를 도입할 예정입니다. Android 9(API 레벨 28) 이하를 실행 중인 기기에서 호출되면 래퍼는 설정 앱에서 가장 적절한 페이지를 엽니다.

공유 향상

Android Q에서는 공유 기능이 다양하게 개선되었습니다. 자세한 내용은 Android Q의 공유 개선을 참조하세요.

어두운 테마

Android Q에서는 Android 시스템 UI 및 기기에서 실행되는 앱 둘 다에 적용되는 어두운 테마를 새로 제공합니다. 자세한 내용은 어두운 테마를 참조하세요.

포그라운드 서비스 유형

Android Q에는 여러 특정 서비스 정의에 포함되는 XML manifest 속성인 foregroundServiceType이 새로 도입되었습니다. 드문 경우지만, 하나의 특정 서비스에 여러 포그라운드 서비스 유형을 할당할 수 있습니다.

다음 표에서는 다양한 포그라운드 서비스 유형과 특정 유형 선언에 적합한 서비스를 보여줍니다.

포그라운드 서비스 유형 이 유형을 선언해야 하는 서비스 사용 사례
connectedDevice 웨어러블 피트니스 트래커 모니터링
dataSync 네트워크에서 파일 다운로드
location 사용자가 시작한 작업 계속하기
mediaPlayback 오디오북, 팟캐스트 또는 음악 재생
mediaProjection 짧은 기간의 기기 디스플레이 동영상 녹화
phoneCall 진행 중인 전화 통화 처리

Kotlin

Android Q에는 Kotlin 개발을 위한 다음과 같은 업데이트가 포함되어 있습니다.

libcore API에 대한 Null 허용 여부 주석

Android Q에서는 libcore API용 SDK에서 null 허용 여부 주석의 노출 범위가 개선되었습니다. 이러한 주석을 사용하면 Android 스튜디오에서 Kotlin 또는 자바 null 허용 여부 분석을 사용 중인 앱 개발자가 이러한 API와 상호작용할 때 nullness 정보를 가져올 수 있습니다.

일반적으로 Kotlin에서 null 허용 여부 계약을 위반하면 컴파일 오류가 발생합니다. 기존 코드와의 호환성을 보장하기 위해 새로운 주석은 @RecentlyNullable@RecentlyNonNull로 제한됩니다. 즉, null 허용 여부를 위반할 경우 오류 대신 경고가 표시됩니다.

또한 Android 9에 추가된 @RecentlyNullable 또는 @RecentlyNonNull 주석이 각각 @Nullable@NonNull로 변경됩니다. 즉, null 허용 여부를 위반하면 이제 경고 대신 오류가 발생합니다.

주석 변경에 관한 자세한 내용은 Android 개발자 블로그에서 이제 Android Pie SDK에서 Kotlin 지원이 강화되었습니다를 참조하세요.

NDK

Android Q에는 다음과 같은 NDK 변경사항이 있습니다.

파일 설명어 소유권 디버깅 향상

Android Q에는 파일 설명어 소유권 문제를 더 간편하게 찾아서 해결할 수 있도록 fdsan이 추가되었습니다.

use-after-closedouble-close로 표시되는 경향이 있는 잘못된 파일 설명어 소유권 처리와 관련한 버그는 메모리 할당 use-after-freedouble-free 버그와 유사하지만 진단하여 수정하기가 훨씬 더 어려운 경향이 있습니다. fdsan은 파일 설명어 소유권을 강제 적용하여 잘못된 파일 설명어 관리를 감지한 후 차단하려고 합니다.

이러한 문제와 관련한 충돌에 관한 자세한 내용은 fdsan에 의해 감지되는 오류를 참조하세요. fdsan에 관한 자세한 내용은 fdsan의 Googlesource 페이지를 참조하세요.

ELF TLS

NDK를 사용하여 최소 API 레벨 29로 빌드된 애플리케이션에서는 더 이상 emutls를 사용할 필요가 없지만 대신 ELF TLS를 사용할 수 있습니다. 스레드 로컬 변수를 처리하는 새로운 메서드를 지원하기 위해 동적 및 정적 링커 지원이 추가되었습니다.

API 레벨 28 이하용으로 빌드된 앱의 경우 일부 emutls 문제를 해결하기 위해 libgcc/compiler-rt를 개선했습니다.

자세한 내용은 NDK 개발자를 위한 Android 변경사항을 참조하세요.

런타임

Android Q에는 다음과 같은 런타임 변경사항이 포함되어 있습니다.

Mallinfo 기반 가비지 컬렉션 실행

예를 들어 작은 플랫폼 자바 개체가 C++ 힙에서 큰 개체를 참조하는 경우 자바 개체가 수집되고 최종 마무리된 경우에만 C++ 개체가 회수될 수 있습니다. 이전 출시에서는 플랫폼에서 자바 개체와 연결된 많은 C++ 개체의 크기를 예측했습니다. 이 예측은 항상 정확한 것은 아니며 때때로 플랫폼에서 필요한 가비지 컬렉션에 실패할 경우 메모리 사용량이 크게 증가했습니다.

Q에서는 가비지 컬렉터(GC)가 시스템 malloc()에 의해 할당되는 총 힙 크기를 추적하여 큰 malloc() 할당이 GC 트리거 계산에 항상 포함되도록 합니다. 자바를 실행하여 많은 수의 C++ 할당과 인터리빙하는 앱에서는 결과적으로 가비지 컬렉션 빈도가 증가할 수 있습니다. 다른 앱에서는 약간 감소될 수 있습니다.

테스트 및 디버깅

Android Q에는 다음과 같은 테스트 및 디버깅 관련 개선 사항이 포함되어 있습니다.

온디바이스 시스템 추적 기능 개선

이제 온디바이스 시스템 추적을 수행할 때 추적의 크기와 지속 시간에 대해 한도를 지정할 수 있습니다. 두 값 중 하나를 지정하면 시스템에서는 장시간 추적을 수행하여 추적이 기록되는 동안 추적 버퍼를 대상 파일에 주기적으로 복사합니다. 지정한 크기 또는 지속 시간 한도에 도달하면 추적이 완료됩니다.

이러한 추가 매개변수를 사용하여 표준 추적으로 테스트하는 것과는 다른 사용 사례를 테스트하세요. 예를 들어 앱을 오랜 기간 실행한 후에만 발생하는 성능 버그를 진단할 수 있습니다. 이 경우 하루종일 수행한 장시간 추적을 기록한 다음, 보고서의 CPU 스케줄러, 디스크 활동, 앱 스레드 및 기타 데이터를 분석하면 버그의 원인을 파악하는 데 도움이 됩니다.

TextClassifier 개선 사항

Android Q에서는 TextClassifier 인터페이스에 추가 텍스트 분류 기능을 제공합니다.

언어 감지

TextClassifier에서 이제 detectLanguage() 메서드를 제공합니다. 이 메서드는 기존 분류 메서드와 유사하게 작동하여 TextLanguage.Request 개체를 수신하고 TextLanguage 개체를 반환합니다.

새로운 TextLanguage 개체는 순서쌍의 목록으로 구성됩니다. 각 쌍에는 요청된 텍스트 샘플의 언어와 해당하는 신뢰도 점수가 포함되어 있습니다.

권장 대화 작업

TextClassifier에서 이제 suggestConversationActions() 메서드를 제공합니다. 이 메서드는 기존 분류 메서드와 유사하게 작동하여 ConversationActions.Request 개체를 수신하고 ConversationActions 개체를 반환합니다.

ConversationActions 개체는 ConversationAction 개체 목록으로 구성되어 있습니다. 각 ConversationAction 개체에는 잠재적인 권장 작업과 그 작업의 신뢰도 점수가 포함되어 있습니다.

알림의 스마트 답장/작업

Android 9에서는 알림 내에 추천 답장을 표시할 수 있는 기능이 도입되었습니다. Android Q부터는 알림에 추천 인텐트 기반 작업도 포함할 수 있습니다. 그뿐만 아니라 이제 시스템에서 이러한 추천을 자동으로 생성할 수 있습니다. 앱도 자체 추천을 제공하거나 시스템 생성 추천을 선택 해제할 수 있습니다.

이러한 답장을 생성하는 데 사용되는 API는 TextClassifier의 일부이며 Android Q에서 개발자에게 직접 노출됩니다. 자세한 내용은 TextClassifier의 향상된 기능에 대한 섹션을 참조하세요.

앱에서 자체 추천을 제공하는 경우 플랫폼에서 자동 추천을 생성하지 않습니다. 앱 알림에 추천 답장 또는 작업을 표시하지 않으려면 setAllowGeneratedReplies()setAllowSystemGeneratedContextualActions()를 사용하여 시스템 생성 답장 및 작업을 선택 해제할 수 있습니다.