Chiao Cheng | cb5b270 | 2012-09-05 16:10:50 -0700 | [diff] [blame] | 1 | /* |
Brian Attwell | 066bd68 | 2015-02-03 17:10:19 -0800 | [diff] [blame] | 2 | * Copyright (C) 2015 The Android Open Source Project |
Chiao Cheng | cb5b270 | 2012-09-05 16:10:50 -0700 | [diff] [blame] | 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 | |
Gary Mai | 0a49afa | 2016-12-05 15:53:58 -0800 | [diff] [blame] | 17 | package com.android.contacts; |
Brian Attwell | 066bd68 | 2015-02-03 17:10:19 -0800 | [diff] [blame] | 18 | |
Andrew Lee | 7e558dc | 2014-08-20 16:02:11 -0700 | [diff] [blame] | 19 | import android.content.Context; |
Chiao Cheng | cb5b270 | 2012-09-05 16:10:50 -0700 | [diff] [blame] | 20 | import android.content.Intent; |
| 21 | import android.net.Uri; |
Gary Mai | 8e6856b | 2017-06-12 15:19:31 -0700 | [diff] [blame] | 22 | import android.os.Bundle; |
| 23 | import android.os.PersistableBundle; |
Tyler Gunn | 5cf7f01 | 2014-09-10 15:20:21 -0700 | [diff] [blame] | 24 | import android.telecom.PhoneAccount; |
Vinit Deshpande | ca6b31e | 2015-03-15 13:23:01 -0700 | [diff] [blame] | 25 | import android.telecom.PhoneAccountHandle; |
Tyler Gunn | 5cf7f01 | 2014-09-10 15:20:21 -0700 | [diff] [blame] | 26 | import android.telecom.TelecomManager; |
| 27 | import android.telecom.VideoProfile; |
Gary Mai | 8e6856b | 2017-06-12 15:19:31 -0700 | [diff] [blame] | 28 | import android.telephony.CarrierConfigManager; |
yaolu | 18417a4 | 2017-05-04 12:33:47 -0700 | [diff] [blame] | 29 | import android.telephony.PhoneNumberUtils; |
Brian Attwell | 066bd68 | 2015-02-03 17:10:19 -0800 | [diff] [blame] | 30 | import android.text.TextUtils; |
Gary Mai | 8e6856b | 2017-06-12 15:19:31 -0700 | [diff] [blame] | 31 | import android.util.Log; |
Chiao Cheng | cb5b270 | 2012-09-05 16:10:50 -0700 | [diff] [blame] | 32 | |
Gary Mai | 0a49afa | 2016-12-05 15:53:58 -0800 | [diff] [blame] | 33 | import com.android.contacts.compat.CompatUtils; |
| 34 | import com.android.contacts.compat.PhoneAccountSdkCompat; |
| 35 | import com.android.contacts.util.PermissionsUtil; |
| 36 | import com.android.contacts.util.PhoneNumberHelper; |
| 37 | import com.android.contactsbind.FeedbackHelper; |
Gary Mai | 8e6856b | 2017-06-12 15:19:31 -0700 | [diff] [blame] | 38 | import com.android.contactsbind.experiments.Flags; |
Gary Mai | 0a49afa | 2016-12-05 15:53:58 -0800 | [diff] [blame] | 39 | import com.android.phone.common.PhoneConstants; |
| 40 | |
Yorke Lee | 9028db0 | 2015-03-19 17:01:54 +0000 | [diff] [blame] | 41 | import java.util.List; |
| 42 | |
Chiao Cheng | cb5b270 | 2012-09-05 16:10:50 -0700 | [diff] [blame] | 43 | /** |
Brian Attwell | 066bd68 | 2015-02-03 17:10:19 -0800 | [diff] [blame] | 44 | * Utilities related to calls that can be used by non system apps. These |
| 45 | * use {@link Intent#ACTION_CALL} instead of ACTION_CALL_PRIVILEGED. |
| 46 | * |
| 47 | * The privileged version of this util exists inside Dialer. |
Chiao Cheng | cb5b270 | 2012-09-05 16:10:50 -0700 | [diff] [blame] | 48 | */ |
| 49 | public class CallUtil { |
| 50 | |
Wenyi Wang | 7a27b85 | 2016-11-11 11:36:24 -0800 | [diff] [blame] | 51 | public static final String TAG = "CallUtil"; |
| 52 | |
Chiao Cheng | cb5b270 | 2012-09-05 16:10:50 -0700 | [diff] [blame] | 53 | /** |
Tyler Gunn | 001d974 | 2015-12-18 13:57:02 -0800 | [diff] [blame] | 54 | * Indicates that the video calling is not available. |
| 55 | */ |
| 56 | public static final int VIDEO_CALLING_DISABLED = 0; |
| 57 | |
| 58 | /** |
| 59 | * Indicates that video calling is enabled, regardless of presence status. |
| 60 | */ |
| 61 | public static final int VIDEO_CALLING_ENABLED = 1; |
| 62 | |
| 63 | /** |
| 64 | * Indicates that video calling is enabled, but the availability of video call affordances is |
| 65 | * determined by the presence status associated with contacts. |
| 66 | */ |
| 67 | public static final int VIDEO_CALLING_PRESENCE = 2; |
| 68 | |
Gary Mai | 8e6856b | 2017-06-12 15:19:31 -0700 | [diff] [blame] | 69 | /** {@link PhoneAccount#EXTRA_SUPPORTS_VIDEO_CALLING_FALLBACK} */ |
| 70 | private static final String EXTRA_SUPPORTS_VIDEO_CALLING_FALLBACK = |
| 71 | "android.telecom.extra.SUPPORTS_VIDEO_CALLING_FALLBACK"; |
| 72 | |
| 73 | /** {@link CarrierConfigManager#CONFIG_ALLOW_VIDEO_CALLING_FALLBACK} */ |
| 74 | private static final String CONFIG_ALLOW_VIDEO_CALLING_FALLBACK = |
| 75 | "allow_video_calling_fallback_bool"; |
| 76 | |
Tyler Gunn | 001d974 | 2015-12-18 13:57:02 -0800 | [diff] [blame] | 77 | /** |
Chiao Cheng | cb5b270 | 2012-09-05 16:10:50 -0700 | [diff] [blame] | 78 | * Return an Intent for making a phone call. Scheme (e.g. tel, sip) will be determined |
| 79 | * automatically. |
| 80 | */ |
Tyler Gunn | 9e0c14e | 2015-08-04 13:33:49 -0700 | [diff] [blame] | 81 | public static Intent getCallWithSubjectIntent(String number, |
| 82 | PhoneAccountHandle phoneAccountHandle, String callSubject) { |
| 83 | |
| 84 | final Intent intent = getCallIntent(getCallUri(number)); |
| 85 | intent.putExtra(TelecomManager.EXTRA_CALL_SUBJECT, callSubject); |
| 86 | if (phoneAccountHandle != null) { |
| 87 | intent.putExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, phoneAccountHandle); |
| 88 | } |
| 89 | return intent; |
| 90 | } |
| 91 | |
| 92 | /** |
| 93 | * Return an Intent for making a phone call. Scheme (e.g. tel, sip) will be determined |
| 94 | * automatically. |
| 95 | */ |
Chiao Cheng | cb5b270 | 2012-09-05 16:10:50 -0700 | [diff] [blame] | 96 | public static Intent getCallIntent(String number) { |
yaolu | 18417a4 | 2017-05-04 12:33:47 -0700 | [diff] [blame] | 97 | Uri uri = getCallUri(number); |
| 98 | return PhoneNumberUtils.isEmergencyNumber(number) |
| 99 | ? getCallIntentForEmergencyNumber(uri) : getCallIntent(uri); |
| 100 | } |
| 101 | |
| 102 | /** |
| 103 | * Return an Intent to directly start Dialer when calling an emergency number. Scheme is always |
| 104 | * PhoneAccount.SCHEME_TEL. |
| 105 | */ |
| 106 | private static Intent getCallIntentForEmergencyNumber(Uri uri) { |
| 107 | return new Intent(Intent.ACTION_DIAL, uri); |
Chiao Cheng | cb5b270 | 2012-09-05 16:10:50 -0700 | [diff] [blame] | 108 | } |
| 109 | |
| 110 | /** |
| 111 | * Return an Intent for making a phone call. A given Uri will be used as is (without any |
Raman Tenneti | 362f422 | 2020-07-28 16:54:20 -0700 | [diff] [blame^] | 112 | * quick check). |
Chiao Cheng | cb5b270 | 2012-09-05 16:10:50 -0700 | [diff] [blame] | 113 | */ |
| 114 | public static Intent getCallIntent(Uri uri) { |
Brian Attwell | 066bd68 | 2015-02-03 17:10:19 -0800 | [diff] [blame] | 115 | return new Intent(Intent.ACTION_CALL, uri); |
Chiao Cheng | cb5b270 | 2012-09-05 16:10:50 -0700 | [diff] [blame] | 116 | } |
| 117 | |
| 118 | /** |
Brian Attwell | 066bd68 | 2015-02-03 17:10:19 -0800 | [diff] [blame] | 119 | * A variant of {@link #getCallIntent} for starting a video call. |
Andrew Lee | c18a754 | 2014-07-08 16:02:30 -0700 | [diff] [blame] | 120 | */ |
Nancy Chen | c095aee | 2014-07-09 10:29:41 -0700 | [diff] [blame] | 121 | public static Intent getVideoCallIntent(String number, String callOrigin) { |
Brian Attwell | 066bd68 | 2015-02-03 17:10:19 -0800 | [diff] [blame] | 122 | final Intent intent = new Intent(Intent.ACTION_CALL, getCallUri(number)); |
| 123 | intent.putExtra(TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE, |
Yorke Lee | cb93d46 | 2015-05-12 16:23:06 -0700 | [diff] [blame] | 124 | VideoProfile.STATE_BIDIRECTIONAL); |
Brian Attwell | 066bd68 | 2015-02-03 17:10:19 -0800 | [diff] [blame] | 125 | if (!TextUtils.isEmpty(callOrigin)) { |
Chiao Cheng | cb5b270 | 2012-09-05 16:10:50 -0700 | [diff] [blame] | 126 | intent.putExtra(PhoneConstants.EXTRA_CALL_ORIGIN, callOrigin); |
| 127 | } |
| 128 | return intent; |
| 129 | } |
| 130 | |
| 131 | /** |
Jay Shrauner | ed1a3b2 | 2014-09-05 15:37:27 -0700 | [diff] [blame] | 132 | * Return Uri with an appropriate scheme, accepting both SIP and usual phone call |
Chiao Cheng | cb5b270 | 2012-09-05 16:10:50 -0700 | [diff] [blame] | 133 | * numbers. |
| 134 | */ |
| 135 | public static Uri getCallUri(String number) { |
Yorke Lee | 9e8e7cb | 2014-03-17 13:04:45 -0700 | [diff] [blame] | 136 | if (PhoneNumberHelper.isUriNumber(number)) { |
Jay Shrauner | ed1a3b2 | 2014-09-05 15:37:27 -0700 | [diff] [blame] | 137 | return Uri.fromParts(PhoneAccount.SCHEME_SIP, number, null); |
Chiao Cheng | cb5b270 | 2012-09-05 16:10:50 -0700 | [diff] [blame] | 138 | } |
Jay Shrauner | ed1a3b2 | 2014-09-05 15:37:27 -0700 | [diff] [blame] | 139 | return Uri.fromParts(PhoneAccount.SCHEME_TEL, number, null); |
Yorke Lee | 9028db0 | 2015-03-19 17:01:54 +0000 | [diff] [blame] | 140 | } |
Paul Soulos | 5604608 | 2014-08-18 16:12:40 -0700 | [diff] [blame] | 141 | |
Yorke Lee | 9028db0 | 2015-03-19 17:01:54 +0000 | [diff] [blame] | 142 | /** |
Tyler Gunn | 001d974 | 2015-12-18 13:57:02 -0800 | [diff] [blame] | 143 | * Determines if video calling is available, and if so whether presence checking is available |
| 144 | * as well. |
| 145 | * |
| 146 | * Returns a bitmask with {@link #VIDEO_CALLING_ENABLED} to indicate that video calling is |
| 147 | * available, and {@link #VIDEO_CALLING_PRESENCE} if presence indication is also available. |
| 148 | * |
| 149 | * @param context The context |
| 150 | * @return A bit-mask describing the current video capabilities. |
| 151 | */ |
| 152 | public static int getVideoCallingAvailability(Context context) { |
| 153 | if (!PermissionsUtil.hasPermission(context, android.Manifest.permission.READ_PHONE_STATE) |
| 154 | || !CompatUtils.isVideoCompatible()) { |
| 155 | return VIDEO_CALLING_DISABLED; |
| 156 | } |
| 157 | TelecomManager telecommMgr = (TelecomManager) |
| 158 | context.getSystemService(Context.TELECOM_SERVICE); |
| 159 | if (telecommMgr == null) { |
| 160 | return VIDEO_CALLING_DISABLED; |
| 161 | } |
| 162 | |
Wenyi Wang | 7a27b85 | 2016-11-11 11:36:24 -0800 | [diff] [blame] | 163 | try { |
| 164 | List<PhoneAccountHandle> accountHandles = telecommMgr.getCallCapablePhoneAccounts(); |
| 165 | for (PhoneAccountHandle accountHandle : accountHandles) { |
| 166 | PhoneAccount account = telecommMgr.getPhoneAccount(accountHandle); |
| 167 | if (account != null) { |
| 168 | if (account.hasCapabilities(PhoneAccount.CAPABILITY_VIDEO_CALLING)) { |
| 169 | // Builds prior to N do not have presence support. |
| 170 | if (!CompatUtils.isVideoPresenceCompatible()) { |
| 171 | return VIDEO_CALLING_ENABLED; |
| 172 | } |
Tyler Gunn | 001d974 | 2015-12-18 13:57:02 -0800 | [diff] [blame] | 173 | |
Wenyi Wang | 7a27b85 | 2016-11-11 11:36:24 -0800 | [diff] [blame] | 174 | int videoCapabilities = VIDEO_CALLING_ENABLED; |
| 175 | if (account.hasCapabilities(PhoneAccountSdkCompat |
| 176 | .CAPABILITY_VIDEO_CALLING_RELIES_ON_PRESENCE)) { |
| 177 | videoCapabilities |= VIDEO_CALLING_PRESENCE; |
| 178 | } |
| 179 | return videoCapabilities; |
Tyler Gunn | 001d974 | 2015-12-18 13:57:02 -0800 | [diff] [blame] | 180 | } |
Tyler Gunn | 001d974 | 2015-12-18 13:57:02 -0800 | [diff] [blame] | 181 | } |
| 182 | } |
Wenyi Wang | 7a27b85 | 2016-11-11 11:36:24 -0800 | [diff] [blame] | 183 | return VIDEO_CALLING_DISABLED; |
| 184 | } catch (SecurityException e) { |
| 185 | FeedbackHelper.sendFeedback(context, TAG, |
Wenyi Wang | 969c595 | 2016-12-20 14:31:18 -0800 | [diff] [blame] | 186 | "Security exception when getting call capable phone accounts", e); |
Wenyi Wang | 7a27b85 | 2016-11-11 11:36:24 -0800 | [diff] [blame] | 187 | return VIDEO_CALLING_DISABLED; |
Tyler Gunn | 001d974 | 2015-12-18 13:57:02 -0800 | [diff] [blame] | 188 | } |
Tyler Gunn | 001d974 | 2015-12-18 13:57:02 -0800 | [diff] [blame] | 189 | } |
| 190 | |
| 191 | /** |
Tyler Gunn | a05f153 | 2015-08-06 15:01:44 -0700 | [diff] [blame] | 192 | * Determines if one of the call capable phone accounts defined supports calling with a subject |
| 193 | * specified. |
| 194 | * |
| 195 | * @param context The context. |
| 196 | * @return {@code true} if one of the call capable phone accounts supports calling with a |
| 197 | * subject specified, {@code false} otherwise. |
| 198 | */ |
| 199 | public static boolean isCallWithSubjectSupported(Context context) { |
Nancy Chen | 5fe647d | 2015-12-08 16:57:48 -0800 | [diff] [blame] | 200 | if (!PermissionsUtil.hasPermission(context, android.Manifest.permission.READ_PHONE_STATE) |
| 201 | || !CompatUtils.isCallSubjectCompatible()) { |
Yorke Lee | d2c9692 | 2015-09-18 12:59:16 -0700 | [diff] [blame] | 202 | return false; |
| 203 | } |
Tyler Gunn | a05f153 | 2015-08-06 15:01:44 -0700 | [diff] [blame] | 204 | TelecomManager telecommMgr = (TelecomManager) |
| 205 | context.getSystemService(Context.TELECOM_SERVICE); |
| 206 | if (telecommMgr == null) { |
| 207 | return false; |
| 208 | } |
| 209 | |
Wenyi Wang | 969c595 | 2016-12-20 14:31:18 -0800 | [diff] [blame] | 210 | try { |
| 211 | List<PhoneAccountHandle> accountHandles = telecommMgr.getCallCapablePhoneAccounts(); |
| 212 | for (PhoneAccountHandle accountHandle : accountHandles) { |
| 213 | PhoneAccount account = telecommMgr.getPhoneAccount(accountHandle); |
| 214 | if (account != null && account.hasCapabilities(PhoneAccount.CAPABILITY_CALL_SUBJECT)) { |
| 215 | return true; |
| 216 | } |
Tyler Gunn | a05f153 | 2015-08-06 15:01:44 -0700 | [diff] [blame] | 217 | } |
Wenyi Wang | 969c595 | 2016-12-20 14:31:18 -0800 | [diff] [blame] | 218 | return false; |
| 219 | } catch (SecurityException e) { |
| 220 | FeedbackHelper.sendFeedback(context, TAG, |
| 221 | "Security exception when getting call capable phone accounts", e); |
| 222 | return false; |
Tyler Gunn | a05f153 | 2015-08-06 15:01:44 -0700 | [diff] [blame] | 223 | } |
Wenyi Wang | 969c595 | 2016-12-20 14:31:18 -0800 | [diff] [blame] | 224 | |
Tyler Gunn | a05f153 | 2015-08-06 15:01:44 -0700 | [diff] [blame] | 225 | } |
Gary Mai | 8e6856b | 2017-06-12 15:19:31 -0700 | [diff] [blame] | 226 | |
| 227 | /** |
| 228 | * Determines if we're able to use Tachyon as a fallback for video calling. |
| 229 | * |
| 230 | * @param context The context. |
| 231 | * @return {@code true} if there exists a call capable phone account which supports using a |
| 232 | * fallback for video calling, the carrier configuration supports a fallback, and the |
| 233 | * experiment for using a fallback is enabled. Otherwise {@code false} is returned. |
| 234 | */ |
| 235 | public static boolean isTachyonEnabled(Context context) { |
| 236 | // Need to be able to read phone state, and be on at least N to check PhoneAccount extras. |
| 237 | if (!PermissionsUtil.hasPermission(context, android.Manifest.permission.READ_PHONE_STATE) |
| 238 | || !CompatUtils.isNCompatible()) { |
| 239 | return false; |
| 240 | } |
| 241 | TelecomManager telecommMgr = (TelecomManager) |
| 242 | context.getSystemService(Context.TELECOM_SERVICE); |
| 243 | if (telecommMgr == null) { |
| 244 | return false; |
| 245 | } |
| 246 | try { |
| 247 | List<PhoneAccountHandle> accountHandles = telecommMgr.getCallCapablePhoneAccounts(); |
| 248 | for (PhoneAccountHandle accountHandle : accountHandles) { |
| 249 | PhoneAccount account = telecommMgr.getPhoneAccount(accountHandle); |
| 250 | if (account == null) { |
| 251 | continue; |
| 252 | } |
| 253 | // Check availability for the device config. |
| 254 | final Bundle accountExtras = account.getExtras(); |
| 255 | final boolean deviceEnabled = accountExtras != null && accountExtras.getBoolean( |
| 256 | EXTRA_SUPPORTS_VIDEO_CALLING_FALLBACK); |
| 257 | if (Log.isLoggable(TAG, Log.DEBUG)) { |
| 258 | Log.d(TAG, "Device video fallback config: " + deviceEnabled); |
| 259 | } |
| 260 | |
| 261 | // Check availability from carrier config. |
| 262 | final PersistableBundle carrierConfig = context.getSystemService( |
| 263 | CarrierConfigManager.class).getConfig(); |
| 264 | final boolean carrierEnabled = |
| 265 | carrierConfig != null && carrierConfig.getBoolean( |
| 266 | CONFIG_ALLOW_VIDEO_CALLING_FALLBACK); |
| 267 | if (Log.isLoggable(TAG, Log.DEBUG)) { |
| 268 | Log.d(TAG, "Carrier video fallback config: " + carrierEnabled); |
| 269 | } |
| 270 | |
| 271 | // Check experiment value. |
| 272 | final boolean experimentEnabled = Flags.getInstance().getBoolean( |
| 273 | Experiments.QUICK_CONTACT_VIDEO_CALL); |
| 274 | if (Log.isLoggable(TAG, Log.DEBUG)) { |
| 275 | Log.d(TAG, "Experiment video fallback config: " + experimentEnabled); |
| 276 | } |
| 277 | |
| 278 | // All three checks above must be true to enable Tachyon calling. |
| 279 | return deviceEnabled && carrierEnabled && experimentEnabled; |
| 280 | } |
| 281 | return false; |
| 282 | } catch (SecurityException e) { |
| 283 | FeedbackHelper.sendFeedback(context, TAG, |
| 284 | "Security exception when getting call capable phone accounts", e); |
| 285 | return false; |
| 286 | } |
| 287 | } |
Chiao Cheng | cb5b270 | 2012-09-05 16:10:50 -0700 | [diff] [blame] | 288 | } |