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