Home | History | Annotate | Download | only in compat
      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.common.compat;
     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.compat.CompatUtils;
     31 import java.lang.reflect.InvocationTargetException;
     32 
     33 public class TelephonyManagerCompat {
     34 
     35   // TODO: 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_TO_WIFI_FAILED =
     39       "android.telephony.event.EVENT_HANDOVER_TO_WIFI_FAILED";
     40   public static final String EVENT_CALL_REMOTELY_HELD = "android.telecom.event.CALL_REMOTELY_HELD";
     41   public static final String EVENT_CALL_REMOTELY_UNHELD =
     42       "android.telecom.event.CALL_REMOTELY_UNHELD";
     43 
     44   public static final String EVENT_NOTIFY_INTERNATIONAL_CALL_ON_WFC =
     45       "android.telephony.event.EVENT_NOTIFY_INTERNATIONAL_CALL_ON_WFC";
     46 
     47   public static final String TELEPHONY_MANAGER_CLASS = "android.telephony.TelephonyManager";
     48 
     49   private static final String SECRET_CODE_ACTION = "android.provider.Telephony.SECRET_CODE";
     50 
     51   /**
     52    * @param telephonyManager The telephony manager instance to use for method calls.
     53    * @return true if the current device is "voice capable".
     54    *     <p>"Voice capable" means that this device supports circuit-switched (i.e. voice) phone
     55    *     calls over the telephony network, and is allowed to display the in-call UI while a cellular
     56    *     voice call is active. This will be false on "data only" devices which can't make voice
     57    *     calls and don't support any in-call UI.
     58    *     <p>Note: the meaning of this flag is subtly different from the
     59    *     PackageManager.FEATURE_TELEPHONY system feature, which is available on any device with a
     60    *     telephony radio, even if the device is data-only.
     61    */
     62   public static boolean isVoiceCapable(@Nullable TelephonyManager telephonyManager) {
     63     if (telephonyManager == null) {
     64       return false;
     65     }
     66     if (CompatUtils.isLollipopMr1Compatible()
     67         || CompatUtils.isMethodAvailable(TELEPHONY_MANAGER_CLASS, "isVoiceCapable")) {
     68       // isVoiceCapable was unhidden in L-MR1
     69       return telephonyManager.isVoiceCapable();
     70     }
     71     final int phoneType = telephonyManager.getPhoneType();
     72     return phoneType == TelephonyManager.PHONE_TYPE_CDMA
     73         || phoneType == TelephonyManager.PHONE_TYPE_GSM;
     74   }
     75 
     76   /**
     77    * Returns the number of phones available. Returns 1 for Single standby mode (Single SIM
     78    * functionality) Returns 2 for Dual standby mode.(Dual SIM functionality)
     79    *
     80    * <p>Returns 1 if the method or telephonyManager is not available.
     81    *
     82    * @param telephonyManager The telephony manager instance to use for method calls.
     83    */
     84   public static int getPhoneCount(@Nullable TelephonyManager telephonyManager) {
     85     if (telephonyManager == null) {
     86       return 1;
     87     }
     88     if (CompatUtils.isMarshmallowCompatible()
     89         || CompatUtils.isMethodAvailable(TELEPHONY_MANAGER_CLASS, "getPhoneCount")) {
     90       return telephonyManager.getPhoneCount();
     91     }
     92     return 1;
     93   }
     94 
     95   /**
     96    * Returns the unique device ID of a subscription, for example, the IMEI for GSM and the MEID for
     97    * CDMA phones. Return null if device ID is not available.
     98    *
     99    * <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
    100    *
    101    * @param telephonyManager The telephony manager instance to use for method calls.
    102    * @param slotId of which deviceID is returned
    103    */
    104   public static String getDeviceId(@Nullable TelephonyManager telephonyManager, int slotId) {
    105     if (telephonyManager == null) {
    106       return null;
    107     }
    108     if (CompatUtils.isMarshmallowCompatible()
    109         || CompatUtils.isMethodAvailable(TELEPHONY_MANAGER_CLASS, "getDeviceId", Integer.class)) {
    110       return telephonyManager.getDeviceId(slotId);
    111     }
    112     return null;
    113   }
    114 
    115   /**
    116    * Whether the phone supports TTY mode.
    117    *
    118    * @param telephonyManager The telephony manager instance to use for method calls.
    119    * @return {@code true} if the device supports TTY mode, and {@code false} otherwise.
    120    */
    121   public static boolean isTtyModeSupported(@Nullable TelephonyManager telephonyManager) {
    122     if (telephonyManager == null) {
    123       return false;
    124     }
    125     if (CompatUtils.isMarshmallowCompatible()
    126         || CompatUtils.isMethodAvailable(TELEPHONY_MANAGER_CLASS, "isTtyModeSupported")) {
    127       return telephonyManager.isTtyModeSupported();
    128     }
    129     return false;
    130   }
    131 
    132   /**
    133    * Whether the phone supports hearing aid compatibility.
    134    *
    135    * @param telephonyManager The telephony manager instance to use for method calls.
    136    * @return {@code true} if the device supports hearing aid compatibility, and {@code false}
    137    *     otherwise.
    138    */
    139   public static boolean isHearingAidCompatibilitySupported(
    140       @Nullable TelephonyManager telephonyManager) {
    141     if (telephonyManager == null) {
    142       return false;
    143     }
    144     if (CompatUtils.isMarshmallowCompatible()
    145         || CompatUtils.isMethodAvailable(
    146             TELEPHONY_MANAGER_CLASS, "isHearingAidCompatibilitySupported")) {
    147       return telephonyManager.isHearingAidCompatibilitySupported();
    148     }
    149     return false;
    150   }
    151 
    152   /**
    153    * Returns the URI for the per-account voicemail ringtone set in Phone settings.
    154    *
    155    * @param telephonyManager The telephony manager instance to use for method calls.
    156    * @param accountHandle The handle for the {@link android.telecom.PhoneAccount} for which to
    157    *     retrieve the voicemail ringtone.
    158    * @return The URI for the ringtone to play when receiving a voicemail from a specific
    159    *     PhoneAccount.
    160    */
    161   @Nullable
    162   public static Uri getVoicemailRingtoneUri(
    163       TelephonyManager telephonyManager, PhoneAccountHandle accountHandle) {
    164     if (VERSION.SDK_INT < VERSION_CODES.N) {
    165       return null;
    166     }
    167     return telephonyManager.getVoicemailRingtoneUri(accountHandle);
    168   }
    169 
    170   /**
    171    * Returns whether vibration is set for voicemail notification in Phone settings.
    172    *
    173    * @param telephonyManager The telephony manager instance to use for method calls.
    174    * @param accountHandle The handle for the {@link android.telecom.PhoneAccount} for which to
    175    *     retrieve the voicemail vibration setting.
    176    * @return {@code true} if the vibration is set for this PhoneAccount, {@code false} otherwise.
    177    */
    178   public static boolean isVoicemailVibrationEnabled(
    179       TelephonyManager telephonyManager, PhoneAccountHandle accountHandle) {
    180     return VERSION.SDK_INT < VERSION_CODES.N
    181         || telephonyManager.isVoicemailVibrationEnabled(accountHandle);
    182   }
    183 
    184   /**
    185    * This method uses a new system API to enable or disable visual voicemail. TODO: restrict
    186    * to N MR1, not needed in future SDK.
    187    */
    188   public static void setVisualVoicemailEnabled(
    189       TelephonyManager telephonyManager, PhoneAccountHandle handle, boolean enabled) {
    190     if (VERSION.SDK_INT < VERSION_CODES.N_MR1) {
    191       Assert.fail("setVisualVoicemailEnabled called on pre-NMR1");
    192     }
    193     try {
    194       TelephonyManager.class
    195           .getMethod("setVisualVoicemailEnabled", PhoneAccountHandle.class, boolean.class)
    196           .invoke(telephonyManager, handle, enabled);
    197     } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
    198       LogUtil.e("TelephonyManagerCompat.setVisualVoicemailEnabled", "failed", e);
    199     }
    200   }
    201 
    202   /**
    203    * This method uses a new system API to check if visual voicemail is enabled TODO: restrict
    204    * to N MR1, not needed in future SDK.
    205    */
    206   public static boolean isVisualVoicemailEnabled(
    207       TelephonyManager telephonyManager, PhoneAccountHandle handle) {
    208     if (VERSION.SDK_INT < VERSION_CODES.N_MR1) {
    209       Assert.fail("isVisualVoicemailEnabled called on pre-NMR1");
    210     }
    211     try {
    212       return (boolean)
    213           TelephonyManager.class
    214               .getMethod("isVisualVoicemailEnabled", PhoneAccountHandle.class)
    215               .invoke(telephonyManager, handle);
    216     } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
    217       LogUtil.e("TelephonyManagerCompat.setVisualVoicemailEnabled", "failed", e);
    218     }
    219     return false;
    220   }
    221 
    222   /**
    223    * Handles secret codes to launch arbitrary activities.
    224    *
    225    * @param context the context to use
    226    * @param secretCode the secret code without the "*#*#" prefix and "#*#*" suffix
    227    */
    228   public static void handleSecretCode(Context context, String secretCode) {
    229     // Must use system service on O+ to avoid using broadcasts, which are not allowed on O+.
    230     if (BuildCompat.isAtLeastO()) {
    231       context.getSystemService(TelephonyManager.class).sendDialerSpecialCode(secretCode);
    232     } else {
    233       // System service call is not supported pre-O, so must use a broadcast for N-.
    234       Intent intent =
    235           new Intent(SECRET_CODE_ACTION, Uri.parse("android_secret_code://" + secretCode));
    236       context.sendBroadcast(intent);
    237     }
    238   }
    239 }
    240