• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
receiveSessionModifyRequest(VideoProfile videoProfile)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
receiveSessionModifyResponse(int status, VideoProfile requestProfile, VideoProfile responseProfile)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
handleCallSessionEvent(int event)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
changePeerDimensions(int width, int height)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
changeVideoQuality(int videoQuality)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
changeCallDataUsage(long dataUsage)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
changeCameraCapabilities(VideoProfile.CameraCapabilities cameraCapabilities)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 
MessageHandler(Looper looper)140         public MessageHandler(Looper looper) {
141             super(looper);
142         }
143 
144         @Override
handleMessage(Message msg)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 
VideoCallImpl(IVideoProvider videoProvider)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 
destroy()208     public void destroy() {
209         unregisterCallback(mCallback);
210     }
211 
212     /** {@inheritDoc} */
registerCallback(VideoCall.Callback callback)213     public void registerCallback(VideoCall.Callback callback) {
214         registerCallback(callback, null);
215     }
216 
217     /** {@inheritDoc} */
registerCallback(VideoCall.Callback callback, Handler handler)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} */
unregisterCallback(VideoCall.Callback callback)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} */
setCamera(String cameraId)241     public void setCamera(String cameraId) {
242         try {
243             mVideoProvider.setCamera(cameraId);
244         } catch (RemoteException e) {
245         }
246     }
247 
248     /** {@inheritDoc} */
setPreviewSurface(Surface surface)249     public void setPreviewSurface(Surface surface) {
250         try {
251             mVideoProvider.setPreviewSurface(surface);
252         } catch (RemoteException e) {
253         }
254     }
255 
256     /** {@inheritDoc} */
setDisplaySurface(Surface surface)257     public void setDisplaySurface(Surface surface) {
258         try {
259             mVideoProvider.setDisplaySurface(surface);
260         } catch (RemoteException e) {
261         }
262     }
263 
264     /** {@inheritDoc} */
setDeviceOrientation(int rotation)265     public void setDeviceOrientation(int rotation) {
266         try {
267             mVideoProvider.setDeviceOrientation(rotation);
268         } catch (RemoteException e) {
269         }
270     }
271 
272     /** {@inheritDoc} */
setZoom(float value)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      */
sendSessionModifyRequest(VideoProfile requestProfile)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} */
sendSessionModifyResponse(VideoProfile responseProfile)302     public void sendSessionModifyResponse(VideoProfile responseProfile) {
303         try {
304             mVideoProvider.sendSessionModifyResponse(responseProfile);
305         } catch (RemoteException e) {
306         }
307     }
308 
309     /** {@inheritDoc} */
requestCameraCapabilities()310     public void requestCameraCapabilities() {
311         try {
312             mVideoProvider.requestCameraCapabilities();
313         } catch (RemoteException e) {
314         }
315     }
316 
317     /** {@inheritDoc} */
requestCallDataUsage()318     public void requestCallDataUsage() {
319         try {
320             mVideoProvider.requestCallDataUsage();
321         } catch (RemoteException e) {
322         }
323     }
324 
325     /** {@inheritDoc} */
setPauseImage(Uri uri)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      */
setVideoState(int videoState)337     public void setVideoState(int videoState) {
338         mVideoState = videoState;
339     }
340 }
341