API review cleanups/changes.

- Change onCreateIncomingConnectionFailed/onCreateOutgoingConnectionFailed
to accept the connection mgr phone account as the first parameter.
- For the video APIs, pass the target SDK of the caller into along so
that the Telecom permission check can have fallback behavior for older API
versions.
- Add guidance for how UX should be shown in onShowIncomingCallUi API.
API guidance follows how the Dialer app shows its notification and full
screen UX.

Test: Manual, CTS.
Bug: 35767711
Bug: 35767096
Change-Id: Ib343f0eda1a4d067a38c553f33f140b4efcf3e48
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index e939b2e..98f7ccb 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -1007,6 +1007,7 @@
     private int mState;
     private List<String> mCannedTextResponses = null;
     private String mCallingPackage;
+    private int mTargetSdkVersion;
     private String mRemainingPostDialSequence;
     private VideoCallImpl mVideoCallImpl;
     private RttCall mRttCall;
@@ -1540,22 +1541,25 @@
     }
 
     /** {@hide} */
-    Call(Phone phone, String telecomCallId, InCallAdapter inCallAdapter, String callingPackage) {
+    Call(Phone phone, String telecomCallId, InCallAdapter inCallAdapter, String callingPackage,
+         int targetSdkVersion) {
         mPhone = phone;
         mTelecomCallId = telecomCallId;
         mInCallAdapter = inCallAdapter;
         mState = STATE_NEW;
         mCallingPackage = callingPackage;
+        mTargetSdkVersion = targetSdkVersion;
     }
 
     /** {@hide} */
     Call(Phone phone, String telecomCallId, InCallAdapter inCallAdapter, int state,
-            String callingPackage) {
+            String callingPackage, int targetSdkVersion) {
         mPhone = phone;
         mTelecomCallId = telecomCallId;
         mInCallAdapter = inCallAdapter;
         mState = state;
         mCallingPackage = callingPackage;
+        mTargetSdkVersion = targetSdkVersion;
     }
 
     /** {@hide} */
@@ -1581,7 +1585,8 @@
             cannedTextResponsesChanged = true;
         }
 
-        VideoCallImpl newVideoCallImpl = parcelableCall.getVideoCallImpl(mCallingPackage);
+        VideoCallImpl newVideoCallImpl = parcelableCall.getVideoCallImpl(mCallingPackage,
+                mTargetSdkVersion);
         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 3e690b9..417fa3b 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -23,6 +23,8 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
+import android.app.Notification;
+import android.content.Intent;
 import android.hardware.camera2.CameraManager;
 import android.net.Uri;
 import android.os.Binder;
@@ -1005,7 +1007,7 @@
                         try {
                             onSetCamera((String) args.arg1);
                             onSetCamera((String) args.arg1, (String) args.arg2, args.argi1,
-                                    args.argi2);
+                                    args.argi2, args.argi3);
                         } finally {
                             args.recycle();
                         }
@@ -1065,7 +1067,9 @@
                         MSG_REMOVE_VIDEO_CALLBACK, videoCallbackBinder).sendToTarget();
             }
 
-            public void setCamera(String cameraId, String callingPackageName) {
+            public void setCamera(String cameraId, String callingPackageName,
+                                  int targetSdkVersion) {
+
                 SomeArgs args = SomeArgs.obtain();
                 args.arg1 = cameraId;
                 // Propagate the calling package; originally determined in
@@ -1077,6 +1081,9 @@
                 // check to see if the calling app is able to use the camera.
                 args.argi1 = Binder.getCallingUid();
                 args.argi2 = Binder.getCallingPid();
+                // Pass along the target SDK version of the calling InCallService.  This is used to
+                // maintain backwards compatibility of the API for older callers.
+                args.argi3 = targetSdkVersion;
                 mMessageHandler.obtainMessage(MSG_SET_CAMERA, args).sendToTarget();
             }
 
@@ -1179,10 +1186,11 @@
          * @param callingPackageName The AppOpps package name of the caller.
          * @param callingUid The UID of the caller.
          * @param callingPid The PID of the caller.
+         * @param targetSdkVersion The target SDK version of the caller.
          * @hide
          */
         public void onSetCamera(String cameraId, String callingPackageName, int callingUid,
-                int callingPid) {}
+                int callingPid, int targetSdkVersion) {}
 
         /**
          * Sets the surface to be used for displaying a preview of what the user's camera is
@@ -2592,6 +2600,41 @@
      * regular {@link ConnectionService}, the Telecom framework will display its own incoming call
      * user interface to allow the user to choose whether to answer the new incoming call and
      * disconnect other ongoing calls, or to reject the new incoming call.
+     * <p>
+     * You should trigger the display of the incoming call user interface for your application by
+     * showing a {@link Notification} with a full-screen {@link Intent} specified.
+     * For example:
+     * <pre><code>
+     *     // Create an intent which triggers your fullscreen incoming call user interface.
+     *     Intent intent = new Intent(Intent.ACTION_MAIN, null);
+     *     intent.setFlags(Intent.FLAG_ACTIVITY_NO_USER_ACTION | Intent.FLAG_ACTIVITY_NEW_TASK);
+     *     intent.setClass(context, YourIncomingCallActivity.class);
+     *     PendingIntent pendingIntent = PendingIntent.getActivity(context, 1, intent, 0);
+     *
+     *     // Build the notification as an ongoing high priority item; this ensures it will show as
+     *     // a heads up notification which slides down over top of the current content.
+     *     final Notification.Builder builder = new Notification.Builder(context);
+     *     builder.setOngoing(true);
+     *     builder.setPriority(Notification.PRIORITY_HIGH);
+     *
+     *     // Set notification content intent to take user to fullscreen UI if user taps on the
+     *     // notification body.
+     *     builder.setContentIntent(pendingIntent);
+     *     // Set full screen intent to trigger display of the fullscreen UI when the notification
+     *     // manager deems it appropriate.
+     *     builder.setFullScreenIntent(pendingIntent, true);
+     *
+     *     // Setup notification content.
+     *     builder.setSmallIcon( yourIconResourceId );
+     *     builder.setContentTitle("Your notification title");
+     *     builder.setContentText("Your notification content.");
+     *
+     *     // Use builder.addAction(..) to add buttons to answer or reject the call.
+     *
+     *     NotificationManager notificationManager = mContext.getSystemService(
+     *         NotificationManager.class);
+     *     notificationManager.notify(YOUR_TAG, YOUR_ID, builder.build());
+     * </code></pre>
      */
     public void onShowIncomingCallUi() {}
 
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index 6e10029..79f085c 100644
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -214,6 +214,7 @@
 
         @Override
         public void createConnectionFailed(
+                PhoneAccountHandle connectionManagerPhoneAccount,
                 String callId,
                 ConnectionRequest request,
                 boolean isIncoming,
@@ -224,6 +225,7 @@
                 args.arg1 = callId;
                 args.arg2 = request;
                 args.arg3 = Log.createSubsession();
+                args.arg4 = connectionManagerPhoneAccount;
                 args.argi1 = isIncoming ? 1 : 0;
                 mHandler.obtainMessage(MSG_CREATE_CONNECTION_FAILED, args).sendToTarget();
             } finally {
@@ -581,6 +583,8 @@
                         final String id = (String) args.arg1;
                         final ConnectionRequest request = (ConnectionRequest) args.arg2;
                         final boolean isIncoming = args.argi1 == 1;
+                        final PhoneAccountHandle connectionMgrPhoneAccount =
+                                (PhoneAccountHandle) args.arg4;
                         if (!mAreAccountsInitialized) {
                             Log.d(this, "Enqueueing pre-init request %s", id);
                             mPreInitializationConnectionRequests.add(
@@ -589,12 +593,14 @@
                                             null /*lock*/) {
                                         @Override
                                         public void loggedRun() {
-                                            createConnectionFailed(id, request, isIncoming);
+                                            createConnectionFailed(connectionMgrPhoneAccount, id,
+                                                    request, isIncoming);
                                         }
                                     }.prepare());
                         } else {
                             Log.i(this, "createConnectionFailed %s", id);
-                            createConnectionFailed(id, request, isIncoming);
+                            createConnectionFailed(connectionMgrPhoneAccount, id, request,
+                                    isIncoming);
                         }
                     } finally {
                         args.recycle();
@@ -1225,14 +1231,15 @@
         }
     }
 
-    private void createConnectionFailed(final String callId, final ConnectionRequest request,
-            boolean isIncoming) {
+    private void createConnectionFailed(final PhoneAccountHandle callManagerAccount,
+                                        final String callId, final ConnectionRequest request,
+                                        boolean isIncoming) {
 
         Log.i(this, "createConnectionFailed %s", callId);
         if (isIncoming) {
-            onCreateIncomingConnectionFailed(request);
+            onCreateIncomingConnectionFailed(callManagerAccount, request);
         } else {
-            onCreateOutgoingConnectionFailed(request);
+            onCreateOutgoingConnectionFailed(callManagerAccount, request);
         }
     }
 
@@ -1682,9 +1689,12 @@
      * <p>
      * See {@link TelecomManager#isIncomingCallPermitted(PhoneAccountHandle)} for more information.
      *
+     * @param connectionManagerPhoneAccount See description at
+     *         {@link #onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)}.
      * @param request The incoming connection request.
      */
-    public void onCreateIncomingConnectionFailed(ConnectionRequest request) {
+    public void onCreateIncomingConnectionFailed(PhoneAccountHandle connectionManagerPhoneAccount,
+                                                 ConnectionRequest request) {
     }
 
     /**
@@ -1698,9 +1708,12 @@
      * <p>
      * See {@link TelecomManager#isOutgoingCallPermitted(PhoneAccountHandle)} for more information.
      *
+     * @param connectionManagerPhoneAccount See description at
+     *         {@link #onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)}.
      * @param request The outgoing connection request.
      */
-    public void onCreateOutgoingConnectionFailed(ConnectionRequest request) {
+    public void onCreateOutgoingConnectionFailed(PhoneAccountHandle connectionManagerPhoneAccount,
+                                                 ConnectionRequest request) {
     }
 
     /**
diff --git a/telecomm/java/android/telecom/InCallService.java b/telecomm/java/android/telecom/InCallService.java
index 4bc64c0..c4f5ffc 100644
--- a/telecomm/java/android/telecom/InCallService.java
+++ b/telecomm/java/android/telecom/InCallService.java
@@ -89,7 +89,8 @@
             switch (msg.what) {
                 case MSG_SET_IN_CALL_ADAPTER:
                     String callingPackage = getApplicationContext().getOpPackageName();
-                    mPhone = new Phone(new InCallAdapter((IInCallAdapter) msg.obj), callingPackage);
+                    mPhone = new Phone(new InCallAdapter((IInCallAdapter) msg.obj), callingPackage,
+                            getApplicationContext().getApplicationInfo().targetSdkVersion);
                     mPhone.addListener(mPhoneListener);
                     onPhoneCreated(mPhone);
                     break;
diff --git a/telecomm/java/android/telecom/ParcelableCall.java b/telecomm/java/android/telecom/ParcelableCall.java
index 975aa5a..85a92d1 100644
--- a/telecomm/java/android/telecom/ParcelableCall.java
+++ b/telecomm/java/android/telecom/ParcelableCall.java
@@ -193,13 +193,16 @@
 
     /**
      * Returns an object for remotely communicating through the video call provider's binder.
-
+     *
+     * @param callingPackageName the package name of the calling InCallService.
+     * @param targetSdkVersion the target SDK version of the calling InCallService.
      * @return The video call.
      */
-    public VideoCallImpl getVideoCallImpl(String callingPackageName) {
+    public VideoCallImpl getVideoCallImpl(String callingPackageName, int targetSdkVersion) {
         if (mVideoCall == null && mVideoCallProvider != null) {
             try {
-                mVideoCall = new VideoCallImpl(mVideoCallProvider, callingPackageName);
+                mVideoCall = new VideoCallImpl(mVideoCallProvider, callingPackageName,
+                        targetSdkVersion);
             } catch (RemoteException ignored) {
                 // Ignore RemoteException.
             }
diff --git a/telecomm/java/android/telecom/Phone.java b/telecomm/java/android/telecom/Phone.java
index ebd04c7..524dc70 100644
--- a/telecomm/java/android/telecom/Phone.java
+++ b/telecomm/java/android/telecom/Phone.java
@@ -127,14 +127,20 @@
 
     private final String mCallingPackage;
 
-    Phone(InCallAdapter adapter, String callingPackage) {
+    /**
+     * The Target SDK version of the InCallService implementation.
+     */
+    private final int mTargetSdkVersion;
+
+    Phone(InCallAdapter adapter, String callingPackage, int targetSdkVersion) {
         mInCallAdapter = adapter;
         mCallingPackage = callingPackage;
+        mTargetSdkVersion = targetSdkVersion;
     }
 
     final void internalAddCall(ParcelableCall parcelableCall) {
         Call call = new Call(this, parcelableCall.getId(), mInCallAdapter,
-                parcelableCall.getState(), mCallingPackage);
+                parcelableCall.getState(), mCallingPackage, mTargetSdkVersion);
         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 77e0e54..e121238 100644
--- a/telecomm/java/android/telecom/RemoteConnection.java
+++ b/telecomm/java/android/telecom/RemoteConnection.java
@@ -410,6 +410,8 @@
 
         private final String mCallingPackage;
 
+        private final int mTargetSdkVersion;
+
         /**
          * ConcurrentHashMap constructor params: 8 is initial table size, 0.9f is
          * load factor before resizing, 1 means we only expect a single thread to
@@ -418,9 +420,12 @@
         private final Set<Callback> mCallbacks = Collections.newSetFromMap(
                 new ConcurrentHashMap<Callback, Boolean>(8, 0.9f, 1));
 
-        VideoProvider(IVideoProvider videoProviderBinder, String callingPackage) {
+        VideoProvider(IVideoProvider videoProviderBinder, String callingPackage,
+                      int targetSdkVersion) {
+
             mVideoProviderBinder = videoProviderBinder;
             mCallingPackage = callingPackage;
+            mTargetSdkVersion = targetSdkVersion;
             try {
                 mVideoProviderBinder.addVideoCallback(mVideoCallbackServant.getStub().asBinder());
             } catch (RemoteException e) {
@@ -455,7 +460,7 @@
          */
         public void setCamera(String cameraId) {
             try {
-                mVideoProviderBinder.setCamera(cameraId, mCallingPackage);
+                mVideoProviderBinder.setCamera(cameraId, mCallingPackage, mTargetSdkVersion);
             } catch (RemoteException e) {
             }
         }
@@ -631,7 +636,7 @@
      * @hide
      */
     RemoteConnection(String callId, IConnectionService connectionService,
-            ParcelableConnection connection, String callingPackage) {
+            ParcelableConnection connection, String callingPackage, int targetSdkVersion) {
         mConnectionId = callId;
         mConnectionService = connectionService;
         mConnected = true;
@@ -643,7 +648,8 @@
         mVideoState = connection.getVideoState();
         IVideoProvider videoProvider = connection.getVideoProvider();
         if (videoProvider != null) {
-            mVideoProvider = new RemoteConnection.VideoProvider(videoProvider, callingPackage);
+            mVideoProvider = new RemoteConnection.VideoProvider(videoProvider, callingPackage,
+                    targetSdkVersion);
         } else {
             mVideoProvider = null;
         }
diff --git a/telecomm/java/android/telecom/RemoteConnectionService.java b/telecomm/java/android/telecom/RemoteConnectionService.java
index 60a40f5..b00c0aa 100644
--- a/telecomm/java/android/telecom/RemoteConnectionService.java
+++ b/telecomm/java/android/telecom/RemoteConnectionService.java
@@ -286,10 +286,11 @@
 
             String callingPackage = mOurConnectionServiceImpl.getApplicationContext()
                     .getOpPackageName();
+            int targetSdkVersion = mOurConnectionServiceImpl.getApplicationInfo().targetSdkVersion;
             RemoteConnection.VideoProvider remoteVideoProvider = null;
             if (videoProvider != null) {
                 remoteVideoProvider = new RemoteConnection.VideoProvider(videoProvider,
-                        callingPackage);
+                        callingPackage, targetSdkVersion);
             }
             findConnectionForAction(callId, "setVideoProvider")
                     .setVideoProvider(remoteVideoProvider);
@@ -357,8 +358,11 @@
                 Session.Info sessionInfo) {
             String callingPackage = mOurConnectionServiceImpl.getApplicationContext().
                     getOpPackageName();
+            int callingTargetSdkVersion = mOurConnectionServiceImpl.getApplicationInfo()
+                    .targetSdkVersion;
             RemoteConnection remoteConnection = new RemoteConnection(callId,
-                    mOutgoingConnectionServiceRpc, connection, callingPackage);
+                    mOutgoingConnectionServiceRpc, connection, callingPackage,
+                    callingTargetSdkVersion);
             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 d8ede5c..429a434 100644
--- a/telecomm/java/android/telecom/VideoCallImpl.java
+++ b/telecomm/java/android/telecom/VideoCallImpl.java
@@ -44,6 +44,7 @@
     private int mVideoQuality = VideoProfile.QUALITY_UNKNOWN;
     private int mVideoState = VideoProfile.STATE_AUDIO_ONLY;
     private final String mCallingPackageName;
+    private final int mTargetSdkVersion;
 
     private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
         @Override
@@ -198,13 +199,15 @@
 
     private Handler mHandler;
 
-    VideoCallImpl(IVideoProvider videoProvider, String callingPackageName) throws RemoteException {
+    VideoCallImpl(IVideoProvider videoProvider, String callingPackageName, int targetSdkVersion)
+            throws RemoteException {
         mVideoProvider = videoProvider;
         mVideoProvider.asBinder().linkToDeath(mDeathRecipient, 0);
 
         mBinder = new VideoCallListenerBinder();
         mVideoProvider.addVideoCallback(mBinder);
         mCallingPackageName = callingPackageName;
+        mTargetSdkVersion = targetSdkVersion;
     }
 
     public void destroy() {
@@ -243,7 +246,7 @@
     public void setCamera(String cameraId) {
         try {
             Log.w(this, "setCamera: cameraId=%s, calling=%s", cameraId, mCallingPackageName);
-            mVideoProvider.setCamera(cameraId, mCallingPackageName);
+            mVideoProvider.setCamera(cameraId, mCallingPackageName, mTargetSdkVersion);
         } catch (RemoteException e) {
         }
     }