1 /* 2 * Copyright (C) 2015 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.dialer.util; 18 19 import android.Manifest; 20 import android.app.Activity; 21 import android.content.Context; 22 import android.content.Intent; 23 import android.content.pm.PackageManager; 24 import android.net.Uri; 25 import android.provider.CallLog.Calls; 26 import android.support.annotation.Nullable; 27 import android.support.v4.content.ContextCompat; 28 import android.telecom.PhoneAccount; 29 import android.telecom.PhoneAccountHandle; 30 import android.telecom.TelecomManager; 31 import android.telephony.PhoneNumberUtils; 32 import android.telephony.TelephonyManager; 33 import android.text.TextUtils; 34 import android.util.Log; 35 36 import com.android.contacts.common.compat.CompatUtils; 37 import com.android.contacts.common.compat.telecom.TelecomManagerCompat; 38 import com.android.dialer.compat.DialerCompatUtils; 39 40 import java.util.ArrayList; 41 import java.util.List; 42 43 /** 44 * Performs permission checks before calling into TelecomManager. Each method is self-explanatory - 45 * perform the required check and return the fallback default if the permission is missing, 46 * otherwise return the value from TelecomManager. 47 * 48 */ 49 public class TelecomUtil { 50 private static final String TAG = "TelecomUtil"; 51 private static boolean sWarningLogged = false; 52 showInCallScreen(Context context, boolean showDialpad)53 public static void showInCallScreen(Context context, boolean showDialpad) { 54 if (hasReadPhoneStatePermission(context)) { 55 try { 56 getTelecomManager(context).showInCallScreen(showDialpad); 57 } catch (SecurityException e) { 58 // Just in case 59 Log.w(TAG, "TelecomManager.showInCallScreen called without permission."); 60 } 61 } 62 } 63 silenceRinger(Context context)64 public static void silenceRinger(Context context) { 65 if (hasModifyPhoneStatePermission(context)) { 66 try { 67 TelecomManagerCompat.silenceRinger(getTelecomManager(context)); 68 } catch (SecurityException e) { 69 // Just in case 70 Log.w(TAG, "TelecomManager.silenceRinger called without permission."); 71 } 72 } 73 } 74 cancelMissedCallsNotification(Context context)75 public static void cancelMissedCallsNotification(Context context) { 76 if (hasModifyPhoneStatePermission(context)) { 77 try { 78 getTelecomManager(context).cancelMissedCallsNotification(); 79 } catch (SecurityException e) { 80 Log.w(TAG, "TelecomManager.cancelMissedCalls called without permission."); 81 } 82 } 83 } 84 getAdnUriForPhoneAccount(Context context, PhoneAccountHandle handle)85 public static Uri getAdnUriForPhoneAccount(Context context, PhoneAccountHandle handle) { 86 if (hasModifyPhoneStatePermission(context)) { 87 try { 88 return TelecomManagerCompat.getAdnUriForPhoneAccount( 89 getTelecomManager(context), handle); 90 } catch (SecurityException e) { 91 Log.w(TAG, "TelecomManager.getAdnUriForPhoneAccount called without permission."); 92 } 93 } 94 return null; 95 } 96 handleMmi(Context context, String dialString, PhoneAccountHandle handle)97 public static boolean handleMmi(Context context, String dialString, 98 PhoneAccountHandle handle) { 99 if (hasModifyPhoneStatePermission(context)) { 100 try { 101 return TelecomManagerCompat.handleMmi( 102 getTelecomManager(context), dialString, handle); 103 } catch (SecurityException e) { 104 Log.w(TAG, "TelecomManager.handleMmi called without permission."); 105 } 106 } 107 return false; 108 } 109 110 @Nullable getDefaultOutgoingPhoneAccount(Context context, String uriScheme)111 public static PhoneAccountHandle getDefaultOutgoingPhoneAccount(Context context, 112 String uriScheme) { 113 if (hasReadPhoneStatePermission(context)) { 114 return TelecomManagerCompat.getDefaultOutgoingPhoneAccount( 115 getTelecomManager(context), uriScheme); 116 } 117 return null; 118 } 119 getPhoneAccount(Context context, PhoneAccountHandle handle)120 public static PhoneAccount getPhoneAccount(Context context, PhoneAccountHandle handle) { 121 return TelecomManagerCompat.getPhoneAccount(getTelecomManager(context), handle); 122 } 123 getCallCapablePhoneAccounts(Context context)124 public static List<PhoneAccountHandle> getCallCapablePhoneAccounts(Context context) { 125 if (hasReadPhoneStatePermission(context)) { 126 return TelecomManagerCompat.getCallCapablePhoneAccounts(getTelecomManager(context)); 127 } 128 return new ArrayList<>(); 129 } 130 isInCall(Context context)131 public static boolean isInCall(Context context) { 132 if (hasReadPhoneStatePermission(context)) { 133 return getTelecomManager(context).isInCall(); 134 } 135 return false; 136 } 137 isVoicemailNumber(Context context, PhoneAccountHandle accountHandle, String number)138 public static boolean isVoicemailNumber(Context context, PhoneAccountHandle accountHandle, 139 String number) { 140 if (hasReadPhoneStatePermission(context)) { 141 return TelecomManagerCompat.isVoiceMailNumber(getTelecomManager(context), 142 accountHandle, number); 143 } 144 return false; 145 } 146 147 @Nullable getVoicemailNumber(Context context, PhoneAccountHandle accountHandle)148 public static String getVoicemailNumber(Context context, PhoneAccountHandle accountHandle) { 149 if (hasReadPhoneStatePermission(context)) { 150 return TelecomManagerCompat.getVoiceMailNumber(getTelecomManager(context), 151 getTelephonyManager(context), accountHandle); 152 } 153 return null; 154 } 155 156 /** 157 * Tries to place a call using the {@link TelecomManager}. 158 * 159 * @param activity a valid activity. 160 * @param intent the call intent. 161 * 162 * @return {@code true} if we successfully attempted to place the call, {@code false} if it 163 * failed due to a permission check. 164 */ placeCall(Activity activity, Intent intent)165 public static boolean placeCall(Activity activity, Intent intent) { 166 if (hasCallPhonePermission(activity)) { 167 TelecomManagerCompat.placeCall(activity, getTelecomManager(activity), intent); 168 return true; 169 } 170 return false; 171 } 172 getCallLogUri(Context context)173 public static Uri getCallLogUri(Context context) { 174 return hasReadWriteVoicemailPermissions(context) ? Calls.CONTENT_URI_WITH_VOICEMAIL 175 : Calls.CONTENT_URI; 176 } 177 hasReadWriteVoicemailPermissions(Context context)178 public static boolean hasReadWriteVoicemailPermissions(Context context) { 179 return isDefaultDialer(context) 180 || (hasPermission(context, Manifest.permission.READ_VOICEMAIL) 181 && hasPermission(context, Manifest.permission.WRITE_VOICEMAIL)); 182 } 183 hasModifyPhoneStatePermission(Context context)184 public static boolean hasModifyPhoneStatePermission(Context context) { 185 return isDefaultDialer(context) 186 || hasPermission(context, Manifest.permission.MODIFY_PHONE_STATE); 187 } 188 hasReadPhoneStatePermission(Context context)189 public static boolean hasReadPhoneStatePermission(Context context) { 190 return isDefaultDialer(context) 191 || hasPermission(context, Manifest.permission.READ_PHONE_STATE); 192 } 193 hasCallPhonePermission(Context context)194 public static boolean hasCallPhonePermission(Context context) { 195 return isDefaultDialer(context) 196 || hasPermission(context, Manifest.permission.CALL_PHONE); 197 } 198 hasPermission(Context context, String permission)199 private static boolean hasPermission(Context context, String permission) { 200 return ContextCompat.checkSelfPermission(context, permission) 201 == PackageManager.PERMISSION_GRANTED; 202 } 203 isDefaultDialer(Context context)204 public static boolean isDefaultDialer(Context context) { 205 final boolean result = TextUtils.equals(context.getPackageName(), 206 TelecomManagerCompat.getDefaultDialerPackage(getTelecomManager(context))); 207 if (result) { 208 sWarningLogged = false; 209 } else { 210 if (!sWarningLogged) { 211 // Log only once to prevent spam. 212 Log.w(TAG, "Dialer is not currently set to be default dialer"); 213 sWarningLogged = true; 214 } 215 } 216 return result; 217 } 218 getTelecomManager(Context context)219 private static TelecomManager getTelecomManager(Context context) { 220 return (TelecomManager) context.getSystemService(Context.TELECOM_SERVICE); 221 } 222 getTelephonyManager(Context context)223 private static TelephonyManager getTelephonyManager(Context context) { 224 return (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); 225 } 226 } 227