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