diff --git a/api/current.txt b/api/current.txt index 1bcbb52d75fb8..7da2240bff2cd 100644 --- a/api/current.txt +++ b/api/current.txt @@ -36655,6 +36655,7 @@ package android.telecom { method public void receiveSessionModifyResponse(int, android.telecom.VideoProfile, android.telecom.VideoProfile); method public void setCallDataUsage(long); field public static final int SESSION_EVENT_CAMERA_FAILURE = 5; // 0x5 + field public static final int SESSION_EVENT_CAMERA_PERMISSION_ERROR = 7; // 0x7 field public static final int SESSION_EVENT_CAMERA_READY = 6; // 0x6 field public static final int SESSION_EVENT_RX_PAUSE = 1; // 0x1 field public static final int SESSION_EVENT_RX_RESUME = 2; // 0x2 diff --git a/api/system-current.txt b/api/system-current.txt index 2bcac92c9bab6..4c903da308d66 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -39635,6 +39635,7 @@ package android.telecom { method public void receiveSessionModifyResponse(int, android.telecom.VideoProfile, android.telecom.VideoProfile); method public void setCallDataUsage(long); field public static final int SESSION_EVENT_CAMERA_FAILURE = 5; // 0x5 + field public static final int SESSION_EVENT_CAMERA_PERMISSION_ERROR = 7; // 0x7 field public static final int SESSION_EVENT_CAMERA_READY = 6; // 0x6 field public static final int SESSION_EVENT_RX_PAUSE = 1; // 0x1 field public static final int SESSION_EVENT_RX_RESUME = 2; // 0x2 diff --git a/api/test-current.txt b/api/test-current.txt index 77a939327d21b..ab3c0d9931e08 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -36737,6 +36737,7 @@ package android.telecom { method public void receiveSessionModifyResponse(int, android.telecom.VideoProfile, android.telecom.VideoProfile); method public void setCallDataUsage(long); field public static final int SESSION_EVENT_CAMERA_FAILURE = 5; // 0x5 + field public static final int SESSION_EVENT_CAMERA_PERMISSION_ERROR = 7; // 0x7 field public static final int SESSION_EVENT_CAMERA_READY = 6; // 0x6 field public static final int SESSION_EVENT_RX_PAUSE = 1; // 0x1 field public static final int SESSION_EVENT_RX_RESUME = 2; // 0x2 diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java index 58c500244d3b6..c69b7c2771acd 100644 --- a/telecomm/java/android/telecom/Call.java +++ b/telecomm/java/android/telecom/Call.java @@ -853,6 +853,7 @@ public final class Call { private String mParentId = null; private int mState; private List mCannedTextResponses = null; + private String mCallingPackage; private String mRemainingPostDialSequence; private VideoCallImpl mVideoCallImpl; private Details mDetails; @@ -1340,19 +1341,22 @@ public final class Call { } /** {@hide} */ - Call(Phone phone, String telecomCallId, InCallAdapter inCallAdapter) { + Call(Phone phone, String telecomCallId, InCallAdapter inCallAdapter, String callingPackage) { mPhone = phone; mTelecomCallId = telecomCallId; mInCallAdapter = inCallAdapter; mState = STATE_NEW; + mCallingPackage = callingPackage; } /** {@hide} */ - Call(Phone phone, String telecomCallId, InCallAdapter inCallAdapter, int state) { + Call(Phone phone, String telecomCallId, InCallAdapter inCallAdapter, int state, + String callingPackage) { mPhone = phone; mTelecomCallId = telecomCallId; mInCallAdapter = inCallAdapter; mState = state; + mCallingPackage = callingPackage; } /** {@hide} */ @@ -1362,6 +1366,7 @@ public final class Call { /** {@hide} */ final void internalUpdate(ParcelableCall parcelableCall, Map callIdMap) { + // First, we update the internal state as far as possible before firing any updates. Details details = Details.createFromParcelableCall(parcelableCall); boolean detailsChanged = !Objects.equals(mDetails, details); @@ -1377,7 +1382,7 @@ public final class Call { cannedTextResponsesChanged = true; } - VideoCallImpl newVideoCallImpl = parcelableCall.getVideoCallImpl(); + VideoCallImpl newVideoCallImpl = parcelableCall.getVideoCallImpl(mCallingPackage); boolean videoCallChanged = parcelableCall.isVideoCallProviderChanged() && !Objects.equals(mVideoCallImpl, newVideoCallImpl); if (videoCallChanged) { diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java index 10faa7d455a72..b7391b4c57acc 100644 --- a/telecomm/java/android/telecom/Connection.java +++ b/telecomm/java/android/telecom/Connection.java @@ -25,6 +25,7 @@ import android.annotation.Nullable; import android.annotation.SystemApi; import android.hardware.camera2.CameraManager; import android.net.Uri; +import android.os.Binder; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; @@ -799,7 +800,7 @@ public abstract class Connection extends Conferenceable { public static final int SESSION_EVENT_TX_STOP = 4; /** - * A camera failure has occurred for the selected camera. The {@link InCallService} can use + * A camera failure has occurred for the selected camera. The {@link VideoProvider} can use * this as a cue to inform the user the camera is not available. * @see #handleCallSessionEvent(int) */ @@ -807,12 +808,20 @@ public abstract class Connection extends Conferenceable { /** * Issued after {@link #SESSION_EVENT_CAMERA_FAILURE} when the camera is once again ready - * for operation. The {@link InCallService} can use this as a cue to inform the user that + * for operation. The {@link VideoProvider} can use this as a cue to inform the user that * the camera has become available again. * @see #handleCallSessionEvent(int) */ public static final int SESSION_EVENT_CAMERA_READY = 6; + /** + * Session event raised by Telecom when + * {@link android.telecom.InCallService.VideoCall#setCamera(String)} is called and the + * caller does not have the necessary {@link android.Manifest.permission#CAMERA} permission. + * @see #handleCallSessionEvent(int) + */ + public static final int SESSION_EVENT_CAMERA_PERMISSION_ERROR = 7; + /** * Session modify request was successful. * @see #receiveSessionModifyResponse(int, VideoProfile, VideoProfile) @@ -862,6 +871,8 @@ public abstract class Connection extends Conferenceable { private static final String SESSION_EVENT_TX_STOP_STR = "TX_STOP"; private static final String SESSION_EVENT_CAMERA_FAILURE_STR = "CAMERA_FAIL"; private static final String SESSION_EVENT_CAMERA_READY_STR = "CAMERA_READY"; + private static final String SESSION_EVENT_CAMERA_PERMISSION_ERROR_STR = + "CAMERA_PERMISSION_ERROR"; private static final String SESSION_EVENT_UNKNOWN_STR = "UNKNOWN"; private VideoProvider.VideoProviderHandler mMessageHandler; @@ -920,8 +931,17 @@ public abstract class Connection extends Conferenceable { break; } case MSG_SET_CAMERA: - onSetCamera((String) msg.obj); - break; + { + SomeArgs args = (SomeArgs) msg.obj; + try { + onSetCamera((String) args.arg1); + onSetCamera((String) args.arg1, (String) args.arg2, args.argi1, + args.argi2); + } finally { + args.recycle(); + } + } + break; case MSG_SET_PREVIEW_SURFACE: onSetPreviewSurface((Surface) msg.obj); break; @@ -976,8 +996,19 @@ public abstract class Connection extends Conferenceable { MSG_REMOVE_VIDEO_CALLBACK, videoCallbackBinder).sendToTarget(); } - public void setCamera(String cameraId) { - mMessageHandler.obtainMessage(MSG_SET_CAMERA, cameraId).sendToTarget(); + public void setCamera(String cameraId, String callingPackageName) { + SomeArgs args = SomeArgs.obtain(); + args.arg1 = cameraId; + // Propagate the calling package; originally determined in + // android.telecom.InCallService.VideoCall#setCamera(String) from the calling + // process. + args.arg2 = callingPackageName; + // Pass along the uid and pid of the calling app; this gets lost when we put the + // message onto the handler. These are required for Telecom to perform a permission + // check to see if the calling app is able to use the camera. + args.argi1 = Binder.getCallingUid(); + args.argi2 = Binder.getCallingPid(); + mMessageHandler.obtainMessage(MSG_SET_CAMERA, args).sendToTarget(); } public void setPreviewSurface(Surface surface) { @@ -1061,6 +1092,29 @@ public abstract class Connection extends Conferenceable { */ public abstract void onSetCamera(String cameraId); + /** + * Sets the camera to be used for the outgoing video. + *

+ * The {@link VideoProvider} should respond by communicating the capabilities of the chosen + * camera via + * {@link VideoProvider#changeCameraCapabilities(VideoProfile.CameraCapabilities)}. + *

+ * This prototype is used internally to ensure that the calling package name, UID and PID + * are sent to Telecom so that can perform a camera permission check on the caller. + *

+ * Sent from the {@link InCallService} via + * {@link InCallService.VideoCall#setCamera(String)}. + * + * @param cameraId The id of the camera (use ids as reported by + * {@link CameraManager#getCameraIdList()}). + * @param callingPackageName The AppOpps package name of the caller. + * @param callingUid The UID of the caller. + * @param callingPid The PID of the caller. + * @hide + */ + public void onSetCamera(String cameraId, String callingPackageName, int callingUid, + int callingPid) {} + /** * Sets the surface to be used for displaying a preview of what the user's camera is * currently capturing. When video transmission is enabled, this is the video signal which @@ -1247,7 +1301,8 @@ public abstract class Connection extends Conferenceable { * {@link VideoProvider#SESSION_EVENT_TX_START}, * {@link VideoProvider#SESSION_EVENT_TX_STOP}, * {@link VideoProvider#SESSION_EVENT_CAMERA_FAILURE}, - * {@link VideoProvider#SESSION_EVENT_CAMERA_READY}. + * {@link VideoProvider#SESSION_EVENT_CAMERA_READY}, + * {@link VideoProvider#SESSION_EVENT_CAMERA_FAILURE}. */ public void handleCallSessionEvent(int event) { if (mVideoCallbacks != null) { @@ -1396,6 +1451,8 @@ public abstract class Connection extends Conferenceable { return SESSION_EVENT_TX_START_STR; case SESSION_EVENT_TX_STOP: return SESSION_EVENT_TX_STOP_STR; + case SESSION_EVENT_CAMERA_PERMISSION_ERROR: + return SESSION_EVENT_CAMERA_PERMISSION_ERROR_STR; default: return SESSION_EVENT_UNKNOWN_STR + " " + event; } diff --git a/telecomm/java/android/telecom/InCallService.java b/telecomm/java/android/telecom/InCallService.java index 69de89d5ed746..5d68aaeda988e 100644 --- a/telecomm/java/android/telecom/InCallService.java +++ b/telecomm/java/android/telecom/InCallService.java @@ -87,7 +87,8 @@ public abstract class InCallService extends Service { switch (msg.what) { case MSG_SET_IN_CALL_ADAPTER: - mPhone = new Phone(new InCallAdapter((IInCallAdapter) msg.obj)); + String callingPackage = getApplicationContext().getOpPackageName(); + mPhone = new Phone(new InCallAdapter((IInCallAdapter) msg.obj), callingPackage); mPhone.addListener(mPhoneListener); onPhoneCreated(mPhone); break; @@ -664,7 +665,8 @@ public abstract class InCallService extends Service { * {@link Connection.VideoProvider#SESSION_EVENT_TX_START}, * {@link Connection.VideoProvider#SESSION_EVENT_TX_STOP}, * {@link Connection.VideoProvider#SESSION_EVENT_CAMERA_FAILURE}, - * {@link Connection.VideoProvider#SESSION_EVENT_CAMERA_READY}. + * {@link Connection.VideoProvider#SESSION_EVENT_CAMERA_READY}, + * {@link Connection.VideoProvider#SESSION_EVENT_CAMERA_PERMISSION_ERROR}. */ public abstract void onCallSessionEvent(int event); diff --git a/telecomm/java/android/telecom/ParcelableCall.java b/telecomm/java/android/telecom/ParcelableCall.java index f7a6595241e0a..a3fce9ca67097 100644 --- a/telecomm/java/android/telecom/ParcelableCall.java +++ b/telecomm/java/android/telecom/ParcelableCall.java @@ -190,10 +190,10 @@ public final class ParcelableCall implements Parcelable { * @return The video call. */ - public VideoCallImpl getVideoCallImpl() { + public VideoCallImpl getVideoCallImpl(String callingPackageName) { if (mVideoCall == null && mVideoCallProvider != null) { try { - mVideoCall = new VideoCallImpl(mVideoCallProvider); + mVideoCall = new VideoCallImpl(mVideoCallProvider, callingPackageName); } catch (RemoteException ignored) { // Ignore RemoteException. } diff --git a/telecomm/java/android/telecom/Phone.java b/telecomm/java/android/telecom/Phone.java index a4ef5601e5515..30ec5b350307d 100644 --- a/telecomm/java/android/telecom/Phone.java +++ b/telecomm/java/android/telecom/Phone.java @@ -125,13 +125,16 @@ public final class Phone { private boolean mCanAddCall = true; - Phone(InCallAdapter adapter) { + private final String mCallingPackage; + + Phone(InCallAdapter adapter, String callingPackage) { mInCallAdapter = adapter; + mCallingPackage = callingPackage; } final void internalAddCall(ParcelableCall parcelableCall) { Call call = new Call(this, parcelableCall.getId(), mInCallAdapter, - parcelableCall.getState()); + parcelableCall.getState(), mCallingPackage); mCallByTelecomCallId.put(parcelableCall.getId(), call); mCalls.add(call); checkCallTree(parcelableCall); diff --git a/telecomm/java/android/telecom/RemoteConnection.java b/telecomm/java/android/telecom/RemoteConnection.java index 0e4f53e4881a5..77e0e54861270 100644 --- a/telecomm/java/android/telecom/RemoteConnection.java +++ b/telecomm/java/android/telecom/RemoteConnection.java @@ -408,6 +408,8 @@ public final class RemoteConnection { private final IVideoProvider mVideoProviderBinder; + private final String mCallingPackage; + /** * ConcurrentHashMap constructor params: 8 is initial table size, 0.9f is * load factor before resizing, 1 means we only expect a single thread to @@ -416,8 +418,9 @@ public final class RemoteConnection { private final Set mCallbacks = Collections.newSetFromMap( new ConcurrentHashMap(8, 0.9f, 1)); - VideoProvider(IVideoProvider videoProviderBinder) { + VideoProvider(IVideoProvider videoProviderBinder, String callingPackage) { mVideoProviderBinder = videoProviderBinder; + mCallingPackage = callingPackage; try { mVideoProviderBinder.addVideoCallback(mVideoCallbackServant.getStub().asBinder()); } catch (RemoteException e) { @@ -452,7 +455,7 @@ public final class RemoteConnection { */ public void setCamera(String cameraId) { try { - mVideoProviderBinder.setCamera(cameraId); + mVideoProviderBinder.setCamera(cameraId, mCallingPackage); } catch (RemoteException e) { } } @@ -628,7 +631,7 @@ public final class RemoteConnection { * @hide */ RemoteConnection(String callId, IConnectionService connectionService, - ParcelableConnection connection) { + ParcelableConnection connection, String callingPackage) { mConnectionId = callId; mConnectionService = connectionService; mConnected = true; @@ -640,7 +643,7 @@ public final class RemoteConnection { mVideoState = connection.getVideoState(); IVideoProvider videoProvider = connection.getVideoProvider(); if (videoProvider != null) { - mVideoProvider = new RemoteConnection.VideoProvider(videoProvider); + mVideoProvider = new RemoteConnection.VideoProvider(videoProvider, callingPackage); } else { mVideoProvider = null; } diff --git a/telecomm/java/android/telecom/RemoteConnectionService.java b/telecomm/java/android/telecom/RemoteConnectionService.java index c65d5ef0b1148..0c7404aa5e954 100644 --- a/telecomm/java/android/telecom/RemoteConnectionService.java +++ b/telecomm/java/android/telecom/RemoteConnectionService.java @@ -283,9 +283,13 @@ final class RemoteConnectionService { @Override public void setVideoProvider(String callId, IVideoProvider videoProvider, Session.Info sessionInfo) { + + String callingPackage = mOurConnectionServiceImpl.getApplicationContext() + .getOpPackageName(); RemoteConnection.VideoProvider remoteVideoProvider = null; if (videoProvider != null) { - remoteVideoProvider = new RemoteConnection.VideoProvider(videoProvider); + remoteVideoProvider = new RemoteConnection.VideoProvider(videoProvider, + callingPackage); } findConnectionForAction(callId, "setVideoProvider") .setVideoProvider(remoteVideoProvider); @@ -351,8 +355,10 @@ final class RemoteConnectionService { @Override public void addExistingConnection(String callId, ParcelableConnection connection, Session.Info sessionInfo) { + String callingPackage = mOurConnectionServiceImpl.getApplicationContext(). + getOpPackageName(); RemoteConnection remoteConnection = new RemoteConnection(callId, - mOutgoingConnectionServiceRpc, connection); + mOutgoingConnectionServiceRpc, connection, callingPackage); mConnectionById.put(callId, remoteConnection); remoteConnection.registerCallback(new RemoteConnection.Callback() { @Override diff --git a/telecomm/java/android/telecom/VideoCallImpl.java b/telecomm/java/android/telecom/VideoCallImpl.java index e54abeebb8801..d8ede5c213164 100644 --- a/telecomm/java/android/telecom/VideoCallImpl.java +++ b/telecomm/java/android/telecom/VideoCallImpl.java @@ -43,6 +43,7 @@ public class VideoCallImpl extends VideoCall { private VideoCall.Callback mCallback; private int mVideoQuality = VideoProfile.QUALITY_UNKNOWN; private int mVideoState = VideoProfile.STATE_AUDIO_ONLY; + private final String mCallingPackageName; private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() { @Override @@ -197,12 +198,13 @@ public class VideoCallImpl extends VideoCall { private Handler mHandler; - VideoCallImpl(IVideoProvider videoProvider) throws RemoteException { + VideoCallImpl(IVideoProvider videoProvider, String callingPackageName) throws RemoteException { mVideoProvider = videoProvider; mVideoProvider.asBinder().linkToDeath(mDeathRecipient, 0); mBinder = new VideoCallListenerBinder(); mVideoProvider.addVideoCallback(mBinder); + mCallingPackageName = callingPackageName; } public void destroy() { @@ -240,7 +242,8 @@ public class VideoCallImpl extends VideoCall { /** {@inheritDoc} */ public void setCamera(String cameraId) { try { - mVideoProvider.setCamera(cameraId); + Log.w(this, "setCamera: cameraId=%s, calling=%s", cameraId, mCallingPackageName); + mVideoProvider.setCamera(cameraId, mCallingPackageName); } catch (RemoteException e) { } } diff --git a/telecomm/java/com/android/internal/telecom/IVideoProvider.aidl b/telecomm/java/com/android/internal/telecom/IVideoProvider.aidl index 68e5fd48e1aca..a109e90243fe9 100644 --- a/telecomm/java/com/android/internal/telecom/IVideoProvider.aidl +++ b/telecomm/java/com/android/internal/telecom/IVideoProvider.aidl @@ -30,7 +30,7 @@ oneway interface IVideoProvider { void removeVideoCallback(IBinder videoCallbackBinder); - void setCamera(String cameraId); + void setCamera(String cameraId, in String mCallingPackageName); void setPreviewSurface(in Surface surface);