Home | History | Annotate | Download | only in telecom
      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
    195         public void setInCallAdapter(IInCallAdapter inCallAdapter) {
    196             mHandler.obtainMessage(MSG_SET_IN_CALL_ADAPTER, inCallAdapter).sendToTarget();
    197         }
    198 
    199         @Override
    200         public void addCall(ParcelableCall call) {
    201             mHandler.obtainMessage(MSG_ADD_CALL, call).sendToTarget();
    202         }
    203 
    204         @Override
    205         public void updateCall(ParcelableCall call) {
    206             mHandler.obtainMessage(MSG_UPDATE_CALL, call).sendToTarget();
    207         }
    208 
    209         @Override
    210         public void setPostDial(String callId, String remaining) {
    211             // TODO: Unused
    212         }
    213 
    214         @Override
    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
    223         public void onCallAudioStateChanged(CallAudioState callAudioState) {
    224             mHandler.obtainMessage(MSG_ON_CALL_AUDIO_STATE_CHANGED, callAudioState).sendToTarget();
    225         }
    226 
    227         @Override
    228         public void bringToForeground(boolean showDialpad) {
    229             mHandler.obtainMessage(MSG_BRING_TO_FOREGROUND, showDialpad ? 1 : 0, 0).sendToTarget();
    230         }
    231 
    232         @Override
    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
    239         public void silenceRinger() {
    240             mHandler.obtainMessage(MSG_SILENCE_RINGER).sendToTarget();
    241         }
    242 
    243         @Override
    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
    253         public void onRttUpgradeRequest(String callId, int id) {
    254             mHandler.obtainMessage(MSG_ON_RTT_UPGRADE_REQUEST, id, 0, callId).sendToTarget();
    255         }
    256 
    257         @Override
    258         public void onRttInitiationFailure(String callId, int reason) {
    259             mHandler.obtainMessage(MSG_ON_RTT_INITIATION_FAILURE, reason, 0, callId).sendToTarget();
    260         }
    261 
    262         @Override
    263         public void onHandoverFailed(String callId, int error) {
    264             mHandler.obtainMessage(MSG_ON_HANDOVER_FAILED, error, 0, callId).sendToTarget();
    265         }
    266 
    267         @Override
    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 
    318     public InCallService() {
    319     }
    320 
    321     @Override
    322     public IBinder onBind(Intent intent) {
    323         return new InCallServiceBinder();
    324     }
    325 
    326     @Override
    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
    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      */
    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      */
    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
    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      */
    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      */
    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      */
    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      */
    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
    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
    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
    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      */
    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      */
    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      */
    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      */
    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      */
    528     public void onCanAddCallChanged(boolean canAddCall) {
    529     }
    530 
    531     /**
    532      * Called to silence the ringer if a ringing call exists.
    533      */
    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      */
    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 */
    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          */
    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          */
    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          */
    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          */
    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          */
    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          */
    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          */
    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          */
    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          */
    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          */
    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          */
    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          */
    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          */
    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              */
    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              */
    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              */
    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              */
    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              */
    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              */
    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              */
    810             public abstract void onCameraCapabilitiesChanged(
    811                     VideoProfile.CameraCapabilities cameraCapabilities);
    812         }
    813     }
    814 }
    815