• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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