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 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