Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit dfd78b49 authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "Support notifying Telecom when a call is ended due to new emergency call"

parents 0831bdd3 d0628ae3
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -48,6 +48,14 @@
         [CHAR LIMIT=18] -->
    <string name="notification_missedCall_message">Message</string>

    <!-- Disconnected call notification label, used when the call has been automatically
         disconnected by telecom to make room for a higher priority call, such as an emergency
         call.-->
    <string name="notification_disconnectedCall_title">Disconnected call</string>
    <!-- Body of the notification presented when an ongoing call is disconnected in favor of placing
         an emergency call. This is required by some carriers. [CHAR LIMIT=NONE] -->
    <string name="notification_disconnectedCall_body">The call to <xliff:g id="caller">%s</xliff:g> has been disconnected due to an emergency call being placed.</string>

    <!-- Title for the persistent notification presented when an app has requested that a call
         be put into the background so that the app can access the audio from the call
         [CHAR LIMIT=40] -->
@@ -290,6 +298,8 @@
    <string name="notification_channel_call_blocking">Call Blocking</string>
    <!-- Notification channel name for a channel containing background call notifications. -->
    <string name="notification_channel_background_calls">Background calls</string>
    <!-- Notification channel name for a channel containing disconnected call notifications. -->
    <string name="notification_channel_disconnected_calls">Disconnected 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". -->
+25 −16
Original line number Diff line number Diff line
@@ -58,6 +58,7 @@ import android.widget.Toast;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telecom.IVideoProvider;
import com.android.internal.util.Preconditions;
import com.android.server.telecom.ui.DisconnectedCallNotifier;
import com.android.server.telecom.ui.ToastFactory;

import java.io.IOException;
@@ -366,9 +367,10 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable,

    /**
     * Override the disconnect cause set by the connection service. Used for audio processing and
     * simulated ringing calls.
     * simulated ringing calls as well as the condition when an emergency call is ended due to
     * an emergency call being placed.
     */
    private int mOverrideDisconnectCauseCode = DisconnectCause.UNKNOWN;
    private DisconnectCause mOverrideDisconnectCause = new DisconnectCause(DisconnectCause.UNKNOWN);

    private Bundle mIntentExtras = new Bundle();

@@ -1166,23 +1168,30 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable,
    }

    /**
     * @param disconnectCause The reason for the disconnection, represented by
     * @param cause The reason for the disconnection, represented by
     * {@link android.telecom.DisconnectCause}.
     */
    public void setDisconnectCause(DisconnectCause disconnectCause) {
    public void setDisconnectCause(DisconnectCause cause) {
        // TODO: Consider combining this method with a setDisconnected() method that is totally
        // separate from setState.
        if (mOverrideDisconnectCauseCode != DisconnectCause.UNKNOWN) {
            disconnectCause = new DisconnectCause(mOverrideDisconnectCauseCode,
                    disconnectCause.getLabel(), disconnectCause.getDescription(),
                    disconnectCause.getReason(), disconnectCause.getTone());

        if (mOverrideDisconnectCause.getCode() != DisconnectCause.UNKNOWN) {
            cause = new DisconnectCause(mOverrideDisconnectCause.getCode(),
                    TextUtils.isEmpty(mOverrideDisconnectCause.getLabel()) ?
                            cause.getLabel() : mOverrideDisconnectCause.getLabel(),
                    (mOverrideDisconnectCause.getDescription() == null) ?
                            cause.getDescription() :mOverrideDisconnectCause.getDescription(),
                    TextUtils.isEmpty(mOverrideDisconnectCause.getReason()) ?
                            cause.getReason() : mOverrideDisconnectCause.getReason(),
                    (mOverrideDisconnectCause.getTone() == 0) ?
                            cause.getTone() : mOverrideDisconnectCause.getTone());
        }
        mAnalytics.setCallDisconnectCause(disconnectCause);
        mDisconnectCause = disconnectCause;
        mAnalytics.setCallDisconnectCause(cause);
        mDisconnectCause = cause;
    }

    public void setOverrideDisconnectCauseCode(int overrideDisconnectCauseCode) {
        mOverrideDisconnectCauseCode = overrideDisconnectCauseCode;
    public void setOverrideDisconnectCauseCode(DisconnectCause overrideDisconnectCause) {
        mOverrideDisconnectCause = overrideDisconnectCause;
    }


@@ -1962,12 +1971,12 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable,
            abort(disconnectionTimeout);
        } else if (mState != CallState.ABORTED && mState != CallState.DISCONNECTED) {
            if (mState == CallState.AUDIO_PROCESSING && !hasGoneActiveBefore()) {
                mOverrideDisconnectCauseCode = DisconnectCause.REJECTED;
                setOverrideDisconnectCauseCode(new DisconnectCause(DisconnectCause.REJECTED));
            } else if (mState == CallState.SIMULATED_RINGING) {
                // This is the case where the dialer calls disconnect() because the call timed out
                // or an emergency call was dialed while in this state.
                // Override the disconnect cause to MISSED
                mOverrideDisconnectCauseCode = DisconnectCause.MISSED;
                setOverrideDisconnectCauseCode(new DisconnectCause(DisconnectCause.MISSED));
            }
            if (mConnectionService == null) {
                Log.e(this, new Exception(), "disconnect() request on a call without a"
@@ -2128,7 +2137,7 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable,
            // This handles the case where the user manually rejects a call that's in simulated
            // ringing. Since the call is already active on the connectionservice side, we want to
            // hangup, not reject.
            mOverrideDisconnectCauseCode = DisconnectCause.REJECTED;
            setOverrideDisconnectCauseCode(new DisconnectCause(DisconnectCause.REJECTED));
            if (mConnectionService != null) {
                mConnectionService.disconnect(this);
            } else {
+37 −4
Original line number Diff line number Diff line
@@ -95,6 +95,7 @@ import com.android.server.telecom.ui.AudioProcessingNotification;
import com.android.server.telecom.ui.CallRedirectionConfirmDialogActivity;
import com.android.server.telecom.ui.CallRedirectionTimeoutDialogActivity;
import com.android.server.telecom.ui.ConfirmCallDialogActivity;
import com.android.server.telecom.ui.DisconnectedCallNotifier;
import com.android.server.telecom.ui.IncomingCallNotifier;
import com.android.server.telecom.ui.ToastFactory;

@@ -329,6 +330,7 @@ public class CallsManager extends Call.ListenerBase
    private final TelecomSystem.SyncRoot mLock;
    private final PhoneAccountRegistrar mPhoneAccountRegistrar;
    private final MissedCallNotifier mMissedCallNotifier;
    private final DisconnectedCallNotifier mDisconnectedCallNotifier;
    private IncomingCallNotifier mIncomingCallNotifier;
    private final CallerInfoLookupHelper mCallerInfoLookupHelper;
    private final IncomingCallFilter.Factory mIncomingCallFilterFactory;
@@ -437,6 +439,7 @@ public class CallsManager extends Call.ListenerBase
            TelecomSystem.SyncRoot lock,
            CallerInfoLookupHelper callerInfoLookupHelper,
            MissedCallNotifier missedCallNotifier,
            DisconnectedCallNotifier.Factory disconnectedCallNotifierFactory,
            PhoneAccountRegistrar phoneAccountRegistrar,
            HeadsetMediaButtonFactory headsetMediaButtonFactory,
            ProximitySensorManagerFactory proximitySensorManagerFactory,
@@ -468,6 +471,7 @@ public class CallsManager extends Call.ListenerBase
        mPhoneAccountRegistrar = phoneAccountRegistrar;
        mPhoneAccountRegistrar.addListener(mPhoneAccountListener);
        mMissedCallNotifier = missedCallNotifier;
        mDisconnectedCallNotifier = disconnectedCallNotifierFactory.create(mContext, this);
        StatusBarNotifier statusBarNotifier = new StatusBarNotifier(context, this);
        mWiredHeadsetManager = wiredHeadsetManager;
        mSystemStateHelper = systemStateHelper;
@@ -547,6 +551,7 @@ public class CallsManager extends Call.ListenerBase
        mListeners.add(mCallAudioManager);
        mListeners.add(mCallRecordingTonePlayer);
        mListeners.add(missedCallNotifier);
        mListeners.add(mDisconnectedCallNotifier);
        mListeners.add(mHeadsetMediaButton);
        mListeners.add(mProximitySensorManager);
        mListeners.add(audioProcessingNotification);
@@ -2706,7 +2711,7 @@ public class CallsManager extends Call.ListenerBase
                && disconnectCause.getCode() == DisconnectCause.REMOTE) {
            // If the remote end hangs up while in SIMULATED_RINGING, the call should
            // be marked as missed.
            call.setOverrideDisconnectCauseCode(DisconnectCause.MISSED);
            call.setOverrideDisconnectCauseCode(new DisconnectCause(DisconnectCause.MISSED));
        }
        call.setDisconnectCause(disconnectCause);
        setCallState(call, CallState.DISCONNECTED, "disconnected set explicitly");
@@ -3104,6 +3109,14 @@ public class CallsManager extends Call.ListenerBase
        return mPhoneAccountRegistrar;
    }

    /**
     * Retrieves the {@link DisconnectedCallNotifier}
     * @return The {@link DisconnectedCallNotifier}.
     */
    DisconnectedCallNotifier getDisconnectedCallNotifier() {
        return mDisconnectedCallNotifier;
    }

    /**
     * Retrieves the {@link MissedCallNotifier}
     * @return The {@link MissedCallNotifier}.
@@ -3633,7 +3646,8 @@ public class CallsManager extends Call.ListenerBase
                    // we will try to connect the first outgoing call.
                    call.getAnalytics().setCallIsAdditional(true);
                    outgoingCall.getAnalytics().setCallIsInterrupted(true);
                    outgoingCall.disconnect();
                    outgoingCall.disconnect("Disconnecting dialing call in favor of new dialing"
                            + " emergency call.");
                    return true;
                }
                if (outgoingCall.getState() == CallState.SELECT_PHONE_ACCOUNT) {
@@ -3641,7 +3655,8 @@ public class CallsManager extends Call.ListenerBase
                    // state, just disconnect it since the user has explicitly started a new call.
                    call.getAnalytics().setCallIsAdditional(true);
                    outgoingCall.getAnalytics().setCallIsInterrupted(true);
                    outgoingCall.disconnect();
                    outgoingCall.disconnect("Disconnecting call in SELECT_PHONE_ACCOUNT in favor"
                            + " of new outgoing call.");
                    return true;
                }
                return false;
@@ -3680,6 +3695,23 @@ public class CallsManager extends Call.ListenerBase
                        liveCallPhoneAccount);
            }

            // We may not know which PhoneAccount the emergency call will be placed on yet, but if
            // the liveCall PhoneAccount does not support placing emergency calls, then we know it
            // will not be that one and we do not want multiple PhoneAccounts active during an
            // emergency call if possible. Disconnect the active call in favor of the emergency call
            // instead of trying to hold.
            if (isEmergency && liveCall.getTargetPhoneAccount() != null) {
                PhoneAccount pa = mPhoneAccountRegistrar.getPhoneAccountUnchecked(
                        liveCall.getTargetPhoneAccount());
                if((pa.getCapabilities() & PhoneAccount.CAPABILITY_PLACE_EMERGENCY_CALLS) == 0) {
                    liveCall.setOverrideDisconnectCauseCode(new DisconnectCause(
                            DisconnectCause.LOCAL, DisconnectCause.REASON_EMERGENCY_CALL_PLACED));
                    liveCall.disconnect("outgoing call does not support emergency calls, "
                            + "disconnecting.");
                }
                return true;
            }

            // First thing, if we are trying to make a call with the same phone account as the live
            // call, then allow it so that the connection service can make its own decision about
            // how to handle the new call relative to the current one.
@@ -3730,7 +3762,8 @@ public class CallsManager extends Call.ListenerBase
            } else { // normal incoming ringing call.
                // Hang up the ringing call to make room for the emergency call and mark as missed,
                // since the user did not reject.
                ringingCall.setOverrideDisconnectCauseCode(DisconnectCause.MISSED);
                ringingCall.setOverrideDisconnectCauseCode(
                        new DisconnectCause(DisconnectCause.MISSED));
                ringingCall.reject(false, null, "emergency call dialed during ringing.");
            }
            return true;
+58 −17
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import android.widget.Toast;

import com.android.server.telecom.ui.CallRedirectionConfirmDialogActivity;
import com.android.server.telecom.ui.ConfirmCallDialogActivity;
import com.android.server.telecom.ui.DisconnectedCallNotifier;

import java.util.List;

@@ -38,6 +39,14 @@ public final class TelecomBroadcastIntentProcessor {
    public static final String ACTION_CALL_BACK_FROM_NOTIFICATION =
            "com.android.server.telecom.ACTION_CALL_BACK_FROM_NOTIFICATION";

    /** The action used to send SMS response for the disconnected call notification. */
    public static final String ACTION_DISCONNECTED_SEND_SMS_FROM_NOTIFICATION =
            "com.android.server.telecom.ACTION_DISCONNECTED_SEND_SMS_FROM_NOTIFICATION";

    /** The action used to call a handle back for the disconnected call notification. */
    public static final String ACTION_DISCONNECTED_CALL_BACK_FROM_NOTIFICATION =
            "com.android.server.telecom.ACTION_DISCONNECTED_CALL_BACK_FROM_NOTIFICATION";

    /** The action used to clear missed calls. */
    public static final String ACTION_CLEAR_MISSED_CALLS =
            "com.android.server.telecom.ACTION_CLEAR_MISSED_CALLS";
@@ -121,34 +130,45 @@ public final class TelecomBroadcastIntentProcessor {
                // Close the notification shade and the notification itself.
                closeSystemDialogs(mContext);
                missedCallNotifier.clearMissedCalls(userHandle);

                Intent callIntent = new Intent(Intent.ACTION_SENDTO, intent.getData());
                callIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                PackageManager packageManager = mContext.getPackageManager();
                List<ResolveInfo> activities = packageManager.queryIntentActivitiesAsUser(
                        callIntent, PackageManager.MATCH_DEFAULT_ONLY, userHandle.getIdentifier());
                if (activities.size() > 0) {
                    mContext.startActivityAsUser(callIntent, userHandle);
                } else {
                    Toast.makeText(mContext, com.android.internal.R.string.noApplications,
                            Toast.LENGTH_SHORT).show();
                }
                sendSmsIntent(intent, userHandle);

                // Call back recent caller from the missed call notification.
            } else if (ACTION_CALL_BACK_FROM_NOTIFICATION.equals(action)) {
                // Close the notification shade and the notification itself.
                closeSystemDialogs(mContext);
                missedCallNotifier.clearMissedCalls(userHandle);

                Intent callIntent = new Intent(Intent.ACTION_CALL, intent.getData());
                callIntent.setFlags(
                        Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
                mContext.startActivityAsUser(callIntent, userHandle);
                sendCallBackIntent(intent, userHandle);

                // Clear the missed call notification and call log entries.
            } else if (ACTION_CLEAR_MISSED_CALLS.equals(action)) {
                missedCallNotifier.clearMissedCalls(userHandle);
            }
        } else if(ACTION_DISCONNECTED_SEND_SMS_FROM_NOTIFICATION.equals(action) ||
                ACTION_DISCONNECTED_CALL_BACK_FROM_NOTIFICATION.equals(action)) {
            Log.v(this, "Action received: %s.", action);
            UserHandle userHandle = intent.getParcelableExtra(EXTRA_USERHANDLE);
            if (userHandle == null) {
                Log.d(this, "disconnect user handle can't be null, not processing the broadcast");
                return;
            }

            DisconnectedCallNotifier disconnectedCallNotifier =
                    mCallsManager.getDisconnectedCallNotifier();

            // Send an SMS from the disconnected call notification.
            if (ACTION_DISCONNECTED_SEND_SMS_FROM_NOTIFICATION.equals(action)) {
                // Close the notification shade and the notification itself.
                closeSystemDialogs(mContext);
                disconnectedCallNotifier.clearNotification(userHandle);
                sendSmsIntent(intent, userHandle);

            // Call back recent caller from the disconnected call notification.
            } else if (ACTION_DISCONNECTED_CALL_BACK_FROM_NOTIFICATION.equals(action)) {
                // Close the notification shade and the notification itself.
                closeSystemDialogs(mContext);
                disconnectedCallNotifier.clearNotification(userHandle);
                sendCallBackIntent(intent, userHandle);
            }
        } else if (ACTION_ANSWER_FROM_NOTIFICATION.equals(action)) {
            Log.startSession("TBIP.aAFM");
            try {
@@ -230,4 +250,25 @@ public final class TelecomBroadcastIntentProcessor {
        Intent intent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
        context.sendBroadcastAsUser(intent, UserHandle.ALL);
    }

    private void sendSmsIntent(Intent intent, UserHandle userHandle) {
        Intent callIntent = new Intent(Intent.ACTION_SENDTO, intent.getData());
        callIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        PackageManager packageManager = mContext.getPackageManager();
        List<ResolveInfo> activities = packageManager.queryIntentActivitiesAsUser(
                callIntent, PackageManager.MATCH_DEFAULT_ONLY, userHandle.getIdentifier());
        if (activities.size() > 0) {
            mContext.startActivityAsUser(callIntent, userHandle);
        } else {
            Toast.makeText(mContext, com.android.internal.R.string.noApplications,
                    Toast.LENGTH_SHORT).show();
        }
    }

    private void sendCallBackIntent(Intent intent, UserHandle userHandle) {
        Intent callIntent = new Intent(Intent.ACTION_CALL, intent.getData());
        callIntent.setFlags(
                Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
        mContext.startActivityAsUser(callIntent, userHandle);
    }
}
+4 −0
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import com.android.server.telecom.callfiltering.IncomingCallFilter;
import com.android.server.telecom.components.UserCallIntentProcessor;
import com.android.server.telecom.components.UserCallIntentProcessorFactory;
import com.android.server.telecom.ui.AudioProcessingNotification;
import com.android.server.telecom.ui.DisconnectedCallNotifier;
import com.android.server.telecom.ui.IncomingCallNotifier;
import com.android.server.telecom.ui.MissedCallNotifierImpl.MissedCallNotifierImplFactory;
import com.android.server.telecom.BluetoothPhoneServiceImpl.BluetoothPhoneServiceImplFactory;
@@ -251,6 +252,8 @@ public class TelecomSystem {

        mMissedCallNotifier = missedCallNotifierImplFactory
                .makeMissedCallNotifierImpl(mContext, mPhoneAccountRegistrar, defaultDialerCache);
        DisconnectedCallNotifier.Factory disconnectedCallNotifierFactory =
                new DisconnectedCallNotifier.Default();

        CallerInfoLookupHelper callerInfoLookupHelper =
                new CallerInfoLookupHelper(context, callerInfoAsyncQueryFactory,
@@ -291,6 +294,7 @@ public class TelecomSystem {
                mLock,
                callerInfoLookupHelper,
                mMissedCallNotifier,
                disconnectedCallNotifierFactory,
                mPhoneAccountRegistrar,
                headsetMediaButtonFactory,
                proximitySensorManagerFactory,
Loading