web-dev-qa-db-ja.com

Android ConnectionServiceの着信

Androidに_iOS callkit_動作を実装しようとしています。 Firebaseからプッシュ通知を受信して​​いますが、「着信」画面をユーザーに表示したいのですが。そのためには、_Android.telecom_パッケージおよびその他のクラスのConnectionServiceを使用します。

これが私のコールマネージャークラスです。

_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 UIを表示します-onShowIncomingCallUi()メソッドでいくつかのアクションを実行する必要があります。ただし、システムから呼び出されることはありません。

どうすれば修正できますか?

8
WorieN

テストアプリとAndroid PixelをPixel 2 XLで実行しているPieを使用して動作させることができました。

私のテストから重要な部分は、以下を確認することです。

  • そのConnection.PROPERTY_SELF_MANAGEDが接続に設定されています。 API 26以上が必要です。
  • 電話アカウントを登録する必要があります。
  • 電話アカウントを登録するときは、ケーパビリティでPhoneAccount.CAPABILITY_SELF_MANAGEDを設定する必要があります。それが私が設定した唯一の機能です。他の機能を設定すると、例外がスローされました。
  • 最後に、AndroidManifest.xmlでこれら2つの権限が設定されていることを確認する必要があります。 Android.permission.MANAGE_OWN_CALLSおよびAndroid.permission.READ_CALL_LOG

したがって、マニフェストをチェックして、権限があることと、機能が正しく設定されていることを確認します。上記のコードで他のすべてが正しく設定されているようです。

お役に立てば幸いです。

3
TALE