/*
 * 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 com.android.settings.wifi.calling;

import static android.app.slice.Slice.EXTRA_TOGGLE_STATE;

import static com.android.settings.Utils.SETTINGS_PACKAGE_NAME;
import static com.android.settings.slices.CustomSliceRegistry.WIFI_CALLING_PREFERENCE_URI;
import static com.android.settings.slices.CustomSliceRegistry.WIFI_CALLING_URI;

import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.net.Uri;
import android.os.PersistableBundle;
import android.provider.Settings;
import android.telephony.CarrierConfigManager;
import android.telephony.SubscriptionManager;
import android.telephony.ims.ImsMmTelManager;
import android.text.TextUtils;
import android.util.Log;

import androidx.annotation.VisibleForTesting;
import androidx.core.graphics.drawable.IconCompat;
import androidx.slice.Slice;
import androidx.slice.builders.ListBuilder;
import androidx.slice.builders.ListBuilder.RowBuilder;
import androidx.slice.builders.SliceAction;

import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settings.network.ims.WifiCallingQueryImsState;
import com.android.settings.slices.SliceBroadcastReceiver;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

/**
 * Helper class to control slices for wifi calling settings.
 */
public class WifiCallingSliceHelper {

    private static final String TAG = "WifiCallingSliceHelper";

    /**
     * Settings slice path to wifi calling preference setting.
     */
    public static final String PATH_WIFI_CALLING_PREFERENCE =
            "wifi_calling_preference";

    /**
     * Action passed for changes to wifi calling slice (toggle).
     */
    public static final String ACTION_WIFI_CALLING_CHANGED =
            "com.android.settings.wifi.calling.action.WIFI_CALLING_CHANGED";

    /**
     * Action passed when user selects wifi only preference.
     */
    public static final String ACTION_WIFI_CALLING_PREFERENCE_WIFI_ONLY =
            "com.android.settings.slice.action.WIFI_CALLING_PREFERENCE_WIFI_ONLY";
    /**
     * Action passed when user selects wifi preferred preference.
     */
    public static final String ACTION_WIFI_CALLING_PREFERENCE_WIFI_PREFERRED =
            "com.android.settings.slice.action.WIFI_CALLING_PREFERENCE_WIFI_PREFERRED";
    /**
     * Action passed when user selects cellular preferred preference.
     */
    public static final String ACTION_WIFI_CALLING_PREFERENCE_CELLULAR_PREFERRED =
            "com.android.settings.slice.action.WIFI_CALLING_PREFERENCE_CELLULAR_PREFERRED";

    /**
     * Action for Wifi calling Settings activity which
     * allows setting configuration for Wifi calling
     * related settings
     */
    public static final String ACTION_WIFI_CALLING_SETTINGS_ACTIVITY =
            "android.settings.WIFI_CALLING_SETTINGS";

    /**
     * Timeout for querying wifi calling setting from ims manager.
     */
    private static final int TIMEOUT_MILLIS = 2000;

    private final Context mContext;

    @VisibleForTesting
    public WifiCallingSliceHelper(Context context) {
        mContext = context;
    }

    /**
     * Returns Slice object for wifi calling settings.
     *
     * If wifi calling is being turned on and if wifi calling activation is needed for the current
     * carrier, this method will return Slice with instructions to go to Settings App.
     *
     * If wifi calling is not supported for the current carrier, this method will return slice with
     * not supported message.
     *
     * If wifi calling setting can be changed, this method will return the slice to toggle wifi
     * calling option with ACTION_WIFI_CALLING_CHANGED as endItem.
     */
    public Slice createWifiCallingSlice(Uri sliceUri) {
        final int subId = getDefaultVoiceSubId();

        if (!queryImsState(subId).isReadyToWifiCalling()) {
            Log.d(TAG, "Wifi calling is either not provisioned or not enabled by Platform");
            return null;
        }

        final boolean isWifiCallingEnabled = isWifiCallingEnabled();
        final Intent activationAppIntent =
                getWifiCallingCarrierActivityIntent(subId);

        // Send this actionable wifi calling slice to toggle the setting
        // only when there is no need for wifi calling activation with the server
        if (activationAppIntent != null && !isWifiCallingEnabled) {
            Log.d(TAG, "Needs Activation");
            // Activation needed for the next action of the user
            // Give instructions to go to settings app
            final Resources res = getResourcesForSubId(subId);
            return getNonActionableWifiCallingSlice(
                    res.getText(R.string.wifi_calling_settings_title),
                    res.getText(R.string.wifi_calling_settings_activation_instructions),
                    sliceUri, getActivityIntent(ACTION_WIFI_CALLING_SETTINGS_ACTIVITY));
        }
        return getWifiCallingSlice(sliceUri, isWifiCallingEnabled, subId);
    }

    private boolean isWifiCallingEnabled() {
        final WifiCallingQueryImsState queryState = queryImsState(getDefaultVoiceSubId());
        return queryState.isEnabledByUser() && queryState.isAllowUserControl();
    }

    /**
     * Builds a toggle slice where the intent takes you to the wifi calling page and the toggle
     * enables/disables wifi calling.
     */
    private Slice getWifiCallingSlice(Uri sliceUri, boolean isWifiCallingEnabled, int subId) {
        final IconCompat icon = IconCompat.createWithResource(mContext, R.drawable.wifi_signal);
        final Resources res = getResourcesForSubId(subId);

        return new ListBuilder(mContext, sliceUri, ListBuilder.INFINITY)
                .setAccentColor(Utils.getColorAccentDefaultColor(mContext))
                .addRow(new RowBuilder()
                        .setTitle(res.getText(R.string.wifi_calling_settings_title))
                        .addEndItem(
                                SliceAction.createToggle(
                                        getBroadcastIntent(ACTION_WIFI_CALLING_CHANGED,
                                                isWifiCallingEnabled),
                                        null /* actionTitle */, isWifiCallingEnabled))
                        .setPrimaryAction(SliceAction.createDeeplink(
                                getActivityIntent(ACTION_WIFI_CALLING_SETTINGS_ACTIVITY),
                                icon,
                                ListBuilder.ICON_IMAGE,
                                res.getText(R.string.wifi_calling_settings_title))))
                .build();
    }

    /**
     * Returns Slice object for wifi calling preference.
     *
     * If wifi calling is not turned on, this method will return a slice to turn on wifi calling.
     *
     * If wifi calling preference is not user editable, this method will return a slice to display
     * appropriate message.
     *
     * If wifi calling preference can be changed, this method will return a slice with 3 or 4 rows:
     * Header Row: current preference settings
     * Row 1: wifi only option with ACTION_WIFI_CALLING_PREFERENCE_WIFI_ONLY, if wifi only option
     * is editable
     * Row 2: wifi preferred option with ACTION_WIFI_CALLING_PREFERENCE_WIFI_PREFERRED
     * Row 3: cellular preferred option with ACTION_WIFI_CALLING_PREFERENCE_CELLULAR_PREFERRED
     */
    public Slice createWifiCallingPreferenceSlice(Uri sliceUri) {
        final int subId = getDefaultVoiceSubId();

        if (!SubscriptionManager.isValidSubscriptionId(subId)) {
            Log.d(TAG, "Invalid Subscription Id");
            return null;
        }

        final boolean isWifiCallingPrefEditable = isCarrierConfigManagerKeyEnabled(
                CarrierConfigManager.KEY_EDITABLE_WFC_MODE_BOOL, subId, false);
        final boolean isWifiOnlySupported = isCarrierConfigManagerKeyEnabled(
                CarrierConfigManager.KEY_CARRIER_WFC_SUPPORTS_WIFI_ONLY_BOOL, subId, true);

        if (!isWifiCallingPrefEditable) {
            Log.d(TAG, "Wifi calling preference is not editable");
            return null;
        }

        if (!queryImsState(subId).isReadyToWifiCalling()) {
            Log.d(TAG, "Wifi calling is either not provisioned or not enabled by platform");
            return null;
        }

        boolean isWifiCallingEnabled = false;
        int wfcMode = -1;
        try {
            final ImsMmTelManager imsMmTelManager = getImsMmTelManager(subId);
            isWifiCallingEnabled = isWifiCallingEnabled();
            wfcMode = getWfcMode(imsMmTelManager);
        } catch (InterruptedException | ExecutionException | TimeoutException e) {
            Log.e(TAG, "Unable to get wifi calling preferred mode", e);
            return null;
        }
        if (!isWifiCallingEnabled) {
            // wifi calling is not enabled. Ask user to enable wifi calling
            final Resources res = getResourcesForSubId(subId);
            return getNonActionableWifiCallingSlice(
                    res.getText(R.string.wifi_calling_mode_title),
                    res.getText(R.string.wifi_calling_turn_on),
                    sliceUri, getActivityIntent(ACTION_WIFI_CALLING_SETTINGS_ACTIVITY));
        }
        // Return the slice to change wifi calling preference
        return getWifiCallingPreferenceSlice(
                isWifiOnlySupported, wfcMode, sliceUri, subId);
    }

    /**
     * Returns actionable wifi calling preference slice.
     *
     * @param isWifiOnlySupported adds row for wifi only if this is true
     * @param currentWfcPref      current Preference {@link ImsConfig}
     * @param sliceUri            sliceUri
     * @param subId               subscription id
     * @return Slice for actionable wifi calling preference settings
     */
    private Slice getWifiCallingPreferenceSlice(boolean isWifiOnlySupported,
            int currentWfcPref,
            Uri sliceUri,
            int subId) {
        final IconCompat icon = IconCompat.createWithResource(mContext, R.drawable.wifi_signal);
        final Resources res = getResourcesForSubId(subId);
        // Top row shows information on current preference state
        final ListBuilder listBuilder = new ListBuilder(mContext, sliceUri, ListBuilder.INFINITY)
                .setAccentColor(Utils.getColorAccentDefaultColor(mContext));
        final ListBuilder.HeaderBuilder headerBuilder = new ListBuilder.HeaderBuilder()
                .setTitle(res.getText(R.string.wifi_calling_mode_title))
                .setPrimaryAction(SliceAction.createDeeplink(
                        getActivityIntent(ACTION_WIFI_CALLING_SETTINGS_ACTIVITY),
                        icon,
                        ListBuilder.ICON_IMAGE,
                        res.getText(R.string.wifi_calling_mode_title)));
        if (!Utils.isSettingsIntelligence(mContext)) {
            headerBuilder.setSubtitle(getWifiCallingPreferenceSummary(currentWfcPref, subId));
        }
        listBuilder.setHeader(headerBuilder);

        if (isWifiOnlySupported) {
            listBuilder.addRow(wifiPreferenceRowBuilder(listBuilder,
                    com.android.internal.R.string.wfc_mode_wifi_only_summary,
                    ACTION_WIFI_CALLING_PREFERENCE_WIFI_ONLY,
                    currentWfcPref == ImsMmTelManager.WIFI_MODE_WIFI_ONLY, subId));
        }

        listBuilder.addRow(wifiPreferenceRowBuilder(listBuilder,
                com.android.internal.R.string.wfc_mode_wifi_preferred_summary,
                ACTION_WIFI_CALLING_PREFERENCE_WIFI_PREFERRED,
                currentWfcPref == ImsMmTelManager.WIFI_MODE_WIFI_PREFERRED, subId));

        listBuilder.addRow(wifiPreferenceRowBuilder(listBuilder,
                com.android.internal.R.string.wfc_mode_cellular_preferred_summary,
                ACTION_WIFI_CALLING_PREFERENCE_CELLULAR_PREFERRED,
                currentWfcPref == ImsMmTelManager.WIFI_MODE_CELLULAR_PREFERRED, subId));

        return listBuilder.build();
    }

    /**
     * Returns RowBuilder for a new row containing specific wifi calling preference.
     *
     * @param listBuilder          ListBuilder that will be the parent for this RowBuilder
     * @param preferenceTitleResId resource Id for the preference row title
     * @param action               action to be added for the row
     * @param subId                subscription id
     * @return RowBuilder for the row
     */
    private RowBuilder wifiPreferenceRowBuilder(ListBuilder listBuilder,
            int preferenceTitleResId, String action, boolean checked, int subId) {
        final IconCompat icon =
                IconCompat.createWithResource(mContext, R.drawable.radio_button_check);
        final Resources res = getResourcesForSubId(subId);
        return new RowBuilder()
                .setTitle(res.getText(preferenceTitleResId))
                .setTitleItem(SliceAction.createToggle(getBroadcastIntent(action, checked),
                        icon, res.getText(preferenceTitleResId), checked));
    }


    /**
     * Returns the String describing wifi calling preference mentioned in wfcMode
     *
     * @param wfcMode ImsConfig constant for the preference {@link ImsConfig}
     * @return summary/name of the wifi calling preference
     */
    private CharSequence getWifiCallingPreferenceSummary(int wfcMode, int subId) {
        final Resources res = getResourcesForSubId(subId);
        switch (wfcMode) {
            case ImsMmTelManager.WIFI_MODE_WIFI_ONLY:
                return res.getText(
                        com.android.internal.R.string.wfc_mode_wifi_only_summary);
            case ImsMmTelManager.WIFI_MODE_WIFI_PREFERRED:
                return res.getText(
                        com.android.internal.R.string.wfc_mode_wifi_preferred_summary);
            case ImsMmTelManager.WIFI_MODE_CELLULAR_PREFERRED:
                return res.getText(
                        com.android.internal.R.string.wfc_mode_cellular_preferred_summary);
            default:
                return null;
        }
    }

    protected ImsMmTelManager getImsMmTelManager(int subId) {
        return ImsMmTelManager.createForSubscriptionId(subId);
    }

    private int getWfcMode(ImsMmTelManager imsMmTelManager)
            throws InterruptedException, ExecutionException, TimeoutException {
        final FutureTask<Integer> wfcModeTask = new FutureTask<>(new Callable<Integer>() {
            @Override
            public Integer call() {
                int wfcMode = ImsMmTelManager.WIFI_MODE_UNKNOWN;
                try {
                    wfcMode = imsMmTelManager.getVoWiFiModeSetting();
                } catch (IllegalArgumentException e) {
                    Log.e(TAG, "getResourceIdForWfcMode: Exception", e);
                }
                return wfcMode;
            }
        });
        final ExecutorService executor = Executors.newSingleThreadExecutor();
        executor.execute(wfcModeTask);
        return wfcModeTask.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
    }

    /**
     * Handles wifi calling setting change from wifi calling slice and posts notification. Should be
     * called when intent action is ACTION_WIFI_CALLING_CHANGED. Executed in @WorkerThread
     *
     * @param intent action performed
     */
    public void handleWifiCallingChanged(Intent intent) {
        final int subId = getDefaultVoiceSubId();

        if (SubscriptionManager.isValidSubscriptionId(subId)
                && intent.hasExtra(EXTRA_TOGGLE_STATE)) {
            final WifiCallingQueryImsState queryState = queryImsState(subId);
            if (queryState.isWifiCallingProvisioned()) {
                final boolean currentValue = isWifiCallingEnabled();
                final boolean newValue = !(intent.getBooleanExtra(EXTRA_TOGGLE_STATE,
                        currentValue));
                final Intent activationAppIntent =
                        getWifiCallingCarrierActivityIntent(subId);
                // 1. If activationApp is not null, users only can turn off WFC, or
                // 2. Turn on/off directly if there is no activationApp.
                if ((newValue != currentValue) && (activationAppIntent == null || !newValue)) {
                    // If either the action is to turn off wifi calling setting
                    // or there is no activation involved - Update the setting
                    final ImsMmTelManager imsMmTelManager = getImsMmTelManager(subId);
                    try {
                        imsMmTelManager.setVoWiFiSettingEnabled(newValue);
                    } catch (IllegalArgumentException e) {
                        Log.e(TAG, "handleWifiCallingChanged: Exception", e);
                    }
                } else {
                    Log.w(TAG, "action not taken: subId " + subId
                            + " from " + currentValue + " to " + newValue);
                }
            } else {
                Log.w(TAG, "action not taken: subId " + subId + " needs provision");
            }
        } else {
            Log.w(TAG, "action not taken: subId " + subId);
        }

        // notify change in slice in any case to get re-queried. This would result in displaying
        // appropriate message with the updated setting.
        mContext.getContentResolver().notifyChange(WIFI_CALLING_URI, null);
    }

    /**
     * Handles wifi calling preference Setting change from wifi calling preference Slice and posts
     * notification for the change. Should be called when intent action is one of the below
     * ACTION_WIFI_CALLING_PREFERENCE_WIFI_ONLY
     * ACTION_WIFI_CALLING_PREFERENCE_WIFI_PREFERRED
     * ACTION_WIFI_CALLING_PREFERENCE_CELLULAR_PREFERRED
     *
     * @param intent intent
     */
    public void handleWifiCallingPreferenceChanged(Intent intent) {
        final int subId = getDefaultVoiceSubId();
        final int errorValue = -1;

        if (SubscriptionManager.isValidSubscriptionId(subId)) {
            final boolean isWifiCallingPrefEditable = isCarrierConfigManagerKeyEnabled(
                    CarrierConfigManager.KEY_EDITABLE_WFC_MODE_BOOL, subId, false);
            final boolean isWifiOnlySupported = isCarrierConfigManagerKeyEnabled(
                    CarrierConfigManager.KEY_CARRIER_WFC_SUPPORTS_WIFI_ONLY_BOOL, subId, true);

            final WifiCallingQueryImsState queryState = queryImsState(subId);
            if (isWifiCallingPrefEditable
                    && queryState.isWifiCallingProvisioned()
                    && queryState.isEnabledByUser()
                    && queryState.isAllowUserControl()) {
                // Change the preference only when wifi calling is enabled
                // And when wifi calling preference is editable for the current carrier
                final ImsMmTelManager imsMmTelManager = getImsMmTelManager(subId);
                int currentValue = ImsMmTelManager.WIFI_MODE_UNKNOWN;
                try {
                    currentValue = imsMmTelManager.getVoWiFiModeSetting();
                } catch (IllegalArgumentException e) {
                    Log.e(TAG, "handleWifiCallingPreferenceChanged: Exception", e);
                    return;
                }

                int newValue = errorValue;
                switch (intent.getAction()) {
                    case ACTION_WIFI_CALLING_PREFERENCE_WIFI_ONLY:
                        if (isWifiOnlySupported) {
                            // change to wifi_only when wifi_only is enabled.
                            newValue = ImsMmTelManager.WIFI_MODE_WIFI_ONLY;
                        }
                        break;
                    case ACTION_WIFI_CALLING_PREFERENCE_WIFI_PREFERRED:
                        newValue = ImsMmTelManager.WIFI_MODE_WIFI_PREFERRED;
                        break;
                    case ACTION_WIFI_CALLING_PREFERENCE_CELLULAR_PREFERRED:
                        newValue = ImsMmTelManager.WIFI_MODE_CELLULAR_PREFERRED;
                        break;
                }
                if (newValue != errorValue && newValue != currentValue) {
                    // Update the setting only when there is a valid update
                    try {
                        imsMmTelManager.setVoWiFiModeSetting(newValue);
                    } catch (IllegalArgumentException e) {
                        Log.e(TAG, "handleWifiCallingPreferenceChanged: Exception", e);
                    }
                }
            }
        }

        // notify change in slice in any case to get re-queried. This would result in displaying
        // appropriate message.
        mContext.getContentResolver().notifyChange(WIFI_CALLING_PREFERENCE_URI, null);
    }

    /**
     * Returns Slice with the title and subtitle provided as arguments with wifi signal Icon.
     *
     * @param title    Title of the slice
     * @param subtitle Subtitle of the slice
     * @param sliceUri slice uri
     * @return Slice with title and subtitle
     */
    private Slice getNonActionableWifiCallingSlice(CharSequence title, CharSequence subtitle,
            Uri sliceUri, PendingIntent primaryActionIntent) {
        final IconCompat icon = IconCompat.createWithResource(mContext, R.drawable.wifi_signal);
        final RowBuilder rowBuilder = new RowBuilder()
                .setTitle(title)
                .setPrimaryAction(SliceAction.createDeeplink(
                        primaryActionIntent, icon, ListBuilder.SMALL_IMAGE,
                        title));
        if (!Utils.isSettingsIntelligence(mContext)) {
            rowBuilder.setSubtitle(subtitle);
        }
        return new ListBuilder(mContext, sliceUri, ListBuilder.INFINITY)
                .setAccentColor(Utils.getColorAccentDefaultColor(mContext))
                .addRow(rowBuilder)
                .build();
    }

    /**
     * Returns {@code true} when the key is enabled for the carrier, and {@code false} otherwise.
     */
    protected boolean isCarrierConfigManagerKeyEnabled(String key, int subId,
            boolean defaultValue) {
        final CarrierConfigManager configManager = getCarrierConfigManager(mContext);
        boolean ret = false;
        if (configManager != null) {
            final PersistableBundle bundle = configManager.getConfigForSubId(subId);
            if (bundle != null) {
                ret = bundle.getBoolean(key, defaultValue);
            }
        }
        return ret;
    }

    protected CarrierConfigManager getCarrierConfigManager(Context mContext) {
        return mContext.getSystemService(CarrierConfigManager.class);
    }

    /**
     * Returns the current default voice subId obtained from SubscriptionManager
     */
    protected int getDefaultVoiceSubId() {
        return SubscriptionManager.getDefaultVoiceSubscriptionId();
    }

    /**
     * Returns Intent of the activation app required to activate wifi calling or null if there is no
     * need for activation.
     */
    protected Intent getWifiCallingCarrierActivityIntent(int subId) {
        final CarrierConfigManager configManager = getCarrierConfigManager(mContext);
        if (configManager == null) {
            return null;
        }

        final PersistableBundle bundle = configManager.getConfigForSubId(subId);
        if (bundle == null) {
            return null;
        }

        final String carrierApp = bundle.getString(
                CarrierConfigManager.KEY_WFC_EMERGENCY_ADDRESS_CARRIER_APP_STRING);
        if (TextUtils.isEmpty(carrierApp)) {
            return null;
        }

        final ComponentName componentName = ComponentName.unflattenFromString(carrierApp);
        if (componentName == null) {
            return null;
        }

        final Intent intent = new Intent();
        intent.setComponent(componentName);
        return intent;
    }

    /**
     * @return {@link PendingIntent} to the Settings home page.
     */
    public static PendingIntent getSettingsIntent(Context context) {
        final Intent intent = new Intent(Settings.ACTION_SETTINGS);
        return PendingIntent.getActivity(context, 0 /* requestCode */, intent,
                PendingIntent.FLAG_IMMUTABLE);
    }

    /**
     * Create PendingIntent for Slice.
     * Note: SliceAction#createDeeplink() didn't support toggle status so far,
     *       therefore, embedding toggle status within PendingIntent.
     *
     * @param action Slice action
     * @param isChecked Status when Slice created.
     * @return PendingIntent
     */
    private PendingIntent getBroadcastIntent(String action, boolean isChecked) {
        final Intent intent = new Intent(action);
        intent.setClass(mContext, SliceBroadcastReceiver.class);
        intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
        intent.putExtra(EXTRA_TOGGLE_STATE, isChecked);
        return PendingIntent.getBroadcast(mContext, 0 /* requestCode */, intent,
                PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE);
    }

    /**
     * Returns PendingIntent to start activity specified by action
     */
    private PendingIntent getActivityIntent(String action) {
        final Intent intent = new Intent(action);
        intent.setPackage(SETTINGS_PACKAGE_NAME);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        return PendingIntent.getActivity(mContext, 0 /* requestCode */, intent,
                PendingIntent.FLAG_IMMUTABLE);
    }

    private Resources getResourcesForSubId(int subId) {
        return SubscriptionManager.getResourcesForSubId(mContext, subId);
    }

    @VisibleForTesting
    WifiCallingQueryImsState queryImsState(int subId) {
        return new WifiCallingQueryImsState(mContext, subId);
    }
}
