Yorke Lee | 6dc1c75 | 2014-09-23 18:50:35 -0700 | [diff] [blame] | 1 | package com.android.server.telecom; |
| 2 | |
Ihab Awad | 78a5e6b | 2015-02-06 10:13:05 -0800 | [diff] [blame] | 3 | import com.android.server.telecom.components.ErrorDialogActivity; |
| 4 | |
Yorke Lee | 6dc1c75 | 2014-09-23 18:50:35 -0700 | [diff] [blame] | 5 | import android.content.Context; |
| 6 | import android.content.Intent; |
| 7 | import android.net.Uri; |
| 8 | import android.os.Bundle; |
Yorke Lee | 9b71ea8 | 2014-11-26 11:15:13 -0800 | [diff] [blame] | 9 | import android.os.Trace; |
Yorke Lee | 6dc1c75 | 2014-09-23 18:50:35 -0700 | [diff] [blame] | 10 | import android.os.UserHandle; |
Tony Mak | 2221405 | 2016-01-19 18:50:44 +0000 | [diff] [blame] | 11 | import android.os.UserManager; |
Tyler Gunn | 24b6d77 | 2015-08-03 08:45:40 -0700 | [diff] [blame] | 12 | import android.telecom.Connection; |
Tony Mak | 2221405 | 2016-01-19 18:50:44 +0000 | [diff] [blame] | 13 | import android.telecom.DefaultDialerManager; |
Brad Ebinger | 953e1af | 2016-10-05 15:45:22 -0700 | [diff] [blame] | 14 | import android.telecom.Log; |
Yorke Lee | 6dc1c75 | 2014-09-23 18:50:35 -0700 | [diff] [blame] | 15 | import android.telecom.PhoneAccount; |
| 16 | import android.telecom.PhoneAccountHandle; |
| 17 | import android.telecom.TelecomManager; |
Andrew Lee | 4550623 | 2014-10-22 17:54:33 -0700 | [diff] [blame] | 18 | import android.telecom.VideoProfile; |
Yorke Lee | 6dc1c75 | 2014-09-23 18:50:35 -0700 | [diff] [blame] | 19 | import android.telephony.DisconnectCause; |
| 20 | import android.telephony.PhoneNumberUtils; |
Andrew Lee | 4550623 | 2014-10-22 17:54:33 -0700 | [diff] [blame] | 21 | import android.widget.Toast; |
Yorke Lee | 6dc1c75 | 2014-09-23 18:50:35 -0700 | [diff] [blame] | 22 | |
| 23 | /** |
Ihab Awad | 8d5d9dd | 2015-03-12 11:11:06 -0700 | [diff] [blame] | 24 | * Single point of entry for all outgoing and incoming calls. |
| 25 | * {@link com.android.server.telecom.components.UserCallIntentProcessor} serves as a trampoline that |
| 26 | * captures call intents for individual users and forwards it to the {@link CallIntentProcessor} |
| 27 | * which interacts with the rest of Telecom, both of which run only as the primary user. |
Yorke Lee | 6dc1c75 | 2014-09-23 18:50:35 -0700 | [diff] [blame] | 28 | */ |
Ihab Awad | 78a5e6b | 2015-02-06 10:13:05 -0800 | [diff] [blame] | 29 | public class CallIntentProcessor { |
Hall Liu | ecda554 | 2015-12-04 11:31:31 -0800 | [diff] [blame] | 30 | public interface Adapter { |
| 31 | void processOutgoingCallIntent(Context context, CallsManager callsManager, |
| 32 | Intent intent); |
| 33 | void processIncomingCallIntent(CallsManager callsManager, Intent intent); |
| 34 | void processUnknownCallIntent(CallsManager callsManager, Intent intent); |
| 35 | } |
| 36 | |
| 37 | public static class AdapterImpl implements Adapter { |
| 38 | @Override |
| 39 | public void processOutgoingCallIntent(Context context, CallsManager callsManager, |
| 40 | Intent intent) { |
| 41 | CallIntentProcessor.processOutgoingCallIntent(context, callsManager, intent); |
| 42 | } |
| 43 | |
| 44 | @Override |
| 45 | public void processIncomingCallIntent(CallsManager callsManager, Intent intent) { |
| 46 | CallIntentProcessor.processIncomingCallIntent(callsManager, intent); |
| 47 | } |
| 48 | |
| 49 | @Override |
| 50 | public void processUnknownCallIntent(CallsManager callsManager, Intent intent) { |
| 51 | CallIntentProcessor.processUnknownCallIntent(callsManager, intent); |
| 52 | } |
| 53 | } |
Yorke Lee | 6dc1c75 | 2014-09-23 18:50:35 -0700 | [diff] [blame] | 54 | |
Ihab Awad | 8d5d9dd | 2015-03-12 11:11:06 -0700 | [diff] [blame] | 55 | public static final String KEY_IS_UNKNOWN_CALL = "is_unknown_call"; |
| 56 | public static final String KEY_IS_INCOMING_CALL = "is_incoming_call"; |
Yorke Lee | 8105072 | 2015-04-23 19:57:10 -0700 | [diff] [blame] | 57 | /* |
| 58 | * Whether or not the dialer initiating this outgoing call is the default dialer, or system |
| 59 | * dialer and thus allowed to make emergency calls. |
| 60 | */ |
| 61 | public static final String KEY_IS_PRIVILEGED_DIALER = "is_privileged_dialer"; |
Yorke Lee | 6dc1c75 | 2014-09-23 18:50:35 -0700 | [diff] [blame] | 62 | |
Tony Mak | 578a4e6 | 2015-11-23 11:18:51 +0000 | [diff] [blame] | 63 | /** |
| 64 | * The user initiating the outgoing call. |
| 65 | */ |
| 66 | public static final String KEY_INITIATING_USER = "initiating_user"; |
| 67 | |
| 68 | |
Ihab Awad | 78a5e6b | 2015-02-06 10:13:05 -0800 | [diff] [blame] | 69 | private final Context mContext; |
| 70 | private final CallsManager mCallsManager; |
| 71 | |
| 72 | public CallIntentProcessor(Context context, CallsManager callsManager) { |
| 73 | this.mContext = context; |
| 74 | this.mCallsManager = callsManager; |
| 75 | } |
| 76 | |
| 77 | public void processIntent(Intent intent) { |
Yorke Lee | 9250e5f | 2014-10-01 13:39:09 -0700 | [diff] [blame] | 78 | final boolean isUnknownCall = intent.getBooleanExtra(KEY_IS_UNKNOWN_CALL, false); |
Yorke Lee | e732ef4 | 2014-10-14 11:53:16 -0700 | [diff] [blame] | 79 | Log.i(this, "onReceive - isUnknownCall: %s", isUnknownCall); |
Yorke Lee | 6dc1c75 | 2014-09-23 18:50:35 -0700 | [diff] [blame] | 80 | |
Yorke Lee | 9b71ea8 | 2014-11-26 11:15:13 -0800 | [diff] [blame] | 81 | Trace.beginSection("processNewCallCallIntent"); |
Yorke Lee | 9250e5f | 2014-10-01 13:39:09 -0700 | [diff] [blame] | 82 | if (isUnknownCall) { |
Ihab Awad | 78a5e6b | 2015-02-06 10:13:05 -0800 | [diff] [blame] | 83 | processUnknownCallIntent(mCallsManager, intent); |
Yorke Lee | 6dc1c75 | 2014-09-23 18:50:35 -0700 | [diff] [blame] | 84 | } else { |
Ihab Awad | 78a5e6b | 2015-02-06 10:13:05 -0800 | [diff] [blame] | 85 | processOutgoingCallIntent(mContext, mCallsManager, intent); |
Yorke Lee | 6dc1c75 | 2014-09-23 18:50:35 -0700 | [diff] [blame] | 86 | } |
Yorke Lee | 9b71ea8 | 2014-11-26 11:15:13 -0800 | [diff] [blame] | 87 | Trace.endSection(); |
Yorke Lee | 6dc1c75 | 2014-09-23 18:50:35 -0700 | [diff] [blame] | 88 | } |
| 89 | |
Ihab Awad | 78a5e6b | 2015-02-06 10:13:05 -0800 | [diff] [blame] | 90 | |
Yorke Lee | 6dc1c75 | 2014-09-23 18:50:35 -0700 | [diff] [blame] | 91 | /** |
| 92 | * Processes CALL, CALL_PRIVILEGED, and CALL_EMERGENCY intents. |
| 93 | * |
| 94 | * @param intent Call intent containing data about the handle to call. |
| 95 | */ |
Ihab Awad | 78a5e6b | 2015-02-06 10:13:05 -0800 | [diff] [blame] | 96 | static void processOutgoingCallIntent( |
| 97 | Context context, |
| 98 | CallsManager callsManager, |
| 99 | Intent intent) { |
Andrew Lee | 4550623 | 2014-10-22 17:54:33 -0700 | [diff] [blame] | 100 | |
Yorke Lee | 6dc1c75 | 2014-09-23 18:50:35 -0700 | [diff] [blame] | 101 | Uri handle = intent.getData(); |
| 102 | String scheme = handle.getScheme(); |
| 103 | String uriString = handle.getSchemeSpecificPart(); |
| 104 | |
| 105 | if (!PhoneAccount.SCHEME_VOICEMAIL.equals(scheme)) { |
| 106 | handle = Uri.fromParts(PhoneNumberUtils.isUriNumber(uriString) ? |
| 107 | PhoneAccount.SCHEME_SIP : PhoneAccount.SCHEME_TEL, uriString, null); |
| 108 | } |
| 109 | |
| 110 | PhoneAccountHandle phoneAccountHandle = intent.getParcelableExtra( |
| 111 | TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE); |
| 112 | |
| 113 | Bundle clientExtras = null; |
| 114 | if (intent.hasExtra(TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS)) { |
| 115 | clientExtras = intent.getBundleExtra(TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS); |
| 116 | } |
| 117 | if (clientExtras == null) { |
Yorke Lee | a49ede1 | 2015-03-23 11:15:35 -0700 | [diff] [blame] | 118 | clientExtras = new Bundle(); |
Yorke Lee | 6dc1c75 | 2014-09-23 18:50:35 -0700 | [diff] [blame] | 119 | } |
| 120 | |
Tyler Gunn | 24b6d77 | 2015-08-03 08:45:40 -0700 | [diff] [blame] | 121 | // Ensure call subject is passed on to the connection service. |
| 122 | if (intent.hasExtra(TelecomManager.EXTRA_CALL_SUBJECT)) { |
| 123 | String callsubject = intent.getStringExtra(TelecomManager.EXTRA_CALL_SUBJECT); |
| 124 | clientExtras.putString(TelecomManager.EXTRA_CALL_SUBJECT, callsubject); |
| 125 | } |
| 126 | |
Omkar Kolangade | 005612a | 2015-08-25 11:08:18 -0700 | [diff] [blame] | 127 | final int videoState = intent.getIntExtra( TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE, |
| 128 | VideoProfile.STATE_AUDIO_ONLY); |
| 129 | clientExtras.putInt(TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE, videoState); |
| 130 | |
Yorke Lee | 8105072 | 2015-04-23 19:57:10 -0700 | [diff] [blame] | 131 | final boolean isPrivilegedDialer = intent.getBooleanExtra(KEY_IS_PRIVILEGED_DIALER, false); |
Yorke Lee | 6dc1c75 | 2014-09-23 18:50:35 -0700 | [diff] [blame] | 132 | |
Tony Mak | d7aaa1c | 2016-02-17 17:37:22 +0000 | [diff] [blame] | 133 | boolean fixedInitiatingUser = fixInitiatingUserIfNecessary(context, intent); |
| 134 | // Show the toast to warn user that it is a personal call though initiated in work profile. |
| 135 | if (fixedInitiatingUser) { |
| 136 | Toast.makeText(context, R.string.toast_personal_call_msg, Toast.LENGTH_LONG).show(); |
| 137 | } |
| 138 | |
Tony Mak | 578a4e6 | 2015-11-23 11:18:51 +0000 | [diff] [blame] | 139 | UserHandle initiatingUser = intent.getParcelableExtra(KEY_INITIATING_USER); |
| 140 | |
Yorke Lee | 6dc1c75 | 2014-09-23 18:50:35 -0700 | [diff] [blame] | 141 | // Send to CallsManager to ensure the InCallUI gets kicked off before the broadcast returns |
Tony Mak | 578a4e6 | 2015-11-23 11:18:51 +0000 | [diff] [blame] | 142 | Call call = callsManager |
| 143 | .startOutgoingCall(handle, phoneAccountHandle, clientExtras, initiatingUser); |
Yorke Lee | 6dc1c75 | 2014-09-23 18:50:35 -0700 | [diff] [blame] | 144 | |
| 145 | if (call != null) { |
| 146 | // Asynchronous calls should not usually be made inside a BroadcastReceiver because once |
| 147 | // onReceive is complete, the BroadcastReceiver's process runs the risk of getting |
| 148 | // killed if memory is scarce. However, this is OK here because the entire Telecom |
| 149 | // process will be running throughout the duration of the phone call and should never |
| 150 | // be killed. |
| 151 | NewOutgoingCallIntentBroadcaster broadcaster = new NewOutgoingCallIntentBroadcaster( |
Brad Ebinger | 6e8f3d7 | 2016-06-20 11:35:42 -0700 | [diff] [blame] | 152 | context, callsManager, call, intent, callsManager.getPhoneNumberUtilsAdapter(), |
Hall Liu | 220b419 | 2015-12-11 11:33:08 -0800 | [diff] [blame] | 153 | isPrivilegedDialer); |
Yorke Lee | 6dc1c75 | 2014-09-23 18:50:35 -0700 | [diff] [blame] | 154 | final int result = broadcaster.processIntent(); |
| 155 | final boolean success = result == DisconnectCause.NOT_DISCONNECTED; |
| 156 | |
| 157 | if (!success && call != null) { |
| 158 | disconnectCallAndShowErrorDialog(context, call, result); |
| 159 | } |
| 160 | } |
| 161 | } |
| 162 | |
Tony Mak | 2221405 | 2016-01-19 18:50:44 +0000 | [diff] [blame] | 163 | /** |
| 164 | * If the call is initiated from managed profile but there is no work dialer installed, treat |
| 165 | * the call is initiated from its parent user. |
Tony Mak | d7aaa1c | 2016-02-17 17:37:22 +0000 | [diff] [blame] | 166 | * |
| 167 | * @return whether the initiating user is fixed. |
Tony Mak | 2221405 | 2016-01-19 18:50:44 +0000 | [diff] [blame] | 168 | */ |
Tony Mak | d7aaa1c | 2016-02-17 17:37:22 +0000 | [diff] [blame] | 169 | static boolean fixInitiatingUserIfNecessary(Context context, Intent intent) { |
Tony Mak | 2221405 | 2016-01-19 18:50:44 +0000 | [diff] [blame] | 170 | final UserHandle initiatingUser = intent.getParcelableExtra(KEY_INITIATING_USER); |
| 171 | if (UserUtil.isManagedProfile(context, initiatingUser)) { |
| 172 | boolean noDialerInstalled = DefaultDialerManager.getInstalledDialerApplications(context, |
| 173 | initiatingUser.getIdentifier()).size() == 0; |
| 174 | if (noDialerInstalled) { |
| 175 | final UserManager userManager = UserManager.get(context); |
| 176 | UserHandle parentUserHandle = |
| 177 | userManager.getProfileParent( |
| 178 | initiatingUser.getIdentifier()).getUserHandle(); |
| 179 | intent.putExtra(KEY_INITIATING_USER, parentUserHandle); |
Tony Mak | d7aaa1c | 2016-02-17 17:37:22 +0000 | [diff] [blame] | 180 | return true; |
Tony Mak | 2221405 | 2016-01-19 18:50:44 +0000 | [diff] [blame] | 181 | } |
| 182 | } |
Tony Mak | d7aaa1c | 2016-02-17 17:37:22 +0000 | [diff] [blame] | 183 | return false; |
Tony Mak | 2221405 | 2016-01-19 18:50:44 +0000 | [diff] [blame] | 184 | } |
| 185 | |
Ihab Awad | 78a5e6b | 2015-02-06 10:13:05 -0800 | [diff] [blame] | 186 | static void processIncomingCallIntent(CallsManager callsManager, Intent intent) { |
Yorke Lee | 6dc1c75 | 2014-09-23 18:50:35 -0700 | [diff] [blame] | 187 | PhoneAccountHandle phoneAccountHandle = intent.getParcelableExtra( |
| 188 | TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE); |
| 189 | |
| 190 | if (phoneAccountHandle == null) { |
Ihab Awad | 78a5e6b | 2015-02-06 10:13:05 -0800 | [diff] [blame] | 191 | Log.w(CallIntentProcessor.class, |
| 192 | "Rejecting incoming call due to null phone account"); |
Yorke Lee | 6dc1c75 | 2014-09-23 18:50:35 -0700 | [diff] [blame] | 193 | return; |
| 194 | } |
| 195 | if (phoneAccountHandle.getComponentName() == null) { |
Ihab Awad | 78a5e6b | 2015-02-06 10:13:05 -0800 | [diff] [blame] | 196 | Log.w(CallIntentProcessor.class, |
| 197 | "Rejecting incoming call due to null component name"); |
Yorke Lee | 6dc1c75 | 2014-09-23 18:50:35 -0700 | [diff] [blame] | 198 | return; |
| 199 | } |
| 200 | |
| 201 | Bundle clientExtras = null; |
| 202 | if (intent.hasExtra(TelecomManager.EXTRA_INCOMING_CALL_EXTRAS)) { |
| 203 | clientExtras = intent.getBundleExtra(TelecomManager.EXTRA_INCOMING_CALL_EXTRAS); |
| 204 | } |
| 205 | if (clientExtras == null) { |
Yorke Lee | a49ede1 | 2015-03-23 11:15:35 -0700 | [diff] [blame] | 206 | clientExtras = new Bundle(); |
Yorke Lee | 6dc1c75 | 2014-09-23 18:50:35 -0700 | [diff] [blame] | 207 | } |
| 208 | |
Ihab Awad | 78a5e6b | 2015-02-06 10:13:05 -0800 | [diff] [blame] | 209 | Log.d(CallIntentProcessor.class, |
| 210 | "Processing incoming call from connection service [%s]", |
Yorke Lee | 6dc1c75 | 2014-09-23 18:50:35 -0700 | [diff] [blame] | 211 | phoneAccountHandle.getComponentName()); |
Ihab Awad | 78a5e6b | 2015-02-06 10:13:05 -0800 | [diff] [blame] | 212 | callsManager.processIncomingCallIntent(phoneAccountHandle, clientExtras); |
Yorke Lee | 6dc1c75 | 2014-09-23 18:50:35 -0700 | [diff] [blame] | 213 | } |
| 214 | |
David Stevens | 0785274 | 2015-04-10 18:22:47 -0700 | [diff] [blame] | 215 | static void processUnknownCallIntent(CallsManager callsManager, Intent intent) { |
Yorke Lee | 9250e5f | 2014-10-01 13:39:09 -0700 | [diff] [blame] | 216 | PhoneAccountHandle phoneAccountHandle = intent.getParcelableExtra( |
| 217 | TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE); |
| 218 | |
| 219 | if (phoneAccountHandle == null) { |
Ihab Awad | 78a5e6b | 2015-02-06 10:13:05 -0800 | [diff] [blame] | 220 | Log.w(CallIntentProcessor.class, "Rejecting unknown call due to null phone account"); |
Yorke Lee | 9250e5f | 2014-10-01 13:39:09 -0700 | [diff] [blame] | 221 | return; |
| 222 | } |
| 223 | if (phoneAccountHandle.getComponentName() == null) { |
Ihab Awad | 78a5e6b | 2015-02-06 10:13:05 -0800 | [diff] [blame] | 224 | Log.w(CallIntentProcessor.class, "Rejecting unknown call due to null component name"); |
Yorke Lee | 9250e5f | 2014-10-01 13:39:09 -0700 | [diff] [blame] | 225 | return; |
| 226 | } |
| 227 | |
Ihab Awad | 78a5e6b | 2015-02-06 10:13:05 -0800 | [diff] [blame] | 228 | callsManager.addNewUnknownCall(phoneAccountHandle, intent.getExtras()); |
Yorke Lee | 6dc1c75 | 2014-09-23 18:50:35 -0700 | [diff] [blame] | 229 | } |
| 230 | |
Andrew Lee | 72d271c | 2014-10-03 11:58:06 -0700 | [diff] [blame] | 231 | private static void disconnectCallAndShowErrorDialog( |
| 232 | Context context, Call call, int errorCode) { |
Yorke Lee | 6dc1c75 | 2014-09-23 18:50:35 -0700 | [diff] [blame] | 233 | call.disconnect(); |
| 234 | final Intent errorIntent = new Intent(context, ErrorDialogActivity.class); |
| 235 | int errorMessageId = -1; |
| 236 | switch (errorCode) { |
| 237 | case DisconnectCause.INVALID_NUMBER: |
| 238 | case DisconnectCause.NO_PHONE_NUMBER_SUPPLIED: |
| 239 | errorMessageId = R.string.outgoing_call_error_no_phone_number_supplied; |
| 240 | break; |
| 241 | } |
| 242 | if (errorMessageId != -1) { |
| 243 | errorIntent.putExtra(ErrorDialogActivity.ERROR_MESSAGE_ID_EXTRA, errorMessageId); |
Yorke Lee | 94c7ab2 | 2015-04-30 14:59:12 -0700 | [diff] [blame] | 244 | errorIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); |
| 245 | context.startActivityAsUser(errorIntent, UserHandle.CURRENT); |
Yorke Lee | 6dc1c75 | 2014-09-23 18:50:35 -0700 | [diff] [blame] | 246 | } |
Yorke Lee | 6dc1c75 | 2014-09-23 18:50:35 -0700 | [diff] [blame] | 247 | } |
Yorke Lee | 6dc1c75 | 2014-09-23 18:50:35 -0700 | [diff] [blame] | 248 | } |