1 /* 2 * Copyright (C) 2021 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 android.telecom; 18 19 import android.annotation.IntDef; 20 import android.annotation.NonNull; 21 import android.annotation.Nullable; 22 import android.annotation.SystemApi; 23 import android.telephony.Annotation; 24 import android.telephony.CallQuality; 25 import android.telephony.ims.ImsReasonInfo; 26 27 import java.lang.annotation.Retention; 28 import java.lang.annotation.RetentionPolicy; 29 import java.util.concurrent.Executor; 30 31 /** 32 * {@link CallDiagnostics} provides a way for a {@link CallDiagnosticService} to receive diagnostic 33 * information about a mobile call on the device. A {@link CallDiagnostics} instance is similar to 34 * a {@link Call}, however it does not expose call control capabilities and exposes extra diagnostic 35 * and messaging capabilities not present on a {@link Call}. The {@link CallDiagnosticService} 36 * creates a {@link CallDiagnostics} for each {@link Call} on the device. This means that for each 37 * in progress call on the device, the {@link CallDiagnosticService} will create an instance of 38 * {@link CallDiagnostics}. 39 * <p> 40 * The {@link CallDiagnosticService} can generate mid-call diagnostic messages using the 41 * {@link #displayDiagnosticMessage(int, CharSequence)} API which provides the user with valuable 42 * information about conditions impacting their call and corrective actions. For example, if the 43 * {@link CallDiagnosticService} determines that conditions on the call are degrading, it can inform 44 * the user that the call may soon drop and that they can try using a different calling method 45 * (e.g. VOIP or WIFI). 46 * <h2>Threading Model</h2> 47 * All incoming IPC from Telecom in this class will use the same {@link Executor} as the 48 * {@link CallDiagnosticService}. See {@link CallDiagnosticService#setExecutor(Executor)} for more 49 * information. 50 * @hide 51 */ 52 @SystemApi 53 public abstract class CallDiagnostics { 54 55 /** 56 * @hide 57 */ 58 public interface Listener { 59 /** 60 * Used to inform the {@link CallDiagnosticService} of a request to send a D2d message 61 * @param callDiagnostics the call the message is from. 62 * @param message the message type 63 * @param value the message value 64 */ onSendDeviceToDeviceMessage(CallDiagnostics callDiagnostics, int message, int value)65 void onSendDeviceToDeviceMessage(CallDiagnostics callDiagnostics, int message, int value); 66 67 /** 68 * Used to inform the {@link CallDiagnosticService} of a request to display a diagnostic 69 * message. 70 * @param callDiagnostics the call the message pertains to. 71 * @param messageId an identifier for the message. 72 * @param message the message to display. 73 */ onDisplayDiagnosticMessage(CallDiagnostics callDiagnostics, int messageId, CharSequence message)74 void onDisplayDiagnosticMessage(CallDiagnostics callDiagnostics, int messageId, 75 CharSequence message); 76 77 /** 78 * Used to inform the {@link CallDiagnosticService} that a previously shown message is no 79 * longer pertinent. 80 * @param callDiagnostics the call the message pertains to. 81 * @param messageId the ID of the previously posted message. 82 */ onClearDiagnosticMessage(CallDiagnostics callDiagnostics, int messageId)83 void onClearDiagnosticMessage(CallDiagnostics callDiagnostics, int messageId); 84 } 85 86 /** 87 * Device to device message sent via {@link #sendDeviceToDeviceMessage(int, int)} (received via 88 * {@link #onReceiveDeviceToDeviceMessage(int, int)}) which communicates the radio access type 89 * used for the current call. The call network type communicated here is an intentional 90 * simplification of the {@link android.telephony.TelephonyManager#getNetworkType(int)} which 91 * removes some of the resolution inherent in those values; the 92 * {@link android.telephony.TelephonyManager#NETWORK_TYPE_LTE_CA} value, for example is 93 * collapsed into the {@link android.telephony.TelephonyManager#NETWORK_TYPE_LTE} value for 94 * efficiency of transport. For a discussion on the necessity of this simplification, see 95 * {@link #sendDeviceToDeviceMessage(int, int)}. 96 * <p> 97 * Valid values are below: 98 * <UL> 99 * <LI>{@link android.telephony.TelephonyManager#NETWORK_TYPE_LTE}</LI> 100 * <LI>{@link android.telephony.TelephonyManager#NETWORK_TYPE_IWLAN}</LI> 101 * <LI>{@link android.telephony.TelephonyManager#NETWORK_TYPE_NR}</LI> 102 * </UL> 103 */ 104 public static final int MESSAGE_CALL_NETWORK_TYPE = 1; 105 106 /** 107 * Device to device message sent via {@link #sendDeviceToDeviceMessage(int, int)} (received via 108 * {@link #onReceiveDeviceToDeviceMessage(int, int)}) which communicates the call audio codec 109 * used for the current call. 110 * <p> 111 * The audio codec communicated here is an intentional simplification of the 112 * {@link Connection#EXTRA_AUDIO_CODEC} for a call and focuses on communicating the most common 113 * variants of these audio codecs. Other variants of these codecs are reported as the next 114 * closest variant. For example, the {@link Connection#AUDIO_CODEC_EVS_FB} full band codec 115 * is reported via device to device communication as {@link Connection#AUDIO_CODEC_EVS_WB}. 116 * For a discussion on the necessity of this simplification, see 117 * {@link #sendDeviceToDeviceMessage(int, int)}. 118 * <p> 119 * Valid values: 120 * <UL> 121 * <LI>{@link Connection#AUDIO_CODEC_EVS_WB}</LI> 122 * <LI>{@link Connection#AUDIO_CODEC_AMR_WB}</LI> 123 * <LI>{@link Connection#AUDIO_CODEC_AMR}</LI> 124 * </UL> 125 */ 126 public static final int MESSAGE_CALL_AUDIO_CODEC = 2; 127 128 /** 129 * Device to device message sent via {@link #sendDeviceToDeviceMessage(int, int)} (received via 130 * {@link #onReceiveDeviceToDeviceMessage(int, int)}) which communicates the battery state of 131 * the device. Will typically mirror battery state reported via intents such as 132 * {@link android.content.Intent#ACTION_BATTERY_LOW}. 133 * <p> 134 * Valid values: 135 * <UL> 136 * <LI>{@link #BATTERY_STATE_LOW}</LI> 137 * <LI>{@link #BATTERY_STATE_GOOD}</LI> 138 * <LI>{@link #BATTERY_STATE_CHARGING}</LI> 139 * </UL> 140 */ 141 public static final int MESSAGE_DEVICE_BATTERY_STATE = 3; 142 143 /** 144 * Device to device message sent via {@link #sendDeviceToDeviceMessage(int, int)} (received via 145 * {@link #onReceiveDeviceToDeviceMessage(int, int)}) which communicates the overall network 146 * coverage as it pertains to the current call. A {@link CallDiagnosticService} should signal 147 * poor coverage if the network coverage reaches a level where there is a high probability of 148 * the call dropping as a result. 149 * <p> 150 * Valid values: 151 * <UL> 152 * <LI>{@link #COVERAGE_POOR}</LI> 153 * <LI>{@link #COVERAGE_GOOD}</LI> 154 * </UL> 155 */ 156 public static final int MESSAGE_DEVICE_NETWORK_COVERAGE = 4; 157 158 /**@hide*/ 159 @Retention(RetentionPolicy.SOURCE) 160 @IntDef(prefix = "MESSAGE_", value = { 161 MESSAGE_CALL_NETWORK_TYPE, 162 MESSAGE_CALL_AUDIO_CODEC, 163 MESSAGE_DEVICE_BATTERY_STATE, 164 MESSAGE_DEVICE_NETWORK_COVERAGE 165 }) 166 public @interface MessageType {} 167 168 /** 169 * Used with {@link #MESSAGE_DEVICE_BATTERY_STATE} to indicate that the battery is low. 170 */ 171 public static final int BATTERY_STATE_LOW = 1; 172 173 /** 174 * Used with {@link #MESSAGE_DEVICE_BATTERY_STATE} to indicate that the battery is not low. 175 */ 176 public static final int BATTERY_STATE_GOOD = 2; 177 178 /** 179 * Used with {@link #MESSAGE_DEVICE_BATTERY_STATE} to indicate that the battery is charging. 180 */ 181 public static final int BATTERY_STATE_CHARGING = 3; 182 183 /** 184 * Used with {@link #MESSAGE_DEVICE_NETWORK_COVERAGE} to indicate that the coverage is poor. 185 */ 186 public static final int COVERAGE_POOR = 1; 187 188 /** 189 * Used with {@link #MESSAGE_DEVICE_NETWORK_COVERAGE} to indicate that the coverage is good. 190 */ 191 public static final int COVERAGE_GOOD = 2; 192 193 private Listener mListener; 194 private String mCallId; 195 196 /** 197 * @hide 198 */ setListener(@onNull Listener listener)199 public void setListener(@NonNull Listener listener) { 200 mListener = listener; 201 } 202 203 /** 204 * Sets the call ID for this {@link CallDiagnostics}. 205 * @param callId 206 * @hide 207 */ setCallId(@onNull String callId)208 public void setCallId(@NonNull String callId) { 209 mCallId = callId; 210 } 211 212 /** 213 * @return the Telecom call ID for this {@link CallDiagnostics}. 214 * @hide 215 */ getCallId()216 public @NonNull String getCallId() { 217 return mCallId; 218 } 219 220 /** 221 * Telecom calls this method when the details of a call changes. 222 * <p> 223 * Calls to this method will use the same {@link Executor} as the {@link CallDiagnosticService}; 224 * see {@link CallDiagnosticService#getExecutor()} for more information. 225 */ onCallDetailsChanged(@onNull android.telecom.Call.Details details)226 public abstract void onCallDetailsChanged(@NonNull android.telecom.Call.Details details); 227 228 /** 229 * The {@link CallDiagnosticService} implements this method to handle messages received via 230 * device to device communication. 231 * <p> 232 * See {@link #sendDeviceToDeviceMessage(int, int)} for background on device to device 233 * communication. 234 * <p> 235 * The underlying device to device communication protocol assumes that where there the two 236 * devices communicating are using a different version of the protocol, messages the recipient 237 * are not aware of are silently discarded. This means an older client talking to a new client 238 * will not receive newer messages and values sent by the new client. 239 * <p> 240 * Calls to this method will use the same {@link Executor} as the {@link CallDiagnosticService}; 241 * see {@link CallDiagnosticService#getExecutor()} for more information. 242 */ onReceiveDeviceToDeviceMessage( @essageType int message, int value)243 public abstract void onReceiveDeviceToDeviceMessage( 244 @MessageType int message, 245 int value); 246 247 /** 248 * Sends a device to device message to the device on the other end of this call. 249 * <p> 250 * Device to device communication is an Android platform feature which supports low bandwidth 251 * communication between Android devices while they are in a call. The device to device 252 * communication leverages DTMF tones or RTP header extensions to pass messages. The 253 * messages are unacknowledged and sent in a best-effort manner. The protocols assume that the 254 * nature of the message are informational only and are used only to convey basic state 255 * information between devices. 256 * <p> 257 * Device to device messages are intentional simplifications of more rich indicators in the 258 * platform due to the extreme bandwidth constraints inherent with underlying device to device 259 * communication transports used by the telephony framework. Device to device communication is 260 * either accomplished by adding RFC8285 compliant RTP header extensions to the audio packets 261 * for a call, or using the DTMF digits A-D as a communication pathway. RTP header extension 262 * packets ride alongside a the audio for a call, and are thus limited to roughly a byte for 263 * a message. Signalling requirements for DTMF digits place even more significant limitations 264 * on the amount of information which can be communicated during a call, offering only a few 265 * bits of potential information per message. The messages and values are constrained in order 266 * to meet the limited bandwidth inherent with DTMF signalling. 267 * <p> 268 * Allowed message types are: 269 * <ul> 270 * <li>{@link #MESSAGE_CALL_NETWORK_TYPE}</LI> 271 * <li>{@link #MESSAGE_CALL_AUDIO_CODEC}</LI> 272 * <li>{@link #MESSAGE_DEVICE_BATTERY_STATE}</LI> 273 * <li>{@link #MESSAGE_DEVICE_NETWORK_COVERAGE}</LI> 274 * </ul> 275 * @param message The message type to send. 276 * @param value The message value corresponding to the type. 277 */ sendDeviceToDeviceMessage(int message, int value)278 public final void sendDeviceToDeviceMessage(int message, int value) { 279 if (mListener != null) { 280 mListener.onSendDeviceToDeviceMessage(this, message, value); 281 } 282 } 283 284 /** 285 * Telecom calls this method when a GSM or CDMA call disconnects. 286 * The CallDiagnosticService can return a human readable disconnect message which will be passed 287 * to the Dialer app as the {@link DisconnectCause#getDescription()}. A dialer app typically 288 * shows this message at the termination of the call. If {@code null} is returned, the 289 * disconnect message generated by the telephony stack will be shown instead. 290 * <p> 291 * @param disconnectCause the disconnect cause for the call. 292 * @param preciseDisconnectCause the precise disconnect cause for the call. 293 * @return the disconnect message to use in place of the default Telephony message, or 294 * {@code null} if the default message will not be overridden. 295 * <p> 296 * Calls to this method will use the same {@link Executor} as the {@link CallDiagnosticService}; 297 * see {@link CallDiagnosticService#getExecutor()} for more information. 298 */ 299 // TODO: Wire in Telephony support for this. onCallDisconnected( @nnotation.DisconnectCauses int disconnectCause, @Annotation.PreciseDisconnectCauses int preciseDisconnectCause)300 public abstract @Nullable CharSequence onCallDisconnected( 301 @Annotation.DisconnectCauses int disconnectCause, 302 @Annotation.PreciseDisconnectCauses int preciseDisconnectCause); 303 304 /** 305 * Telecom calls this method when an IMS call disconnects and Telephony has already 306 * provided the disconnect reason info and disconnect message for the call. The 307 * {@link CallDiagnosticService} can intercept the raw IMS disconnect reason at this point and 308 * combine it with other call diagnostic information it is aware of to override the disconnect 309 * call message if desired. 310 * 311 * @param disconnectReason The {@link ImsReasonInfo} associated with the call disconnection. 312 * @return A user-readable call disconnect message to use in place of the platform-generated 313 * disconnect message, or {@code null} if the disconnect message should not be overridden. 314 * <p> 315 * Calls to this method will use the same {@link Executor} as the {@link CallDiagnosticService}; 316 * see {@link CallDiagnosticService#getExecutor()} for more information. 317 */ 318 // TODO: Wire in Telephony support for this. onCallDisconnected( @onNull ImsReasonInfo disconnectReason)319 public abstract @Nullable CharSequence onCallDisconnected( 320 @NonNull ImsReasonInfo disconnectReason); 321 322 /** 323 * Telecom calls this method when a {@link CallQuality} report is received from the telephony 324 * stack for a call. 325 * @param callQuality The call quality report for this call. 326 * <p> 327 * Calls to this method will use the same {@link Executor} as the {@link CallDiagnosticService}; 328 * see {@link CallDiagnosticService#getExecutor()} for more information. 329 */ onCallQualityReceived(@onNull CallQuality callQuality)330 public abstract void onCallQualityReceived(@NonNull CallQuality callQuality); 331 332 /** 333 * Signals the active default dialer app to display a call diagnostic message. This can be 334 * used to report problems encountered during the span of a call. 335 * <p> 336 * The {@link CallDiagnosticService} provides a unique client-specific identifier used to 337 * identify the specific diagnostic message type. 338 * <p> 339 * The {@link CallDiagnosticService} should call {@link #clearDiagnosticMessage(int)} when the 340 * diagnostic condition has cleared. 341 * @param messageId the unique message identifier. 342 * @param message a human-readable, localized message to be shown to the user indicating a 343 * call issue which has occurred, along with potential mitigating actions. 344 */ displayDiagnosticMessage(int messageId, @NonNull CharSequence message)345 public final void displayDiagnosticMessage(int messageId, @NonNull 346 CharSequence message) { 347 if (mListener != null) { 348 mListener.onDisplayDiagnosticMessage(this, messageId, message); 349 } 350 } 351 352 /** 353 * Signals to the active default dialer that the diagnostic message previously signalled using 354 * {@link #displayDiagnosticMessage(int, CharSequence)} with the specified messageId is no 355 * longer applicable (e.g. service has improved, for example. 356 * @param messageId the message identifier for a message previously shown via 357 * {@link #displayDiagnosticMessage(int, CharSequence)}. 358 */ clearDiagnosticMessage(int messageId)359 public final void clearDiagnosticMessage(int messageId) { 360 if (mListener != null) { 361 mListener.onClearDiagnosticMessage(this, messageId); 362 } 363 } 364 365 /** 366 * Called by the {@link CallDiagnosticService} to update the call details for this 367 * {@link CallDiagnostics} based on an update received from Telecom. 368 * @param newDetails the new call details. 369 * @hide 370 */ handleCallUpdated(@onNull Call.Details newDetails)371 public void handleCallUpdated(@NonNull Call.Details newDetails) { 372 onCallDetailsChanged(newDetails); 373 } 374 } 375