API review cleanups.

- Modify the video call permission check to use the API version of the
caller to determine whether to use the API26
SESSION_EVENT_CAMERA_PERMISSION_ERROR event.  If the caller is using an
older API, use the more generic SESSION_EVENT_CAMERA_FAILURE.
- Update the sample Self Managed calling app to use the incoming call UX
guidance specified in the Javadocs.
- Fix bug in InCallController which could cause InCallService to see
self-managed connections.

Test: Manual
Bug: 35767096
Bug: 35767711
Change-Id: I3e5e2b84eb026eec37f884029bb77d446a04e255
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 7ace0e0..4caa4a3 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -262,6 +262,7 @@
                 <category android:name="android.intent.category.DEFAULT" />
             </intent-filter>
         </activity>
+        <activity android:name=".testapps.IncomingSelfManagedCallActivity" />
 
         <receiver android:name=".components.PrimaryCallReceiver"
                 android:exported="true"
diff --git a/src/com/android/server/telecom/ConnectionServiceWrapper.java b/src/com/android/server/telecom/ConnectionServiceWrapper.java
index df1bb4a..7a2043a 100644
--- a/src/com/android/server/telecom/ConnectionServiceWrapper.java
+++ b/src/com/android/server/telecom/ConnectionServiceWrapper.java
@@ -923,7 +923,9 @@
                             Log.piiHandle(call.getHandle()));
                     try {
                         logOutgoing("createConnectionFailed %s", callId);
-                        mServiceInterface.createConnectionFailed(callId,
+                        mServiceInterface.createConnectionFailed(
+                                call.getConnectionManagerPhoneAccount(),
+                                callId,
                                 new ConnectionRequest(
                                         call.getTargetPhoneAccount(),
                                         call.getHandle(),
diff --git a/src/com/android/server/telecom/InCallController.java b/src/com/android/server/telecom/InCallController.java
index 85b5e70..843ba19 100644
--- a/src/com/android/server/telecom/InCallController.java
+++ b/src/com/android/server/telecom/InCallController.java
@@ -687,6 +687,10 @@
                     continue;
                 }
 
+                if (call.isSelfManaged() && !info.isSelfManagedCallsSupported()) {
+                    continue;
+                }
+
                 // Only send the RTT call if it's a UI in-call service
                 boolean includeRttCall = info.equals(mInCallServiceConnection.getInfo());
 
diff --git a/src/com/android/server/telecom/VideoProviderProxy.java b/src/com/android/server/telecom/VideoProviderProxy.java
index 480d8c9..26018de 100644
--- a/src/com/android/server/telecom/VideoProviderProxy.java
+++ b/src/com/android/server/telecom/VideoProviderProxy.java
@@ -21,6 +21,7 @@
 import android.content.Context;
 import android.net.Uri;
 import android.os.Binder;
+import android.os.Build;
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.RemoteException;
@@ -303,10 +304,12 @@
      * @param callingPackage The package calling in.
      * @param callingUid The UID of the caller.
      * @param callingPid The PID of the caller.
+     * @param targetSdkVersion The target SDK version of the calling InCallService where the camera
+     *      request originated.
      */
     @Override
     public void onSetCamera(String cameraId, String callingPackage, int callingUid,
-            int callingPid) {
+            int callingPid, int targetSdkVersion) {
         synchronized (mLock) {
             logFromInCall("setCamera: " + cameraId + " callingPackage=" + callingPackage +
                     "; callingUid=" + callingUid);
@@ -316,15 +319,24 @@
                     // Calling app is not permitted to use the camera.  Ignore the request and send
                     // back a call session event indicating the error.
                     Log.i(this, "onSetCamera: camera permission denied; package=%d, uid=%d, "
-                            + "pid=%d",
-                            callingPackage, callingUid, callingPid);
-                    VideoProviderProxy.this.handleCallSessionEvent(
-                            Connection.VideoProvider.SESSION_EVENT_CAMERA_PERMISSION_ERROR);
+                            + "pid=%d, targetSdkVersion=%d",
+                            callingPackage, callingUid, callingPid, targetSdkVersion);
+
+                    // API 26 introduces a new camera permission error we can use here since the
+                    // caller supports that API version.
+                    if (targetSdkVersion > Build.VERSION_CODES.N_MR1) {
+                        VideoProviderProxy.this.handleCallSessionEvent(
+                                Connection.VideoProvider.SESSION_EVENT_CAMERA_PERMISSION_ERROR);
+                    } else {
+                        VideoProviderProxy.this.handleCallSessionEvent(
+                                Connection.VideoProvider.SESSION_EVENT_CAMERA_FAILURE);
+                    }
                     return;
                 }
             }
             try {
-                mConectionServiceVideoProvider.setCamera(cameraId, callingPackage);
+                mConectionServiceVideoProvider.setCamera(cameraId, callingPackage,
+                        targetSdkVersion);
             } catch (RemoteException e) {
                 VideoProviderProxy.this.handleCallSessionEvent(
                         Connection.VideoProvider.SESSION_EVENT_CAMERA_FAILURE);
diff --git a/testapps/AndroidManifest.xml b/testapps/AndroidManifest.xml
index a6a0d76..776759e 100644
--- a/testapps/AndroidManifest.xml
+++ b/testapps/AndroidManifest.xml
@@ -173,6 +173,14 @@
           </intent-filter>
         </activity>
 
+        <activity android:name="com.android.server.telecom.testapps.IncomingSelfManagedCallActivity"
+                  android:label="@string/selfManagedCallingActivityLabel"
+                  android:process="com.android.server.telecom.testapps.SelfMangingCallingApp">
+          <intent-filter>
+              <action android:name="android.intent.action.MAIN" />
+          </intent-filter>
+        </activity>
+
         <service android:name="com.android.server.telecom.testapps.SelfManagedConnectionService"
                  android:permission="android.permission.BIND_TELECOM_CONNECTION_SERVICE"
                  android:process="com.android.server.telecom.testapps.SelfMangingCallingApp">
@@ -180,5 +188,9 @@
               <action android:name="android.telecom.ConnectionService" />
           </intent-filter>
         </service>
+
+        <receiver android:exported="false"
+            android:process="com.android.server.telecom.testapps.SelfMangingCallingApp"
+            android:name="com.android.server.telecom.testapps.SelfManagedCallNotificationReceiver" />
     </application>
 </manifest>
diff --git a/testapps/res/drawable-hdpi/ic_android_black_24dp.png b/testapps/res/drawable-hdpi/ic_android_black_24dp.png
new file mode 100644
index 0000000..ed3ee45
--- /dev/null
+++ b/testapps/res/drawable-hdpi/ic_android_black_24dp.png
Binary files differ
diff --git a/testapps/res/drawable-mdpi/ic_android_black_24dp.png b/testapps/res/drawable-mdpi/ic_android_black_24dp.png
new file mode 100644
index 0000000..a4add51
--- /dev/null
+++ b/testapps/res/drawable-mdpi/ic_android_black_24dp.png
Binary files differ
diff --git a/testapps/res/drawable-xhdpi/ic_android_black_24dp.png b/testapps/res/drawable-xhdpi/ic_android_black_24dp.png
new file mode 100644
index 0000000..41558f2
--- /dev/null
+++ b/testapps/res/drawable-xhdpi/ic_android_black_24dp.png
Binary files differ
diff --git a/testapps/res/drawable-xxhdpi/ic_android_black_24dp.png b/testapps/res/drawable-xxhdpi/ic_android_black_24dp.png
new file mode 100644
index 0000000..6006b12
--- /dev/null
+++ b/testapps/res/drawable-xxhdpi/ic_android_black_24dp.png
Binary files differ
diff --git a/testapps/res/drawable-xxxhdpi/ic_android_black_24dp.png b/testapps/res/drawable-xxxhdpi/ic_android_black_24dp.png
new file mode 100644
index 0000000..4f935bf
--- /dev/null
+++ b/testapps/res/drawable-xxxhdpi/ic_android_black_24dp.png
Binary files differ
diff --git a/testapps/res/layout/self_managed_incoming_call.xml b/testapps/res/layout/self_managed_incoming_call.xml
new file mode 100644
index 0000000..c346342
--- /dev/null
+++ b/testapps/res/layout/self_managed_incoming_call.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2017 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical" android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <TextView
+        android:text="Incoming Call!"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:id="@+id/incomingCallText" />
+
+    <Button
+        android:text="Answer Call"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:id="@+id/answerCallButton" />
+
+    <Button
+        android:text="Reject Call"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:id="@+id/rejectCallButton" />
+</LinearLayout>
\ No newline at end of file
diff --git a/testapps/res/layout/self_managed_sample_main.xml b/testapps/res/layout/self_managed_sample_main.xml
index f239997..144d6ec 100644
--- a/testapps/res/layout/self_managed_sample_main.xml
+++ b/testapps/res/layout/self_managed_sample_main.xml
@@ -68,6 +68,11 @@
                 android:layout_height="wrap_content"
                 android:text="Incoming Call"
                 android:id="@+id/placeIncomingCallButton" />
+            <Button
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="Incoming Call (Delay)"
+                android:id="@+id/placeIncomingCallDelayButton" />
         </TableRow>
         <TableRow android:layout_span="2">
             <ListView
diff --git a/testapps/src/com/android/server/telecom/testapps/IncomingSelfManagedCallActivity.java b/testapps/src/com/android/server/telecom/testapps/IncomingSelfManagedCallActivity.java
new file mode 100644
index 0000000..05b6a6b
--- /dev/null
+++ b/testapps/src/com/android/server/telecom/testapps/IncomingSelfManagedCallActivity.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.telecom.testapps;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.telecom.Log;
+import android.telephony.DisconnectCause;
+import android.view.View;
+import android.widget.Button;
+
+import com.android.server.telecom.testapps.R;
+
+/**
+ * Sample Incoming Call activity for Self-Managed calls.
+ */
+public class IncomingSelfManagedCallActivity extends Activity {
+    public static final String EXTRA_CALL_ID = "com.android.server.telecom.testapps.extra.CALL_ID";
+
+    private Button mAnswerCallButton;
+    private Button mRejectCallButton;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        Intent launchingIntent = getIntent();
+        int callId = launchingIntent.getIntExtra(EXTRA_CALL_ID, 0);
+        Log.i(this, "showing fullscreen answer ux for call id %d", callId);
+
+        setContentView(R.layout.self_managed_incoming_call);
+        final SelfManagedConnection connection = SelfManagedCallList.getInstance()
+                .getConnectionById(callId);
+        mAnswerCallButton = (Button) findViewById(R.id.answerCallButton);
+        mAnswerCallButton.setOnClickListener((View v) -> {
+            if (connection != null) {
+                connection.setConnectionActive();
+            }
+            finish();
+        });
+        mRejectCallButton = (Button) findViewById(R.id.rejectCallButton);
+        mRejectCallButton.setOnClickListener((View v) -> {
+            if (connection != null) {
+                connection.setConnectionDisconnected(DisconnectCause.INCOMING_REJECTED);
+                connection.destroy();
+            }
+            finish();
+        });
+    }
+}
\ No newline at end of file
diff --git a/testapps/src/com/android/server/telecom/testapps/SelfManagedCallList.java b/testapps/src/com/android/server/telecom/testapps/SelfManagedCallList.java
index e0d7442..1d6367e 100644
--- a/testapps/src/com/android/server/telecom/testapps/SelfManagedCallList.java
+++ b/testapps/src/com/android/server/telecom/testapps/SelfManagedCallList.java
@@ -29,6 +29,7 @@
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
 
 /**
  * Manages the list of {@link SelfManagedConnection} active in the sample third-party calling app.
@@ -64,6 +65,25 @@
 
     private List<SelfManagedConnection> mConnections = new ArrayList<>();
 
+    private SelfManagedConnection.Listener mConnectionListener =
+            new SelfManagedConnection.Listener() {
+                @Override
+                public void onConnectionStateChanged(SelfManagedConnection connection) {
+                    notifyCallModified();
+                }
+
+                @Override
+                public void onConnectionRemoved(SelfManagedConnection connection) {
+                    removeConnection(connection);
+                    notifyCallModified();
+                }
+    };
+
+    public SelfManagedConnection.Listener getConnectionListener() {
+        return mConnectionListener;
+    }
+
+
     public void setListener(Listener listener) {
         mListener = listener;
     }
@@ -125,6 +145,13 @@
         return mConnections;
     }
 
+    public SelfManagedConnection getConnectionById(int callId) {
+        Optional<SelfManagedConnection> foundOptional = mConnections.stream()
+                .filter((c) -> {return c.getCallId() == callId;})
+                .findFirst();
+        return foundOptional.orElse(null);
+    }
+
     public void notifyCallModified() {
         if (mListener != null) {
             mListener.onConnectionListChanged();
diff --git a/testapps/src/com/android/server/telecom/testapps/SelfManagedCallNotificationReceiver.java b/testapps/src/com/android/server/telecom/testapps/SelfManagedCallNotificationReceiver.java
new file mode 100644
index 0000000..81a9bfa
--- /dev/null
+++ b/testapps/src/com/android/server/telecom/testapps/SelfManagedCallNotificationReceiver.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.telecom.testapps;
+
+import android.app.NotificationManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.telecom.Log;
+import android.telephony.DisconnectCause;
+
+/**
+ * Handles actions from the self-managed calling sample app incoming call UX.
+ */
+public class SelfManagedCallNotificationReceiver extends BroadcastReceiver {
+    public static final String ACTION_ANSWER_CALL =
+            "com.android.server.telecom.testapps.action.ANSWER_CALL";
+    public static final String ACTION_REJECT_CALL =
+            "com.android.server.telecom.testapps.action.REJECT_CALL";
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        String action = intent.getAction();
+        int callId = intent.getIntExtra(IncomingSelfManagedCallActivity.EXTRA_CALL_ID, 0);
+        NotificationManager notificationManager = context.getSystemService(
+                NotificationManager.class);
+        SelfManagedConnection connection = SelfManagedCallList.getInstance()
+                .getConnectionById(callId);
+        switch (action) {
+            case ACTION_ANSWER_CALL:
+                Log.i(this, "onReceive - answerCall %d", callId);
+                if (connection != null) {
+                    connection.setConnectionActive();
+                }
+                notificationManager.cancel(SelfManagedConnection.CALL_NOTIFICATION, callId);
+                break;
+
+            case ACTION_REJECT_CALL:
+                Log.i(this, "onReceive - rejectCall %d", callId);
+                if (connection != null) {
+                    connection.setConnectionDisconnected(DisconnectCause.INCOMING_REJECTED);
+                    connection.destroy();
+                }
+                notificationManager.cancel(SelfManagedConnection.CALL_NOTIFICATION, callId);
+                break;
+        }
+    }
+}
diff --git a/testapps/src/com/android/server/telecom/testapps/SelfManagedCallingActivity.java b/testapps/src/com/android/server/telecom/testapps/SelfManagedCallingActivity.java
index 8b7eae0..c8f6157 100644
--- a/testapps/src/com/android/server/telecom/testapps/SelfManagedCallingActivity.java
+++ b/testapps/src/com/android/server/telecom/testapps/SelfManagedCallingActivity.java
@@ -24,6 +24,7 @@
 import android.telecom.TelecomManager;
 import android.util.Log;
 import android.view.View;
+import android.view.WindowManager;
 import android.widget.Button;
 import android.widget.CheckBox;
 import android.widget.EditText;
@@ -45,6 +46,7 @@
     private CheckBox mCheckIfPermittedBeforeCalling;
     private Button mPlaceOutgoingCallButton;
     private Button mPlaceIncomingCallButton;
+    private Button mPlaceIncomingCallDelayButton;
     private RadioButton mUseAcct1Button;
     private RadioButton mUseAcct2Button;
     private EditText mNumber;
@@ -76,6 +78,12 @@
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
+        int flags =
+                WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
+                        | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
+                        | WindowManager.LayoutParams.FLAG_IGNORE_CHEEK_PRESSES;
+
+        getWindow().addFlags(flags);
         setContentView(R.layout.self_managed_sample_main);
         mCheckIfPermittedBeforeCalling = (CheckBox) findViewById(
                 R.id.checkIfPermittedBeforeCalling);
@@ -93,6 +101,20 @@
                 placeIncomingCall();
             }
         });
+
+        mPlaceIncomingCallDelayButton = (Button) findViewById(R.id.placeIncomingCallDelayButton);
+        mPlaceIncomingCallDelayButton.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                // Delay the incoming call so that we can turn off the screen and
+                try {
+                    Thread.sleep(5000);
+                } catch (InterruptedException e) {
+                    e.printStackTrace();
+                }
+                placeIncomingCall();
+            }
+        });
         mUseAcct1Button = (RadioButton) findViewById(R.id.useAcct1Button);
         mUseAcct2Button = (RadioButton) findViewById(R.id.useAcct2Button);
         mNumber = (EditText) findViewById(R.id.phoneNumber);
diff --git a/testapps/src/com/android/server/telecom/testapps/SelfManagedConnection.java b/testapps/src/com/android/server/telecom/testapps/SelfManagedConnection.java
index 5fd8eba..051948b 100644
--- a/testapps/src/com/android/server/telecom/testapps/SelfManagedConnection.java
+++ b/testapps/src/com/android/server/telecom/testapps/SelfManagedConnection.java
@@ -16,31 +16,55 @@
 
 package com.android.server.telecom.testapps;
 
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
 import android.content.Context;
+import android.content.Intent;
+import android.graphics.drawable.Icon;
 import android.media.MediaPlayer;
 import android.telecom.CallAudioState;
 import android.telecom.Connection;
 import android.telecom.ConnectionService;
 import android.telecom.DisconnectCause;
 
+import com.android.server.telecom.testapps.R;
+
 /**
  * Sample self-managed {@link Connection} for a self-managed {@link ConnectionService}.
  * <p>
  * See {@link android.telecom} for more information on self-managed {@link ConnectionService}s.
  */
 public class SelfManagedConnection extends Connection {
+    public static class Listener {
+        public void onConnectionStateChanged(SelfManagedConnection connection) {}
+        public void onConnectionRemoved(SelfManagedConnection connection) {}
+    }
+
     public static final String EXTRA_PHONE_ACCOUNT_HANDLE =
             "com.android.server.telecom.testapps.extra.PHONE_ACCOUNT_HANDLE";
+    public static final String CALL_NOTIFICATION = "com.android.server.telecom.testapps.CALL";
 
+    private static int sNextCallId = 1;
+
+    private final int mCallId;
+    private final Context mContext;
     private final SelfManagedCallList mCallList;
     private final MediaPlayer mMediaPlayer;
     private final boolean mIsIncomingCall;
     private boolean mIsIncomingCallUiShowing;
+    private Listener mListener;
 
     SelfManagedConnection(SelfManagedCallList callList, Context context, boolean isIncoming) {
         mCallList = callList;
         mMediaPlayer = createMediaPlayer(context);
         mIsIncomingCall = isIncoming;
+        mContext = context;
+        mCallId = sNextCallId++;
+    }
+
+    public void setListener(Listener listener) {
+        mListener = listener;
     }
 
     /**
@@ -52,20 +76,82 @@
         mCallList.notifyCallModified();
     }
 
+    @Override
+    public void onShowIncomingCallUi() {
+        // Create the fullscreen intent used to show the fullscreen incoming call UX.
+        Intent intent = new Intent(Intent.ACTION_MAIN, null);
+        intent.setFlags(Intent.FLAG_ACTIVITY_NO_USER_ACTION | Intent.FLAG_ACTIVITY_NEW_TASK);
+        intent.setClass(mContext, IncomingSelfManagedCallActivity.class);
+        intent.putExtra(IncomingSelfManagedCallActivity.EXTRA_CALL_ID, mCallId);
+        PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 1, intent, 0);
+
+        // Build the notification as an ongoing high priority item.
+        final Notification.Builder builder = new Notification.Builder(mContext);
+        builder.setOngoing(true);
+        builder.setPriority(Notification.PRIORITY_HIGH);
+
+        // Set up the main intent to send the user to the incoming call screen.
+        builder.setContentIntent(pendingIntent);
+        builder.setFullScreenIntent(pendingIntent, true);
+
+        // Setup notification content.
+        builder.setSmallIcon(R.drawable.ic_android_black_24dp);
+        builder.setContentTitle("Incoming call...");
+        builder.setContentText("Incoming test call from " + getAddress());
+
+        // Setup answer and reject call button
+        final Intent answerIntent = new Intent(
+                SelfManagedCallNotificationReceiver.ACTION_ANSWER_CALL, null, mContext,
+                SelfManagedCallNotificationReceiver.class);
+        answerIntent.putExtra(IncomingSelfManagedCallActivity.EXTRA_CALL_ID, mCallId);
+        final Intent rejectIntent = new Intent(
+                SelfManagedCallNotificationReceiver.ACTION_REJECT_CALL, null, mContext,
+                SelfManagedCallNotificationReceiver.class);
+        rejectIntent.putExtra(IncomingSelfManagedCallActivity.EXTRA_CALL_ID, mCallId);
+
+        builder.addAction(
+                new Notification.Action.Builder(
+                        Icon.createWithResource(mContext, R.drawable.ic_android_black_24dp),
+                        "Answer",
+                        PendingIntent.getBroadcast(mContext, 0, answerIntent,
+                                PendingIntent.FLAG_UPDATE_CURRENT))
+                        .build());
+        builder.addAction(
+                new Notification.Action.Builder(
+                        Icon.createWithResource(mContext, R.drawable.ic_android_black_24dp),
+                        "Reject",
+                        PendingIntent.getBroadcast(mContext, 0, rejectIntent,
+                                PendingIntent.FLAG_UPDATE_CURRENT))
+                        .build());
+
+        NotificationManager notificationManager = mContext.getSystemService(
+                NotificationManager.class);
+        notificationManager.notify(CALL_NOTIFICATION, mCallId, builder.build());
+    }
+
     public void setConnectionActive() {
         mMediaPlayer.start();
         setActive();
+        if (mListener != null ) {
+            mListener.onConnectionStateChanged(this);
+        }
     }
 
     public void setConnectionHeld() {
         mMediaPlayer.pause();
         setOnHold();
+        if (mListener != null ) {
+            mListener.onConnectionStateChanged(this);
+        }
     }
 
     public void setConnectionDisconnected(int cause) {
         mMediaPlayer.stop();
         setDisconnected(new DisconnectCause(cause));
         destroy();
+        if (mListener != null ) {
+            mListener.onConnectionRemoved(this);
+        }
     }
 
     public void setIsIncomingCallUiShowing(boolean showing) {
@@ -80,6 +166,10 @@
         return mIsIncomingCall;
     }
 
+    public int getCallId() {
+        return mCallId;
+    }
+
     private MediaPlayer createMediaPlayer(Context context) {
         int audioToPlay = (Math.random() > 0.5f) ? R.raw.sample_audio : R.raw.sample_audio2;
         MediaPlayer mediaPlayer = MediaPlayer.create(context, audioToPlay);
diff --git a/testapps/src/com/android/server/telecom/testapps/SelfManagedConnectionService.java b/testapps/src/com/android/server/telecom/testapps/SelfManagedConnectionService.java
index 31bbcd6..e1a01ba 100644
--- a/testapps/src/com/android/server/telecom/testapps/SelfManagedConnectionService.java
+++ b/testapps/src/com/android/server/telecom/testapps/SelfManagedConnectionService.java
@@ -49,12 +49,14 @@
     }
 
     @Override
-    public void onCreateIncomingConnectionFailed(ConnectionRequest request) {
+    public void onCreateIncomingConnectionFailed(PhoneAccountHandle connectionManagerPhoneAccount,
+                                                 ConnectionRequest request) {
         mCallList.notifyCreateIncomingConnectionFailed(request);
     }
 
     @Override
-    public void onCreateOutgoingConnectionFailed(ConnectionRequest request) {
+    public void onCreateOutgoingConnectionFailed(PhoneAccountHandle connectionManagerPhoneAccount,
+                                                 ConnectionRequest request) {
         mCallList.notifyCreateOutgoingConnectionFailed(request);
     }
 
@@ -62,6 +64,7 @@
     private Connection createSelfManagedConnection(ConnectionRequest request, boolean isIncoming) {
         SelfManagedConnection connection = new SelfManagedConnection(mCallList,
                 getApplicationContext(), isIncoming);
+        connection.setListener(mCallList.getConnectionListener());
         connection.setConnectionProperties(Connection.PROPERTY_SELF_MANAGED);
         connection.setAddress(request.getAddress(), TelecomManager.PRESENTATION_ALLOWED);
         connection.setExtras(request.getExtras());
diff --git a/tests/src/com/android/server/telecom/tests/AnalyticsTests.java b/tests/src/com/android/server/telecom/tests/AnalyticsTests.java
index f41c13f..86e5559 100644
--- a/tests/src/com/android/server/telecom/tests/AnalyticsTests.java
+++ b/tests/src/com/android/server/telecom/tests/AnalyticsTests.java
@@ -17,6 +17,7 @@
 package com.android.server.telecom.tests;
 
 import android.content.Context;
+import android.os.Build;
 import android.telecom.Connection;
 import android.telecom.DisconnectCause;
 import android.telecom.InCallService;
@@ -208,7 +209,7 @@
                 mConnectionServiceFixtureA.mLatestConnectionId);
         InCallService.VideoCall videoCall =
                 mInCallServiceFixtureX.getCall(callIds.mCallId).getVideoCallImpl(
-                        mInCallServiceComponentNameX.getPackageName());
+                        mInCallServiceComponentNameX.getPackageName(), Build.VERSION.SDK_INT);
         videoCall.registerCallback(callback);
         ((VideoCallImpl) videoCall).setVideoState(VideoProfile.STATE_BIDIRECTIONAL);
 
diff --git a/tests/src/com/android/server/telecom/tests/ConnectionServiceFixture.java b/tests/src/com/android/server/telecom/tests/ConnectionServiceFixture.java
index 9907ca7..12f19da 100644
--- a/tests/src/com/android/server/telecom/tests/ConnectionServiceFixture.java
+++ b/tests/src/com/android/server/telecom/tests/ConnectionServiceFixture.java
@@ -239,8 +239,9 @@
         }
 
         @Override
-        public void createConnectionFailed(String callId, ConnectionRequest request,
-                boolean isIncoming, Session.Info sessionInfo) throws RemoteException {
+        public void createConnectionFailed(PhoneAccountHandle connectionManagerPhoneAccount,
+                String callId, ConnectionRequest request, boolean isIncoming,
+                Session.Info sessionInfo) throws RemoteException {
             Log.i(ConnectionServiceFixture.this, "createConnectionFailed --> " + callId);
 
             if (mConnectionById.containsKey(callId)) {
diff --git a/tests/src/com/android/server/telecom/tests/VideoProviderTest.java b/tests/src/com/android/server/telecom/tests/VideoProviderTest.java
index ee4890f..f6734c7 100644
--- a/tests/src/com/android/server/telecom/tests/VideoProviderTest.java
+++ b/tests/src/com/android/server/telecom/tests/VideoProviderTest.java
@@ -27,6 +27,7 @@
 import android.content.Context;
 import android.graphics.SurfaceTexture;
 import android.net.Uri;
+import android.os.Build;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.UserHandle;
@@ -106,7 +107,7 @@
         mVideoCallCallback = mock(InCallService.VideoCall.Callback.class);
 
         mVideoCall = mInCallServiceFixtureX.getCall(mCallIds.mCallId).getVideoCallImpl(
-                mInCallServiceComponentNameX.getPackageName());
+                mInCallServiceComponentNameX.getPackageName(), Build.VERSION.SDK_INT);
         mVideoCallImpl = (VideoCallImpl) mVideoCall;
         mVideoCall.registerCallback(mVideoCallCallback);