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