1 /* 2 * Copyright 2024 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package androidx.core.telecom.extensions 18 19 import android.net.Uri 20 import android.telecom.Call 21 import androidx.core.telecom.util.ExperimentalAppActions 22 23 /** 24 * Provides a scope where extensions can be first initialized and next managed for a [Call] once 25 * [onConnected] is called. 26 * 27 * The following extension is supported on a call: 28 * - [addParticipantExtension] - Show the user more information about the [Participant]s in the 29 * call. 30 * 31 * ``` 32 * class InCallServiceImpl : InCallServiceCompat() { 33 * ... 34 * override fun onCallAdded(call: Call) { 35 * lifecycleScope.launch { 36 * connectExtensions(context, call) { 37 * // Initialize extensions 38 * onConnected { call -> 39 * // change call states & listen for extension updates/send extension actions 40 * } 41 * } 42 * // Once the call is destroyed, control flow will resume again 43 * } 44 * } 45 * ... 46 * } 47 * ``` 48 */ 49 @ExperimentalAppActions 50 public interface CallExtensionScope { 51 52 /** 53 * Called when the [Call] extensions have been successfully set up and are ready to be used. 54 * 55 * @param block Called when the [Call] and initialized extensions are ready to be used. 56 */ onConnectednull57 public fun onConnected(block: suspend (Call) -> Unit) 58 59 /** 60 * Add support for this remote surface to display information related to the [Participant]s in 61 * this call. 62 * 63 * ``` 64 * connectExtensions(call) { 65 * val participantExtension = addParticipantExtension( 66 * // consume participant changed events 67 * ) 68 * onConnected { 69 * // extensions have been negotiated and actions are ready to be used 70 * } 71 * } 72 * ``` 73 * 74 * @param onActiveParticipantChanged Called with the active [Participant] in the call has 75 * changed. If this method is called with a `null` [Participant], there is no active 76 * [Participant]. The active [Participant] in the call is the [Participant] that should take 77 * focus and be either more prominent on the screen or otherwise featured as active in UI. For 78 * example, this could be the [Participant] that is actively talking or presenting. 79 * @param onParticipantsUpdated Called when the [Participant]s in the [Call] have changed and 80 * the UI should be updated. 81 * @return The interface that is used to set up additional actions for this extension. 82 */ 83 public fun addParticipantExtension( 84 onActiveParticipantChanged: suspend (Participant?) -> Unit, 85 onParticipantsUpdated: suspend (Set<Participant>) -> Unit 86 ): ParticipantExtensionRemote 87 88 /** 89 * Add support for this remote surface to display meeting summary information for this call. 90 * 91 * This function establishes a connection with a remote service that provides meeting summary 92 * information, such as the current speaker and the number of participants. The extension will 93 * provide updates via the provided callbacks: 94 * 95 * @param onCurrentSpeakerChanged A suspend function that is called whenever the current speaker 96 * in the meeting changes. The function receives a [CharSequence] representing the new 97 * speaker's identifier (e.g., name or ID) or null if there is no current speaker. 98 * @param onParticipantCountChanged A suspend function that is called whenever the number of 99 * participants in the meeting changes. It receives the new participant count as an [Int], 100 * which is always 0 or greater. 101 * @return A [MeetingSummaryRemote] object with an `isSupported` property of this object will 102 * indicate whether the meeting summary extension is supported by the calling application. 103 * 104 * Example Usage: 105 * ```kotlin 106 * connectExtensions(call) { 107 * val meetingSummaryRemote = addMeetingSummaryExtension( 108 * onCurrentSpeakerChanged = { speaker -> 109 * // Update UI with the new speaker 110 * Log.d(TAG, "Current speaker: $speaker") 111 * }, 112 * onParticipantCountChanged = { count -> 113 * // Update UI with the new participant count 114 * Log.d(TAG, "Participant count: $count") 115 * } 116 * ) 117 * onConnected { 118 * if (meetingSummaryRemote.isSupported) { 119 * // The extension is ready to use 120 * } else { 121 * // Handle the case where the extension is not supported. 122 * } 123 * } 124 * } 125 * ``` 126 */ 127 public fun addMeetingSummaryExtension( 128 onCurrentSpeakerChanged: suspend (CharSequence?) -> Unit, 129 onParticipantCountChanged: suspend (Int) -> Unit 130 ): MeetingSummaryRemote 131 132 /** 133 * Add support for this remote surface to display information related to the local call silence 134 * state for this call. 135 * 136 * ``` 137 * connectExtensions(call) { 138 * val localCallSilenceExtension = addLocalCallSilenceExtension( 139 * // consume local call silence state changes 140 * ) 141 * onConnected { 142 * // At this point, support for the local call silence extension will be known 143 * } 144 * } 145 * ``` 146 * 147 * @param onIsLocallySilencedUpdated Called when the local call silence state has changed and 148 * the UI should be updated. 149 * @return The interface that is used to interact with the local call silence extension methods. 150 */ 151 public fun addLocalCallSilenceExtension( 152 onIsLocallySilencedUpdated: suspend (Boolean) -> Unit 153 ): LocalCallSilenceExtensionRemote 154 155 /** 156 * Add support for call icon updates and provides a callback to receive those updates. This 157 * remote surface should implement a [android.database.ContentObserver] to observe changes to 158 * the icon's content URI. This is necessary to ensure the displayed icon reflects any updates 159 * made by the application if the URI remains the same. 160 * 161 * ``` 162 * connectExtensions(call) { 163 * val callIconExtension = addCallIconSupport( 164 * // consume call icon state changes 165 * ) 166 * onConnected { 167 * // At this point, support for call icon extension will be known 168 * } 169 * } 170 * ``` 171 * 172 * @param onCallIconChanged A suspend function that will be invoked with the [Uri] of the new 173 * call icon whenever it changes. This callback will only be called if the calling application 174 * supports the call icon extension (i.e., `isSupported` returns `true`). 175 * @return A [CallIconExtensionRemote] instance that allows the remote to check if the calling 176 * application supports the call icon extension. The remote *must* use this instance to check 177 * support before expecting icon updates. 178 */ 179 public fun addCallIconSupport(onCallIconChanged: suspend (Uri) -> Unit): CallIconExtensionRemote 180 } 181