blob: 4a1aa0a8ffa4bf8eb38c74e9779756e4a679bf9b [file] [log] [blame]
Andrew Lee50aca232014-07-22 16:41:54 -07001/*
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
Tyler Gunnef9f6f92014-09-12 22:16:17 -070017package android.telecom;
Andrew Lee50aca232014-07-22 16:41:54 -070018
Mathew Inwood42346d12018-08-01 11:33:05 +010019import android.annotation.UnsupportedAppUsage;
Yorke Lee32f24732015-05-12 16:18:03 -070020import android.net.Uri;
Tyler Gunn17933eb2019-03-05 13:58:45 -080021import android.os.Build;
Andrew Lee50aca232014-07-22 16:41:54 -070022import android.os.Handler;
23import android.os.IBinder;
24import android.os.Looper;
25import android.os.Message;
26import android.os.RemoteException;
Tyler Gunnef9f6f92014-09-12 22:16:17 -070027import android.telecom.InCallService.VideoCall;
Andrew Lee50aca232014-07-22 16:41:54 -070028import android.view.Surface;
29
Brad Ebinger0d55a302017-03-20 13:16:28 -070030import com.android.internal.annotations.VisibleForTesting;
Andrew Lee50aca232014-07-22 16:41:54 -070031import com.android.internal.os.SomeArgs;
Tyler Gunnef9f6f92014-09-12 22:16:17 -070032import com.android.internal.telecom.IVideoCallback;
33import com.android.internal.telecom.IVideoProvider;
Andrew Lee50aca232014-07-22 16:41:54 -070034
Tyler Gunnd1fdf3a2019-11-05 15:47:58 -080035import java.util.NoSuchElementException;
36
Andrew Lee50aca232014-07-22 16:41:54 -070037/**
38 * Implementation of a Video Call, which allows InCallUi to communicate commands to the underlying
Ihab Awadb19a0bc2014-08-07 19:46:01 -070039 * {@link Connection.VideoProvider}, and direct callbacks from the
40 * {@link Connection.VideoProvider} to the appropriate {@link VideoCall.Listener}.
41 *
42 * {@hide}
Andrew Lee50aca232014-07-22 16:41:54 -070043 */
44public class VideoCallImpl extends VideoCall {
Andrew Lee50aca232014-07-22 16:41:54 -070045
Ihab Awadb19a0bc2014-08-07 19:46:01 -070046 private final IVideoProvider mVideoProvider;
Andrew Lee50aca232014-07-22 16:41:54 -070047 private final VideoCallListenerBinder mBinder;
Andrew Leeda80c872015-04-15 14:09:50 -070048 private VideoCall.Callback mCallback;
Tyler Gunn45382162015-05-06 08:52:27 -070049 private int mVideoQuality = VideoProfile.QUALITY_UNKNOWN;
Tyler Gunn584ba6c2015-12-08 10:53:41 -080050 private int mVideoState = VideoProfile.STATE_AUDIO_ONLY;
Tyler Gunnbf9c6fd2016-11-09 10:19:23 -080051 private final String mCallingPackageName;
Brad Ebinger0d55a302017-03-20 13:16:28 -070052
53 private int mTargetSdkVersion;
Andrew Lee50aca232014-07-22 16:41:54 -070054
55 private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
56 @Override
57 public void binderDied() {
Tyler Gunnd1fdf3a2019-11-05 15:47:58 -080058 try {
59 mVideoProvider.asBinder().unlinkToDeath(this, 0);
60 } catch (NoSuchElementException nse) {
61 // Already unlinked in destroy below.
62 }
Andrew Lee50aca232014-07-22 16:41:54 -070063 }
64 };
65
66 /**
Ihab Awadb19a0bc2014-08-07 19:46:01 -070067 * IVideoCallback stub implementation.
Andrew Lee50aca232014-07-22 16:41:54 -070068 */
Ihab Awadb19a0bc2014-08-07 19:46:01 -070069 private final class VideoCallListenerBinder extends IVideoCallback.Stub {
Andrew Lee50aca232014-07-22 16:41:54 -070070 @Override
Ihab Awadb19a0bc2014-08-07 19:46:01 -070071 public void receiveSessionModifyRequest(VideoProfile videoProfile) {
Tyler Gunne988cf72015-05-28 15:47:06 -070072 if (mHandler == null) {
73 return;
74 }
Andrew Lee011728f2015-04-23 15:47:06 -070075 mHandler.obtainMessage(MessageHandler.MSG_RECEIVE_SESSION_MODIFY_REQUEST,
Ihab Awadb19a0bc2014-08-07 19:46:01 -070076 videoProfile).sendToTarget();
Tyler Gunne988cf72015-05-28 15:47:06 -070077
Andrew Lee50aca232014-07-22 16:41:54 -070078 }
79
80 @Override
Ihab Awadb19a0bc2014-08-07 19:46:01 -070081 public void receiveSessionModifyResponse(int status, VideoProfile requestProfile,
82 VideoProfile responseProfile) {
Tyler Gunne988cf72015-05-28 15:47:06 -070083 if (mHandler == null) {
84 return;
85 }
Andrew Lee50aca232014-07-22 16:41:54 -070086 SomeArgs args = SomeArgs.obtain();
87 args.arg1 = status;
88 args.arg2 = requestProfile;
89 args.arg3 = responseProfile;
Andrew Lee011728f2015-04-23 15:47:06 -070090 mHandler.obtainMessage(MessageHandler.MSG_RECEIVE_SESSION_MODIFY_RESPONSE, args)
91 .sendToTarget();
Andrew Lee50aca232014-07-22 16:41:54 -070092 }
93
94 @Override
95 public void handleCallSessionEvent(int event) {
Tyler Gunne988cf72015-05-28 15:47:06 -070096 if (mHandler == null) {
97 return;
98 }
Andrew Lee011728f2015-04-23 15:47:06 -070099 mHandler.obtainMessage(MessageHandler.MSG_HANDLE_CALL_SESSION_EVENT, event)
100 .sendToTarget();
Andrew Lee50aca232014-07-22 16:41:54 -0700101 }
102
103 @Override
104 public void changePeerDimensions(int width, int height) {
Tyler Gunne988cf72015-05-28 15:47:06 -0700105 if (mHandler == null) {
106 return;
107 }
Andrew Lee50aca232014-07-22 16:41:54 -0700108 SomeArgs args = SomeArgs.obtain();
109 args.arg1 = width;
110 args.arg2 = height;
Andrew Lee011728f2015-04-23 15:47:06 -0700111 mHandler.obtainMessage(MessageHandler.MSG_CHANGE_PEER_DIMENSIONS, args).sendToTarget();
Andrew Lee50aca232014-07-22 16:41:54 -0700112 }
113
114 @Override
Rekha Kumar07366812015-03-24 16:42:31 -0700115 public void changeVideoQuality(int videoQuality) {
Tyler Gunne988cf72015-05-28 15:47:06 -0700116 if (mHandler == null) {
117 return;
118 }
Andrew Lee011728f2015-04-23 15:47:06 -0700119 mHandler.obtainMessage(MessageHandler.MSG_CHANGE_VIDEO_QUALITY, videoQuality, 0)
120 .sendToTarget();
Rekha Kumar07366812015-03-24 16:42:31 -0700121 }
122
123 @Override
124 public void changeCallDataUsage(long dataUsage) {
Tyler Gunne988cf72015-05-28 15:47:06 -0700125 if (mHandler == null) {
126 return;
127 }
Andrew Lee011728f2015-04-23 15:47:06 -0700128 mHandler.obtainMessage(MessageHandler.MSG_CHANGE_CALL_DATA_USAGE, dataUsage)
129 .sendToTarget();
Andrew Lee50aca232014-07-22 16:41:54 -0700130 }
131
132 @Override
Yorke Lee400470f2015-05-12 13:31:25 -0700133 public void changeCameraCapabilities(VideoProfile.CameraCapabilities cameraCapabilities) {
Tyler Gunne988cf72015-05-28 15:47:06 -0700134 if (mHandler == null) {
135 return;
136 }
Andrew Lee011728f2015-04-23 15:47:06 -0700137 mHandler.obtainMessage(MessageHandler.MSG_CHANGE_CAMERA_CAPABILITIES,
Andrew Lee50aca232014-07-22 16:41:54 -0700138 cameraCapabilities).sendToTarget();
139 }
140 }
141
142 /** Default handler used to consolidate binder method calls onto a single thread. */
Andrew Lee011728f2015-04-23 15:47:06 -0700143 private final class MessageHandler extends Handler {
144 private static final int MSG_RECEIVE_SESSION_MODIFY_REQUEST = 1;
145 private static final int MSG_RECEIVE_SESSION_MODIFY_RESPONSE = 2;
146 private static final int MSG_HANDLE_CALL_SESSION_EVENT = 3;
147 private static final int MSG_CHANGE_PEER_DIMENSIONS = 4;
148 private static final int MSG_CHANGE_CALL_DATA_USAGE = 5;
149 private static final int MSG_CHANGE_CAMERA_CAPABILITIES = 6;
150 private static final int MSG_CHANGE_VIDEO_QUALITY = 7;
151
152 public MessageHandler(Looper looper) {
153 super(looper);
154 }
155
Andrew Lee50aca232014-07-22 16:41:54 -0700156 @Override
157 public void handleMessage(Message msg) {
Andrew Leeda80c872015-04-15 14:09:50 -0700158 if (mCallback == null) {
Andrew Lee50aca232014-07-22 16:41:54 -0700159 return;
160 }
161
162 SomeArgs args;
163 switch (msg.what) {
164 case MSG_RECEIVE_SESSION_MODIFY_REQUEST:
Andrew Leeda80c872015-04-15 14:09:50 -0700165 mCallback.onSessionModifyRequestReceived((VideoProfile) msg.obj);
Andrew Lee50aca232014-07-22 16:41:54 -0700166 break;
167 case MSG_RECEIVE_SESSION_MODIFY_RESPONSE:
168 args = (SomeArgs) msg.obj;
169 try {
170 int status = (int) args.arg1;
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700171 VideoProfile requestProfile = (VideoProfile) args.arg2;
172 VideoProfile responseProfile = (VideoProfile) args.arg3;
Andrew Lee50aca232014-07-22 16:41:54 -0700173
Andrew Leeda80c872015-04-15 14:09:50 -0700174 mCallback.onSessionModifyResponseReceived(
Andrew Lee50aca232014-07-22 16:41:54 -0700175 status, requestProfile, responseProfile);
176 } finally {
177 args.recycle();
178 }
179 break;
180 case MSG_HANDLE_CALL_SESSION_EVENT:
Andrew Leeda80c872015-04-15 14:09:50 -0700181 mCallback.onCallSessionEvent((int) msg.obj);
Andrew Lee50aca232014-07-22 16:41:54 -0700182 break;
183 case MSG_CHANGE_PEER_DIMENSIONS:
184 args = (SomeArgs) msg.obj;
185 try {
186 int width = (int) args.arg1;
187 int height = (int) args.arg2;
Andrew Leeda80c872015-04-15 14:09:50 -0700188 mCallback.onPeerDimensionsChanged(width, height);
Andrew Lee50aca232014-07-22 16:41:54 -0700189 } finally {
190 args.recycle();
191 }
192 break;
193 case MSG_CHANGE_CALL_DATA_USAGE:
Andrew Leeda80c872015-04-15 14:09:50 -0700194 mCallback.onCallDataUsageChanged((long) msg.obj);
Andrew Lee50aca232014-07-22 16:41:54 -0700195 break;
196 case MSG_CHANGE_CAMERA_CAPABILITIES:
Andrew Leeda80c872015-04-15 14:09:50 -0700197 mCallback.onCameraCapabilitiesChanged(
Yorke Lee400470f2015-05-12 13:31:25 -0700198 (VideoProfile.CameraCapabilities) msg.obj);
Andrew Lee50aca232014-07-22 16:41:54 -0700199 break;
Rekha Kumar07366812015-03-24 16:42:31 -0700200 case MSG_CHANGE_VIDEO_QUALITY:
Tyler Gunn45382162015-05-06 08:52:27 -0700201 mVideoQuality = msg.arg1;
Andrew Leeda80c872015-04-15 14:09:50 -0700202 mCallback.onVideoQualityChanged(msg.arg1);
Rekha Kumar07366812015-03-24 16:42:31 -0700203 break;
Andrew Lee50aca232014-07-22 16:41:54 -0700204 default:
205 break;
206 }
207 }
208 };
209
Andrew Lee011728f2015-04-23 15:47:06 -0700210 private Handler mHandler;
211
Tyler Gunn159f35c2017-03-02 09:28:37 -0800212 VideoCallImpl(IVideoProvider videoProvider, String callingPackageName, int targetSdkVersion)
213 throws RemoteException {
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700214 mVideoProvider = videoProvider;
215 mVideoProvider.asBinder().linkToDeath(mDeathRecipient, 0);
Andrew Lee50aca232014-07-22 16:41:54 -0700216
217 mBinder = new VideoCallListenerBinder();
Tyler Gunn75958422015-04-15 14:23:42 -0700218 mVideoProvider.addVideoCallback(mBinder);
Tyler Gunnbf9c6fd2016-11-09 10:19:23 -0800219 mCallingPackageName = callingPackageName;
Brad Ebinger0d55a302017-03-20 13:16:28 -0700220 setTargetSdkVersion(targetSdkVersion);
221 }
222
223 @VisibleForTesting
224 public void setTargetSdkVersion(int sdkVersion) {
225 mTargetSdkVersion = sdkVersion;
Andrew Lee50aca232014-07-22 16:41:54 -0700226 }
227
Tyler Gunn17933eb2019-03-05 13:58:45 -0800228 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 127403196)
Andrew Lee011728f2015-04-23 15:47:06 -0700229 public void destroy() {
230 unregisterCallback(mCallback);
Tyler Gunnd1fdf3a2019-11-05 15:47:58 -0800231 try {
232 mVideoProvider.asBinder().unlinkToDeath(mDeathRecipient, 0);
233 } catch (NoSuchElementException nse) {
234 // Already unlinked in binderDied above.
235 }
Andrew Lee50aca232014-07-22 16:41:54 -0700236 }
237
238 /** {@inheritDoc} */
Andrew Lee011728f2015-04-23 15:47:06 -0700239 public void registerCallback(VideoCall.Callback callback) {
240 registerCallback(callback, null);
241 }
242
243 /** {@inheritDoc} */
244 public void registerCallback(VideoCall.Callback callback, Handler handler) {
245 mCallback = callback;
246 if (handler == null) {
247 mHandler = new MessageHandler(Looper.getMainLooper());
248 } else {
249 mHandler = new MessageHandler(handler.getLooper());
250 }
251 }
252
253 /** {@inheritDoc} */
254 public void unregisterCallback(VideoCall.Callback callback) {
255 if (callback != mCallback) {
256 return;
257 }
258
Etan Cohen89427242015-04-23 12:26:37 -0700259 mCallback = null;
Tyler Gunn75958422015-04-15 14:23:42 -0700260 try {
261 mVideoProvider.removeVideoCallback(mBinder);
262 } catch (RemoteException e) {
263 }
264 }
265
266 /** {@inheritDoc} */
Andrew Lee50aca232014-07-22 16:41:54 -0700267 public void setCamera(String cameraId) {
268 try {
Tyler Gunnbf9c6fd2016-11-09 10:19:23 -0800269 Log.w(this, "setCamera: cameraId=%s, calling=%s", cameraId, mCallingPackageName);
Tyler Gunn159f35c2017-03-02 09:28:37 -0800270 mVideoProvider.setCamera(cameraId, mCallingPackageName, mTargetSdkVersion);
Andrew Lee50aca232014-07-22 16:41:54 -0700271 } catch (RemoteException e) {
272 }
273 }
274
275 /** {@inheritDoc} */
276 public void setPreviewSurface(Surface surface) {
277 try {
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700278 mVideoProvider.setPreviewSurface(surface);
Andrew Lee50aca232014-07-22 16:41:54 -0700279 } catch (RemoteException e) {
280 }
281 }
282
283 /** {@inheritDoc} */
284 public void setDisplaySurface(Surface surface) {
285 try {
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700286 mVideoProvider.setDisplaySurface(surface);
Andrew Lee50aca232014-07-22 16:41:54 -0700287 } catch (RemoteException e) {
288 }
289 }
290
291 /** {@inheritDoc} */
292 public void setDeviceOrientation(int rotation) {
293 try {
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700294 mVideoProvider.setDeviceOrientation(rotation);
Andrew Lee50aca232014-07-22 16:41:54 -0700295 } catch (RemoteException e) {
296 }
297 }
298
299 /** {@inheritDoc} */
300 public void setZoom(float value) {
301 try {
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700302 mVideoProvider.setZoom(value);
Andrew Lee50aca232014-07-22 16:41:54 -0700303 } catch (RemoteException e) {
304 }
305 }
306
Tyler Gunn45382162015-05-06 08:52:27 -0700307 /**
308 * Sends a session modification request to the video provider.
309 * <p>
310 * The {@link InCallService} will create the {@code requestProfile} based on the current
311 * video state (i.e. {@link Call.Details#getVideoState()}). It is, however, possible that the
312 * video state maintained by the {@link InCallService} could get out of sync with what is known
313 * by the {@link android.telecom.Connection.VideoProvider}. To remove ambiguity, the
314 * {@link VideoCallImpl} passes along the pre-modify video profile to the {@code VideoProvider}
315 * to ensure it has full context of the requested change.
316 *
317 * @param requestProfile The requested video profile.
318 */
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700319 public void sendSessionModifyRequest(VideoProfile requestProfile) {
Andrew Lee50aca232014-07-22 16:41:54 -0700320 try {
Tyler Gunn584ba6c2015-12-08 10:53:41 -0800321 VideoProfile originalProfile = new VideoProfile(mVideoState, mVideoQuality);
Tyler Gunn45382162015-05-06 08:52:27 -0700322
323 mVideoProvider.sendSessionModifyRequest(originalProfile, requestProfile);
Andrew Lee50aca232014-07-22 16:41:54 -0700324 } catch (RemoteException e) {
325 }
326 }
327
328 /** {@inheritDoc} */
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700329 public void sendSessionModifyResponse(VideoProfile responseProfile) {
Andrew Lee50aca232014-07-22 16:41:54 -0700330 try {
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700331 mVideoProvider.sendSessionModifyResponse(responseProfile);
Andrew Lee50aca232014-07-22 16:41:54 -0700332 } catch (RemoteException e) {
333 }
334 }
335
336 /** {@inheritDoc} */
337 public void requestCameraCapabilities() {
338 try {
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700339 mVideoProvider.requestCameraCapabilities();
Andrew Lee50aca232014-07-22 16:41:54 -0700340 } catch (RemoteException e) {
341 }
342 }
343
344 /** {@inheritDoc} */
345 public void requestCallDataUsage() {
346 try {
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700347 mVideoProvider.requestCallDataUsage();
Andrew Lee50aca232014-07-22 16:41:54 -0700348 } catch (RemoteException e) {
349 }
350 }
351
352 /** {@inheritDoc} */
Yorke Lee32f24732015-05-12 16:18:03 -0700353 public void setPauseImage(Uri uri) {
Andrew Lee50aca232014-07-22 16:41:54 -0700354 try {
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700355 mVideoProvider.setPauseImage(uri);
Andrew Lee50aca232014-07-22 16:41:54 -0700356 } catch (RemoteException e) {
357 }
358 }
Tyler Gunn584ba6c2015-12-08 10:53:41 -0800359
360 /**
361 * Sets the video state for the current video call.
362 * @param videoState the new video state.
363 */
364 public void setVideoState(int videoState) {
365 mVideoState = videoState;
366 }
Tyler Gunnd1fdf3a2019-11-05 15:47:58 -0800367
368 /**
369 * Get the video provider binder.
370 * @return the video provider binder.
371 */
372 public IVideoProvider getVideoProvider() {
373 return mVideoProvider;
374 }
Rekha Kumar07366812015-03-24 16:42:31 -0700375}