Confirm managed call when there are ongoing self-managed calls.
When the user places a managed call while there are ongoing self-managed
calls, the system will now display a dialog giving the user the option of
NOT placing the managed call, or placing the managed call and disconnecting
the ongoing self-managed call(s).
This is done by stopping the outgoing call during startOutgoingCall and
bringing up a dialog to confirm whether the user wants to place the call.
If they chose to place the call, ongoing self-mgds calls are disconnected,
the call is added, and the NewutgoingCallBroadcast is sent as usual.
If the user chooses not to start the call, the call is cancelled.
Test: Manual
Bug: 37828805
Change-Id: I8539b0601cf5f324d2fb204485ee0d9bbf03426d
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 6579106..4323274 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -212,6 +212,8 @@
<action android:name="com.android.server.telecom.ACTION_SEND_SMS_FROM_NOTIFICATION" />
<action android:name="com.android.server.telecom.ACTION_ANSWER_FROM_NOTIFICATION" />
<action android:name="com.android.server.telecom.ACTION_REJECT_FROM_NOTIFICATION" />
+ <action android:name="com.android.server.telecom.PROCEED_WITH_CALL" />
+ <action android:name="com.android.server.telecom.CANCEL_CALL" />
</intent-filter>
</receiver>
@@ -254,6 +256,14 @@
android:process=":ui">
</activity>
+ <activity android:name=".ui.ConfirmCallDialogActivity"
+ android:configChanges="orientation|screenSize|keyboardHidden"
+ android:excludeFromRecents="true"
+ android:launchMode="singleInstance"
+ android:theme="@style/Theme.Telecomm.Transparent"
+ android:process=":ui">
+ </activity>
+
<activity android:name=".components.ChangeDefaultDialerDialog"
android:label="@string/change_default_dialer_dialog_title"
android:excludeFromRecents="true"
@@ -265,7 +275,6 @@
<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/res/values/strings.xml b/res/values/strings.xml
index 2363a1d..58e5284 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -252,4 +252,8 @@
<string name="notification_channel_incoming_call">Incoming calls</string>
<!-- Notification channel name for a channel containing missed call notifications. -->
<string name="notification_channel_missed_call">Missed calls</string>
+
+ <!-- Alert dialog content used to inform the user that placing a new outgoing call will end the
+ ongoing call in the app "other_app". -->
+ <string name="alert_outgoing_call">Placing this call will end your <xliff:g id="other_app">%1$s</xliff:g> call.</string>
</resources>
diff --git a/src/com/android/server/telecom/Call.java b/src/com/android/server/telecom/Call.java
index a71770f..6e4329d 100644
--- a/src/com/android/server/telecom/Call.java
+++ b/src/com/android/server/telecom/Call.java
@@ -17,6 +17,7 @@
package com.android.server.telecom;
import android.content.Context;
+import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.net.Uri;
@@ -317,6 +318,12 @@
private Bundle mIntentExtras = new Bundle();
+ /**
+ * The {@link Intent} which originally created this call. Only populated when we are putting a
+ * call into a pending state and need to pick up initiation of the call later.
+ */
+ private Intent mOriginalCallIntent = null;
+
/** Set of listeners on this call.
*
* ConcurrentHashMap constructor params: 8 is initial table size, 0.9f is
@@ -1786,6 +1793,14 @@
mIntentExtras = extras;
}
+ public Intent getOriginalCallIntent() {
+ return mOriginalCallIntent;
+ }
+
+ public void setOriginalCallIntent(Intent intent) {
+ mOriginalCallIntent = intent;
+ }
+
/**
* @return the uri of the contact associated with this call.
*/
diff --git a/src/com/android/server/telecom/CallIntentProcessor.java b/src/com/android/server/telecom/CallIntentProcessor.java
index 2126c48..fdd4ebc 100644
--- a/src/com/android/server/telecom/CallIntentProcessor.java
+++ b/src/com/android/server/telecom/CallIntentProcessor.java
@@ -9,7 +9,6 @@
import android.os.Trace;
import android.os.UserHandle;
import android.os.UserManager;
-import android.telecom.Connection;
import android.telecom.DefaultDialerManager;
import android.telecom.Log;
import android.telecom.PhoneAccount;
@@ -128,8 +127,6 @@
VideoProfile.STATE_AUDIO_ONLY);
clientExtras.putInt(TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE, videoState);
- final boolean isPrivilegedDialer = intent.getBooleanExtra(KEY_IS_PRIVILEGED_DIALER, false);
-
boolean fixedInitiatingUser = fixInitiatingUserIfNecessary(context, intent);
// Show the toast to warn user that it is a personal call though initiated in work profile.
if (fixedInitiatingUser) {
@@ -140,23 +137,31 @@
// Send to CallsManager to ensure the InCallUI gets kicked off before the broadcast returns
Call call = callsManager
- .startOutgoingCall(handle, phoneAccountHandle, clientExtras, initiatingUser);
+ .startOutgoingCall(handle, phoneAccountHandle, clientExtras, initiatingUser,
+ intent);
if (call != null) {
- // Asynchronous calls should not usually be made inside a BroadcastReceiver because once
- // onReceive is complete, the BroadcastReceiver's process runs the risk of getting
- // killed if memory is scarce. However, this is OK here because the entire Telecom
- // process will be running throughout the duration of the phone call and should never
- // be killed.
- NewOutgoingCallIntentBroadcaster broadcaster = new NewOutgoingCallIntentBroadcaster(
- context, callsManager, call, intent, callsManager.getPhoneNumberUtilsAdapter(),
- isPrivilegedDialer);
- final int result = broadcaster.processIntent();
- final boolean success = result == DisconnectCause.NOT_DISCONNECTED;
+ sendNewOutgoingCallIntent(context, call, callsManager, intent);
+ }
+ }
- if (!success && call != null) {
- disconnectCallAndShowErrorDialog(context, call, result);
- }
+ static void sendNewOutgoingCallIntent(Context context, Call call, CallsManager callsManager,
+ Intent intent) {
+ // Asynchronous calls should not usually be made inside a BroadcastReceiver because once
+ // onReceive is complete, the BroadcastReceiver's process runs the risk of getting
+ // killed if memory is scarce. However, this is OK here because the entire Telecom
+ // process will be running throughout the duration of the phone call and should never
+ // be killed.
+ final boolean isPrivilegedDialer = intent.getBooleanExtra(KEY_IS_PRIVILEGED_DIALER, false);
+
+ NewOutgoingCallIntentBroadcaster broadcaster = new NewOutgoingCallIntentBroadcaster(
+ context, callsManager, call, intent, callsManager.getPhoneNumberUtilsAdapter(),
+ isPrivilegedDialer);
+ final int result = broadcaster.processIntent();
+ final boolean success = result == DisconnectCause.NOT_DISCONNECTED;
+
+ if (!success && call != null) {
+ disconnectCallAndShowErrorDialog(context, call, result);
}
}
diff --git a/src/com/android/server/telecom/CallsManager.java b/src/com/android/server/telecom/CallsManager.java
index 8f97b1b..4f03177 100644
--- a/src/com/android/server/telecom/CallsManager.java
+++ b/src/com/android/server/telecom/CallsManager.java
@@ -65,6 +65,7 @@
import com.android.server.telecom.callfiltering.DirectToVoicemailCallFilter;
import com.android.server.telecom.callfiltering.IncomingCallFilter;
import com.android.server.telecom.components.ErrorDialogActivity;
+import com.android.server.telecom.ui.ConfirmCallDialogActivity;
import com.android.server.telecom.ui.IncomingCallNotifier;
import java.util.ArrayList;
@@ -208,6 +209,12 @@
new ConcurrentHashMap<Call, Boolean>(8, 0.9f, 1));
/**
+ * A pending call is one which requires user-intervention in order to be placed.
+ * Used by {@link #startCallConfirmation(Call)}.
+ */
+ private Call mPendingCall;
+
+ /**
* The current telecom call ID. Used when creating new instances of {@link Call}. Should
* only be accessed using the {@link #getNextCallId()} method which synchronizes on the
* {@link #mLock} sync root.
@@ -994,15 +1001,15 @@
* For managed connections, this is the first step to launching the Incall UI.
* For self-managed connections, we don't expect the Incall UI to launch, but this is still a
* first step in getting the self-managed ConnectionService to create the connection.
- *
* @param handle Handle to connect the call with.
* @param phoneAccountHandle The phone account which contains the component name of the
* connection service to use for this call.
* @param extras The optional extras Bundle passed with the intent used for the incoming call.
* @param initiatingUser {@link UserHandle} of user that place the outgoing call.
+ * @param originalIntent
*/
Call startOutgoingCall(Uri handle, PhoneAccountHandle phoneAccountHandle, Bundle extras,
- UserHandle initiatingUser) {
+ UserHandle initiatingUser, Intent originalIntent) {
boolean isReusedCall = true;
Call call = reuseOutgoingCall(handle);
@@ -1042,7 +1049,6 @@
}
call.setInitiatingUser(initiatingUser);
-
isReusedCall = false;
}
@@ -1160,9 +1166,15 @@
}
setIntentExtrasAndStartTime(call, extras);
- // Do not add the call if it is a potential MMI code.
- if ((isPotentialMMICode(handle) || isPotentialInCallMMICode) && !needsAccountSelection) {
+ if ((isPotentialMMICode(handle) || isPotentialInCallMMICode)
+ && !needsAccountSelection) {
+ // Do not add the call if it is a potential MMI code.
call.addListener(this);
+ } else if (!isSelfManaged && hasSelfManagedCalls() && !call.isEmergencyCall()) {
+ // Adding a managed call and there are ongoing self-managed call(s).
+ call.setOriginalCallIntent(originalIntent);
+ startCallConfirmation(call);
+ return null;
} else if (!mCalls.contains(call)) {
// We check if mCalls already contains the call because we could potentially be reusing
// a call which was previously added (See {@link #reuseOutgoingCall}).
@@ -1235,23 +1247,11 @@
if (call.isSelfManaged() && !isOutgoingCallPermitted) {
notifyCreateConnectionFailed(call.getTargetPhoneAccount(), call);
} else if (!call.isSelfManaged() && hasSelfManagedCalls() && !call.isEmergencyCall()) {
- Call activeCall = getActiveCall();
- CharSequence errorMessage;
- if (activeCall == null) {
- // Realistically this shouldn't happen, but best to handle gracefully
- errorMessage = mContext.getText(R.string.cant_call_due_to_ongoing_unknown_call);
- } else {
- errorMessage = mContext.getString(R.string.cant_call_due_to_ongoing_call,
- activeCall.getTargetPhoneAccountLabel());
- }
- // Call is managed and there are ongoing self-managed calls.
- markCallAsDisconnected(call, new DisconnectCause(DisconnectCause.ERROR,
- errorMessage, errorMessage, "Ongoing call in another app."));
- markCallAsRemoved(call);
+ markCallDisconnectedDueToSelfManagedCall(call);
} else {
if (call.isEmergencyCall()) {
// Disconnect all self-managed calls to make priority for emergency call.
- mCalls.stream().filter(c -> c.isSelfManaged()).forEach(c -> c.disconnect());
+ disconnectSelfManagedCalls();
}
call.startCreateConnection(mPhoneAccountRegistrar);
@@ -1750,6 +1750,33 @@
}
/**
+ * Given a call, marks the call as disconnected and removes it. Set the error message to
+ * indicate to the user that the call cannot me placed due to an ongoing call in another app.
+ *
+ * Used when there are ongoing self-managed calls and the user tries to make an outgoing managed
+ * call. Called by {@link #startCallConfirmation(Call)} when the user is already confirming an
+ * outgoing call. Realistically this should almost never be called since in practice the user
+ * won't make multiple outgoing calls at the same time.
+ *
+ * @param call The call to mark as disconnected.
+ */
+ void markCallDisconnectedDueToSelfManagedCall(Call call) {
+ Call activeCall = getActiveCall();
+ CharSequence errorMessage;
+ if (activeCall == null) {
+ // Realistically this shouldn't happen, but best to handle gracefully
+ errorMessage = mContext.getText(R.string.cant_call_due_to_ongoing_unknown_call);
+ } else {
+ errorMessage = mContext.getString(R.string.cant_call_due_to_ongoing_call,
+ activeCall.getTargetPhoneAccountLabel());
+ }
+ // Call is managed and there are ongoing self-managed calls.
+ markCallAsDisconnected(call, new DisconnectCause(DisconnectCause.ERROR,
+ errorMessage, errorMessage, "Ongoing call in another app."));
+ markCallAsRemoved(call);
+ }
+
+ /**
* Cleans up any calls currently associated with the specified connection service when the
* service binder disconnects unexpectedly.
*
@@ -2761,6 +2788,97 @@
}
/**
+ * Used to confirm creation of an outgoing call which was marked as pending confirmation in
+ * {@link #startOutgoingCall(Uri, PhoneAccountHandle, Bundle, UserHandle, Intent)}.
+ * Called via {@link TelecomBroadcastIntentProcessor} for a call which was confirmed via
+ * {@link ConfirmCallDialogActivity}.
+ * @param callId The call ID of the call to confirm.
+ */
+ public void confirmPendingCall(String callId) {
+ Log.i(this, "confirmPendingCall: callId=%s", callId);
+ if (mPendingCall != null && mPendingCall.getId().equals(callId)) {
+ Log.addEvent(mPendingCall, LogUtils.Events.USER_CONFIRMED);
+ addCall(mPendingCall);
+
+ // We are going to place the new outgoing call, so disconnect any ongoing self-managed
+ // calls which are ongoing at this time.
+ disconnectSelfManagedCalls();
+
+ // Kick of the new outgoing call intent from where it left off prior to confirming the
+ // call.
+ CallIntentProcessor.sendNewOutgoingCallIntent(mContext, mPendingCall, this,
+ mPendingCall.getOriginalCallIntent());
+ mPendingCall = null;
+ }
+ }
+
+ /**
+ * Used to cancel an outgoing call which was marked as pending confirmation in
+ * {@link #startOutgoingCall(Uri, PhoneAccountHandle, Bundle, UserHandle, Intent)}.
+ * Called via {@link TelecomBroadcastIntentProcessor} for a call which was confirmed via
+ * {@link ConfirmCallDialogActivity}.
+ * @param callId The call ID of the call to cancel.
+ */
+ public void cancelPendingCall(String callId) {
+ Log.i(this, "cancelPendingCall: callId=%s", callId);
+ if (mPendingCall != null && mPendingCall.getId().equals(callId)) {
+ Log.addEvent(mPendingCall, LogUtils.Events.USER_CANCELLED);
+ markCallAsDisconnected(mPendingCall, new DisconnectCause(DisconnectCause.CANCELED));
+ markCallAsRemoved(mPendingCall);
+ mPendingCall = null;
+ }
+ }
+
+ /**
+ * Called from {@link #startOutgoingCall(Uri, PhoneAccountHandle, Bundle, UserHandle, Intent)} when
+ * a managed call is added while there are ongoing self-managed calls. Starts
+ * {@link ConfirmCallDialogActivity} to prompt the user to see if they wish to place the
+ * outgoing call or not.
+ * @param call The call to confirm.
+ */
+ private void startCallConfirmation(Call call) {
+ if (mPendingCall != null) {
+ Log.i(this, "startCallConfirmation: call %s is already pending; disconnecting %s",
+ mPendingCall.getId(), call.getId());
+ markCallDisconnectedDueToSelfManagedCall(call);
+ return;
+ }
+ Log.addEvent(call, LogUtils.Events.USER_CONFIRMATION);
+ mPendingCall = call;
+
+ // Figure out the name of the app in charge of the self-managed call(s).
+ Call selfManagedCall = mCalls.stream()
+ .filter(c -> c.isSelfManaged())
+ .findFirst()
+ .orElse(null);
+ CharSequence ongoingAppName = "";
+ if (selfManagedCall != null) {
+ ongoingAppName = selfManagedCall.getTargetPhoneAccountLabel();
+ }
+ Log.i(this, "startCallConfirmation: callId=%s, ongoingApp=%s", call.getId(),
+ ongoingAppName);
+
+ Intent confirmIntent = new Intent(mContext, ConfirmCallDialogActivity.class);
+ confirmIntent.putExtra(ConfirmCallDialogActivity.EXTRA_OUTGOING_CALL_ID, call.getId());
+ confirmIntent.putExtra(ConfirmCallDialogActivity.EXTRA_ONGOING_APP_NAME, ongoingAppName);
+ confirmIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ mContext.startActivityAsUser(confirmIntent, UserHandle.CURRENT);
+ }
+
+ /**
+ * Disconnects all self-managed calls.
+ */
+ private void disconnectSelfManagedCalls() {
+ // Disconnect all self-managed calls to make priority for emergency call.
+ // Use Call.disconnect() to command the ConnectionService to disconnect the calls.
+ // CallsManager.markCallAsDisconnected doesn't actually tell the ConnectionService to
+ // disconnect.
+ mCalls.stream()
+ .filter(c -> c.isSelfManaged())
+ .forEach(c -> c.disconnect());
+ }
+
+ /**
* Dumps the state of the {@link CallsManager}.
*
* @param pw The {@code IndentingPrintWriter} to write the state to.
@@ -2776,6 +2894,11 @@
pw.decreaseIndent();
}
+ if (mPendingCall != null) {
+ pw.print("mPendingCall:");
+ pw.println(mPendingCall.getId());
+ }
+
if (mCallAudioManager != null) {
pw.println("mCallAudioManager:");
pw.increaseIndent();
@@ -2903,7 +3026,7 @@
extras.putParcelable(TelecomManager.EXTRA_CALL_AUDIO_STATE,
mCallAudioManager.getCallAudioState());
Call handoverToCall = startOutgoingCall(handoverFromCall.getHandle(), handoverToHandle,
- extras, getCurrentUserHandle());
+ extras, getCurrentUserHandle(), null /* originalIntent */);
Log.addEvent(handoverFromCall, LogUtils.Events.START_HANDOVER,
"handOverFrom=%s, handOverTo=%s", handoverFromCall.getId(), handoverToCall.getId());
handoverFromCall.setHandoverToCall(handoverToCall);
diff --git a/src/com/android/server/telecom/LogUtils.java b/src/com/android/server/telecom/LogUtils.java
index c61ff65..34d875e 100644
--- a/src/com/android/server/telecom/LogUtils.java
+++ b/src/com/android/server/telecom/LogUtils.java
@@ -54,6 +54,9 @@
public final static class Events {
public static final String CREATED = "CREATED";
+ public static final String USER_CONFIRMATION = "USER_CONFIRMATION";
+ public static final String USER_CONFIRMED = "USER_CONFIRMED";
+ public static final String USER_CANCELLED = "USER_CANCELLED";
public static final String DESTROYED = "DESTROYED";
public static final String SET_CONNECTING = "SET_CONNECTING";
public static final String SET_DIALING = "SET_DIALING";
diff --git a/src/com/android/server/telecom/TelecomBroadcastIntentProcessor.java b/src/com/android/server/telecom/TelecomBroadcastIntentProcessor.java
index 5df4451..a51ef73 100644
--- a/src/com/android/server/telecom/TelecomBroadcastIntentProcessor.java
+++ b/src/com/android/server/telecom/TelecomBroadcastIntentProcessor.java
@@ -21,6 +21,8 @@
import android.os.UserHandle;
import android.telecom.Log;
+import com.android.server.telecom.ui.ConfirmCallDialogActivity;
+
public final class TelecomBroadcastIntentProcessor {
/** The action used to send SMS response for the missed call notification. */
public static final String ACTION_SEND_SMS_FROM_NOTIFICATION =
@@ -48,6 +50,20 @@
public static final String ACTION_REJECT_FROM_NOTIFICATION =
"com.android.server.telecom.ACTION_REJECT_FROM_NOTIFICATION";
+ /**
+ * The action used to proceed with a call being confirmed via
+ * {@link com.android.server.telecom.ui.ConfirmCallDialogActivity}.
+ */
+ public static final String ACTION_PROCEED_WITH_CALL =
+ "com.android.server.telecom.PROCEED_WITH_CALL";
+
+ /**
+ * The action used to cancel a call being confirmed via
+ * {@link com.android.server.telecom.ui.ConfirmCallDialogActivity}.
+ */
+ public static final String ACTION_CANCEL_CALL =
+ "com.android.server.telecom.CANCEL_CALL";
+
public static final String EXTRA_USERHANDLE = "userhandle";
private final Context mContext;
@@ -112,6 +128,7 @@
} else if (ACTION_REJECT_FROM_NOTIFICATION.equals(action)) {
Log.startSession("TBIP.aRFM");
try {
+
// Reject the current ringing call.
Call incomingCall = mCallsManager.getIncomingCallNotifier().getIncomingCall();
if (incomingCall != null) {
@@ -120,6 +137,24 @@
} finally {
Log.endSession();
}
+ } else if (ACTION_PROCEED_WITH_CALL.equals(action)) {
+ Log.startSession("TBIP.aPWC");
+ try {
+ String callId = intent.getStringExtra(
+ ConfirmCallDialogActivity.EXTRA_OUTGOING_CALL_ID);
+ mCallsManager.confirmPendingCall(callId);
+ } finally {
+ Log.endSession();
+ }
+ } else if (ACTION_CANCEL_CALL.equals(action)) {
+ Log.startSession("TBIP.aCC");
+ try {
+ String callId = intent.getStringExtra(
+ ConfirmCallDialogActivity.EXTRA_OUTGOING_CALL_ID);
+ mCallsManager.cancelPendingCall(callId);
+ } finally {
+ Log.endSession();
+ }
}
}
diff --git a/src/com/android/server/telecom/ui/ConfirmCallDialogActivity.java b/src/com/android/server/telecom/ui/ConfirmCallDialogActivity.java
new file mode 100644
index 0000000..4735e3c
--- /dev/null
+++ b/src/com/android/server/telecom/ui/ConfirmCallDialogActivity.java
@@ -0,0 +1,96 @@
+/*
+ * 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.ui;
+
+import com.android.server.telecom.R;
+import com.android.server.telecom.TelecomBroadcastIntentProcessor;
+import com.android.server.telecom.components.TelecomBroadcastReceiver;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.os.Bundle;
+import android.telecom.Log;
+
+/**
+ * Dialog activity used when there is an ongoing self-managed call and the user initiates a new
+ * outgoing managed call. The dialog prompts the user to see if they want to disconnect the ongoing
+ * self-managed call in order to place the new managed call.
+ */
+public class ConfirmCallDialogActivity extends Activity {
+ public static final String EXTRA_OUTGOING_CALL_ID = "android.telecom.extra.OUTGOING_CALL_ID";
+ public static final String EXTRA_ONGOING_APP_NAME = "android.telecom.extra.ONGOING_APP_NAME";
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ final String callId = getIntent().getStringExtra(EXTRA_OUTGOING_CALL_ID);
+ final CharSequence ongoingAppName = getIntent().getCharSequenceExtra(
+ EXTRA_ONGOING_APP_NAME);
+ showDialog(callId, ongoingAppName);
+ }
+
+ private void showDialog(final String callId, CharSequence ongoingAppName) {
+ Log.i(this, "showDialog: confirming callId=%s, ongoing=%s", callId, ongoingAppName);
+ CharSequence message = getString(R.string.alert_outgoing_call, ongoingAppName);
+ final AlertDialog errorDialog = new AlertDialog.Builder(this)
+ .setMessage(message)
+ .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ Intent proceedWithCall = new Intent(
+ TelecomBroadcastIntentProcessor.ACTION_PROCEED_WITH_CALL, null,
+ ConfirmCallDialogActivity.this,
+ TelecomBroadcastReceiver.class);
+ proceedWithCall.putExtra(EXTRA_OUTGOING_CALL_ID, callId);
+ sendBroadcast(proceedWithCall);
+ dialog.dismiss();
+ finish();
+ }
+ })
+ .setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ Intent cancelCall = new Intent(
+ TelecomBroadcastIntentProcessor.ACTION_CANCEL_CALL, null,
+ ConfirmCallDialogActivity.this,
+ TelecomBroadcastReceiver.class);
+ cancelCall.putExtra(EXTRA_OUTGOING_CALL_ID, callId);
+ sendBroadcast(cancelCall);
+ dialog.dismiss();
+ finish();
+ }
+ })
+ .setOnCancelListener(new DialogInterface.OnCancelListener() {
+ @Override
+ public void onCancel(DialogInterface dialog) {
+ Intent cancelCall = new Intent(
+ TelecomBroadcastIntentProcessor.ACTION_CANCEL_CALL, null,
+ ConfirmCallDialogActivity.this,
+ TelecomBroadcastReceiver.class);
+ cancelCall.putExtra(EXTRA_OUTGOING_CALL_ID, callId);
+ sendBroadcast(cancelCall);
+ dialog.dismiss();
+ finish();
+ }
+ })
+ .create();
+
+ errorDialog.show();
+ }
+}