1 /* 2 * Copyright (C) 2013 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.SdkConstant; 21 import android.annotation.SystemApi; 22 import android.app.Service; 23 import android.bluetooth.BluetoothDevice; 24 import android.content.Intent; 25 import android.hardware.camera2.CameraManager; 26 import android.net.Uri; 27 import android.os.Bundle; 28 import android.os.Handler; 29 import android.os.IBinder; 30 import android.os.Looper; 31 import android.os.Message; 32 import android.view.Surface; 33 34 import com.android.internal.os.SomeArgs; 35 import com.android.internal.telecom.IInCallAdapter; 36 import com.android.internal.telecom.IInCallService; 37 38 import java.util.Collections; 39 import java.util.List; 40 41 /** 42 * This service is implemented by an app that wishes to provide functionality for managing 43 * phone calls. 44 * <h2>Becoming the Default Phone App</h2> 45 * The default dialer/phone app is one which provides the in-call user interface while the device is 46 * in a call. A device is bundled with a system provided default dialer/phone app. The user may 47 * choose a single app to take over this role from the system app. An app which wishes to fulfill 48 * one this role uses the {@code android.app.role.RoleManager} to request that they fill the role. 49 * <p> 50 * An app filling the role of the default phone app provides a user interface while the device is in 51 * a call, and the device is not in car mode. 52 * <p> 53 * Below is an example manifest registration for an {@code InCallService}. The meta-data 54 * {@link TelecomManager#METADATA_IN_CALL_SERVICE_UI} indicates that this particular 55 * {@code InCallService} implementation intends to replace the built-in in-call UI. 56 * The meta-data {@link TelecomManager#METADATA_IN_CALL_SERVICE_RINGING} indicates that this 57 * {@link InCallService} will play the ringtone for incoming calls. See 58 * <a href="#incomingCallNotification">below</a> for more information on showing the incoming call 59 * UI and playing the ringtone in your app. 60 * <pre> 61 * {@code 62 * <service android:name="your.package.YourInCallServiceImplementation" 63 * android:permission="android.permission.BIND_INCALL_SERVICE"> 64 * <meta-data android:name="android.telecom.IN_CALL_SERVICE_UI" android:value="true" /> 65 * <meta-data android:name="android.telecom.IN_CALL_SERVICE_RINGING" 66 * android:value="true" /> 67 * <intent-filter> 68 * <action android:name="android.telecom.InCallService"/> 69 * </intent-filter> 70 * </service> 71 * } 72 * </pre> 73 * <p> 74 * In addition to implementing the {@link InCallService} API, you must also declare an activity in 75 * your manifest which handles the {@link Intent#ACTION_DIAL} intent. The example below illustrates 76 * how this is done: 77 * <pre> 78 * {@code 79 * <activity android:name="your.package.YourDialerActivity" 80 * android:label="@string/yourDialerActivityLabel"> 81 * <intent-filter> 82 * <action android:name="android.intent.action.DIAL" /> 83 * <category android:name="android.intent.category.DEFAULT" /> 84 * </intent-filter> 85 * </activity> 86 * } 87 * </pre> 88 * <p> 89 * When a user installs your application and runs it for the first time, you should use the 90 * {@link android.app.role.RoleManager} to prompt the user to see if they would like your app to 91 * be the new default phone app. 92 * <p id="requestRole"> 93 * The code below shows how your app can request to become the default phone/dialer app: 94 * <pre> 95 * {@code 96 * private static final int REQUEST_ID = 1; 97 * 98 * public void requestRole() { 99 * RoleManager roleManager = (RoleManager) getSystemService(ROLE_SERVICE); 100 * Intent intent = roleManager.createRequestRoleIntent(RoleManager.ROLE_DIALER); 101 * startActivityForResult(intent, REQUEST_ID); 102 * } 103 * 104 * @Override 105 * public void onActivityResult(int requestCode, int resultCode, Intent data) { 106 * if (requestCode == REQUEST_ID) { 107 * if (resultCode == android.app.Activity.RESULT_OK) { 108 * // Your app is now the default dialer app 109 * } else { 110 * // Your app is not the default dialer app 111 * } 112 * } 113 * } 114 * </pre> 115 * <p id="incomingCallNotification"> 116 * <h3>Showing the Incoming Call Notification</h3> 117 * When your app receives a new incoming call via {@link InCallService#onCallAdded(Call)}, it is 118 * responsible for displaying an incoming call UI for the incoming call. It should do this using 119 * {@link android.app.NotificationManager} APIs to post a new incoming call notification. 120 * <p> 121 * Where your app declares the meta-data {@link TelecomManager#METADATA_IN_CALL_SERVICE_RINGING}, it 122 * is responsible for playing the ringtone for incoming calls. Your app should create a 123 * {@link android.app.NotificationChannel} which specifies the desired ringtone. For example: 124 * <pre><code> 125 * NotificationChannel channel = new NotificationChannel(YOUR_CHANNEL_ID, "Incoming Calls", 126 * NotificationManager.IMPORTANCE_MAX); 127 * // other channel setup stuff goes here. 128 * 129 * // We'll use the default system ringtone for our incoming call notification channel. You can 130 * // use your own audio resource here. 131 * Uri ringtoneUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE); 132 * channel.setSound(ringtoneUri, new AudioAttributes.Builder() 133 * // Setting the AudioAttributes is important as it identifies the purpose of your 134 * // notification sound. 135 * .setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE) 136 * .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION) 137 * .build()); 138 * 139 * NotificationManager mgr = getSystemService(NotificationManager.class); 140 * mgr.createNotificationChannel(channel); 141 * </code></pre> 142 * <p> 143 * When your app receives a new incoming call, it creates a {@link android.app.Notification} for the 144 * incoming call and associates it with your incoming call notification channel. You can specify a 145 * {@link android.app.PendingIntent} on the notification which will launch your full screen 146 * incoming call UI. The notification manager framework will display your notification as a 147 * heads-up notification if the user is actively using the phone. When the user is not using the 148 * phone, your full-screen incoming call UI is used instead. 149 * For example: 150 * <pre><code>{@code 151 * // Create an intent which triggers your fullscreen incoming call user interface. 152 * Intent intent = new Intent(Intent.ACTION_MAIN, null); 153 * intent.setFlags(Intent.FLAG_ACTIVITY_NO_USER_ACTION | Intent.FLAG_ACTIVITY_NEW_TASK); 154 * intent.setClass(context, YourIncomingCallActivity.class); 155 * PendingIntent pendingIntent = PendingIntent.getActivity(context, 1, intent, 0); 156 * 157 * // Build the notification as an ongoing high priority item; this ensures it will show as 158 * // a heads up notification which slides down over top of the current content. 159 * final Notification.Builder builder = new Notification.Builder(context); 160 * builder.setOngoing(true); 161 * builder.setPriority(Notification.PRIORITY_HIGH); 162 * 163 * // Set notification content intent to take user to the fullscreen UI if user taps on the 164 * // notification body. 165 * builder.setContentIntent(pendingIntent); 166 * // Set full screen intent to trigger display of the fullscreen UI when the notification 167 * // manager deems it appropriate. 168 * builder.setFullScreenIntent(pendingIntent, true); 169 * 170 * // Setup notification content. 171 * builder.setSmallIcon( yourIconResourceId ); 172 * builder.setContentTitle("Your notification title"); 173 * builder.setContentText("Your notification content."); 174 * 175 * // Use builder.addAction(..) to add buttons to answer or reject the call. 176 * 177 * NotificationManager notificationManager = mContext.getSystemService( 178 * NotificationManager.class); 179 * notificationManager.notify(YOUR_CHANNEL_ID, YOUR_TAG, YOUR_ID, builder.build()); 180 * }</pre> 181 * <p> 182 */ 183 public abstract class InCallService extends Service { 184 185 /** 186 * The {@link Intent} that must be declared as handled by the service. 187 */ 188 @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION) 189 public static final String SERVICE_INTERFACE = "android.telecom.InCallService"; 190 191 private static final int MSG_SET_IN_CALL_ADAPTER = 1; 192 private static final int MSG_ADD_CALL = 2; 193 private static final int MSG_UPDATE_CALL = 3; 194 private static final int MSG_SET_POST_DIAL_WAIT = 4; 195 private static final int MSG_ON_CALL_AUDIO_STATE_CHANGED = 5; 196 private static final int MSG_BRING_TO_FOREGROUND = 6; 197 private static final int MSG_ON_CAN_ADD_CALL_CHANGED = 7; 198 private static final int MSG_SILENCE_RINGER = 8; 199 private static final int MSG_ON_CONNECTION_EVENT = 9; 200 private static final int MSG_ON_RTT_UPGRADE_REQUEST = 10; 201 private static final int MSG_ON_RTT_INITIATION_FAILURE = 11; 202 private static final int MSG_ON_HANDOVER_FAILED = 12; 203 private static final int MSG_ON_HANDOVER_COMPLETE = 13; 204 205 /** Default Handler used to consolidate binder method calls onto a single thread. */ 206 private final Handler mHandler = new Handler(Looper.getMainLooper()) { 207 @Override 208 public void handleMessage(Message msg) { 209 if (mPhone == null && msg.what != MSG_SET_IN_CALL_ADAPTER) { 210 return; 211 } 212 213 switch (msg.what) { 214 case MSG_SET_IN_CALL_ADAPTER: 215 String callingPackage = getApplicationContext().getOpPackageName(); 216 mPhone = new Phone(new InCallAdapter((IInCallAdapter) msg.obj), callingPackage, 217 getApplicationContext().getApplicationInfo().targetSdkVersion); 218 mPhone.addListener(mPhoneListener); 219 onPhoneCreated(mPhone); 220 break; 221 case MSG_ADD_CALL: 222 mPhone.internalAddCall((ParcelableCall) msg.obj); 223 break; 224 case MSG_UPDATE_CALL: 225 mPhone.internalUpdateCall((ParcelableCall) msg.obj); 226 break; 227 case MSG_SET_POST_DIAL_WAIT: { 228 SomeArgs args = (SomeArgs) msg.obj; 229 try { 230 String callId = (String) args.arg1; 231 String remaining = (String) args.arg2; 232 mPhone.internalSetPostDialWait(callId, remaining); 233 } finally { 234 args.recycle(); 235 } 236 break; 237 } 238 case MSG_ON_CALL_AUDIO_STATE_CHANGED: 239 mPhone.internalCallAudioStateChanged((CallAudioState) msg.obj); 240 break; 241 case MSG_BRING_TO_FOREGROUND: 242 mPhone.internalBringToForeground(msg.arg1 == 1); 243 break; 244 case MSG_ON_CAN_ADD_CALL_CHANGED: 245 mPhone.internalSetCanAddCall(msg.arg1 == 1); 246 break; 247 case MSG_SILENCE_RINGER: 248 mPhone.internalSilenceRinger(); 249 break; 250 case MSG_ON_CONNECTION_EVENT: { 251 SomeArgs args = (SomeArgs) msg.obj; 252 try { 253 String callId = (String) args.arg1; 254 String event = (String) args.arg2; 255 Bundle extras = (Bundle) args.arg3; 256 mPhone.internalOnConnectionEvent(callId, event, extras); 257 } finally { 258 args.recycle(); 259 } 260 break; 261 } 262 case MSG_ON_RTT_UPGRADE_REQUEST: { 263 String callId = (String) msg.obj; 264 int requestId = msg.arg1; 265 mPhone.internalOnRttUpgradeRequest(callId, requestId); 266 break; 267 } 268 case MSG_ON_RTT_INITIATION_FAILURE: { 269 String callId = (String) msg.obj; 270 int reason = msg.arg1; 271 mPhone.internalOnRttInitiationFailure(callId, reason); 272 break; 273 } 274 case MSG_ON_HANDOVER_FAILED: { 275 String callId = (String) msg.obj; 276 int error = msg.arg1; 277 mPhone.internalOnHandoverFailed(callId, error); 278 break; 279 } 280 case MSG_ON_HANDOVER_COMPLETE: { 281 String callId = (String) msg.obj; 282 mPhone.internalOnHandoverComplete(callId); 283 break; 284 } 285 default: 286 break; 287 } 288 } 289 }; 290 291 /** Manages the binder calls so that the implementor does not need to deal with it. */ 292 private final class InCallServiceBinder extends IInCallService.Stub { 293 @Override setInCallAdapter(IInCallAdapter inCallAdapter)294 public void setInCallAdapter(IInCallAdapter inCallAdapter) { 295 mHandler.obtainMessage(MSG_SET_IN_CALL_ADAPTER, inCallAdapter).sendToTarget(); 296 } 297 298 @Override addCall(ParcelableCall call)299 public void addCall(ParcelableCall call) { 300 mHandler.obtainMessage(MSG_ADD_CALL, call).sendToTarget(); 301 } 302 303 @Override updateCall(ParcelableCall call)304 public void updateCall(ParcelableCall call) { 305 mHandler.obtainMessage(MSG_UPDATE_CALL, call).sendToTarget(); 306 } 307 308 @Override setPostDial(String callId, String remaining)309 public void setPostDial(String callId, String remaining) { 310 // TODO: Unused 311 } 312 313 @Override setPostDialWait(String callId, String remaining)314 public void setPostDialWait(String callId, String remaining) { 315 SomeArgs args = SomeArgs.obtain(); 316 args.arg1 = callId; 317 args.arg2 = remaining; 318 mHandler.obtainMessage(MSG_SET_POST_DIAL_WAIT, args).sendToTarget(); 319 } 320 321 @Override onCallAudioStateChanged(CallAudioState callAudioState)322 public void onCallAudioStateChanged(CallAudioState callAudioState) { 323 mHandler.obtainMessage(MSG_ON_CALL_AUDIO_STATE_CHANGED, callAudioState).sendToTarget(); 324 } 325 326 @Override bringToForeground(boolean showDialpad)327 public void bringToForeground(boolean showDialpad) { 328 mHandler.obtainMessage(MSG_BRING_TO_FOREGROUND, showDialpad ? 1 : 0, 0).sendToTarget(); 329 } 330 331 @Override onCanAddCallChanged(boolean canAddCall)332 public void onCanAddCallChanged(boolean canAddCall) { 333 mHandler.obtainMessage(MSG_ON_CAN_ADD_CALL_CHANGED, canAddCall ? 1 : 0, 0) 334 .sendToTarget(); 335 } 336 337 @Override silenceRinger()338 public void silenceRinger() { 339 mHandler.obtainMessage(MSG_SILENCE_RINGER).sendToTarget(); 340 } 341 342 @Override onConnectionEvent(String callId, String event, Bundle extras)343 public void onConnectionEvent(String callId, String event, Bundle extras) { 344 SomeArgs args = SomeArgs.obtain(); 345 args.arg1 = callId; 346 args.arg2 = event; 347 args.arg3 = extras; 348 mHandler.obtainMessage(MSG_ON_CONNECTION_EVENT, args).sendToTarget(); 349 } 350 351 @Override onRttUpgradeRequest(String callId, int id)352 public void onRttUpgradeRequest(String callId, int id) { 353 mHandler.obtainMessage(MSG_ON_RTT_UPGRADE_REQUEST, id, 0, callId).sendToTarget(); 354 } 355 356 @Override onRttInitiationFailure(String callId, int reason)357 public void onRttInitiationFailure(String callId, int reason) { 358 mHandler.obtainMessage(MSG_ON_RTT_INITIATION_FAILURE, reason, 0, callId).sendToTarget(); 359 } 360 361 @Override onHandoverFailed(String callId, int error)362 public void onHandoverFailed(String callId, int error) { 363 mHandler.obtainMessage(MSG_ON_HANDOVER_FAILED, error, 0, callId).sendToTarget(); 364 } 365 366 @Override onHandoverComplete(String callId)367 public void onHandoverComplete(String callId) { 368 mHandler.obtainMessage(MSG_ON_HANDOVER_COMPLETE, callId).sendToTarget(); 369 } 370 } 371 372 private Phone.Listener mPhoneListener = new Phone.Listener() { 373 /** ${inheritDoc} */ 374 @Override 375 public void onAudioStateChanged(Phone phone, AudioState audioState) { 376 InCallService.this.onAudioStateChanged(audioState); 377 } 378 379 public void onCallAudioStateChanged(Phone phone, CallAudioState callAudioState) { 380 InCallService.this.onCallAudioStateChanged(callAudioState); 381 }; 382 383 /** ${inheritDoc} */ 384 @Override 385 public void onBringToForeground(Phone phone, boolean showDialpad) { 386 InCallService.this.onBringToForeground(showDialpad); 387 } 388 389 /** ${inheritDoc} */ 390 @Override 391 public void onCallAdded(Phone phone, Call call) { 392 InCallService.this.onCallAdded(call); 393 } 394 395 /** ${inheritDoc} */ 396 @Override 397 public void onCallRemoved(Phone phone, Call call) { 398 InCallService.this.onCallRemoved(call); 399 } 400 401 /** ${inheritDoc} */ 402 @Override 403 public void onCanAddCallChanged(Phone phone, boolean canAddCall) { 404 InCallService.this.onCanAddCallChanged(canAddCall); 405 } 406 407 /** ${inheritDoc} */ 408 @Override 409 public void onSilenceRinger(Phone phone) { 410 InCallService.this.onSilenceRinger(); 411 } 412 413 }; 414 415 private Phone mPhone; 416 InCallService()417 public InCallService() { 418 } 419 420 @Override onBind(Intent intent)421 public IBinder onBind(Intent intent) { 422 return new InCallServiceBinder(); 423 } 424 425 @Override onUnbind(Intent intent)426 public boolean onUnbind(Intent intent) { 427 if (mPhone != null) { 428 Phone oldPhone = mPhone; 429 mPhone = null; 430 431 oldPhone.destroy(); 432 // destroy sets all the calls to disconnected if any live ones still exist. Therefore, 433 // it is important to remove the Listener *after* the call to destroy so that 434 // InCallService.on* callbacks are appropriately called. 435 oldPhone.removeListener(mPhoneListener); 436 437 onPhoneDestroyed(oldPhone); 438 } 439 440 return false; 441 } 442 443 /** 444 * Obtain the {@code Phone} associated with this {@code InCallService}. 445 * 446 * @return The {@code Phone} object associated with this {@code InCallService}, or {@code null} 447 * if the {@code InCallService} is not in a state where it has an associated 448 * {@code Phone}. 449 * @hide 450 * @deprecated Use direct methods on InCallService instead of {@link Phone}. 451 */ 452 @SystemApi 453 @Deprecated getPhone()454 public Phone getPhone() { 455 return mPhone; 456 } 457 458 /** 459 * Obtains the current list of {@code Call}s to be displayed by this in-call service. 460 * 461 * @return A list of the relevant {@code Call}s. 462 */ getCalls()463 public final List<Call> getCalls() { 464 return mPhone == null ? Collections.<Call>emptyList() : mPhone.getCalls(); 465 } 466 467 /** 468 * Returns if the device can support additional calls. 469 * 470 * @return Whether the phone supports adding more calls. 471 */ canAddCall()472 public final boolean canAddCall() { 473 return mPhone == null ? false : mPhone.canAddCall(); 474 } 475 476 /** 477 * Obtains the current phone call audio state. 478 * 479 * @return An object encapsulating the audio state. Returns null if the service is not 480 * fully initialized. 481 * @deprecated Use {@link #getCallAudioState()} instead. 482 * @hide 483 */ 484 @Deprecated getAudioState()485 public final AudioState getAudioState() { 486 return mPhone == null ? null : mPhone.getAudioState(); 487 } 488 489 /** 490 * Obtains the current phone call audio state. 491 * 492 * @return An object encapsulating the audio state. Returns null if the service is not 493 * fully initialized. 494 */ getCallAudioState()495 public final CallAudioState getCallAudioState() { 496 return mPhone == null ? null : mPhone.getCallAudioState(); 497 } 498 499 /** 500 * Sets the microphone mute state. When this request is honored, there will be change to 501 * the {@link #getCallAudioState()}. 502 * 503 * @param state {@code true} if the microphone should be muted; {@code false} otherwise. 504 */ setMuted(boolean state)505 public final void setMuted(boolean state) { 506 if (mPhone != null) { 507 mPhone.setMuted(state); 508 } 509 } 510 511 /** 512 * Sets the audio route (speaker, bluetooth, etc...). When this request is honored, there will 513 * be change to the {@link #getCallAudioState()}. 514 * 515 * @param route The audio route to use. 516 */ setAudioRoute(int route)517 public final void setAudioRoute(int route) { 518 if (mPhone != null) { 519 mPhone.setAudioRoute(route); 520 } 521 } 522 523 /** 524 * Request audio routing to a specific bluetooth device. Calling this method may result in 525 * the device routing audio to a different bluetooth device than the one specified if the 526 * bluetooth stack is unable to route audio to the requested device. 527 * A list of available devices can be obtained via 528 * {@link CallAudioState#getSupportedBluetoothDevices()} 529 * 530 * @param bluetoothDevice The bluetooth device to connect to. 531 */ requestBluetoothAudio(@onNull BluetoothDevice bluetoothDevice)532 public final void requestBluetoothAudio(@NonNull BluetoothDevice bluetoothDevice) { 533 if (mPhone != null) { 534 mPhone.requestBluetoothAudio(bluetoothDevice.getAddress()); 535 } 536 } 537 538 /** 539 * Invoked when the {@code Phone} has been created. This is a signal to the in-call experience 540 * to start displaying in-call information to the user. Each instance of {@code InCallService} 541 * will have only one {@code Phone}, and this method will be called exactly once in the lifetime 542 * of the {@code InCallService}. 543 * 544 * @param phone The {@code Phone} object associated with this {@code InCallService}. 545 * @hide 546 * @deprecated Use direct methods on InCallService instead of {@link Phone}. 547 */ 548 @SystemApi 549 @Deprecated onPhoneCreated(Phone phone)550 public void onPhoneCreated(Phone phone) { 551 } 552 553 /** 554 * Invoked when a {@code Phone} has been destroyed. This is a signal to the in-call experience 555 * to stop displaying in-call information to the user. This method will be called exactly once 556 * in the lifetime of the {@code InCallService}, and it will always be called after a previous 557 * call to {@link #onPhoneCreated(Phone)}. 558 * 559 * @param phone The {@code Phone} object associated with this {@code InCallService}. 560 * @hide 561 * @deprecated Use direct methods on InCallService instead of {@link Phone}. 562 */ 563 @SystemApi 564 @Deprecated onPhoneDestroyed(Phone phone)565 public void onPhoneDestroyed(Phone phone) { 566 } 567 568 /** 569 * Called when the audio state changes. 570 * 571 * @param audioState The new {@link AudioState}. 572 * @deprecated Use {@link #onCallAudioStateChanged(CallAudioState) instead}. 573 * @hide 574 */ 575 @Deprecated onAudioStateChanged(AudioState audioState)576 public void onAudioStateChanged(AudioState audioState) { 577 } 578 579 /** 580 * Called when the audio state changes. 581 * 582 * @param audioState The new {@link CallAudioState}. 583 */ onCallAudioStateChanged(CallAudioState audioState)584 public void onCallAudioStateChanged(CallAudioState audioState) { 585 } 586 587 /** 588 * Called to bring the in-call screen to the foreground. The in-call experience should 589 * respond immediately by coming to the foreground to inform the user of the state of 590 * ongoing {@code Call}s. 591 * 592 * @param showDialpad If true, put up the dialpad when the screen is shown. 593 */ onBringToForeground(boolean showDialpad)594 public void onBringToForeground(boolean showDialpad) { 595 } 596 597 /** 598 * Called when a {@code Call} has been added to this in-call session. The in-call user 599 * experience should add necessary state listeners to the specified {@code Call} and 600 * immediately start to show the user information about the existence 601 * and nature of this {@code Call}. Subsequent invocations of {@link #getCalls()} will 602 * include this {@code Call}. 603 * 604 * @param call A newly added {@code Call}. 605 */ onCallAdded(Call call)606 public void onCallAdded(Call call) { 607 } 608 609 /** 610 * Called when a {@code Call} has been removed from this in-call session. The in-call user 611 * experience should remove any state listeners from the specified {@code Call} and 612 * immediately stop displaying any information about this {@code Call}. 613 * Subsequent invocations of {@link #getCalls()} will no longer include this {@code Call}. 614 * 615 * @param call A newly removed {@code Call}. 616 */ onCallRemoved(Call call)617 public void onCallRemoved(Call call) { 618 } 619 620 /** 621 * Called when the ability to add more calls changes. If the phone cannot 622 * support more calls then {@code canAddCall} is set to {@code false}. If it can, then it 623 * is set to {@code true}. This can be used to control the visibility of UI to add more calls. 624 * 625 * @param canAddCall Indicates whether an additional call can be added. 626 */ onCanAddCallChanged(boolean canAddCall)627 public void onCanAddCallChanged(boolean canAddCall) { 628 } 629 630 /** 631 * Called to silence the ringer if a ringing call exists. 632 */ onSilenceRinger()633 public void onSilenceRinger() { 634 } 635 636 /** 637 * Unused; to handle connection events issued by a {@link ConnectionService}, implement the 638 * {@link android.telecom.Call.Callback#onConnectionEvent(Call, String, Bundle)} callback. 639 * <p> 640 * See {@link Connection#sendConnectionEvent(String, Bundle)}. 641 * 642 * @param call The call the event is associated with. 643 * @param event The event. 644 * @param extras Any associated extras. 645 */ onConnectionEvent(Call call, String event, Bundle extras)646 public void onConnectionEvent(Call call, String event, Bundle extras) { 647 } 648 649 /** 650 * Used to issue commands to the {@link Connection.VideoProvider} associated with a 651 * {@link Call}. 652 */ 653 public static abstract class VideoCall { 654 655 /** @hide */ destroy()656 public abstract void destroy(); 657 658 /** 659 * Registers a callback to receive commands and state changes for video calls. 660 * 661 * @param callback The video call callback. 662 */ registerCallback(VideoCall.Callback callback)663 public abstract void registerCallback(VideoCall.Callback callback); 664 665 /** 666 * Registers a callback to receive commands and state changes for video calls. 667 * 668 * @param callback The video call callback. 669 * @param handler A handler which commands and status changes will be delivered to. 670 */ registerCallback(VideoCall.Callback callback, Handler handler)671 public abstract void registerCallback(VideoCall.Callback callback, Handler handler); 672 673 /** 674 * Clears the video call callback set via {@link #registerCallback}. 675 * 676 * @param callback The video call callback to clear. 677 */ unregisterCallback(VideoCall.Callback callback)678 public abstract void unregisterCallback(VideoCall.Callback callback); 679 680 /** 681 * Sets the camera to be used for the outgoing video. 682 * <p> 683 * Handled by {@link Connection.VideoProvider#onSetCamera(String)}. 684 * 685 * @param cameraId The id of the camera (use ids as reported by 686 * {@link CameraManager#getCameraIdList()}). 687 */ setCamera(String cameraId)688 public abstract void setCamera(String cameraId); 689 690 /** 691 * Sets the surface to be used for displaying a preview of what the user's camera is 692 * currently capturing. When video transmission is enabled, this is the video signal which 693 * is sent to the remote device. 694 * <p> 695 * Handled by {@link Connection.VideoProvider#onSetPreviewSurface(Surface)}. 696 * 697 * @param surface The {@link Surface}. 698 */ setPreviewSurface(Surface surface)699 public abstract void setPreviewSurface(Surface surface); 700 701 /** 702 * Sets the surface to be used for displaying the video received from the remote device. 703 * <p> 704 * Handled by {@link Connection.VideoProvider#onSetDisplaySurface(Surface)}. 705 * 706 * @param surface The {@link Surface}. 707 */ setDisplaySurface(Surface surface)708 public abstract void setDisplaySurface(Surface surface); 709 710 /** 711 * Sets the device orientation, in degrees. Assumes that a standard portrait orientation of 712 * the device is 0 degrees. 713 * <p> 714 * Handled by {@link Connection.VideoProvider#onSetDeviceOrientation(int)}. 715 * 716 * @param rotation The device orientation, in degrees. 717 */ setDeviceOrientation(int rotation)718 public abstract void setDeviceOrientation(int rotation); 719 720 /** 721 * Sets camera zoom ratio. 722 * <p> 723 * Handled by {@link Connection.VideoProvider#onSetZoom(float)}. 724 * 725 * @param value The camera zoom ratio. 726 */ setZoom(float value)727 public abstract void setZoom(float value); 728 729 /** 730 * Issues a request to modify the properties of the current video session. 731 * <p> 732 * Example scenarios include: requesting an audio-only call to be upgraded to a 733 * bi-directional video call, turning on or off the user's camera, sending a pause signal 734 * when the {@link InCallService} is no longer the foreground application. 735 * <p> 736 * Handled by 737 * {@link Connection.VideoProvider#onSendSessionModifyRequest(VideoProfile, VideoProfile)}. 738 * 739 * @param requestProfile The requested call video properties. 740 */ sendSessionModifyRequest(VideoProfile requestProfile)741 public abstract void sendSessionModifyRequest(VideoProfile requestProfile); 742 743 /** 744 * Provides a response to a request to change the current call video session 745 * properties. This should be called in response to a request the {@link InCallService} has 746 * received via {@link VideoCall.Callback#onSessionModifyRequestReceived}. 747 * <p> 748 * Handled by 749 * {@link Connection.VideoProvider#onSendSessionModifyResponse(VideoProfile)}. 750 * 751 * @param responseProfile The response call video properties. 752 */ sendSessionModifyResponse(VideoProfile responseProfile)753 public abstract void sendSessionModifyResponse(VideoProfile responseProfile); 754 755 /** 756 * Issues a request to the {@link Connection.VideoProvider} to retrieve the capabilities 757 * of the current camera. The current camera is selected using 758 * {@link VideoCall#setCamera(String)}. 759 * <p> 760 * Camera capabilities are reported to the caller via 761 * {@link VideoCall.Callback#onCameraCapabilitiesChanged(VideoProfile.CameraCapabilities)}. 762 * <p> 763 * Handled by {@link Connection.VideoProvider#onRequestCameraCapabilities()}. 764 */ requestCameraCapabilities()765 public abstract void requestCameraCapabilities(); 766 767 /** 768 * Issues a request to the {@link Connection.VideoProvider} to retrieve the cumulative data 769 * usage for the video component of the current call (in bytes). Data usage is reported 770 * to the caller via {@link VideoCall.Callback#onCallDataUsageChanged}. 771 * <p> 772 * Handled by {@link Connection.VideoProvider#onRequestConnectionDataUsage()}. 773 */ requestCallDataUsage()774 public abstract void requestCallDataUsage(); 775 776 /** 777 * Provides the {@link Connection.VideoProvider} with the {@link Uri} of an image to be 778 * displayed to the peer device when the video signal is paused. 779 * <p> 780 * Handled by {@link Connection.VideoProvider#onSetPauseImage(Uri)}. 781 * 782 * @param uri URI of image to display. 783 */ setPauseImage(Uri uri)784 public abstract void setPauseImage(Uri uri); 785 786 /** 787 * The {@link InCallService} extends this class to provide a means of receiving callbacks 788 * from the {@link Connection.VideoProvider}. 789 * <p> 790 * When the {@link InCallService} receives the 791 * {@link Call.Callback#onVideoCallChanged(Call, VideoCall)} callback, it should create an 792 * instance its {@link VideoCall.Callback} implementation and set it on the 793 * {@link VideoCall} using {@link VideoCall#registerCallback(Callback)}. 794 */ 795 public static abstract class Callback { 796 /** 797 * Called when the {@link Connection.VideoProvider} receives a session modification 798 * request from the peer device. 799 * <p> 800 * The {@link InCallService} may potentially prompt the user to confirm whether they 801 * wish to accept the request, or decide to automatically accept the request. In either 802 * case the {@link InCallService} should call 803 * {@link VideoCall#sendSessionModifyResponse(VideoProfile)} to indicate the video 804 * profile agreed upon. 805 * <p> 806 * Callback originates from 807 * {@link Connection.VideoProvider#receiveSessionModifyRequest(VideoProfile)}. 808 * 809 * @param videoProfile The requested video profile. 810 */ onSessionModifyRequestReceived(VideoProfile videoProfile)811 public abstract void onSessionModifyRequestReceived(VideoProfile videoProfile); 812 813 /** 814 * Called when the {@link Connection.VideoProvider} receives a response to a session 815 * modification request previously sent to the peer device. 816 * <p> 817 * The new video state should not be considered active by the {@link InCallService} 818 * until the {@link Call} video state changes (the 819 * {@link Call.Callback#onDetailsChanged(Call, Call.Details)} callback is triggered 820 * when the video state changes). 821 * <p> 822 * Callback originates from 823 * {@link Connection.VideoProvider#receiveSessionModifyResponse(int, VideoProfile, 824 * VideoProfile)}. 825 * 826 * @param status Status of the session modify request. Valid values are 827 * {@link Connection.VideoProvider#SESSION_MODIFY_REQUEST_SUCCESS}, 828 * {@link Connection.VideoProvider#SESSION_MODIFY_REQUEST_FAIL}, 829 * {@link Connection.VideoProvider#SESSION_MODIFY_REQUEST_INVALID}, 830 * {@link Connection.VideoProvider#SESSION_MODIFY_REQUEST_TIMED_OUT}, 831 * {@link Connection.VideoProvider#SESSION_MODIFY_REQUEST_REJECTED_BY_REMOTE}. 832 * @param requestedProfile The original request which was sent to the peer device. 833 * @param responseProfile The actual profile changes made by the peer device. 834 */ onSessionModifyResponseReceived(int status, VideoProfile requestedProfile, VideoProfile responseProfile)835 public abstract void onSessionModifyResponseReceived(int status, 836 VideoProfile requestedProfile, VideoProfile responseProfile); 837 838 /** 839 * Handles events related to the current video session which the {@link InCallService} 840 * may wish to handle. These are separate from requested changes to the session due to 841 * the underlying protocol or connection. 842 * <p> 843 * Callback originates from 844 * {@link Connection.VideoProvider#handleCallSessionEvent(int)}. 845 * 846 * @param event The event. Valid values are: 847 * {@link Connection.VideoProvider#SESSION_EVENT_RX_PAUSE}, 848 * {@link Connection.VideoProvider#SESSION_EVENT_RX_RESUME}, 849 * {@link Connection.VideoProvider#SESSION_EVENT_TX_START}, 850 * {@link Connection.VideoProvider#SESSION_EVENT_TX_STOP}, 851 * {@link Connection.VideoProvider#SESSION_EVENT_CAMERA_FAILURE}, 852 * {@link Connection.VideoProvider#SESSION_EVENT_CAMERA_READY}, 853 * {@link Connection.VideoProvider#SESSION_EVENT_CAMERA_PERMISSION_ERROR}. 854 */ onCallSessionEvent(int event)855 public abstract void onCallSessionEvent(int event); 856 857 /** 858 * Handles a change to the video dimensions from the peer device. This could happen if, 859 * for example, the peer changes orientation of their device, or switches cameras. 860 * <p> 861 * Callback originates from 862 * {@link Connection.VideoProvider#changePeerDimensions(int, int)}. 863 * 864 * @param width The updated peer video width. 865 * @param height The updated peer video height. 866 */ onPeerDimensionsChanged(int width, int height)867 public abstract void onPeerDimensionsChanged(int width, int height); 868 869 /** 870 * Handles a change to the video quality. 871 * <p> 872 * Callback originates from {@link Connection.VideoProvider#changeVideoQuality(int)}. 873 * 874 * @param videoQuality The updated peer video quality. Valid values: 875 * {@link VideoProfile#QUALITY_HIGH}, 876 * {@link VideoProfile#QUALITY_MEDIUM}, 877 * {@link VideoProfile#QUALITY_LOW}, 878 * {@link VideoProfile#QUALITY_DEFAULT}. 879 */ onVideoQualityChanged(int videoQuality)880 public abstract void onVideoQualityChanged(int videoQuality); 881 882 /** 883 * Handles an update to the total data used for the current video session. 884 * <p> 885 * Used by the {@link Connection.VideoProvider} in response to 886 * {@link VideoCall#requestCallDataUsage()}. May also be called periodically by the 887 * {@link Connection.VideoProvider}. 888 * <p> 889 * Callback originates from {@link Connection.VideoProvider#setCallDataUsage(long)}. 890 * 891 * @param dataUsage The updated data usage (in bytes). 892 */ onCallDataUsageChanged(long dataUsage)893 public abstract void onCallDataUsageChanged(long dataUsage); 894 895 /** 896 * Handles a change in the capabilities of the currently selected camera. 897 * <p> 898 * Used by the {@link Connection.VideoProvider} in response to 899 * {@link VideoCall#requestCameraCapabilities()}. The {@link Connection.VideoProvider} 900 * may also report the camera capabilities after a call to 901 * {@link VideoCall#setCamera(String)}. 902 * <p> 903 * Callback originates from 904 * {@link Connection.VideoProvider#changeCameraCapabilities( 905 * VideoProfile.CameraCapabilities)}. 906 * 907 * @param cameraCapabilities The changed camera capabilities. 908 */ onCameraCapabilitiesChanged( VideoProfile.CameraCapabilities cameraCapabilities)909 public abstract void onCameraCapabilitiesChanged( 910 VideoProfile.CameraCapabilities cameraCapabilities); 911 } 912 } 913 } 914