Home | History | Annotate | Download | only in telecom
      1 /*
      2  * Copyright (C) 2014 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.net.Uri;
     20 import android.os.Handler;
     21 import android.os.IBinder;
     22 import android.os.Looper;
     23 import android.os.Message;
     24 import android.os.RemoteException;
     25 import android.telecom.InCallService.VideoCall;
     26 import android.view.Surface;
     27 
     28 import com.android.internal.annotations.VisibleForTesting;
     29 import com.android.internal.os.SomeArgs;
     30 import com.android.internal.telecom.IVideoCallback;
     31 import com.android.internal.telecom.IVideoProvider;
     32 
     33 /**
     34  * Implementation of a Video Call, which allows InCallUi to communicate commands to the underlying
     35  * {@link Connection.VideoProvider}, and direct callbacks from the
     36  * {@link Connection.VideoProvider} to the appropriate {@link VideoCall.Listener}.
     37  *
     38  * {@hide}
     39  */
     40 public class VideoCallImpl extends VideoCall {
     41 
     42     private final IVideoProvider mVideoProvider;
     43     private final VideoCallListenerBinder mBinder;
     44     private VideoCall.Callback mCallback;
     45     private int mVideoQuality = VideoProfile.QUALITY_UNKNOWN;
     46     private int mVideoState = VideoProfile.STATE_AUDIO_ONLY;
     47     private final String mCallingPackageName;
     48 
     49     private int mTargetSdkVersion;
     50 
     51     private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
     52         @Override
     53         public void binderDied() {
     54             mVideoProvider.asBinder().unlinkToDeath(this, 0);
     55         }
     56     };
     57 
     58     /**
     59      * IVideoCallback stub implementation.
     60      */
     61     private final class VideoCallListenerBinder extends IVideoCallback.Stub {
     62         @Override
     63         public void receiveSessionModifyRequest(VideoProfile videoProfile) {
     64             if (mHandler == null) {
     65                 return;
     66             }
     67             mHandler.obtainMessage(MessageHandler.MSG_RECEIVE_SESSION_MODIFY_REQUEST,
     68                     videoProfile).sendToTarget();
     69 
     70         }
     71 
     72         @Override
     73         public void receiveSessionModifyResponse(int status, VideoProfile requestProfile,
     74                 VideoProfile responseProfile) {
     75             if (mHandler == null) {
     76                 return;
     77             }
     78             SomeArgs args = SomeArgs.obtain();
     79             args.arg1 = status;
     80             args.arg2 = requestProfile;
     81             args.arg3 = responseProfile;
     82             mHandler.obtainMessage(MessageHandler.MSG_RECEIVE_SESSION_MODIFY_RESPONSE, args)
     83                     .sendToTarget();
     84         }
     85 
     86         @Override
     87         public void handleCallSessionEvent(int event) {
     88             if (mHandler == null) {
     89                 return;
     90             }
     91             mHandler.obtainMessage(MessageHandler.MSG_HANDLE_CALL_SESSION_EVENT, event)
     92                     .sendToTarget();
     93         }
     94 
     95         @Override
     96         public void changePeerDimensions(int width, int height) {
     97             if (mHandler == null) {
     98                 return;
     99             }
    100             SomeArgs args = SomeArgs.obtain();
    101             args.arg1 = width;
    102             args.arg2 = height;
    103             mHandler.obtainMessage(MessageHandler.MSG_CHANGE_PEER_DIMENSIONS, args).sendToTarget();
    104         }
    105 
    106         @Override
    107         public void changeVideoQuality(int videoQuality) {
    108             if (mHandler == null) {
    109                 return;
    110             }
    111             mHandler.obtainMessage(MessageHandler.MSG_CHANGE_VIDEO_QUALITY, videoQuality, 0)
    112                     .sendToTarget();
    113         }
    114 
    115         @Override
    116         public void changeCallDataUsage(long dataUsage) {
    117             if (mHandler == null) {
    118                 return;
    119             }
    120             mHandler.obtainMessage(MessageHandler.MSG_CHANGE_CALL_DATA_USAGE, dataUsage)
    121                     .sendToTarget();
    122         }
    123 
    124         @Override
    125         public void changeCameraCapabilities(VideoProfile.CameraCapabilities cameraCapabilities) {
    126             if (mHandler == null) {
    127                 return;
    128             }
    129             mHandler.obtainMessage(MessageHandler.MSG_CHANGE_CAMERA_CAPABILITIES,
    130                     cameraCapabilities).sendToTarget();
    131         }
    132     }
    133 
    134     /** Default handler used to consolidate binder method calls onto a single thread. */
    135     private final class MessageHandler extends Handler {
    136         private static final int MSG_RECEIVE_SESSION_MODIFY_REQUEST = 1;
    137         private static final int MSG_RECEIVE_SESSION_MODIFY_RESPONSE = 2;
    138         private static final int MSG_HANDLE_CALL_SESSION_EVENT = 3;
    139         private static final int MSG_CHANGE_PEER_DIMENSIONS = 4;
    140         private static final int MSG_CHANGE_CALL_DATA_USAGE = 5;
    141         private static final int MSG_CHANGE_CAMERA_CAPABILITIES = 6;
    142         private static final int MSG_CHANGE_VIDEO_QUALITY = 7;
    143 
    144         public MessageHandler(Looper looper) {
    145             super(looper);
    146         }
    147 
    148         @Override
    149         public void handleMessage(Message msg) {
    150             if (mCallback == null) {
    151                 return;
    152             }
    153 
    154             SomeArgs args;
    155             switch (msg.what) {
    156                 case MSG_RECEIVE_SESSION_MODIFY_REQUEST:
    157                     mCallback.onSessionModifyRequestReceived((VideoProfile) msg.obj);
    158                     break;
    159                 case MSG_RECEIVE_SESSION_MODIFY_RESPONSE:
    160                     args = (SomeArgs) msg.obj;
    161                     try {
    162                         int status = (int) args.arg1;
    163                         VideoProfile requestProfile = (VideoProfile) args.arg2;
    164                         VideoProfile responseProfile = (VideoProfile) args.arg3;
    165 
    166                         mCallback.onSessionModifyResponseReceived(
    167                                 status, requestProfile, responseProfile);
    168                     } finally {
    169                         args.recycle();
    170                     }
    171                     break;
    172                 case MSG_HANDLE_CALL_SESSION_EVENT:
    173                     mCallback.onCallSessionEvent((int) msg.obj);
    174                     break;
    175                 case MSG_CHANGE_PEER_DIMENSIONS:
    176                     args = (SomeArgs) msg.obj;
    177                     try {
    178                         int width = (int) args.arg1;
    179                         int height = (int) args.arg2;
    180                         mCallback.onPeerDimensionsChanged(width, height);
    181                     } finally {
    182                         args.recycle();
    183                     }
    184                     break;
    185                 case MSG_CHANGE_CALL_DATA_USAGE:
    186                     mCallback.onCallDataUsageChanged((long) msg.obj);
    187                     break;
    188                 case MSG_CHANGE_CAMERA_CAPABILITIES:
    189                     mCallback.onCameraCapabilitiesChanged(
    190                             (VideoProfile.CameraCapabilities) msg.obj);
    191                     break;
    192                 case MSG_CHANGE_VIDEO_QUALITY:
    193                     mVideoQuality = msg.arg1;
    194                     mCallback.onVideoQualityChanged(msg.arg1);
    195                     break;
    196                 default:
    197                     break;
    198             }
    199         }
    200     };
    201 
    202     private Handler mHandler;
    203 
    204     VideoCallImpl(IVideoProvider videoProvider, String callingPackageName, int targetSdkVersion)
    205             throws RemoteException {
    206         mVideoProvider = videoProvider;
    207         mVideoProvider.asBinder().linkToDeath(mDeathRecipient, 0);
    208 
    209         mBinder = new VideoCallListenerBinder();
    210         mVideoProvider.addVideoCallback(mBinder);
    211         mCallingPackageName = callingPackageName;
    212         setTargetSdkVersion(targetSdkVersion);
    213     }
    214 
    215     @VisibleForTesting
    216     public void setTargetSdkVersion(int sdkVersion) {
    217         mTargetSdkVersion = sdkVersion;
    218     }
    219 
    220     public void destroy() {
    221         unregisterCallback(mCallback);
    222     }
    223 
    224     /** {@inheritDoc} */
    225     public void registerCallback(VideoCall.Callback callback) {
    226         registerCallback(callback, null);
    227     }
    228 
    229     /** {@inheritDoc} */
    230     public void registerCallback(VideoCall.Callback callback, Handler handler) {
    231         mCallback = callback;
    232         if (handler == null) {
    233             mHandler = new MessageHandler(Looper.getMainLooper());
    234         } else {
    235             mHandler = new MessageHandler(handler.getLooper());
    236         }
    237     }
    238 
    239     /** {@inheritDoc} */
    240     public void unregisterCallback(VideoCall.Callback callback) {
    241         if (callback != mCallback) {
    242             return;
    243         }
    244 
    245         mCallback = null;
    246         try {
    247             mVideoProvider.removeVideoCallback(mBinder);
    248         } catch (RemoteException e) {
    249         }
    250     }
    251 
    252     /** {@inheritDoc} */
    253     public void setCamera(String cameraId) {
    254         try {
    255             Log.w(this, "setCamera: cameraId=%s, calling=%s", cameraId, mCallingPackageName);
    256             mVideoProvider.setCamera(cameraId, mCallingPackageName, mTargetSdkVersion);
    257         } catch (RemoteException e) {
    258         }
    259     }
    260 
    261     /** {@inheritDoc} */
    262     public void setPreviewSurface(Surface surface) {
    263         try {
    264             mVideoProvider.setPreviewSurface(surface);
    265         } catch (RemoteException e) {
    266         }
    267     }
    268 
    269     /** {@inheritDoc} */
    270     public void setDisplaySurface(Surface surface) {
    271         try {
    272             mVideoProvider.setDisplaySurface(surface);
    273         } catch (RemoteException e) {
    274         }
    275     }
    276 
    277     /** {@inheritDoc} */
    278     public void setDeviceOrientation(int rotation) {
    279         try {
    280             mVideoProvider.setDeviceOrientation(rotation);
    281         } catch (RemoteException e) {
    282         }
    283     }
    284 
    285     /** {@inheritDoc} */
    286     public void setZoom(float value) {
    287         try {
    288             mVideoProvider.setZoom(value);
    289         } catch (RemoteException e) {
    290         }
    291     }
    292 
    293     /**
    294      * Sends a session modification request to the video provider.
    295      * <p>
    296      * The {@link InCallService} will create the {@code requestProfile} based on the current
    297      * video state (i.e. {@link Call.Details#getVideoState()}).  It is, however, possible that the
    298      * video state maintained by the {@link InCallService} could get out of sync with what is known
    299      * by the {@link android.telecom.Connection.VideoProvider}.  To remove ambiguity, the
    300      * {@link VideoCallImpl} passes along the pre-modify video profile to the {@code VideoProvider}
    301      * to ensure it has full context of the requested change.
    302      *
    303      * @param requestProfile The requested video profile.
    304      */
    305     public void sendSessionModifyRequest(VideoProfile requestProfile) {
    306         try {
    307             VideoProfile originalProfile = new VideoProfile(mVideoState, mVideoQuality);
    308 
    309             mVideoProvider.sendSessionModifyRequest(originalProfile, requestProfile);
    310         } catch (RemoteException e) {
    311         }
    312     }
    313 
    314     /** {@inheritDoc} */
    315     public void sendSessionModifyResponse(VideoProfile responseProfile) {
    316         try {
    317             mVideoProvider.sendSessionModifyResponse(responseProfile);
    318         } catch (RemoteException e) {
    319         }
    320     }
    321 
    322     /** {@inheritDoc} */
    323     public void requestCameraCapabilities() {
    324         try {
    325             mVideoProvider.requestCameraCapabilities();
    326         } catch (RemoteException e) {
    327         }
    328     }
    329 
    330     /** {@inheritDoc} */
    331     public void requestCallDataUsage() {
    332         try {
    333             mVideoProvider.requestCallDataUsage();
    334         } catch (RemoteException e) {
    335         }
    336     }
    337 
    338     /** {@inheritDoc} */
    339     public void setPauseImage(Uri uri) {
    340         try {
    341             mVideoProvider.setPauseImage(uri);
    342         } catch (RemoteException e) {
    343         }
    344     }
    345 
    346     /**
    347      * Sets the video state for the current video call.
    348      * @param videoState the new video state.
    349      */
    350     public void setVideoState(int videoState) {
    351         mVideoState = videoState;
    352     }
    353 }
    354