Android ConnectionService входящие звонки - PullRequest
0 голосов
/ 05 ноября 2018

Я пытаюсь реализовать поведение iOS callkit на Android. Я получаю push-уведомление от firebase и хочу показать пользователю экран «Входящий звонок». Для этого я использую ConnectionService из android.telecom пакета и другие классы.

Вот мой класс менеджера звонков:

class CallManager(context: Context) {
val telecomManager: TelecomManager
var phoneAccountHandle:PhoneAccountHandle
var context:Context
val number = "3924823202"
init {
    telecomManager = context.getSystemService(Context.TELECOM_SERVICE) as TelecomManager
    this.context = context
    val componentName =  ComponentName(this.context, CallConnectionService::class.java)
    phoneAccountHandle = PhoneAccountHandle(componentName, "Admin")
    val phoneAccount = PhoneAccount.builder(phoneAccountHandle, "Admin").setCapabilities(PhoneAccount.CAPABILITY_SELF_MANAGED).build()


    telecomManager.registerPhoneAccount(phoneAccount)
    val intent = Intent()
    intent.component = ComponentName("com.android.server.telecom", "com.android.server.telecom.settings.EnableAccountPreferenceActivity")
    intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP

}


@TargetApi(Build.VERSION_CODES.M)
fun startOutgoingCall() {
    val extras = Bundle()
    extras.putBoolean(TelecomManager.EXTRA_START_CALL_WITH_SPEAKERPHONE, true)

    val manager = context.getSystemService(TELECOM_SERVICE) as TelecomManager
    val phoneAccountHandle = PhoneAccountHandle(ComponentName(context.packageName, CallConnectionService::class.java!!.getName()), "estosConnectionServiceId")
    val test = Bundle()
    test.putParcelable(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, phoneAccountHandle)
    test.putInt(TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE, VideoProfile.STATE_BIDIRECTIONAL)
    test.putParcelable(TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS, extras)
    try {
        manager.placeCall(Uri.parse("tel:$number"), test)
    } catch (e:SecurityException){
        e.printStackTrace()
    }
}

@TargetApi(Build.VERSION_CODES.M)
fun  startIncomingCall(){
    if (this.context.checkSelfPermission(Manifest.permission.MANAGE_OWN_CALLS) == PackageManager.PERMISSION_GRANTED) {
        val extras = Bundle()
        val uri = Uri.fromParts(PhoneAccount.SCHEME_TEL, number, null)
        extras.putParcelable(TelecomManager.EXTRA_INCOMING_CALL_ADDRESS, uri)
        extras.putParcelable(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, phoneAccountHandle)
        extras.putBoolean(TelecomManager.EXTRA_START_CALL_WITH_SPEAKERPHONE, true)
        val isCallPermitted = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            telecomManager.isIncomingCallPermitted(phoneAccountHandle)
        } else {
           true
        }
        Log.i("CallManager", "is incoming call permited = $isCallPermitted")
        telecomManager.addNewIncomingCall(phoneAccountHandle, extras)
    }
}

}

И моя пользовательская ConnectionService реализация:

class CallConnectionService : ConnectionService() {
override fun onCreateOutgoingConnection(connectionManagerPhoneAccount: PhoneAccountHandle?, request: ConnectionRequest?): Connection {
    Log.i("CallConnectionService", "onCreateOutgoingConnection")
    val conn = CallConnection(applicationContext)
    conn.setAddress(request!!.address, PRESENTATION_ALLOWED)
    conn.setInitializing()
    conn.videoProvider = MyVideoProvider()
    conn.setActive()
    return conn
}

override fun onCreateOutgoingConnectionFailed(connectionManagerPhoneAccount: PhoneAccountHandle?, request: ConnectionRequest?) {
    super.onCreateOutgoingConnectionFailed(connectionManagerPhoneAccount, request)
    Log.i("CallConnectionService", "create outgoing call failed")
}

override fun onCreateIncomingConnection(connectionManagerPhoneAccount: PhoneAccountHandle?, request: ConnectionRequest?): Connection {
    Log.i("CallConnectionService", "onCreateIncomingConnection")
    val conn = CallConnection(applicationContext)
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
        conn.connectionProperties = Connection.PROPERTY_SELF_MANAGED
    }
    conn.setCallerDisplayName("test call", TelecomManager.PRESENTATION_ALLOWED)
    conn.setAddress(request!!.address, PRESENTATION_ALLOWED)
    conn.setInitializing()
    conn.videoProvider = MyVideoProvider()
    conn.setActive()

    return conn
}

override fun onCreateIncomingConnectionFailed(connectionManagerPhoneAccount: PhoneAccountHandle?, request: ConnectionRequest?) {
    super.onCreateIncomingConnectionFailed(connectionManagerPhoneAccount, request)
    Log.i("CallConnectionService", "create outgoing call failed ")
}

}

И моя реализация подключения выглядит так:

    class CallConnection(ctx:Context) : Connection() {

    var ctx:Context = ctx
    val TAG = "CallConnection"

    override fun onShowIncomingCallUi() {
//        super.onShowIncomingCallUi()
        Log.i(TAG, "onShowIncomingCallUi")
        val intent = Intent(Intent.ACTION_MAIN, null)
        intent.flags = Intent.FLAG_ACTIVITY_NO_USER_ACTION or Intent.FLAG_ACTIVITY_NEW_TASK
        intent.setClass(ctx, IncomingCallActivity::class.java!!)
        val pendingIntent = PendingIntent.getActivity(ctx, 1, intent, 0)
        val builder = Notification.Builder(ctx)
        builder.setOngoing(true)
        builder.setPriority(Notification.PRIORITY_HIGH)

        // Set notification content intent to take user to 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(R.mipmap.ic_launcher)
        builder.setContentTitle("Your notification title")
        builder.setContentText("Your notification content.")

        // Use builder.addAction(..) to add buttons to answer or reject the call.

        val notificationManager = ctx.getSystemService(
                NotificationManager::class.java)

        notificationManager.notify("Call Notification", 37, builder.build())
    }

    override fun onCallAudioStateChanged(state: CallAudioState?) {
        Log.i(TAG, "onCallAudioStateChanged")
    }

    override fun onAnswer() {
        Log.i(TAG, "onAnswer")
    }

    override fun onDisconnect() {
        Log.i(TAG, "onDisconnect")
    }

    override fun onHold() {
        Log.i(TAG, "onHold")
    }

    override fun onUnhold() {
        Log.i(TAG, "onUnhold")
    }

    override fun onReject() {
        Log.i(TAG, "onReject")
    }
}

Согласно документу для отображения пользовательского пользовательского интерфейса входящего calcustomon - я должен выполнить некоторые действия в методе onShowIncomingCallUi(). Но это просто не вызывается системой.

Как я могу это исправить?

1 Ответ

0 голосов
/ 18 января 2019

Мне удалось заставить его работать с помощью тестового приложения и Android Pie, работающего на Pixel 2 XL.

По результатам моих испытаний важны следующие детали:

  • То, что Connection.PROPERTY_SELF_MANAGED установлено для соединения. Требуется минимум API 26.
  • Вы должны зарегистрировать свой телефонный счет.
  • Вы должны установить PhoneAccount.CAPABILITY_SELF_MANAGED в своих возможностях при регистрации учетной записи телефона. Это единственная возможность, которую я установил. Установка других возможностей вызвала исключение.
  • Наконец, вам нужно убедиться, что у вас есть эти два разрешения, установленные в AndroidManifest.xml. android.permission.MANAGE_OWN_CALLS и android.permission.READ_CALL_LOG

Итак, я бы проверил ваш манифест, чтобы убедиться, что у вас есть разрешения, а также чтобы убедиться, что возможности установлены правильно. Похоже, что все остальное было правильно установлено в вашем коде выше.

Надеюсь, это поможет!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...