기본 전화 애플리케이션 빌드

기본 전화 애플리케이션을 사용하면 Android 텔레콤 프레임워크가 Android 기기의 기본 전화 앱을 대체하는 역할 관리자 및 통화 중 서비스를 사용하여 애플리케이션에 통화 상태를 알리고 InCallService API를 구현합니다. 구현 시 다음 요구사항을 충족해야 합니다.

통화 기능이 없어야 하며 통화를 위한 사용자 인터페이스로만 구성되어야 합니다. 텔레콤 프레임워크가 인식하고 있는 모든 통화를 처리해야 하며 통화의 성격을 가정해서는 안 됩니다. 예를 들어 통화가 SIM 기반 전화 통화라고 가정하거나 하나의 ConnectionService에 기반한 통화 제한(예: 영상 통화에 대한 전화 제한 적용)을 구현해서는 안 됩니다.

통화 앱을 통해 사용자는 기기에서 음성 통화 또는 영상 통화를 받거나 걸 수 있습니다. 다음 스크린샷과 같이 통화 앱은 통화 시 기본 전화 앱 인터페이스를 사용하는 대신 자체 사용자 인터페이스를 사용합니다.

통화 앱의 예
자체 사용자 인터페이스를 사용하는 통화 앱의 예

Android 프레임워크에는 android.telecom 패키지가 포함되어 있으며 이 패키지에는 텔레콤 프레임워크에 따라 통화 앱을 빌드하는 데 도움이 되는 클래스가 포함되어 있습니다. 텔레콤 프레임워크에 따라 앱을 빌드하면 다음과 같은 이점이 있습니다.

  • 앱이 기기의 네이티브 텔레콤 하위 시스템과 올바르게 상호 운용됩니다.
  • 앱이 프레임워크를 준수하는 다른 통화 앱과도 올바르게 상호 운용됩니다.
  • 프레임워크를 통해 앱이 음성 및 영상 라우팅을 관리할 수 있습니다.
  • 프레임워크를 통해 앱이 통화에 포커스가 있는지 여부를 확인할 수 있습니다.

매니페스트 선언 및 권한

앱 매니페스트에서 앱이 MANAGE_OWN_CALLS 드림 권한을 부여할 수 있습니다.

<manifest … >
    <uses-permission android:name="android.permission.MANAGE_OWN_CALLS"/>
</manifest>

앱 권한 선언에 관한 자세한 내용은 권한을 참조하세요.

앱에서 ConnectionService 클래스를 구현하는 클래스를 지정하는 서비스를 선언해야 합니다. 텔레콤 하위 시스템에서는 서비스가 시스템에 결합할 수 있도록 BIND_TELECOM_CONNECTION_SERVICE 권한을 선언해야 합니다. 다음 예는 앱 매니페스트에서 서비스를 선언하는 방법을 보여줍니다.

<service android:name="com.example.MyConnectionService"
    android:permission="android.permission.BIND_TELECOM_CONNECTION_SERVICE">
    <intent-filter>
        <action android:name="android.telecom.ConnectionService" />
    </intent-filter>
</service>

서비스를 비롯한 앱 구성요소 선언에 관한 자세한 내용은 앱 구성요소를 참조하세요.

연결 서비스 구현

통화 앱은 텔레콤 하위 시스템이 결합할 수 있는 ConnectionService 클래스의 구현을 제공해야 합니다. ConnectionService 구현은 다음 메서드를 재정의해야 합니다.

onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)

텔레콤 하위 시스템은 새 발신 전화를 걸기 위해 placeCall(Uri, Bundle)을 호출하는 앱에 응답하여 이 메서드를 호출합니다. 앱은 새 발신 전화를 나타내는 Connection 클래스 구현의 새 인스턴스를 반환합니다. 자세한 내용은 연결 구현을 참조하세요. 다음 작업을 실행하여 발신 연결을 더욱 상세하게 맞춤설정할 수 있습니다.

onCreateOutgoingConnectionFailed(PhoneAccountHandle, ConnectionRequest)

앱에서 placeCall(Uri, Bundle) 메서드를 호출했는데 발신 전화를 걸 수 없을 때 텔레콤 하위 시스템은 이 메서드를 호출합니다. 이 상황에 대응하여 앱은 발신 전화를 걸 수 없다는 것을 사용자에게 알려야 합니다(예: 알림 상자 또는 토스트 메시지 사용). 진행 중인 긴급 전화가 있거나 다른 앱에서 먼저 진행 중인 통화를 보류할 수 없다면 앱에서 전화를 걸지 못할 수 있습니다.

onCreateIncomingConnection(PhoneAccountHandle, ConnectionRequest)

앱에서 addNewIncomingCall(PhoneAccountHandle, Bundle) 메서드를 호출하여 앱의 새로운 수신 전화를 시스템에 알릴 때 텔레콤 하위 시스템은 이 메서드를 호출합니다. 앱은 새 수신 전화를 나타내는 Connection 구현의 새 인스턴스를 반환합니다. 자세한 내용은 연결 구현을 참조하세요. 다음 작업을 실행하여 수신 연결을 더욱 상세하게 맞춤설정할 수 있습니다.

onCreateIncomingConnectionFailed(PhoneAccountHandle, ConnectionRequest)

앱에서 addNewIncomingCall(PhoneAccountHandle, Bundle) 메서드를 호출하여 새로운 수신 전화를 텔레콤에 알렸으나 수신 전화가 허용되지 않을 때 텔레콤 하위 시스템이 이 메서드를 호출합니다. 자세한 내용은 통화 제약을 참조하세요. 앱에서 자동으로 수신 전화를 거부하고 부재중 전화를 사용자에게 알리는 알림을 게시할 수도 있습니다.

연결 구현

앱에서 Connection의 서브클래스를 생성하여 앱의 통화를 나타내야 합니다. 구현 시 다음 메서드를 재정의해야 합니다.

onShowIncomingCallUi()

새 수신 전화가 추가되어 앱에 수신 전화 UI를 표시해야 할 때 텔레콤 하위 시스템은 이 메서드를 호출합니다.

onCallAudioStateChanged(CallAudioState)

텔레콤 하위 시스템은 이 메서드를 호출하여 현재 오디오 경로 또는 모드가 변경되었다는 것을 앱에 알립니다. 앱에서 setAudioRoute(int) 메서드를 사용하여 오디오 모드를 변경하는 것에 대응하여 이 메서드가 호출됩니다. 또한 시스템이 오디오 경로를 변경하면(예: 블루투스 헤드셋 연결이 끊겼을 때) 이 메서드가 호출될 수도 있습니다.

onHold()

텔레콤 하위 시스템은 통화를 대기 상태로 전환하려고 할 때 이 메서드를 호출합니다. 이 요청에 대응하여 앱은 통화를 대기 상태로 전환한 후 setOnHold() 메서드를 호출하여 통화가 대기 중이라는 것을 시스템에 알려야 합니다. 통화를 표시하는 Android Auto와 같은 통화 중 서비스에서 통화를 대기 상태로 전환하려는 사용자 요청을 전달하려고 할 때 텔레콤 하위 시스템은 이 메서드를 호출할 수 있습니다. 또한 사용자가 다른 앱에서 통화를 활성화할 때에도 텔레콤 하위 시스템은 이 메서드를 호출합니다. 통화 중 서비스에 관한 자세한 내용은 InCallService를 참조하세요.

onUnhold()

텔레콤 하위 시스템은 대기 상태의 통화를 재개하려고 할 때 이 메서드를 호출합니다. 앱에서 통화를 재개하면 setActive() 메서드를 호출하여 통화가 더 이상 대기 상태가 아니라는 것을 시스템에 알려야 합니다. 통화를 표시하는 Android Auto와 같은 통화 중 서비스에서 통화 재개 요청을 전달하려고 할 때 텔레콤 하위 시스템은 이 메서드를 호출할 수 있습니다. 통화 중 서비스에 관한 자세한 내용은 InCallService를 참조하세요.

onAnswer()

텔레콤 하위 시스템은 이 메서드를 호출하여 수신 전화에 응답해야 한다는 것을 앱에 알립니다. 앱에서 통화에 응답하면 setActive() 메서드를 호출하여 통화에 응답했다는 것을 시스템에 알려야 합니다. 앱에서 새 수신 전화를 추가했는데 다른 앱에서 이미 진행 중인 통화를 보류할 수 없을 때 텔레콤 하위 시스템은 이 메서드를 호출할 수 있습니다. 이럴 때 텔레콤 하위 시스템은 앱을 대신하여 수신 전화 UI를 표시합니다. 프레임워크는 전화에 응답할 영상 상태를 지정할 수 있도록 지원하는 오버로드된 메서드를 제공합니다. 자세한 내용은 onAnswer(int)를 참고하세요.

onReject()

텔레콤 하위 시스템은 수신 전화를 거부하려고 할 때 이 메서드를 호출합니다. 앱에서 통화를 거부하면 setDisconnected(DisconnectCause)를 호출하고 REJECTED를 매개변수로 지정해야 합니다. 그런 다음 앱에서 destroy() 메서드를 호출하여 통화를 처리했다는 것을 시스템에 알려야 합니다. 사용자가 앱에서 수신 전화를 거부했을 때 텔레콤 하위 시스템은 이 메서드를 호출합니다.

onDisconnect()

텔레콤 하위 시스템은 통화 연결을 끊으려고 할 때 이 메서드를 호출합니다. 통화가 종료되면 앱에서 setDisconnected(DisconnectCause) 메서드를 호출하고 LOCAL를 매개변수로 지정하여 사용자 요청으로 인해 통화 연결이 끊어졌습니다. 그런 다음 앱에서 destroy() 메서드를 호출하여 통화를 처리했다는 것을 텔레콤 하위 시스템에 알려야 합니다. 사용자가 Android Auto와 같은 다른 통화 중 서비스를 통해 통화 연결을 끊었을 때 시스템이 이 메서드를 호출할 수 있습니다. 또한 사용자가 긴급 전화를 걸려고 하는 상황과 같이 새 전화를 걸기 위해 기존 통화 연결을 끊어야 하는 때에도 시스템은 이 메서드를 호출합니다. 통화 중 서비스에 관한 자세한 내용은 InCallService를 참조하세요.

일반적인 통화 처리 시나리오

호출 흐름의 ConnectionService API를 사용하면 android.telecom 패키지의 다른 클래스와 상호작용하게 됩니다. 다음 섹션에서는 일반적인 통화 시나리오 및 앱에서 API를 사용하여 통화를 처리하는 방법을 설명합니다.

수신 전화 받기

수신 전화를 처리하는 흐름은 다른 앱에 통화가 있는지 여부에 따라 변경됩니다. 흐름의 차이가 생기는 이유는 기기의 모든 통화 앱에 안정적인 환경을 보장하기 위해 다른 앱에 진행 중인 통화가 있을 때 텔레콤 프레임워크가 일부 제약을 설정해야 하기 때문입니다. 자세한 내용은 통화 제약을 참조하세요.

다른 앱에 진행 중인 통화가 없을 때

다른 앱에 진행 중인 통화가 없을 때 수신 전화를 받으려면 다음 단계를 따르세요.

  1. 앱에서 일반적인 메커니즘을 사용하여 새로운 수신 전화를 받습니다.
  2. addNewIncomingCall(PhoneAccountHandle, Bundle) 메서드를 사용하여 새 수신 전화에 관해 텔레콤 하위 시스템에 알립니다.
  3. 텔레콤 하위 시스템은 앱의 ConnectionService 구현에 결합하고 onCreateIncomingConnection(PhoneAccountHandle, ConnectionRequest) 메서드를 사용하여 새 수신 전화를 나타내는 Connection 클래스의 새 인스턴스를 요청합니다.
  4. 텔레콤 하위 시스템은 onShowIncomingCallUi() 메서드를 사용하여 수신 전화 사용자 인터페이스를 표시해야 한다는 것을 앱에 알립니다.
  5. 앱은 관련 전체 화면 인텐트가 있는 알림을 사용하여 수신 전화 UI를 표시합니다. 자세한 내용은 onShowIncomingCallUi()를 참조하세요.
  6. 사용자가 수신 전화를 수락하면 setActive() 메서드를 호출하거나 사용자가 수신 전화를 거부하면 REJECTED를 매개변수로 지정하여 setDisconnected(DisconnectCause)를 호출한 후 destroy() 메서드를 호출합니다.

다른 앱에서 진행 중인 통화를 보류할 수 없을 때

다른 앱에서 진행 중인 통화를 보류할 수 없을 때 수신 전화를 받으려면 다음 단계를 따르세요.

  1. 앱에서 일반적인 메커니즘을 사용하여 새로운 수신 전화를 받습니다.
  2. addNewIncomingCall(PhoneAccountHandle, Bundle) 메서드를 사용하여 새 수신 전화에 관해 텔레콤 하위 시스템에 알립니다.
  3. 텔레콤 하위 시스템은 앱의 ConnectionService 구현에 결합하고 onCreateIncomingConnection(PhoneAccountHandle, ConnectionRequest) 메서드를 사용하여 새 수신 전화를 나타내는 Connection 객체의 새 인스턴스를 요청합니다.
  4. 텔레콤 하위 시스템은 수신 전화를 위해 수신 전화 UI를 표시합니다.
  5. 사용자가 통화를 수락하면 텔레콤 하위 시스템은 onAnswer() 메서드를 호출합니다. setActive() 메서드를 호출하여 이제 통화가 연결되었음을 텔레콤 하위 시스템에 알려야 합니다.
  6. 사용자가 통화를 거부하면 텔레콤 하위 시스템은 onReject() 메서드를 호출합니다. REJECTED를 매개변수로 지정하여 setDisconnected(DisconnectCause) 메서드를 호출한 후 destroy() 메서드를 호출해야 합니다.

발신 전화 걸기

발신 전화를 걸기 위한 흐름에는 텔레콤 프레임워크에 의해 부과된 제약으로 인해 전화를 걸지 못할 가능성을 처리하는 것이 포함됩니다. 자세한 내용은 통화 제약을 참조하세요.

발신 전화를 걸려면 다음 단계를 따르세요.

  1. 사용자가 앱 내에서 발신 전화를 시작합니다.
  2. placeCall(Uri, Bundle) 메서드를 사용하여 새 발신 전화에 관해 텔레콤 하위 시스템에 알립니다. 메서드 매개변수와 관련하여 다음을 고려합니다.
    • Uri 매개변수는 전화를 걸고 있는 대상 주소를 나타냅니다. 일반 전화번호에는 tel: URI 스키마를 사용합니다.
    • Bundle 매개변수를 사용하면 EXTRA_PHONE_ACCOUNT_HANDLE 엑스트라에 앱의 PhoneAccountHandle 객체를 추가하여 통화 앱에 관한 정보를 제공할 수 있습니다. 앱은 모든 발신 전화에 PhoneAccountHandle 객체를 제공해야 합니다.
    • 또한 Bundle 매개변수를 사용하면 EXTRA_START_CALL_WITH_VIDEO_STATE 엑스트라에 STATE_BIDIRECTIONAL 값을 지정하여 발신 전화에 영상을 포함할지 여부도 지정할 수 있습니다. 기본적으로 텔레콤 하위 시스템은 영상 통화를 스피커폰으로 라우팅합니다.
  3. 텔레콤 하위 시스템은 앱의 ConnectionService 구현에 결합합니다.
  4. 앱에서 발신 전화를 걸 수 없다면 텔레콤 하위 시스템은 onCreateOutgoingConnectionFailed(PhoneAccountHandle, ConnectionRequest) 메서드를 호출하여 현재는 전화를 걸 수 없다는 것을 앱에 알립니다. 앱은 전화를 걸 수 없다는 것을 사용자에게 알려야 합니다.
  5. 앱에서 발신 전화를 걸 수 있다면 텔레콤 하위 시스템은 onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest) 메서드를 호출합니다. 앱은 새 발신 전화를 나타내는 Connection 클래스의 인스턴스를 반환해야 합니다. 연결 시 설정해야 하는 속성에 관한 자세한 내용은 연결 서비스 구현을 참조하세요.
  6. 발신 전화가 연결되면 setActive() 메서드를 호출하여 통화가 활성화되었다는 것을 텔레콤 하위 시스템에 알립니다.

통화 종료

통화를 종료하려면 다음 단계를 따르세요.

  1. 사용자가 통화를 종료하면 LOCAL을 매개변수로 전달하여 setDisconnected(DisconnectCause)를 호출하고 상대방이 통화를 종료하면 REMOTE를 매개변수로 전달합니다.
  2. destroy() 메서드를 호출합니다.

통화 제약

사용자에게 일관되고 간편한 통화 환경을 보장하기 위해 텔레콤 프레임워크는 기기에서 통화를 관리하기 위한 몇 가지 제약을 적용합니다. 예를 들어 사용자가 자체 관리 ConnectionService API를 구현하는 두 가지 통화 앱인 FooTalk 및 BarTalk을 설치했다고 생각해 보세요. 이 경우 다음과 같은 제약이 적용됩니다.

  • API 레벨 27 이하에서 실행되는 기기에서는 한번에 하나의 앱만 진행 중인 통화를 유지할 수 있습니다. 이 제약은 사용자가 FooTalk 앱을 사용하여 통화를 진행하는 동안 BarTalk 앱은 새로운 통화를 시작하거나 전화를 받을 수 없다는 것을 의미합니다.

    API 레벨 28 이상에서 실행되는 기기에서는 FooTalk 및 BarTalk 앱 모두에서 CAPABILITY_SUPPORT_HOLDCAPABILITY_HOLD 권한을 선언하면 사용자가 앱 간을 전환하며 또 다른 통화를 시작하거나 전화를 받아 진행 중인 통화를 둘 이상 유지할 수 있습니다.

  • 사용자가 일반 관리 통화(예: 기본 제공 전화 또는 다이얼러 앱 사용)를 사용 중이라면 통화 앱에서 시작된 통화를 사용할 수 없습니다. 즉, 사용자가 이동통신사를 통해 일반 통화를 하는 중에 FooTalk 또는 BarTalk 통화를 동시에 할 수 없습니다.

  • 사용자가 긴급 전화를 걸면 텔레콤 하위 시스템은 앱의 통화 연결을 끊습니다.

  • 사용자가 긴급 전화를 하는 동안에는 앱에서 전화를 받거나 걸 수 없습니다.

  • 앱에 수신 전화가 걸려올 때 다른 통화 앱에서 진행 중인 통화가 있는데 수신 전화를 받으면 다른 앱에서 진행 중인 통화는 종료됩니다. 앱에 일반적인 수신 전화 사용자 인터페이스가 표시되어서는 안 됩니다. 텔레콤 프레임워크는 수신 전화 사용자 인터페이스를 표시하여 새로운 전화를 받으면 진행 중인 통화가 종료됨을 사용자에게 알립니다. 즉, 사용자가 FooTalk 통화 중인데 BarTalk 앱에 수신 전화가 걸려올 경우 텔레콤 프레임워크는 사용자에게 새로운 BarTalk 수신 전화가 왔으며 이를 받으면 기존 FooTalk 통화가 종료된다고 알려줍니다.

기본 전화 앱으로 설정

기본 다이얼러/전화 앱은 기기가 있는 동안 통화 중 사용자 인터페이스를 제공하는 앱입니다. 통화 중 또한 사용자가 통화를 시작하고 통화 기록을 확인할 수 있는 수단을 제공합니다. 확인할 수 있습니다. 기기는 시스템에서 제공하는 기본 다이얼러/전화 앱과 번들로 제공됩니다. 사용자 시스템 앱에서 이 역할을 맡을 단일 앱을 선택할 수 있습니다. 앱이 이 역할은 RoleManager를 사용하여 RoleManager.ROLE_DIALER 역할

기본 전화 앱은 기기가 통화 중일 때 사용자 인터페이스를 제공하며, 기기가 다음과 같은 상태인 경우 운전 모드가 아닌 것 (예: UiModeManager#getCurrentModeType()Configuration.UI_MODE_TYPE_CAR).

RoleManager.ROLE_DIALER 역할을 충족하려면 앱이 다음 기준을 충족해야 합니다. 요구사항:

  • Intent#ACTION_DIAL 인텐트를 처리해야 합니다. 즉, 앱에서 다이얼패드 UI가 있어야 합니다.
  • InCallService API를 완전히 구현하고 수신 전화를 모두 제공해야 합니다. 진행 중인 통화 UI도 있습니다.

참고: RoleManager.ROLE_DIALER를 채우는 앱이 바인딩 중에 null InCallService인 경우 텔레콤 프레임워크가 자동으로 중단됩니다. 기기에 미리 로드된 다이얼러 앱을 다시 사용하는 단계로 돌아가게 됩니다. 시스템에서 미리 로드된 다이얼러 앱을 사용하여 계속 통화를 하고 있다고 알려왔습니다. 내 앱은 null 결합을 반환해서는 안 됩니다. 이렇게 하면 RoleManager.ROLE_DIALER 요구사항을 충족해야 합니다.

참고: 앱이 RoleManager.ROLE_DIALER를 채우고 더 이상 이 역할의 요구사항을 충족하지 못하게 하므로 RoleManager님이 자동으로 이 역할에서 앱을 삭제하고 앱을 종료합니다. 있습니다. 예를 들어 PackageManager.setComponentEnabledSetting(ComponentName, int, int)부터 앱이 매니페스트에 선언한 InCallService를 프로그래매틱 방식으로 사용 중지합니다. 더 이상 RoleManager.ROLE_DIALER입니다.

미리 로드된 다이얼러는 사용자가 긴급 전화를 걸 때 항상 사용됩니다. 앱이 RoleManager.ROLE_DIALER 역할을 수행합니다. 최적의 결정을 내리려면 긴급 전화를 걸 때 기본 다이얼러가 항상 전화를 걸려면 TelecomManager.placeCall(Uri, Bundle)( 긴급 전화). 이렇게 하면 플랫폼이 요청의 출처임을 확인할 수 있습니다. 기본 다이얼러를 사용합니다. 미리 로드되지 않은 다이얼러 앱이 Intent#ACTION_CALL를 사용하여 긴급 전화인 경우 Intent#ACTION_DIAL를 사용하여 미리 로드된 다이얼러 앱으로 전달됩니다. 확인을 위해 이는 차선의 사용자 환경입니다.

다음은 InCallService의 매니페스트 등록 예입니다. 메타데이터 TelecomManager#METADATA_IN_CALL_SERVICE_UI는 이 특정 InCallService 구현은 내장된 통화 내 UI를 대체하려고 합니다. 메타데이터 TelecomManager#METADATA_IN_CALL_SERVICE_RINGINGInCallService에서 전화가 올 때 벨소리를 재생합니다. 자세한 내용은 수신 전화 표시에 관한 자세한 내용은 아래를 참고하세요. 벨소리를 재생하는 UI 및 벨소리입니다.

 <service android:name="your.package.YourInCallServiceImplementation"
          android:permission="android.permission.BIND_INCALL_SERVICE"
          android:exported="true">
      <meta-data android:name="android.telecom.IN_CALL_SERVICE_UI" android:value="true" />
      <meta-data android:name="android.telecom.IN_CALL_SERVICE_RINGING"
          android:value="true" />
      <intent-filter>
          <action android:name="android.telecom.InCallService"/>
      </intent-filter>
 </service>

참고: InCallServiceandroid:exported="false" 그렇게 하면 구현에 바인딩하지 못할 수 있습니다. 하는 것입니다.

InCallService API를 구현하는 것 외에도 다음 위치에서 활동을 선언해야 합니다. Intent#ACTION_DIAL 인텐트를 처리하는 매니페스트를 빌드합니다. 아래 예는 방법은 다음과 같습니다.

 <activity android:name="your.package.YourDialerActivity"
           android:label="@string/yourDialerActivityLabel">
      <intent-filter>
           <action android:name="android.intent.action.DIAL" />
           <category android:name="android.intent.category.DEFAULT" />
      </intent-filter>
      <intent-filter>
           <action android:name="android.intent.action.DIAL" />
           <category android:name="android.intent.category.DEFAULT" />
           <data android:scheme="tel" />
      </intent-filter>
 </activity>

사용자가 애플리케이션을 설치하고 처음으로 실행하는 경우 RoleManager: 사용자에게 앱에서 다음 중 무엇을 원하는지 묻는 메시지 표시 새로운 기본 전화 앱이 될 것입니다.

아래 코드는 앱이 기본 전화/다이얼러 앱이 되도록 요청하는 방법을 보여줍니다.

 private static final int REQUEST_ID = 1;

 public void requestRole() {
     RoleManager roleManager = (RoleManager) getSystemService(ROLE_SERVICE);
     Intent intent = roleManager.createRequestRoleIntent(RoleManager.ROLE_DIALER);
     startActivityForResult(intent, REQUEST_ID);
 }

 public void onActivityResult(int requestCode, int resultCode, Intent data) {
     if (requestCode == REQUEST_ID) {
         if (resultCode == android.app.Activity.RESULT_OK) {
             // Your app is now the default dialer app
         } else {
             // Your app is not the default dialer app
         }
     }
 }

웨어러블 기기의 InCallService 액세스

<ph type="x-smartling-placeholder">
    </ph> 앱이 서드 파티 호환 앱이고 InCallService API에 액세스하려는 경우 수행할 수 있는 작업은 다음과 같습니다.

    1. 매니페스트에서 MANAGE_ONGOING_CALLS 권한 선언
    2. 다음을 통해 실제 웨어러블 기기와 연결 CompanionDeviceManager API를 사용할 수 있습니다. 다음을 참조하세요. https://developer.android.com/guide/topics/connectivity/Companion-device-pairing
    3. BIND_INCALL_SERVICE 권한으로 이 InCallService 구현

수신 전화 알림 표시

앱이 InCallService#onCallAdded(Call)를 통해 새로운 수신 전화를 받으면 다음과 같이 처리됩니다. 수신 전화의 수신 전화 UI를 표시합니다. 이 작업은 NotificationManager API를 사용하여 새 수신 전화 알림을 게시합니다.

앱이 메타데이터 TelecomManager#METADATA_IN_CALL_SERVICE_RINGING를 선언하는 경우 수신 전화의 벨소리를 재생합니다. 앱에서는 NotificationChannel: 원하는 벨소리를 지정합니다. 예를 들면 다음과 같습니다.

 NotificationChannel channel = new NotificationChannel(YOUR_CHANNEL_ID, "Incoming Calls",
          NotificationManager.IMPORTANCE_MAX);
 // other channel setup stuff goes here.

 // We'll use the default system ringtone for our incoming call notification channel.  You can
 // use your own audio resource here.
 Uri ringtoneUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE);
 channel.setSound(ringtoneUri, new AudioAttributes.Builder()
          // Setting the AudioAttributes is important as it identifies the purpose of your
          // notification sound.
          .setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE)
          .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
      .build());

 NotificationManager mgr = getSystemService(NotificationManager.class);
 mgr.createNotificationChannel(channel);

앱이 새로운 수신 전화를 받으면 Notification를 만듭니다. 수신 전화 알림 채널과 연결합니다. 포드의 전체 화면을 실행하는 알림의 PendingIntent 수신 전화 UI 알림 관리자 프레임워크는 알림을 사용자가 휴대전화를 활발하게 사용하는 경우 표시되는 헤드업 알림 사용자가 전체 화면 수신 전화 UI가 대신 사용됩니다. 예를 들면 다음과 같습니다.

 // Create an intent which triggers your fullscreen incoming call user interface.
 Intent intent = new Intent(Intent.ACTION_MAIN, null);
 intent.setFlags(Intent.FLAG_ACTIVITY_NO_USER_ACTION | Intent.FLAG_ACTIVITY_NEW_TASK);
 intent.setClass(context, YourIncomingCallActivity.class);
 PendingIntent pendingIntent = PendingIntent.getActivity(context, 1, intent, PendingIntent.FLAG_MUTABLE_UNAUDITED);
 // Build the notification as an ongoing high priority item; this ensures it will show as
 // a heads up notification which slides down over top of the current content.
 final Notification.Builder builder = new Notification.Builder(context);
 builder.setOngoing(true);
 builder.setPriority(Notification.PRIORITY_HIGH);
 // Set notification content intent to take user to the fullscreen UI if user taps on the
 // notification body.
 builder.setContentIntent(pendingIntent);
 // Set full screen intent to trigger display of the fullscreen UI when the notification
 // manager deems it appropriate.
 builder.setFullScreenIntent(pendingIntent, true);
 // Setup notification content.
 builder.setSmallIcon( yourIconResourceId );
 builder.setContentTitle("Your notification title");
 builder.setContentText("Your notification content.");
 // Use builder.addAction(..) to add buttons to answer or reject the call.
 NotificationManager notificationManager = mContext.getSystemService(
     NotificationManager.class);
 notificationManager.notify(YOUR_CHANNEL_ID, YOUR_TAG, YOUR_ID, builder.build());
```