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 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 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 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 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 97 public static boolean handleMmi(Context context, String dialString, 98 @Nullable PhoneAccountHandle handle) { 99 if (hasModifyPhoneStatePermission(context)) { 100 try { 101 if (handle == null) { 102 return getTelecomManager(context).handleMmi(dialString); 103 } else { 104 return getTelecomManager(context).handleMmi(dialString, handle); 105 } 106 } catch (SecurityException e) { 107 Log.w(TAG, "TelecomManager.handleMmi called without permission."); 108 } 109 } 110 return false; 111 } 112 113 @Nullable 114 public static PhoneAccountHandle getDefaultOutgoingPhoneAccount(Context context, 115 String uriScheme) { 116 if (hasReadPhoneStatePermission(context)) { 117 return TelecomManagerCompat.getDefaultOutgoingPhoneAccount( 118 getTelecomManager(context), uriScheme); 119 } 120 return null; 121 } 122 123 public static PhoneAccount getPhoneAccount(Context context, PhoneAccountHandle handle) { 124 return TelecomManagerCompat.getPhoneAccount(getTelecomManager(context), handle); 125 } 126 127 public static List<PhoneAccountHandle> getCallCapablePhoneAccounts(Context context) { 128 if (hasReadPhoneStatePermission(context)) { 129 return TelecomManagerCompat.getCallCapablePhoneAccounts(getTelecomManager(context)); 130 } 131 return new ArrayList<>(); 132 } 133 134 public static boolean isInCall(Context context) { 135 if (hasReadPhoneStatePermission(context)) { 136 return getTelecomManager(context).isInCall(); 137 } 138 return false; 139 } 140 141 public static boolean isVoicemailNumber(Context context, PhoneAccountHandle accountHandle, 142 String number) { 143 if (hasReadPhoneStatePermission(context)) { 144 return TelecomManagerCompat.isVoiceMailNumber(getTelecomManager(context), 145 accountHandle, number); 146 } 147 return false; 148 } 149 150 @Nullable 151 public static String getVoicemailNumber(Context context, PhoneAccountHandle accountHandle) { 152 if (hasReadPhoneStatePermission(context)) { 153 return TelecomManagerCompat.getVoiceMailNumber(getTelecomManager(context), 154 getTelephonyManager(context), accountHandle); 155 } 156 return null; 157 } 158 159 /** 160 * Tries to place a call using the {@link TelecomManager}. 161 * 162 * @param activity a valid activity. 163 * @param intent the call intent. 164 * 165 * @return {@code true} if we successfully attempted to place the call, {@code false} if it 166 * failed due to a permission check. 167 */ 168 public static boolean placeCall(Activity activity, Intent intent) { 169 if (hasCallPhonePermission(activity)) { 170 TelecomManagerCompat.placeCall(activity, getTelecomManager(activity), intent); 171 return true; 172 } 173 return false; 174 } 175 176 public static Uri getCallLogUri(Context context) { 177 return hasReadWriteVoicemailPermissions(context) ? Calls.CONTENT_URI_WITH_VOICEMAIL 178 : Calls.CONTENT_URI; 179 } 180 181 public static boolean hasReadWriteVoicemailPermissions(Context context) { 182 return isDefaultDialer(context) 183 || (hasPermission(context, Manifest.permission.READ_VOICEMAIL) 184 && hasPermission(context, Manifest.permission.WRITE_VOICEMAIL)); 185 } 186 187 public static boolean hasModifyPhoneStatePermission(Context context) { 188 return isDefaultDialer(context) 189 || hasPermission(context, Manifest.permission.MODIFY_PHONE_STATE); 190 } 191 192 public static boolean hasReadPhoneStatePermission(Context context) { 193 return isDefaultDialer(context) 194 || hasPermission(context, Manifest.permission.READ_PHONE_STATE); 195 } 196 197 public static boolean hasCallPhonePermission(Context context) { 198 return isDefaultDialer(context) 199 || hasPermission(context, Manifest.permission.CALL_PHONE); 200 } 201 202 private static boolean hasPermission(Context context, String permission) { 203 return ContextCompat.checkSelfPermission(context, permission) 204 == PackageManager.PERMISSION_GRANTED; 205 } 206 207 public static boolean isDefaultDialer(Context context) { 208 final boolean result = TextUtils.equals(context.getPackageName(), 209 TelecomManagerCompat.getDefaultDialerPackage(getTelecomManager(context))); 210 if (result) { 211 sWarningLogged = false; 212 } else { 213 if (!sWarningLogged) { 214 // Log only once to prevent spam. 215 Log.w(TAG, "Dialer is not currently set to be default dialer"); 216 sWarningLogged = true; 217 } 218 } 219 return result; 220 } 221 222 private static TelecomManager getTelecomManager(Context context) { 223 return (TelecomManager) context.getSystemService(Context.TELECOM_SERVICE); 224 } 225 226 private static TelephonyManager getTelephonyManager(Context context) { 227 return (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); 228 } 229 } 230