blob: be5872387d7bf0b39d2cc82559c04056dd6979e8 [file] [log] [blame]
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.telephony.ims;
import android.Manifest;
import android.annotation.CallbackExecutor;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.content.Context;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Binder;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.telephony.AccessNetworkConstants;
import android.telephony.SubscriptionManager;
import android.telephony.ims.aidl.IImsCapabilityCallback;
import android.telephony.ims.aidl.IImsRegistrationCallback;
import android.telephony.ims.feature.ImsFeature;
import android.telephony.ims.feature.MmTelFeature;
import android.telephony.ims.stub.ImsRegistrationImplBase;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.ITelephony;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Executor;
/**
* A manager for the MmTel (Multimedia Telephony) feature of an IMS network, given an associated
* subscription.
*
* Allows a user to query the IMS MmTel feature information for a subscription, register for
* registration and MmTel capability status callbacks, as well as query/modify user settings for the
* associated subscription.
*
* @see #createForSubscriptionId(int)
* @hide
*/
@SystemApi
public class ImsMmTelManager {
private static final String TAG = "ImsMmTelManager";
/**
* @hide
*/
@Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = "WIFI_MODE_", value = {
WIFI_MODE_WIFI_ONLY,
WIFI_MODE_CELLULAR_PREFERRED,
WIFI_MODE_WIFI_PREFERRED
})
public @interface WiFiCallingMode {}
/**
* Register for IMS over IWLAN if WiFi signal quality is high enough. Do not hand over to LTE
* registration if signal quality degrades.
*/
public static final int WIFI_MODE_WIFI_ONLY = 0;
/**
* Prefer registering for IMS over LTE if LTE signal quality is high enough.
*/
public static final int WIFI_MODE_CELLULAR_PREFERRED = 1;
/**
* Prefer registering for IMS over IWLAN if possible if WiFi signal quality is high enough.
*/
public static final int WIFI_MODE_WIFI_PREFERRED = 2;
/**
* Callback class for receiving IMS network Registration callback events.
* @see #registerImsRegistrationCallback(Executor, RegistrationCallback) (RegistrationCallback)
* @see #unregisterImsRegistrationCallback(RegistrationCallback)
*/
public static class RegistrationCallback {
private static class RegistrationBinder extends IImsRegistrationCallback.Stub {
// Translate ImsRegistrationImplBase API to new AccessNetworkConstant because WLAN
// and WWAN are more accurate constants.
private static final Map<Integer, Integer> IMS_REG_TO_ACCESS_TYPE_MAP =
new HashMap<Integer, Integer>() {{
// Map NONE to -1 to make sure that we handle the REGISTRATION_TECH_NONE
// case, since it is defined.
put(ImsRegistrationImplBase.REGISTRATION_TECH_NONE, -1);
put(ImsRegistrationImplBase.REGISTRATION_TECH_LTE,
AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
put(ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN,
AccessNetworkConstants.TRANSPORT_TYPE_WLAN);
}};
private final RegistrationCallback mLocalCallback;
private Executor mExecutor;
RegistrationBinder(RegistrationCallback localCallback) {
mLocalCallback = localCallback;
}
@Override
public void onRegistered(int imsRadioTech) {
if (mLocalCallback == null) return;
Binder.withCleanCallingIdentity(() -> mExecutor.execute(() ->
mLocalCallback.onRegistered(getAccessType(imsRadioTech))));
}
@Override
public void onRegistering(int imsRadioTech) {
if (mLocalCallback == null) return;
Binder.withCleanCallingIdentity(() -> mExecutor.execute(() ->
mLocalCallback.onRegistering(getAccessType(imsRadioTech))));
}
@Override
public void onDeregistered(ImsReasonInfo info) {
if (mLocalCallback == null) return;
Binder.withCleanCallingIdentity(() ->
mExecutor.execute(() -> mLocalCallback.onUnregistered(info)));
}
@Override
public void onTechnologyChangeFailed(int imsRadioTech, ImsReasonInfo info) {
if (mLocalCallback == null) return;
Binder.withCleanCallingIdentity(() ->
mExecutor.execute(() -> mLocalCallback.onTechnologyChangeFailed(
getAccessType(imsRadioTech), info)));
}
@Override
public void onSubscriberAssociatedUriChanged(Uri[] uris) {
if (mLocalCallback == null) return;
Binder.withCleanCallingIdentity(() ->
mExecutor.execute(() ->
mLocalCallback.onSubscriberAssociatedUriChanged(uris)));
}
private void setExecutor(Executor executor) {
mExecutor = executor;
}
private static int getAccessType(int regType) {
if (!IMS_REG_TO_ACCESS_TYPE_MAP.containsKey(regType)) {
Log.w("ImsMmTelManager", "RegistrationBinder - invalid regType returned: "
+ regType);
return -1;
}
return IMS_REG_TO_ACCESS_TYPE_MAP.get(regType);
}
}
private final RegistrationBinder mBinder = new RegistrationBinder(this);
/**
* Notifies the framework when the IMS Provider is registered to the IMS network.
*
* @param imsTransportType the radio access technology. Valid values are defined in
* {@link android.telephony.AccessNetworkConstants.TransportType}.
*/
public void onRegistered(int imsTransportType) {
}
/**
* Notifies the framework when the IMS Provider is trying to register the IMS network.
*
* @param imsTransportType the radio access technology. Valid values are defined in
* {@link android.telephony.AccessNetworkConstants.TransportType}.
*/
public void onRegistering(int imsTransportType) {
}
/**
* Notifies the framework when the IMS Provider is deregistered from the IMS network.
*
* @param info the {@link ImsReasonInfo} associated with why registration was disconnected.
*/
public void onUnregistered(@Nullable ImsReasonInfo info) {
}
/**
* A failure has occurred when trying to handover registration to another technology type,
* defined in {@link android.telephony.AccessNetworkConstants.TransportType}
*
* @param imsTransportType The
* {@link android.telephony.AccessNetworkConstants.TransportType}
* transport type that has failed to handover registration to.
* @param info A {@link ImsReasonInfo} that identifies the reason for failure.
*/
public void onTechnologyChangeFailed(int imsTransportType, @Nullable ImsReasonInfo info) {
}
/**
* Returns a list of subscriber {@link Uri}s associated with this IMS subscription when
* it changes. Per RFC3455, an associated URI is a URI that the service provider has
* allocated to a user for their own usage. A user's phone number is typically one of the
* associated URIs.
* @param uris new array of subscriber {@link Uri}s that are associated with this IMS
* subscription.
* @hide
*/
public void onSubscriberAssociatedUriChanged(@Nullable Uri[] uris) {
}
/**@hide*/
public final IImsRegistrationCallback getBinder() {
return mBinder;
}
/**@hide*/
//Only exposed as public for compatibility with deprecated ImsManager APIs.
public void setExecutor(Executor executor) {
mBinder.setExecutor(executor);
}
}
/**
* Receives IMS capability status updates from the ImsService. This information is also
* available via the {@link #isAvailable(int, int)} method below.
*
* @see #registerMmTelCapabilityCallback(Executor, CapabilityCallback) (CapabilityCallback)
* @see #unregisterMmTelCapabilityCallback(CapabilityCallback)
*/
public static class CapabilityCallback {
private static class CapabilityBinder extends IImsCapabilityCallback.Stub {
private final CapabilityCallback mLocalCallback;
private Executor mExecutor;
CapabilityBinder(CapabilityCallback c) {
mLocalCallback = c;
}
@Override
public void onCapabilitiesStatusChanged(int config) {
if (mLocalCallback == null) return;
Binder.withCleanCallingIdentity(() ->
mExecutor.execute(() -> mLocalCallback.onCapabilitiesStatusChanged(
new MmTelFeature.MmTelCapabilities(config))));
}
@Override
public void onQueryCapabilityConfiguration(int capability, int radioTech,
boolean isEnabled) {
// This is not used for public interfaces.
}
@Override
public void onChangeCapabilityConfigurationError(int capability, int radioTech,
@ImsFeature.ImsCapabilityError int reason) {
// This is not used for public interfaces
}
private void setExecutor(Executor executor) {
mExecutor = executor;
}
}
private final CapabilityBinder mBinder = new CapabilityBinder(this);
/**
* The status of the feature's capabilities has changed to either available or unavailable.
* If unavailable, the feature is not able to support the unavailable capability at this
* time.
*
* This information can also be queried using the {@link #isAvailable(int, int)} API.
*
* @param capabilities The new availability of the capabilities.
*/
public void onCapabilitiesStatusChanged(
@NonNull MmTelFeature.MmTelCapabilities capabilities) {
}
/**@hide*/
public final IImsCapabilityCallback getBinder() {
return mBinder;
}
/**@hide*/
// Only exposed as public method for compatibility with deprecated ImsManager APIs.
// TODO: clean up dependencies and change back to private visibility.
public final void setExecutor(Executor executor) {
mBinder.setExecutor(executor);
}
}
private int mSubId;
/**
* Create an instance of {@link ImsMmTelManager} for the subscription id specified.
*
* @param subId The ID of the subscription that this ImsMmTelManager will use.
* @see android.telephony.SubscriptionManager#getActiveSubscriptionInfoList()
* @throws IllegalArgumentException if the subscription is invalid.
*/
public static @NonNull ImsMmTelManager createForSubscriptionId(int subId) {
if (!SubscriptionManager.isValidSubscriptionId(subId)) {
throw new IllegalArgumentException("Invalid subscription ID");
}
return new ImsMmTelManager(subId);
}
/**
* Only visible for testing, use {@link #createForSubscriptionId(int)} instead.
* @hide
*/
@VisibleForTesting
public ImsMmTelManager(int subId) {
mSubId = subId;
}
/**
* Registers a {@link RegistrationCallback} with the system, which will provide registration
* updates for the subscription specified in {@link #createForSubscriptionId(int)}. Use
* {@link SubscriptionManager.OnSubscriptionsChangedListener} to listen to Subscription changed
* events and call {@link #unregisterImsRegistrationCallback(RegistrationCallback)} to clean up.
*
* When the callback is registered, it will initiate the callback c to be called with the
* current registration state.
*
* @param executor The executor the callback events should be run on.
* @param c The {@link RegistrationCallback} to be added.
* @see #unregisterImsRegistrationCallback(RegistrationCallback)
* @throws IllegalArgumentException if the subscription associated with this callback is not
* active (SIM is not inserted, ESIM inactive) or invalid, or a null {@link Executor} or
* {@link CapabilityCallback} callback.
* @throws ImsException if the subscription associated with this callback is valid, but
* the {@link ImsService} associated with the subscription is not available. This can happen if
* the service crashed, for example. See {@link ImsException#getCode()} for a more detailed
* reason.
*/
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public void registerImsRegistrationCallback(@NonNull @CallbackExecutor Executor executor,
@NonNull RegistrationCallback c) throws ImsException {
if (c == null) {
throw new IllegalArgumentException("Must include a non-null RegistrationCallback.");
}
if (executor == null) {
throw new IllegalArgumentException("Must include a non-null Executor.");
}
if (!isImsAvailableOnDevice()) {
throw new ImsException("IMS not available on device.",
ImsException.CODE_ERROR_UNSUPPORTED_OPERATION);
}
c.setExecutor(executor);
try {
getITelephony().registerImsRegistrationCallback(mSubId, c.getBinder());
} catch (RemoteException | IllegalStateException e) {
throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
}
}
/**
* Removes an existing {@link RegistrationCallback}.
*
* When the subscription associated with this callback is removed (SIM removed, ESIM swap,
* etc...), this callback will automatically be removed. If this method is called for an
* inactive subscription, it will result in a no-op.
*
* @param c The {@link RegistrationCallback} to be removed.
* @see SubscriptionManager.OnSubscriptionsChangedListener
* @see #registerImsRegistrationCallback(Executor, RegistrationCallback)
* @throws IllegalArgumentException if the subscription ID associated with this callback is
* invalid.
*/
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public void unregisterImsRegistrationCallback(@NonNull RegistrationCallback c) {
if (c == null) {
throw new IllegalArgumentException("Must include a non-null RegistrationCallback.");
}
try {
getITelephony().unregisterImsRegistrationCallback(mSubId, c.getBinder());
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
}
/**
* Registers a {@link CapabilityCallback} with the system, which will provide MmTel service
* availability updates for the subscription specified in
* {@link #createForSubscriptionId(int)}. The method {@link #isAvailable(int, int)}
* can also be used to query this information at any time.
*
* Use {@link SubscriptionManager.OnSubscriptionsChangedListener} to listen to
* subscription changed events and call
* {@link #unregisterImsRegistrationCallback(RegistrationCallback)} to clean up.
*
* When the callback is registered, it will initiate the callback c to be called with the
* current capabilities.
*
* @param executor The executor the callback events should be run on.
* @param c The MmTel {@link CapabilityCallback} to be registered.
* @see #unregisterMmTelCapabilityCallback(CapabilityCallback)
* @throws IllegalArgumentException if the subscription associated with this callback is not
* active (SIM is not inserted, ESIM inactive) or invalid, or a null {@link Executor} or
* {@link CapabilityCallback} callback.
* @throws ImsException if the subscription associated with this callback is valid, but
* the {@link ImsService} associated with the subscription is not available. This can happen if
* the service crashed, for example. See {@link ImsException#getCode()} for a more detailed
* reason.
*/
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public void registerMmTelCapabilityCallback(@NonNull @CallbackExecutor Executor executor,
@NonNull CapabilityCallback c) throws ImsException {
if (c == null) {
throw new IllegalArgumentException("Must include a non-null RegistrationCallback.");
}
if (executor == null) {
throw new IllegalArgumentException("Must include a non-null Executor.");
}
if (!isImsAvailableOnDevice()) {
throw new ImsException("IMS not available on device.",
ImsException.CODE_ERROR_UNSUPPORTED_OPERATION);
}
c.setExecutor(executor);
try {
getITelephony().registerMmTelCapabilityCallback(mSubId, c.getBinder());
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
} catch (IllegalStateException e) {
throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
}
}
/**
* Removes an existing MmTel {@link CapabilityCallback}.
*
* When the subscription associated with this callback is removed (SIM removed, ESIM swap,
* etc...), this callback will automatically be removed. If this method is called for an
* inactive subscription, it will result in a no-op.
* @param c The MmTel {@link CapabilityCallback} to be removed.
* @see #registerMmTelCapabilityCallback(Executor, CapabilityCallback)
* @throws IllegalArgumentException if the subscription ID associated with this callback is
* invalid.
*/
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public void unregisterMmTelCapabilityCallback(@NonNull CapabilityCallback c) {
if (c == null) {
throw new IllegalArgumentException("Must include a non-null RegistrationCallback.");
}
try {
getITelephony().unregisterMmTelCapabilityCallback(mSubId, c.getBinder());
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
}
/**
* Query the user’s setting for “Advanced Calling” or "Enhanced 4G LTE", which is used to
* enable MmTel IMS features, depending on the carrier configuration for the current
* subscription. If this setting is enabled, IMS voice and video telephony over IWLAN/LTE will
* be enabled as long as the carrier has provisioned these services for the specified
* subscription. Other IMS services (SMS/UT) are not affected by this user setting and depend on
* carrier requirements.
*
* Modifying this value may also trigger an IMS registration or deregistration, depending on
* whether or not the new value is enabled or disabled.
*
* Note: If the carrier configuration for advanced calling is not editable or hidden, this
* method will do nothing and will instead always use the default value.
*
* @see android.telephony.CarrierConfigManager#KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL
* @see android.telephony.CarrierConfigManager#KEY_EDITABLE_ENHANCED_4G_LTE_BOOL
* @see android.telephony.CarrierConfigManager#KEY_HIDE_ENHANCED_4G_LTE_BOOL
* @see android.telephony.CarrierConfigManager#KEY_ENHANCED_4G_LTE_ON_BY_DEFAULT_BOOL
* @see android.telephony.CarrierConfigManager#KEY_CARRIER_VOLTE_AVAILABLE_BOOL
* @see #setAdvancedCallingSettingEnabled(boolean)
* @return true if the user's setting for advanced calling is enabled, false otherwise.
*/
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public boolean isAdvancedCallingSettingEnabled() {
try {
return getITelephony().isAdvancedCallingSettingEnabled(mSubId);
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
}
/**
* Modify the user’s setting for “Advanced Calling” or "Enhanced 4G LTE", which is used to
* enable MmTel IMS features, depending on the carrier configuration for the current
* subscription. If this setting is enabled, IMS voice and video telephony over IWLAN/LTE will
* be enabled as long as the carrier has provisioned these services for the specified
* subscription. Other IMS services (SMS/UT) are not affected by this user setting and depend on
* carrier requirements.
*
* Modifying this value may also trigger an IMS registration or deregistration, depending on
* whether or not the new value is enabled or disabled.
*
* Note: If the carrier configuration for advanced calling is not editable or hidden, this
* method will do nothing and will instead always use the default value.
*
* @see android.telephony.CarrierConfigManager#KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL
* @see android.telephony.CarrierConfigManager#KEY_EDITABLE_ENHANCED_4G_LTE_BOOL
* @see android.telephony.CarrierConfigManager#KEY_HIDE_ENHANCED_4G_LTE_BOOL
* @see android.telephony.CarrierConfigManager#KEY_ENHANCED_4G_LTE_ON_BY_DEFAULT_BOOL
* @see android.telephony.CarrierConfigManager#KEY_CARRIER_VOLTE_AVAILABLE_BOOL
* @see #isAdvancedCallingSettingEnabled()
*/
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
public void setAdvancedCallingSettingEnabled(boolean isEnabled) {
try {
getITelephony().setAdvancedCallingSettingEnabled(mSubId, isEnabled);
return;
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
}
/**
* Query the IMS MmTel capability for a given registration technology. This does not
* necessarily mean that we are registered and the capability is available, but rather the
* subscription is capable of this service over IMS.
*
* @see android.telephony.CarrierConfigManager#KEY_CARRIER_VOLTE_AVAILABLE_BOOL
* @see android.telephony.CarrierConfigManager#KEY_CARRIER_VT_AVAILABLE_BOOL
* @see android.telephony.CarrierConfigManager#KEY_CARRIER_IMS_GBA_REQUIRED_BOOL
* @see #isAvailable(int, int)
*
* @param imsRegTech The IMS registration technology, can be one of the following:
* {@link ImsRegistrationImplBase#REGISTRATION_TECH_LTE},
* {@link ImsRegistrationImplBase#REGISTRATION_TECH_IWLAN}
* @param capability The IMS MmTel capability to query, can be one of the following:
* {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_VOICE},
* {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_VIDEO,
* {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_UT},
* {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_SMS}
* @return {@code true} if the MmTel IMS capability is capable for this subscription, false
* otherwise.
*/
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public boolean isCapable(@MmTelFeature.MmTelCapabilities.MmTelCapability int capability,
@ImsRegistrationImplBase.ImsRegistrationTech int imsRegTech) {
try {
return getITelephony().isCapable(mSubId, capability, imsRegTech);
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
}
/**
* Query the availability of an IMS MmTel capability for a given registration technology. If
* a capability is available, IMS is registered and the service is currently available over IMS.
*
* @see #isCapable(int, int)
*
* @param imsRegTech The IMS registration technology, can be one of the following:
* {@link ImsRegistrationImplBase#REGISTRATION_TECH_LTE},
* {@link ImsRegistrationImplBase#REGISTRATION_TECH_IWLAN}
* @param capability The IMS MmTel capability to query, can be one of the following:
* {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_VOICE},
* {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_VIDEO,
* {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_UT},
* {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_SMS}
* @return {@code true} if the MmTel IMS capability is available for this subscription, false
* otherwise.
*/
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public boolean isAvailable(@MmTelFeature.MmTelCapabilities.MmTelCapability int capability,
@ImsRegistrationImplBase.ImsRegistrationTech int imsRegTech) {
try {
return getITelephony().isAvailable(mSubId, capability, imsRegTech);
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
}
/**
* The user's setting for whether or not they have enabled the "Video Calling" setting.
* @return true if the user’s “Video Calling” setting is currently enabled.
* @see #setVtSettingEnabled(boolean)
*/
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public boolean isVtSettingEnabled() {
try {
return getITelephony().isVtSettingEnabled(mSubId);
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
}
/**
* Change the user's setting for Video Telephony and enable the Video Telephony capability.
* @see #isVtSettingEnabled()
*/
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
public void setVtSettingEnabled(boolean isEnabled) {
try {
getITelephony().setVtSettingEnabled(mSubId, isEnabled);
return;
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
}
/**
* @return true if the user's setting for Voice over WiFi is enabled and false if it is not.
* @see #setVoWiFiSettingEnabled(boolean)
*/
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public boolean isVoWiFiSettingEnabled() {
try {
return getITelephony().isVoWiFiSettingEnabled(mSubId);
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
}
/**
* Sets the user's setting for whether or not Voice over WiFi is enabled.
* @param isEnabled true if the user's setting for Voice over WiFi is enabled, false otherwise=
* @see #isVoWiFiSettingEnabled()
*/
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
public void setVoWiFiSettingEnabled(boolean isEnabled) {
try {
getITelephony().setVoWiFiSettingEnabled(mSubId, isEnabled);
return;
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
}
/**
* @return true if the user's setting for Voice over WiFi while roaming is enabled, false
* if disabled.
* @see #setVoWiFiRoamingSettingEnabled(boolean)
*/
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public boolean isVoWiFiRoamingSettingEnabled() {
try {
return getITelephony().isVoWiFiRoamingSettingEnabled(mSubId);
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
}
/**
* Change the user's setting for Voice over WiFi while roaming.
* @param isEnabled true if the user's setting for Voice over WiFi while roaming is enabled,
* false otherwise.
* @see #isVoWiFiRoamingSettingEnabled()
*/
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
public void setVoWiFiRoamingSettingEnabled(boolean isEnabled) {
try {
getITelephony().setVoWiFiRoamingSettingEnabled(mSubId, isEnabled);
return;
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
}
/**
* Overrides the Voice over WiFi capability to true for IMS, but do not persist the setting.
* Typically used during the Voice over WiFi registration process for some carriers.
*
* @param isCapable true if the IMS stack should try to register for IMS over IWLAN, false
* otherwise.
* @param mode the Voice over WiFi mode preference to set, which can be one of the following:
* - {@link #WIFI_MODE_WIFI_ONLY}
* - {@link #WIFI_MODE_CELLULAR_PREFERRED}
* - {@link #WIFI_MODE_WIFI_PREFERRED}
* @see #setVoWiFiSettingEnabled(boolean)
*/
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
public void setVoWiFiNonPersistent(boolean isCapable, int mode) {
try {
getITelephony().setVoWiFiNonPersistent(mSubId, isCapable, mode);
return;
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
}
/**
* @return The Voice over WiFi Mode preference set by the user, which can be one of the
* following:
* - {@link #WIFI_MODE_WIFI_ONLY}
* - {@link #WIFI_MODE_CELLULAR_PREFERRED}
* - {@link #WIFI_MODE_WIFI_PREFERRED}
* @see #setVoWiFiSettingEnabled(boolean)
*/
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public @WiFiCallingMode int getVoWiFiModeSetting() {
try {
return getITelephony().getVoWiFiModeSetting(mSubId);
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
}
/**
* Set the user's preference for Voice over WiFi calling mode.
* @param mode The user's preference for the technology to register for IMS over, can be one of
* the following:
* - {@link #WIFI_MODE_WIFI_ONLY}
* - {@link #WIFI_MODE_CELLULAR_PREFERRED}
* - {@link #WIFI_MODE_WIFI_PREFERRED}
* @see #getVoWiFiModeSetting()
*/
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
public void setVoWiFiModeSetting(@WiFiCallingMode int mode) {
try {
getITelephony().setVoWiFiModeSetting(mSubId, mode);
return;
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
}
/**
* Set the user's preference for Voice over WiFi calling mode while the device is roaming on
* another network.
*
* @return The user's preference for the technology to register for IMS over when roaming on
* another network, can be one of the following:
* - {@link #WIFI_MODE_WIFI_ONLY}
* - {@link #WIFI_MODE_CELLULAR_PREFERRED}
* - {@link #WIFI_MODE_WIFI_PREFERRED}
* @see #setVoWiFiRoamingSettingEnabled(boolean)
*/
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public @WiFiCallingMode int getVoWiFiRoamingModeSetting() {
try {
return getITelephony().getVoWiFiRoamingModeSetting(mSubId);
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
}
/**
* Set the user's preference for Voice over WiFi mode while the device is roaming on another
* network.
*
* @param mode The user's preference for the technology to register for IMS over when roaming on
* another network, can be one of the following:
* - {@link #WIFI_MODE_WIFI_ONLY}
* - {@link #WIFI_MODE_CELLULAR_PREFERRED}
* - {@link #WIFI_MODE_WIFI_PREFERRED}
* @see #getVoWiFiRoamingModeSetting()
*/
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
public void setVoWiFiRoamingModeSetting(@WiFiCallingMode int mode) {
try {
getITelephony().setVoWiFiRoamingModeSetting(mSubId, mode);
return;
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
}
/**
* Sets the capability of RTT for IMS calls placed on this subscription.
*
* Note: This does not affect the value of
* {@link android.provider.Settings.Secure#RTT_CALLING_MODE}, which is the global user setting
* for RTT. That value is enabled/disabled separately by the user through the Accessibility
* settings.
* @param isEnabled if true RTT should be enabled during calls made on this subscription.
*/
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
public void setRttCapabilitySetting(boolean isEnabled) {
try {
getITelephony().setRttCapabilitySetting(mSubId, isEnabled);
return;
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
}
/**
* @return true if TTY over VoLTE is supported
* @see android.telecom.TelecomManager#getCurrentTtyMode
* @see android.telephony.CarrierConfigManager#KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL
*/
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
boolean isTtyOverVolteEnabled() {
try {
return getITelephony().isTtyOverVolteEnabled(mSubId);
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
}
private static boolean isImsAvailableOnDevice() {
IPackageManager pm = IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
if (pm == null) {
// For some reason package manger is not available.. This will fail internally anyways,
// so do not throw error and allow.
return true;
}
try {
return pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY_IMS, 0);
} catch (RemoteException e) {
// For some reason package manger is not available.. This will fail internally anyways,
// so do not throw error and allow.
}
return true;
}
private static ITelephony getITelephony() {
ITelephony binder = ITelephony.Stub.asInterface(
ServiceManager.getService(Context.TELEPHONY_SERVICE));
if (binder == null) {
throw new RuntimeException("Could not find Telephony Service.");
}
return binder;
}
}