diff --git a/res/drawable/ic_radio_button_checked_black_24dp.xml b/res/drawable/ic_radio_button_checked_black_24dp.xml new file mode 100644 index 00000000000..3be6f9962e3 --- /dev/null +++ b/res/drawable/ic_radio_button_checked_black_24dp.xml @@ -0,0 +1,24 @@ + + + + diff --git a/res/drawable/ic_radio_button_unchecked_black_24dp.xml b/res/drawable/ic_radio_button_unchecked_black_24dp.xml new file mode 100644 index 00000000000..a864f7b07b4 --- /dev/null +++ b/res/drawable/ic_radio_button_unchecked_black_24dp.xml @@ -0,0 +1,24 @@ + + + + diff --git a/res/drawable/radio_button_check.xml b/res/drawable/radio_button_check.xml new file mode 100644 index 00000000000..e7884d71731 --- /dev/null +++ b/res/drawable/radio_button_check.xml @@ -0,0 +1,26 @@ + + + + + + \ No newline at end of file diff --git a/res/values/strings.xml b/res/values/strings.xml index c3faa20a623..1646b7016d6 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -7256,7 +7256,7 @@ You will see notifications on your screen When notifications arrive, your phone won\u2019t make a sound or vibrate. - + No visuals or sound from notifications You won\u2019t see or hear notifications 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/nfc/PaymentSettings.java b/src/com/android/settings/nfc/PaymentSettings.java index 82335814581..6e03842634f 100644 --- a/src/com/android/settings/nfc/PaymentSettings.java +++ b/src/com/android/settings/nfc/PaymentSettings.java @@ -20,12 +20,15 @@ import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.os.Bundle; +import android.os.UserHandle; +import android.os.UserManager; import android.provider.SearchIndexableResource; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; +import android.content.pm.UserInfo; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settings.R; @@ -111,6 +114,11 @@ public class PaymentSettings extends DashboardFragment { @Override protected boolean isPageSearchEnabled(Context context) { + final UserManager userManager = context.getSystemService(UserManager.class); + final UserInfo myUserInfo = userManager.getUserInfo(UserHandle.myUserId()); + if (myUserInfo.isGuest()) { + return false; + } final PackageManager pm = context.getPackageManager(); return pm.hasSystemFeature(PackageManager.FEATURE_NFC); } diff --git a/src/com/android/settings/notification/ZenModeStarredContactsPreferenceController.java b/src/com/android/settings/notification/ZenModeStarredContactsPreferenceController.java index 0996534b9d9..28475b6b5e3 100644 --- a/src/com/android/settings/notification/ZenModeStarredContactsPreferenceController.java +++ b/src/com/android/settings/notification/ZenModeStarredContactsPreferenceController.java @@ -117,6 +117,7 @@ public class ZenModeStarredContactsPreferenceController extends } } + // values in displayContacts must not be null mPreference.setSummary(ListFormatter.getInstance().format(displayContacts)); } @@ -130,22 +131,32 @@ public class ZenModeStarredContactsPreferenceController extends return true; } - private List getStarredContacts() { + @VisibleForTesting + List getStarredContacts(Cursor cursor) { List starredContacts = new ArrayList<>(); - Cursor cursor = mContext.getContentResolver().query(ContactsContract.Contacts.CONTENT_URI, - new String[]{ContactsContract.Contacts.DISPLAY_NAME_PRIMARY}, - ContactsContract.Data.STARRED + "=1", null, - ContactsContract.Data.TIMES_CONTACTED); - if (cursor.moveToFirst()) { do { - starredContacts.add(cursor.getString(0)); + String contact = cursor.getString(0); + if (contact != null) { + starredContacts.add(contact); + } } while (cursor.moveToNext()); } return starredContacts; } + private List getStarredContacts() { + return getStarredContacts(queryData()); + } + + private Cursor queryData() { + return mContext.getContentResolver().query(ContactsContract.Contacts.CONTENT_URI, + new String[]{ContactsContract.Contacts.DISPLAY_NAME_PRIMARY}, + ContactsContract.Data.STARRED + "=1", null, + ContactsContract.Data.TIMES_CONTACTED); + } + private boolean isIntentValid() { return mStarredContactsIntent.resolveActivity(mPackageManager) != null || mFallbackIntent.resolveActivity(mPackageManager) != null; diff --git a/src/com/android/settings/slices/SettingsSliceProvider.java b/src/com/android/settings/slices/SettingsSliceProvider.java index f4dfd6ee71d..db09a378e1b 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,32 @@ 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); + } else if (WifiCallingSliceHelper.WIFI_CALLING_PREFERENCE_URI.equals(sliceUri)) { + return FeatureFactory.getFactory(getContext()) + .getSlicesFeatureProvider() + .getNewWifiCallingSliceHelper(getContext()) + .createWifiCallingPreferenceSlice(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..9f1ef769d7d 100644 --- a/src/com/android/settings/slices/SliceBroadcastReceiver.java +++ b/src/com/android/settings/slices/SliceBroadcastReceiver.java @@ -24,6 +24,10 @@ 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 static com.android.settings.wifi.calling.WifiCallingSliceHelper.ACTION_WIFI_CALLING_PREFERENCE_WIFI_ONLY; +import static com.android.settings.wifi.calling.WifiCallingSliceHelper.ACTION_WIFI_CALLING_PREFERENCE_WIFI_PREFERRED; +import static com.android.settings.wifi.calling.WifiCallingSliceHelper.ACTION_WIFI_CALLING_PREFERENCE_CELLULAR_PREFERRED; import android.app.slice.Slice; import android.content.BroadcastReceiver; @@ -84,6 +88,20 @@ 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; + case ACTION_WIFI_CALLING_PREFERENCE_WIFI_ONLY: + case ACTION_WIFI_CALLING_PREFERENCE_WIFI_PREFERRED: + case ACTION_WIFI_CALLING_PREFERENCE_CELLULAR_PREFERRED: + FeatureFactory.getFactory(context) + .getSlicesFeatureProvider() + .getNewWifiCallingSliceHelper(context) + .handleWifiCallingPreferenceChanged(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/src/com/android/settings/wifi/calling/WifiCallingSliceHelper.java b/src/com/android/settings/wifi/calling/WifiCallingSliceHelper.java index e8e33ef0531..ab8db2b7728 100644 --- a/src/com/android/settings/wifi/calling/WifiCallingSliceHelper.java +++ b/src/com/android/settings/wifi/calling/WifiCallingSliceHelper.java @@ -35,11 +35,14 @@ import android.util.Log; 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.ims.ImsConfig; 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; @@ -65,12 +68,34 @@ public class WifiCallingSliceHelper { */ public static final String PATH_WIFI_CALLING = "wifi_calling"; + /** + * 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 @@ -88,12 +113,20 @@ public class WifiCallingSliceHelper { .appendPath(PATH_WIFI_CALLING) .build(); + /** + * Full {@link Uri} for the Wifi Calling Preference Slice. + */ + public static final Uri WIFI_CALLING_PREFERENCE_URI = new Uri.Builder() + .scheme(ContentResolver.SCHEME_CONTENT) + .authority(SettingsSliceProvider.SLICE_AUTHORITY) + .appendPath(PATH_WIFI_CALLING_PREFERENCE) + .build(); + /** * Timeout for querying wifi calling setting from ims manager. */ private static final int TIMEOUT_MILLIS = 2000; - protected SubscriptionManager mSubscriptionManager; private final Context mContext; @VisibleForTesting @@ -115,14 +148,10 @@ public class WifiCallingSliceHelper { */ 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, getSettingsIntent(mContext)); + return null; } final ImsManager imsManager = getImsManager(subId); @@ -130,10 +159,7 @@ public class WifiCallingSliceHelper { 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, getSettingsIntent(mContext)); + return null; } try { @@ -148,18 +174,15 @@ public class WifiCallingSliceHelper { // 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( + mContext.getText(R.string.wifi_calling_settings_title), + mContext.getText( R.string.wifi_calling_settings_activation_instructions), sliceUri, getActivityIntent(ACTION_WIFI_CALLING_SETTINGS_ACTIVITY)); } - return getWifiCallingSlice(sliceUri, mContext, isWifiCallingEnabled); + return getWifiCallingSlice(sliceUri, 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)); + return null; } } @@ -174,25 +197,21 @@ public class WifiCallingSliceHelper { final ExecutorService executor = Executors.newSingleThreadExecutor(); executor.execute(isWifiOnTask); - Boolean isWifiEnabledByUser = false; - isWifiEnabledByUser = isWifiOnTask.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); - - return isWifiEnabledByUser && imsManager.isNonTtyOrTtyOnVolteEnabled(); + return isWifiOnTask.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS) + && 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) { - + private Slice getWifiCallingSlice(Uri sliceUri, 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, ListBuilder.INFINITY) - .setColor(R.color.material_blue_500) + .setAccentColor(Utils.getColorAccentDefaultColor(mContext)) .addRow(b -> b - .setTitle(title) + .setTitle(mContext.getText(R.string.wifi_calling_settings_title)) .addEndItem( new SliceAction( getBroadcastIntent(ACTION_WIFI_CALLING_CHANGED), @@ -200,15 +219,160 @@ public class WifiCallingSliceHelper { .setPrimaryAction(new SliceAction( getActivityIntent(ACTION_WIFI_CALLING_SETTINGS_ACTIVITY), icon, - title))) + mContext.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 (subId <= SubscriptionManager.INVALID_SUBSCRIPTION_ID) { + 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); + 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 null; + } + + if (!isWifiCallingPrefEditable) { + Log.d(TAG, "Wifi calling preference is not editable"); + return null; + } + + boolean isWifiCallingEnabled = false; + int wfcMode = -1; + try { + isWifiCallingEnabled = isWifiCallingEnabled(imsManager); + wfcMode = getWfcMode(imsManager); + } 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 + return getNonActionableWifiCallingSlice( + mContext.getText(R.string.wifi_calling_mode_title), + mContext.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); + } + + /** + * 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 + * @return Slice for actionable wifi calling preference settings + */ + private Slice getWifiCallingPreferenceSlice(boolean isWifiOnlySupported, + int currentWfcPref, + Uri sliceUri) { + final IconCompat icon = IconCompat.createWithResource(mContext, R.drawable.wifi_signal); + // Top row shows information on current preference state + ListBuilder listBuilder = new ListBuilder(mContext, sliceUri, ListBuilder.INFINITY) + .setAccentColor(Utils.getColorAccentDefaultColor(mContext)); + listBuilder.setHeader(new ListBuilder.HeaderBuilder(listBuilder) + .setTitle(mContext.getText(R.string.wifi_calling_mode_title)) + .setSubtitle(getWifiCallingPreferenceSummary(currentWfcPref)) + .setPrimaryAction(new SliceAction( + getActivityIntent(ACTION_WIFI_CALLING_SETTINGS_ACTIVITY), + icon, + mContext.getText(R.string.wifi_calling_mode_title)))); + + if (isWifiOnlySupported) { + listBuilder.addRow(wifiPreferenceRowBuilder(listBuilder, + com.android.internal.R.string.wfc_mode_wifi_only_summary, + ACTION_WIFI_CALLING_PREFERENCE_WIFI_ONLY, + currentWfcPref == ImsConfig.WfcModeFeatureValueConstants.WIFI_ONLY)); + } + + listBuilder.addRow(wifiPreferenceRowBuilder(listBuilder, + com.android.internal.R.string.wfc_mode_wifi_preferred_summary, + ACTION_WIFI_CALLING_PREFERENCE_WIFI_PREFERRED, + currentWfcPref == ImsConfig.WfcModeFeatureValueConstants.WIFI_PREFERRED)); + + listBuilder.addRow(wifiPreferenceRowBuilder(listBuilder, + com.android.internal.R.string.wfc_mode_cellular_preferred_summary, + ACTION_WIFI_CALLING_PREFERENCE_CELLULAR_PREFERRED, + currentWfcPref == ImsConfig.WfcModeFeatureValueConstants.CELLULAR_PREFERRED)); + + 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 + * @return RowBuilder for the row + */ + private RowBuilder wifiPreferenceRowBuilder(ListBuilder listBuilder, + int preferenceTitleResId, String action, boolean checked) { + final IconCompat icon = + IconCompat.createWithResource(mContext, R.drawable.radio_button_check); + return new RowBuilder(listBuilder) + .setTitle(mContext.getText(preferenceTitleResId)) + .setTitleItem(new SliceAction(getBroadcastIntent(action), + icon, mContext.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) { + switch (wfcMode) { + case ImsConfig.WfcModeFeatureValueConstants.WIFI_ONLY: + return mContext.getText( + com.android.internal.R.string.wfc_mode_wifi_only_summary); + case ImsConfig.WfcModeFeatureValueConstants.WIFI_PREFERRED: + return mContext.getText( + com.android.internal.R.string.wfc_mode_wifi_preferred_summary); + case ImsConfig.WfcModeFeatureValueConstants.CELLULAR_PREFERRED: + return mContext.getText( + com.android.internal.R.string.wfc_mode_cellular_preferred_summary); + default: + return null; + } + } + protected ImsManager getImsManager(int subId) { return ImsManager.getInstance(mContext, SubscriptionManager.getPhoneId(subId)); } - private Integer getWfcMode(ImsManager imsManager) + private int getWfcMode(ImsManager imsManager) throws InterruptedException, ExecutionException, TimeoutException { FutureTask wfcModeTask = new FutureTask<>(new Callable() { @Override @@ -233,7 +397,7 @@ public class WifiCallingSliceHelper { if (subId > SubscriptionManager.INVALID_SUBSCRIPTION_ID) { final ImsManager imsManager = getImsManager(subId); if (imsManager.isWfcEnabledByPlatform() - || imsManager.isWfcProvisionedOnDevice()) { + && imsManager.isWfcProvisionedOnDevice()) { final boolean currentValue = imsManager.isWfcEnabledByUser() && imsManager.isNonTtyOrTtyOnVolteEnabled(); final boolean newValue = intent.getBooleanExtra(EXTRA_TOGGLE_STATE, @@ -255,6 +419,63 @@ public class WifiCallingSliceHelper { mContext.getContentResolver().notifyChange(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 (subId > SubscriptionManager.INVALID_SUBSCRIPTION_ID) { + 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); + + ImsManager imsManager = getImsManager(subId); + if (isWifiCallingPrefEditable + && imsManager.isWfcEnabledByPlatform() + && imsManager.isWfcProvisionedOnDevice() + && imsManager.isWfcEnabledByUser() + && imsManager.isNonTtyOrTtyOnVolteEnabled()) { + // Change the preference only when wifi calling is enabled + // And when wifi calling preference is editable for the current carrier + final int currentValue = imsManager.getWfcMode(false); + 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 = ImsConfig.WfcModeFeatureValueConstants.WIFI_ONLY; + } + break; + case ACTION_WIFI_CALLING_PREFERENCE_WIFI_PREFERRED: + newValue = ImsConfig.WfcModeFeatureValueConstants.WIFI_PREFERRED; + break; + case ACTION_WIFI_CALLING_PREFERENCE_CELLULAR_PREFERRED: + newValue = ImsConfig.WfcModeFeatureValueConstants.CELLULAR_PREFERRED; + break; + } + if (newValue != errorValue && newValue != currentValue) { + // Update the setting only when there is a valid update + imsManager.setWfcMode(newValue, false); + } + } + } + + // notify change in slice in any case to get re-queried. This would result in displaying + // appropriate message. + final Uri uri = SliceBuilderUtils.getUri(PATH_WIFI_CALLING_PREFERENCE, + false /*isPlatformSlice*/); + mContext.getContentResolver().notifyChange(uri, null); + } + /** * Returns Slice with the title and subtitle provided as arguments with wifi signal Icon. * @@ -263,12 +484,11 @@ public class WifiCallingSliceHelper { * @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) { + private Slice getNonActionableWifiCallingSlice(CharSequence title, CharSequence subtitle, + Uri sliceUri, PendingIntent primaryActionIntent) { final IconCompat icon = IconCompat.createWithResource(mContext, R.drawable.wifi_signal); return new ListBuilder(mContext, sliceUri, ListBuilder.INFINITY) - .setColor(R.color.material_blue_500) + .setAccentColor(Utils.getColorAccentDefaultColor(mContext)) .addRow(b -> b .setTitle(title) .setSubtitle(subtitle) @@ -281,8 +501,8 @@ public class WifiCallingSliceHelper { /** * 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) { + protected boolean isCarrierConfigManagerKeyEnabled(String key, int subId, + boolean defaultValue) { final CarrierConfigManager configManager = getCarrierConfigManager(mContext); boolean ret = false; if (configManager != null) { @@ -302,9 +522,6 @@ public class WifiCallingSliceHelper { * Returns the current default voice subId obtained from SubscriptionManager */ protected int getDefaultVoiceSubId() { - if (mSubscriptionManager == null) { - mSubscriptionManager = mContext.getSystemService(SubscriptionManager.class); - } return SubscriptionManager.getDefaultVoiceSubscriptionId(); } @@ -350,6 +567,7 @@ public class WifiCallingSliceHelper { private PendingIntent getBroadcastIntent(String action) { final Intent intent = new Intent(action); intent.setClass(mContext, SliceBroadcastReceiver.class); + intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); return PendingIntent.getBroadcast(mContext, 0 /* requestCode */, intent, PendingIntent.FLAG_CANCEL_CURRENT); } @@ -362,17 +580,4 @@ public class WifiCallingSliceHelper { 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/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; + } + } +} diff --git a/tests/robotests/src/com/android/settings/nfc/PaymentSettingsTest.java b/tests/robotests/src/com/android/settings/nfc/PaymentSettingsTest.java index 02687115493..b85bddad55e 100644 --- a/tests/robotests/src/com/android/settings/nfc/PaymentSettingsTest.java +++ b/tests/robotests/src/com/android/settings/nfc/PaymentSettingsTest.java @@ -18,11 +18,16 @@ package com.android.settings.nfc; import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; import android.content.Context; import android.content.pm.PackageManager; +import android.content.pm.UserInfo; +import android.os.UserHandle; +import android.os.UserManager; import com.android.settings.testutils.SettingsRobolectricTestRunner; @@ -45,22 +50,31 @@ public class PaymentSettingsTest { static final String PAYMENT_KEY = "nfc_payment"; static final String FOREGROUND_KEY = "nfc_foreground"; + static final String PAYMENT_SCREEN_KEY = "nfc_payment_settings_screen"; private Context mContext; @Mock - private PackageManager mManager; + private PackageManager mPackageManager; + + @Mock + private UserManager mUserManager; + + @Mock + private UserInfo mUserInfo; @Before public void setUp() { MockitoAnnotations.initMocks(this); mContext = spy(RuntimeEnvironment.application); - when(mContext.getPackageManager()).thenReturn(mManager); + when(mContext.getPackageManager()).thenReturn(mPackageManager); + doReturn(mUserManager).when(mContext).getSystemService(UserManager.class); + when(mUserManager.getUserInfo(UserHandle.myUserId())).thenReturn(mUserInfo); } @Test - public void getNonIndexableKey_NoNFC_AllKeysAdded() { - when(mManager.hasSystemFeature(PackageManager.FEATURE_NFC)).thenReturn(false); + public void getNonIndexableKey_noNFC_allKeysAdded() { + when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_NFC)).thenReturn(false); final List niks = PaymentSettings.SEARCH_INDEX_DATA_PROVIDER.getNonIndexableKeys(mContext); @@ -70,8 +84,8 @@ public class PaymentSettingsTest { } @Test - public void getNonIndexableKey_NFC_ForegroundKeyAdded() { - when(mManager.hasSystemFeature(PackageManager.FEATURE_NFC)).thenReturn(true); + public void getNonIndexableKey_NFC_foregroundKeyAdded() { + when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_NFC)).thenReturn(true); final List niks = PaymentSettings.SEARCH_INDEX_DATA_PROVIDER.getNonIndexableKeys(mContext); @@ -79,6 +93,27 @@ public class PaymentSettingsTest { assertThat(niks).contains(FOREGROUND_KEY); } + @Test + public void getNonIndexableKey_primaryUser_returnsTrue() { + when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_NFC)).thenReturn(true); + + final List niks = + PaymentSettings.SEARCH_INDEX_DATA_PROVIDER.getNonIndexableKeys(mContext); + + assertThat(niks).containsExactly(FOREGROUND_KEY); + } + + @Test + public void getNonIndexabkeKey_guestUser_returnsFalse() { + when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_NFC)).thenReturn(true); + when(mUserInfo.isGuest()).thenReturn(true); + + final List niks = + PaymentSettings.SEARCH_INDEX_DATA_PROVIDER.getNonIndexableKeys(mContext); + + assertThat(niks).containsAllOf(FOREGROUND_KEY, PAYMENT_KEY, PAYMENT_SCREEN_KEY); + } + @Implements(PaymentBackend.class) public static class ShadowPaymentBackend { private ArrayList mAppInfos; diff --git a/tests/robotests/src/com/android/settings/notification/ZenModeStarredContactsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/ZenModeStarredContactsPreferenceControllerTest.java index 9a2bccd6b15..064c0911319 100644 --- a/tests/robotests/src/com/android/settings/notification/ZenModeStarredContactsPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/notification/ZenModeStarredContactsPreferenceControllerTest.java @@ -23,12 +23,25 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.Matchers.any; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import static org.mockito.Mockito.doAnswer; +import org.mockito.stubbing.Answer; +import org.mockito.invocation.InvocationOnMock; import android.app.NotificationManager; import android.content.ComponentName; +import android.content.ContentResolver; import android.content.Context; import android.content.Intent; +import android.database.CharArrayBuffer; +import android.database.ContentObserver; +import android.database.Cursor; +import android.database.DataSetObserver; +import android.net.Uri; +import android.os.Bundle; + import androidx.preference.Preference; import androidx.preference.PreferenceScreen; @@ -42,6 +55,8 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.shadows.ShadowApplication; import org.robolectric.util.ReflectionHelpers; +import java.util.ArrayList; +import java.util.List; @RunWith(SettingsRobolectricTestRunner.class) public class ZenModeStarredContactsPreferenceControllerTest { @@ -148,4 +163,31 @@ public class ZenModeStarredContactsPreferenceControllerTest { assertThat(mMessagesController.isAvailable()).isTrue(); } + + @Test + public void updateSummary_nullCursorValues() { + Cursor testCursorWithNullValues = mock(Cursor.class); + when(testCursorWithNullValues.moveToFirst()).thenReturn(true); + + doAnswer(new Answer() { + int count = 0; + @Override + public Boolean answer(InvocationOnMock invocation) throws Throwable { + if (count < 3) { + count++; + return true; + } + return false; + } + + }).when(testCursorWithNullValues).moveToNext(); + + when(testCursorWithNullValues.getString(0)).thenReturn(null); + + // expected - no null values + List contacts = mMessagesController.getStarredContacts(testCursorWithNullValues); + for (int i = 0 ; i < contacts.size(); i++) { + assertThat(contacts.get(i)).isNotNull(); + } + } } diff --git a/tests/robotests/src/com/android/settings/wifi/calling/WifiCallingSliceHelperTest.java b/tests/robotests/src/com/android/settings/wifi/calling/WifiCallingSliceHelperTest.java index 21f6daa3428..6388297eaeb 100644 --- a/tests/robotests/src/com/android/settings/wifi/calling/WifiCallingSliceHelperTest.java +++ b/tests/robotests/src/com/android/settings/wifi/calling/WifiCallingSliceHelperTest.java @@ -20,9 +20,12 @@ 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.android.settings.slices.SettingsSliceProvider.EXTRA_SLICE_PLATFORM_DEFINED; + import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; @@ -41,8 +44,11 @@ import androidx.slice.SliceMetadata; import androidx.slice.SliceProvider; import androidx.slice.core.SliceAction; import androidx.slice.core.SliceQuery; +import androidx.slice.widget.ListContent; +import androidx.slice.widget.RowContent; import androidx.slice.widget.SliceLiveData; +import com.android.ims.ImsConfig; import com.android.ims.ImsManager; import com.android.settings.R; import com.android.settings.slices.SettingsSliceProvider; @@ -61,6 +67,8 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.RuntimeEnvironment; +import java.util.ArrayList; +import java.util.Iterator; import java.util.List; @RunWith(SettingsRobolectricTestRunner.class) @@ -73,8 +81,6 @@ public class WifiCallingSliceHelperTest { @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; @@ -111,21 +117,21 @@ public class WifiCallingSliceHelperTest { public void test_CreateWifiCallingSlice_invalidSubId() { mWfcSliceHelper.setDefaultVoiceSubId(-1); - final Slice slice = mWfcSliceHelper.createWifiCallingSlice(mWfcURI); + final Slice slice = mWfcSliceHelper.createWifiCallingSlice( + WifiCallingSliceHelper.WIFI_CALLING_URI); - testWifiCallingSettingsUnavailableSlice(slice, null, - WifiCallingSliceHelper.getSettingsIntent(mContext)); + assertThat(slice).isNull(); } @Test public void test_CreateWifiCallingSlice_wfcNotSupported() { - doReturn(false).when(mMockImsManager).isWfcEnabledByPlatform(); + when(mMockImsManager.isWfcEnabledByPlatform()).thenReturn(false); - final Slice slice = mWfcSliceHelper.createWifiCallingSlice(mWfcURI); + final Slice slice = mWfcSliceHelper.createWifiCallingSlice( + WifiCallingSliceHelper.WIFI_CALLING_URI); assertThat(mWfcSliceHelper.getDefaultVoiceSubId()).isEqualTo(1); - testWifiCallingSettingsUnavailableSlice(slice, null, - WifiCallingSliceHelper.getSettingsIntent(mContext)); + assertThat(slice).isNull(); } @Test @@ -135,29 +141,32 @@ public class WifiCallingSliceHelperTest { 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); + when(mMockImsManager.isWfcEnabledByPlatform()).thenReturn(true); + when(mMockImsManager.isWfcProvisionedOnDevice()).thenReturn(true); + when(mMockImsManager.isWfcEnabledByUser()).thenReturn(false); + when(mMockImsManager.isNonTtyOrTtyOnVolteEnabled()).thenReturn(false); + when(mMockCarrierConfigManager.getConfigForSubId(1)).thenReturn(null); mWfcSliceHelper.setActivationAppIntent(new Intent()); // dummy Intent - final Slice slice = mWfcSliceHelper.createWifiCallingSlice(mWfcURI); + final Slice slice = mWfcSliceHelper.createWifiCallingSlice( + WifiCallingSliceHelper.WIFI_CALLING_URI); assertThat(mWfcSliceHelper.getDefaultVoiceSubId()).isEqualTo(1); testWifiCallingSettingsUnavailableSlice(slice, null, - getActivityIntent(WifiCallingSliceHelper.ACTION_WIFI_CALLING_SETTINGS_ACTIVITY)); + getActivityIntent(WifiCallingSliceHelper.ACTION_WIFI_CALLING_SETTINGS_ACTIVITY), + mContext.getString(R.string.wifi_calling_settings_title)); } @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); + when(mMockImsManager.isWfcEnabledByPlatform()).thenReturn(true); + when(mMockImsManager.isWfcProvisionedOnDevice()).thenReturn(true); + when(mMockImsManager.isWfcEnabledByUser()).thenReturn(true); + when(mMockImsManager.isNonTtyOrTtyOnVolteEnabled()).thenReturn(true); + when(mMockCarrierConfigManager.getConfigForSubId(1)).thenReturn(null); - final Slice slice = mWfcSliceHelper.createWifiCallingSlice(mWfcURI); + final Slice slice = mWfcSliceHelper.createWifiCallingSlice( + WifiCallingSliceHelper.WIFI_CALLING_URI); assertThat(mWfcSliceHelper.getDefaultVoiceSubId()).isEqualTo(1); testWifiCallingSettingsToggleSlice(slice, null); @@ -165,28 +174,28 @@ public class WifiCallingSliceHelperTest { @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); + when(mMockImsManager.isWfcEnabledByPlatform()).thenReturn(true); + when(mMockImsManager.isWfcProvisionedOnDevice()).thenReturn(true); + when(mMockImsManager.isWfcEnabledByUser()).thenReturn(true); + when(mMockImsManager.isNonTtyOrTtyOnVolteEnabled()).thenReturn(true); + when(mMockCarrierConfigManager.getConfigForSubId(1)).thenReturn(null); + when(mSlicesFeatureProvider.getNewWifiCallingSliceHelper(mContext)) + .thenReturn(mWfcSliceHelper); - final Slice slice = mProvider.onBindSlice(mWfcURI); + final Slice slice = mProvider.onBindSlice(WifiCallingSliceHelper.WIFI_CALLING_URI); 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); + public void test_SliceBroadcastReceiver_toggleOnWifiCalling() { + when(mMockImsManager.isWfcEnabledByPlatform()).thenReturn(true); + when(mMockImsManager.isWfcProvisionedOnDevice()).thenReturn(true); + when(mMockImsManager.isWfcEnabledByUser()).thenReturn(false); + when(mMockImsManager.isNonTtyOrTtyOnVolteEnabled()).thenReturn(true); + when(mSlicesFeatureProvider.getNewWifiCallingSliceHelper(mContext)) + .thenReturn(mWfcSliceHelper); mWfcSliceHelper.setActivationAppIntent(null); ArgumentCaptor mWfcSettingCaptor = ArgumentCaptor.forClass(Boolean.class); @@ -204,8 +213,104 @@ public class WifiCallingSliceHelperTest { assertThat(mWfcSettingCaptor.getValue()).isTrue(); } + @Test + public void test_CreateWifiCallingPreferenceSlice_prefNotEditable() { + when(mMockImsManager.isWfcEnabledByPlatform()).thenReturn(true); + when(mMockImsManager.isWfcProvisionedOnDevice()).thenReturn(true); + when(mMockImsManager.isWfcEnabledByUser()).thenReturn(true); + when(mMockImsManager.isNonTtyOrTtyOnVolteEnabled()).thenReturn(true); + mWfcSliceHelper.setIsWifiCallingPrefEditable(false); + + final Slice slice = mWfcSliceHelper.createWifiCallingPreferenceSlice( + WifiCallingSliceHelper.WIFI_CALLING_PREFERENCE_URI); + + assertThat(mWfcSliceHelper.getDefaultVoiceSubId()).isEqualTo(1); + assertThat(slice).isNull(); + } + + @Test + public void test_CreateWifiCallingPreferenceSlice_wfcOff() { + when(mMockImsManager.isWfcEnabledByPlatform()).thenReturn(true); + when(mMockImsManager.isWfcProvisionedOnDevice()).thenReturn(true); + when(mMockImsManager.isWfcEnabledByUser()).thenReturn(false); + when(mMockImsManager.isNonTtyOrTtyOnVolteEnabled()).thenReturn(true); + mWfcSliceHelper.setIsWifiCallingPrefEditable(true); + + final Slice slice = mWfcSliceHelper.createWifiCallingPreferenceSlice( + WifiCallingSliceHelper.WIFI_CALLING_PREFERENCE_URI); + + assertThat(mWfcSliceHelper.getDefaultVoiceSubId()).isEqualTo(1); + testWifiCallingSettingsUnavailableSlice(slice, null, + getActivityIntent(WifiCallingSliceHelper.ACTION_WIFI_CALLING_SETTINGS_ACTIVITY), + mContext.getString(R.string.wifi_calling_mode_title)); + } + + @Test + public void test_CreateWifiCallingPreferenceSlice_success() { + when(mMockImsManager.isWfcEnabledByPlatform()).thenReturn(true); + when(mMockImsManager.isWfcProvisionedOnDevice()).thenReturn(true); + when(mMockImsManager.isWfcEnabledByUser()).thenReturn(true); + when(mMockImsManager.isNonTtyOrTtyOnVolteEnabled()).thenReturn(true); + when(mMockImsManager.getWfcMode(false)).thenReturn( + ImsConfig.WfcModeFeatureValueConstants.WIFI_PREFERRED); + mWfcSliceHelper.setIsWifiCallingPrefEditable(true); + + final Slice slice = mWfcSliceHelper.createWifiCallingPreferenceSlice( + WifiCallingSliceHelper.WIFI_CALLING_PREFERENCE_URI); + + assertThat(mWfcSliceHelper.getDefaultVoiceSubId()).isEqualTo(1); + testWifiCallingPreferenceSlice(slice, null, + getActivityIntent(WifiCallingSliceHelper.ACTION_WIFI_CALLING_SETTINGS_ACTIVITY)); + } + + @Test + public void test_SettingsSliceProvider_getWfcPreferenceSlice() { + when(mMockImsManager.isWfcEnabledByPlatform()).thenReturn(true); + when(mMockImsManager.isWfcProvisionedOnDevice()).thenReturn(true); + when(mMockImsManager.isWfcEnabledByUser()).thenReturn(true); + when(mMockImsManager.isNonTtyOrTtyOnVolteEnabled()).thenReturn(true); + when(mMockImsManager.getWfcMode(false)).thenReturn( + ImsConfig.WfcModeFeatureValueConstants.WIFI_PREFERRED); + when(mSlicesFeatureProvider.getNewWifiCallingSliceHelper(mContext)) + .thenReturn(mWfcSliceHelper); + mWfcSliceHelper.setIsWifiCallingPrefEditable(true); + + final Slice slice = mProvider.onBindSlice( + WifiCallingSliceHelper.WIFI_CALLING_PREFERENCE_URI); + + assertThat(mWfcSliceHelper.getDefaultVoiceSubId()).isEqualTo(1); + testWifiCallingPreferenceSlice(slice, null, + getActivityIntent(WifiCallingSliceHelper.ACTION_WIFI_CALLING_SETTINGS_ACTIVITY)); + } + @Test + public void test_SliceBroadcastReceiver_setWfcPrefCellularPref() { + when(mMockImsManager.isWfcEnabledByPlatform()).thenReturn(true); + when(mMockImsManager.isWfcProvisionedOnDevice()).thenReturn(true); + when(mMockImsManager.isWfcEnabledByUser()).thenReturn(true); + when(mMockImsManager.isNonTtyOrTtyOnVolteEnabled()).thenReturn(true); + when(mMockImsManager.getWfcMode(false)).thenReturn( + ImsConfig.WfcModeFeatureValueConstants.WIFI_PREFERRED); + when(mSlicesFeatureProvider.getNewWifiCallingSliceHelper(mContext)) + .thenReturn(mWfcSliceHelper); + mWfcSliceHelper.setIsWifiCallingPrefEditable(true); + + ArgumentCaptor mWfcPreferenceCaptor = ArgumentCaptor.forClass(Integer.class); + + // Change preference to Cellular pref + Intent intent = new Intent( + WifiCallingSliceHelper.ACTION_WIFI_CALLING_PREFERENCE_CELLULAR_PREFERRED); + + mReceiver.onReceive(mContext, intent); + + verify((mMockImsManager)).setWfcMode(mWfcPreferenceCaptor.capture(), eq(false)); + + // assert the change + assertThat(mWfcPreferenceCaptor.getValue()).isEqualTo( + ImsConfig.WfcModeFeatureValueConstants.CELLULAR_PREFERRED); + } + private void testWifiCallingSettingsUnavailableSlice(Slice slice, - SliceData sliceData, PendingIntent expectedPrimaryAction) { + SliceData sliceData, PendingIntent expectedPrimaryAction, String title) { final SliceMetadata metadata = SliceMetadata.from(mContext, slice); //Check there is no toggle action @@ -219,7 +324,7 @@ public class WifiCallingSliceHelperTest { // Check the title final List sliceItems = slice.getItems(); - assertTitle(sliceItems, mContext.getString(R.string.wifi_calling_settings_title)); + assertTitle(sliceItems, title); } private void testWifiCallingSettingsToggleSlice(Slice slice, @@ -248,6 +353,51 @@ public class WifiCallingSliceHelperTest { assertTitle(sliceItems, mContext.getString(R.string.wifi_calling_settings_title)); } + private void testWifiCallingPreferenceSlice(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); + + // Get all the rows + final ListContent listContent = new ListContent(mContext, slice); + final ArrayList rowItems = listContent.getRowItems(); + + assertThat(rowItems.size()).isEqualTo(4 /* 4 items including header */); + + // First row is HEADER + SliceItem rowSliceItem = rowItems.get(0); + RowContent rowContent = new RowContent(mContext, rowSliceItem, true); + assertThat(rowContent.getTitleItem().getText()).isEqualTo(mContext.getText( + R.string.wifi_calling_mode_title)); + + // next is WIFI_ONLY + rowSliceItem = rowItems.get(1); + rowContent = new RowContent(mContext, rowSliceItem, false); + assertThat(rowContent.getTitleItem().getText()).isEqualTo(mContext.getText( + com.android.internal.R.string.wfc_mode_wifi_only_summary)); + + // next is WIFI_PREFERRED + rowSliceItem = rowItems.get(2); + rowContent = new RowContent(mContext, rowSliceItem, false); + assertThat(rowContent.getTitleItem().getText()).isEqualTo(mContext.getText( + com.android.internal.R.string.wfc_mode_wifi_preferred_summary)); + + // next is CELLULAR_PREFERRED + rowSliceItem = rowItems.get(3); + rowContent = new RowContent(mContext, rowSliceItem, false); + assertThat(rowContent.getTitleItem().getText()).isEqualTo(mContext.getText( + com.android.internal.R.string.wfc_mode_cellular_preferred_summary)); + + } + private PendingIntent getBroadcastIntent(String action) { final Intent intent = new Intent(action); intent.setClass(mContext, SliceBroadcastReceiver.class); @@ -279,6 +429,8 @@ public class WifiCallingSliceHelperTest { } private class FakeWifiCallingSliceHelper extends WifiCallingSliceHelper { int mSubId = 1; + boolean isWifiCallingPrefEditable = true; + boolean isWifiOnlySupported = true; private Intent mActivationAppIntent; FakeWifiCallingSliceHelper(Context context) { @@ -308,9 +460,23 @@ public class WifiCallingSliceHelperTest { protected Intent getWifiCallingCarrierActivityIntent(int subId) { return mActivationAppIntent; } + @Override + protected boolean isCarrierConfigManagerKeyEnabled(String key, int subId, + boolean defaultValue) { + if(key.equals(CarrierConfigManager.KEY_EDITABLE_WFC_MODE_BOOL)) { + return isWifiCallingPrefEditable; + } else if(key.equals(CarrierConfigManager.KEY_CARRIER_WFC_SUPPORTS_WIFI_ONLY_BOOL)) { + return isWifiOnlySupported; + } + return defaultValue; + } public void setActivationAppIntent(Intent intent) { mActivationAppIntent = intent; } + + public void setIsWifiCallingPrefEditable(boolean isWifiCallingPrefEditable) { + this.isWifiCallingPrefEditable = isWifiCallingPrefEditable; + } } }