blob: 7d90a6da30ad4d527a49dd097ce1b5695ead986b [file] [log] [blame]
Tyler Gunn86014fc2015-06-12 14:31:25 -07001/*
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
17package com.android.server.telecom;
18
Tyler Gunna0a43d52016-11-09 14:09:58 -080019import android.Manifest;
20import android.app.AppOpsManager;
21import android.content.Context;
Tyler Gunn86014fc2015-06-12 14:31:25 -070022import android.net.Uri;
Tyler Gunna0a43d52016-11-09 14:09:58 -080023import android.os.Binder;
Tyler Gunn115c06e2017-03-02 09:29:07 -080024import android.os.Build;
Tyler Gunn86014fc2015-06-12 14:31:25 -070025import android.os.IBinder;
26import android.os.Looper;
27import android.os.RemoteException;
Tyler Gunn1bf0e6b2016-11-30 15:19:13 -080028import android.os.UserHandle;
Tyler Gunn86014fc2015-06-12 14:31:25 -070029import android.telecom.Connection;
30import android.telecom.InCallService;
Brad Ebingera3eccfe2016-10-05 15:45:22 -070031import android.telecom.Log;
Tyler Gunn86014fc2015-06-12 14:31:25 -070032import android.telecom.VideoProfile;
Tyler Gunna0a43d52016-11-09 14:09:58 -080033import android.text.TextUtils;
Tyler Gunn86014fc2015-06-12 14:31:25 -070034import android.view.Surface;
35
36import com.android.internal.telecom.IVideoCallback;
37import com.android.internal.telecom.IVideoProvider;
38
39import java.util.Collections;
Tyler Gunn86014fc2015-06-12 14:31:25 -070040import java.util.Set;
41import java.util.concurrent.ConcurrentHashMap;
42
Tyler Gunna0a43d52016-11-09 14:09:58 -080043import static android.Manifest.permission.CALL_PHONE;
44
Tyler Gunn86014fc2015-06-12 14:31:25 -070045/**
46 * Proxies video provider messages from {@link InCallService.VideoCall}
47 * implementations to the underlying {@link Connection.VideoProvider} implementation. Also proxies
48 * callbacks from the {@link Connection.VideoProvider} to {@link InCallService.VideoCall}
49 * implementations.
50 *
51 * Also provides a means for Telecom to send and receive these messages.
52 */
53public class VideoProviderProxy extends Connection.VideoProvider {
54
55 /**
56 * Listener for Telecom components interested in callbacks from the video provider.
57 */
58 interface Listener {
59 void onSessionModifyRequestReceived(Call call, VideoProfile videoProfile);
60 }
61
62 /**
63 * Set of listeners on this VideoProviderProxy.
64 *
65 * ConcurrentHashMap constructor params: 8 is initial table size, 0.9f is
66 * load factor before resizing, 1 means we only expect a single thread to
67 * access the map so make only a single shard
68 */
69 private final Set<Listener> mListeners = Collections.newSetFromMap(
70 new ConcurrentHashMap<Listener, Boolean>(8, 0.9f, 1));
71
72 /** The TelecomSystem SyncRoot used for synchronized operations. */
73 private final TelecomSystem.SyncRoot mLock;
74
75 /**
76 * The {@link android.telecom.Connection.VideoProvider} implementation residing with the
77 * {@link android.telecom.ConnectionService} which is being wrapped by this
78 * {@link VideoProviderProxy}.
79 */
80 private final IVideoProvider mConectionServiceVideoProvider;
81
82 /**
83 * Binder used to bind to the {@link android.telecom.ConnectionService}'s
84 * {@link com.android.internal.telecom.IVideoCallback}.
85 */
86 private final VideoCallListenerBinder mVideoCallListenerBinder;
87
88 /**
89 * The Telecom {@link Call} this {@link VideoProviderProxy} is associated with.
90 */
91 private Call mCall;
92
Tyler Gunn1bf0e6b2016-11-30 15:19:13 -080093 /**
94 * Interface providing access to the currently logged in user.
95 */
96 private CurrentUserProxy mCurrentUserProxy;
97
Tyler Gunn86014fc2015-06-12 14:31:25 -070098 private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
99 @Override
100 public void binderDied() {
101 mConectionServiceVideoProvider.asBinder().unlinkToDeath(this, 0);
102 }
103 };
104
105 /**
106 * Creates a new instance of the {@link VideoProviderProxy}, binding it to the passed in
107 * {@code videoProvider} residing with the {@link android.telecom.ConnectionService}.
108 *
109 *
110 * @param lock
111 * @param videoProvider The {@link android.telecom.ConnectionService}'s video provider.
112 * @param call The current call.
113 * @throws RemoteException Remote exception.
114 */
115 VideoProviderProxy(TelecomSystem.SyncRoot lock,
Tyler Gunn1bf0e6b2016-11-30 15:19:13 -0800116 IVideoProvider videoProvider, Call call, CurrentUserProxy currentUserProxy)
117 throws RemoteException {
Tyler Gunn86014fc2015-06-12 14:31:25 -0700118
119 super(Looper.getMainLooper());
120
121 mLock = lock;
122
123 mConectionServiceVideoProvider = videoProvider;
124 mConectionServiceVideoProvider.asBinder().linkToDeath(mDeathRecipient, 0);
125
126 mVideoCallListenerBinder = new VideoCallListenerBinder();
127 mConectionServiceVideoProvider.addVideoCallback(mVideoCallListenerBinder);
128 mCall = call;
Tyler Gunn1bf0e6b2016-11-30 15:19:13 -0800129 mCurrentUserProxy = currentUserProxy;
Tyler Gunn86014fc2015-06-12 14:31:25 -0700130 }
131
Ravi Palurib4088ee2016-12-20 20:00:00 +0530132 public void clearVideoCallback() {
133 try {
134 mConectionServiceVideoProvider.removeVideoCallback(mVideoCallListenerBinder);
135 } catch (RemoteException e) {
136 }
137 }
138
Tyler Gunn86014fc2015-06-12 14:31:25 -0700139 /**
140 * IVideoCallback stub implementation. An instance of this class receives callbacks from the
141 * {@code ConnectionService}'s video provider.
142 */
143 private final class VideoCallListenerBinder extends IVideoCallback.Stub {
144 /**
145 * Proxies a request from the {@link #mConectionServiceVideoProvider} to the
146 * {@link InCallService} when a session modification request is received.
147 *
148 * @param videoProfile The requested video profile.
149 */
150 @Override
151 public void receiveSessionModifyRequest(VideoProfile videoProfile) {
Brad Ebinger3165d502015-12-15 17:22:29 -0800152 try {
153 Log.startSession("VPP.rSMR");
154 synchronized (mLock) {
155 logFromVideoProvider("receiveSessionModifyRequest: " + videoProfile);
Brad Ebingera3eccfe2016-10-05 15:45:22 -0700156 Log.addEvent(mCall, LogUtils.Events.RECEIVE_VIDEO_REQUEST,
Tyler Gunn70d6f852016-06-21 10:22:06 -0700157 VideoProfile.videoStateToString(videoProfile.getVideoState()));
Tyler Gunn86014fc2015-06-12 14:31:25 -0700158
Hall Liu4640c4f2016-06-22 17:13:20 -0700159 mCall.getAnalytics().addVideoEvent(
160 Analytics.RECEIVE_REMOTE_SESSION_MODIFY_REQUEST,
161 videoProfile.getVideoState());
Tyler Gunn13e8a692016-08-03 18:38:00 -0700162
163 if (!mCall.isVideoCallingSupported() &&
164 VideoProfile.isVideo(videoProfile.getVideoState())) {
165 // If video calling is not supported by the phone account, and we receive
166 // a request to upgrade to video, automatically reject it without informing
167 // the InCallService.
168
Brad Ebingera3eccfe2016-10-05 15:45:22 -0700169 Log.addEvent(mCall, LogUtils.Events.SEND_VIDEO_RESPONSE, "video not supported");
Tyler Gunn13e8a692016-08-03 18:38:00 -0700170 VideoProfile responseProfile = new VideoProfile(
171 VideoProfile.STATE_AUDIO_ONLY);
172 try {
173 mConectionServiceVideoProvider.sendSessionModifyResponse(
174 responseProfile);
175 } catch (RemoteException e) {
176 }
177
178 // Don't want to inform listeners of the request as we've just rejected it.
179 return;
180 }
181
Brad Ebinger3165d502015-12-15 17:22:29 -0800182 // Inform other Telecom components of the session modification request.
183 for (Listener listener : mListeners) {
184 listener.onSessionModifyRequestReceived(mCall, videoProfile);
185 }
186
187 VideoProviderProxy.this.receiveSessionModifyRequest(videoProfile);
Tyler Gunn86014fc2015-06-12 14:31:25 -0700188 }
Brad Ebinger3165d502015-12-15 17:22:29 -0800189 } finally {
190 Log.endSession();
Tyler Gunn86014fc2015-06-12 14:31:25 -0700191 }
192 }
193
194 /**
195 * Proxies a request from the {@link #mConectionServiceVideoProvider} to the
196 * {@link InCallService} when a session modification response is received.
197 *
198 * @param status The status of the response.
199 * @param requestProfile The requested video profile.
200 * @param responseProfile The response video profile.
201 */
202 @Override
203 public void receiveSessionModifyResponse(int status, VideoProfile requestProfile,
204 VideoProfile responseProfile) {
Brad Ebinger10f8cd22016-07-13 16:06:56 -0700205 logFromVideoProvider("receiveSessionModifyResponse: status=" + status +
206 " requestProfile=" + requestProfile + " responseProfile=" + responseProfile);
207 String eventMessage = "Status Code : " + status + " Video State: " +
208 (responseProfile != null ? responseProfile.getVideoState() : "null");
Brad Ebingera3eccfe2016-10-05 15:45:22 -0700209 Log.addEvent(mCall, LogUtils.Events.RECEIVE_VIDEO_RESPONSE, eventMessage);
Tyler Gunn86014fc2015-06-12 14:31:25 -0700210 synchronized (mLock) {
Brad Ebinger10f8cd22016-07-13 16:06:56 -0700211 if (status == Connection.VideoProvider.SESSION_MODIFY_REQUEST_SUCCESS) {
212 mCall.getAnalytics().addVideoEvent(
213 Analytics.RECEIVE_REMOTE_SESSION_MODIFY_RESPONSE,
Hall Liu2f4f0a02016-08-08 17:23:20 -0700214 responseProfile == null ?
215 VideoProfile.STATE_AUDIO_ONLY :
216 responseProfile.getVideoState());
Brad Ebinger10f8cd22016-07-13 16:06:56 -0700217 }
Tyler Gunn86014fc2015-06-12 14:31:25 -0700218 VideoProviderProxy.this.receiveSessionModifyResponse(status, requestProfile,
219 responseProfile);
220 }
221 }
222
223 /**
224 * Proxies a request from the {@link #mConectionServiceVideoProvider} to the
225 * {@link InCallService} when a call session event occurs.
226 *
227 * @param event The call session event.
228 */
229 @Override
230 public void handleCallSessionEvent(int event) {
231 synchronized (mLock) {
Tyler Gunn33e45382016-09-02 09:59:05 -0700232 logFromVideoProvider("handleCallSessionEvent: " +
233 Connection.VideoProvider.sessionEventToString(event));
Tyler Gunn86014fc2015-06-12 14:31:25 -0700234 VideoProviderProxy.this.handleCallSessionEvent(event);
235 }
236 }
237
238 /**
239 * Proxies a request from the {@link #mConectionServiceVideoProvider} to the
240 * {@link InCallService} when the peer dimensions change.
241 *
242 * @param width The width of the peer's video.
243 * @param height The height of the peer's video.
244 */
245 @Override
246 public void changePeerDimensions(int width, int height) {
247 synchronized (mLock) {
248 logFromVideoProvider("changePeerDimensions: width=" + width + " height=" +
249 height);
250 VideoProviderProxy.this.changePeerDimensions(width, height);
251 }
252 }
253
254 /**
255 * Proxies a request from the {@link #mConectionServiceVideoProvider} to the
256 * {@link InCallService} when the video quality changes.
257 *
258 * @param videoQuality The video quality.
259 */
260 @Override
261 public void changeVideoQuality(int videoQuality) {
262 synchronized (mLock) {
263 logFromVideoProvider("changeVideoQuality: " + videoQuality);
264 VideoProviderProxy.this.changeVideoQuality(videoQuality);
265 }
266 }
267
268 /**
269 * Proxies a request from the {@link #mConectionServiceVideoProvider} to the
270 * {@link InCallService} when the call data usage changes.
271 *
Tyler Gunn7a1f8232015-12-03 19:52:59 -0800272 * Also tracks the current call data usage on the {@link Call} for use when writing to the
273 * call log.
274 *
Tyler Gunn86014fc2015-06-12 14:31:25 -0700275 * @param dataUsage The data usage.
276 */
277 @Override
278 public void changeCallDataUsage(long dataUsage) {
279 synchronized (mLock) {
280 logFromVideoProvider("changeCallDataUsage: " + dataUsage);
281 VideoProviderProxy.this.setCallDataUsage(dataUsage);
Tyler Gunn7a1f8232015-12-03 19:52:59 -0800282 mCall.setCallDataUsage(dataUsage);
Tyler Gunn86014fc2015-06-12 14:31:25 -0700283 }
284 }
285
286 /**
287 * Proxies a request from the {@link #mConectionServiceVideoProvider} to the
288 * {@link InCallService} when the camera capabilities change.
289 *
290 * @param cameraCapabilities The camera capabilities.
291 */
292 @Override
293 public void changeCameraCapabilities(VideoProfile.CameraCapabilities cameraCapabilities) {
294 synchronized (mLock) {
295 logFromVideoProvider("changeCameraCapabilities: " + cameraCapabilities);
296 VideoProviderProxy.this.changeCameraCapabilities(cameraCapabilities);
297 }
298 }
299 }
300
Tyler Gunna0a43d52016-11-09 14:09:58 -0800301 @Override
302 public void onSetCamera(String cameraId) {
303 // No-op. We implement the other prototype of onSetCamera so that we can use the calling
304 // package, uid and pid to verify permission.
305 }
306
Tyler Gunn86014fc2015-06-12 14:31:25 -0700307 /**
308 * Proxies a request from the {@link InCallService} to the
309 * {@link #mConectionServiceVideoProvider} to change the camera.
310 *
311 * @param cameraId The id of the camera.
Tyler Gunna0a43d52016-11-09 14:09:58 -0800312 * @param callingPackage The package calling in.
313 * @param callingUid The UID of the caller.
314 * @param callingPid The PID of the caller.
Tyler Gunn115c06e2017-03-02 09:29:07 -0800315 * @param targetSdkVersion The target SDK version of the calling InCallService where the camera
316 * request originated.
Tyler Gunn86014fc2015-06-12 14:31:25 -0700317 */
318 @Override
Tyler Gunna0a43d52016-11-09 14:09:58 -0800319 public void onSetCamera(String cameraId, String callingPackage, int callingUid,
Tyler Gunn115c06e2017-03-02 09:29:07 -0800320 int callingPid, int targetSdkVersion) {
Tyler Gunn86014fc2015-06-12 14:31:25 -0700321 synchronized (mLock) {
Tyler Gunn1bf0e6b2016-11-30 15:19:13 -0800322 logFromInCall("setCamera: " + cameraId + " callingPackage=" + callingPackage +
323 "; callingUid=" + callingUid);
Tyler Gunna0a43d52016-11-09 14:09:58 -0800324
325 if (!TextUtils.isEmpty(cameraId)) {
326 if (!canUseCamera(mCall.getContext(), callingPackage, callingUid, callingPid)) {
327 // Calling app is not permitted to use the camera. Ignore the request and send
328 // back a call session event indicating the error.
Garik Badalyan772fdf62017-03-15 13:44:39 -0700329 Log.i(this, "onSetCamera: camera permission denied; package=%s, uid=%d, "
Tyler Gunn115c06e2017-03-02 09:29:07 -0800330 + "pid=%d, targetSdkVersion=%d",
331 callingPackage, callingUid, callingPid, targetSdkVersion);
332
333 // API 26 introduces a new camera permission error we can use here since the
334 // caller supports that API version.
335 if (targetSdkVersion > Build.VERSION_CODES.N_MR1) {
336 VideoProviderProxy.this.handleCallSessionEvent(
337 Connection.VideoProvider.SESSION_EVENT_CAMERA_PERMISSION_ERROR);
338 } else {
339 VideoProviderProxy.this.handleCallSessionEvent(
340 Connection.VideoProvider.SESSION_EVENT_CAMERA_FAILURE);
341 }
Tyler Gunna0a43d52016-11-09 14:09:58 -0800342 return;
343 }
344 }
Tyler Gunn86014fc2015-06-12 14:31:25 -0700345 try {
Tyler Gunn115c06e2017-03-02 09:29:07 -0800346 mConectionServiceVideoProvider.setCamera(cameraId, callingPackage,
347 targetSdkVersion);
Tyler Gunn86014fc2015-06-12 14:31:25 -0700348 } catch (RemoteException e) {
Tyler Gunna0a43d52016-11-09 14:09:58 -0800349 VideoProviderProxy.this.handleCallSessionEvent(
350 Connection.VideoProvider.SESSION_EVENT_CAMERA_FAILURE);
Tyler Gunn86014fc2015-06-12 14:31:25 -0700351 }
352 }
353 }
354
355 /**
356 * Proxies a request from the {@link InCallService} to the
357 * {@link #mConectionServiceVideoProvider} to set the preview surface.
358 *
359 * @param surface The surface.
360 */
361 @Override
362 public void onSetPreviewSurface(Surface surface) {
363 synchronized (mLock) {
364 logFromInCall("setPreviewSurface");
365 try {
366 mConectionServiceVideoProvider.setPreviewSurface(surface);
367 } catch (RemoteException e) {
368 }
369 }
370 }
371
372 /**
373 * Proxies a request from the {@link InCallService} to the
374 * {@link #mConectionServiceVideoProvider} to change the display surface.
375 *
376 * @param surface The surface.
377 */
378 @Override
379 public void onSetDisplaySurface(Surface surface) {
380 synchronized (mLock) {
381 logFromInCall("setDisplaySurface");
382 try {
383 mConectionServiceVideoProvider.setDisplaySurface(surface);
384 } catch (RemoteException e) {
385 }
386 }
387 }
388
389 /**
390 * Proxies a request from the {@link InCallService} to the
391 * {@link #mConectionServiceVideoProvider} to change the device orientation.
392 *
393 * @param rotation The device orientation, in degrees.
394 */
395 @Override
396 public void onSetDeviceOrientation(int rotation) {
397 synchronized (mLock) {
398 logFromInCall("setDeviceOrientation: " + rotation);
399 try {
400 mConectionServiceVideoProvider.setDeviceOrientation(rotation);
401 } catch (RemoteException e) {
402 }
403 }
404 }
405
406 /**
407 * Proxies a request from the {@link InCallService} to the
408 * {@link #mConectionServiceVideoProvider} to change the camera zoom ratio.
409 *
410 * @param value The camera zoom ratio.
411 */
412 @Override
413 public void onSetZoom(float value) {
414 synchronized (mLock) {
415 logFromInCall("setZoom: " + value);
416 try {
417 mConectionServiceVideoProvider.setZoom(value);
418 } catch (RemoteException e) {
419 }
420 }
421 }
422
423 /**
424 * Proxies a request from the {@link InCallService} to the
425 * {@link #mConectionServiceVideoProvider} to provide a response to a session modification
426 * request.
427 *
428 * @param fromProfile The video properties prior to the request.
429 * @param toProfile The video properties with the requested changes made.
430 */
431 @Override
432 public void onSendSessionModifyRequest(VideoProfile fromProfile, VideoProfile toProfile) {
433 synchronized (mLock) {
434 logFromInCall("sendSessionModifyRequest: from=" + fromProfile + " to=" + toProfile);
Brad Ebingera3eccfe2016-10-05 15:45:22 -0700435 Log.addEvent(mCall, LogUtils.Events.SEND_VIDEO_REQUEST,
Tyler Gunn70d6f852016-06-21 10:22:06 -0700436 VideoProfile.videoStateToString(toProfile.getVideoState()));
Hall Liu4640c4f2016-06-22 17:13:20 -0700437 mCall.getAnalytics().addVideoEvent(
438 Analytics.SEND_LOCAL_SESSION_MODIFY_REQUEST,
439 toProfile.getVideoState());
Tyler Gunn86014fc2015-06-12 14:31:25 -0700440 try {
441 mConectionServiceVideoProvider.sendSessionModifyRequest(fromProfile, toProfile);
442 } catch (RemoteException e) {
443 }
444 }
445 }
446
447 /**
448 * Proxies a request from the {@link InCallService} to the
449 * {@link #mConectionServiceVideoProvider} to send a session modification request.
450 *
451 * @param responseProfile The response connection video properties.
452 */
453 @Override
454 public void onSendSessionModifyResponse(VideoProfile responseProfile) {
455 synchronized (mLock) {
456 logFromInCall("sendSessionModifyResponse: " + responseProfile);
Brad Ebingera3eccfe2016-10-05 15:45:22 -0700457 Log.addEvent(mCall, LogUtils.Events.SEND_VIDEO_RESPONSE,
Tyler Gunn70d6f852016-06-21 10:22:06 -0700458 VideoProfile.videoStateToString(responseProfile.getVideoState()));
Hall Liu4640c4f2016-06-22 17:13:20 -0700459 mCall.getAnalytics().addVideoEvent(
460 Analytics.SEND_LOCAL_SESSION_MODIFY_RESPONSE,
461 responseProfile.getVideoState());
Tyler Gunn86014fc2015-06-12 14:31:25 -0700462 try {
463 mConectionServiceVideoProvider.sendSessionModifyResponse(responseProfile);
464 } catch (RemoteException e) {
465 }
466 }
467 }
468
469 /**
470 * Proxies a request from the {@link InCallService} to the
471 * {@link #mConectionServiceVideoProvider} to request the camera capabilities.
472 */
473 @Override
474 public void onRequestCameraCapabilities() {
475 synchronized (mLock) {
476 logFromInCall("requestCameraCapabilities");
477 try {
478 mConectionServiceVideoProvider.requestCameraCapabilities();
479 } catch (RemoteException e) {
480 }
481 }
482 }
483
484 /**
485 * Proxies a request from the {@link InCallService} to the
486 * {@link #mConectionServiceVideoProvider} to request the connection data usage.
487 */
488 @Override
489 public void onRequestConnectionDataUsage() {
490 synchronized (mLock) {
491 logFromInCall("requestCallDataUsage");
492 try {
493 mConectionServiceVideoProvider.requestCallDataUsage();
494 } catch (RemoteException e) {
495 }
496 }
497 }
498
499 /**
500 * Proxies a request from the {@link InCallService} to the
501 * {@link #mConectionServiceVideoProvider} to set the pause image.
502 *
503 * @param uri URI of image to display.
504 */
505 @Override
506 public void onSetPauseImage(Uri uri) {
507 synchronized (mLock) {
508 logFromInCall("setPauseImage: " + uri);
509 try {
510 mConectionServiceVideoProvider.setPauseImage(uri);
511 } catch (RemoteException e) {
512 }
513 }
514 }
515
516 /**
517 * Add a listener to this {@link VideoProviderProxy}.
518 *
519 * @param listener The listener.
520 */
521 public void addListener(Listener listener) {
522 mListeners.add(listener);
523 }
524
525 /**
526 * Remove a listener from this {@link VideoProviderProxy}.
527 *
528 * @param listener The listener.
529 */
530 public void removeListener(Listener listener) {
531 if (listener != null) {
532 mListeners.remove(listener);
533 }
534 }
535
536 /**
537 * Logs a message originating from the {@link InCallService}.
538 *
539 * @param toLog The message to log.
540 */
541 private void logFromInCall(String toLog) {
Tyler Gunn33e45382016-09-02 09:59:05 -0700542 Log.i(this, "IC->VP (callId=" + (mCall == null ? "?" : mCall.getId()) + "): " + toLog);
Tyler Gunn86014fc2015-06-12 14:31:25 -0700543 }
544
545 /**
546 * Logs a message originating from the {@link android.telecom.ConnectionService}'s
547 * {@link Connection.VideoProvider}.
548 *
549 * @param toLog The message to log.
550 */
551 private void logFromVideoProvider(String toLog) {
Tyler Gunn33e45382016-09-02 09:59:05 -0700552 Log.i(this, "VP->IC (callId=" + (mCall == null ? "?" : mCall.getId()) + "): " + toLog);
Tyler Gunn86014fc2015-06-12 14:31:25 -0700553 }
Tyler Gunna0a43d52016-11-09 14:09:58 -0800554
555 /**
556 * Determines if the caller has permission to use the camera.
557 *
558 * @param context The context.
559 * @param callingPackage The package name of the caller (i.e. Dialer).
560 * @param callingUid The UID of the caller.
Tyler Gunn1bf0e6b2016-11-30 15:19:13 -0800561 * @param callingPid The PID of the caller.
Tyler Gunna0a43d52016-11-09 14:09:58 -0800562 * @return {@code true} if the calling uid and package can use the camera, {@code false}
563 * otherwise.
564 */
565 private boolean canUseCamera(Context context, String callingPackage, int callingUid,
566 int callingPid) {
Tyler Gunn1bf0e6b2016-11-30 15:19:13 -0800567
568 UserHandle callingUser = UserHandle.getUserHandleForUid(callingUid);
569 UserHandle currentUserHandle = mCurrentUserProxy.getCurrentUserHandle();
570 if (currentUserHandle != null && !currentUserHandle.equals(callingUser)) {
571 Log.w(this, "canUseCamera attempt to user camera by background user.");
572 return false;
573 }
574
Tyler Gunna0a43d52016-11-09 14:09:58 -0800575 try {
576 context.enforcePermission(Manifest.permission.CAMERA, callingPid, callingUid,
577 "Camera permission required.");
578 } catch (SecurityException se) {
579 return false;
580 }
581
582 AppOpsManager appOpsManager = (AppOpsManager) context.getSystemService(
583 Context.APP_OPS_SERVICE);
584
585 try {
586 // Some apps that have the permission can be restricted via app ops.
587 return appOpsManager != null && appOpsManager.noteOp(AppOpsManager.OP_CAMERA,
588 callingUid, callingPackage) == AppOpsManager.MODE_ALLOWED;
589 } catch (SecurityException se) {
Tyler Gunn1bf0e6b2016-11-30 15:19:13 -0800590 Log.w(this, "canUseCamera got appOpps Exception " + se.toString());
Tyler Gunna0a43d52016-11-09 14:09:58 -0800591 return false;
592 }
593 }
594
Tyler Gunn86014fc2015-06-12 14:31:25 -0700595}