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.contacts;
18 
19 import android.content.Context;
20 import android.content.Intent;
21 import android.net.Uri;
22 import android.telecom.PhoneAccount;
23 import android.telecom.PhoneAccountHandle;
24 import android.telecom.TelecomManager;
25 import android.telecom.VideoProfile;
26 import android.text.TextUtils;
27 
28 import com.android.contacts.compat.CompatUtils;
29 import com.android.contacts.compat.PhoneAccountSdkCompat;
30 import com.android.contacts.util.PermissionsUtil;
31 import com.android.contacts.util.PhoneNumberHelper;
32 import com.android.contactsbind.FeedbackHelper;
33 import com.android.phone.common.PhoneConstants;
34 
35 import java.util.List;
36 
37 /**
38  * Utilities related to calls that can be used by non system apps. These
39  * use {@link Intent#ACTION_CALL} instead of ACTION_CALL_PRIVILEGED.
40  *
41  * The privileged version of this util exists inside Dialer.
42  */
43 public class CallUtil {
44 
45     public static final String TAG = "CallUtil";
46 
47     /**
48      * Indicates that the video calling is not available.
49      */
50     public static final int VIDEO_CALLING_DISABLED = 0;
51 
52     /**
53      * Indicates that video calling is enabled, regardless of presence status.
54      */
55     public static final int VIDEO_CALLING_ENABLED = 1;
56 
57     /**
58      * Indicates that video calling is enabled, but the availability of video call affordances is
59      * determined by the presence status associated with contacts.
60      */
61     public static final int VIDEO_CALLING_PRESENCE = 2;
62 
63     /**
64      * Return an Intent for making a phone call. Scheme (e.g. tel, sip) will be determined
65      * automatically.
66      */
getCallWithSubjectIntent(String number, PhoneAccountHandle phoneAccountHandle, String callSubject)67     public static Intent getCallWithSubjectIntent(String number,
68             PhoneAccountHandle phoneAccountHandle, String callSubject) {
69 
70         final Intent intent = getCallIntent(getCallUri(number));
71         intent.putExtra(TelecomManager.EXTRA_CALL_SUBJECT, callSubject);
72         if (phoneAccountHandle != null) {
73             intent.putExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, phoneAccountHandle);
74         }
75         return intent;
76     }
77 
78     /**
79      * Return an Intent for making a phone call. Scheme (e.g. tel, sip) will be determined
80      * automatically.
81      */
getCallIntent(String number)82     public static Intent getCallIntent(String number) {
83         return getCallIntent(getCallUri(number));
84     }
85 
86     /**
87      * Return an Intent for making a phone call. A given Uri will be used as is (without any
88      * sanity check).
89      */
getCallIntent(Uri uri)90     public static Intent getCallIntent(Uri uri) {
91         return new Intent(Intent.ACTION_CALL, uri);
92     }
93 
94     /**
95      * A variant of {@link #getCallIntent} for starting a video call.
96      */
getVideoCallIntent(String number, String callOrigin)97     public static Intent getVideoCallIntent(String number, String callOrigin) {
98         final Intent intent = new Intent(Intent.ACTION_CALL, getCallUri(number));
99         intent.putExtra(TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE,
100                 VideoProfile.STATE_BIDIRECTIONAL);
101         if (!TextUtils.isEmpty(callOrigin)) {
102             intent.putExtra(PhoneConstants.EXTRA_CALL_ORIGIN, callOrigin);
103         }
104         return intent;
105     }
106 
107     /**
108      * Return Uri with an appropriate scheme, accepting both SIP and usual phone call
109      * numbers.
110      */
getCallUri(String number)111     public static Uri getCallUri(String number) {
112         if (PhoneNumberHelper.isUriNumber(number)) {
113              return Uri.fromParts(PhoneAccount.SCHEME_SIP, number, null);
114         }
115         return Uri.fromParts(PhoneAccount.SCHEME_TEL, number, null);
116     }
117 
118     /**
119      * Determines if video calling is available, and if so whether presence checking is available
120      * as well.
121      *
122      * Returns a bitmask with {@link #VIDEO_CALLING_ENABLED} to indicate that video calling is
123      * available, and {@link #VIDEO_CALLING_PRESENCE} if presence indication is also available.
124      *
125      * @param context The context
126      * @return A bit-mask describing the current video capabilities.
127      */
getVideoCallingAvailability(Context context)128     public static int getVideoCallingAvailability(Context context) {
129         if (!PermissionsUtil.hasPermission(context, android.Manifest.permission.READ_PHONE_STATE)
130                 || !CompatUtils.isVideoCompatible()) {
131             return VIDEO_CALLING_DISABLED;
132         }
133         TelecomManager telecommMgr = (TelecomManager)
134                 context.getSystemService(Context.TELECOM_SERVICE);
135         if (telecommMgr == null) {
136             return VIDEO_CALLING_DISABLED;
137         }
138 
139         try {
140             List<PhoneAccountHandle> accountHandles = telecommMgr.getCallCapablePhoneAccounts();
141             for (PhoneAccountHandle accountHandle : accountHandles) {
142                 PhoneAccount account = telecommMgr.getPhoneAccount(accountHandle);
143                 if (account != null) {
144                     if (account.hasCapabilities(PhoneAccount.CAPABILITY_VIDEO_CALLING)) {
145                         // Builds prior to N do not have presence support.
146                         if (!CompatUtils.isVideoPresenceCompatible()) {
147                             return VIDEO_CALLING_ENABLED;
148                         }
149 
150                         int videoCapabilities = VIDEO_CALLING_ENABLED;
151                         if (account.hasCapabilities(PhoneAccountSdkCompat
152                                 .CAPABILITY_VIDEO_CALLING_RELIES_ON_PRESENCE)) {
153                             videoCapabilities |= VIDEO_CALLING_PRESENCE;
154                         }
155                         return videoCapabilities;
156                     }
157                 }
158             }
159             return VIDEO_CALLING_DISABLED;
160         } catch (SecurityException e) {
161             FeedbackHelper.sendFeedback(context, TAG,
162                     "Security exception when getting call capable phone accounts", e);
163             return VIDEO_CALLING_DISABLED;
164         }
165     }
166 
167     /**
168      * Determines if one of the call capable phone accounts defined supports calling with a subject
169      * specified.
170      *
171      * @param context The context.
172      * @return {@code true} if one of the call capable phone accounts supports calling with a
173      *      subject specified, {@code false} otherwise.
174      */
isCallWithSubjectSupported(Context context)175     public static boolean isCallWithSubjectSupported(Context context) {
176         if (!PermissionsUtil.hasPermission(context, android.Manifest.permission.READ_PHONE_STATE)
177                 || !CompatUtils.isCallSubjectCompatible()) {
178             return false;
179         }
180         TelecomManager telecommMgr = (TelecomManager)
181                 context.getSystemService(Context.TELECOM_SERVICE);
182         if (telecommMgr == null) {
183             return false;
184         }
185 
186         try {
187             List<PhoneAccountHandle> accountHandles = telecommMgr.getCallCapablePhoneAccounts();
188             for (PhoneAccountHandle accountHandle : accountHandles) {
189                 PhoneAccount account = telecommMgr.getPhoneAccount(accountHandle);
190                 if (account != null && account.hasCapabilities(PhoneAccount.CAPABILITY_CALL_SUBJECT)) {
191                     return true;
192                 }
193             }
194             return false;
195         } catch (SecurityException e) {
196             FeedbackHelper.sendFeedback(context, TAG,
197                     "Security exception when getting call capable phone accounts", e);
198             return false;
199         }
200 
201     }
202 }
203