blob: fdd4ebc28907a6872a25001aacf525b388ff1412 [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;
Tony Mak22214052016-01-19 18:50:44 +000012import android.telecom.DefaultDialerManager;
Brad Ebingera3eccfe2016-10-05 15:45:22 -070013import android.telecom.Log;
Yorke Lee6dc1c752014-09-23 18:50:35 -070014import android.telecom.PhoneAccount;
15import android.telecom.PhoneAccountHandle;
16import android.telecom.TelecomManager;
Andrew Lee45506232014-10-22 17:54:33 -070017import android.telecom.VideoProfile;
Yorke Lee6dc1c752014-09-23 18:50:35 -070018import android.telephony.DisconnectCause;
19import android.telephony.PhoneNumberUtils;
Andrew Lee45506232014-10-22 17:54:33 -070020import android.widget.Toast;
Yorke Lee6dc1c752014-09-23 18:50:35 -070021
22/**
Ihab Awad8d5d9dd2015-03-12 11:11:06 -070023 * Single point of entry for all outgoing and incoming calls.
24 * {@link com.android.server.telecom.components.UserCallIntentProcessor} serves as a trampoline that
25 * captures call intents for individual users and forwards it to the {@link CallIntentProcessor}
26 * which interacts with the rest of Telecom, both of which run only as the primary user.
Yorke Lee6dc1c752014-09-23 18:50:35 -070027 */
Ihab Awad78a5e6b2015-02-06 10:13:05 -080028public class CallIntentProcessor {
Hall Liuecda5542015-12-04 11:31:31 -080029 public interface Adapter {
30 void processOutgoingCallIntent(Context context, CallsManager callsManager,
31 Intent intent);
32 void processIncomingCallIntent(CallsManager callsManager, Intent intent);
33 void processUnknownCallIntent(CallsManager callsManager, Intent intent);
34 }
35
36 public static class AdapterImpl implements Adapter {
37 @Override
38 public void processOutgoingCallIntent(Context context, CallsManager callsManager,
39 Intent intent) {
40 CallIntentProcessor.processOutgoingCallIntent(context, callsManager, intent);
41 }
42
43 @Override
44 public void processIncomingCallIntent(CallsManager callsManager, Intent intent) {
45 CallIntentProcessor.processIncomingCallIntent(callsManager, intent);
46 }
47
48 @Override
49 public void processUnknownCallIntent(CallsManager callsManager, Intent intent) {
50 CallIntentProcessor.processUnknownCallIntent(callsManager, intent);
51 }
52 }
Yorke Lee6dc1c752014-09-23 18:50:35 -070053
Ihab Awad8d5d9dd2015-03-12 11:11:06 -070054 public static final String KEY_IS_UNKNOWN_CALL = "is_unknown_call";
55 public static final String KEY_IS_INCOMING_CALL = "is_incoming_call";
Yorke Lee81050722015-04-23 19:57:10 -070056 /*
57 * Whether or not the dialer initiating this outgoing call is the default dialer, or system
58 * dialer and thus allowed to make emergency calls.
59 */
60 public static final String KEY_IS_PRIVILEGED_DIALER = "is_privileged_dialer";
Yorke Lee6dc1c752014-09-23 18:50:35 -070061
Tony Mak578a4e62015-11-23 11:18:51 +000062 /**
63 * The user initiating the outgoing call.
64 */
65 public static final String KEY_INITIATING_USER = "initiating_user";
66
67
Ihab Awad78a5e6b2015-02-06 10:13:05 -080068 private final Context mContext;
69 private final CallsManager mCallsManager;
70
71 public CallIntentProcessor(Context context, CallsManager callsManager) {
72 this.mContext = context;
73 this.mCallsManager = callsManager;
74 }
75
76 public void processIntent(Intent intent) {
Yorke Lee9250e5f2014-10-01 13:39:09 -070077 final boolean isUnknownCall = intent.getBooleanExtra(KEY_IS_UNKNOWN_CALL, false);
Yorke Leee732ef42014-10-14 11:53:16 -070078 Log.i(this, "onReceive - isUnknownCall: %s", isUnknownCall);
Yorke Lee6dc1c752014-09-23 18:50:35 -070079
Yorke Lee9b71ea82014-11-26 11:15:13 -080080 Trace.beginSection("processNewCallCallIntent");
Yorke Lee9250e5f2014-10-01 13:39:09 -070081 if (isUnknownCall) {
Ihab Awad78a5e6b2015-02-06 10:13:05 -080082 processUnknownCallIntent(mCallsManager, intent);
Yorke Lee6dc1c752014-09-23 18:50:35 -070083 } else {
Ihab Awad78a5e6b2015-02-06 10:13:05 -080084 processOutgoingCallIntent(mContext, mCallsManager, intent);
Yorke Lee6dc1c752014-09-23 18:50:35 -070085 }
Yorke Lee9b71ea82014-11-26 11:15:13 -080086 Trace.endSection();
Yorke Lee6dc1c752014-09-23 18:50:35 -070087 }
88
Ihab Awad78a5e6b2015-02-06 10:13:05 -080089
Yorke Lee6dc1c752014-09-23 18:50:35 -070090 /**
91 * Processes CALL, CALL_PRIVILEGED, and CALL_EMERGENCY intents.
92 *
93 * @param intent Call intent containing data about the handle to call.
94 */
Ihab Awad78a5e6b2015-02-06 10:13:05 -080095 static void processOutgoingCallIntent(
96 Context context,
97 CallsManager callsManager,
98 Intent intent) {
Andrew Lee45506232014-10-22 17:54:33 -070099
Yorke Lee6dc1c752014-09-23 18:50:35 -0700100 Uri handle = intent.getData();
101 String scheme = handle.getScheme();
102 String uriString = handle.getSchemeSpecificPart();
103
104 if (!PhoneAccount.SCHEME_VOICEMAIL.equals(scheme)) {
105 handle = Uri.fromParts(PhoneNumberUtils.isUriNumber(uriString) ?
106 PhoneAccount.SCHEME_SIP : PhoneAccount.SCHEME_TEL, uriString, null);
107 }
108
109 PhoneAccountHandle phoneAccountHandle = intent.getParcelableExtra(
110 TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE);
111
112 Bundle clientExtras = null;
113 if (intent.hasExtra(TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS)) {
114 clientExtras = intent.getBundleExtra(TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS);
115 }
116 if (clientExtras == null) {
Yorke Leea49ede12015-03-23 11:15:35 -0700117 clientExtras = new Bundle();
Yorke Lee6dc1c752014-09-23 18:50:35 -0700118 }
119
Tyler Gunn24b6d772015-08-03 08:45:40 -0700120 // Ensure call subject is passed on to the connection service.
121 if (intent.hasExtra(TelecomManager.EXTRA_CALL_SUBJECT)) {
122 String callsubject = intent.getStringExtra(TelecomManager.EXTRA_CALL_SUBJECT);
123 clientExtras.putString(TelecomManager.EXTRA_CALL_SUBJECT, callsubject);
124 }
125
Omkar Kolangade005612a2015-08-25 11:08:18 -0700126 final int videoState = intent.getIntExtra( TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE,
127 VideoProfile.STATE_AUDIO_ONLY);
128 clientExtras.putInt(TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE, videoState);
129
Tony Makd7aaa1c2016-02-17 17:37:22 +0000130 boolean fixedInitiatingUser = fixInitiatingUserIfNecessary(context, intent);
131 // Show the toast to warn user that it is a personal call though initiated in work profile.
132 if (fixedInitiatingUser) {
133 Toast.makeText(context, R.string.toast_personal_call_msg, Toast.LENGTH_LONG).show();
134 }
135
Tony Mak578a4e62015-11-23 11:18:51 +0000136 UserHandle initiatingUser = intent.getParcelableExtra(KEY_INITIATING_USER);
137
Yorke Lee6dc1c752014-09-23 18:50:35 -0700138 // Send to CallsManager to ensure the InCallUI gets kicked off before the broadcast returns
Tony Mak578a4e62015-11-23 11:18:51 +0000139 Call call = callsManager
Tyler Gunnbbd78a72017-04-30 14:16:07 -0700140 .startOutgoingCall(handle, phoneAccountHandle, clientExtras, initiatingUser,
141 intent);
Yorke Lee6dc1c752014-09-23 18:50:35 -0700142
143 if (call != null) {
Tyler Gunnbbd78a72017-04-30 14:16:07 -0700144 sendNewOutgoingCallIntent(context, call, callsManager, intent);
145 }
146 }
Yorke Lee6dc1c752014-09-23 18:50:35 -0700147
Tyler Gunnbbd78a72017-04-30 14:16:07 -0700148 static void sendNewOutgoingCallIntent(Context context, Call call, CallsManager callsManager,
149 Intent intent) {
150 // Asynchronous calls should not usually be made inside a BroadcastReceiver because once
151 // onReceive is complete, the BroadcastReceiver's process runs the risk of getting
152 // killed if memory is scarce. However, this is OK here because the entire Telecom
153 // process will be running throughout the duration of the phone call and should never
154 // be killed.
155 final boolean isPrivilegedDialer = intent.getBooleanExtra(KEY_IS_PRIVILEGED_DIALER, false);
156
157 NewOutgoingCallIntentBroadcaster broadcaster = new NewOutgoingCallIntentBroadcaster(
158 context, callsManager, call, intent, callsManager.getPhoneNumberUtilsAdapter(),
159 isPrivilegedDialer);
160 final int result = broadcaster.processIntent();
161 final boolean success = result == DisconnectCause.NOT_DISCONNECTED;
162
163 if (!success && call != null) {
164 disconnectCallAndShowErrorDialog(context, call, result);
Yorke Lee6dc1c752014-09-23 18:50:35 -0700165 }
166 }
167
Tony Mak22214052016-01-19 18:50:44 +0000168 /**
169 * If the call is initiated from managed profile but there is no work dialer installed, treat
170 * the call is initiated from its parent user.
Tony Makd7aaa1c2016-02-17 17:37:22 +0000171 *
172 * @return whether the initiating user is fixed.
Tony Mak22214052016-01-19 18:50:44 +0000173 */
Tony Makd7aaa1c2016-02-17 17:37:22 +0000174 static boolean fixInitiatingUserIfNecessary(Context context, Intent intent) {
Tony Mak22214052016-01-19 18:50:44 +0000175 final UserHandle initiatingUser = intent.getParcelableExtra(KEY_INITIATING_USER);
176 if (UserUtil.isManagedProfile(context, initiatingUser)) {
177 boolean noDialerInstalled = DefaultDialerManager.getInstalledDialerApplications(context,
178 initiatingUser.getIdentifier()).size() == 0;
179 if (noDialerInstalled) {
180 final UserManager userManager = UserManager.get(context);
181 UserHandle parentUserHandle =
182 userManager.getProfileParent(
183 initiatingUser.getIdentifier()).getUserHandle();
184 intent.putExtra(KEY_INITIATING_USER, parentUserHandle);
Tony Makd7aaa1c2016-02-17 17:37:22 +0000185 return true;
Tony Mak22214052016-01-19 18:50:44 +0000186 }
187 }
Tony Makd7aaa1c2016-02-17 17:37:22 +0000188 return false;
Tony Mak22214052016-01-19 18:50:44 +0000189 }
190
Ihab Awad78a5e6b2015-02-06 10:13:05 -0800191 static void processIncomingCallIntent(CallsManager callsManager, Intent intent) {
Yorke Lee6dc1c752014-09-23 18:50:35 -0700192 PhoneAccountHandle phoneAccountHandle = intent.getParcelableExtra(
193 TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE);
194
195 if (phoneAccountHandle == null) {
Ihab Awad78a5e6b2015-02-06 10:13:05 -0800196 Log.w(CallIntentProcessor.class,
197 "Rejecting incoming call due to null phone account");
Yorke Lee6dc1c752014-09-23 18:50:35 -0700198 return;
199 }
200 if (phoneAccountHandle.getComponentName() == null) {
Ihab Awad78a5e6b2015-02-06 10:13:05 -0800201 Log.w(CallIntentProcessor.class,
202 "Rejecting incoming call due to null component name");
Yorke Lee6dc1c752014-09-23 18:50:35 -0700203 return;
204 }
205
206 Bundle clientExtras = null;
207 if (intent.hasExtra(TelecomManager.EXTRA_INCOMING_CALL_EXTRAS)) {
208 clientExtras = intent.getBundleExtra(TelecomManager.EXTRA_INCOMING_CALL_EXTRAS);
209 }
210 if (clientExtras == null) {
Yorke Leea49ede12015-03-23 11:15:35 -0700211 clientExtras = new Bundle();
Yorke Lee6dc1c752014-09-23 18:50:35 -0700212 }
213
Ihab Awad78a5e6b2015-02-06 10:13:05 -0800214 Log.d(CallIntentProcessor.class,
215 "Processing incoming call from connection service [%s]",
Yorke Lee6dc1c752014-09-23 18:50:35 -0700216 phoneAccountHandle.getComponentName());
Ihab Awad78a5e6b2015-02-06 10:13:05 -0800217 callsManager.processIncomingCallIntent(phoneAccountHandle, clientExtras);
Yorke Lee6dc1c752014-09-23 18:50:35 -0700218 }
219
David Stevens07852742015-04-10 18:22:47 -0700220 static void processUnknownCallIntent(CallsManager callsManager, Intent intent) {
Yorke Lee9250e5f2014-10-01 13:39:09 -0700221 PhoneAccountHandle phoneAccountHandle = intent.getParcelableExtra(
222 TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE);
223
224 if (phoneAccountHandle == null) {
Ihab Awad78a5e6b2015-02-06 10:13:05 -0800225 Log.w(CallIntentProcessor.class, "Rejecting unknown call due to null phone account");
Yorke Lee9250e5f2014-10-01 13:39:09 -0700226 return;
227 }
228 if (phoneAccountHandle.getComponentName() == null) {
Ihab Awad78a5e6b2015-02-06 10:13:05 -0800229 Log.w(CallIntentProcessor.class, "Rejecting unknown call due to null component name");
Yorke Lee9250e5f2014-10-01 13:39:09 -0700230 return;
231 }
232
Ihab Awad78a5e6b2015-02-06 10:13:05 -0800233 callsManager.addNewUnknownCall(phoneAccountHandle, intent.getExtras());
Yorke Lee6dc1c752014-09-23 18:50:35 -0700234 }
235
Andrew Lee72d271c2014-10-03 11:58:06 -0700236 private static void disconnectCallAndShowErrorDialog(
237 Context context, Call call, int errorCode) {
Yorke Lee6dc1c752014-09-23 18:50:35 -0700238 call.disconnect();
239 final Intent errorIntent = new Intent(context, ErrorDialogActivity.class);
240 int errorMessageId = -1;
241 switch (errorCode) {
242 case DisconnectCause.INVALID_NUMBER:
243 case DisconnectCause.NO_PHONE_NUMBER_SUPPLIED:
244 errorMessageId = R.string.outgoing_call_error_no_phone_number_supplied;
245 break;
246 }
247 if (errorMessageId != -1) {
248 errorIntent.putExtra(ErrorDialogActivity.ERROR_MESSAGE_ID_EXTRA, errorMessageId);
Yorke Lee94c7ab22015-04-30 14:59:12 -0700249 errorIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
250 context.startActivityAsUser(errorIntent, UserHandle.CURRENT);
Yorke Lee6dc1c752014-09-23 18:50:35 -0700251 }
Yorke Lee6dc1c752014-09-23 18:50:35 -0700252 }
Yorke Lee6dc1c752014-09-23 18:50:35 -0700253}