| Tyler Gunn | d582184 | 2021-02-05 11:12:57 -0800 | [diff] [blame] | 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.NonNull; | 
|  | 20 | import android.annotation.Nullable; | 
|  | 21 | import android.annotation.SdkConstant; | 
| Tyler Gunn | 8019621 | 2021-03-11 22:43:09 -0800 | [diff] [blame] | 22 | import android.annotation.SuppressLint; | 
| Tyler Gunn | d582184 | 2021-02-05 11:12:57 -0800 | [diff] [blame] | 23 | import android.annotation.SystemApi; | 
|  | 24 | import android.app.Service; | 
|  | 25 | import android.content.Intent; | 
| Tyler Gunn | 8019621 | 2021-03-11 22:43:09 -0800 | [diff] [blame] | 26 | import android.os.Handler; | 
|  | 27 | import android.os.HandlerExecutor; | 
| Tyler Gunn | d582184 | 2021-02-05 11:12:57 -0800 | [diff] [blame] | 28 | import android.os.IBinder; | 
|  | 29 | import android.os.RemoteException; | 
| Tyler Gunn | 0a1c6d1 | 2021-03-12 15:44:08 -0800 | [diff] [blame] | 30 |  | 
|  | 31 | import android.telephony.CallQuality; | 
| Tyler Gunn | d582184 | 2021-02-05 11:12:57 -0800 | [diff] [blame] | 32 | import android.util.ArrayMap; | 
|  | 33 |  | 
|  | 34 | import com.android.internal.telecom.ICallDiagnosticService; | 
|  | 35 | import com.android.internal.telecom.ICallDiagnosticServiceAdapter; | 
|  | 36 |  | 
|  | 37 | import java.util.Map; | 
| Tyler Gunn | 8019621 | 2021-03-11 22:43:09 -0800 | [diff] [blame] | 38 | import java.util.concurrent.Executor; | 
| Tyler Gunn | d582184 | 2021-02-05 11:12:57 -0800 | [diff] [blame] | 39 |  | 
|  | 40 | /** | 
|  | 41 | * The platform supports a single OEM provided {@link CallDiagnosticService}, as defined by the | 
|  | 42 | * {@code call_diagnostic_service_package_name} key in the | 
|  | 43 | * {@code packages/services/Telecomm/res/values/config.xml} file.  An OEM can use this API to help | 
|  | 44 | * provide more actionable information about calling issues the user encounters during and after | 
|  | 45 | * a call. | 
|  | 46 | * | 
|  | 47 | * <h1>Manifest Declaration</h1> | 
|  | 48 | * The following is an example of how to declare the service entry in the | 
|  | 49 | * {@link CallDiagnosticService} manifest file: | 
|  | 50 | * <pre> | 
|  | 51 | * {@code | 
|  | 52 | * <service android:name="your.package.YourCallDiagnosticServiceImplementation" | 
|  | 53 | *          android:permission="android.permission.BIND_CALL_DIAGNOSTIC_SERVICE"> | 
|  | 54 | *      <intent-filter> | 
|  | 55 | *          <action android:name="android.telecom.CallDiagnosticService"/> | 
|  | 56 | *      </intent-filter> | 
|  | 57 | * </service> | 
|  | 58 | * } | 
|  | 59 | * </pre> | 
| Tyler Gunn | 8019621 | 2021-03-11 22:43:09 -0800 | [diff] [blame] | 60 | * <p> | 
|  | 61 | * <h2>Threading Model</h2> | 
| Tyler Gunn | 066de60 | 2021-03-16 09:58:07 -0700 | [diff] [blame] | 62 | * By default, all incoming IPC from Telecom in this service and in the {@link CallDiagnostics} | 
| Tyler Gunn | 8019621 | 2021-03-11 22:43:09 -0800 | [diff] [blame] | 63 | * instances will take place on the main thread.  You can override {@link #getExecutor()} in your | 
|  | 64 | * implementation to provide your own {@link Executor}. | 
| Tyler Gunn | d582184 | 2021-02-05 11:12:57 -0800 | [diff] [blame] | 65 | * @hide | 
|  | 66 | */ | 
|  | 67 | @SystemApi | 
|  | 68 | public abstract class CallDiagnosticService extends Service { | 
|  | 69 |  | 
|  | 70 | /** | 
|  | 71 | * Binder stub implementation which handles incoming requests from Telecom. | 
|  | 72 | */ | 
|  | 73 | private final class CallDiagnosticServiceBinder extends ICallDiagnosticService.Stub { | 
|  | 74 |  | 
|  | 75 | @Override | 
|  | 76 | public void setAdapter(ICallDiagnosticServiceAdapter adapter) throws RemoteException { | 
|  | 77 | handleSetAdapter(adapter); | 
|  | 78 | } | 
|  | 79 |  | 
|  | 80 | @Override | 
|  | 81 | public void initializeDiagnosticCall(ParcelableCall call) throws RemoteException { | 
|  | 82 | handleCallAdded(call); | 
|  | 83 | } | 
|  | 84 |  | 
|  | 85 | @Override | 
|  | 86 | public void updateCall(ParcelableCall call) throws RemoteException { | 
|  | 87 | handleCallUpdated(call); | 
|  | 88 | } | 
|  | 89 |  | 
|  | 90 | @Override | 
|  | 91 | public void removeDiagnosticCall(String callId) throws RemoteException { | 
|  | 92 | handleCallRemoved(callId); | 
|  | 93 | } | 
|  | 94 |  | 
|  | 95 | @Override | 
|  | 96 | public void updateCallAudioState(CallAudioState callAudioState) throws RemoteException { | 
| Tyler Gunn | 8019621 | 2021-03-11 22:43:09 -0800 | [diff] [blame] | 97 | getExecutor().execute(() -> onCallAudioStateChanged(callAudioState)); | 
| Tyler Gunn | d582184 | 2021-02-05 11:12:57 -0800 | [diff] [blame] | 98 | } | 
|  | 99 |  | 
|  | 100 | @Override | 
|  | 101 | public void receiveDeviceToDeviceMessage(String callId, int message, int value) { | 
|  | 102 | handleReceivedD2DMessage(callId, message, value); | 
|  | 103 | } | 
|  | 104 |  | 
|  | 105 | @Override | 
|  | 106 | public void receiveBluetoothCallQualityReport(BluetoothCallQualityReport qualityReport) | 
|  | 107 | throws RemoteException { | 
|  | 108 | handleBluetoothCallQualityReport(qualityReport); | 
|  | 109 | } | 
| Tyler Gunn | bc9ecbc | 2021-03-09 15:06:30 -0800 | [diff] [blame] | 110 |  | 
|  | 111 | @Override | 
|  | 112 | public void notifyCallDisconnected(@NonNull String callId, | 
|  | 113 | @NonNull DisconnectCause disconnectCause) throws RemoteException { | 
|  | 114 | handleCallDisconnected(callId, disconnectCause); | 
|  | 115 | } | 
| Tyler Gunn | 0a1c6d1 | 2021-03-12 15:44:08 -0800 | [diff] [blame] | 116 |  | 
|  | 117 | @Override | 
|  | 118 | public void callQualityChanged(String callId, CallQuality callQuality) | 
|  | 119 | throws RemoteException { | 
|  | 120 | handleCallQualityChanged(callId, callQuality); | 
|  | 121 | } | 
| Tyler Gunn | d582184 | 2021-02-05 11:12:57 -0800 | [diff] [blame] | 122 | } | 
|  | 123 |  | 
|  | 124 | /** | 
| Tyler Gunn | 066de60 | 2021-03-16 09:58:07 -0700 | [diff] [blame] | 125 | * Listens to events raised by a {@link CallDiagnostics}. | 
| Tyler Gunn | d582184 | 2021-02-05 11:12:57 -0800 | [diff] [blame] | 126 | */ | 
| Tyler Gunn | 066de60 | 2021-03-16 09:58:07 -0700 | [diff] [blame] | 127 | private CallDiagnostics.Listener mDiagnosticCallListener = | 
|  | 128 | new CallDiagnostics.Listener() { | 
| Tyler Gunn | d582184 | 2021-02-05 11:12:57 -0800 | [diff] [blame] | 129 |  | 
|  | 130 | @Override | 
| Tyler Gunn | 066de60 | 2021-03-16 09:58:07 -0700 | [diff] [blame] | 131 | public void onSendDeviceToDeviceMessage(CallDiagnostics callDiagnostics, | 
|  | 132 | @CallDiagnostics.MessageType int message, int value) { | 
|  | 133 | handleSendDeviceToDeviceMessage(callDiagnostics, message, value); | 
| Tyler Gunn | d582184 | 2021-02-05 11:12:57 -0800 | [diff] [blame] | 134 | } | 
|  | 135 |  | 
|  | 136 | @Override | 
| Tyler Gunn | 066de60 | 2021-03-16 09:58:07 -0700 | [diff] [blame] | 137 | public void onDisplayDiagnosticMessage(CallDiagnostics callDiagnostics, | 
|  | 138 | int messageId, | 
| Tyler Gunn | d582184 | 2021-02-05 11:12:57 -0800 | [diff] [blame] | 139 | CharSequence message) { | 
| Tyler Gunn | 066de60 | 2021-03-16 09:58:07 -0700 | [diff] [blame] | 140 | handleDisplayDiagnosticMessage(callDiagnostics, messageId, message); | 
| Tyler Gunn | d582184 | 2021-02-05 11:12:57 -0800 | [diff] [blame] | 141 | } | 
|  | 142 |  | 
|  | 143 | @Override | 
| Tyler Gunn | 066de60 | 2021-03-16 09:58:07 -0700 | [diff] [blame] | 144 | public void onClearDiagnosticMessage(CallDiagnostics callDiagnostics, | 
|  | 145 | int messageId) { | 
|  | 146 | handleClearDiagnosticMessage(callDiagnostics, messageId); | 
| Tyler Gunn | d582184 | 2021-02-05 11:12:57 -0800 | [diff] [blame] | 147 | } | 
|  | 148 | }; | 
|  | 149 |  | 
|  | 150 | /** | 
|  | 151 | * The {@link Intent} that must be declared as handled by the service. | 
|  | 152 | */ | 
|  | 153 | @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION) | 
|  | 154 | public static final String SERVICE_INTERFACE = "android.telecom.CallDiagnosticService"; | 
|  | 155 |  | 
|  | 156 | /** | 
|  | 157 | * Map which tracks the Telecom calls received from the Telecom stack. | 
|  | 158 | */ | 
|  | 159 | private final Map<String, Call.Details> mCallByTelecomCallId = new ArrayMap<>(); | 
| Tyler Gunn | 066de60 | 2021-03-16 09:58:07 -0700 | [diff] [blame] | 160 | private final Map<String, CallDiagnostics> mDiagnosticCallByTelecomCallId = new ArrayMap<>(); | 
| Tyler Gunn | 8019621 | 2021-03-11 22:43:09 -0800 | [diff] [blame] | 161 | private final Object mLock = new Object(); | 
| Tyler Gunn | d582184 | 2021-02-05 11:12:57 -0800 | [diff] [blame] | 162 | private ICallDiagnosticServiceAdapter mAdapter; | 
|  | 163 |  | 
| Tyler Gunn | 8019621 | 2021-03-11 22:43:09 -0800 | [diff] [blame] | 164 | /** | 
|  | 165 | * Handles binding to the {@link CallDiagnosticService}. | 
|  | 166 | * | 
|  | 167 | * @param intent The Intent that was used to bind to this service, | 
|  | 168 | * as given to {@link android.content.Context#bindService | 
|  | 169 | * Context.bindService}.  Note that any extras that were included with | 
|  | 170 | * the Intent at that point will <em>not</em> be seen here. | 
|  | 171 | * @return | 
|  | 172 | */ | 
| Tyler Gunn | d582184 | 2021-02-05 11:12:57 -0800 | [diff] [blame] | 173 | @Nullable | 
|  | 174 | @Override | 
|  | 175 | public IBinder onBind(@NonNull Intent intent) { | 
|  | 176 | Log.i(this, "onBind!"); | 
|  | 177 | return new CallDiagnosticServiceBinder(); | 
|  | 178 | } | 
|  | 179 |  | 
|  | 180 | /** | 
| Tyler Gunn | 8019621 | 2021-03-11 22:43:09 -0800 | [diff] [blame] | 181 | * Returns the {@link Executor} to use for incoming IPS from Telecom into your service | 
|  | 182 | * implementation. | 
|  | 183 | * <p> | 
|  | 184 | * Override this method in your {@link CallDiagnosticService} implementation to provide the | 
|  | 185 | * executor you want to use for incoming IPC. | 
|  | 186 | * | 
|  | 187 | * @return the {@link Executor} to use for incoming IPC from Telecom to | 
| Tyler Gunn | 066de60 | 2021-03-16 09:58:07 -0700 | [diff] [blame] | 188 | * {@link CallDiagnosticService} and {@link CallDiagnostics}. | 
| Tyler Gunn | 8019621 | 2021-03-11 22:43:09 -0800 | [diff] [blame] | 189 | */ | 
|  | 190 | @SuppressLint("OnNameExpected") | 
|  | 191 | @NonNull public Executor getExecutor() { | 
|  | 192 | return new HandlerExecutor(Handler.createAsync(getMainLooper())); | 
|  | 193 | } | 
|  | 194 |  | 
|  | 195 | /** | 
| Tyler Gunn | d582184 | 2021-02-05 11:12:57 -0800 | [diff] [blame] | 196 | * Telecom calls this method on the {@link CallDiagnosticService} with details about a new call | 
|  | 197 | * which was added to Telecom. | 
|  | 198 | * <p> | 
| Tyler Gunn | 066de60 | 2021-03-16 09:58:07 -0700 | [diff] [blame] | 199 | * The {@link CallDiagnosticService} returns an implementation of {@link CallDiagnostics} to be | 
| Tyler Gunn | d582184 | 2021-02-05 11:12:57 -0800 | [diff] [blame] | 200 | * used for the lifespan of this call. | 
| Tyler Gunn | 8019621 | 2021-03-11 22:43:09 -0800 | [diff] [blame] | 201 | * <p> | 
|  | 202 | * Calls to this method will use the {@link CallDiagnosticService}'s {@link Executor}; see | 
|  | 203 | * {@link CallDiagnosticService#getExecutor()} for more information. | 
| Tyler Gunn | d582184 | 2021-02-05 11:12:57 -0800 | [diff] [blame] | 204 | * | 
|  | 205 | * @param call The details of the new call. | 
| Tyler Gunn | 066de60 | 2021-03-16 09:58:07 -0700 | [diff] [blame] | 206 | * @return An instance of {@link CallDiagnostics} which the {@link CallDiagnosticService} | 
| Tyler Gunn | d582184 | 2021-02-05 11:12:57 -0800 | [diff] [blame] | 207 | * provides to be used for the lifespan of the call. | 
| Tyler Gunn | 066de60 | 2021-03-16 09:58:07 -0700 | [diff] [blame] | 208 | * @throws IllegalArgumentException if a {@code null} {@link CallDiagnostics} is returned. | 
| Tyler Gunn | d582184 | 2021-02-05 11:12:57 -0800 | [diff] [blame] | 209 | */ | 
| Tyler Gunn | 066de60 | 2021-03-16 09:58:07 -0700 | [diff] [blame] | 210 | public abstract @NonNull CallDiagnostics onInitializeCallDiagnostics(@NonNull | 
| Tyler Gunn | d582184 | 2021-02-05 11:12:57 -0800 | [diff] [blame] | 211 | android.telecom.Call.Details call); | 
|  | 212 |  | 
|  | 213 | /** | 
| Tyler Gunn | 066de60 | 2021-03-16 09:58:07 -0700 | [diff] [blame] | 214 | * Telecom calls this method when a previous created {@link CallDiagnostics} is no longer | 
|  | 215 | * needed.  This happens when Telecom is no longer tracking the call in question. | 
| Tyler Gunn | 8019621 | 2021-03-11 22:43:09 -0800 | [diff] [blame] | 216 | * <p> | 
|  | 217 | * Calls to this method will use the {@link CallDiagnosticService}'s {@link Executor}; see | 
|  | 218 | * {@link CallDiagnosticService#getExecutor()} for more information. | 
|  | 219 | * | 
| Tyler Gunn | d582184 | 2021-02-05 11:12:57 -0800 | [diff] [blame] | 220 | * @param call The diagnostic call which is no longer tracked by Telecom. | 
|  | 221 | */ | 
| Tyler Gunn | 066de60 | 2021-03-16 09:58:07 -0700 | [diff] [blame] | 222 | public abstract void onRemoveCallDiagnostics(@NonNull CallDiagnostics call); | 
| Tyler Gunn | d582184 | 2021-02-05 11:12:57 -0800 | [diff] [blame] | 223 |  | 
|  | 224 | /** | 
|  | 225 | * Telecom calls this method when the audio routing or available audio route information | 
|  | 226 | * changes. | 
|  | 227 | * <p> | 
|  | 228 | * Audio state is common to all calls. | 
| Tyler Gunn | 8019621 | 2021-03-11 22:43:09 -0800 | [diff] [blame] | 229 | * <p> | 
|  | 230 | * Calls to this method will use the {@link CallDiagnosticService}'s {@link Executor}; see | 
|  | 231 | * {@link CallDiagnosticService#getExecutor()} for more information. | 
| Tyler Gunn | d582184 | 2021-02-05 11:12:57 -0800 | [diff] [blame] | 232 | * | 
|  | 233 | * @param audioState The new audio state. | 
|  | 234 | */ | 
|  | 235 | public abstract void onCallAudioStateChanged( | 
|  | 236 | @NonNull CallAudioState audioState); | 
|  | 237 |  | 
|  | 238 | /** | 
|  | 239 | * Telecom calls this method when a {@link BluetoothCallQualityReport} is received from the | 
|  | 240 | * bluetooth stack. | 
| Tyler Gunn | 8019621 | 2021-03-11 22:43:09 -0800 | [diff] [blame] | 241 | * <p> | 
|  | 242 | * Calls to this method will use the {@link CallDiagnosticService}'s {@link Executor}; see | 
|  | 243 | * {@link CallDiagnosticService#getExecutor()} for more information. | 
|  | 244 | * | 
| Tyler Gunn | d582184 | 2021-02-05 11:12:57 -0800 | [diff] [blame] | 245 | * @param qualityReport the {@link BluetoothCallQualityReport}. | 
|  | 246 | */ | 
|  | 247 | public abstract void onBluetoothCallQualityReportReceived( | 
|  | 248 | @NonNull BluetoothCallQualityReport qualityReport); | 
|  | 249 |  | 
|  | 250 | /** | 
|  | 251 | * Handles a request from Telecom to set the adapater used to communicate back to Telecom. | 
|  | 252 | * @param adapter | 
|  | 253 | */ | 
|  | 254 | private void handleSetAdapter(@NonNull ICallDiagnosticServiceAdapter adapter) { | 
|  | 255 | mAdapter = adapter; | 
|  | 256 | } | 
|  | 257 |  | 
|  | 258 | /** | 
|  | 259 | * Handles a request from Telecom to add a new call. | 
|  | 260 | * @param parcelableCall | 
|  | 261 | */ | 
|  | 262 | private void handleCallAdded(@NonNull ParcelableCall parcelableCall) { | 
|  | 263 | String telecomCallId = parcelableCall.getId(); | 
|  | 264 | Log.i(this, "handleCallAdded: callId=%s - added", telecomCallId); | 
|  | 265 | Call.Details newCallDetails = Call.Details.createFromParcelableCall(parcelableCall); | 
| Tyler Gunn | 8019621 | 2021-03-11 22:43:09 -0800 | [diff] [blame] | 266 | synchronized (mLock) { | 
|  | 267 | mCallByTelecomCallId.put(telecomCallId, newCallDetails); | 
| Tyler Gunn | d582184 | 2021-02-05 11:12:57 -0800 | [diff] [blame] | 268 | } | 
| Tyler Gunn | 8019621 | 2021-03-11 22:43:09 -0800 | [diff] [blame] | 269 |  | 
|  | 270 | getExecutor().execute(() -> { | 
| Tyler Gunn | 066de60 | 2021-03-16 09:58:07 -0700 | [diff] [blame] | 271 | CallDiagnostics callDiagnostics = onInitializeCallDiagnostics(newCallDetails); | 
|  | 272 | if (callDiagnostics == null) { | 
| Tyler Gunn | 8019621 | 2021-03-11 22:43:09 -0800 | [diff] [blame] | 273 | throw new IllegalArgumentException( | 
|  | 274 | "A valid DiagnosticCall instance was not provided."); | 
|  | 275 | } | 
|  | 276 | synchronized (mLock) { | 
| Tyler Gunn | 066de60 | 2021-03-16 09:58:07 -0700 | [diff] [blame] | 277 | callDiagnostics.setListener(mDiagnosticCallListener); | 
|  | 278 | callDiagnostics.setCallId(telecomCallId); | 
|  | 279 | mDiagnosticCallByTelecomCallId.put(telecomCallId, callDiagnostics); | 
| Tyler Gunn | 8019621 | 2021-03-11 22:43:09 -0800 | [diff] [blame] | 280 | } | 
|  | 281 | }); | 
| Tyler Gunn | d582184 | 2021-02-05 11:12:57 -0800 | [diff] [blame] | 282 | } | 
|  | 283 |  | 
|  | 284 | /** | 
|  | 285 | * Handles an update to {@link Call.Details} notified by Telecom. | 
| Tyler Gunn | 066de60 | 2021-03-16 09:58:07 -0700 | [diff] [blame] | 286 | * Caches the call details and notifies the {@link CallDiagnostics} of the change via | 
|  | 287 | * {@link CallDiagnostics#onCallDetailsChanged(Call.Details)}. | 
| Tyler Gunn | d582184 | 2021-02-05 11:12:57 -0800 | [diff] [blame] | 288 | * @param parcelableCall the new parceled call details from Telecom. | 
|  | 289 | */ | 
|  | 290 | private void handleCallUpdated(@NonNull ParcelableCall parcelableCall) { | 
|  | 291 | String telecomCallId = parcelableCall.getId(); | 
|  | 292 | Log.i(this, "handleCallUpdated: callId=%s - updated", telecomCallId); | 
|  | 293 | Call.Details newCallDetails = Call.Details.createFromParcelableCall(parcelableCall); | 
| Tyler Gunn | 066de60 | 2021-03-16 09:58:07 -0700 | [diff] [blame] | 294 | CallDiagnostics callDiagnostics; | 
| Tyler Gunn | 8019621 | 2021-03-11 22:43:09 -0800 | [diff] [blame] | 295 | synchronized (mLock) { | 
| Tyler Gunn | 066de60 | 2021-03-16 09:58:07 -0700 | [diff] [blame] | 296 | callDiagnostics = mDiagnosticCallByTelecomCallId.get(telecomCallId); | 
| Tyler Gunn | 07d3736 | 2021-05-21 16:20:16 -0700 | [diff] [blame] | 297 | if (callDiagnostics == null) { | 
|  | 298 | // Possible to get a call update after a call is removed. | 
|  | 299 | return; | 
|  | 300 | } | 
| Tyler Gunn | 8019621 | 2021-03-11 22:43:09 -0800 | [diff] [blame] | 301 | mCallByTelecomCallId.put(telecomCallId, newCallDetails); | 
|  | 302 | } | 
| Tyler Gunn | 066de60 | 2021-03-16 09:58:07 -0700 | [diff] [blame] | 303 | getExecutor().execute(() -> callDiagnostics.handleCallUpdated(newCallDetails)); | 
| Tyler Gunn | d582184 | 2021-02-05 11:12:57 -0800 | [diff] [blame] | 304 | } | 
|  | 305 |  | 
|  | 306 | /** | 
|  | 307 | * Handles a request from Telecom to remove an existing call. | 
|  | 308 | * @param telecomCallId | 
|  | 309 | */ | 
|  | 310 | private void handleCallRemoved(@NonNull String telecomCallId) { | 
|  | 311 | Log.i(this, "handleCallRemoved: callId=%s - removed", telecomCallId); | 
|  | 312 |  | 
| Tyler Gunn | 066de60 | 2021-03-16 09:58:07 -0700 | [diff] [blame] | 313 | CallDiagnostics callDiagnostics; | 
| Tyler Gunn | 8019621 | 2021-03-11 22:43:09 -0800 | [diff] [blame] | 314 | synchronized (mLock) { | 
| Tyler Gunn | 07d3736 | 2021-05-21 16:20:16 -0700 | [diff] [blame] | 315 | if (mCallByTelecomCallId.containsKey(telecomCallId)) { | 
|  | 316 | mCallByTelecomCallId.remove(telecomCallId); | 
|  | 317 | } | 
|  | 318 |  | 
| Tyler Gunn | 8019621 | 2021-03-11 22:43:09 -0800 | [diff] [blame] | 319 | if (mDiagnosticCallByTelecomCallId.containsKey(telecomCallId)) { | 
| Tyler Gunn | 066de60 | 2021-03-16 09:58:07 -0700 | [diff] [blame] | 320 | callDiagnostics = mDiagnosticCallByTelecomCallId.remove(telecomCallId); | 
| Tyler Gunn | 8019621 | 2021-03-11 22:43:09 -0800 | [diff] [blame] | 321 | } else { | 
| Tyler Gunn | 066de60 | 2021-03-16 09:58:07 -0700 | [diff] [blame] | 322 | callDiagnostics = null; | 
| Tyler Gunn | 8019621 | 2021-03-11 22:43:09 -0800 | [diff] [blame] | 323 | } | 
|  | 324 | } | 
|  | 325 |  | 
|  | 326 | // Inform the service of the removed call. | 
| Tyler Gunn | 066de60 | 2021-03-16 09:58:07 -0700 | [diff] [blame] | 327 | if (callDiagnostics != null) { | 
|  | 328 | getExecutor().execute(() -> onRemoveCallDiagnostics(callDiagnostics)); | 
| Tyler Gunn | d582184 | 2021-02-05 11:12:57 -0800 | [diff] [blame] | 329 | } | 
|  | 330 | } | 
|  | 331 |  | 
|  | 332 | /** | 
|  | 333 | * Handles an incoming device to device message received from Telecom.  Notifies the | 
| Tyler Gunn | 066de60 | 2021-03-16 09:58:07 -0700 | [diff] [blame] | 334 | * {@link CallDiagnostics} via {@link CallDiagnostics#onReceiveDeviceToDeviceMessage(int, int)}. | 
| Tyler Gunn | d582184 | 2021-02-05 11:12:57 -0800 | [diff] [blame] | 335 | * @param callId | 
|  | 336 | * @param message | 
|  | 337 | * @param value | 
|  | 338 | */ | 
|  | 339 | private void handleReceivedD2DMessage(@NonNull String callId, int message, int value) { | 
|  | 340 | Log.i(this, "handleReceivedD2DMessage: callId=%s, msg=%d/%d", callId, message, value); | 
| Tyler Gunn | 066de60 | 2021-03-16 09:58:07 -0700 | [diff] [blame] | 341 | CallDiagnostics callDiagnostics; | 
| Tyler Gunn | 8019621 | 2021-03-11 22:43:09 -0800 | [diff] [blame] | 342 | synchronized (mLock) { | 
| Tyler Gunn | 066de60 | 2021-03-16 09:58:07 -0700 | [diff] [blame] | 343 | callDiagnostics = mDiagnosticCallByTelecomCallId.get(callId); | 
| Tyler Gunn | 8019621 | 2021-03-11 22:43:09 -0800 | [diff] [blame] | 344 | } | 
| Tyler Gunn | 066de60 | 2021-03-16 09:58:07 -0700 | [diff] [blame] | 345 | if (callDiagnostics != null) { | 
| Tyler Gunn | 8019621 | 2021-03-11 22:43:09 -0800 | [diff] [blame] | 346 | getExecutor().execute( | 
| Tyler Gunn | 066de60 | 2021-03-16 09:58:07 -0700 | [diff] [blame] | 347 | () -> callDiagnostics.onReceiveDeviceToDeviceMessage(message, value)); | 
| Tyler Gunn | 8019621 | 2021-03-11 22:43:09 -0800 | [diff] [blame] | 348 | } | 
| Tyler Gunn | d582184 | 2021-02-05 11:12:57 -0800 | [diff] [blame] | 349 | } | 
|  | 350 |  | 
|  | 351 | /** | 
| Tyler Gunn | bc9ecbc | 2021-03-09 15:06:30 -0800 | [diff] [blame] | 352 | * Handles a request from the Telecom framework to get a disconnect message from the | 
|  | 353 | * {@link CallDiagnosticService}. | 
|  | 354 | * @param callId The ID of the call. | 
|  | 355 | * @param disconnectCause The telecom disconnect cause. | 
|  | 356 | */ | 
|  | 357 | private void handleCallDisconnected(@NonNull String callId, | 
|  | 358 | @NonNull DisconnectCause disconnectCause) { | 
|  | 359 | Log.i(this, "handleCallDisconnected: call=%s; cause=%s", callId, disconnectCause); | 
| Tyler Gunn | 07d3736 | 2021-05-21 16:20:16 -0700 | [diff] [blame] | 360 | CallDiagnostics callDiagnostics; | 
|  | 361 | synchronized (mLock) { | 
|  | 362 | callDiagnostics = mDiagnosticCallByTelecomCallId.get(callId); | 
|  | 363 | } | 
| Tyler Gunn | bc9ecbc | 2021-03-09 15:06:30 -0800 | [diff] [blame] | 364 | CharSequence message; | 
|  | 365 | if (disconnectCause.getImsReasonInfo() != null) { | 
| Tyler Gunn | 066de60 | 2021-03-16 09:58:07 -0700 | [diff] [blame] | 366 | message = callDiagnostics.onCallDisconnected(disconnectCause.getImsReasonInfo()); | 
| Tyler Gunn | bc9ecbc | 2021-03-09 15:06:30 -0800 | [diff] [blame] | 367 | } else { | 
| Tyler Gunn | 066de60 | 2021-03-16 09:58:07 -0700 | [diff] [blame] | 368 | message = callDiagnostics.onCallDisconnected( | 
| Tyler Gunn | bc9ecbc | 2021-03-09 15:06:30 -0800 | [diff] [blame] | 369 | disconnectCause.getTelephonyDisconnectCause(), | 
|  | 370 | disconnectCause.getTelephonyPreciseDisconnectCause()); | 
|  | 371 | } | 
|  | 372 | try { | 
|  | 373 | mAdapter.overrideDisconnectMessage(callId, message); | 
|  | 374 | } catch (RemoteException e) { | 
|  | 375 | Log.w(this, "handleCallDisconnected: call=%s; cause=%s; %s", | 
|  | 376 | callId, disconnectCause, e); | 
|  | 377 | } | 
|  | 378 | } | 
|  | 379 |  | 
|  | 380 | /** | 
| Tyler Gunn | d582184 | 2021-02-05 11:12:57 -0800 | [diff] [blame] | 381 | * Handles an incoming bluetooth call quality report from Telecom.  Notifies via | 
|  | 382 | * {@link CallDiagnosticService#onBluetoothCallQualityReportReceived( | 
|  | 383 | * BluetoothCallQualityReport)}. | 
|  | 384 | * @param qualityReport The bluetooth call quality remote. | 
|  | 385 | */ | 
|  | 386 | private void handleBluetoothCallQualityReport(@NonNull BluetoothCallQualityReport | 
|  | 387 | qualityReport) { | 
|  | 388 | Log.i(this, "handleBluetoothCallQualityReport; report=%s", qualityReport); | 
| Tyler Gunn | 8019621 | 2021-03-11 22:43:09 -0800 | [diff] [blame] | 389 | getExecutor().execute(() -> onBluetoothCallQualityReportReceived(qualityReport)); | 
| Tyler Gunn | d582184 | 2021-02-05 11:12:57 -0800 | [diff] [blame] | 390 | } | 
|  | 391 |  | 
|  | 392 | /** | 
| Tyler Gunn | 0a1c6d1 | 2021-03-12 15:44:08 -0800 | [diff] [blame] | 393 | * Handles a change reported by Telecom to the call quality for a call. | 
|  | 394 | * @param callId the call ID the change applies to. | 
|  | 395 | * @param callQuality The new call quality. | 
|  | 396 | */ | 
|  | 397 | private void handleCallQualityChanged(@NonNull String callId, | 
|  | 398 | @NonNull CallQuality callQuality) { | 
|  | 399 | Log.i(this, "handleCallQualityChanged; call=%s, cq=%s", callId, callQuality); | 
|  | 400 | CallDiagnostics callDiagnostics; | 
| Tyler Gunn | 07d3736 | 2021-05-21 16:20:16 -0700 | [diff] [blame] | 401 | synchronized(mLock) { | 
|  | 402 | callDiagnostics = mDiagnosticCallByTelecomCallId.get(callId); | 
|  | 403 | } | 
| Tyler Gunn | 0a1c6d1 | 2021-03-12 15:44:08 -0800 | [diff] [blame] | 404 | if (callDiagnostics != null) { | 
|  | 405 | callDiagnostics.onCallQualityReceived(callQuality); | 
|  | 406 | } | 
|  | 407 | } | 
|  | 408 |  | 
|  | 409 | /** | 
| Tyler Gunn | 066de60 | 2021-03-16 09:58:07 -0700 | [diff] [blame] | 410 | * Handles a request from a {@link CallDiagnostics} to send a device to device message (received | 
|  | 411 | * via {@link CallDiagnostics#sendDeviceToDeviceMessage(int, int)}. | 
|  | 412 | * @param callDiagnostics | 
| Tyler Gunn | d582184 | 2021-02-05 11:12:57 -0800 | [diff] [blame] | 413 | * @param message | 
|  | 414 | * @param value | 
|  | 415 | */ | 
| Tyler Gunn | 066de60 | 2021-03-16 09:58:07 -0700 | [diff] [blame] | 416 | private void handleSendDeviceToDeviceMessage(@NonNull CallDiagnostics callDiagnostics, | 
| Tyler Gunn | d582184 | 2021-02-05 11:12:57 -0800 | [diff] [blame] | 417 | int message, int value) { | 
| Tyler Gunn | 066de60 | 2021-03-16 09:58:07 -0700 | [diff] [blame] | 418 | String callId = callDiagnostics.getCallId(); | 
| Tyler Gunn | d582184 | 2021-02-05 11:12:57 -0800 | [diff] [blame] | 419 | try { | 
|  | 420 | mAdapter.sendDeviceToDeviceMessage(callId, message, value); | 
|  | 421 | Log.i(this, "handleSendDeviceToDeviceMessage: call=%s; msg=%d/%d", callId, message, | 
|  | 422 | value); | 
|  | 423 | } catch (RemoteException e) { | 
|  | 424 | Log.w(this, "handleSendDeviceToDeviceMessage: call=%s; msg=%d/%d failed %s", | 
|  | 425 | callId, message, value, e); | 
|  | 426 | } | 
|  | 427 | } | 
|  | 428 |  | 
|  | 429 | /** | 
| Tyler Gunn | 066de60 | 2021-03-16 09:58:07 -0700 | [diff] [blame] | 430 | * Handles a request from a {@link CallDiagnostics} to display an in-call diagnostic message. | 
|  | 431 | * Originates from {@link CallDiagnostics#displayDiagnosticMessage(int, CharSequence)}. | 
|  | 432 | * @param callDiagnostics | 
| Tyler Gunn | d582184 | 2021-02-05 11:12:57 -0800 | [diff] [blame] | 433 | * @param messageId | 
|  | 434 | * @param message | 
|  | 435 | */ | 
| Tyler Gunn | 066de60 | 2021-03-16 09:58:07 -0700 | [diff] [blame] | 436 | private void handleDisplayDiagnosticMessage(CallDiagnostics callDiagnostics, int messageId, | 
| Tyler Gunn | d582184 | 2021-02-05 11:12:57 -0800 | [diff] [blame] | 437 | CharSequence message) { | 
| Tyler Gunn | 066de60 | 2021-03-16 09:58:07 -0700 | [diff] [blame] | 438 | String callId = callDiagnostics.getCallId(); | 
| Tyler Gunn | d582184 | 2021-02-05 11:12:57 -0800 | [diff] [blame] | 439 | try { | 
|  | 440 | mAdapter.displayDiagnosticMessage(callId, messageId, message); | 
|  | 441 | Log.i(this, "handleDisplayDiagnosticMessage: call=%s; msg=%d/%s", callId, messageId, | 
|  | 442 | message); | 
|  | 443 | } catch (RemoteException e) { | 
|  | 444 | Log.w(this, "handleDisplayDiagnosticMessage: call=%s; msg=%d/%s failed %s", | 
|  | 445 | callId, messageId, message, e); | 
|  | 446 | } | 
|  | 447 | } | 
|  | 448 |  | 
|  | 449 | /** | 
| Tyler Gunn | 066de60 | 2021-03-16 09:58:07 -0700 | [diff] [blame] | 450 | * Handles a request from a {@link CallDiagnostics} to clear a previously shown diagnostic | 
| Tyler Gunn | d582184 | 2021-02-05 11:12:57 -0800 | [diff] [blame] | 451 | * message. | 
| Tyler Gunn | 066de60 | 2021-03-16 09:58:07 -0700 | [diff] [blame] | 452 | * Originates from {@link CallDiagnostics#clearDiagnosticMessage(int)}. | 
|  | 453 | * @param callDiagnostics | 
| Tyler Gunn | d582184 | 2021-02-05 11:12:57 -0800 | [diff] [blame] | 454 | * @param messageId | 
|  | 455 | */ | 
| Tyler Gunn | 066de60 | 2021-03-16 09:58:07 -0700 | [diff] [blame] | 456 | private void handleClearDiagnosticMessage(CallDiagnostics callDiagnostics, int messageId) { | 
|  | 457 | String callId = callDiagnostics.getCallId(); | 
| Tyler Gunn | d582184 | 2021-02-05 11:12:57 -0800 | [diff] [blame] | 458 | try { | 
|  | 459 | mAdapter.clearDiagnosticMessage(callId, messageId); | 
|  | 460 | Log.i(this, "handleClearDiagnosticMessage: call=%s; msg=%d", callId, messageId); | 
|  | 461 | } catch (RemoteException e) { | 
|  | 462 | Log.w(this, "handleClearDiagnosticMessage: call=%s; msg=%d failed %s", | 
|  | 463 | callId, messageId, e); | 
|  | 464 | } | 
|  | 465 | } | 
|  | 466 | } |