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 17package com.android.ims.internal; 18 19import android.net.Uri; 20import android.os.Handler; 21import android.os.IBinder; 22import android.os.Looper; 23import android.os.Message; 24import android.os.RegistrantList; 25import android.os.RemoteException; 26import android.telecom.Connection; 27import android.telecom.VideoProfile; 28import android.view.Surface; 29 30import com.android.internal.os.SomeArgs; 31 32import java.util.Collections; 33import java.util.Set; 34import java.util.concurrent.ConcurrentHashMap; 35 36/** 37 * Subclass implementation of {@link Connection.VideoProvider}. This intermediates and 38 * communicates with the actual implementation of the video call provider in the IMS service; it is 39 * in essence, a wrapper around the IMS's video call provider implementation. 40 * 41 * This class maintains a binder by which the ImsVideoCallProvider's implementation can communicate 42 * its intent to invoke callbacks. In this class, the message across this binder is handled, and 43 * the superclass's methods are used to execute the callbacks. 44 * 45 * @hide 46 */ 47public class ImsVideoCallProviderWrapper extends Connection.VideoProvider { 48 49 public interface ImsVideoProviderWrapperCallback { 50 void onReceiveSessionModifyResponse(int status, VideoProfile requestProfile, 51 VideoProfile responseProfile); 52 } 53 54 private static final int MSG_RECEIVE_SESSION_MODIFY_REQUEST = 1; 55 private static final int MSG_RECEIVE_SESSION_MODIFY_RESPONSE = 2; 56 private static final int MSG_HANDLE_CALL_SESSION_EVENT = 3; 57 private static final int MSG_CHANGE_PEER_DIMENSIONS = 4; 58 private static final int MSG_CHANGE_CALL_DATA_USAGE = 5; 59 private static final int MSG_CHANGE_CAMERA_CAPABILITIES = 6; 60 private static final int MSG_CHANGE_VIDEO_QUALITY = 7; 61 62 private final IImsVideoCallProvider mVideoCallProvider; 63 private final ImsVideoCallCallback mBinder; 64 private RegistrantList mDataUsageUpdateRegistrants = new RegistrantList(); 65 private final Set<ImsVideoProviderWrapperCallback> mCallbacks = Collections.newSetFromMap( 66 new ConcurrentHashMap<ImsVideoProviderWrapperCallback, Boolean>(8, 0.9f, 1)); 67 68 private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() { 69 @Override 70 public void binderDied() { 71 mVideoCallProvider.asBinder().unlinkToDeath(this, 0); 72 } 73 }; 74 75 /** 76 * IImsVideoCallCallback stub implementation. 77 */ 78 private final class ImsVideoCallCallback extends IImsVideoCallCallback.Stub { 79 @Override 80 public void receiveSessionModifyRequest(VideoProfile VideoProfile) { 81 mHandler.obtainMessage(MSG_RECEIVE_SESSION_MODIFY_REQUEST, 82 VideoProfile).sendToTarget(); 83 } 84 85 @Override 86 public void receiveSessionModifyResponse( 87 int status, VideoProfile requestProfile, VideoProfile responseProfile) { 88 SomeArgs args = SomeArgs.obtain(); 89 args.arg1 = status; 90 args.arg2 = requestProfile; 91 args.arg3 = responseProfile; 92 mHandler.obtainMessage(MSG_RECEIVE_SESSION_MODIFY_RESPONSE, args).sendToTarget(); 93 } 94 95 @Override 96 public void handleCallSessionEvent(int event) { 97 mHandler.obtainMessage(MSG_HANDLE_CALL_SESSION_EVENT, event).sendToTarget(); 98 } 99 100 @Override 101 public void changePeerDimensions(int width, int height) { 102 SomeArgs args = SomeArgs.obtain(); 103 args.arg1 = width; 104 args.arg2 = height; 105 mHandler.obtainMessage(MSG_CHANGE_PEER_DIMENSIONS, args).sendToTarget(); 106 } 107 108 @Override 109 public void changeVideoQuality(int videoQuality) { 110 mHandler.obtainMessage(MSG_CHANGE_VIDEO_QUALITY, videoQuality, 0).sendToTarget(); 111 } 112 113 @Override 114 public void changeCallDataUsage(long dataUsage) { 115 mHandler.obtainMessage(MSG_CHANGE_CALL_DATA_USAGE, dataUsage).sendToTarget(); 116 } 117 118 @Override 119 public void changeCameraCapabilities( 120 VideoProfile.CameraCapabilities cameraCapabilities) { 121 mHandler.obtainMessage(MSG_CHANGE_CAMERA_CAPABILITIES, 122 cameraCapabilities).sendToTarget(); 123 } 124 } 125 126 public void registerForDataUsageUpdate(Handler h, int what, Object obj) { 127 mDataUsageUpdateRegistrants.addUnique(h, what, obj); 128 } 129 130 public void unregisterForDataUsageUpdate(Handler h) { 131 mDataUsageUpdateRegistrants.remove(h); 132 } 133 134 public void addImsVideoProviderCallback(ImsVideoProviderWrapperCallback callback) { 135 mCallbacks.add(callback); 136 } 137 138 public void removeImsVideoProviderCallback(ImsVideoProviderWrapperCallback callback) { 139 mCallbacks.remove(callback); 140 } 141 142 /** Default handler used to consolidate binder method calls onto a single thread. */ 143 private final Handler mHandler = new Handler(Looper.getMainLooper()) { 144 @Override 145 public void handleMessage(Message msg) { 146 SomeArgs args; 147 switch (msg.what) { 148 case MSG_RECEIVE_SESSION_MODIFY_REQUEST: 149 receiveSessionModifyRequest((VideoProfile) msg.obj); 150 break; 151 case MSG_RECEIVE_SESSION_MODIFY_RESPONSE: 152 args = (SomeArgs) msg.obj; 153 try { 154 int status = (int) args.arg1; 155 VideoProfile requestProfile = (VideoProfile) args.arg2; 156 VideoProfile responseProfile = (VideoProfile) args.arg3; 157 158 receiveSessionModifyResponse(status, requestProfile, responseProfile); 159 160 // Notify any local Telephony components interested in upgrade responses. 161 for (ImsVideoProviderWrapperCallback callback : mCallbacks) { 162 if (callback != null) { 163 callback.onReceiveSessionModifyResponse(status, requestProfile, 164 responseProfile); 165 } 166 } 167 } finally { 168 args.recycle(); 169 } 170 break; 171 case MSG_HANDLE_CALL_SESSION_EVENT: 172 handleCallSessionEvent((int) msg.obj); 173 break; 174 case MSG_CHANGE_PEER_DIMENSIONS: 175 args = (SomeArgs) msg.obj; 176 try { 177 int width = (int) args.arg1; 178 int height = (int) args.arg2; 179 changePeerDimensions(width, height); 180 } finally { 181 args.recycle(); 182 } 183 break; 184 case MSG_CHANGE_CALL_DATA_USAGE: 185 // TODO: We should use callback in the future. 186 setCallDataUsage((long) msg.obj); 187 mDataUsageUpdateRegistrants.notifyResult(msg.obj); 188 break; 189 case MSG_CHANGE_CAMERA_CAPABILITIES: 190 changeCameraCapabilities((VideoProfile.CameraCapabilities) msg.obj); 191 break; 192 case MSG_CHANGE_VIDEO_QUALITY: 193 changeVideoQuality(msg.arg1); 194 break; 195 default: 196 break; 197 } 198 } 199 }; 200 201 /** 202 * Instantiates an instance of the ImsVideoCallProvider, taking in the binder for IMS's video 203 * call provider implementation. 204 * 205 * @param VideoProvider 206 */ 207 public ImsVideoCallProviderWrapper(IImsVideoCallProvider VideoProvider) 208 throws RemoteException { 209 mVideoCallProvider = VideoProvider; 210 mVideoCallProvider.asBinder().linkToDeath(mDeathRecipient, 0); 211 212 mBinder = new ImsVideoCallCallback(); 213 mVideoCallProvider.setCallback(mBinder); 214 } 215 216 /** @inheritDoc */ 217 public void onSetCamera(String cameraId) { 218 try { 219 mVideoCallProvider.setCamera(cameraId); 220 } catch (RemoteException e) { 221 } 222 } 223 224 /** @inheritDoc */ 225 public void onSetPreviewSurface(Surface surface) { 226 try { 227 mVideoCallProvider.setPreviewSurface(surface); 228 } catch (RemoteException e) { 229 } 230 } 231 232 /** @inheritDoc */ 233 public void onSetDisplaySurface(Surface surface) { 234 try { 235 mVideoCallProvider.setDisplaySurface(surface); 236 } catch (RemoteException e) { 237 } 238 } 239 240 /** @inheritDoc */ 241 public void onSetDeviceOrientation(int rotation) { 242 try { 243 mVideoCallProvider.setDeviceOrientation(rotation); 244 } catch (RemoteException e) { 245 } 246 } 247 248 /** @inheritDoc */ 249 public void onSetZoom(float value) { 250 try { 251 mVideoCallProvider.setZoom(value); 252 } catch (RemoteException e) { 253 } 254 } 255 256 /** @inheritDoc */ 257 public void onSendSessionModifyRequest(VideoProfile fromProfile, VideoProfile toProfile) { 258 try { 259 mVideoCallProvider.sendSessionModifyRequest(fromProfile, toProfile); 260 } catch (RemoteException e) { 261 } 262 } 263 264 /** @inheritDoc */ 265 public void onSendSessionModifyResponse(VideoProfile responseProfile) { 266 try { 267 mVideoCallProvider.sendSessionModifyResponse(responseProfile); 268 } catch (RemoteException e) { 269 } 270 } 271 272 /** @inheritDoc */ 273 public void onRequestCameraCapabilities() { 274 try { 275 mVideoCallProvider.requestCameraCapabilities(); 276 } catch (RemoteException e) { 277 } 278 } 279 280 /** @inheritDoc */ 281 public void onRequestConnectionDataUsage() { 282 try { 283 mVideoCallProvider.requestCallDataUsage(); 284 } catch (RemoteException e) { 285 } 286 } 287 288 /** @inheritDoc */ 289 public void onSetPauseImage(Uri uri) { 290 try { 291 mVideoCallProvider.setPauseImage(uri); 292 } catch (RemoteException e) { 293 } 294 } 295} 296