| /* |
| * 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 + ")"; |
| } |
| } |
| } |