Home | History | Annotate | Download | only in components
      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.DefaultDialerManager;
     26 import android.telecom.Log;
     27 import android.telecom.PhoneAccount;
     28 import android.telecom.TelecomManager;
     29 import android.telecom.VideoProfile;
     30 import android.telephony.PhoneNumberUtils;
     31 import android.text.TextUtils;
     32 
     33 import com.android.server.telecom.CallIntentProcessor;
     34 import com.android.server.telecom.R;
     35 import com.android.server.telecom.TelecomSystem;
     36 import com.android.server.telecom.TelephonyUtil;
     37 import com.android.server.telecom.UserUtil;
     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      * @param callingPackageName The package name of the calling app.
     73      * @param canCallNonEmergency {@code true} if the caller is permitted to call non-emergency
     74      *                            numbers.
     75      * @param isLocalInvocation {@code true} if the caller is within the system service (i.e. the
     76      *                            caller is {@link com.android.server.telecom.TelecomServiceImpl})
     77      *                            and we can skip the re-broadcast of the intent to Telecom.
     78      *                            When {@code false}, we need to re-broadcast the intent to Telcom
     79      *                            to trampoline it to the system service where the Telecom
     80      *                            service resides.
     81      */
     82     public void processIntent(Intent intent, String callingPackageName,
     83             boolean canCallNonEmergency, boolean isLocalInvocation) {
     84         // Ensure call intents are not processed on devices that are not capable of calling.
     85         if (!isVoiceCapable()) {
     86             return;
     87         }
     88 
     89         String action = intent.getAction();
     90 
     91         if (Intent.ACTION_CALL.equals(action) ||
     92                 Intent.ACTION_CALL_PRIVILEGED.equals(action) ||
     93                 Intent.ACTION_CALL_EMERGENCY.equals(action)) {
     94             processOutgoingCallIntent(intent, callingPackageName, canCallNonEmergency,
     95                     isLocalInvocation);
     96         }
     97     }
     98 
     99     private void processOutgoingCallIntent(Intent intent, String callingPackageName,
    100             boolean canCallNonEmergency, boolean isLocalInvocation) {
    101         Uri handle = intent.getData();
    102         String scheme = handle.getScheme();
    103         String uriString = handle.getSchemeSpecificPart();
    104 
    105         // Ensure sip URIs dialed using TEL scheme get converted to SIP scheme.
    106         if (PhoneAccount.SCHEME_TEL.equals(scheme) && PhoneNumberUtils.isUriNumber(uriString)) {
    107             handle = Uri.fromParts(PhoneAccount.SCHEME_SIP, uriString, null);
    108         }
    109 
    110         // Check DISALLOW_OUTGOING_CALLS restriction. Note: We are skipping this check in a managed
    111         // profile user because this check can always be bypassed by copying and pasting the phone
    112         // number into the personal dialer.
    113         if (!UserUtil.isManagedProfile(mContext, mUserHandle)) {
    114             // Only emergency calls are allowed for users with the DISALLOW_OUTGOING_CALLS
    115             // restriction.
    116             if (!TelephonyUtil.shouldProcessAsEmergency(mContext, handle)) {
    117                 final UserManager userManager = (UserManager) mContext.getSystemService(
    118                         Context.USER_SERVICE);
    119                 if (userManager.hasBaseUserRestriction(UserManager.DISALLOW_OUTGOING_CALLS,
    120                         mUserHandle)) {
    121                     showErrorDialogForRestrictedOutgoingCall(mContext,
    122                             R.string.outgoing_call_not_allowed_user_restriction);
    123                     Log.w(this, "Rejecting non-emergency phone call due to DISALLOW_OUTGOING_CALLS "
    124                             + "restriction");
    125                     return;
    126                 } else if (userManager.hasUserRestriction(UserManager.DISALLOW_OUTGOING_CALLS,
    127                         mUserHandle)) {
    128                     final DevicePolicyManager dpm =
    129                             mContext.getSystemService(DevicePolicyManager.class);
    130                     if (dpm == null) {
    131                         return;
    132                     }
    133                     final Intent adminSupportIntent = dpm.createAdminSupportIntent(
    134                             UserManager.DISALLOW_OUTGOING_CALLS);
    135                     if (adminSupportIntent != null) {
    136                         mContext.startActivity(adminSupportIntent);
    137                     }
    138                     return;
    139                 }
    140             }
    141         }
    142 
    143         if (!canCallNonEmergency && !TelephonyUtil.shouldProcessAsEmergency(mContext, handle)) {
    144             showErrorDialogForRestrictedOutgoingCall(mContext,
    145                     R.string.outgoing_call_not_allowed_no_permission);
    146             Log.w(this, "Rejecting non-emergency phone call because "
    147                     + android.Manifest.permission.CALL_PHONE + " permission is not granted.");
    148             return;
    149         }
    150 
    151         int videoState = intent.getIntExtra(
    152                 TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE,
    153                 VideoProfile.STATE_AUDIO_ONLY);
    154         Log.d(this, "processOutgoingCallIntent videoState = " + videoState);
    155 
    156         intent.putExtra(CallIntentProcessor.KEY_IS_PRIVILEGED_DIALER,
    157                 isDefaultOrSystemDialer(callingPackageName));
    158 
    159         // Save the user handle of current user before forwarding the intent to primary user.
    160         intent.putExtra(CallIntentProcessor.KEY_INITIATING_USER, mUserHandle);
    161 
    162         sendIntentToDestination(intent, isLocalInvocation);
    163     }
    164 
    165     private boolean isDefaultOrSystemDialer(String callingPackageName) {
    166         if (TextUtils.isEmpty(callingPackageName)) {
    167             return false;
    168         }
    169 
    170         final String defaultDialer = DefaultDialerManager.getDefaultDialerApplication(mContext,
    171                 mUserHandle.getIdentifier());
    172         if (TextUtils.equals(defaultDialer, callingPackageName)) {
    173             return true;
    174         }
    175 
    176         final TelecomManager telecomManager =
    177                 (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);
    178         return TextUtils.equals(telecomManager.getSystemDialerPackage(), callingPackageName);
    179     }
    180 
    181     /**
    182      * Returns whether the device is voice-capable (e.g. a phone vs a tablet).
    183      *
    184      * @return {@code True} if the device is voice-capable.
    185      */
    186     private boolean isVoiceCapable() {
    187         return mContext.getApplicationContext().getResources().getBoolean(
    188                 com.android.internal.R.bool.config_voice_capable);
    189     }
    190 
    191     /**
    192      * Potentially trampolines the intent to the broadcast receiver that runs only as the primary
    193      * user.  If the caller is local to the Telecom service, we send the intent to Telecom without
    194      * rebroadcasting it.
    195      */
    196     private boolean sendIntentToDestination(Intent intent, boolean isLocalInvocation) {
    197         intent.putExtra(CallIntentProcessor.KEY_IS_INCOMING_CALL, false);
    198         intent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
    199         intent.setClass(mContext, PrimaryCallReceiver.class);
    200         if (isLocalInvocation) {
    201             // We are invoking this from TelecomServiceImpl, so TelecomSystem is available.  Don't
    202             // bother trampolining the intent, just sent it directly to the call intent processor.
    203             // TODO: We should not be using an intent here; this whole flows needs cleanup.
    204             Log.i(this, "sendIntentToDestination: send intent to Telecom directly.");
    205             synchronized (TelecomSystem.getInstance().getLock()) {
    206                 TelecomSystem.getInstance().getCallIntentProcessor().processIntent(intent);
    207             }
    208         } else {
    209             // We're calling from the UserCallActivity, so the TelecomSystem is not in the same
    210             // process; we need to trampoline to TelecomSystem in the system server process.
    211             Log.i(this, "sendIntentToDestination: trampoline to Telecom.");
    212             mContext.sendBroadcastAsUser(intent, UserHandle.SYSTEM);
    213         }
    214         return true;
    215     }
    216 
    217     private static void showErrorDialogForRestrictedOutgoingCall(Context context, int stringId) {
    218         final Intent intent = new Intent(context, ErrorDialogActivity.class);
    219         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    220         intent.putExtra(ErrorDialogActivity.ERROR_MESSAGE_ID_EXTRA, stringId);
    221         context.startActivityAsUser(intent, UserHandle.CURRENT);
    222     }
    223 }
    224