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 com.android.server.telecom.CallIntentProcessor; 20 import com.android.server.telecom.R; 21 import com.android.server.telecom.TelephonyUtil; 22 import com.android.server.telecom.UserUtil; 23 import com.android.settingslib.RestrictedLockUtils; 24 import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; 25 26 import android.app.AppOpsManager; 27 import android.content.Context; 28 import android.content.Intent; 29 import android.content.pm.PackageManager; 30 import android.net.Uri; 31 import android.os.UserHandle; 32 import android.os.UserManager; 33 import android.telecom.DefaultDialerManager; 34 import android.telecom.Log; 35 import android.telecom.PhoneAccount; 36 import android.telecom.TelecomManager; 37 import android.telecom.VideoProfile; 38 import android.telephony.PhoneNumberUtils; 39 import android.text.TextUtils; 40 import android.widget.Toast; 41 42 // TODO: Needed for move to system service: import com.android.internal.R; 43 44 /** 45 * Handles system CALL actions and forwards them to {@link CallIntentProcessor}. 46 * Handles all three CALL action types: CALL, CALL_PRIVILEGED, and CALL_EMERGENCY. 47 * 48 * Pre-L, the only way apps were were allowed to make outgoing emergency calls was the 49 * ACTION_CALL_PRIVILEGED action (which requires the system only CALL_PRIVILEGED permission). 50 * 51 * In L, any app that has the CALL_PRIVILEGED permission can continue to make outgoing emergency 52 * calls via ACTION_CALL_PRIVILEGED. 53 * 54 * In addition, the default dialer (identified via 55 * {@link android.telecom.TelecomManager#getDefaultDialerPackage()} will also be granted the 56 * ability to make emergency outgoing calls using the CALL action. In order to do this, it must 57 * use the {@link TelecomManager#placeCall(Uri, android.os.Bundle)} method to allow its package 58 * name to be passed to {@link UserCallIntentProcessor}. Calling startActivity will continue to 59 * work on all non-emergency numbers just like it did pre-L. 60 */ 61 public class UserCallIntentProcessor { 62 63 private final Context mContext; 64 private final UserHandle mUserHandle; 65 UserCallIntentProcessor(Context context, UserHandle userHandle)66 public UserCallIntentProcessor(Context context, UserHandle userHandle) { 67 mContext = context; 68 mUserHandle = userHandle; 69 } 70 71 /** 72 * Processes intents sent to the activity. 73 * 74 * @param intent The intent. 75 */ processIntent(Intent intent, String callingPackageName, boolean canCallNonEmergency)76 public void processIntent(Intent intent, String callingPackageName, 77 boolean canCallNonEmergency) { 78 // Ensure call intents are not processed on devices that are not capable of calling. 79 if (!isVoiceCapable()) { 80 return; 81 } 82 83 String action = intent.getAction(); 84 85 if (Intent.ACTION_CALL.equals(action) || 86 Intent.ACTION_CALL_PRIVILEGED.equals(action) || 87 Intent.ACTION_CALL_EMERGENCY.equals(action)) { 88 processOutgoingCallIntent(intent, callingPackageName, canCallNonEmergency); 89 } 90 } 91 processOutgoingCallIntent(Intent intent, String callingPackageName, boolean canCallNonEmergency)92 private void processOutgoingCallIntent(Intent intent, String callingPackageName, 93 boolean canCallNonEmergency) { 94 Uri handle = intent.getData(); 95 String scheme = handle.getScheme(); 96 String uriString = handle.getSchemeSpecificPart(); 97 98 if (!PhoneAccount.SCHEME_VOICEMAIL.equals(scheme)) { 99 handle = Uri.fromParts(PhoneNumberUtils.isUriNumber(uriString) ? 100 PhoneAccount.SCHEME_SIP : PhoneAccount.SCHEME_TEL, uriString, null); 101 } 102 103 // Check DISALLOW_OUTGOING_CALLS restriction. Note: We are skipping this check in a managed 104 // profile user because this check can always be bypassed by copying and pasting the phone 105 // number into the personal dialer. 106 if (!UserUtil.isManagedProfile(mContext, mUserHandle)) { 107 // Only emergency calls are allowed for users with the DISALLOW_OUTGOING_CALLS 108 // restriction. 109 if (!TelephonyUtil.shouldProcessAsEmergency(mContext, handle)) { 110 final UserManager userManager = (UserManager) mContext.getSystemService( 111 Context.USER_SERVICE); 112 if (userManager.hasBaseUserRestriction(UserManager.DISALLOW_OUTGOING_CALLS, 113 mUserHandle)) { 114 showErrorDialogForRestrictedOutgoingCall(mContext, 115 R.string.outgoing_call_not_allowed_user_restriction); 116 Log.w(this, "Rejecting non-emergency phone call due to DISALLOW_OUTGOING_CALLS " 117 + "restriction"); 118 return; 119 } else if (userManager.hasUserRestriction(UserManager.DISALLOW_OUTGOING_CALLS, 120 mUserHandle)) { 121 RestrictedLockUtils.sendShowAdminSupportDetailsIntent(mContext, 122 EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN); 123 return; 124 } 125 } 126 } 127 128 if (!canCallNonEmergency && !TelephonyUtil.shouldProcessAsEmergency(mContext, handle)) { 129 showErrorDialogForRestrictedOutgoingCall(mContext, 130 R.string.outgoing_call_not_allowed_no_permission); 131 Log.w(this, "Rejecting non-emergency phone call because " 132 + android.Manifest.permission.CALL_PHONE + " permission is not granted."); 133 return; 134 } 135 136 int videoState = intent.getIntExtra( 137 TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE, 138 VideoProfile.STATE_AUDIO_ONLY); 139 Log.d(this, "processOutgoingCallIntent videoState = " + videoState); 140 141 intent.putExtra(CallIntentProcessor.KEY_IS_PRIVILEGED_DIALER, 142 isDefaultOrSystemDialer(callingPackageName)); 143 144 // Save the user handle of current user before forwarding the intent to primary user. 145 intent.putExtra(CallIntentProcessor.KEY_INITIATING_USER, mUserHandle); 146 147 sendBroadcastToReceiver(intent); 148 } 149 isDefaultOrSystemDialer(String callingPackageName)150 private boolean isDefaultOrSystemDialer(String callingPackageName) { 151 if (TextUtils.isEmpty(callingPackageName)) { 152 return false; 153 } 154 155 final String defaultDialer = DefaultDialerManager.getDefaultDialerApplication(mContext, 156 mUserHandle.getIdentifier()); 157 if (TextUtils.equals(defaultDialer, callingPackageName)) { 158 return true; 159 } 160 161 final TelecomManager telecomManager = 162 (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE); 163 return TextUtils.equals(telecomManager.getSystemDialerPackage(), callingPackageName); 164 } 165 166 /** 167 * Returns whether the device is voice-capable (e.g. a phone vs a tablet). 168 * 169 * @return {@code True} if the device is voice-capable. 170 */ isVoiceCapable()171 private boolean isVoiceCapable() { 172 return mContext.getApplicationContext().getResources().getBoolean( 173 com.android.internal.R.bool.config_voice_capable); 174 } 175 176 /** 177 * Trampolines the intent to the broadcast receiver that runs only as the primary user. 178 */ sendBroadcastToReceiver(Intent intent)179 private boolean sendBroadcastToReceiver(Intent intent) { 180 intent.putExtra(CallIntentProcessor.KEY_IS_INCOMING_CALL, false); 181 intent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND); 182 intent.setClass(mContext, PrimaryCallReceiver.class); 183 Log.d(this, "Sending broadcast as user to CallReceiver"); 184 mContext.sendBroadcastAsUser(intent, UserHandle.SYSTEM); 185 return true; 186 } 187 showErrorDialogForRestrictedOutgoingCall(Context context, int stringId)188 private static void showErrorDialogForRestrictedOutgoingCall(Context context, int stringId) { 189 final Intent intent = new Intent(context, ErrorDialogActivity.class); 190 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 191 intent.putExtra(ErrorDialogActivity.ERROR_MESSAGE_ID_EXTRA, stringId); 192 context.startActivityAsUser(intent, UserHandle.CURRENT); 193 } 194 } 195