diff --git a/matrix-sdk-android/src/main/res/values/strings.xml b/matrix-sdk-android/src/main/res/values/strings.xml index 3cd7674253..a34c3a1f9f 100644 --- a/matrix-sdk-android/src/main/res/values/strings.xml +++ b/matrix-sdk-android/src/main/res/values/strings.xml @@ -362,4 +362,7 @@ %s is requesting to verify your key, but your client does not support in-chat key verification. You will need to use legacy key verification to verify keys. + Accept + Reject + diff --git a/vector/src/main/AndroidManifest.xml b/vector/src/main/AndroidManifest.xml index 1cd522337e..76281afe0b 100644 --- a/vector/src/main/AndroidManifest.xml +++ b/vector/src/main/AndroidManifest.xml @@ -12,11 +12,13 @@ - - + + + + @@ -195,15 +197,24 @@ android:name=".core.services.VectorSyncService" android:exported="false" /> - + + + + = Build.VERSION_CODES.M) { ContextCompat.getSystemService(context, TelecomManager::class.java)?.let { telecomManager -> phoneAccountHandle?.let { phoneAccountHandle -> @@ -372,6 +376,7 @@ class WebRtcPeerConnectionManager @Inject constructor( } } } + */ } override fun onCallAnswerReceived(callAnswerContent: CallAnswerContent) { diff --git a/vector/src/main/java/im/vector/riotx/features/call/service/CallHeadsUpActionReceiver.kt b/vector/src/main/java/im/vector/riotx/features/call/service/CallHeadsUpActionReceiver.kt new file mode 100644 index 0000000000..99f163d42d --- /dev/null +++ b/vector/src/main/java/im/vector/riotx/features/call/service/CallHeadsUpActionReceiver.kt @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2020 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.riotx.features.call.service + +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import timber.log.Timber + +class CallHeadsUpActionReceiver : BroadcastReceiver() { + + override fun onReceive(context: Context, intent: Intent?) { + when (intent?.getIntExtra(CallHeadsUpService.EXTRA_CALL_ACTION_KEY, 0)) { + CallHeadsUpService.CALL_ACTION_ANSWER -> onCallAnswerClicked() + CallHeadsUpService.CALL_ACTION_REJECT -> onCallRejectClicked() + } + + context.sendBroadcast(Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)) + context.stopService(Intent(context, CallHeadsUpService::class.java)) + } + + private fun onCallRejectClicked() { + Timber.d("onCallRejectClicked") + } + + private fun onCallAnswerClicked() { + Timber.d("onCallAnswerClicked") + } +} diff --git a/vector/src/main/java/im/vector/riotx/features/call/service/CallHeadsUpService.kt b/vector/src/main/java/im/vector/riotx/features/call/service/CallHeadsUpService.kt new file mode 100644 index 0000000000..b8fa16d6ad --- /dev/null +++ b/vector/src/main/java/im/vector/riotx/features/call/service/CallHeadsUpService.kt @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2020 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.riotx.features.call.service + +import android.app.NotificationChannel +import android.app.NotificationManager +import android.app.PendingIntent +import android.app.Service +import android.content.Context +import android.content.Intent +import android.media.AudioAttributes +import android.media.AudioManager +import android.net.Uri +import android.os.Binder +import android.os.Build +import android.os.IBinder +import androidx.core.app.NotificationCompat +import im.vector.riotx.R + +class CallHeadsUpService : Service() { + + private val CHANNEL_ID = "CallChannel" + private val CHANNEL_NAME = "Call Channel" + private val CHANNEL_DESCRIPTION = "Call Notifications" + + private val binder: IBinder = CallHeadsUpServiceBinder() + + override fun onBind(intent: Intent): IBinder? { + return binder + } + + override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { + //val callHeadsUpServiceArgs: CallHeadsUpServiceArgs? = intent?.extras?.getParcelable(EXTRA_CALL_HEADS_UP_SERVICE_PARAMS) + + val answerCallActionReceiver = Intent(applicationContext, CallHeadsUpActionReceiver::class.java).apply { + putExtra(EXTRA_CALL_ACTION_KEY, CALL_ACTION_ANSWER) + } + val rejectCallActionReceiver = Intent(applicationContext, CallHeadsUpActionReceiver::class.java).apply { + putExtra(EXTRA_CALL_ACTION_KEY, CALL_ACTION_REJECT) + } + + val answerCallPendingIntent = PendingIntent.getBroadcast(applicationContext, CALL_ACTION_ANSWER, answerCallActionReceiver, PendingIntent.FLAG_UPDATE_CURRENT) + val rejectCallPendingIntent = PendingIntent.getBroadcast(applicationContext, CALL_ACTION_REJECT, rejectCallActionReceiver, PendingIntent.FLAG_UPDATE_CURRENT) + + createNotificationChannel() + + val notification = NotificationCompat + .Builder(applicationContext, CHANNEL_ID) + .setContentTitle("Title") + .setContentText("Content") + .setSmallIcon(R.drawable.ic_call_incoming) + .setPriority(NotificationCompat.PRIORITY_HIGH) + .setCategory(NotificationCompat.CATEGORY_CALL) + .addAction(R.drawable.ic_call_incoming, getString(R.string.call_notification_answer), answerCallPendingIntent) + .addAction(R.drawable.ic_call_incoming, getString(R.string.call_notification_reject), rejectCallPendingIntent) + .setAutoCancel(true) + .setSound(Uri.parse("android.resource://" + applicationContext.packageName + "/ring.ogg")) + .setFullScreenIntent(answerCallPendingIntent, true) + .build() + + startForeground(NOTIFICATION_ID, notification) + + return START_STICKY + } + + private fun createNotificationChannel() { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return + + val channel = NotificationChannel(CHANNEL_ID, CHANNEL_NAME, NotificationManager.IMPORTANCE_HIGH).apply { + description = CHANNEL_DESCRIPTION + setSound( + Uri.parse("android.resource://" + applicationContext.packageName + "/ring.ogg"), + AudioAttributes + .Builder() + .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION) + .setLegacyStreamType(AudioManager.STREAM_RING) + .build() + ) + } + applicationContext.getSystemService(NotificationManager::class.java)?.createNotificationChannel(channel) + } + + inner class CallHeadsUpServiceBinder : Binder() { + + fun getService() = this@CallHeadsUpService + } + + companion object { + private const val EXTRA_CALL_HEADS_UP_SERVICE_PARAMS = "EXTRA_CALL_PARAMS" + + const val EXTRA_CALL_ACTION_KEY = "EXTRA_CALL_ACTION_KEY" + const val CALL_ACTION_ANSWER = 100 + const val CALL_ACTION_REJECT = 101 + + private const val NOTIFICATION_ID = 999 + + fun newInstance(context: Context, callerDisplayName: String, isIncomingCall: Boolean, isVideoCall: Boolean): Intent { + val args = CallHeadsUpServiceArgs(callerDisplayName, isIncomingCall, isVideoCall) + return Intent(context, CallHeadsUpService::class.java).apply { + putExtra(EXTRA_CALL_HEADS_UP_SERVICE_PARAMS, args) + } + } + } +} diff --git a/vector/src/main/java/im/vector/riotx/features/call/service/CallHeadsUpServiceArgs.kt b/vector/src/main/java/im/vector/riotx/features/call/service/CallHeadsUpServiceArgs.kt new file mode 100644 index 0000000000..9769724944 --- /dev/null +++ b/vector/src/main/java/im/vector/riotx/features/call/service/CallHeadsUpServiceArgs.kt @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2020 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.riotx.features.call.service + +import android.os.Parcelable +import kotlinx.android.parcel.Parcelize + +@Parcelize +data class CallHeadsUpServiceArgs( + val callerDisplayName: String, + val isIncomingCall: Boolean, + val isVideoCall: Boolean +) : Parcelable diff --git a/vector/src/main/java/im/vector/riotx/features/call/CallConnection.kt b/vector/src/main/java/im/vector/riotx/features/call/telecom/CallConnection.kt similarity index 94% rename from vector/src/main/java/im/vector/riotx/features/call/CallConnection.kt rename to vector/src/main/java/im/vector/riotx/features/call/telecom/CallConnection.kt index 9523b4ebdd..27bdf24570 100644 --- a/vector/src/main/java/im/vector/riotx/features/call/CallConnection.kt +++ b/vector/src/main/java/im/vector/riotx/features/call/telecom/CallConnection.kt @@ -14,13 +14,16 @@ * limitations under the License. */ -package im.vector.riotx.features.call +package im.vector.riotx.features.call.telecom import android.content.Context import android.os.Build import android.telecom.Connection import android.telecom.DisconnectCause import androidx.annotation.RequiresApi +import im.vector.riotx.features.call.VectorCallViewActions +import im.vector.riotx.features.call.VectorCallViewModel +import im.vector.riotx.features.call.WebRtcPeerConnectionManager import org.webrtc.Camera1Enumerator import org.webrtc.Camera2Enumerator import org.webrtc.IceCandidate diff --git a/vector/src/main/java/im/vector/riotx/features/call/VectorConnectionService.kt b/vector/src/main/java/im/vector/riotx/features/call/telecom/VectorConnectionService.kt similarity index 99% rename from vector/src/main/java/im/vector/riotx/features/call/VectorConnectionService.kt rename to vector/src/main/java/im/vector/riotx/features/call/telecom/VectorConnectionService.kt index fed93c9faa..8185c9fc49 100644 --- a/vector/src/main/java/im/vector/riotx/features/call/VectorConnectionService.kt +++ b/vector/src/main/java/im/vector/riotx/features/call/telecom/VectorConnectionService.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package im.vector.riotx.features.call +package im.vector.riotx.features.call.telecom import android.content.ComponentName import android.content.Intent diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt index 2b743ed940..efa045ddd2 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt @@ -127,7 +127,7 @@ import im.vector.riotx.features.attachments.ContactAttachment import im.vector.riotx.features.attachments.preview.AttachmentsPreviewActivity import im.vector.riotx.features.attachments.preview.AttachmentsPreviewArgs import im.vector.riotx.features.attachments.toGroupedContentAttachmentData -import im.vector.riotx.features.call.VectorCallActivity +import im.vector.riotx.features.call.service.CallHeadsUpService import im.vector.riotx.features.command.Command import im.vector.riotx.features.crypto.keysbackup.restore.KeysBackupRestoreActivity import im.vector.riotx.features.crypto.util.toImageRes @@ -485,9 +485,13 @@ class RoomDetailFragment @Inject constructor( return true } if (item.itemId == R.id.voip_call) { + /* VectorCallActivity.newIntent(requireContext(), roomDetailArgs.roomId).let { startActivity(it) } + */ + val callHeadsUpServiceIntent = Intent(requireContext(), CallHeadsUpService::class.java) + ContextCompat.startForegroundService(requireContext(), callHeadsUpServiceIntent) return true } return super.onOptionsItemSelected(item) diff --git a/vector/src/main/res/drawable/ic_call_incoming.xml b/vector/src/main/res/drawable/ic_call_incoming.xml new file mode 100644 index 0000000000..0f4e2d1d89 --- /dev/null +++ b/vector/src/main/res/drawable/ic_call_incoming.xml @@ -0,0 +1,5 @@ + + +