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.compat.telephony;
18 
19 import android.content.Context;
20 import android.content.Intent;
21 import android.net.Uri;
22 import android.os.Build.VERSION;
23 import android.os.Build.VERSION_CODES;
24 import android.support.annotation.Nullable;
25 import android.support.v4.os.BuildCompat;
26 import android.telecom.PhoneAccountHandle;
27 import android.telephony.TelephonyManager;
28 import com.android.dialer.common.LogUtil;
29 import com.android.dialer.telecom.TelecomUtil;
30 import java.lang.reflect.InvocationTargetException;
31 
32 /** Hidden APIs in {@link android.telephony.TelephonyManager}. */
33 public class TelephonyManagerCompat {
34 
35   // TODO(maxwelb): Use public API for these constants when available
36   public static final String EVENT_HANDOVER_VIDEO_FROM_WIFI_TO_LTE =
37       "android.telephony.event.EVENT_HANDOVER_VIDEO_FROM_WIFI_TO_LTE";
38   public static final String EVENT_HANDOVER_VIDEO_FROM_LTE_TO_WIFI =
39       "android.telephony.event.EVENT_HANDOVER_VIDEO_FROM_LTE_TO_WIFI";
40   public static final String EVENT_HANDOVER_TO_WIFI_FAILED =
41       "android.telephony.event.EVENT_HANDOVER_TO_WIFI_FAILED";
42   public static final String EVENT_CALL_REMOTELY_HELD = "android.telecom.event.CALL_REMOTELY_HELD";
43   public static final String EVENT_CALL_REMOTELY_UNHELD =
44       "android.telecom.event.CALL_REMOTELY_UNHELD";
45   public static final String EVENT_MERGE_START = "android.telecom.event.MERGE_START";
46   public static final String EVENT_MERGE_COMPLETE = "android.telecom.event.MERGE_COMPLETE";
47 
48   public static final String EVENT_NOTIFY_INTERNATIONAL_CALL_ON_WFC =
49       "android.telephony.event.EVENT_NOTIFY_INTERNATIONAL_CALL_ON_WFC";
50   public static final String EVENT_CALL_FORWARDED = "android.telephony.event.EVENT_CALL_FORWARDED";
51 
52   public static final String TELEPHONY_MANAGER_CLASS = "android.telephony.TelephonyManager";
53 
54   private static final String SECRET_CODE_ACTION = "android.provider.Telephony.SECRET_CODE";
55 
56   // TODO(erfanian): a bug Replace with the platform/telecom constant when available.
57   /**
58    * Indicates that the call being placed originated from a known contact.
59    *
60    * <p>This signals to the telephony platform that an outgoing call qualifies for assisted dialing.
61    */
62   public static final String USE_ASSISTED_DIALING = "android.telecom.extra.USE_ASSISTED_DIALING";
63 
64   // TODO(erfanian): a bug Replace with the platform/telecom API when available.
65   /** Additional information relating to the assisted dialing transformation. */
66   public static final String ASSISTED_DIALING_EXTRAS =
67       "android.telecom.extra.ASSISTED_DIALING_EXTRAS";
68 
69   /** Indicates the Connection/Call used assisted dialing. */
70   public static final int PROPERTY_ASSISTED_DIALING_USED = 1 << 9;
71 
72   public static final String EXTRA_IS_REFRESH =
73       BuildCompat.isAtLeastOMR1() ? "android.telephony.extra.IS_REFRESH" : "is_refresh";
74 
75   /**
76    * Indicates the call underwent Assisted Dialing; typically set as a feature available from the
77    * CallLog.
78    */
79   public static final Integer FEATURES_ASSISTED_DIALING = 1 << 4;
80 
81   /**
82    * Flag specifying whether to show an alert dialog for video call charges. By default this value
83    * is {@code false}. TODO(a bug): Replace with public API for these constants when available.
84    */
85   public static final String CARRIER_CONFIG_KEY_SHOW_VIDEO_CALL_CHARGES_ALERT_DIALOG_BOOL =
86       "show_video_call_charges_alert_dialog_bool";
87 
88   /**
89    * Returns the number of phones available. Returns 1 for Single standby mode (Single SIM
90    * functionality) Returns 2 for Dual standby mode.(Dual SIM functionality)
91    *
92    * <p>Returns 1 if the method or telephonyManager is not available.
93    *
94    * @param telephonyManager The telephony manager instance to use for method calls.
95    */
getPhoneCount(@ullable TelephonyManager telephonyManager)96   public static int getPhoneCount(@Nullable TelephonyManager telephonyManager) {
97     if (telephonyManager == null) {
98       return 1;
99     }
100     return telephonyManager.getPhoneCount();
101   }
102 
103   /**
104    * Whether the phone supports TTY mode.
105    *
106    * @param telephonyManager The telephony manager instance to use for method calls.
107    * @return {@code true} if the device supports TTY mode, and {@code false} otherwise.
108    */
isTtyModeSupported(@ullable TelephonyManager telephonyManager)109   public static boolean isTtyModeSupported(@Nullable TelephonyManager telephonyManager) {
110     return telephonyManager != null && telephonyManager.isTtyModeSupported();
111   }
112 
113   /**
114    * Whether the phone supports hearing aid compatibility.
115    *
116    * @param telephonyManager The telephony manager instance to use for method calls.
117    * @return {@code true} if the device supports hearing aid compatibility, and {@code false}
118    *     otherwise.
119    */
isHearingAidCompatibilitySupported( @ullable TelephonyManager telephonyManager)120   public static boolean isHearingAidCompatibilitySupported(
121       @Nullable TelephonyManager telephonyManager) {
122     return telephonyManager != null && telephonyManager.isHearingAidCompatibilitySupported();
123   }
124 
125   /**
126    * Returns the URI for the per-account voicemail ringtone set in Phone settings.
127    *
128    * @param telephonyManager The telephony manager instance to use for method calls.
129    * @param accountHandle The handle for the {@link android.telecom.PhoneAccount} for which to
130    *     retrieve the voicemail ringtone.
131    * @return The URI for the ringtone to play when receiving a voicemail from a specific
132    *     PhoneAccount.
133    */
134   @Nullable
getVoicemailRingtoneUri( TelephonyManager telephonyManager, PhoneAccountHandle accountHandle)135   public static Uri getVoicemailRingtoneUri(
136       TelephonyManager telephonyManager, PhoneAccountHandle accountHandle) {
137     return telephonyManager.getVoicemailRingtoneUri(accountHandle);
138   }
139 
140   /**
141    * Returns whether vibration is set for voicemail notification in Phone settings.
142    *
143    * @param telephonyManager The telephony manager instance to use for method calls.
144    * @param accountHandle The handle for the {@link android.telecom.PhoneAccount} for which to
145    *     retrieve the voicemail vibration setting.
146    * @return {@code true} if the vibration is set for this PhoneAccount, {@code false} otherwise.
147    */
isVoicemailVibrationEnabled( TelephonyManager telephonyManager, PhoneAccountHandle accountHandle)148   public static boolean isVoicemailVibrationEnabled(
149       TelephonyManager telephonyManager, PhoneAccountHandle accountHandle) {
150     return telephonyManager.isVoicemailVibrationEnabled(accountHandle);
151   }
152 
153   /**
154    * This method uses a new system API to enable or disable visual voicemail. TODO(twyen): restrict
155    * to N MR1, not needed in future SDK.
156    */
setVisualVoicemailEnabled( TelephonyManager telephonyManager, PhoneAccountHandle handle, boolean enabled)157   public static void setVisualVoicemailEnabled(
158       TelephonyManager telephonyManager, PhoneAccountHandle handle, boolean enabled) {
159     try {
160       TelephonyManager.class
161           .getMethod("setVisualVoicemailEnabled", PhoneAccountHandle.class, boolean.class)
162           .invoke(telephonyManager, handle, enabled);
163     } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
164       LogUtil.e("TelephonyManagerCompat.setVisualVoicemailEnabled", "failed", e);
165     }
166   }
167 
168   /**
169    * This method uses a new system API to check if visual voicemail is enabled TODO(twyen): restrict
170    * to N MR1, not needed in future SDK.
171    */
isVisualVoicemailEnabled( TelephonyManager telephonyManager, PhoneAccountHandle handle)172   public static boolean isVisualVoicemailEnabled(
173       TelephonyManager telephonyManager, PhoneAccountHandle handle) {
174     try {
175       return (boolean)
176           TelephonyManager.class
177               .getMethod("isVisualVoicemailEnabled", PhoneAccountHandle.class)
178               .invoke(telephonyManager, handle);
179     } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
180       LogUtil.e("TelephonyManagerCompat.setVisualVoicemailEnabled", "failed", e);
181     }
182     return false;
183   }
184 
185   /**
186    * Handles secret codes to launch arbitrary activities.
187    *
188    * @param context the context to use
189    * @param secretCode the secret code without the "*#*#" prefix and "#*#*" suffix
190    */
handleSecretCode(Context context, String secretCode)191   public static void handleSecretCode(Context context, String secretCode) {
192     // Must use system service on O+ to avoid using broadcasts, which are not allowed on O+.
193     if (BuildCompat.isAtLeastO()) {
194       if (!TelecomUtil.isDefaultDialer(context)) {
195         LogUtil.e(
196             "TelephonyManagerCompat.handleSecretCode",
197             "not default dialer, cannot send special code");
198         return;
199       }
200       context.getSystemService(TelephonyManager.class).sendDialerSpecialCode(secretCode);
201     } else {
202       // System service call is not supported pre-O, so must use a broadcast for N-.
203       Intent intent =
204           new Intent(SECRET_CODE_ACTION, Uri.parse("android_secret_code://" + secretCode));
205       context.sendBroadcast(intent);
206     }
207   }
208 
209   /**
210    * Returns network country iso for given {@code PhoneAccountHandle} for O+ devices and country iso
211    * for default sim for pre-O devices.
212    */
getNetworkCountryIsoForPhoneAccountHandle( Context context, @Nullable PhoneAccountHandle phoneAccountHandle)213   public static String getNetworkCountryIsoForPhoneAccountHandle(
214       Context context, @Nullable PhoneAccountHandle phoneAccountHandle) {
215     return getTelephonyManagerForPhoneAccountHandle(context, phoneAccountHandle)
216         .getNetworkCountryIso();
217   }
218 
219   /**
220    * Returns TelephonyManager for given {@code PhoneAccountHandle} for O+ devices and default {@code
221    * TelephonyManager} for pre-O devices.
222    */
getTelephonyManagerForPhoneAccountHandle( Context context, @Nullable PhoneAccountHandle phoneAccountHandle)223   public static TelephonyManager getTelephonyManagerForPhoneAccountHandle(
224       Context context, @Nullable PhoneAccountHandle phoneAccountHandle) {
225     TelephonyManager telephonyManager = context.getSystemService(TelephonyManager.class);
226     if (phoneAccountHandle == null) {
227       return telephonyManager;
228     }
229     if (VERSION.SDK_INT >= VERSION_CODES.O) {
230       TelephonyManager telephonyManagerForPhoneAccount =
231           telephonyManager.createForPhoneAccountHandle(phoneAccountHandle);
232       if (telephonyManagerForPhoneAccount != null) {
233         return telephonyManagerForPhoneAccount;
234       }
235     }
236     return telephonyManager;
237   }
238 }
239