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.os.Handler;
20 import android.os.IBinder;
21 import android.os.Looper;
22 import android.os.Message;
23 import android.os.RemoteException;
24 import android.telecom.InCallService.VideoCall;
25 import android.view.Surface;
26 
27 import com.android.internal.os.SomeArgs;
28 import com.android.internal.telecom.IVideoCallback;
29 import com.android.internal.telecom.IVideoProvider;
30 
31 /**
32  * Implementation of a Video Call, which allows InCallUi to communicate commands to the underlying
33  * {@link Connection.VideoProvider}, and direct callbacks from the
34  * {@link Connection.VideoProvider} to the appropriate {@link VideoCall.Listener}.
35  *
36  * {@hide}
37  */
38 public class VideoCallImpl extends VideoCall {
39     private static final int MSG_RECEIVE_SESSION_MODIFY_REQUEST = 1;
40     private static final int MSG_RECEIVE_SESSION_MODIFY_RESPONSE = 2;
41     private static final int MSG_HANDLE_CALL_SESSION_EVENT = 3;
42     private static final int MSG_CHANGE_PEER_DIMENSIONS = 4;
43     private static final int MSG_CHANGE_CALL_DATA_USAGE = 5;
44     private static final int MSG_CHANGE_CAMERA_CAPABILITIES = 6;
45 
46     private final IVideoProvider mVideoProvider;
47     private final VideoCallListenerBinder mBinder;
48     private VideoCall.Listener mVideoCallListener;
49 
50     private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
51         @Override
52         public void binderDied() {
53             mVideoProvider.asBinder().unlinkToDeath(this, 0);
54         }
55     };
56 
57     /**
58      * IVideoCallback stub implementation.
59      */
60     private final class VideoCallListenerBinder extends IVideoCallback.Stub {
61         @Override
receiveSessionModifyRequest(VideoProfile videoProfile)62         public void receiveSessionModifyRequest(VideoProfile videoProfile) {
63             mHandler.obtainMessage(MSG_RECEIVE_SESSION_MODIFY_REQUEST,
64                     videoProfile).sendToTarget();
65         }
66 
67         @Override
receiveSessionModifyResponse(int status, VideoProfile requestProfile, VideoProfile responseProfile)68         public void receiveSessionModifyResponse(int status, VideoProfile requestProfile,
69                 VideoProfile responseProfile) {
70             SomeArgs args = SomeArgs.obtain();
71             args.arg1 = status;
72             args.arg2 = requestProfile;
73             args.arg3 = responseProfile;
74             mHandler.obtainMessage(MSG_RECEIVE_SESSION_MODIFY_RESPONSE, args).sendToTarget();
75         }
76 
77         @Override
handleCallSessionEvent(int event)78         public void handleCallSessionEvent(int event) {
79             mHandler.obtainMessage(MSG_HANDLE_CALL_SESSION_EVENT, event).sendToTarget();
80         }
81 
82         @Override
changePeerDimensions(int width, int height)83         public void changePeerDimensions(int width, int height) {
84             SomeArgs args = SomeArgs.obtain();
85             args.arg1 = width;
86             args.arg2 = height;
87             mHandler.obtainMessage(MSG_CHANGE_PEER_DIMENSIONS, args).sendToTarget();
88         }
89 
90         @Override
changeCallDataUsage(int dataUsage)91         public void changeCallDataUsage(int dataUsage) {
92             mHandler.obtainMessage(MSG_CHANGE_CALL_DATA_USAGE, dataUsage).sendToTarget();
93         }
94 
95         @Override
changeCameraCapabilities(CameraCapabilities cameraCapabilities)96         public void changeCameraCapabilities(CameraCapabilities cameraCapabilities) {
97             mHandler.obtainMessage(MSG_CHANGE_CAMERA_CAPABILITIES,
98                     cameraCapabilities).sendToTarget();
99         }
100     }
101 
102     /** Default handler used to consolidate binder method calls onto a single thread. */
103     private final Handler mHandler = new Handler(Looper.getMainLooper()) {
104         @Override
105         public void handleMessage(Message msg) {
106             if (mVideoCallListener == null) {
107                 return;
108             }
109 
110             SomeArgs args;
111             switch (msg.what) {
112                 case MSG_RECEIVE_SESSION_MODIFY_REQUEST:
113                     mVideoCallListener.onSessionModifyRequestReceived((VideoProfile) msg.obj);
114                     break;
115                 case MSG_RECEIVE_SESSION_MODIFY_RESPONSE:
116                     args = (SomeArgs) msg.obj;
117                     try {
118                         int status = (int) args.arg1;
119                         VideoProfile requestProfile = (VideoProfile) args.arg2;
120                         VideoProfile responseProfile = (VideoProfile) args.arg3;
121 
122                         mVideoCallListener.onSessionModifyResponseReceived(
123                                 status, requestProfile, responseProfile);
124                     } finally {
125                         args.recycle();
126                     }
127                     break;
128                 case MSG_HANDLE_CALL_SESSION_EVENT:
129                     mVideoCallListener.onCallSessionEvent((int) msg.obj);
130                     break;
131                 case MSG_CHANGE_PEER_DIMENSIONS:
132                     args = (SomeArgs) msg.obj;
133                     try {
134                         int width = (int) args.arg1;
135                         int height = (int) args.arg2;
136                         mVideoCallListener.onPeerDimensionsChanged(width, height);
137                     } finally {
138                         args.recycle();
139                     }
140                     break;
141                 case MSG_CHANGE_CALL_DATA_USAGE:
142                     mVideoCallListener.onCallDataUsageChanged(msg.arg1);
143                     break;
144                 case MSG_CHANGE_CAMERA_CAPABILITIES:
145                     mVideoCallListener.onCameraCapabilitiesChanged(
146                             (CameraCapabilities) msg.obj);
147                     break;
148                 default:
149                     break;
150             }
151         }
152     };
153 
154     /** {@hide} */
VideoCallImpl(IVideoProvider videoProvider)155     VideoCallImpl(IVideoProvider videoProvider) throws RemoteException {
156         mVideoProvider = videoProvider;
157         mVideoProvider.asBinder().linkToDeath(mDeathRecipient, 0);
158 
159         mBinder = new VideoCallListenerBinder();
160         mVideoProvider.setVideoCallback(mBinder);
161     }
162 
163     /** {@inheritDoc} */
setVideoCallListener(VideoCall.Listener videoCallListener)164     public void setVideoCallListener(VideoCall.Listener videoCallListener) {
165         mVideoCallListener = videoCallListener;
166     }
167 
168     /** {@inheritDoc} */
setCamera(String cameraId)169     public void setCamera(String cameraId) {
170         try {
171             mVideoProvider.setCamera(cameraId);
172         } catch (RemoteException e) {
173         }
174     }
175 
176     /** {@inheritDoc} */
setPreviewSurface(Surface surface)177     public void setPreviewSurface(Surface surface) {
178         try {
179             mVideoProvider.setPreviewSurface(surface);
180         } catch (RemoteException e) {
181         }
182     }
183 
184     /** {@inheritDoc} */
setDisplaySurface(Surface surface)185     public void setDisplaySurface(Surface surface) {
186         try {
187             mVideoProvider.setDisplaySurface(surface);
188         } catch (RemoteException e) {
189         }
190     }
191 
192     /** {@inheritDoc} */
setDeviceOrientation(int rotation)193     public void setDeviceOrientation(int rotation) {
194         try {
195             mVideoProvider.setDeviceOrientation(rotation);
196         } catch (RemoteException e) {
197         }
198     }
199 
200     /** {@inheritDoc} */
setZoom(float value)201     public void setZoom(float value) {
202         try {
203             mVideoProvider.setZoom(value);
204         } catch (RemoteException e) {
205         }
206     }
207 
208     /** {@inheritDoc} */
sendSessionModifyRequest(VideoProfile requestProfile)209     public void sendSessionModifyRequest(VideoProfile requestProfile) {
210         try {
211             mVideoProvider.sendSessionModifyRequest(requestProfile);
212         } catch (RemoteException e) {
213         }
214     }
215 
216     /** {@inheritDoc} */
sendSessionModifyResponse(VideoProfile responseProfile)217     public void sendSessionModifyResponse(VideoProfile responseProfile) {
218         try {
219             mVideoProvider.sendSessionModifyResponse(responseProfile);
220         } catch (RemoteException e) {
221         }
222     }
223 
224     /** {@inheritDoc} */
requestCameraCapabilities()225     public void requestCameraCapabilities() {
226         try {
227             mVideoProvider.requestCameraCapabilities();
228         } catch (RemoteException e) {
229         }
230     }
231 
232     /** {@inheritDoc} */
requestCallDataUsage()233     public void requestCallDataUsage() {
234         try {
235             mVideoProvider.requestCallDataUsage();
236         } catch (RemoteException e) {
237         }
238     }
239 
240     /** {@inheritDoc} */
setPauseImage(String uri)241     public void setPauseImage(String uri) {
242         try {
243             mVideoProvider.setPauseImage(uri);
244         } catch (RemoteException e) {
245         }
246     }
247 }