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