1 /* 2 * Copyright (C) 2015 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 com.android.server.telecom; 18 19 import android.net.Uri; 20 import android.os.IBinder; 21 import android.os.Looper; 22 import android.os.RemoteException; 23 import android.telecom.Connection; 24 import android.telecom.InCallService; 25 import android.telecom.VideoProfile; 26 import android.view.Surface; 27 28 import com.android.internal.telecom.IVideoCallback; 29 import com.android.internal.telecom.IVideoProvider; 30 31 import java.util.Collections; 32 import java.util.HashMap; 33 import java.util.Set; 34 import java.util.concurrent.ConcurrentHashMap; 35 36 /** 37 * Proxies video provider messages from {@link InCallService.VideoCall} 38 * implementations to the underlying {@link Connection.VideoProvider} implementation. Also proxies 39 * callbacks from the {@link Connection.VideoProvider} to {@link InCallService.VideoCall} 40 * implementations. 41 * 42 * Also provides a means for Telecom to send and receive these messages. 43 */ 44 public class VideoProviderProxy extends Connection.VideoProvider { 45 46 /** 47 * Listener for Telecom components interested in callbacks from the video provider. 48 */ 49 interface Listener { onSessionModifyRequestReceived(Call call, VideoProfile videoProfile)50 void onSessionModifyRequestReceived(Call call, VideoProfile videoProfile); 51 } 52 53 /** 54 * Set of listeners on this VideoProviderProxy. 55 * 56 * ConcurrentHashMap constructor params: 8 is initial table size, 0.9f is 57 * load factor before resizing, 1 means we only expect a single thread to 58 * access the map so make only a single shard 59 */ 60 private final Set<Listener> mListeners = Collections.newSetFromMap( 61 new ConcurrentHashMap<Listener, Boolean>(8, 0.9f, 1)); 62 63 /** The TelecomSystem SyncRoot used for synchronized operations. */ 64 private final TelecomSystem.SyncRoot mLock; 65 66 /** 67 * The {@link android.telecom.Connection.VideoProvider} implementation residing with the 68 * {@link android.telecom.ConnectionService} which is being wrapped by this 69 * {@link VideoProviderProxy}. 70 */ 71 private final IVideoProvider mConectionServiceVideoProvider; 72 73 /** 74 * Binder used to bind to the {@link android.telecom.ConnectionService}'s 75 * {@link com.android.internal.telecom.IVideoCallback}. 76 */ 77 private final VideoCallListenerBinder mVideoCallListenerBinder; 78 79 /** 80 * The Telecom {@link Call} this {@link VideoProviderProxy} is associated with. 81 */ 82 private Call mCall; 83 84 private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() { 85 @Override 86 public void binderDied() { 87 mConectionServiceVideoProvider.asBinder().unlinkToDeath(this, 0); 88 } 89 }; 90 91 /** 92 * Creates a new instance of the {@link VideoProviderProxy}, binding it to the passed in 93 * {@code videoProvider} residing with the {@link android.telecom.ConnectionService}. 94 * 95 * 96 * @param lock 97 * @param videoProvider The {@link android.telecom.ConnectionService}'s video provider. 98 * @param call The current call. 99 * @throws RemoteException Remote exception. 100 */ VideoProviderProxy(TelecomSystem.SyncRoot lock, IVideoProvider videoProvider, Call call)101 VideoProviderProxy(TelecomSystem.SyncRoot lock, 102 IVideoProvider videoProvider, Call call) throws RemoteException { 103 104 super(Looper.getMainLooper()); 105 106 mLock = lock; 107 108 mConectionServiceVideoProvider = videoProvider; 109 mConectionServiceVideoProvider.asBinder().linkToDeath(mDeathRecipient, 0); 110 111 mVideoCallListenerBinder = new VideoCallListenerBinder(); 112 mConectionServiceVideoProvider.addVideoCallback(mVideoCallListenerBinder); 113 mCall = call; 114 } 115 116 /** 117 * IVideoCallback stub implementation. An instance of this class receives callbacks from the 118 * {@code ConnectionService}'s video provider. 119 */ 120 private final class VideoCallListenerBinder extends IVideoCallback.Stub { 121 /** 122 * Proxies a request from the {@link #mConectionServiceVideoProvider} to the 123 * {@link InCallService} when a session modification request is received. 124 * 125 * @param videoProfile The requested video profile. 126 */ 127 @Override receiveSessionModifyRequest(VideoProfile videoProfile)128 public void receiveSessionModifyRequest(VideoProfile videoProfile) { 129 synchronized (mLock) { 130 logFromVideoProvider("receiveSessionModifyRequest: " + videoProfile); 131 132 // Inform other Telecom components of the session modification request. 133 for (Listener listener : mListeners) { 134 listener.onSessionModifyRequestReceived(mCall, videoProfile); 135 } 136 137 VideoProviderProxy.this.receiveSessionModifyRequest(videoProfile); 138 } 139 } 140 141 /** 142 * Proxies a request from the {@link #mConectionServiceVideoProvider} to the 143 * {@link InCallService} when a session modification response is received. 144 * 145 * @param status The status of the response. 146 * @param requestProfile The requested video profile. 147 * @param responseProfile The response video profile. 148 */ 149 @Override receiveSessionModifyResponse(int status, VideoProfile requestProfile, VideoProfile responseProfile)150 public void receiveSessionModifyResponse(int status, VideoProfile requestProfile, 151 VideoProfile responseProfile) { 152 synchronized (mLock) { 153 logFromVideoProvider("receiveSessionModifyResponse: status=" + status + 154 " requestProfile=" + requestProfile + " responseProfile=" + 155 responseProfile); 156 VideoProviderProxy.this.receiveSessionModifyResponse(status, requestProfile, 157 responseProfile); 158 } 159 } 160 161 /** 162 * Proxies a request from the {@link #mConectionServiceVideoProvider} to the 163 * {@link InCallService} when a call session event occurs. 164 * 165 * @param event The call session event. 166 */ 167 @Override handleCallSessionEvent(int event)168 public void handleCallSessionEvent(int event) { 169 synchronized (mLock) { 170 logFromVideoProvider("handleCallSessionEvent: " + event); 171 VideoProviderProxy.this.handleCallSessionEvent(event); 172 } 173 } 174 175 /** 176 * Proxies a request from the {@link #mConectionServiceVideoProvider} to the 177 * {@link InCallService} when the peer dimensions change. 178 * 179 * @param width The width of the peer's video. 180 * @param height The height of the peer's video. 181 */ 182 @Override changePeerDimensions(int width, int height)183 public void changePeerDimensions(int width, int height) { 184 synchronized (mLock) { 185 logFromVideoProvider("changePeerDimensions: width=" + width + " height=" + 186 height); 187 VideoProviderProxy.this.changePeerDimensions(width, height); 188 } 189 } 190 191 /** 192 * Proxies a request from the {@link #mConectionServiceVideoProvider} to the 193 * {@link InCallService} when the video quality changes. 194 * 195 * @param videoQuality The video quality. 196 */ 197 @Override changeVideoQuality(int videoQuality)198 public void changeVideoQuality(int videoQuality) { 199 synchronized (mLock) { 200 logFromVideoProvider("changeVideoQuality: " + videoQuality); 201 VideoProviderProxy.this.changeVideoQuality(videoQuality); 202 } 203 } 204 205 /** 206 * Proxies a request from the {@link #mConectionServiceVideoProvider} to the 207 * {@link InCallService} when the call data usage changes. 208 * 209 * @param dataUsage The data usage. 210 */ 211 @Override changeCallDataUsage(long dataUsage)212 public void changeCallDataUsage(long dataUsage) { 213 synchronized (mLock) { 214 logFromVideoProvider("changeCallDataUsage: " + dataUsage); 215 VideoProviderProxy.this.setCallDataUsage(dataUsage); 216 } 217 } 218 219 /** 220 * Proxies a request from the {@link #mConectionServiceVideoProvider} to the 221 * {@link InCallService} when the camera capabilities change. 222 * 223 * @param cameraCapabilities The camera capabilities. 224 */ 225 @Override changeCameraCapabilities(VideoProfile.CameraCapabilities cameraCapabilities)226 public void changeCameraCapabilities(VideoProfile.CameraCapabilities cameraCapabilities) { 227 synchronized (mLock) { 228 logFromVideoProvider("changeCameraCapabilities: " + cameraCapabilities); 229 VideoProviderProxy.this.changeCameraCapabilities(cameraCapabilities); 230 } 231 } 232 } 233 234 /** 235 * Proxies a request from the {@link InCallService} to the 236 * {@link #mConectionServiceVideoProvider} to change the camera. 237 * 238 * @param cameraId The id of the camera. 239 */ 240 @Override onSetCamera(String cameraId)241 public void onSetCamera(String cameraId) { 242 synchronized (mLock) { 243 logFromInCall("setCamera: " + cameraId); 244 try { 245 mConectionServiceVideoProvider.setCamera(cameraId); 246 } catch (RemoteException e) { 247 } 248 } 249 } 250 251 /** 252 * Proxies a request from the {@link InCallService} to the 253 * {@link #mConectionServiceVideoProvider} to set the preview surface. 254 * 255 * @param surface The surface. 256 */ 257 @Override onSetPreviewSurface(Surface surface)258 public void onSetPreviewSurface(Surface surface) { 259 synchronized (mLock) { 260 logFromInCall("setPreviewSurface"); 261 try { 262 mConectionServiceVideoProvider.setPreviewSurface(surface); 263 } catch (RemoteException e) { 264 } 265 } 266 } 267 268 /** 269 * Proxies a request from the {@link InCallService} to the 270 * {@link #mConectionServiceVideoProvider} to change the display surface. 271 * 272 * @param surface The surface. 273 */ 274 @Override onSetDisplaySurface(Surface surface)275 public void onSetDisplaySurface(Surface surface) { 276 synchronized (mLock) { 277 logFromInCall("setDisplaySurface"); 278 try { 279 mConectionServiceVideoProvider.setDisplaySurface(surface); 280 } catch (RemoteException e) { 281 } 282 } 283 } 284 285 /** 286 * Proxies a request from the {@link InCallService} to the 287 * {@link #mConectionServiceVideoProvider} to change the device orientation. 288 * 289 * @param rotation The device orientation, in degrees. 290 */ 291 @Override onSetDeviceOrientation(int rotation)292 public void onSetDeviceOrientation(int rotation) { 293 synchronized (mLock) { 294 logFromInCall("setDeviceOrientation: " + rotation); 295 try { 296 mConectionServiceVideoProvider.setDeviceOrientation(rotation); 297 } catch (RemoteException e) { 298 } 299 } 300 } 301 302 /** 303 * Proxies a request from the {@link InCallService} to the 304 * {@link #mConectionServiceVideoProvider} to change the camera zoom ratio. 305 * 306 * @param value The camera zoom ratio. 307 */ 308 @Override onSetZoom(float value)309 public void onSetZoom(float value) { 310 synchronized (mLock) { 311 logFromInCall("setZoom: " + value); 312 try { 313 mConectionServiceVideoProvider.setZoom(value); 314 } catch (RemoteException e) { 315 } 316 } 317 } 318 319 /** 320 * Proxies a request from the {@link InCallService} to the 321 * {@link #mConectionServiceVideoProvider} to provide a response to a session modification 322 * request. 323 * 324 * @param fromProfile The video properties prior to the request. 325 * @param toProfile The video properties with the requested changes made. 326 */ 327 @Override onSendSessionModifyRequest(VideoProfile fromProfile, VideoProfile toProfile)328 public void onSendSessionModifyRequest(VideoProfile fromProfile, VideoProfile toProfile) { 329 synchronized (mLock) { 330 logFromInCall("sendSessionModifyRequest: from=" + fromProfile + " to=" + toProfile); 331 try { 332 mConectionServiceVideoProvider.sendSessionModifyRequest(fromProfile, toProfile); 333 } catch (RemoteException e) { 334 } 335 } 336 } 337 338 /** 339 * Proxies a request from the {@link InCallService} to the 340 * {@link #mConectionServiceVideoProvider} to send a session modification request. 341 * 342 * @param responseProfile The response connection video properties. 343 */ 344 @Override onSendSessionModifyResponse(VideoProfile responseProfile)345 public void onSendSessionModifyResponse(VideoProfile responseProfile) { 346 synchronized (mLock) { 347 logFromInCall("sendSessionModifyResponse: " + responseProfile); 348 try { 349 mConectionServiceVideoProvider.sendSessionModifyResponse(responseProfile); 350 } catch (RemoteException e) { 351 } 352 } 353 } 354 355 /** 356 * Proxies a request from the {@link InCallService} to the 357 * {@link #mConectionServiceVideoProvider} to request the camera capabilities. 358 */ 359 @Override onRequestCameraCapabilities()360 public void onRequestCameraCapabilities() { 361 synchronized (mLock) { 362 logFromInCall("requestCameraCapabilities"); 363 try { 364 mConectionServiceVideoProvider.requestCameraCapabilities(); 365 } catch (RemoteException e) { 366 } 367 } 368 } 369 370 /** 371 * Proxies a request from the {@link InCallService} to the 372 * {@link #mConectionServiceVideoProvider} to request the connection data usage. 373 */ 374 @Override onRequestConnectionDataUsage()375 public void onRequestConnectionDataUsage() { 376 synchronized (mLock) { 377 logFromInCall("requestCallDataUsage"); 378 try { 379 mConectionServiceVideoProvider.requestCallDataUsage(); 380 } catch (RemoteException e) { 381 } 382 } 383 } 384 385 /** 386 * Proxies a request from the {@link InCallService} to the 387 * {@link #mConectionServiceVideoProvider} to set the pause image. 388 * 389 * @param uri URI of image to display. 390 */ 391 @Override onSetPauseImage(Uri uri)392 public void onSetPauseImage(Uri uri) { 393 synchronized (mLock) { 394 logFromInCall("setPauseImage: " + uri); 395 try { 396 mConectionServiceVideoProvider.setPauseImage(uri); 397 } catch (RemoteException e) { 398 } 399 } 400 } 401 402 /** 403 * Add a listener to this {@link VideoProviderProxy}. 404 * 405 * @param listener The listener. 406 */ addListener(Listener listener)407 public void addListener(Listener listener) { 408 mListeners.add(listener); 409 } 410 411 /** 412 * Remove a listener from this {@link VideoProviderProxy}. 413 * 414 * @param listener The listener. 415 */ removeListener(Listener listener)416 public void removeListener(Listener listener) { 417 if (listener != null) { 418 mListeners.remove(listener); 419 } 420 } 421 422 /** 423 * Logs a message originating from the {@link InCallService}. 424 * 425 * @param toLog The message to log. 426 */ logFromInCall(String toLog)427 private void logFromInCall(String toLog) { 428 Log.v(this, "IC->VP: " + toLog); 429 } 430 431 /** 432 * Logs a message originating from the {@link android.telecom.ConnectionService}'s 433 * {@link Connection.VideoProvider}. 434 * 435 * @param toLog The message to log. 436 */ logFromVideoProvider(String toLog)437 private void logFromVideoProvider(String toLog) { 438 Log.v(this, "VP->IC: " + toLog); 439 } 440 } 441