diff --git a/src/com/android/settings/mobilenetwork/Enhanced4gLteSliceHelper.java b/src/com/android/settings/mobilenetwork/Enhanced4gLteSliceHelper.java new file mode 100644 index 00000000000..de542ace95c --- /dev/null +++ b/src/com/android/settings/mobilenetwork/Enhanced4gLteSliceHelper.java @@ -0,0 +1,295 @@ +/* + * 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.mobilenetwork; + +import static android.app.slice.Slice.EXTRA_TOGGLE_STATE; + +import android.app.PendingIntent; +import android.content.ContentResolver; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.res.Resources; +import android.net.Uri; +import android.os.PersistableBundle; +import androidx.core.graphics.drawable.IconCompat; +import android.telephony.CarrierConfigManager; +import android.telephony.SubscriptionManager; +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.Utils; +import com.android.settings.slices.SettingsSliceProvider; +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 enhanced 4g LTE settings. + */ +public class Enhanced4gLteSliceHelper { + + private static final String TAG = "Enhanced4gLteSliceHelper"; + + /** + * Settings slice path to enhanced 4g LTE setting. + */ + public static final String PATH_ENHANCED_4G_LTE = "enhanced_4g_lte"; + + /** + * Action passed for changes to enhanced 4g LTE slice (toggle). + */ + public static final String ACTION_ENHANCED_4G_LTE_CHANGED = + "com.android.settings.mobilenetwork.action.ENHANCED_4G_LTE_CHANGED"; + + /** + * Slice Uri for Enhanced 4G slice + */ + public static final Uri SLICE_URI = new Uri.Builder() + .scheme(ContentResolver.SCHEME_CONTENT) + .authority(SettingsSliceProvider.SLICE_AUTHORITY) + .appendPath(PATH_ENHANCED_4G_LTE) + .build(); + /** + * Action for mobile network settings activity which + * allows setting configuration for Enhanced 4G LTE + * related settings + */ + public static final String ACTION_MOBILE_NETWORK_SETTINGS_ACTIVITY = + "android.settings.NETWORK_OPERATOR_SETTINGS"; + + /** + * Timeout for querying enhanced 4g lte setting from ims manager. + */ + private static final int TIMEOUT_MILLIS = 2000; + + private final Context mContext; + + /** + * Phone package name + */ + private static final String PACKAGE_PHONE = "com.android.phone"; + + /** + * String resource type + */ + private static final String RESOURCE_TYPE_STRING = "string"; + + /** + * Enhanced 4g lte mode title variant resource name + */ + private static final String RESOURCE_ENHANCED_4G_LTE_MODE_TITLE_VARIANT = + "enhanced_4g_lte_mode_title_variant"; + + @VisibleForTesting + public Enhanced4gLteSliceHelper(Context context) { + mContext = context; + } + + /** + * Returns Slice object for enhanced_4g_lte settings. + * + * If enhanced 4g LTE is not supported for the current carrier, this method will return slice + * with not supported message. + * + * If enhanced 4g LTE is not editable for the current carrier, this method will return slice + * with not editable message. + * + * If enhanced 4g LTE setting can be changed, this method will return the slice to toggle + * enhanced 4g LTE option with ACTION_ENHANCED_4G_LTE_CHANGED as endItem. + */ + public Slice createEnhanced4gLteSlice(Uri sliceUri) { + final int subId = getDefaultVoiceSubId(); + + if (subId <= SubscriptionManager.INVALID_SUBSCRIPTION_ID) { + Log.d(TAG, "Invalid subscription Id"); + return null; + } + + final ImsManager imsManager = getImsManager(subId); + + if (!imsManager.isVolteEnabledByPlatform() + || !imsManager.isVolteProvisionedOnDevice()) { + Log.d(TAG, "Setting is either not provisioned or not enabled by Platform"); + return null; + } + + if (isCarrierConfigManagerKeyEnabled( + CarrierConfigManager.KEY_HIDE_ENHANCED_4G_LTE_BOOL, subId, false) + || !isCarrierConfigManagerKeyEnabled( + CarrierConfigManager.KEY_EDITABLE_ENHANCED_4G_LTE_BOOL, subId, + true)) { + Log.d(TAG, "Setting is either hidden or not editable"); + return null; + } + + try { + return getEnhanced4gLteSlice(sliceUri, + isEnhanced4gLteModeEnabled(imsManager), subId); + } catch (InterruptedException | TimeoutException | ExecutionException e) { + Log.e(TAG, "Unable to read the current Enhanced 4g LTE status", e); + return null; + } + } + + private boolean isEnhanced4gLteModeEnabled(ImsManager imsManager) + throws InterruptedException, ExecutionException, TimeoutException { + final FutureTask isEnhanced4gLteOnTask = new FutureTask<>(new Callable() { + @Override + public Boolean call() { + return imsManager.isEnhanced4gLteModeSettingEnabledByUser(); + } + }); + final ExecutorService executor = Executors.newSingleThreadExecutor(); + executor.execute(isEnhanced4gLteOnTask); + + return isEnhanced4gLteOnTask.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); + } + + /** + * Builds a toggle slice where the intent takes you to the Enhanced 4G LTE page and the toggle + * enables/disables Enhanced 4G LTE mode setting. + */ + private Slice getEnhanced4gLteSlice(Uri sliceUri, boolean isEnhanced4gLteEnabled, int subId) { + final IconCompat icon = IconCompat.createWithResource(mContext, + R.drawable.ic_launcher_settings); + + return new ListBuilder(mContext, sliceUri, ListBuilder.INFINITY) + .setAccentColor(Utils.getColorAccentDefaultColor(mContext)) + .addRow(b -> b + .setTitle(getEnhanced4glteModeTitle(subId)) + .addEndItem( + new SliceAction( + getBroadcastIntent(ACTION_ENHANCED_4G_LTE_CHANGED), + null /* actionTitle */, isEnhanced4gLteEnabled)) + .setPrimaryAction(new SliceAction( + getActivityIntent(ACTION_MOBILE_NETWORK_SETTINGS_ACTIVITY), + icon, + getEnhanced4glteModeTitle(subId)))) + .build(); + } + + protected ImsManager getImsManager(int subId) { + return ImsManager.getInstance(mContext, SubscriptionManager.getPhoneId(subId)); + } + + /** + * Handles Enhanced 4G LTE mode setting change from Enhanced 4G LTE slice and posts + * notification. Should be called when intent action is ACTION_ENHANCED_4G_LTE_CHANGED + * + * @param intent action performed + */ + public void handleEnhanced4gLteChanged(Intent intent) { + final int subId = getDefaultVoiceSubId(); + + if (subId > SubscriptionManager.INVALID_SUBSCRIPTION_ID) { + final ImsManager imsManager = getImsManager(subId); + if (imsManager.isVolteEnabledByPlatform() + && imsManager.isVolteProvisionedOnDevice()) { + final boolean currentValue = imsManager.isEnhanced4gLteModeSettingEnabledByUser() + && imsManager.isNonTtyOrTtyOnVolteEnabled(); + final boolean newValue = intent.getBooleanExtra(EXTRA_TOGGLE_STATE, + currentValue); + if (newValue != currentValue) { + imsManager.setEnhanced4gLteModeSetting(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_ENHANCED_4G_LTE, false /*isPlatformSlice*/); + mContext.getContentResolver().notifyChange(uri, null); + } + + private CharSequence getEnhanced4glteModeTitle(int subId) { + CharSequence ret = mContext.getText(R.string.enhanced_4g_lte_mode_title); + try { + if (isCarrierConfigManagerKeyEnabled( + CarrierConfigManager.KEY_ENHANCED_4G_LTE_TITLE_VARIANT_BOOL, + subId, + false)) { + final PackageManager manager = mContext.getPackageManager(); + final Resources resources = manager.getResourcesForApplication( + PACKAGE_PHONE); + final int resId = resources.getIdentifier( + RESOURCE_ENHANCED_4G_LTE_MODE_TITLE_VARIANT, + RESOURCE_TYPE_STRING, PACKAGE_PHONE); + ret = resources.getText(resId); + } + } catch (PackageManager.NameNotFoundException e) { + Log.e(TAG, "package name not found"); + } + return ret; + } + + /** + * Returns {@code true} when the key is enabled for the carrier, and {@code false} otherwise. + */ + private boolean isCarrierConfigManagerKeyEnabled(String key, + int subId, boolean defaultValue) { + final CarrierConfigManager configManager = getCarrierConfigManager(); + boolean ret = defaultValue; + if (configManager != null) { + final PersistableBundle bundle = configManager.getConfigForSubId(subId); + if (bundle != null) { + ret = bundle.getBoolean(key, defaultValue); + } + } + return ret; + } + + protected CarrierConfigManager getCarrierConfigManager() { + return mContext.getSystemService(CarrierConfigManager.class); + } + + 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 the current default voice subId obtained from SubscriptionManager + */ + protected int getDefaultVoiceSubId() { + return SubscriptionManager.getDefaultVoiceSubscriptionId(); + } + + /** + * 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 */); + } +} + diff --git a/src/com/android/settings/slices/SettingsSliceProvider.java b/src/com/android/settings/slices/SettingsSliceProvider.java index f4dfd6ee71d..0fd5c42f4df 100644 --- a/src/com/android/settings/slices/SettingsSliceProvider.java +++ b/src/com/android/settings/slices/SettingsSliceProvider.java @@ -36,6 +36,7 @@ import com.android.settings.bluetooth.BluetoothSliceBuilder; import com.android.settings.core.BasePreferenceController; import com.android.settings.location.LocationSliceBuilder; import com.android.settings.notification.ZenModeSliceBuilder; +import com.android.settings.mobilenetwork.Enhanced4gLteSliceHelper; import com.android.settings.overlay.FeatureFactory; import com.android.settings.wifi.WifiSliceBuilder; import com.android.settings.wifi.calling.WifiCallingSliceHelper; @@ -190,23 +191,27 @@ public class SettingsSliceProvider extends SliceProvider { Log.e(TAG, "Requested blocked slice with Uri: " + sliceUri); return null; } - - // If adding a new Slice, do not directly match Slice URIs. - // Use {@link SlicesDatabaseAccessor}. - if (WifiCallingSliceHelper.WIFI_CALLING_URI.equals(sliceUri)) { - return FeatureFactory.getFactory(getContext()) - .getSlicesFeatureProvider() - .getNewWifiCallingSliceHelper(getContext()) - .createWifiCallingSlice(sliceUri); - } else if (WifiSliceBuilder.WIFI_URI.equals(sliceUri)) { - return WifiSliceBuilder.getSlice(getContext()); - } else if (ZenModeSliceBuilder.ZEN_MODE_URI.equals(sliceUri)) { - return ZenModeSliceBuilder.getSlice(getContext()); - } else if (BluetoothSliceBuilder.BLUETOOTH_URI.equals(sliceUri)) { - return BluetoothSliceBuilder.getSlice(getContext()); - } else if (LocationSliceBuilder.LOCATION_URI.equals(sliceUri)) { - return LocationSliceBuilder.getSlice(getContext()); - } + // If adding a new Slice, do not directly match Slice URIs. + // Use {@link SlicesDatabaseAccessor}. + if (WifiCallingSliceHelper.WIFI_CALLING_URI.equals(sliceUri)) { + return FeatureFactory.getFactory(getContext()) + .getSlicesFeatureProvider() + .getNewWifiCallingSliceHelper(getContext()) + .createWifiCallingSlice(sliceUri); + } else if (WifiSliceBuilder.WIFI_URI.equals(sliceUri)) { + return WifiSliceBuilder.getSlice(getContext()); + } else if (ZenModeSliceBuilder.ZEN_MODE_URI.equals(sliceUri)) { + return ZenModeSliceBuilder.getSlice(getContext()); + } else if (BluetoothSliceBuilder.BLUETOOTH_URI.equals(sliceUri)) { + return BluetoothSliceBuilder.getSlice(getContext()); + } else if (LocationSliceBuilder.LOCATION_URI.equals(sliceUri)) { + return LocationSliceBuilder.getSlice(getContext()); + } else if (Enhanced4gLteSliceHelper.SLICE_URI.equals(sliceUri)) { + return FeatureFactory.getFactory(getContext()) + .getSlicesFeatureProvider() + .getNewEnhanced4gLteSliceHelper(getContext()) + .createEnhanced4gLteSlice(sliceUri); + } SliceData cachedSliceData = mSliceWeakDataCache.get(sliceUri); if (cachedSliceData == null) { diff --git a/src/com/android/settings/slices/SliceBroadcastReceiver.java b/src/com/android/settings/slices/SliceBroadcastReceiver.java index d81734a974d..231298c9ddd 100644 --- a/src/com/android/settings/slices/SliceBroadcastReceiver.java +++ b/src/com/android/settings/slices/SliceBroadcastReceiver.java @@ -24,6 +24,7 @@ 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 static com.android.settings.wifi.WifiSliceBuilder.ACTION_WIFI_SLICE_CHANGED; +import static com.android.settings.mobilenetwork.Enhanced4gLteSliceHelper.ACTION_ENHANCED_4G_LTE_CHANGED; import android.app.slice.Slice; import android.content.BroadcastReceiver; @@ -84,6 +85,12 @@ public class SliceBroadcastReceiver extends BroadcastReceiver { case ACTION_ZEN_MODE_SLICE_CHANGED: ZenModeSliceBuilder.handleUriChange(context, intent); break; + case ACTION_ENHANCED_4G_LTE_CHANGED: + FeatureFactory.getFactory(context) + .getSlicesFeatureProvider() + .getNewEnhanced4gLteSliceHelper(context) + .handleEnhanced4gLteChanged(intent); + break; default: final String uriString = intent.getStringExtra(SliceBroadcastRelay.EXTRA_URI); if (!TextUtils.isEmpty(uriString)) { diff --git a/src/com/android/settings/slices/SlicesFeatureProvider.java b/src/com/android/settings/slices/SlicesFeatureProvider.java index 8dd6547b398..8395a58dc16 100644 --- a/src/com/android/settings/slices/SlicesFeatureProvider.java +++ b/src/com/android/settings/slices/SlicesFeatureProvider.java @@ -2,6 +2,7 @@ package com.android.settings.slices; import android.content.Context; +import com.android.settings.mobilenetwork.Enhanced4gLteSliceHelper; import com.android.settings.wifi.calling.WifiCallingSliceHelper; /** @@ -31,4 +32,10 @@ public interface SlicesFeatureProvider { * Gets new WifiCallingSliceHelper object */ WifiCallingSliceHelper getNewWifiCallingSliceHelper(Context context); + + /** + * Gets new Enhanced4gLteSliceHelper object + */ + Enhanced4gLteSliceHelper getNewEnhanced4gLteSliceHelper(Context context); } + diff --git a/src/com/android/settings/slices/SlicesFeatureProviderImpl.java b/src/com/android/settings/slices/SlicesFeatureProviderImpl.java index 16684bfb022..988bcfe2273 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.mobilenetwork.Enhanced4gLteSliceHelper; import com.android.settings.wifi.calling.WifiCallingSliceHelper; import com.android.settingslib.utils.ThreadUtils; @@ -45,4 +46,9 @@ public class SlicesFeatureProviderImpl implements SlicesFeatureProvider { public WifiCallingSliceHelper getNewWifiCallingSliceHelper(Context context) { return new WifiCallingSliceHelper(context); } + + @Override + public Enhanced4gLteSliceHelper getNewEnhanced4gLteSliceHelper(Context context) { + return new Enhanced4gLteSliceHelper(context); + } } diff --git a/tests/robotests/src/com/android/settings/mobilenetwork/Enhanced4gLteSliceHelperTest.java b/tests/robotests/src/com/android/settings/mobilenetwork/Enhanced4gLteSliceHelperTest.java new file mode 100644 index 00000000000..625a68bef85 --- /dev/null +++ b/tests/robotests/src/com/android/settings/mobilenetwork/Enhanced4gLteSliceHelperTest.java @@ -0,0 +1,281 @@ +/* + * 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.mobilenetwork; + +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.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.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 Enhanced4gLteSliceHelperTest { + + private Context mContext; + @Mock + private CarrierConfigManager mMockCarrierConfigManager; + + @Mock + private ImsManager mMockImsManager; + + private FakeEnhanced4gLteSliceHelper mEnhanced4gLteSliceHelper; + 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(); + + mEnhanced4gLteSliceHelper = new FakeEnhanced4gLteSliceHelper(mContext); + + // Set-up specs for SliceMetadata. + SliceProvider.setSpecs(SliceLiveData.SUPPORTED_SPECS); + } + + @Test + public void test_CreateEnhanced4gLteSlice_invalidSubId() { + mEnhanced4gLteSliceHelper.setDefaultVoiceSubId(-1); + + final Slice slice = mEnhanced4gLteSliceHelper.createEnhanced4gLteSlice( + Enhanced4gLteSliceHelper.SLICE_URI); + + assertThat(slice).isNull(); + } + + @Test + public void test_CreateEnhanced4gLteSlice_enhanced4gLteNotSupported() { + when(mMockImsManager.isVolteEnabledByPlatform()).thenReturn(false); + + final Slice slice = mEnhanced4gLteSliceHelper.createEnhanced4gLteSlice( + Enhanced4gLteSliceHelper.SLICE_URI); + + assertThat(mEnhanced4gLteSliceHelper.getDefaultVoiceSubId()).isEqualTo(1); + assertThat(slice).isNull(); + } + + @Test + public void test_CreateEnhanced4gLteSlice_success() { + when(mMockImsManager.isVolteEnabledByPlatform()).thenReturn(true); + when(mMockImsManager.isVolteProvisionedOnDevice()).thenReturn(true); + when(mMockImsManager.isEnhanced4gLteModeSettingEnabledByUser()).thenReturn(true); + when(mMockImsManager.isNonTtyOrTtyOnVolteEnabled()).thenReturn(true); + when(mMockCarrierConfigManager.getConfigForSubId(1)).thenReturn(null); + + final Slice slice = mEnhanced4gLteSliceHelper.createEnhanced4gLteSlice( + Enhanced4gLteSliceHelper.SLICE_URI); + + assertThat(mEnhanced4gLteSliceHelper.getDefaultVoiceSubId()).isEqualTo(1); + testEnhanced4gLteSettingsToggleSlice(slice); + } + + @Test + public void test_SettingSliceProvider_getsRightSliceEnhanced4gLte() { + when(mMockImsManager.isVolteEnabledByPlatform()).thenReturn(true); + when(mMockImsManager.isVolteProvisionedOnDevice()).thenReturn(true); + when(mMockImsManager.isEnhanced4gLteModeSettingEnabledByUser()).thenReturn(true); + when(mMockImsManager.isNonTtyOrTtyOnVolteEnabled()).thenReturn(true); + when(mMockCarrierConfigManager.getConfigForSubId(1)).thenReturn(null); + when(mSlicesFeatureProvider.getNewEnhanced4gLteSliceHelper(mContext)) + .thenReturn(mEnhanced4gLteSliceHelper); + + final Slice slice = mProvider.onBindSlice(Enhanced4gLteSliceHelper.SLICE_URI); + + assertThat(mEnhanced4gLteSliceHelper.getDefaultVoiceSubId()).isEqualTo(1); + testEnhanced4gLteSettingsToggleSlice(slice); + } + + @Test + public void test_SliceBroadcastReceiver_toggleOffEnhanced4gLte() { + when(mMockImsManager.isVolteEnabledByPlatform()).thenReturn(true); + when(mMockImsManager.isVolteProvisionedOnDevice()).thenReturn(true); + when(mMockImsManager.isEnhanced4gLteModeSettingEnabledByUser()).thenReturn(false); + when(mMockImsManager.isNonTtyOrTtyOnVolteEnabled()).thenReturn(true); + when(mSlicesFeatureProvider.getNewEnhanced4gLteSliceHelper(mContext)) + .thenReturn(mEnhanced4gLteSliceHelper); + + ArgumentCaptor mEnhanced4gLteSettingCaptor = ArgumentCaptor.forClass( + Boolean.class); + + // turn on Enhanced4gLte setting + Intent intent = new Intent(Enhanced4gLteSliceHelper.ACTION_ENHANCED_4G_LTE_CHANGED); + intent.putExtra(EXTRA_TOGGLE_STATE, true); + + // change the setting + mReceiver.onReceive(mContext, intent); + + verify((mMockImsManager)).setEnhanced4gLteModeSetting( + mEnhanced4gLteSettingCaptor.capture()); + + // assert the change + assertThat(mEnhanced4gLteSettingCaptor.getValue()).isTrue(); + } + + private void testEnhanced4gLteSettingsUnavailableSlice(Slice slice, + 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 Enhanced4gLte 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.enhanced_4g_lte_mode_title)); + } + + private void testEnhanced4gLteSettingsToggleSlice(Slice slice) { + 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( + Enhanced4gLteSliceHelper.ACTION_ENHANCED_4G_LTE_CHANGED); + assertThat(togglePendingIntent).isEqualTo(expectedToggleIntent); + + // Check primary intent + final PendingIntent primaryPendingIntent = metadata.getPrimaryAction().getAction(); + final PendingIntent expectedPendingIntent = + getActivityIntent(Enhanced4gLteSliceHelper.ACTION_MOBILE_NETWORK_SETTINGS_ACTIVITY); + assertThat(primaryPendingIntent).isEqualTo(expectedPendingIntent); + + // Check the title + final List sliceItems = slice.getItems(); + assertTitle(sliceItems, mContext.getString(R.string.enhanced_4g_lte_mode_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 FakeEnhanced4gLteSliceHelper extends Enhanced4gLteSliceHelper { + int mSubId = 1; + + FakeEnhanced4gLteSliceHelper(Context context) { + super(context); + } + + @Override + protected CarrierConfigManager getCarrierConfigManager() { + return mMockCarrierConfigManager; + } + + @Override + protected ImsManager getImsManager(int subId) { + return mMockImsManager; + } + + protected int getDefaultVoiceSubId() { + return mSubId; + } + + protected void setDefaultVoiceSubId(int id) { + mSubId = id; + } + } +}