blob: 0f09df94e58636ec8dc23d221199c27de5a5a112 [file] [log] [blame]
Chiao Chengcb5b2702012-09-05 16:10:50 -07001/*
Brian Attwell066bd682015-02-03 17:10:19 -08002 * Copyright (C) 2015 The Android Open Source Project
Chiao Chengcb5b2702012-09-05 16:10:50 -07003 *
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 Mai0a49afa2016-12-05 15:53:58 -080017package com.android.contacts;
Brian Attwell066bd682015-02-03 17:10:19 -080018
Andrew Lee7e558dc2014-08-20 16:02:11 -070019import android.content.Context;
Chiao Chengcb5b2702012-09-05 16:10:50 -070020import android.content.Intent;
21import android.net.Uri;
Gary Mai8e6856b2017-06-12 15:19:31 -070022import android.os.Bundle;
23import android.os.PersistableBundle;
Tyler Gunn5cf7f012014-09-10 15:20:21 -070024import android.telecom.PhoneAccount;
Vinit Deshpandeca6b31e2015-03-15 13:23:01 -070025import android.telecom.PhoneAccountHandle;
Tyler Gunn5cf7f012014-09-10 15:20:21 -070026import android.telecom.TelecomManager;
27import android.telecom.VideoProfile;
Gary Mai8e6856b2017-06-12 15:19:31 -070028import android.telephony.CarrierConfigManager;
yaolu18417a42017-05-04 12:33:47 -070029import android.telephony.PhoneNumberUtils;
Brian Attwell066bd682015-02-03 17:10:19 -080030import android.text.TextUtils;
Gary Mai8e6856b2017-06-12 15:19:31 -070031import android.util.Log;
Chiao Chengcb5b2702012-09-05 16:10:50 -070032
Gary Mai0a49afa2016-12-05 15:53:58 -080033import com.android.contacts.compat.CompatUtils;
34import com.android.contacts.compat.PhoneAccountSdkCompat;
35import com.android.contacts.util.PermissionsUtil;
36import com.android.contacts.util.PhoneNumberHelper;
37import com.android.contactsbind.FeedbackHelper;
Gary Mai8e6856b2017-06-12 15:19:31 -070038import com.android.contactsbind.experiments.Flags;
Gary Mai0a49afa2016-12-05 15:53:58 -080039import com.android.phone.common.PhoneConstants;
40
Yorke Lee9028db02015-03-19 17:01:54 +000041import java.util.List;
42
Chiao Chengcb5b2702012-09-05 16:10:50 -070043/**
Brian Attwell066bd682015-02-03 17:10:19 -080044 * 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 Chengcb5b2702012-09-05 16:10:50 -070048 */
49public class CallUtil {
50
Wenyi Wang7a27b852016-11-11 11:36:24 -080051 public static final String TAG = "CallUtil";
52
Chiao Chengcb5b2702012-09-05 16:10:50 -070053 /**
Tyler Gunn001d9742015-12-18 13:57:02 -080054 * 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 Mai8e6856b2017-06-12 15:19:31 -070069 /** {@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 Gunn001d9742015-12-18 13:57:02 -080077 /**
Chiao Chengcb5b2702012-09-05 16:10:50 -070078 * Return an Intent for making a phone call. Scheme (e.g. tel, sip) will be determined
79 * automatically.
80 */
Tyler Gunn9e0c14e2015-08-04 13:33:49 -070081 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 Chengcb5b2702012-09-05 16:10:50 -070096 public static Intent getCallIntent(String number) {
yaolu18417a42017-05-04 12:33:47 -070097 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 Chengcb5b2702012-09-05 16:10:50 -0700108 }
109
110 /**
111 * Return an Intent for making a phone call. A given Uri will be used as is (without any
Raman Tenneti362f4222020-07-28 16:54:20 -0700112 * quick check).
Chiao Chengcb5b2702012-09-05 16:10:50 -0700113 */
114 public static Intent getCallIntent(Uri uri) {
Brian Attwell066bd682015-02-03 17:10:19 -0800115 return new Intent(Intent.ACTION_CALL, uri);
Chiao Chengcb5b2702012-09-05 16:10:50 -0700116 }
117
118 /**
Brian Attwell066bd682015-02-03 17:10:19 -0800119 * A variant of {@link #getCallIntent} for starting a video call.
Andrew Leec18a7542014-07-08 16:02:30 -0700120 */
Nancy Chenc095aee2014-07-09 10:29:41 -0700121 public static Intent getVideoCallIntent(String number, String callOrigin) {
Brian Attwell066bd682015-02-03 17:10:19 -0800122 final Intent intent = new Intent(Intent.ACTION_CALL, getCallUri(number));
123 intent.putExtra(TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE,
Yorke Leecb93d462015-05-12 16:23:06 -0700124 VideoProfile.STATE_BIDIRECTIONAL);
Brian Attwell066bd682015-02-03 17:10:19 -0800125 if (!TextUtils.isEmpty(callOrigin)) {
Chiao Chengcb5b2702012-09-05 16:10:50 -0700126 intent.putExtra(PhoneConstants.EXTRA_CALL_ORIGIN, callOrigin);
127 }
128 return intent;
129 }
130
131 /**
Jay Shraunered1a3b22014-09-05 15:37:27 -0700132 * Return Uri with an appropriate scheme, accepting both SIP and usual phone call
Chiao Chengcb5b2702012-09-05 16:10:50 -0700133 * numbers.
134 */
135 public static Uri getCallUri(String number) {
Yorke Lee9e8e7cb2014-03-17 13:04:45 -0700136 if (PhoneNumberHelper.isUriNumber(number)) {
Jay Shraunered1a3b22014-09-05 15:37:27 -0700137 return Uri.fromParts(PhoneAccount.SCHEME_SIP, number, null);
Chiao Chengcb5b2702012-09-05 16:10:50 -0700138 }
Jay Shraunered1a3b22014-09-05 15:37:27 -0700139 return Uri.fromParts(PhoneAccount.SCHEME_TEL, number, null);
Yorke Lee9028db02015-03-19 17:01:54 +0000140 }
Paul Soulos56046082014-08-18 16:12:40 -0700141
Yorke Lee9028db02015-03-19 17:01:54 +0000142 /**
Tyler Gunn001d9742015-12-18 13:57:02 -0800143 * 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 Wang7a27b852016-11-11 11:36:24 -0800163 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 Gunn001d9742015-12-18 13:57:02 -0800173
Wenyi Wang7a27b852016-11-11 11:36:24 -0800174 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 Gunn001d9742015-12-18 13:57:02 -0800180 }
Tyler Gunn001d9742015-12-18 13:57:02 -0800181 }
182 }
Wenyi Wang7a27b852016-11-11 11:36:24 -0800183 return VIDEO_CALLING_DISABLED;
184 } catch (SecurityException e) {
185 FeedbackHelper.sendFeedback(context, TAG,
Wenyi Wang969c5952016-12-20 14:31:18 -0800186 "Security exception when getting call capable phone accounts", e);
Wenyi Wang7a27b852016-11-11 11:36:24 -0800187 return VIDEO_CALLING_DISABLED;
Tyler Gunn001d9742015-12-18 13:57:02 -0800188 }
Tyler Gunn001d9742015-12-18 13:57:02 -0800189 }
190
191 /**
Tyler Gunna05f1532015-08-06 15:01:44 -0700192 * 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 Chen5fe647d2015-12-08 16:57:48 -0800200 if (!PermissionsUtil.hasPermission(context, android.Manifest.permission.READ_PHONE_STATE)
201 || !CompatUtils.isCallSubjectCompatible()) {
Yorke Leed2c96922015-09-18 12:59:16 -0700202 return false;
203 }
Tyler Gunna05f1532015-08-06 15:01:44 -0700204 TelecomManager telecommMgr = (TelecomManager)
205 context.getSystemService(Context.TELECOM_SERVICE);
206 if (telecommMgr == null) {
207 return false;
208 }
209
Wenyi Wang969c5952016-12-20 14:31:18 -0800210 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 Gunna05f1532015-08-06 15:01:44 -0700217 }
Wenyi Wang969c5952016-12-20 14:31:18 -0800218 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 Gunna05f1532015-08-06 15:01:44 -0700223 }
Wenyi Wang969c5952016-12-20 14:31:18 -0800224
Tyler Gunna05f1532015-08-06 15:01:44 -0700225 }
Gary Mai8e6856b2017-06-12 15:19:31 -0700226
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 Chengcb5b2702012-09-05 16:10:50 -0700288}