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