• 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.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
receiveSessionModifyRequest(VideoProfile videoProfile)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
receiveSessionModifyResponse(int status, VideoProfile requestProfile, VideoProfile responseProfile)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
handleCallSessionEvent(int event)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
changePeerDimensions(int width, int height)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
changeVideoQuality(int videoQuality)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
changeCallDataUsage(long dataUsage)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
changeCameraCapabilities(VideoProfile.CameraCapabilities cameraCapabilities)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 
MessageHandler(Looper looper)144         public MessageHandler(Looper looper) {
145             super(looper);
146         }
147 
148         @Override
handleMessage(Message msg)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 
VideoCallImpl(IVideoProvider videoProvider, String callingPackageName, int targetSdkVersion)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
setTargetSdkVersion(int sdkVersion)216     public void setTargetSdkVersion(int sdkVersion) {
217         mTargetSdkVersion = sdkVersion;
218     }
219 
destroy()220     public void destroy() {
221         unregisterCallback(mCallback);
222     }
223 
224     /** {@inheritDoc} */
registerCallback(VideoCall.Callback callback)225     public void registerCallback(VideoCall.Callback callback) {
226         registerCallback(callback, null);
227     }
228 
229     /** {@inheritDoc} */
registerCallback(VideoCall.Callback callback, Handler handler)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} */
unregisterCallback(VideoCall.Callback callback)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} */
setCamera(String cameraId)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} */
setPreviewSurface(Surface surface)262     public void setPreviewSurface(Surface surface) {
263         try {
264             mVideoProvider.setPreviewSurface(surface);
265         } catch (RemoteException e) {
266         }
267     }
268 
269     /** {@inheritDoc} */
setDisplaySurface(Surface surface)270     public void setDisplaySurface(Surface surface) {
271         try {
272             mVideoProvider.setDisplaySurface(surface);
273         } catch (RemoteException e) {
274         }
275     }
276 
277     /** {@inheritDoc} */
setDeviceOrientation(int rotation)278     public void setDeviceOrientation(int rotation) {
279         try {
280             mVideoProvider.setDeviceOrientation(rotation);
281         } catch (RemoteException e) {
282         }
283     }
284 
285     /** {@inheritDoc} */
setZoom(float value)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      */
sendSessionModifyRequest(VideoProfile requestProfile)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} */
sendSessionModifyResponse(VideoProfile responseProfile)315     public void sendSessionModifyResponse(VideoProfile responseProfile) {
316         try {
317             mVideoProvider.sendSessionModifyResponse(responseProfile);
318         } catch (RemoteException e) {
319         }
320     }
321 
322     /** {@inheritDoc} */
requestCameraCapabilities()323     public void requestCameraCapabilities() {
324         try {
325             mVideoProvider.requestCameraCapabilities();
326         } catch (RemoteException e) {
327         }
328     }
329 
330     /** {@inheritDoc} */
requestCallDataUsage()331     public void requestCallDataUsage() {
332         try {
333             mVideoProvider.requestCallDataUsage();
334         } catch (RemoteException e) {
335         }
336     }
337 
338     /** {@inheritDoc} */
setPauseImage(Uri uri)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      */
setVideoState(int videoState)350     public void setVideoState(int videoState) {
351         mVideoState = videoState;
352     }
353 }
354