Merge "Implement TelecomService#createLaunchEmergencyDialer API."
diff --git a/src/com/android/server/telecom/Call.java b/src/com/android/server/telecom/Call.java
index b4623f7..454321b 100644
--- a/src/com/android/server/telecom/Call.java
+++ b/src/com/android/server/telecom/Call.java
@@ -139,6 +139,7 @@
         boolean onCanceledViaNewOutgoingCallBroadcast(Call call, long disconnectionTimeout);
         void onHoldToneRequested(Call call);
         void onCallHoldFailed(Call call);
+        void onCallSwitchFailed(Call call);
         void onConnectionEvent(Call call, String event, Bundle extras);
         void onExternalCallChanged(Call call, boolean isExternalCall);
         void onRttInitiationFailure(Call call, int reason);
@@ -215,6 +216,8 @@
         @Override
         public void onCallHoldFailed(Call call) {}
         @Override
+        public void onCallSwitchFailed(Call call) {}
+        @Override
         public void onConnectionEvent(Call call, String event, Bundle extras) {}
         @Override
         public void onExternalCallChanged(Call call, boolean isExternalCall) {}
@@ -580,6 +583,13 @@
     private boolean mHasGoneActiveBefore = false;
 
     /**
+     * Indicates the package name of the {@link android.telecom.CallScreeningService} which should
+     * be sent the {@link android.telecom.TelecomManager#ACTION_POST_CALL} intent upon disconnection
+     * of a call.
+     */
+    private String mPostCallPackageName;
+
+    /**
      * Persists the specified parameters and initializes the new instance.
      * @param context The context.
      * @param repository The connection service repository.
@@ -3222,6 +3232,10 @@
             for (Listener l : mListeners) {
                 l.onCallHoldFailed(this);
             }
+        } else if (Connection.EVENT_CALL_SWITCH_FAILED.equals(event)) {
+            for (Listener l : mListeners) {
+                l.onCallSwitchFailed(this);
+            }
         } else {
             for (Listener l : mListeners) {
                 l.onConnectionEvent(this, event, extras);
@@ -3413,4 +3427,23 @@
         }
         return CALL_DIRECTION_UNDEFINED;
     }
+
+    /**
+     * Set the package name of the {@link android.telecom.CallScreeningService} which should be sent
+     * the {@link android.telecom.TelecomManager#ACTION_POST_CALL} upon disconnection of a call.
+     * @param packageName post call screen service package name.
+     */
+    public void setPostCallPackageName(String packageName) {
+        mPostCallPackageName = packageName;
+    }
+
+    /**
+     * Return the package name of the {@link android.telecom.CallScreeningService} which should be
+     * sent the {@link android.telecom.TelecomManager#ACTION_POST_CALL} upon disconnection of a
+     * call.
+     * @return post call screen service package name.
+     */
+    public String getPostCallPackageName() {
+        return mPostCallPackageName;
+    }
 }
diff --git a/src/com/android/server/telecom/CallsManager.java b/src/com/android/server/telecom/CallsManager.java
index ffe1ee7..afd1c6b 100644
--- a/src/com/android/server/telecom/CallsManager.java
+++ b/src/com/android/server/telecom/CallsManager.java
@@ -16,6 +16,18 @@
 
 package com.android.server.telecom;
 
+import static android.telecom.TelecomManager.ACTION_POST_CALL;
+import static android.telecom.TelecomManager.DURATION_LONG;
+import static android.telecom.TelecomManager.DURATION_MEDIUM;
+import static android.telecom.TelecomManager.DURATION_SHORT;
+import static android.telecom.TelecomManager.DURATION_VERY_SHORT;
+import static android.telecom.TelecomManager.EXTRA_CALL_DURATION;
+import static android.telecom.TelecomManager.EXTRA_DISCONNECT_CAUSE;
+import static android.telecom.TelecomManager.EXTRA_HANDLE;
+import static android.telecom.TelecomManager.MEDIUM_CALL_TIME_MS;
+import static android.telecom.TelecomManager.SHORT_CALL_TIME_MS;
+import static android.telecom.TelecomManager.VERY_SHORT_CALL_TIME_MS;
+
 import android.Manifest;
 import android.annotation.NonNull;
 import android.app.ActivityManager;
@@ -600,6 +612,7 @@
     @Override
     public void onSuccessfulOutgoingCall(Call call, int callState) {
         Log.v(this, "onSuccessfulOutgoingCall, %s", call);
+        call.setPostCallPackageName(getRoleManagerAdapter().getDefaultCallScreeningApp());
 
         setCallState(call, callState, "successful outgoing call");
         if (!mCalls.contains(call)) {
@@ -739,6 +752,9 @@
         }
 
         if (result.shouldAllowCall) {
+            incomingCall.setPostCallPackageName(
+                    getRoleManagerAdapter().getDefaultCallScreeningApp());
+
             if (hasMaximumManagedRingingCalls(incomingCall)) {
                 if (shouldSilenceInsteadOfReject(incomingCall)) {
                     incomingCall.silence();
@@ -1030,12 +1046,22 @@
 
     @Override
     public void onCallHoldFailed(Call call) {
-        // Normally, we don't care whether a call hold has failed. However, if a call was held in
-        // order to answer an incoming call, that incoming call needs to be brought out of the
-        // ANSWERED state so that the user can try the operation again.
+        markAllAnsweredCallAsRinging(call, "hold");
+    }
+
+    @Override
+    public void onCallSwitchFailed(Call call) {
+        markAllAnsweredCallAsRinging(call, "switch");
+    }
+
+    private void markAllAnsweredCallAsRinging(Call call, String actionName) {
+        // Normally, we don't care whether a call hold or switch has failed.
+        // However, if a call was held or switched in order to answer an incoming call, that
+        // incoming call needs to be brought out of the ANSWERED state so that the user can
+        // try the operation again.
         for (Call call1 : mCalls) {
             if (call1 != call && call1.getState() == CallState.ANSWERED) {
-                setCallState(call1, CallState.RINGING, "hold failed on other call");
+                setCallState(call1, CallState.RINGING, actionName + " failed on other call");
             }
         }
     }
@@ -3224,6 +3250,10 @@
             // TODO: Define expected state transitions here, and log when an
             // unexpected transition occurs.
             if (call.setState(newState, tag)) {
+                if ((oldState != CallState.AUDIO_PROCESSING) &&
+                        (newState == CallState.DISCONNECTED)) {
+                    maybeSendPostCallScreenIntent(call);
+                }
                 maybeShowErrorDialogOnDisconnect(call);
 
                 Trace.beginSection("onCallStateChanged");
@@ -4803,4 +4833,28 @@
     public LinkedList<HandlerThread> getGraphHandlerThreads() {
         return mGraphHandlerThreads;
     }
+
+    private void maybeSendPostCallScreenIntent(Call call) {
+        if (call.isEmergencyCall() || (call.isNetworkIdentifiedEmergencyCall()) ||
+                (call.getPostCallPackageName() == null)) {
+            return;
+        }
+
+        Intent intent = new Intent(ACTION_POST_CALL);
+        intent.setPackage(call.getPostCallPackageName());
+        intent.putExtra(EXTRA_HANDLE, call.getHandle());
+        intent.putExtra(EXTRA_DISCONNECT_CAUSE, call.getDisconnectCause().getCode());
+        long duration = call.getAgeMillis();
+        int durationCode = DURATION_VERY_SHORT;
+        if ((duration >= VERY_SHORT_CALL_TIME_MS) && (duration < SHORT_CALL_TIME_MS)) {
+            durationCode = DURATION_SHORT;
+        } else if ((duration >= SHORT_CALL_TIME_MS) && (duration < MEDIUM_CALL_TIME_MS)) {
+            durationCode = DURATION_MEDIUM;
+        } else if (duration >= MEDIUM_CALL_TIME_MS) {
+            durationCode = DURATION_LONG;
+        }
+        intent.putExtra(EXTRA_CALL_DURATION, durationCode);
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        mContext.startActivityAsUser(intent, mCurrentUserHandle);
+    }
 }
diff --git a/testapps/AndroidManifest.xml b/testapps/AndroidManifest.xml
index f19c13e..4238191 100644
--- a/testapps/AndroidManifest.xml
+++ b/testapps/AndroidManifest.xml
@@ -273,5 +273,13 @@
                   android:excludeFromRecents="true"
                   android:launchMode="singleInstance">
         </activity>
+
+        <activity android:name=".PostCallActivity"
+                  android:label="@string/postCallActivityLabel">
+            <intent-filter>
+                <action android:name="android.telecom.action.POST_CALL" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
     </application>
 </manifest>
diff --git a/testapps/res/values/donottranslate_strings.xml b/testapps/res/values/donottranslate_strings.xml
index aa34070..fcd6eff 100644
--- a/testapps/res/values/donottranslate_strings.xml
+++ b/testapps/res/values/donottranslate_strings.xml
@@ -96,6 +96,8 @@
 
     <string name="rttUiLabel">Test RTT UI</string>
 
+    <string name="postCallActivityLabel">Test Post Call Screen</string>
+
     <string-array name="rtt_mode_array">
         <item>Full</item>
         <item>HCO</item>
diff --git a/testapps/src/com/android/server/telecom/testapps/PostCallActivity.java b/testapps/src/com/android/server/telecom/testapps/PostCallActivity.java
new file mode 100644
index 0000000..101a68e
--- /dev/null
+++ b/testapps/src/com/android/server/telecom/testapps/PostCallActivity.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2019 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 static android.telecom.TelecomManager.EXTRA_CALL_DURATION;
+import static android.telecom.TelecomManager.EXTRA_DISCONNECT_CAUSE;
+import static android.telecom.TelecomManager.EXTRA_HANDLE;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.telecom.Log;
+
+public class PostCallActivity extends Activity {
+
+    public static final String ACTION_POST_CALL = "android.telecom.action.POST_CALL";
+    public static final int DEFAULT_DISCONNECT_CAUSE = -1;
+    public static final int DEFAULT_DURATION = -1;
+
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        final Intent intent = getIntent();
+        final String action = intent != null ? intent.getAction() : null;
+        Log.i(this, "action: %s", action);
+        if (ACTION_POST_CALL.equals(action)) {
+            Log.i(this, "extra handle: " +
+                    intent.getParcelableExtra(EXTRA_HANDLE));
+            Log.i(this, "extra disconnect cause: " +
+                    intent.getIntExtra(EXTRA_DISCONNECT_CAUSE, DEFAULT_DISCONNECT_CAUSE));
+            Log.i(this, "extra duration: " +
+                    intent.getIntExtra(EXTRA_CALL_DURATION, DEFAULT_DURATION));
+        }
+    }
+}