1752 lines
78 KiB
Java
1752 lines
78 KiB
Java
![]() |
/*
|
|||
|
* 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.FlaggedApi;
|
|||
|
import android.annotation.IntDef;
|
|||
|
import android.annotation.NonNull;
|
|||
|
import android.annotation.RequiresFeature;
|
|||
|
import android.annotation.RequiresPermission;
|
|||
|
import android.annotation.SuppressAutoDoc;
|
|||
|
import android.annotation.SuppressLint;
|
|||
|
import android.annotation.SystemApi;
|
|||
|
import android.content.Context;
|
|||
|
import android.content.pm.PackageManager;
|
|||
|
import android.os.Binder;
|
|||
|
import android.os.RemoteException;
|
|||
|
import android.os.ServiceSpecificException;
|
|||
|
import android.telephony.AccessNetworkConstants;
|
|||
|
import android.telephony.BinderCacheManager;
|
|||
|
import android.telephony.CarrierConfigManager;
|
|||
|
import android.telephony.SubscriptionManager;
|
|||
|
import android.telephony.TelephonyFrameworkInitializer;
|
|||
|
import android.telephony.ims.aidl.IImsCapabilityCallback;
|
|||
|
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.IIntegerConsumer;
|
|||
|
import com.android.internal.telephony.ITelephony;
|
|||
|
import com.android.internal.telephony.flags.Flags;
|
|||
|
|
|||
|
import java.lang.annotation.Retention;
|
|||
|
import java.lang.annotation.RetentionPolicy;
|
|||
|
import java.util.Objects;
|
|||
|
import java.util.concurrent.Executor;
|
|||
|
import java.util.function.Consumer;
|
|||
|
|
|||
|
/**
|
|||
|
* 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.
|
|||
|
*
|
|||
|
* Use {@link android.telephony.ims.ImsManager#getImsMmTelManager(int)} to get an instance of this
|
|||
|
* manager.
|
|||
|
*/
|
|||
|
@RequiresFeature(PackageManager.FEATURE_TELEPHONY_IMS)
|
|||
|
public class ImsMmTelManager implements RegistrationManager {
|
|||
|
private static final String TAG = "ImsMmTelManager";
|
|||
|
|
|||
|
/**
|
|||
|
* @hide
|
|||
|
*/
|
|||
|
@Retention(RetentionPolicy.SOURCE)
|
|||
|
@IntDef(prefix = "WIFI_MODE_", value = {
|
|||
|
WIFI_MODE_UNKNOWN,
|
|||
|
WIFI_MODE_WIFI_ONLY,
|
|||
|
WIFI_MODE_CELLULAR_PREFERRED,
|
|||
|
WIFI_MODE_WIFI_PREFERRED
|
|||
|
})
|
|||
|
public @interface WiFiCallingMode {}
|
|||
|
|
|||
|
/**
|
|||
|
* Wifi calling mode is unknown. This is for initialization only.
|
|||
|
* @hide
|
|||
|
*/
|
|||
|
public static final int WIFI_MODE_UNKNOWN = -1;
|
|||
|
|
|||
|
/**
|
|||
|
* 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)
|
|||
|
* @deprecated Use {@link RegistrationManager.RegistrationCallback} instead.
|
|||
|
* @hide
|
|||
|
*/
|
|||
|
// Do not add to this class, add to RegistrationManager.RegistrationCallback instead.
|
|||
|
@Deprecated
|
|||
|
@SystemApi
|
|||
|
public static class RegistrationCallback extends RegistrationManager.RegistrationCallback {
|
|||
|
|
|||
|
/**
|
|||
|
* Notifies the framework when the IMS Provider is registered to the IMS network.
|
|||
|
*
|
|||
|
* @param imsTransportType the radio access technology.
|
|||
|
*/
|
|||
|
@Override
|
|||
|
public void onRegistered(@AccessNetworkConstants.TransportType int imsTransportType) {
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Notifies the framework when the IMS Provider is trying to register the IMS network.
|
|||
|
*
|
|||
|
* @param imsTransportType the radio access technology.
|
|||
|
*/
|
|||
|
@Override
|
|||
|
public void onRegistering(@AccessNetworkConstants.TransportType 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.
|
|||
|
*/
|
|||
|
@Override
|
|||
|
public void onUnregistered(@NonNull ImsReasonInfo info) {
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* A failure has occurred when trying to handover registration to another technology type.
|
|||
|
*
|
|||
|
* @param imsTransportType The transport type that has failed to handover registration to.
|
|||
|
* @param info A {@link ImsReasonInfo} that identifies the reason for failure.
|
|||
|
*/
|
|||
|
@Override
|
|||
|
public void onTechnologyChangeFailed(
|
|||
|
@AccessNetworkConstants.TransportType int imsTransportType,
|
|||
|
@NonNull ImsReasonInfo info) {
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Receives IMS capability status updates from the ImsService.
|
|||
|
*
|
|||
|
* @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;
|
|||
|
|
|||
|
final long callingIdentity = Binder.clearCallingIdentity();
|
|||
|
try {
|
|||
|
mExecutor.execute(() -> mLocalCallback.onCapabilitiesStatusChanged(
|
|||
|
new MmTelFeature.MmTelCapabilities(config)));
|
|||
|
} finally {
|
|||
|
restoreCallingIdentity(callingIdentity);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
@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.
|
|||
|
*
|
|||
|
* @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 final Context mContext;
|
|||
|
private final int mSubId;
|
|||
|
private final BinderCacheManager<ITelephony> mBinderCache;
|
|||
|
|
|||
|
// Cache Telephony Binder interfaces, one cache per process.
|
|||
|
private static final BinderCacheManager<ITelephony> sTelephonyCache =
|
|||
|
new BinderCacheManager<>(ImsMmTelManager::getITelephonyInterface);
|
|||
|
|
|||
|
/**
|
|||
|
* 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()
|
|||
|
*
|
|||
|
* <p>Requires Permission: {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE
|
|||
|
* READ_PRECISE_PHONE_STATE} or that the calling app has carrier privileges
|
|||
|
* (see {@link android.telephony.TelephonyManager#hasCarrierPrivileges}).
|
|||
|
*
|
|||
|
* @throws IllegalArgumentException if the subscription is invalid.
|
|||
|
* @deprecated Use {@link android.telephony.ims.ImsManager#getImsMmTelManager(int)} to get an
|
|||
|
* instance of this class.
|
|||
|
* @hide
|
|||
|
*/
|
|||
|
@SystemApi
|
|||
|
@Deprecated
|
|||
|
@SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236).
|
|||
|
@RequiresPermission(anyOf = {
|
|||
|
android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
|
|||
|
android.Manifest.permission.READ_PRECISE_PHONE_STATE
|
|||
|
})
|
|||
|
@SuppressLint("ManagerLookup")
|
|||
|
public static @NonNull ImsMmTelManager createForSubscriptionId(int subId) {
|
|||
|
if (!SubscriptionManager.isValidSubscriptionId(subId)) {
|
|||
|
throw new IllegalArgumentException("Invalid subscription ID");
|
|||
|
}
|
|||
|
|
|||
|
return new ImsMmTelManager(subId, sTelephonyCache);
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Only visible for testing, use {@link ImsManager#getImsMmTelManager(int)} instead.
|
|||
|
* @hide
|
|||
|
*/
|
|||
|
@VisibleForTesting
|
|||
|
public ImsMmTelManager(int subId, BinderCacheManager<ITelephony> binderCache) {
|
|||
|
this(null, subId, binderCache);
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Only visible for testing, use {@link ImsManager#getImsMmTelManager(int)} instead.
|
|||
|
* @hide
|
|||
|
*/
|
|||
|
@VisibleForTesting
|
|||
|
public ImsMmTelManager(Context context, int subId, BinderCacheManager<ITelephony> binderCache) {
|
|||
|
mContext = context;
|
|||
|
mSubId = subId;
|
|||
|
mBinderCache = binderCache;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Registers a {@link RegistrationCallback} with the system, which will provide registration
|
|||
|
* updates for the subscription specified in {@link ImsManager#getImsMmTelManager(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.
|
|||
|
* @deprecated Use {@link RegistrationManager#registerImsRegistrationCallback(Executor,
|
|||
|
* RegistrationManager.RegistrationCallback)} instead.
|
|||
|
* @hide
|
|||
|
*/
|
|||
|
@Deprecated
|
|||
|
@SystemApi
|
|||
|
@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.");
|
|||
|
}
|
|||
|
c.setExecutor(executor);
|
|||
|
|
|||
|
ITelephony iTelephony = getITelephony();
|
|||
|
if (iTelephony == null) {
|
|||
|
throw new ImsException("Could not find Telephony Service.",
|
|||
|
ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
|
|||
|
}
|
|||
|
|
|||
|
try {
|
|||
|
iTelephony.registerImsRegistrationCallback(mSubId, c.getBinder());
|
|||
|
} catch (ServiceSpecificException e) {
|
|||
|
if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
|
|||
|
// Rethrow as runtime error to keep API compatible.
|
|||
|
throw new IllegalArgumentException(e.getMessage());
|
|||
|
} else {
|
|||
|
throw new ImsException(e.getMessage(), e.errorCode);
|
|||
|
}
|
|||
|
} catch (RemoteException | IllegalStateException e) {
|
|||
|
throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
*
|
|||
|
* <p>Requires Permission: {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE
|
|||
|
* READ_PRECISE_PHONE_STATE} or that the calling app has carrier privileges
|
|||
|
* (see {@link android.telephony.TelephonyManager#hasCarrierPrivileges}).
|
|||
|
*
|
|||
|
* {@inheritDoc}
|
|||
|
*
|
|||
|
*/
|
|||
|
@Override
|
|||
|
@SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236).
|
|||
|
@RequiresPermission(anyOf = {
|
|||
|
android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
|
|||
|
android.Manifest.permission.READ_PRECISE_PHONE_STATE})
|
|||
|
public void registerImsRegistrationCallback(@NonNull @CallbackExecutor Executor executor,
|
|||
|
@NonNull RegistrationManager.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.");
|
|||
|
}
|
|||
|
c.setExecutor(executor);
|
|||
|
|
|||
|
ITelephony iTelephony = getITelephony();
|
|||
|
if (iTelephony == null) {
|
|||
|
throw new ImsException("Could not find Telephony Service.",
|
|||
|
ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
|
|||
|
}
|
|||
|
|
|||
|
try {
|
|||
|
iTelephony.registerImsRegistrationCallback(mSubId, c.getBinder());
|
|||
|
} catch (ServiceSpecificException e) {
|
|||
|
throw new ImsException(e.getMessage(), e.errorCode);
|
|||
|
} 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)
|
|||
|
* @deprecated Use {@link #unregisterImsRegistrationCallback(
|
|||
|
* RegistrationManager.RegistrationCallback)}.
|
|||
|
* @hide
|
|||
|
*/
|
|||
|
@Deprecated
|
|||
|
@SystemApi
|
|||
|
@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.");
|
|||
|
}
|
|||
|
|
|||
|
ITelephony iTelephony = getITelephony();
|
|||
|
if (iTelephony == null) {
|
|||
|
throw new RuntimeException("Could not find Telephony Service.");
|
|||
|
}
|
|||
|
|
|||
|
try {
|
|||
|
iTelephony.unregisterImsRegistrationCallback(mSubId, c.getBinder());
|
|||
|
} catch (RemoteException e) {
|
|||
|
throw e.rethrowAsRuntimeException();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
*
|
|||
|
* <p>Requires Permission: {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE
|
|||
|
* READ_PRECISE_PHONE_STATE} or that the calling app has carrier privileges
|
|||
|
* (see {@link android.telephony.TelephonyManager#hasCarrierPrivileges}).
|
|||
|
* Access by profile owners is deprecated and will be removed in a future release.
|
|||
|
*
|
|||
|
*{@inheritDoc}
|
|||
|
*/
|
|||
|
@Override
|
|||
|
@SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236).
|
|||
|
@RequiresPermission(anyOf = {
|
|||
|
android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
|
|||
|
android.Manifest.permission.READ_PRECISE_PHONE_STATE})
|
|||
|
public void unregisterImsRegistrationCallback(
|
|||
|
@NonNull RegistrationManager.RegistrationCallback c) {
|
|||
|
if (c == null) {
|
|||
|
throw new IllegalArgumentException("Must include a non-null RegistrationCallback.");
|
|||
|
}
|
|||
|
|
|||
|
ITelephony iTelephony = getITelephony();
|
|||
|
if (iTelephony == null) {
|
|||
|
throw new RuntimeException("Could not find Telephony Service.");
|
|||
|
}
|
|||
|
|
|||
|
try {
|
|||
|
iTelephony.unregisterImsRegistrationCallback(mSubId, c.getBinder());
|
|||
|
} catch (RemoteException e) {
|
|||
|
throw e.rethrowAsRuntimeException();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Registers a {@link RegistrationCallback} with the system, which will provide IMS emergency
|
|||
|
* registration updates for the subscription specified in
|
|||
|
* {@link ImsManager#getImsMmTelManager(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 emergency registration state.
|
|||
|
* Emergency registration callback is available when there is valid SIM card.
|
|||
|
* <p>This API requires one of the following:
|
|||
|
* <ul>
|
|||
|
* <li>The caller holds the READ_PRECISE_PHONE_STATE permission.</li>
|
|||
|
* <li>If the caller is the device or profile owner, the caller holds the
|
|||
|
* {@link Manifest.permission#READ_PRECISE_PHONE_STATE} permission.</li>
|
|||
|
* <li>The caller has carrier privileges (see
|
|||
|
* {@link android.telephony.TelephonyManager#hasCarrierPrivileges}) on any
|
|||
|
* active subscription.</li>
|
|||
|
* </ul>
|
|||
|
* <p>The profile owner is an app that owns a managed profile on the device; for more details
|
|||
|
* see <a href="https://developer.android.com/work/managed-profiles">Work profiles</a>.
|
|||
|
* Access by profile owners is deprecated and will be removed in a future release.
|
|||
|
*
|
|||
|
* @param executor The executor the callback events should be run on.
|
|||
|
* @param c The {@link RegistrationCallback} to be added.
|
|||
|
* @see #unregisterImsEmergencyRegistrationCallback
|
|||
|
* @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.
|
|||
|
* @hide
|
|||
|
*/
|
|||
|
@SystemApi
|
|||
|
@FlaggedApi(Flags.FLAG_EMERGENCY_REGISTRATION_STATE)
|
|||
|
public void registerImsEmergencyRegistrationCallback(
|
|||
|
@NonNull @CallbackExecutor Executor executor,
|
|||
|
@NonNull RegistrationManager.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.");
|
|||
|
}
|
|||
|
c.setExecutor(executor);
|
|||
|
|
|||
|
ITelephony iTelephony = getITelephony();
|
|||
|
if (iTelephony == null) {
|
|||
|
throw new ImsException("Could not find Telephony Service.",
|
|||
|
ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
|
|||
|
}
|
|||
|
|
|||
|
try {
|
|||
|
iTelephony.registerImsEmergencyRegistrationCallback(mSubId, c.getBinder());
|
|||
|
} catch (ServiceSpecificException e) {
|
|||
|
throw new ImsException(e.getMessage(), e.errorCode);
|
|||
|
} catch (RemoteException e) {
|
|||
|
throw e.rethrowAsRuntimeException();
|
|||
|
} catch (IllegalStateException e) {
|
|||
|
throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Removes an existing {@link RegistrationCallback} for Emergency IMS registration.
|
|||
|
*
|
|||
|
* 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.
|
|||
|
* <p>This API requires one of the following:
|
|||
|
* <ul>
|
|||
|
* <li>The caller holds the READ_PRECISE_PHONE_STATE permission.</li>
|
|||
|
* <li>If the caller is the device or profile owner, the caller holds the
|
|||
|
* {@link Manifest.permission#READ_PRECISE_PHONE_STATE} permission.</li>
|
|||
|
* <li>The caller has carrier privileges (see
|
|||
|
* {@link android.telephony.TelephonyManager#hasCarrierPrivileges}) on any
|
|||
|
* active subscription.</li>
|
|||
|
* </ul>
|
|||
|
* <p>The profile owner is an app that owns a managed profile on the device; for more details
|
|||
|
* see <a href="https://developer.android.com/work/managed-profiles">Work profiles</a>.
|
|||
|
* Access by profile owners is deprecated and will be removed in a future release.
|
|||
|
*
|
|||
|
* @param c The {@link RegistrationCallback} to be removed.
|
|||
|
* @see android.telephony.SubscriptionManager.OnSubscriptionsChangedListener
|
|||
|
* @see #registerImsEmergencyRegistrationCallback(Executor,
|
|||
|
* RegistrationManager.RegistrationCallback)
|
|||
|
* @hide
|
|||
|
*/
|
|||
|
@SystemApi
|
|||
|
@FlaggedApi(Flags.FLAG_EMERGENCY_REGISTRATION_STATE)
|
|||
|
public void unregisterImsEmergencyRegistrationCallback(
|
|||
|
@NonNull RegistrationManager.RegistrationCallback c) {
|
|||
|
if (c == null) {
|
|||
|
throw new IllegalArgumentException("Must include a non-null RegistrationCallback.");
|
|||
|
}
|
|||
|
|
|||
|
ITelephony iTelephony = getITelephony();
|
|||
|
if (iTelephony == null) {
|
|||
|
Log.w("ImsMmTelManager", "Could not find Telephony Service.");
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
try {
|
|||
|
iTelephony.unregisterImsEmergencyRegistrationCallback(mSubId, c.getBinder());
|
|||
|
} catch (RemoteException e) {
|
|||
|
throw e.rethrowAsRuntimeException();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* {@inheritDoc}
|
|||
|
* @hide
|
|||
|
*/
|
|||
|
@Override
|
|||
|
@SystemApi
|
|||
|
@RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
|
|||
|
public void getRegistrationState(@NonNull @CallbackExecutor Executor executor,
|
|||
|
@NonNull @ImsRegistrationState Consumer<Integer> stateCallback) {
|
|||
|
if (stateCallback == null) {
|
|||
|
throw new IllegalArgumentException("Must include a non-null callback.");
|
|||
|
}
|
|||
|
if (executor == null) {
|
|||
|
throw new IllegalArgumentException("Must include a non-null Executor.");
|
|||
|
}
|
|||
|
|
|||
|
ITelephony iTelephony = getITelephony();
|
|||
|
if (iTelephony == null) {
|
|||
|
throw new RuntimeException("Could not find Telephony Service.");
|
|||
|
}
|
|||
|
|
|||
|
try {
|
|||
|
iTelephony.getImsMmTelRegistrationState(mSubId, new IIntegerConsumer.Stub() {
|
|||
|
@Override
|
|||
|
public void accept(int result) {
|
|||
|
final long identity = Binder.clearCallingIdentity();
|
|||
|
try {
|
|||
|
executor.execute(() -> stateCallback.accept(result));
|
|||
|
} finally {
|
|||
|
Binder.restoreCallingIdentity(identity);
|
|||
|
}
|
|||
|
}
|
|||
|
});
|
|||
|
} catch (ServiceSpecificException | RemoteException e) {
|
|||
|
Log.w("ImsMmTelManager", "Error getting registration state: " + e);
|
|||
|
executor.execute(() -> stateCallback.accept(REGISTRATION_STATE_NOT_REGISTERED));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* <p>Requires Permission: {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE
|
|||
|
* READ_PRECISE_PHONE_STATE} or that the calling app has carrier privileges
|
|||
|
* (see {@link android.telephony.TelephonyManager#hasCarrierPrivileges}).
|
|||
|
* Access by profile owners is deprecated and will be removed in a future release.
|
|||
|
*
|
|||
|
*{@inheritDoc}
|
|||
|
*/
|
|||
|
@Override
|
|||
|
@SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236).
|
|||
|
@RequiresPermission(anyOf = {
|
|||
|
android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
|
|||
|
android.Manifest.permission.READ_PRECISE_PHONE_STATE})
|
|||
|
public void getRegistrationTransportType(@NonNull @CallbackExecutor Executor executor,
|
|||
|
@NonNull @AccessNetworkConstants.TransportType
|
|||
|
Consumer<Integer> transportTypeCallback) {
|
|||
|
if (transportTypeCallback == null) {
|
|||
|
throw new IllegalArgumentException("Must include a non-null callback.");
|
|||
|
}
|
|||
|
if (executor == null) {
|
|||
|
throw new IllegalArgumentException("Must include a non-null Executor.");
|
|||
|
}
|
|||
|
|
|||
|
ITelephony iTelephony = getITelephony();
|
|||
|
if (iTelephony == null) {
|
|||
|
throw new RuntimeException("Could not find Telephony Service.");
|
|||
|
}
|
|||
|
|
|||
|
try {
|
|||
|
iTelephony.getImsMmTelRegistrationTransportType(mSubId,
|
|||
|
new IIntegerConsumer.Stub() {
|
|||
|
@Override
|
|||
|
public void accept(int result) {
|
|||
|
final long identity = Binder.clearCallingIdentity();
|
|||
|
try {
|
|||
|
executor.execute(() -> transportTypeCallback.accept(result));
|
|||
|
} finally {
|
|||
|
Binder.restoreCallingIdentity(identity);
|
|||
|
}
|
|||
|
}
|
|||
|
});
|
|||
|
} catch (ServiceSpecificException | RemoteException e) {
|
|||
|
Log.w("ImsMmTelManager", "Error getting transport type: " + e);
|
|||
|
executor.execute(() -> transportTypeCallback.accept(
|
|||
|
AccessNetworkConstants.TRANSPORT_TYPE_INVALID));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Registers a {@link CapabilityCallback} with the system, which will provide MmTel service
|
|||
|
* availability updates for the subscription specified in
|
|||
|
* {@link ImsManager#getImsMmTelManager(int)}.
|
|||
|
*
|
|||
|
* Use {@link SubscriptionManager.OnSubscriptionsChangedListener} to listen to
|
|||
|
* subscription changed events and call
|
|||
|
* {@link #unregisterMmTelCapabilityCallback(CapabilityCallback)} to clean up.
|
|||
|
* <p>This API requires one of the following:
|
|||
|
* <ul>
|
|||
|
* <li>The caller holds the READ_PRECISE_PHONE_STATE permission.</li>
|
|||
|
* <li>If the caller is the device or profile owner, the caller holds the
|
|||
|
* {@link Manifest.permission#READ_PRECISE_PHONE_STATE} permission.</li>
|
|||
|
* <li>The caller has carrier privileges (see
|
|||
|
* {@link android.telephony.TelephonyManager#hasCarrierPrivileges}) on any
|
|||
|
* active subscription.</li>
|
|||
|
* </ul>
|
|||
|
* <p>The profile owner is an app that owns a managed profile on the device; for more details
|
|||
|
* see <a href="https://developer.android.com/work/managed-profiles">Work profiles</a>.
|
|||
|
* Access by profile owners is deprecated and will be removed in a future release.
|
|||
|
*
|
|||
|
* 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 ImsException if the subscription associated with this callback is valid, but
|
|||
|
* the {@code 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.
|
|||
|
*/
|
|||
|
@SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236).
|
|||
|
@RequiresPermission(anyOf = {
|
|||
|
android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
|
|||
|
android.Manifest.permission.READ_PRECISE_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.");
|
|||
|
}
|
|||
|
c.setExecutor(executor);
|
|||
|
|
|||
|
ITelephony iTelephony = getITelephony();
|
|||
|
if (iTelephony == null) {
|
|||
|
throw new ImsException("Could not find Telephony Service.",
|
|||
|
ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
|
|||
|
}
|
|||
|
|
|||
|
try {
|
|||
|
iTelephony.registerMmTelCapabilityCallback(mSubId, c.getBinder());
|
|||
|
} catch (ServiceSpecificException e) {
|
|||
|
throw new ImsException(e.getMessage(), e.errorCode);
|
|||
|
} 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.
|
|||
|
* <p>This API requires one of the following:
|
|||
|
* <ul>
|
|||
|
* <li>The caller holds the READ_PRECISE_PHONE_STATE permission.</li>
|
|||
|
* <li>If the caller is the device or profile owner, the caller holds the
|
|||
|
* {@link Manifest.permission#READ_PRECISE_PHONE_STATE} permission.</li>
|
|||
|
* <li>The caller has carrier privileges (see
|
|||
|
* {@link android.telephony.TelephonyManager#hasCarrierPrivileges}) on any
|
|||
|
* active subscription.</li>
|
|||
|
* </ul>
|
|||
|
* <p>The profile owner is an app that owns a managed profile on the device; for more details
|
|||
|
* see <a href="https://developer.android.com/work/managed-profiles">Work profiles</a>.
|
|||
|
* Access by profile owners is deprecated and will be removed in a future release.
|
|||
|
*
|
|||
|
* @param c The MmTel {@link CapabilityCallback} to be removed.
|
|||
|
* @see #registerMmTelCapabilityCallback(Executor, CapabilityCallback)
|
|||
|
*/
|
|||
|
@SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236).
|
|||
|
@RequiresPermission(anyOf = {
|
|||
|
android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
|
|||
|
android.Manifest.permission.READ_PRECISE_PHONE_STATE})
|
|||
|
public void unregisterMmTelCapabilityCallback(@NonNull CapabilityCallback c) {
|
|||
|
if (c == null) {
|
|||
|
throw new IllegalArgumentException("Must include a non-null RegistrationCallback.");
|
|||
|
}
|
|||
|
|
|||
|
ITelephony iTelephony = getITelephony();
|
|||
|
if (iTelephony == null) {
|
|||
|
Log.w("ImsMmTelManager", "Could not find Telephony Service.");
|
|||
|
return;
|
|||
|
}
|
|||
|
try {
|
|||
|
iTelephony.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.
|
|||
|
* <p>
|
|||
|
* Note: If the carrier configuration for advanced calling is not editable or hidden, this
|
|||
|
* method will always return the default value.
|
|||
|
* <p>This API requires one of the following:
|
|||
|
* <ul>
|
|||
|
* <li>The caller holds the READ_PRECISE_PHONE_STATE permission.</li>
|
|||
|
* <li>If the caller is the device or profile owner, the caller holds the
|
|||
|
* {@link Manifest.permission#READ_PRECISE_PHONE_STATE} permission.</li>
|
|||
|
* <li>The caller has carrier privileges (see
|
|||
|
* {@link android.telephony.TelephonyManager#hasCarrierPrivileges}) on any
|
|||
|
* active subscription.</li>
|
|||
|
* </ul>
|
|||
|
* <p>The profile owner is an app that owns a managed profile on the device; for more details
|
|||
|
* see <a href="https://developer.android.com/work/managed-profiles">Work profiles</a>.
|
|||
|
* Access by profile owners is deprecated and will be removed in a future release.
|
|||
|
*
|
|||
|
* @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
|
|||
|
* @throws IllegalArgumentException if the subscription associated with this operation is not
|
|||
|
* active (SIM is not inserted, ESIM inactive) or invalid.
|
|||
|
* @throws UnsupportedOperationException If the device does not have
|
|||
|
* {@link PackageManager#FEATURE_TELEPHONY_IMS}.
|
|||
|
* @return true if the user's setting for advanced calling is enabled, false otherwise.
|
|||
|
*/
|
|||
|
@SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236).
|
|||
|
@RequiresPermission(anyOf = {
|
|||
|
android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
|
|||
|
android.Manifest.permission.READ_PRECISE_PHONE_STATE})
|
|||
|
public boolean isAdvancedCallingSettingEnabled() {
|
|||
|
ITelephony iTelephony = getITelephony();
|
|||
|
if (iTelephony == null) {
|
|||
|
throw new RuntimeException("Could not find Telephony Service.");
|
|||
|
}
|
|||
|
|
|||
|
try {
|
|||
|
return iTelephony.isAdvancedCallingSettingEnabled(mSubId);
|
|||
|
} catch (ServiceSpecificException e) {
|
|||
|
if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
|
|||
|
// Rethrow as runtime error to keep API compatible.
|
|||
|
throw new IllegalArgumentException(e.getMessage());
|
|||
|
} else {
|
|||
|
throw new RuntimeException(e.getMessage());
|
|||
|
}
|
|||
|
} 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()
|
|||
|
* @throws IllegalArgumentException if the subscription associated with this operation is not
|
|||
|
* active (SIM is not inserted, ESIM inactive) or invalid.
|
|||
|
* @throws UnsupportedOperationException If the device does not have
|
|||
|
* {@link PackageManager#FEATURE_TELEPHONY_IMS}.
|
|||
|
* @hide
|
|||
|
*/
|
|||
|
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
|
|||
|
@SystemApi
|
|||
|
public void setAdvancedCallingSettingEnabled(boolean isEnabled) {
|
|||
|
ITelephony iTelephony = getITelephony();
|
|||
|
if (iTelephony == null) {
|
|||
|
throw new RuntimeException("Could not find Telephony Service.");
|
|||
|
}
|
|||
|
|
|||
|
try {
|
|||
|
iTelephony.setAdvancedCallingSettingEnabled(mSubId, isEnabled);
|
|||
|
} catch (ServiceSpecificException e) {
|
|||
|
if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
|
|||
|
// Rethrow as runtime error to keep API compatible.
|
|||
|
throw new IllegalArgumentException(e.getMessage());
|
|||
|
} else {
|
|||
|
throw new RuntimeException(e.getMessage());
|
|||
|
}
|
|||
|
} 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.
|
|||
|
* @param capability The IMS MmTel capability to query.
|
|||
|
* @return {@code true} if the MmTel IMS capability is capable for this subscription, false
|
|||
|
* otherwise.
|
|||
|
* @throws UnsupportedOperationException If the device does not have
|
|||
|
* {@link PackageManager#FEATURE_TELEPHONY_IMS}.
|
|||
|
* @hide
|
|||
|
*/
|
|||
|
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
|
|||
|
@SystemApi
|
|||
|
public boolean isCapable(@MmTelFeature.MmTelCapabilities.MmTelCapability int capability,
|
|||
|
@ImsRegistrationImplBase.ImsRegistrationTech int imsRegTech) {
|
|||
|
ITelephony iTelephony = getITelephony();
|
|||
|
if (iTelephony == null) {
|
|||
|
throw new RuntimeException("Could not find Telephony Service.");
|
|||
|
}
|
|||
|
|
|||
|
try {
|
|||
|
return iTelephony.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.
|
|||
|
* @param capability The IMS MmTel capability to query.
|
|||
|
* @return {@code true} if the MmTel IMS capability is available for this subscription, false
|
|||
|
* otherwise.
|
|||
|
* @throws UnsupportedOperationException If the device does not have
|
|||
|
* {@link PackageManager#FEATURE_TELEPHONY_IMS}.
|
|||
|
* @hide
|
|||
|
*/
|
|||
|
@SystemApi
|
|||
|
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
|
|||
|
public boolean isAvailable(@MmTelFeature.MmTelCapabilities.MmTelCapability int capability,
|
|||
|
@ImsRegistrationImplBase.ImsRegistrationTech int imsRegTech) {
|
|||
|
ITelephony iTelephony = getITelephony();
|
|||
|
if (iTelephony == null) {
|
|||
|
throw new RuntimeException("Could not find Telephony Service.");
|
|||
|
}
|
|||
|
|
|||
|
try {
|
|||
|
return iTelephony.isAvailable(mSubId, capability, imsRegTech);
|
|||
|
} catch (RemoteException e) {
|
|||
|
throw e.rethrowAsRuntimeException();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Query whether or not the requested MmTel capability is supported by the carrier on the
|
|||
|
* specified network transport.
|
|||
|
* <p>
|
|||
|
* This is a configuration option and does not change. The only time this may change is if a
|
|||
|
* new IMS configuration is loaded when there is a
|
|||
|
* {@link CarrierConfigManager#ACTION_CARRIER_CONFIG_CHANGED} broadcast for this subscription.
|
|||
|
* @param capability The capability that is being queried for support on the carrier network.
|
|||
|
* @param transportType The transport type of the capability to check support for.
|
|||
|
* @param executor The executor that the callback will be called with.
|
|||
|
* @param callback A consumer containing a Boolean result specifying whether or not the
|
|||
|
* capability is supported on this carrier network for the transport specified.
|
|||
|
* @throws ImsException if the subscription is no longer valid or the IMS service is not
|
|||
|
* available.
|
|||
|
* @hide
|
|||
|
*/
|
|||
|
@SystemApi
|
|||
|
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
|
|||
|
public void isSupported(@MmTelFeature.MmTelCapabilities.MmTelCapability int capability,
|
|||
|
@AccessNetworkConstants.TransportType int transportType,
|
|||
|
@NonNull @CallbackExecutor Executor executor,
|
|||
|
@NonNull Consumer<Boolean> callback) throws ImsException {
|
|||
|
if (callback == null) {
|
|||
|
throw new IllegalArgumentException("Must include a non-null Consumer.");
|
|||
|
}
|
|||
|
if (executor == null) {
|
|||
|
throw new IllegalArgumentException("Must include a non-null Executor.");
|
|||
|
}
|
|||
|
|
|||
|
ITelephony iTelephony = getITelephony();
|
|||
|
if (iTelephony == null) {
|
|||
|
throw new ImsException("Could not find Telephony Service.",
|
|||
|
ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
|
|||
|
}
|
|||
|
|
|||
|
try {
|
|||
|
iTelephony.isMmTelCapabilitySupported(mSubId, new IIntegerConsumer.Stub() {
|
|||
|
@Override
|
|||
|
public void accept(int result) {
|
|||
|
final long identity = Binder.clearCallingIdentity();
|
|||
|
try {
|
|||
|
executor.execute(() -> callback.accept(result == 1));
|
|||
|
} finally {
|
|||
|
Binder.restoreCallingIdentity(identity);
|
|||
|
}
|
|||
|
}
|
|||
|
}, capability, transportType);
|
|||
|
} catch (ServiceSpecificException sse) {
|
|||
|
throw new ImsException(sse.getMessage(), sse.errorCode);
|
|||
|
} catch (RemoteException e) {
|
|||
|
e.rethrowAsRuntimeException();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* The user's setting for whether or not they have enabled the "Video Calling" setting.
|
|||
|
*
|
|||
|
* <p>
|
|||
|
* Note: If the carrier configuration for advanced calling is not editable or hidden, this
|
|||
|
* method will always return the default value.
|
|||
|
* <p>This API requires one of the following:
|
|||
|
* <ul>
|
|||
|
* <li>The caller holds the READ_PRECISE_PHONE_STATE permission.</li>
|
|||
|
* <li>If the caller is the device or profile owner, the caller holds the
|
|||
|
* {@link Manifest.permission#READ_PRECISE_PHONE_STATE} permission.</li>
|
|||
|
* <li>The caller has carrier privileges (see
|
|||
|
* {@link android.telephony.TelephonyManager#hasCarrierPrivileges}) on any
|
|||
|
* active subscription.</li>
|
|||
|
* </ul>
|
|||
|
* <p>The profile owner is an app that owns a managed profile on the device; for more details
|
|||
|
* see <a href="https://developer.android.com/work/managed-profiles">Work profiles</a>.
|
|||
|
* Access by profile owners is deprecated and will be removed in a future release.
|
|||
|
*
|
|||
|
* @throws IllegalArgumentException if the subscription associated with this operation is not
|
|||
|
* active (SIM is not inserted, ESIM inactive) or invalid.
|
|||
|
* @throws UnsupportedOperationException If the device does not have
|
|||
|
* {@link PackageManager#FEATURE_TELEPHONY_IMS}.
|
|||
|
* @return true if the user’s “Video Calling” setting is currently enabled.
|
|||
|
*/
|
|||
|
@RequiresPermission(anyOf = {
|
|||
|
android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
|
|||
|
android.Manifest.permission.READ_PRECISE_PHONE_STATE})
|
|||
|
@SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236).
|
|||
|
public boolean isVtSettingEnabled() {
|
|||
|
ITelephony iTelephony = getITelephony();
|
|||
|
if (iTelephony == null) {
|
|||
|
throw new RuntimeException("Could not find Telephony Service.");
|
|||
|
}
|
|||
|
|
|||
|
try {
|
|||
|
return iTelephony.isVtSettingEnabled(mSubId);
|
|||
|
} catch (ServiceSpecificException e) {
|
|||
|
if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
|
|||
|
// Rethrow as runtime error to keep API compatible.
|
|||
|
throw new IllegalArgumentException(e.getMessage());
|
|||
|
} else {
|
|||
|
throw new RuntimeException(e.getMessage());
|
|||
|
}
|
|||
|
} catch (RemoteException e) {
|
|||
|
throw e.rethrowAsRuntimeException();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Change the user's setting for Video Telephony and enable the Video Telephony capability.
|
|||
|
*
|
|||
|
* @throws IllegalArgumentException if the subscription associated with this operation is not
|
|||
|
* active (SIM is not inserted, ESIM inactive) or invalid.
|
|||
|
* @throws UnsupportedOperationException If the device does not have
|
|||
|
* {@link PackageManager#FEATURE_TELEPHONY_IMS}.
|
|||
|
* @see #isVtSettingEnabled()
|
|||
|
* @hide
|
|||
|
*/
|
|||
|
@SystemApi
|
|||
|
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
|
|||
|
public void setVtSettingEnabled(boolean isEnabled) {
|
|||
|
ITelephony iTelephony = getITelephony();
|
|||
|
if (iTelephony == null) {
|
|||
|
throw new RuntimeException("Could not find Telephony Service.");
|
|||
|
}
|
|||
|
|
|||
|
try {
|
|||
|
iTelephony.setVtSettingEnabled(mSubId, isEnabled);
|
|||
|
} catch (ServiceSpecificException e) {
|
|||
|
if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
|
|||
|
// Rethrow as runtime error to keep API compatible.
|
|||
|
throw new IllegalArgumentException(e.getMessage());
|
|||
|
} else {
|
|||
|
throw new RuntimeException(e.getMessage());
|
|||
|
}
|
|||
|
} 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.
|
|||
|
*
|
|||
|
* <p>This API requires one of the following:
|
|||
|
* <ul>
|
|||
|
* <li>The caller holds the READ_PRECISE_PHONE_STATE permission.</li>
|
|||
|
* <li>If the caller is the device or profile owner, the caller holds the
|
|||
|
* {@link Manifest.permission#READ_PRECISE_PHONE_STATE} permission.</li>
|
|||
|
* <li>The caller has carrier privileges (see
|
|||
|
* {@link android.telephony.TelephonyManager#hasCarrierPrivileges}) on any
|
|||
|
* active subscription.</li>
|
|||
|
* </ul>
|
|||
|
* <p>The profile owner is an app that owns a managed profile on the device; for more details
|
|||
|
* see <a href="https://developer.android.com/work/managed-profiles">Work profiles</a>.
|
|||
|
* Access by profile owners is deprecated and will be removed in a future release.
|
|||
|
*
|
|||
|
* @throws IllegalArgumentException if the subscription associated with this operation is not
|
|||
|
* active (SIM is not inserted, ESIM inactive) or invalid.
|
|||
|
* @throws UnsupportedOperationException If the device does not have
|
|||
|
* {@link PackageManager#FEATURE_TELEPHONY_IMS}.
|
|||
|
*/
|
|||
|
@SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236).
|
|||
|
@RequiresPermission(anyOf = {
|
|||
|
android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
|
|||
|
android.Manifest.permission.READ_PRECISE_PHONE_STATE})
|
|||
|
public boolean isVoWiFiSettingEnabled() {
|
|||
|
ITelephony iTelephony = getITelephony();
|
|||
|
if (iTelephony == null) {
|
|||
|
throw new RuntimeException("Could not find Telephony Service.");
|
|||
|
}
|
|||
|
|
|||
|
try {
|
|||
|
return iTelephony.isVoWiFiSettingEnabled(mSubId);
|
|||
|
} catch (ServiceSpecificException e) {
|
|||
|
if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
|
|||
|
// Rethrow as runtime error to keep API compatible.
|
|||
|
throw new IllegalArgumentException(e.getMessage());
|
|||
|
} else {
|
|||
|
throw new RuntimeException(e.getMessage());
|
|||
|
}
|
|||
|
} catch (RemoteException e) {
|
|||
|
throw e.rethrowAsRuntimeException();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Sets the user's setting for whether or not Voice over WiFi is enabled.
|
|||
|
*
|
|||
|
* @throws IllegalArgumentException if the subscription associated with this operation is not
|
|||
|
* active (SIM is not inserted, ESIM inactive) or invalid.
|
|||
|
* @throws UnsupportedOperationException If the device does not have
|
|||
|
* {@link PackageManager#FEATURE_TELEPHONY_IMS}.
|
|||
|
* @param isEnabled true if the user's setting for Voice over WiFi is enabled, false otherwise=
|
|||
|
* @see #isVoWiFiSettingEnabled()
|
|||
|
* @hide
|
|||
|
*/
|
|||
|
@SystemApi
|
|||
|
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
|
|||
|
public void setVoWiFiSettingEnabled(boolean isEnabled) {
|
|||
|
ITelephony iTelephony = getITelephony();
|
|||
|
if (iTelephony == null) {
|
|||
|
throw new RuntimeException("Could not find Telephony Service.");
|
|||
|
}
|
|||
|
|
|||
|
try {
|
|||
|
iTelephony.setVoWiFiSettingEnabled(mSubId, isEnabled);
|
|||
|
} catch (ServiceSpecificException e) {
|
|||
|
if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
|
|||
|
// Rethrow as runtime error to keep API compatible.
|
|||
|
throw new IllegalArgumentException(e.getMessage());
|
|||
|
} else {
|
|||
|
throw new RuntimeException(e.getMessage());
|
|||
|
}
|
|||
|
} catch (RemoteException e) {
|
|||
|
throw e.rethrowAsRuntimeException();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* This configuration is meaningful only on dual sim device.
|
|||
|
* If enabled, this will result in the device setting up IMS of all other
|
|||
|
* active subscriptions over the INTERNET APN of the primary default data subscription
|
|||
|
* when any of those subscriptions are roaming or out of service and if wifi is not available
|
|||
|
* for VoWifi. This feature will be disabled if
|
|||
|
* {@link CarrierConfigManager#KEY_CARRIER_CROSS_SIM_IMS_AVAILABLE_BOOL} is set to false.
|
|||
|
* <p>Following are the conditions in which system will try to register IMS over
|
|||
|
* cross sim
|
|||
|
* <ul>
|
|||
|
* <li>Wifi is not available, one SIM is roaming and the default data
|
|||
|
* SIM is in home network. Then roaming SIM IMS will be registered over INTERNET APN of the
|
|||
|
* default data subscription </li>
|
|||
|
* <li>Wifi is not available, one SIM is out of service and the default data
|
|||
|
* SIM is in home network. Then out of service SIM IMS will be registered over INTERNET
|
|||
|
* APN of the default data subscription </li>
|
|||
|
* </ul>
|
|||
|
* <p>This API requires one of the following:
|
|||
|
* <ul>
|
|||
|
* <li>The caller holds the READ_PRECISE_PHONE_STATE permission.</li>
|
|||
|
* <li>If the caller is the device or profile owner, the caller holds the
|
|||
|
* {@link Manifest.permission#READ_PRECISE_PHONE_STATE} permission.</li>
|
|||
|
* <li>The caller has carrier privileges (see
|
|||
|
* {@link android.telephony.TelephonyManager#hasCarrierPrivileges}) on any
|
|||
|
* active subscription.</li>
|
|||
|
* </ul>
|
|||
|
* <p>The profile owner is an app that owns a managed profile on the device; for more details
|
|||
|
* see <a href="https://developer.android.com/work/managed-profiles">Work profiles</a>.
|
|||
|
* Access by profile owners is deprecated and will be removed in a future release.
|
|||
|
*
|
|||
|
* @throws ImsException if the IMS service associated with this subscription is not available or
|
|||
|
* the IMS service is not available.
|
|||
|
* @throws UnsupportedOperationException If the device does not have
|
|||
|
* {@link PackageManager#FEATURE_TELEPHONY_IMS}.
|
|||
|
* @return true if the user's setting for Voice over Cross SIM is enabled and false if it is not
|
|||
|
*/
|
|||
|
@SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236).
|
|||
|
@RequiresPermission(anyOf = {
|
|||
|
android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
|
|||
|
android.Manifest.permission.READ_PRECISE_PHONE_STATE})
|
|||
|
public boolean isCrossSimCallingEnabled() throws ImsException {
|
|||
|
ITelephony iTelephony = getITelephony();
|
|||
|
if (iTelephony == null) {
|
|||
|
throw new ImsException("Could not find Telephony Service.",
|
|||
|
ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
|
|||
|
}
|
|||
|
|
|||
|
try {
|
|||
|
return iTelephony.isCrossSimCallingEnabledByUser(mSubId);
|
|||
|
} catch (ServiceSpecificException sse) {
|
|||
|
throw new ImsException(sse.getMessage(), sse.errorCode);
|
|||
|
} catch (RemoteException e) {
|
|||
|
e.rethrowAsRuntimeException();
|
|||
|
}
|
|||
|
// Not reachable. Adding return to make compiler happy.
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Sets the user's setting for whether or not Voice over Cross SIM is enabled.
|
|||
|
* If enabled, this will result in the device setting up IMS of all other
|
|||
|
* active subscriptions over the INTERNET APN of the primary default data subscription
|
|||
|
* when any of those subscriptions are roaming or out of service and if wifi is not available
|
|||
|
* for VoWifi. This feature will be disabled if
|
|||
|
* {@link CarrierConfigManager#KEY_CARRIER_CROSS_SIM_IMS_AVAILABLE_BOOL} is set to false.
|
|||
|
*
|
|||
|
* <p>Following are the conditions in which system will try to register IMS over
|
|||
|
* cross sim
|
|||
|
* <ul>
|
|||
|
* <li>Wifi is not available, one SIM is roaming and the default data
|
|||
|
* SIM is in home network. Then roaming SIM IMS will be registered over INTERNET APN of the
|
|||
|
* default data subscription </li>
|
|||
|
* <li>Wifi is not available, one SIM is out of service and the default data
|
|||
|
* SIM is in home network. Then out of service SIM IMS will be registered over INTERNET
|
|||
|
* APN of the default data subscription </li>
|
|||
|
* </ul>
|
|||
|
* @throws ImsException if the IMS service associated with this subscription is not available or
|
|||
|
* the IMS service is not available.
|
|||
|
* @throws UnsupportedOperationException If the device does not have
|
|||
|
* {@link PackageManager#FEATURE_TELEPHONY_IMS}.
|
|||
|
* @param isEnabled true if the user's setting for Voice over Cross SIM is enabled,
|
|||
|
* false otherwise
|
|||
|
* @see #isCrossSimCallingEnabled()
|
|||
|
* @hide
|
|||
|
*/
|
|||
|
@SystemApi
|
|||
|
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
|
|||
|
public void setCrossSimCallingEnabled(boolean isEnabled) throws ImsException {
|
|||
|
ITelephony iTelephony = getITelephony();
|
|||
|
if (iTelephony == null) {
|
|||
|
throw new ImsException("Could not find Telephony Service.",
|
|||
|
ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
|
|||
|
}
|
|||
|
|
|||
|
try {
|
|||
|
iTelephony.setCrossSimCallingEnabled(mSubId, isEnabled);
|
|||
|
} catch (ServiceSpecificException sse) {
|
|||
|
throw new ImsException(sse.getMessage(), sse.errorCode);
|
|||
|
} catch (RemoteException e) {
|
|||
|
e.rethrowAsRuntimeException();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Returns the user's voice over WiFi roaming setting associated with the current subscription.
|
|||
|
*
|
|||
|
* <p>This API requires one of the following:
|
|||
|
* <ul>
|
|||
|
* <li>The caller holds the READ_PRECISE_PHONE_STATE permission.</li>
|
|||
|
* <li>If the caller is the device or profile owner, the caller holds the
|
|||
|
* {@link Manifest.permission#READ_PRECISE_PHONE_STATE} permission.</li>
|
|||
|
* <li>The caller has carrier privileges (see
|
|||
|
* {@link android.telephony.TelephonyManager#hasCarrierPrivileges}) on any
|
|||
|
* active subscription.</li>
|
|||
|
* </ul>
|
|||
|
* <p>The profile owner is an app that owns a managed profile on the device; for more details
|
|||
|
* see <a href="https://developer.android.com/work/managed-profiles">Work profiles</a>.
|
|||
|
* Access by profile owners is deprecated and will be removed in a future release.
|
|||
|
*
|
|||
|
* @throws IllegalArgumentException if the subscription associated with this operation is not
|
|||
|
* active (SIM is not inserted, ESIM inactive) or invalid.
|
|||
|
* @throws UnsupportedOperationException If the device does not have
|
|||
|
* {@link PackageManager#FEATURE_TELEPHONY_IMS}.
|
|||
|
* @return true if the user's setting for Voice over WiFi while roaming is enabled, false
|
|||
|
* if disabled.
|
|||
|
*/
|
|||
|
@SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236).
|
|||
|
@RequiresPermission(anyOf = {
|
|||
|
android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
|
|||
|
android.Manifest.permission.READ_PRECISE_PHONE_STATE})
|
|||
|
public boolean isVoWiFiRoamingSettingEnabled() {
|
|||
|
ITelephony iTelephony = getITelephony();
|
|||
|
if (iTelephony == null) {
|
|||
|
throw new RuntimeException("Could not find Telephony Service.");
|
|||
|
}
|
|||
|
|
|||
|
try {
|
|||
|
return iTelephony.isVoWiFiRoamingSettingEnabled(mSubId);
|
|||
|
} catch (ServiceSpecificException e) {
|
|||
|
if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
|
|||
|
// Rethrow as runtime error to keep API compatible.
|
|||
|
throw new IllegalArgumentException(e.getMessage());
|
|||
|
} else {
|
|||
|
throw new RuntimeException(e.getMessage());
|
|||
|
}
|
|||
|
} 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.
|
|||
|
* @throws IllegalArgumentException if the subscription associated with this operation is not
|
|||
|
* active (SIM is not inserted, ESIM inactive) or invalid.
|
|||
|
* @throws UnsupportedOperationException If the device does not have
|
|||
|
* {@link PackageManager#FEATURE_TELEPHONY_IMS}.
|
|||
|
* @see #isVoWiFiRoamingSettingEnabled()
|
|||
|
* @hide
|
|||
|
*/
|
|||
|
@SystemApi
|
|||
|
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
|
|||
|
public void setVoWiFiRoamingSettingEnabled(boolean isEnabled) {
|
|||
|
ITelephony iTelephony = getITelephony();
|
|||
|
if (iTelephony == null) {
|
|||
|
throw new RuntimeException("Could not find Telephony Service.");
|
|||
|
}
|
|||
|
|
|||
|
try {
|
|||
|
iTelephony.setVoWiFiRoamingSettingEnabled(mSubId, isEnabled);
|
|||
|
} catch (ServiceSpecificException e) {
|
|||
|
if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
|
|||
|
// Rethrow as runtime error to keep API compatible.
|
|||
|
throw new IllegalArgumentException(e.getMessage());
|
|||
|
} else {
|
|||
|
throw new RuntimeException(e.getMessage());
|
|||
|
}
|
|||
|
} 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}
|
|||
|
* @throws IllegalArgumentException if the subscription associated with this operation is not
|
|||
|
* active (SIM is not inserted, ESIM inactive) or invalid.
|
|||
|
* @throws UnsupportedOperationException If the device does not have
|
|||
|
* {@link PackageManager#FEATURE_TELEPHONY_IMS}.
|
|||
|
* @see #setVoWiFiSettingEnabled(boolean)
|
|||
|
* @hide
|
|||
|
*/
|
|||
|
@SystemApi
|
|||
|
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
|
|||
|
public void setVoWiFiNonPersistent(boolean isCapable, int mode) {
|
|||
|
ITelephony iTelephony = getITelephony();
|
|||
|
if (iTelephony == null) {
|
|||
|
throw new RuntimeException("Could not find Telephony Service.");
|
|||
|
}
|
|||
|
|
|||
|
try {
|
|||
|
iTelephony.setVoWiFiNonPersistent(mSubId, isCapable, mode);
|
|||
|
} catch (ServiceSpecificException e) {
|
|||
|
if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
|
|||
|
// Rethrow as runtime error to keep API compatible.
|
|||
|
throw new IllegalArgumentException(e.getMessage());
|
|||
|
} else {
|
|||
|
throw new RuntimeException(e.getMessage());
|
|||
|
}
|
|||
|
} catch (RemoteException e) {
|
|||
|
throw e.rethrowAsRuntimeException();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Returns the user's voice over WiFi Roaming mode setting associated with the device.
|
|||
|
*
|
|||
|
* <p>This API requires one of the following:
|
|||
|
* <ul>
|
|||
|
* <li>The caller holds the READ_PRECISE_PHONE_STATE permission.</li>
|
|||
|
* <li>If the caller is the device or profile owner, the caller holds the
|
|||
|
* {@link Manifest.permission#READ_PRECISE_PHONE_STATE} permission.</li>
|
|||
|
* <li>The caller has carrier privileges (see
|
|||
|
* {@link android.telephony.TelephonyManager#hasCarrierPrivileges}) on any
|
|||
|
* active subscription.</li>
|
|||
|
* </ul>
|
|||
|
* <p>The profile owner is an app that owns a managed profile on the device; for more details
|
|||
|
* see <a href="https://developer.android.com/work/managed-profiles">Work profiles</a>.
|
|||
|
* Access by profile owners is deprecated and will be removed in a future release.
|
|||
|
*
|
|||
|
* @throws IllegalArgumentException if the subscription associated with this operation is not
|
|||
|
* active (SIM is not inserted, ESIM inactive) or invalid.
|
|||
|
* @throws UnsupportedOperationException If the device does not have
|
|||
|
* {@link PackageManager#FEATURE_TELEPHONY_IMS}.
|
|||
|
* @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}
|
|||
|
*/
|
|||
|
@SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236).
|
|||
|
@RequiresPermission(anyOf = {
|
|||
|
android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
|
|||
|
android.Manifest.permission.READ_PRECISE_PHONE_STATE})
|
|||
|
public @WiFiCallingMode int getVoWiFiModeSetting() {
|
|||
|
ITelephony iTelephony = getITelephony();
|
|||
|
if (iTelephony == null) {
|
|||
|
throw new RuntimeException("Could not find Telephony Service.");
|
|||
|
}
|
|||
|
|
|||
|
try {
|
|||
|
return iTelephony.getVoWiFiModeSetting(mSubId);
|
|||
|
} catch (ServiceSpecificException e) {
|
|||
|
if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
|
|||
|
// Rethrow as runtime error to keep API compatible.
|
|||
|
throw new IllegalArgumentException(e.getMessage());
|
|||
|
} else {
|
|||
|
throw new RuntimeException(e.getMessage());
|
|||
|
}
|
|||
|
} 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}
|
|||
|
* @throws IllegalArgumentException if the subscription associated with this operation is not
|
|||
|
* active (SIM is not inserted, ESIM inactive) or invalid.
|
|||
|
* @throws UnsupportedOperationException If the device does not have
|
|||
|
* {@link PackageManager#FEATURE_TELEPHONY_IMS}.
|
|||
|
* @see #getVoWiFiModeSetting()
|
|||
|
* @hide
|
|||
|
*/
|
|||
|
@SystemApi
|
|||
|
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
|
|||
|
public void setVoWiFiModeSetting(@WiFiCallingMode int mode) {
|
|||
|
ITelephony iTelephony = getITelephony();
|
|||
|
if (iTelephony == null) {
|
|||
|
throw new RuntimeException("Could not find Telephony Service.");
|
|||
|
}
|
|||
|
|
|||
|
try {
|
|||
|
iTelephony.setVoWiFiModeSetting(mSubId, mode);
|
|||
|
} catch (ServiceSpecificException e) {
|
|||
|
if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
|
|||
|
// Rethrow as runtime error to keep API compatible.
|
|||
|
throw new IllegalArgumentException(e.getMessage());
|
|||
|
} else {
|
|||
|
throw new RuntimeException(e.getMessage());
|
|||
|
}
|
|||
|
} 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}
|
|||
|
* @throws IllegalArgumentException if the subscription associated with this operation is not
|
|||
|
* active (SIM is not inserted, ESIM inactive) or invalid.
|
|||
|
* @throws UnsupportedOperationException If the device does not have
|
|||
|
* {@link PackageManager#FEATURE_TELEPHONY_IMS}.
|
|||
|
* @see #setVoWiFiRoamingSettingEnabled(boolean)
|
|||
|
* @hide
|
|||
|
*/
|
|||
|
@SystemApi
|
|||
|
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
|
|||
|
public @WiFiCallingMode int getVoWiFiRoamingModeSetting() {
|
|||
|
ITelephony iTelephony = getITelephony();
|
|||
|
if (iTelephony == null) {
|
|||
|
throw new RuntimeException("Could not find Telephony Service.");
|
|||
|
}
|
|||
|
|
|||
|
try {
|
|||
|
return iTelephony.getVoWiFiRoamingModeSetting(mSubId);
|
|||
|
} catch (ServiceSpecificException e) {
|
|||
|
if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
|
|||
|
// Rethrow as runtime error to keep API compatible.
|
|||
|
throw new IllegalArgumentException(e.getMessage());
|
|||
|
} else {
|
|||
|
throw new RuntimeException(e.getMessage());
|
|||
|
}
|
|||
|
} 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}
|
|||
|
* @throws IllegalArgumentException if the subscription associated with this operation is not
|
|||
|
* active (SIM is not inserted, ESIM inactive) or invalid.
|
|||
|
* @throws UnsupportedOperationException If the device does not have
|
|||
|
* {@link PackageManager#FEATURE_TELEPHONY_IMS}.
|
|||
|
* @see #getVoWiFiRoamingModeSetting()
|
|||
|
* @hide
|
|||
|
*/
|
|||
|
@SystemApi
|
|||
|
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
|
|||
|
public void setVoWiFiRoamingModeSetting(@WiFiCallingMode int mode) {
|
|||
|
ITelephony iTelephony = getITelephony();
|
|||
|
if (iTelephony == null) {
|
|||
|
throw new RuntimeException("Could not find Telephony Service.");
|
|||
|
}
|
|||
|
|
|||
|
try {
|
|||
|
iTelephony.setVoWiFiRoamingModeSetting(mSubId, mode);
|
|||
|
} catch (ServiceSpecificException e) {
|
|||
|
if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
|
|||
|
// Rethrow as runtime error to keep API compatible.
|
|||
|
throw new IllegalArgumentException(e.getMessage());
|
|||
|
} else {
|
|||
|
throw new RuntimeException(e.getMessage());
|
|||
|
}
|
|||
|
} 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.
|
|||
|
* @throws IllegalArgumentException if the subscription associated with this operation is not
|
|||
|
* active (SIM is not inserted, ESIM inactive) or invalid.
|
|||
|
* @throws UnsupportedOperationException If the device does not have
|
|||
|
* {@link PackageManager#FEATURE_TELEPHONY_IMS}.
|
|||
|
* @param isEnabled if true RTT should be enabled during calls made on this subscription.
|
|||
|
* @hide
|
|||
|
*/
|
|||
|
@SystemApi
|
|||
|
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
|
|||
|
public void setRttCapabilitySetting(boolean isEnabled) {
|
|||
|
ITelephony iTelephony = getITelephony();
|
|||
|
if (iTelephony == null) {
|
|||
|
throw new RuntimeException("Could not find Telephony Service.");
|
|||
|
}
|
|||
|
|
|||
|
try {
|
|||
|
iTelephony.setRttCapabilitySetting(mSubId, isEnabled);
|
|||
|
} catch (ServiceSpecificException e) {
|
|||
|
if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
|
|||
|
// Rethrow as runtime error to keep API compatible.
|
|||
|
throw new IllegalArgumentException(e.getMessage());
|
|||
|
} else {
|
|||
|
throw new RuntimeException(e.getMessage());
|
|||
|
}
|
|||
|
} catch (RemoteException e) {
|
|||
|
throw e.rethrowAsRuntimeException();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* @return true if TTY over VoLTE is supported
|
|||
|
*
|
|||
|
* <p>This API requires one of the following:
|
|||
|
* <ul>
|
|||
|
* <li>The caller holds the READ_PRECISE_PHONE_STATE permission.</li>
|
|||
|
* <li>If the caller is the device or profile owner, the caller holds the
|
|||
|
* {@link Manifest.permission#READ_PRECISE_PHONE_STATE} permission.</li>
|
|||
|
* <li>The caller has carrier privileges (see
|
|||
|
* {@link android.telephony.TelephonyManager#hasCarrierPrivileges}) on any
|
|||
|
* active subscription.</li>
|
|||
|
* </ul>
|
|||
|
* <p>The profile owner is an app that owns a managed profile on the device; for more details
|
|||
|
* see <a href="https://developer.android.com/work/managed-profiles">Work profiles</a>.
|
|||
|
* Access by profile owners is deprecated and will be removed in a future release.
|
|||
|
*
|
|||
|
* @throws IllegalArgumentException if the subscription associated with this operation is not
|
|||
|
* active (SIM is not inserted, ESIM inactive) or invalid.
|
|||
|
* @throws UnsupportedOperationException If the device does not have
|
|||
|
* {@link PackageManager#FEATURE_TELEPHONY_IMS}.
|
|||
|
* @see android.telephony.CarrierConfigManager#KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL
|
|||
|
*/
|
|||
|
@SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236).
|
|||
|
@RequiresPermission(anyOf = {
|
|||
|
android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
|
|||
|
android.Manifest.permission.READ_PRECISE_PHONE_STATE})
|
|||
|
public boolean isTtyOverVolteEnabled() {
|
|||
|
ITelephony iTelephony = getITelephony();
|
|||
|
if (iTelephony == null) {
|
|||
|
throw new RuntimeException("Could not find Telephony Service.");
|
|||
|
}
|
|||
|
|
|||
|
try {
|
|||
|
return iTelephony.isTtyOverVolteEnabled(mSubId);
|
|||
|
} catch (ServiceSpecificException e) {
|
|||
|
if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
|
|||
|
// Rethrow as runtime error to keep API compatible.
|
|||
|
throw new IllegalArgumentException(e.getMessage());
|
|||
|
} else {
|
|||
|
throw new RuntimeException(e.getMessage());
|
|||
|
}
|
|||
|
} catch (RemoteException e) {
|
|||
|
throw e.rethrowAsRuntimeException();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Get the status of the MmTel Feature registered on this subscription.
|
|||
|
* @param executor The executor that will be used to call the callback.
|
|||
|
* @param callback A callback containing an Integer describing the current state of the
|
|||
|
* MmTel feature, Which will be one of the following:
|
|||
|
* {@link ImsFeature#STATE_UNAVAILABLE},
|
|||
|
* {@link ImsFeature#STATE_INITIALIZING},
|
|||
|
* {@link ImsFeature#STATE_READY}. Will be called using the executor
|
|||
|
* specified when the service state has been retrieved from the IMS service.
|
|||
|
* @throws ImsException if the IMS service associated with this subscription is not available or
|
|||
|
* the IMS service is not available.
|
|||
|
* @hide
|
|||
|
*/
|
|||
|
@SystemApi
|
|||
|
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
|
|||
|
public void getFeatureState(@NonNull @CallbackExecutor Executor executor,
|
|||
|
@NonNull @ImsFeature.ImsState Consumer<Integer> callback) throws ImsException {
|
|||
|
if (executor == null) {
|
|||
|
throw new IllegalArgumentException("Must include a non-null Executor.");
|
|||
|
}
|
|||
|
if (callback == null) {
|
|||
|
throw new IllegalArgumentException("Must include a non-null Consumer.");
|
|||
|
}
|
|||
|
|
|||
|
ITelephony iTelephony = getITelephony();
|
|||
|
if (iTelephony == null) {
|
|||
|
throw new ImsException("Could not find Telephony Service.",
|
|||
|
ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
|
|||
|
}
|
|||
|
|
|||
|
try {
|
|||
|
iTelephony.getImsMmTelFeatureState(mSubId, new IIntegerConsumer.Stub() {
|
|||
|
@Override
|
|||
|
public void accept(int result) {
|
|||
|
final long identity = Binder.clearCallingIdentity();
|
|||
|
try {
|
|||
|
executor.execute(() -> callback.accept(result));
|
|||
|
} finally {
|
|||
|
Binder.restoreCallingIdentity(identity);
|
|||
|
}
|
|||
|
}
|
|||
|
});
|
|||
|
} catch (ServiceSpecificException sse) {
|
|||
|
throw new ImsException(sse.getMessage(), sse.errorCode);
|
|||
|
} catch (RemoteException e) {
|
|||
|
e.rethrowAsRuntimeException();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Register a new callback, which is used to notify the registrant of changes to
|
|||
|
* the state of the underlying IMS service that is attached to telephony to
|
|||
|
* implement IMS functionality. If the manager is created for
|
|||
|
* the {@link SubscriptionManager#DEFAULT_SUBSCRIPTION_ID},
|
|||
|
* this throws an {@link ImsException}.
|
|||
|
*
|
|||
|
* <p>Requires Permission:
|
|||
|
* {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE READ_PRECISE_PHONE_STATE}
|
|||
|
* or that the calling app has carrier privileges
|
|||
|
* (see {@link android.telephony.TelephonyManager#hasCarrierPrivileges}).
|
|||
|
*
|
|||
|
* @param executor the Executor that will be used to call the {@link ImsStateCallback}.
|
|||
|
* @param callback The callback instance being registered.
|
|||
|
* @throws ImsException in the case that the callback can not be registered.
|
|||
|
* See {@link ImsException#getCode} for more information on when this is called.
|
|||
|
*/
|
|||
|
@RequiresPermission(anyOf = {Manifest.permission.READ_PRECISE_PHONE_STATE,
|
|||
|
Manifest.permission.READ_PRIVILEGED_PHONE_STATE})
|
|||
|
public void registerImsStateCallback(@NonNull Executor executor,
|
|||
|
@NonNull ImsStateCallback callback) throws ImsException {
|
|||
|
Objects.requireNonNull(callback, "Must include a non-null ImsStateCallback.");
|
|||
|
Objects.requireNonNull(executor, "Must include a non-null Executor.");
|
|||
|
|
|||
|
callback.init(executor);
|
|||
|
ITelephony telephony = mBinderCache.listenOnBinder(callback, callback::binderDied);
|
|||
|
if (telephony == null) {
|
|||
|
throw new ImsException("Telephony server is down",
|
|||
|
ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
|
|||
|
}
|
|||
|
|
|||
|
try {
|
|||
|
telephony.registerImsStateCallback(
|
|||
|
mSubId, ImsFeature.FEATURE_MMTEL,
|
|||
|
callback.getCallbackBinder(), getOpPackageName());
|
|||
|
} catch (ServiceSpecificException e) {
|
|||
|
throw new ImsException(e.getMessage(), e.errorCode);
|
|||
|
} catch (RemoteException | IllegalStateException e) {
|
|||
|
throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Unregisters a previously registered callback.
|
|||
|
*
|
|||
|
* @param callback The callback instance to be unregistered.
|
|||
|
*/
|
|||
|
public void unregisterImsStateCallback(@NonNull ImsStateCallback callback) {
|
|||
|
Objects.requireNonNull(callback, "Must include a non-null ImsStateCallback.");
|
|||
|
|
|||
|
ITelephony telephony = mBinderCache.removeRunnable(callback);
|
|||
|
try {
|
|||
|
if (telephony != null) {
|
|||
|
telephony.unregisterImsStateCallback(callback.getCallbackBinder());
|
|||
|
}
|
|||
|
} catch (RemoteException ignore) {
|
|||
|
// ignore it
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
private String getOpPackageName() {
|
|||
|
if (mContext != null) {
|
|||
|
return mContext.getOpPackageName();
|
|||
|
} else {
|
|||
|
return null;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
private ITelephony getITelephony() {
|
|||
|
return mBinderCache.getBinder();
|
|||
|
}
|
|||
|
|
|||
|
private static ITelephony getITelephonyInterface() {
|
|||
|
ITelephony binder = ITelephony.Stub.asInterface(
|
|||
|
TelephonyFrameworkInitializer
|
|||
|
.getTelephonyServiceManager()
|
|||
|
.getTelephonyServiceRegisterer()
|
|||
|
.get());
|
|||
|
return binder;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Convert Wi-Fi calling mode to string.
|
|||
|
*
|
|||
|
* @param mode Wi-Fi calling mode.
|
|||
|
* @return The Wi-Fi calling mode in string format.
|
|||
|
*
|
|||
|
* @hide
|
|||
|
*/
|
|||
|
@NonNull
|
|||
|
public static String wifiCallingModeToString(@ImsMmTelManager.WiFiCallingMode int mode) {
|
|||
|
switch (mode) {
|
|||
|
case ImsMmTelManager.WIFI_MODE_UNKNOWN: return "UNKNOWN";
|
|||
|
case ImsMmTelManager.WIFI_MODE_WIFI_ONLY: return "WIFI_ONLY";
|
|||
|
case ImsMmTelManager.WIFI_MODE_CELLULAR_PREFERRED: return "CELLULAR_PREFERRED";
|
|||
|
case ImsMmTelManager.WIFI_MODE_WIFI_PREFERRED: return "WIFI_PREFERRED";
|
|||
|
default:
|
|||
|
return "UNKNOWN(" + mode + ")";
|
|||
|
}
|
|||
|
}
|
|||
|
}
|