blob: 2126c4838643ea99a8ce5713c311137740f194ad [file] [log] [blame]
Yorke Lee6dc1c752014-09-23 18:50:35 -07001package com.android.server.telecom;
2
Ihab Awad78a5e6b2015-02-06 10:13:05 -08003import com.android.server.telecom.components.ErrorDialogActivity;
4
Yorke Lee6dc1c752014-09-23 18:50:35 -07005import android.content.Context;
6import android.content.Intent;
7import android.net.Uri;
8import android.os.Bundle;
Yorke Lee9b71ea82014-11-26 11:15:13 -08009import android.os.Trace;
Yorke Lee6dc1c752014-09-23 18:50:35 -070010import android.os.UserHandle;
Tony Mak22214052016-01-19 18:50:44 +000011import android.os.UserManager;
Tyler Gunn24b6d772015-08-03 08:45:40 -070012import android.telecom.Connection;
Tony Mak22214052016-01-19 18:50:44 +000013import android.telecom.DefaultDialerManager;
Brad Ebinger953e1af2016-10-05 15:45:22 -070014import android.telecom.Log;
Yorke Lee6dc1c752014-09-23 18:50:35 -070015import android.telecom.PhoneAccount;
16import android.telecom.PhoneAccountHandle;
17import android.telecom.TelecomManager;
Andrew Lee45506232014-10-22 17:54:33 -070018import android.telecom.VideoProfile;
Yorke Lee6dc1c752014-09-23 18:50:35 -070019import android.telephony.DisconnectCause;
20import android.telephony.PhoneNumberUtils;
Andrew Lee45506232014-10-22 17:54:33 -070021import android.widget.Toast;
Yorke Lee6dc1c752014-09-23 18:50:35 -070022
23/**
Ihab Awad8d5d9dd2015-03-12 11:11:06 -070024 * 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 Lee6dc1c752014-09-23 18:50:35 -070028 */
Ihab Awad78a5e6b2015-02-06 10:13:05 -080029public class CallIntentProcessor {
Hall Liuecda5542015-12-04 11:31:31 -080030 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 Lee6dc1c752014-09-23 18:50:35 -070054
Ihab Awad8d5d9dd2015-03-12 11:11:06 -070055 public static final String KEY_IS_UNKNOWN_CALL = "is_unknown_call";
56 public static final String KEY_IS_INCOMING_CALL = "is_incoming_call";
Yorke Lee81050722015-04-23 19:57:10 -070057 /*
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 Lee6dc1c752014-09-23 18:50:35 -070062
Tony Mak578a4e62015-11-23 11:18:51 +000063 /**
64 * The user initiating the outgoing call.
65 */
66 public static final String KEY_INITIATING_USER = "initiating_user";
67
68
Ihab Awad78a5e6b2015-02-06 10:13:05 -080069 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 Lee9250e5f2014-10-01 13:39:09 -070078 final boolean isUnknownCall = intent.getBooleanExtra(KEY_IS_UNKNOWN_CALL, false);
Yorke Leee732ef42014-10-14 11:53:16 -070079 Log.i(this, "onReceive - isUnknownCall: %s", isUnknownCall);
Yorke Lee6dc1c752014-09-23 18:50:35 -070080
Yorke Lee9b71ea82014-11-26 11:15:13 -080081 Trace.beginSection("processNewCallCallIntent");
Yorke Lee9250e5f2014-10-01 13:39:09 -070082 if (isUnknownCall) {
Ihab Awad78a5e6b2015-02-06 10:13:05 -080083 processUnknownCallIntent(mCallsManager, intent);
Yorke Lee6dc1c752014-09-23 18:50:35 -070084 } else {
Ihab Awad78a5e6b2015-02-06 10:13:05 -080085 processOutgoingCallIntent(mContext, mCallsManager, intent);
Yorke Lee6dc1c752014-09-23 18:50:35 -070086 }
Yorke Lee9b71ea82014-11-26 11:15:13 -080087 Trace.endSection();
Yorke Lee6dc1c752014-09-23 18:50:35 -070088 }
89
Ihab Awad78a5e6b2015-02-06 10:13:05 -080090
Yorke Lee6dc1c752014-09-23 18:50:35 -070091 /**
92 * Processes CALL, CALL_PRIVILEGED, and CALL_EMERGENCY intents.
93 *
94 * @param intent Call intent containing data about the handle to call.
95 */
Ihab Awad78a5e6b2015-02-06 10:13:05 -080096 static void processOutgoingCallIntent(
97 Context context,
98 CallsManager callsManager,
99 Intent intent) {
Andrew Lee45506232014-10-22 17:54:33 -0700100
Yorke Lee6dc1c752014-09-23 18:50:35 -0700101 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 Leea49ede12015-03-23 11:15:35 -0700118 clientExtras = new Bundle();
Yorke Lee6dc1c752014-09-23 18:50:35 -0700119 }
120
Tyler Gunn24b6d772015-08-03 08:45:40 -0700121 // 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 Kolangade005612a2015-08-25 11:08:18 -0700127 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 Lee81050722015-04-23 19:57:10 -0700131 final boolean isPrivilegedDialer = intent.getBooleanExtra(KEY_IS_PRIVILEGED_DIALER, false);
Yorke Lee6dc1c752014-09-23 18:50:35 -0700132
Tony Makd7aaa1c2016-02-17 17:37:22 +0000133 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 Mak578a4e62015-11-23 11:18:51 +0000139 UserHandle initiatingUser = intent.getParcelableExtra(KEY_INITIATING_USER);
140
Yorke Lee6dc1c752014-09-23 18:50:35 -0700141 // Send to CallsManager to ensure the InCallUI gets kicked off before the broadcast returns
Tony Mak578a4e62015-11-23 11:18:51 +0000142 Call call = callsManager
143 .startOutgoingCall(handle, phoneAccountHandle, clientExtras, initiatingUser);
Yorke Lee6dc1c752014-09-23 18:50:35 -0700144
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 Ebinger6e8f3d72016-06-20 11:35:42 -0700152 context, callsManager, call, intent, callsManager.getPhoneNumberUtilsAdapter(),
Hall Liu220b4192015-12-11 11:33:08 -0800153 isPrivilegedDialer);
Yorke Lee6dc1c752014-09-23 18:50:35 -0700154 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 Mak22214052016-01-19 18:50:44 +0000163 /**
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 Makd7aaa1c2016-02-17 17:37:22 +0000166 *
167 * @return whether the initiating user is fixed.
Tony Mak22214052016-01-19 18:50:44 +0000168 */
Tony Makd7aaa1c2016-02-17 17:37:22 +0000169 static boolean fixInitiatingUserIfNecessary(Context context, Intent intent) {
Tony Mak22214052016-01-19 18:50:44 +0000170 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 Makd7aaa1c2016-02-17 17:37:22 +0000180 return true;
Tony Mak22214052016-01-19 18:50:44 +0000181 }
182 }
Tony Makd7aaa1c2016-02-17 17:37:22 +0000183 return false;
Tony Mak22214052016-01-19 18:50:44 +0000184 }
185
Ihab Awad78a5e6b2015-02-06 10:13:05 -0800186 static void processIncomingCallIntent(CallsManager callsManager, Intent intent) {
Yorke Lee6dc1c752014-09-23 18:50:35 -0700187 PhoneAccountHandle phoneAccountHandle = intent.getParcelableExtra(
188 TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE);
189
190 if (phoneAccountHandle == null) {
Ihab Awad78a5e6b2015-02-06 10:13:05 -0800191 Log.w(CallIntentProcessor.class,
192 "Rejecting incoming call due to null phone account");
Yorke Lee6dc1c752014-09-23 18:50:35 -0700193 return;
194 }
195 if (phoneAccountHandle.getComponentName() == null) {
Ihab Awad78a5e6b2015-02-06 10:13:05 -0800196 Log.w(CallIntentProcessor.class,
197 "Rejecting incoming call due to null component name");
Yorke Lee6dc1c752014-09-23 18:50:35 -0700198 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 Leea49ede12015-03-23 11:15:35 -0700206 clientExtras = new Bundle();
Yorke Lee6dc1c752014-09-23 18:50:35 -0700207 }
208
Ihab Awad78a5e6b2015-02-06 10:13:05 -0800209 Log.d(CallIntentProcessor.class,
210 "Processing incoming call from connection service [%s]",
Yorke Lee6dc1c752014-09-23 18:50:35 -0700211 phoneAccountHandle.getComponentName());
Ihab Awad78a5e6b2015-02-06 10:13:05 -0800212 callsManager.processIncomingCallIntent(phoneAccountHandle, clientExtras);
Yorke Lee6dc1c752014-09-23 18:50:35 -0700213 }
214
David Stevens07852742015-04-10 18:22:47 -0700215 static void processUnknownCallIntent(CallsManager callsManager, Intent intent) {
Yorke Lee9250e5f2014-10-01 13:39:09 -0700216 PhoneAccountHandle phoneAccountHandle = intent.getParcelableExtra(
217 TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE);
218
219 if (phoneAccountHandle == null) {
Ihab Awad78a5e6b2015-02-06 10:13:05 -0800220 Log.w(CallIntentProcessor.class, "Rejecting unknown call due to null phone account");
Yorke Lee9250e5f2014-10-01 13:39:09 -0700221 return;
222 }
223 if (phoneAccountHandle.getComponentName() == null) {
Ihab Awad78a5e6b2015-02-06 10:13:05 -0800224 Log.w(CallIntentProcessor.class, "Rejecting unknown call due to null component name");
Yorke Lee9250e5f2014-10-01 13:39:09 -0700225 return;
226 }
227
Ihab Awad78a5e6b2015-02-06 10:13:05 -0800228 callsManager.addNewUnknownCall(phoneAccountHandle, intent.getExtras());
Yorke Lee6dc1c752014-09-23 18:50:35 -0700229 }
230
Andrew Lee72d271c2014-10-03 11:58:06 -0700231 private static void disconnectCallAndShowErrorDialog(
232 Context context, Call call, int errorCode) {
Yorke Lee6dc1c752014-09-23 18:50:35 -0700233 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 Lee94c7ab22015-04-30 14:59:12 -0700244 errorIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
245 context.startActivityAsUser(errorIntent, UserHandle.CURRENT);
Yorke Lee6dc1c752014-09-23 18:50:35 -0700246 }
Yorke Lee6dc1c752014-09-23 18:50:35 -0700247 }
Yorke Lee6dc1c752014-09-23 18:50:35 -0700248}