diff --git a/res/values/strings.xml b/res/values/strings.xml
index 5704c22fddd..b4d55a9ef77 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -2355,6 +2355,17 @@
Learn more about Private DNS features
+
+ Setting managed by carrier
+
+ Activate Wi\u2011Fi Calling
+
+ Turn on Wi\u2011Fi calling
+
+ Wi\u2011Fi calling is not supported for %1$s
+
+ Carrier
Display
diff --git a/src/com/android/settings/slices/SettingsSliceProvider.java b/src/com/android/settings/slices/SettingsSliceProvider.java
index edeb2b5f28c..7eecee92cb7 100644
--- a/src/com/android/settings/slices/SettingsSliceProvider.java
+++ b/src/com/android/settings/slices/SettingsSliceProvider.java
@@ -18,6 +18,8 @@ package com.android.settings.slices;
import static android.Manifest.permission.READ_SEARCH_INDEXABLES;
+import static com.android.settings.wifi.calling.WifiCallingSliceHelper.PATH_WIFI_CALLING;
+
import android.app.PendingIntent;
import android.app.slice.SliceManager;
import android.content.ContentResolver;
@@ -32,7 +34,13 @@ import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;
+import androidx.slice.Slice;
+import androidx.slice.SliceProvider;
+import androidx.slice.builders.ListBuilder;
+import androidx.slice.builders.SliceAction;
+
import com.android.settings.R;
+import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.utils.ThreadUtils;
import java.net.URISyntaxException;
@@ -160,6 +168,11 @@ public class SettingsSliceProvider extends SliceProvider {
switch (path) {
case "/" + PATH_WIFI:
return createWifiSlice(sliceUri);
+ case "/" + PATH_WIFI_CALLING:
+ return FeatureFactory.getFactory(getContext())
+ .getSlicesFeatureProvider()
+ .getNewWifiCallingSliceHelper(getContext())
+ .createWifiCallingSlice(sliceUri);
}
SliceData cachedSliceData = mSliceWeakDataCache.get(sliceUri);
diff --git a/src/com/android/settings/slices/SliceBroadcastReceiver.java b/src/com/android/settings/slices/SliceBroadcastReceiver.java
index 47a7f5a45bd..04097340ed3 100644
--- a/src/com/android/settings/slices/SliceBroadcastReceiver.java
+++ b/src/com/android/settings/slices/SliceBroadcastReceiver.java
@@ -21,6 +21,7 @@ import static com.android.settings.slices.SettingsSliceProvider.ACTION_TOGGLE_CH
import static com.android.settings.slices.SettingsSliceProvider.ACTION_WIFI_CHANGED;
import static com.android.settings.slices.SettingsSliceProvider.EXTRA_SLICE_KEY;
import static com.android.settings.slices.SettingsSliceProvider.EXTRA_SLICE_PLATFORM_DEFINED;
+import static com.android.settings.wifi.calling.WifiCallingSliceHelper.ACTION_WIFI_CALLING_CHANGED;
import android.app.slice.Slice;
import android.content.BroadcastReceiver;
@@ -79,6 +80,12 @@ public class SliceBroadcastReceiver extends BroadcastReceiver {
context.getContentResolver().notifyChange(uri, null);
}, 1000);
break;
+ case ACTION_WIFI_CALLING_CHANGED:
+ FeatureFactory.getFactory(context)
+ .getSlicesFeatureProvider()
+ .getNewWifiCallingSliceHelper(context)
+ .handleWifiCallingChanged(intent);
+ break;
}
}
diff --git a/src/com/android/settings/slices/SlicesFeatureProvider.java b/src/com/android/settings/slices/SlicesFeatureProvider.java
index e5bba617e48..8dd6547b398 100644
--- a/src/com/android/settings/slices/SlicesFeatureProvider.java
+++ b/src/com/android/settings/slices/SlicesFeatureProvider.java
@@ -2,6 +2,8 @@ package com.android.settings.slices;
import android.content.Context;
+import com.android.settings.wifi.calling.WifiCallingSliceHelper;
+
/**
* Manages Slices in Settings.
*/
@@ -24,4 +26,9 @@ public interface SlicesFeatureProvider {
* If the data is already indexed, the data will not change.
*/
void indexSliceData(Context context);
-}
\ No newline at end of file
+
+ /**
+ * Gets new WifiCallingSliceHelper object
+ */
+ WifiCallingSliceHelper getNewWifiCallingSliceHelper(Context context);
+}
diff --git a/src/com/android/settings/slices/SlicesFeatureProviderImpl.java b/src/com/android/settings/slices/SlicesFeatureProviderImpl.java
index 8e5bc067150..16684bfb022 100644
--- a/src/com/android/settings/slices/SlicesFeatureProviderImpl.java
+++ b/src/com/android/settings/slices/SlicesFeatureProviderImpl.java
@@ -2,6 +2,7 @@ package com.android.settings.slices;
import android.content.Context;
+import com.android.settings.wifi.calling.WifiCallingSliceHelper;
import com.android.settingslib.utils.ThreadUtils;
/**
@@ -39,4 +40,9 @@ public class SlicesFeatureProviderImpl implements SlicesFeatureProvider {
SlicesIndexer indexer = getSliceIndexer(context);
indexer.indexSliceData();
}
-}
\ No newline at end of file
+
+ @Override
+ public WifiCallingSliceHelper getNewWifiCallingSliceHelper(Context context) {
+ return new WifiCallingSliceHelper(context);
+ }
+}
diff --git a/src/com/android/settings/wifi/calling/WifiCallingSliceHelper.java b/src/com/android/settings/wifi/calling/WifiCallingSliceHelper.java
new file mode 100644
index 00000000000..3452af777b0
--- /dev/null
+++ b/src/com/android/settings/wifi/calling/WifiCallingSliceHelper.java
@@ -0,0 +1,363 @@
+/*
+ * 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 android.app.PendingIntent;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.PersistableBundle;
+import androidx.core.graphics.drawable.IconCompat;
+import android.telephony.CarrierConfigManager;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+import android.text.TextUtils;
+import android.util.Log;
+
+import androidx.slice.Slice;
+import androidx.slice.builders.ListBuilder;
+import androidx.slice.builders.SliceAction;
+
+import com.android.ims.ImsManager;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.settings.R;
+import com.android.settings.slices.SliceBroadcastReceiver;
+import com.android.settings.slices.SliceBuilderUtils;
+
+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 setting.
+ */
+ public static final String PATH_WIFI_CALLING = "wifi_calling";
+
+ /**
+ * 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 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;
+
+ /**
+ * Time for which data contained in the slice can remain fresh.
+ */
+ private static final int SLICE_TTL_MILLIS = 60000;
+
+ protected SubscriptionManager mSubscriptionManager;
+ 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();
+ final String carrierName = getSimCarrierName();
+
+ if (subId <= SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
+ Log.d(TAG, "Invalid subscription Id");
+ return getNonActionableWifiCallingSlice(
+ mContext.getString(R.string.wifi_calling_settings_title),
+ mContext.getString(R.string.wifi_calling_not_supported, carrierName),
+ sliceUri, SliceBuilderUtils.getSettingsIntent(mContext));
+ }
+
+ final ImsManager imsManager = getImsManager(subId);
+
+ if (!imsManager.isWfcEnabledByPlatform()
+ || !imsManager.isWfcProvisionedOnDevice()) {
+ Log.d(TAG, "Wifi calling is either not provisioned or not enabled by Platform");
+ return getNonActionableWifiCallingSlice(
+ mContext.getString(R.string.wifi_calling_settings_title),
+ mContext.getString(R.string.wifi_calling_not_supported, carrierName),
+ sliceUri, SliceBuilderUtils.getSettingsIntent(mContext));
+ }
+
+ try {
+ final boolean isWifiCallingEnabled = isWifiCallingEnabled(imsManager);
+ 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
+ return getNonActionableWifiCallingSlice(
+ mContext.getString(R.string.wifi_calling_settings_title),
+ mContext.getString(
+ R.string.wifi_calling_settings_activation_instructions),
+ sliceUri, getActivityIntent(ACTION_WIFI_CALLING_SETTINGS_ACTIVITY));
+ }
+ return getWifiCallingSlice(sliceUri, mContext, isWifiCallingEnabled);
+ } catch (InterruptedException | TimeoutException | ExecutionException e) {
+ Log.e(TAG, "Unable to read the current WiFi calling status", e);
+ return getNonActionableWifiCallingSlice(
+ mContext.getString(R.string.wifi_calling_settings_title),
+ mContext.getString(R.string.wifi_calling_turn_on),
+ sliceUri, getActivityIntent(ACTION_WIFI_CALLING_SETTINGS_ACTIVITY));
+ }
+ }
+
+ private boolean isWifiCallingEnabled(ImsManager imsManager)
+ throws InterruptedException, ExecutionException, TimeoutException {
+ final FutureTask isWifiOnTask = new FutureTask<>(new Callable() {
+ @Override
+ public Boolean call() {
+ return imsManager.isWfcEnabledByUser();
+ }
+ });
+ final ExecutorService executor = Executors.newSingleThreadExecutor();
+ executor.execute(isWifiOnTask);
+
+ Boolean isWifiEnabledByUser = false;
+ isWifiEnabledByUser = isWifiOnTask.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
+
+ return isWifiEnabledByUser && imsManager.isNonTtyOrTtyOnVolteEnabled();
+ }
+
+ /**
+ * 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, Context mContext,
+ boolean isWifiCallingEnabled) {
+
+ final IconCompat icon = IconCompat.createWithResource(mContext, R.drawable.wifi_signal);
+ final String title = mContext.getString(R.string.wifi_calling_settings_title);
+ return new ListBuilder(mContext, sliceUri, SLICE_TTL_MILLIS)
+ .setColor(R.color.material_blue_500)
+ .addRow(b -> b
+ .setTitle(title)
+ .addEndItem(
+ new SliceAction(
+ getBroadcastIntent(ACTION_WIFI_CALLING_CHANGED),
+ null /* actionTitle */, isWifiCallingEnabled))
+ .setPrimaryAction(new SliceAction(
+ getActivityIntent(ACTION_WIFI_CALLING_SETTINGS_ACTIVITY),
+ icon,
+ title)))
+ .build();
+ }
+
+ protected ImsManager getImsManager(int subId) {
+ return ImsManager.getInstance(mContext, SubscriptionManager.getPhoneId(subId));
+ }
+
+ private Integer getWfcMode(ImsManager imsManager)
+ throws InterruptedException, ExecutionException, TimeoutException {
+ FutureTask wfcModeTask = new FutureTask<>(new Callable() {
+ @Override
+ public Integer call() {
+ return imsManager.getWfcMode(false);
+ }
+ });
+ 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 (subId > SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
+ final ImsManager imsManager = getImsManager(subId);
+ if (imsManager.isWfcEnabledByPlatform()
+ || imsManager.isWfcProvisionedOnDevice()) {
+ final boolean currentValue = imsManager.isWfcEnabledByUser()
+ && imsManager.isNonTtyOrTtyOnVolteEnabled();
+ final boolean newValue = intent.getBooleanExtra(EXTRA_TOGGLE_STATE,
+ currentValue);
+ final Intent activationAppIntent =
+ getWifiCallingCarrierActivityIntent(subId);
+ if (!newValue || activationAppIntent == null) {
+ // If either the action is to turn off wifi calling setting
+ // or there is no activation involved - Update the setting
+ if (newValue != currentValue) {
+ imsManager.setWfcSetting(newValue);
+ }
+ }
+ }
+ }
+ // notify change in slice in any case to get re-queried. This would result in displaying
+ // appropriate message with the updated setting.
+ final Uri uri = SliceBuilderUtils.getUri(PATH_WIFI_CALLING, false /*isPlatformSlice*/);
+ mContext.getContentResolver().notifyChange(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
+ */
+ // TODO(b/79548264) asses different scenarios and return null instead of non-actionable slice
+ private Slice getNonActionableWifiCallingSlice(String title, String subtitle, Uri sliceUri,
+ PendingIntent primaryActionIntent) {
+ final IconCompat icon = IconCompat.createWithResource(mContext, R.drawable.wifi_signal);
+ return new ListBuilder(mContext, sliceUri, SLICE_TTL_MILLIS)
+ .setColor(R.color.material_blue_500)
+ .addRow(b -> b
+ .setTitle(title)
+ .setSubtitle(subtitle)
+ .setPrimaryAction(new SliceAction(
+ primaryActionIntent, icon,
+ title)))
+ .build();
+ }
+
+ /**
+ * Returns {@code true} when the key is enabled for the carrier, and {@code false} otherwise.
+ */
+ private boolean isCarrierConfigManagerKeyEnabled(Context mContext, 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() {
+ if (mSubscriptionManager == null) {
+ mSubscriptionManager = mContext.getSystemService(SubscriptionManager.class);
+ }
+ 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;
+ }
+
+ private PendingIntent getBroadcastIntent(String action) {
+ final Intent intent = new Intent(action);
+ intent.setClass(mContext, SliceBroadcastReceiver.class);
+ return PendingIntent.getBroadcast(mContext, 0 /* requestCode */, intent,
+ PendingIntent.FLAG_CANCEL_CURRENT);
+ }
+
+ /**
+ * Returns PendingIntent to start activity specified by action
+ */
+ private PendingIntent getActivityIntent(String action) {
+ final Intent intent = new Intent(action);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ return PendingIntent.getActivity(mContext, 0 /* requestCode */, intent, 0 /* flags */);
+ }
+
+ /**
+ * Returns carrier id name of the current Subscription
+ */
+ private String getSimCarrierName() {
+ final TelephonyManager telephonyManager = mContext.getSystemService(TelephonyManager.class);
+ final CharSequence carrierName = telephonyManager.getSimCarrierIdName();
+ if (carrierName == null) {
+ return mContext.getString(R.string.carrier);
+ }
+ return carrierName.toString();
+ }
+
+}
diff --git a/tests/robotests/src/com/android/settings/wifi/calling/WifiCallingSliceHelperTest.java b/tests/robotests/src/com/android/settings/wifi/calling/WifiCallingSliceHelperTest.java
new file mode 100644
index 00000000000..ac3ff3ff635
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/wifi/calling/WifiCallingSliceHelperTest.java
@@ -0,0 +1,316 @@
+/*
+ * 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 android.app.slice.Slice.HINT_TITLE;
+import static android.app.slice.SliceItem.FORMAT_TEXT;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.net.Uri;
+import android.telephony.CarrierConfigManager;
+
+import androidx.slice.Slice;
+import androidx.slice.SliceItem;
+import androidx.slice.SliceMetadata;
+import androidx.slice.SliceProvider;
+import androidx.slice.core.SliceAction;
+import androidx.slice.core.SliceQuery;
+import androidx.slice.widget.SliceLiveData;
+
+import com.android.ims.ImsManager;
+import com.android.settings.R;
+import com.android.settings.slices.SettingsSliceProvider;
+import com.android.settings.slices.SliceBroadcastReceiver;
+import com.android.settings.slices.SliceBuilderUtils;
+import com.android.settings.slices.SliceData;
+import com.android.settings.slices.SlicesFeatureProvider;
+import com.android.settings.testutils.FakeFeatureFactory;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
+
+import java.util.List;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+public class WifiCallingSliceHelperTest {
+
+ private Context mContext;
+ @Mock
+ private CarrierConfigManager mMockCarrierConfigManager;
+
+ @Mock
+ private ImsManager mMockImsManager;
+
+ private final Uri mWfcURI = Uri.parse("content://com.android.settings.slices/wifi_calling");
+
+ private FakeWifiCallingSliceHelper mWfcSliceHelper;
+ private SettingsSliceProvider mProvider;
+ private SliceBroadcastReceiver mReceiver;
+ private FakeFeatureFactory mFeatureFactory;
+ private SlicesFeatureProvider mSlicesFeatureProvider;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mContext = spy(RuntimeEnvironment.application);
+
+ //setup for SettingsSliceProvider tests
+ mProvider = spy(new SettingsSliceProvider());
+ doReturn(mContext).when(mProvider).getContext();
+
+ //setup for SliceBroadcastReceiver test
+ mReceiver = spy(new SliceBroadcastReceiver());
+
+ mFeatureFactory = FakeFeatureFactory.setupForTest();
+ mSlicesFeatureProvider = mFeatureFactory.getSlicesFeatureProvider();
+
+ // Prevent crash in SliceMetadata.
+ Resources resources = spy(mContext.getResources());
+ doReturn(60).when(resources).getDimensionPixelSize(anyInt());
+ doReturn(resources).when(mContext).getResources();
+
+ mWfcSliceHelper = new FakeWifiCallingSliceHelper(mContext);
+
+ // Set-up specs for SliceMetadata.
+ SliceProvider.setSpecs(SliceLiveData.SUPPORTED_SPECS);
+ }
+
+ @Test
+ public void test_CreateWifiCallingSlice_invalidSubId() {
+ mWfcSliceHelper.setDefaultVoiceSubId(-1);
+
+ final Slice slice = mWfcSliceHelper.createWifiCallingSlice(mWfcURI);
+
+ testWifiCallingSettingsUnavailableSlice(slice, null,
+ SliceBuilderUtils.getSettingsIntent(mContext));
+ }
+
+ @Test
+ public void test_CreateWifiCallingSlice_wfcNotSupported() {
+ doReturn(false).when(mMockImsManager).isWfcEnabledByPlatform();
+
+ final Slice slice = mWfcSliceHelper.createWifiCallingSlice(mWfcURI);
+
+ assertThat(mWfcSliceHelper.getDefaultVoiceSubId()).isEqualTo(1);
+ testWifiCallingSettingsUnavailableSlice(slice, null,
+ SliceBuilderUtils.getSettingsIntent(mContext));
+ }
+
+ @Test
+ public void test_CreateWifiCallingSlice_needsActivation() {
+ /* In cases where activation is needed and the user action
+ would be turning on the wifi calling (i.e. if wifi calling is
+ turned off) we need to guide the user to wifi calling settings
+ activity so the user can perform the activation there.(PrimaryAction)
+ */
+ doReturn(true).when(mMockImsManager).isWfcEnabledByPlatform();
+ doReturn(true).when(mMockImsManager).isWfcProvisionedOnDevice();
+ doReturn(false).when(mMockImsManager).isWfcEnabledByUser();
+ doReturn(false).when(mMockImsManager).isNonTtyOrTtyOnVolteEnabled();
+ doReturn(null).when(mMockCarrierConfigManager).getConfigForSubId(1);
+ mWfcSliceHelper.setActivationAppIntent(new Intent()); // dummy Intent
+
+ final Slice slice = mWfcSliceHelper.createWifiCallingSlice(mWfcURI);
+
+ assertThat(mWfcSliceHelper.getDefaultVoiceSubId()).isEqualTo(1);
+ testWifiCallingSettingsUnavailableSlice(slice, null,
+ getActivityIntent(WifiCallingSliceHelper.ACTION_WIFI_CALLING_SETTINGS_ACTIVITY));
+ }
+
+ @Test
+ public void test_CreateWifiCallingSlice_success() {
+ doReturn(true).when(mMockImsManager).isWfcEnabledByPlatform();
+ doReturn(true).when(mMockImsManager).isWfcProvisionedOnDevice();
+ doReturn(true).when(mMockImsManager).isWfcEnabledByUser();
+ doReturn(true).when(mMockImsManager).isNonTtyOrTtyOnVolteEnabled();
+ doReturn(null).when(mMockCarrierConfigManager).getConfigForSubId(1);
+
+ final Slice slice = mWfcSliceHelper.createWifiCallingSlice(mWfcURI);
+
+ assertThat(mWfcSliceHelper.getDefaultVoiceSubId()).isEqualTo(1);
+ testWifiCallingSettingsToggleSlice(slice, null);
+ }
+
+ @Test
+ public void test_SettingSliceProvider_getsRightSliceWifiCalling() {
+ doReturn(true).when(mMockImsManager).isWfcEnabledByPlatform();
+ doReturn(true).when(mMockImsManager).isWfcProvisionedOnDevice();
+ doReturn(true).when(mMockImsManager).isWfcEnabledByUser();
+ doReturn(true).when(mMockImsManager).isNonTtyOrTtyOnVolteEnabled();
+ doReturn(null).when(mMockCarrierConfigManager).getConfigForSubId(1);
+ doReturn(mWfcSliceHelper).when(mSlicesFeatureProvider)
+ .getNewWifiCallingSliceHelper(mContext);
+
+ final Slice slice = mProvider.onBindSlice(mWfcURI);
+
+ assertThat(mWfcSliceHelper.getDefaultVoiceSubId()).isEqualTo(1);
+ testWifiCallingSettingsToggleSlice(slice, null);
+ }
+
+ @Test
+ public void test_SliceBroadcastReceiver_toggleOffWifiCalling() {
+ doReturn(true).when(mMockImsManager).isWfcEnabledByPlatform();
+ doReturn(true).when(mMockImsManager).isWfcProvisionedOnDevice();
+ doReturn(false).when(mMockImsManager).isWfcEnabledByUser();
+ doReturn(true).when(mMockImsManager).isNonTtyOrTtyOnVolteEnabled();
+ doReturn(mWfcSliceHelper).when(mSlicesFeatureProvider)
+ .getNewWifiCallingSliceHelper(mContext);
+ mWfcSliceHelper.setActivationAppIntent(null);
+
+ ArgumentCaptor mWfcSettingCaptor = ArgumentCaptor.forClass(Boolean.class);
+
+ // turn on Wifi calling setting
+ Intent intent = new Intent(WifiCallingSliceHelper.ACTION_WIFI_CALLING_CHANGED);
+ intent.putExtra(EXTRA_TOGGLE_STATE, true);
+
+ // change the setting
+ mReceiver.onReceive(mContext, intent);
+
+ verify((mMockImsManager)).setWfcSetting(mWfcSettingCaptor.capture());
+
+ // assert the change
+ assertThat(mWfcSettingCaptor.getValue()).isTrue();
+ }
+
+ private void testWifiCallingSettingsUnavailableSlice(Slice slice,
+ SliceData sliceData, PendingIntent expectedPrimaryAction) {
+ final SliceMetadata metadata = SliceMetadata.from(mContext, slice);
+
+ //Check there is no toggle action
+ final List toggles = metadata.getToggles();
+ assertThat(toggles).isEmpty();
+
+ // Check whether the primary action is to open wifi calling settings activity
+ final PendingIntent primaryPendingIntent =
+ metadata.getPrimaryAction().getAction();
+ assertThat(primaryPendingIntent).isEqualTo(expectedPrimaryAction);
+
+ // Check the title
+ final List sliceItems = slice.getItems();
+ assertTitle(sliceItems, mContext.getString(R.string.wifi_calling_settings_title));
+ }
+
+ private void testWifiCallingSettingsToggleSlice(Slice slice,
+ SliceData sliceData) {
+ final SliceMetadata metadata = SliceMetadata.from(mContext, slice);
+
+ final List toggles = metadata.getToggles();
+ assertThat(toggles).hasSize(1);
+
+ final SliceAction mainToggleAction = toggles.get(0);
+
+ // Check intent in Toggle Action
+ final PendingIntent togglePendingIntent = mainToggleAction.getAction();
+ final PendingIntent expectedToggleIntent = getBroadcastIntent(
+ WifiCallingSliceHelper.ACTION_WIFI_CALLING_CHANGED);
+ assertThat(togglePendingIntent).isEqualTo(expectedToggleIntent);
+
+ // Check primary intent
+ final PendingIntent primaryPendingIntent = metadata.getPrimaryAction().getAction();
+ final PendingIntent expectedPendingIntent =
+ getActivityIntent(WifiCallingSliceHelper.ACTION_WIFI_CALLING_SETTINGS_ACTIVITY);
+ assertThat(primaryPendingIntent).isEqualTo(expectedPendingIntent);
+
+ // Check the title
+ final List sliceItems = slice.getItems();
+ assertTitle(sliceItems, mContext.getString(R.string.wifi_calling_settings_title));
+ }
+
+ private PendingIntent getBroadcastIntent(String action) {
+ final Intent intent = new Intent(action);
+ intent.setClass(mContext, SliceBroadcastReceiver.class);
+ return PendingIntent.getBroadcast(mContext, 0 /* requestCode */, intent,
+ PendingIntent.FLAG_CANCEL_CURRENT);
+ }
+
+ private PendingIntent getActivityIntent(String action) {
+ final Intent intent = new Intent(action);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ return PendingIntent.getActivity(mContext, 0 /* requestCode */, intent, 0 /* flags */);
+ }
+
+ private void assertTitle(List sliceItems, String title) {
+ boolean hasTitle = false;
+ for (SliceItem item : sliceItems) {
+ List titleItems = SliceQuery.findAll(item, FORMAT_TEXT, HINT_TITLE,
+ null /* non-hints */);
+ if (titleItems == null) {
+ continue;
+ }
+
+ hasTitle = true;
+ for (SliceItem subTitleItem : titleItems) {
+ assertThat(subTitleItem.getText()).isEqualTo(title);
+ }
+ }
+ assertThat(hasTitle).isTrue();
+ }
+ private class FakeWifiCallingSliceHelper extends WifiCallingSliceHelper {
+ int mSubId = 1;
+
+ private Intent mActivationAppIntent;
+ FakeWifiCallingSliceHelper(Context context) {
+ super(context);
+ mActivationAppIntent = null;
+ }
+
+ @Override
+ protected CarrierConfigManager getCarrierConfigManager(Context mContext) {
+ return mMockCarrierConfigManager;
+ }
+
+ @Override
+ protected ImsManager getImsManager(int subId) {
+ return mMockImsManager;
+ }
+
+ protected int getDefaultVoiceSubId() {
+ return mSubId;
+ }
+
+ protected void setDefaultVoiceSubId(int id) {
+ mSubId = id;
+ }
+
+ @Override
+ protected Intent getWifiCallingCarrierActivityIntent(int subId) {
+ return mActivationAppIntent;
+ }
+
+ public void setActivationAppIntent(Intent intent) {
+ mActivationAppIntent = intent;
+ }
+ }
+}