| /* |
| * Copyright 2023 The Android Open Source Project |
| * |
| * 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 androidx.core.telecom.internal.utils |
| |
| import android.os.Build |
| import android.os.RemoteException |
| import android.util.Log |
| import androidx.annotation.IntDef |
| import androidx.annotation.RequiresApi |
| import androidx.annotation.RestrictTo |
| import androidx.core.telecom.CallsManager |
| import androidx.core.telecom.extensions.voip.VoipExtensionManager |
| import androidx.core.telecom.util.ExperimentalAppActions |
| |
| @ExperimentalAppActions |
| @RequiresApi(Build.VERSION_CODES.O) |
| internal class CapabilityExchangeUtils { |
| companion object { |
| /** |
| * Timeouts to help facilitate capability exchange negotiation between ICS and VOIP app. |
| */ |
| internal const val CAPABILITY_EXCHANGE_TIMEOUT = 1000L |
| internal const val CAPABILITY_NEGOTIATION_COROUTINE_TIMEOUT = 3000L |
| internal const val ACTION_RESULT_RESPONSE_TIMEOUT = 1000L |
| |
| /** |
| * Constants used to denote the types of error codes that can be returned from the provided |
| * action callbacks. Used by the VOIP side. |
| */ |
| @Target(AnnotationTarget.TYPE) |
| @RestrictTo(RestrictTo.Scope.LIBRARY) |
| @Retention(AnnotationRetention.SOURCE) |
| @IntDef(VOIP_SERVER_ERROR, VOIP_ACTION_NOT_SUPPORTED_ERROR, PARTICIPANT_NOT_FOUND_ERROR) |
| annotation class ExtensionCallbackErrorCode |
| |
| internal const val VOIP_SERVER_ERROR = 1 |
| internal const val VOIP_ACTION_NOT_SUPPORTED_ERROR = 2 |
| internal const val PARTICIPANT_NOT_FOUND_ERROR = 3 |
| |
| // Id to be used to represent a null Participant. This would be used for sending updates |
| // to the ICS when the active participant is not defined. |
| internal const val NULL_PARTICIPANT_ID = -1 |
| |
| // Logging utils |
| internal const val PARTICIPANT_TAG = "participants" |
| internal const val CALL_DETAILS_TAG = "call details" |
| |
| /** |
| * Static helper to sanitize the passed in actions to make sure no duplicates are found and |
| * only actions supported by the Participant are defined. |
| */ |
| internal fun preprocessSupportedActions( |
| featureId: @CallsManager.Companion.ExtensionType Int, |
| rawActions: IntArray |
| ): MutableSet<Int> { |
| val processedActions: |
| MutableSet<@CallsManager.Companion.ExtensionSupportedActions Int> = mutableSetOf() |
| // Track currently added actions so we don't end accounting for duplicates (user error). |
| for (action in rawActions) { |
| VoipExtensionManager.EXTENSION_SUPPORTED_ACTIONS_MAPPING[featureId]?.let { |
| if (it.contains(action) && !processedActions.contains(action)) { |
| processedActions.add(action) |
| } |
| } |
| } |
| return processedActions |
| } |
| |
| internal fun handleVoipSideUpdateExceptions( |
| logTag: String, |
| prefixTag: String, |
| extensionMsg: String, |
| e: Exception |
| ) { |
| when (e) { |
| is RemoteException -> { |
| Log.w(logTag, "$prefixTag: Remote exception occurred while sending " + |
| "$extensionMsg updates to the ICS.", e) |
| } |
| else -> { |
| Log.w(logTag, "$prefixTag: Exception occurred while sending " + |
| "$extensionMsg updates to the ICS.", e) |
| } |
| } |
| } |
| } |
| } |