1 /* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.telecom.components; 18 19 import android.app.admin.DevicePolicyManager; 20 import android.content.Context; 21 import android.content.Intent; 22 import android.net.Uri; 23 import android.os.UserHandle; 24 import android.os.UserManager; 25 import android.telecom.Log; 26 import android.telecom.PhoneAccount; 27 import android.telecom.TelecomManager; 28 import android.telecom.VideoProfile; 29 import android.telephony.PhoneNumberUtils; 30 import android.telephony.TelephonyManager; 31 32 import com.android.server.telecom.CallIntentProcessor; 33 import com.android.server.telecom.R; 34 import com.android.server.telecom.TelecomSystem; 35 import com.android.server.telecom.TelephonyUtil; 36 import com.android.server.telecom.UserUtil; 37 38 // TODO: Needed for move to system service: import com.android.internal.R; 39 40 /** 41 * Handles system CALL actions and forwards them to {@link CallIntentProcessor}. 42 * Handles all three CALL action types: CALL, CALL_PRIVILEGED, and CALL_EMERGENCY. 43 * 44 * Pre-L, the only way apps were were allowed to make outgoing emergency calls was the 45 * ACTION_CALL_PRIVILEGED action (which requires the system only CALL_PRIVILEGED permission). 46 * 47 * In L, any app that has the CALL_PRIVILEGED permission can continue to make outgoing emergency 48 * calls via ACTION_CALL_PRIVILEGED. 49 * 50 * In addition, the default dialer (identified via 51 * {@link android.telecom.TelecomManager#getDefaultDialerPackage()} will also be granted the 52 * ability to make emergency outgoing calls using the CALL action. In order to do this, it must 53 * use the {@link TelecomManager#placeCall(Uri, android.os.Bundle)} method to allow its package 54 * name to be passed to {@link UserCallIntentProcessor}. Calling startActivity will continue to 55 * work on all non-emergency numbers just like it did pre-L. 56 */ 57 public class UserCallIntentProcessor { 58 59 private final Context mContext; 60 private final UserHandle mUserHandle; 61 62 public UserCallIntentProcessor(Context context, UserHandle userHandle) { 63 mContext = context; 64 mUserHandle = userHandle; 65 } 66 67 /** 68 * Processes intents sent to the activity. 69 * 70 * @param intent The intent. 71 * @param callingPackageName The package name of the calling app. 72 * @param canCallNonEmergency {@code true} if the caller is permitted to call non-emergency 73 * numbers. 74 * @param isLocalInvocation {@code true} if the caller is within the system service (i.e. the 75 * caller is {@link com.android.server.telecom.TelecomServiceImpl}) 76 * and we can skip the re-broadcast of the intent to Telecom. 77 * When {@code false}, we need to re-broadcast the intent to Telcom 78 * to trampoline it to the system service where the Telecom 79 * service resides. 80 */ 81 public void processIntent(Intent intent, String callingPackageName, 82 boolean canCallNonEmergency, boolean isLocalInvocation) { 83 // Ensure call intents are not processed on devices that are not capable of calling. 84 if (!isVoiceCapable()) { 85 return; 86 } 87 88 String action = intent.getAction(); 89 90 if (Intent.ACTION_CALL.equals(action) || 91 Intent.ACTION_CALL_PRIVILEGED.equals(action) || 92 Intent.ACTION_CALL_EMERGENCY.equals(action)) { 93 processOutgoingCallIntent(intent, callingPackageName, canCallNonEmergency, 94 isLocalInvocation); 95 } 96 } 97 98 private void processOutgoingCallIntent(Intent intent, String callingPackageName, 99 boolean canCallNonEmergency, boolean isLocalInvocation) { 100 Uri handle = intent.getData(); 101 String scheme = handle.getScheme(); 102 String uriString = handle.getSchemeSpecificPart(); 103 104 // Ensure sip URIs dialed using TEL scheme get converted to SIP scheme. 105 if (PhoneAccount.SCHEME_TEL.equals(scheme) && PhoneNumberUtils.isUriNumber(uriString)) { 106 handle = Uri.fromParts(PhoneAccount.SCHEME_SIP, uriString, null); 107 } 108 109 // Check DISALLOW_OUTGOING_CALLS restriction. Note: We are skipping this check in a managed 110 // profile user because this check can always be bypassed by copying and pasting the phone 111 // number into the personal dialer. 112 if (!UserUtil.isManagedProfile(mContext, mUserHandle)) { 113 // Only emergency calls are allowed for users with the DISALLOW_OUTGOING_CALLS 114 // restriction. 115 if (!TelephonyUtil.shouldProcessAsEmergency(mContext, handle)) { 116 final UserManager userManager = (UserManager) mContext.getSystemService( 117 Context.USER_SERVICE); 118 if (userManager.hasBaseUserRestriction(UserManager.DISALLOW_OUTGOING_CALLS, 119 mUserHandle)) { 120 showErrorDialogForRestrictedOutgoingCall(mContext, 121 R.string.outgoing_call_not_allowed_user_restriction); 122 Log.w(this, "Rejecting non-emergency phone call due to DISALLOW_OUTGOING_CALLS " 123 + "restriction"); 124 return; 125 } else if (userManager.hasUserRestriction(UserManager.DISALLOW_OUTGOING_CALLS, 126 mUserHandle)) { 127 final DevicePolicyManager dpm = 128 mContext.getSystemService(DevicePolicyManager.class); 129 if (dpm == null) { 130 return; 131 } 132 final Intent adminSupportIntent = dpm.createAdminSupportIntent( 133 UserManager.DISALLOW_OUTGOING_CALLS); 134 if (adminSupportIntent != null) { 135 mContext.startActivity(adminSupportIntent); 136 } 137 return; 138 } 139 } 140 } 141 142 if (!canCallNonEmergency && !TelephonyUtil.shouldProcessAsEmergency(mContext, handle)) { 143 showErrorDialogForRestrictedOutgoingCall(mContext, 144 R.string.outgoing_call_not_allowed_no_permission); 145 Log.w(this, "Rejecting non-emergency phone call because " 146 + android.Manifest.permission.CALL_PHONE + " permission is not granted."); 147 return; 148 } 149 150 int videoState = intent.getIntExtra( 151 TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE, 152 VideoProfile.STATE_AUDIO_ONLY); 153 Log.d(this, "processOutgoingCallIntent videoState = " + videoState); 154 155 // Save the user handle of current user before forwarding the intent to primary user. 156 intent.putExtra(CallIntentProcessor.KEY_INITIATING_USER, mUserHandle); 157 158 sendIntentToDestination(intent, isLocalInvocation, callingPackageName); 159 } 160 161 /** 162 * Returns whether the device is voice-capable (e.g. a phone vs a tablet). 163 * 164 * @return {@code True} if the device is voice-capable. 165 */ 166 private boolean isVoiceCapable() { 167 return ((TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE)) 168 .isVoiceCapable(); 169 } 170 171 /** 172 * Potentially trampolines the intent to Telecom via TelecomServiceImpl. 173 * If the caller is local to the Telecom service, we send the intent to Telecom without 174 * sending it through TelecomServiceImpl. 175 */ 176 private boolean sendIntentToDestination(Intent intent, boolean isLocalInvocation, 177 String callingPackage) { 178 intent.putExtra(CallIntentProcessor.KEY_IS_INCOMING_CALL, false); 179 intent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND); 180 if (isLocalInvocation) { 181 // We are invoking this from TelecomServiceImpl, so TelecomSystem is available. Don't 182 // bother trampolining the intent, just sent it directly to the call intent processor. 183 // TODO: We should not be using an intent here; this whole flows needs cleanup. 184 Log.i(this, "sendIntentToDestination: send intent to Telecom directly."); 185 synchronized (TelecomSystem.getInstance().getLock()) { 186 TelecomSystem.getInstance().getCallIntentProcessor().processIntent(intent, 187 callingPackage); 188 } 189 } else { 190 // We're calling from the UserCallActivity, so the TelecomSystem is not in the same 191 // process; we need to trampoline to TelecomSystem in the system server process. 192 Log.i(this, "sendIntentToDestination: trampoline to Telecom."); 193 TelecomManager tm = (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE); 194 tm.handleCallIntent(intent, callingPackage); 195 } 196 return true; 197 } 198 199 private static void showErrorDialogForRestrictedOutgoingCall(Context context, int stringId) { 200 final Intent intent = new Intent(context, ErrorDialogActivity.class); 201 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 202 intent.putExtra(ErrorDialogActivity.ERROR_MESSAGE_ID_EXTRA, stringId); 203 context.startActivityAsUser(intent, UserHandle.CURRENT); 204 } 205 } 206