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