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 androidx.core.telecom.CallControlScope
21 import androidx.core.telecom.util.ExperimentalAppActions
22 
23 /**
24  * The scope used to initialize extensions on a call as well as manage initialized extensions
25  * associated with the call once the call has been set up.
26  *
27  * Extensions contain state and optional actions that are used to support additional features on a
28  * call, such as information about the participants in the call.
29  *
30  * Supported Extensions:
31  * - The ability to describe meeting participant information as well as actions on those
32  *   participants using [addParticipantExtension]
33  *
34  * For example, to add participant support, the participant extension can be created during
35  * initialization and then used as part of [onCall] to update participant state and listen to action
36  * requests from remote surfaces:
37  * ```
38  * scope.launch {
39  *         mCallsManager.addCallWithExtensions(attributes,
40  *             onAnswerLambda,
41  *             onDisconnectLambda,
42  *             onSetActiveLambda,
43  *             onSetInactiveLambda) {
44  *                 // Initialize extensions ...
45  *                 // Example: add participants support & associated actions
46  *                 val participantExtension = addParticipantExtension(initialParticipants)
47  *                 val raiseHandState = participantExtension.addRaiseHandSupport(
48  *                         initialRaisedHands) { onHandRaisedStateChanged ->
49  *                     // handle raised hand state changed
50  *                 }
51  *                 participantExtension.addKickParticipantSupport {
52  *                         participant ->
53  *                     // handle kicking the requested participant
54  *                 }
55  *                 // Call has been set up, perform in-call actions
56  *                 onCall {
57  *                     // Example: collect call state updates
58  *                     callStateFlow.onEach { newState ->
59  *                         // handle call state updates
60  *                     }.launchIn(this)
61  *                     // update participant extensions
62  *                     participantsFlow.onEach { newParticipants ->
63  *                         participantExtension.updateParticipants(newParticipants)
64  *                     }.launchIn(this)
65  *                     raisedHandsFlow.onEach { newRaisedHands ->
66  *                         raiseHandState.updateRaisedHands(newRaisedHands)
67  *                     }.launchIn(this)
68  *                 }
69  *             }
70  *         }
71  * }
72  * ```
73  */
74 @ExperimentalAppActions
75 public interface ExtensionInitializationScope {
76 
77     /**
78      * User provided callback implementation that is run when the call is ready using the provided
79      * [CallControlScope].
80      *
81      * @param onCall callback invoked when the call has been notified to the framework and the call
82      *   is ready
83      */
onCallnull84     public fun onCall(onCall: suspend CallControlScope.() -> Unit)
85 
86     /**
87      * Adds the participant extension to a call, which provides the ability for this application to
88      * specify participant related information, which will be shared with remote surfaces that
89      * support displaying that information (automotive, watch, etc...).
90      *
91      * @param initialParticipants The initial [List] of [Participant]s in the call. Participants are
92      *   displayed on the remote screen according to their order within the participants list,
93      *   starting with the first element. Duplicate participants are removed. If the same
94      *   participant is added to the list more than once, **only the first occurrence of that
95      *   participant** will be retained in the list; subsequent duplicates are dropped.
96      * @param initialActiveParticipant The initial [Participant] that is active in the call or
97      *   `null` if there is no active participant.
98      * @return The interface used by this application to further update the participant extension
99      *   state to remote surfaces
100      */
101     public fun addParticipantExtension(
102         initialParticipants: List<Participant> = emptyList(),
103         initialActiveParticipant: Participant? = null
104     ): ParticipantExtension
105 
106     /**
107      * Adds the local call silence extension to a call, which provides the ability for this
108      * application to signal to the local call silence state to other surfaces (e.g. Android Auto)
109      *
110      * Local Call Silence means that the call should be silenced at the application layer (local
111      * silence) instead of the hardware layer (global silence). Using a local call silence over
112      * global silence is advantageous when the application wants to still receive the audio input
113      * data while not transmitting audio input data to remote users.
114      *
115      * @param initialCallSilenceState The initial call silence value at the start of the call. True,
116      *   signals silence the user and do not transmit audio data to the remote users. False signals
117      *   the mic is transmitting audio data at the application layer.
118      * @param onLocalSilenceUpdate This is called when the user has requested to change their
119      *   silence state on a remote surface. If true, this user has requested to silence the
120      *   microphone. If false, this user has unsilenced the microphone. This operation should not
121      *   return until the request has been processed.
122      * @return The interface used by this application to further update the local call silence
123      *   extension state to remote surfaces
124      */
125     public fun addLocalCallSilenceExtension(
126         initialCallSilenceState: Boolean,
127         onLocalSilenceUpdate: (suspend (Boolean) -> Unit),
128     ): LocalCallSilenceExtension
129 
130     /**
131      * Adds the call icon extension to a call, which allows the application to specify a custom icon
132      * to be displayed on remote surfaces (e.g., automotive displays, smartwatches) during an active
133      * call. This provides a way to visually represent the call with a specific app, service, or
134      * context.
135      *
136      * @param initialCallIconUri The initial [Uri] of the icon to be displayed. This URI should
137      *   point to a valid image resource that can be loaded and displayed by remote surfaces.
138      *   Consider using a Content Provider URI for accessing resources within your application.
139      * @return The interface used by this application to further update the call icon extension
140      *   state to remote surfaces. This allows dynamically changing the icon during the call.
141      */
142     public fun addCallIconExtension(initialCallIconUri: Uri): CallIconExtension
143 }
144