MSIM support for Wi-Fi calling setting.

UI change to support Wi-Fi calling settings for multi-SIM devices.

Bug: b/65648147
Test: manual
Change-Id: Ia2e3a835400873bf6d8bfc7a7690d98e74049076
This commit is contained in:
Malcolm Chen
2017-09-22 11:58:02 -07:00
parent 9d85cfe762
commit 13d50cb0f5
8 changed files with 1099 additions and 385 deletions

View File

@@ -0,0 +1,45 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2014 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.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/tabs_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.android.settings.widget.SwitchBar
android:id="@+id/switch_bar"
android:layout_height="?android:attr/actionBarSize"
android:layout_width="match_parent"
android:background="@drawable/switchbar_background"
android:theme="?attr/switchBarTheme" />
<FrameLayout
android:id="@android:id/tabcontent"
android:layout_width="0dip"
android:layout_height="0dip" />
<FrameLayout
android:id="@+id/prefs_container"
android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_weight="1"
android:clipChildren="false"
android:clipToPadding="false"
android:smoothScrollbar="false" />
</LinearLayout>

View File

@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2017 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.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/tabs_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.android.settings.widget.SlidingTabLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/sliding_tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scrollbars="none"
android:fillViewport="true"/>
<com.android.settings.widget.RtlCompatibleViewPager
android:id="@+id/view_pager"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>

View File

@@ -16,190 +16,38 @@
package com.android.settings;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.app.Fragment;
import android.app.FragmentManager;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.os.PersistableBundle;
import android.support.v7.preference.ListPreference;
import android.support.v7.preference.Preference;
import android.support.v7.preference.Preference.OnPreferenceClickListener;
import android.support.v7.preference.PreferenceScreen;
import android.telephony.CarrierConfigManager;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.support.v13.app.FragmentPagerAdapter;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.util.Log;
import android.widget.Switch;
import android.widget.TextView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.android.ims.ImsConfig;
import com.android.ims.ImsManager;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.telephony.Phone;
import com.android.settings.widget.SwitchBar;
import com.android.settings.widget.RtlCompatibleViewPager;
import com.android.settings.widget.SlidingTabLayout;
import java.util.List;
/**
* "Wi-Fi Calling settings" screen. This preference screen lets you
* enable/disable Wi-Fi Calling and change Wi-Fi Calling mode.
* "Wi-Fi Calling settings" screen. This is the container fragment which holds
* {@link WifiCallingSettingsForSub} fragments.
*/
public class WifiCallingSettings extends SettingsPreferenceFragment
implements SwitchBar.OnSwitchChangeListener,
Preference.OnPreferenceChangeListener {
public class WifiCallingSettings extends SettingsPreferenceFragment {
private static final String TAG = "WifiCallingSettings";
//String keys for preference lookup
private static final String BUTTON_WFC_MODE = "wifi_calling_mode";
private static final String BUTTON_WFC_ROAMING_MODE = "wifi_calling_roaming_mode";
private static final String PREFERENCE_EMERGENCY_ADDRESS = "emergency_address_key";
private static final int REQUEST_CHECK_WFC_EMERGENCY_ADDRESS = 1;
public static final String EXTRA_LAUNCH_CARRIER_APP = "EXTRA_LAUNCH_CARRIER_APP";
public static final int LAUCH_APP_ACTIVATE = 0;
public static final int LAUCH_APP_UPDATE = 1;
private List<SubscriptionInfo> mSil;
//UI objects
private SwitchBar mSwitchBar;
private Switch mSwitch;
private ListPreference mButtonWfcMode;
private ListPreference mButtonWfcRoamingMode;
private Preference mUpdateAddress;
private TextView mEmptyView;
private boolean mValidListener = false;
private boolean mEditableWfcMode = true;
private boolean mEditableWfcRoamingMode = true;
private final PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
/*
* Enable/disable controls when in/out of a call and depending on
* TTY mode and TTY support over VoLTE.
* @see android.telephony.PhoneStateListener#onCallStateChanged(int,
* java.lang.String)
*/
@Override
public void onCallStateChanged(int state, String incomingNumber) {
final SettingsActivity activity = (SettingsActivity) getActivity();
boolean isNonTtyOrTtyOnVolteEnabled = ImsManager
.isNonTtyOrTtyOnVolteEnabled(activity);
final SwitchBar switchBar = activity.getSwitchBar();
boolean isWfcEnabled = switchBar.getSwitch().isChecked()
&& isNonTtyOrTtyOnVolteEnabled;
switchBar.setEnabled((state == TelephonyManager.CALL_STATE_IDLE)
&& isNonTtyOrTtyOnVolteEnabled);
boolean isWfcModeEditable = true;
boolean isWfcRoamingModeEditable = false;
final CarrierConfigManager configManager = (CarrierConfigManager)
activity.getSystemService(Context.CARRIER_CONFIG_SERVICE);
if (configManager != null) {
PersistableBundle b = configManager.getConfig();
if (b != null) {
isWfcModeEditable = b.getBoolean(
CarrierConfigManager.KEY_EDITABLE_WFC_MODE_BOOL);
isWfcRoamingModeEditable = b.getBoolean(
CarrierConfigManager.KEY_EDITABLE_WFC_ROAMING_MODE_BOOL);
}
}
Preference pref = getPreferenceScreen().findPreference(BUTTON_WFC_MODE);
if (pref != null) {
pref.setEnabled(isWfcEnabled && isWfcModeEditable
&& (state == TelephonyManager.CALL_STATE_IDLE));
}
Preference pref_roam = getPreferenceScreen().findPreference(BUTTON_WFC_ROAMING_MODE);
if (pref_roam != null) {
pref_roam.setEnabled(isWfcEnabled && isWfcRoamingModeEditable
&& (state == TelephonyManager.CALL_STATE_IDLE));
}
}
};
private final OnPreferenceClickListener mUpdateAddressListener =
new OnPreferenceClickListener() {
/*
* Launch carrier emergency address managemnent activity
*/
@Override
public boolean onPreferenceClick(Preference preference) {
final Context context = getActivity();
Intent carrierAppIntent = getCarrierActivityIntent(context);
if (carrierAppIntent != null) {
carrierAppIntent.putExtra(EXTRA_LAUNCH_CARRIER_APP, LAUCH_APP_UPDATE);
startActivity(carrierAppIntent);
}
return true;
}
};
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
final SettingsActivity activity = (SettingsActivity) getActivity();
mSwitchBar = activity.getSwitchBar();
mSwitch = mSwitchBar.getSwitch();
mSwitchBar.show();
mEmptyView = (TextView) getView().findViewById(android.R.id.empty);
setEmptyView(mEmptyView);
String emptyViewText = activity.getString(R.string.wifi_calling_off_explanation)
+ activity.getString(R.string.wifi_calling_off_explanation_2);
mEmptyView.setText(emptyViewText);
}
@Override
public void onDestroyView() {
super.onDestroyView();
mSwitchBar.hide();
}
private void showAlert(Intent intent) {
Context context = getActivity();
CharSequence title = intent.getCharSequenceExtra(Phone.EXTRA_KEY_ALERT_TITLE);
CharSequence message = intent.getCharSequenceExtra(Phone.EXTRA_KEY_ALERT_MESSAGE);
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setMessage(message)
.setTitle(title)
.setIcon(android.R.drawable.ic_dialog_alert)
.setPositiveButton(android.R.string.ok, null);
AlertDialog dialog = builder.create();
dialog.show();
}
private IntentFilter mIntentFilter;
private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(ImsManager.ACTION_IMS_REGISTRATION_ERROR)) {
// If this fragment is active then we are immediately
// showing alert on screen. There is no need to add
// notification in this case.
//
// In order to communicate to ImsPhone that it should
// not show notification, we are changing result code here.
setResultCode(Activity.RESULT_CANCELED);
// UX requirement is to disable WFC in case of "permanent" registration failures.
mSwitch.setChecked(false);
showAlert(intent);
}
}
};
private RtlCompatibleViewPager mViewPager;
private WifiCallingViewPagerAdapter mPagerAdapter;
private SlidingTabLayout mTabLayout;
@Override
public int getMetricsCategory() {
@@ -207,242 +55,81 @@ public class WifiCallingSettings extends SettingsPreferenceFragment
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final View view = inflater.inflate(R.layout.wifi_calling_settings_tabs, container, false);
addPreferencesFromResource(R.xml.wifi_calling_settings);
mTabLayout = view.findViewById(R.id.sliding_tabs);
mViewPager = (RtlCompatibleViewPager) view.findViewById(R.id.view_pager);
mButtonWfcMode = (ListPreference) findPreference(BUTTON_WFC_MODE);
mButtonWfcMode.setOnPreferenceChangeListener(this);
mPagerAdapter = new WifiCallingViewPagerAdapter(getChildFragmentManager(), mViewPager);
mViewPager.setAdapter(mPagerAdapter);
mButtonWfcRoamingMode = (ListPreference) findPreference(BUTTON_WFC_ROAMING_MODE);
mButtonWfcRoamingMode.setOnPreferenceChangeListener(this);
mUpdateAddress = (Preference) findPreference(PREFERENCE_EMERGENCY_ADDRESS);
mUpdateAddress.setOnPreferenceClickListener(mUpdateAddressListener);
mIntentFilter = new IntentFilter();
mIntentFilter.addAction(ImsManager.ACTION_IMS_REGISTRATION_ERROR);
CarrierConfigManager configManager = (CarrierConfigManager)
getSystemService(Context.CARRIER_CONFIG_SERVICE);
boolean isWifiOnlySupported = true;
if (configManager != null) {
PersistableBundle b = configManager.getConfig();
if (b != null) {
mEditableWfcMode = b.getBoolean(CarrierConfigManager.KEY_EDITABLE_WFC_MODE_BOOL);
mEditableWfcRoamingMode = b.getBoolean(
CarrierConfigManager.KEY_EDITABLE_WFC_ROAMING_MODE_BOOL);
isWifiOnlySupported = b.getBoolean(
CarrierConfigManager.KEY_CARRIER_WFC_SUPPORTS_WIFI_ONLY_BOOL, true);
}
}
if (!isWifiOnlySupported) {
mButtonWfcMode.setEntries(R.array.wifi_calling_mode_choices_without_wifi_only);
mButtonWfcMode.setEntryValues(R.array.wifi_calling_mode_values_without_wifi_only);
mButtonWfcRoamingMode.setEntries(
R.array.wifi_calling_mode_choices_v2_without_wifi_only);
mButtonWfcRoamingMode.setEntryValues(
R.array.wifi_calling_mode_values_without_wifi_only);
}
return view;
}
@Override
public void onResume() {
super.onResume();
final Context context = getActivity();
// NOTE: Buttons will be enabled/disabled in mPhoneStateListener
boolean wfcEnabled = ImsManager.isWfcEnabledByUser(context)
&& ImsManager.isNonTtyOrTtyOnVolteEnabled(context);
mSwitch.setChecked(wfcEnabled);
int wfcMode = ImsManager.getWfcMode(context, false);
int wfcRoamingMode = ImsManager.getWfcMode(context, true);
mButtonWfcMode.setValue(Integer.toString(wfcMode));
mButtonWfcRoamingMode.setValue(Integer.toString(wfcRoamingMode));
updateButtonWfcMode(context, wfcEnabled, wfcMode, wfcRoamingMode);
if (ImsManager.isWfcEnabledByPlatform(context)) {
TelephonyManager tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
tm.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
mSwitchBar.addOnSwitchChangeListener(this);
mValidListener = true;
}
context.registerReceiver(mIntentReceiver, mIntentFilter);
Intent intent = getActivity().getIntent();
if (intent.getBooleanExtra(Phone.EXTRA_KEY_ALERT_SHOW, false)) {
showAlert(intent);
}
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
// TODO: besides in onCreate, we should also update subList when SIM / Sub status
// changes.
updateSubList();
}
@Override
public void onPause() {
super.onPause();
public void onStart() {
super.onStart();
final Context context = getActivity();
if (mValidListener) {
mValidListener = false;
TelephonyManager tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
tm.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE);
mSwitchBar.removeOnSwitchChangeListener(this);
}
context.unregisterReceiver(mIntentReceiver);
}
/**
* Listens to the state change of the switch.
*/
@Override
public void onSwitchChanged(Switch switchView, boolean isChecked) {
final Context context = getActivity();
Log.d(TAG, "onSwitchChanged(" + isChecked + ")");
if (!isChecked) {
updateWfcMode(context, false);
return;
}
// Call address management activity before turning on WFC
Intent carrierAppIntent = getCarrierActivityIntent(context);
if (carrierAppIntent != null) {
carrierAppIntent.putExtra(EXTRA_LAUNCH_CARRIER_APP, LAUCH_APP_ACTIVATE);
startActivityForResult(carrierAppIntent, REQUEST_CHECK_WFC_EMERGENCY_ADDRESS);
if (mSil != null && mSil.size() > 1) {
mTabLayout.setViewPager(mViewPager);
} else {
updateWfcMode(context, true);
mTabLayout.setVisibility(View.GONE);
}
}
/*
* Get the Intent to launch carrier emergency address management activity.
* Return null when no activity found.
*/
private static Intent getCarrierActivityIntent(Context context) {
// Retrive component name from carrirt config
CarrierConfigManager configManager = context.getSystemService(CarrierConfigManager.class);
if (configManager == null) return null;
private final class WifiCallingViewPagerAdapter extends FragmentPagerAdapter {
private final RtlCompatibleViewPager mViewPager;
PersistableBundle bundle = configManager.getConfig();
if (bundle == null) return null;
String carrierApp = bundle.getString(
CarrierConfigManager.KEY_WFC_EMERGENCY_ADDRESS_CARRIER_APP_STRING);
if (TextUtils.isEmpty(carrierApp)) return null;
ComponentName componentName = ComponentName.unflattenFromString(carrierApp);
if (componentName == null) return null;
// Build and return intent
Intent intent = new Intent();
intent.setComponent(componentName);
return intent;
}
/*
* Turn on/off WFC mode with ImsManager and update UI accordingly
*/
private void updateWfcMode(Context context, boolean wfcEnabled) {
Log.i(TAG, "updateWfcMode(" + wfcEnabled + ")");
ImsManager.setWfcSetting(context, wfcEnabled);
int wfcMode = ImsManager.getWfcMode(context, false);
int wfcRoamingMode = ImsManager.getWfcMode(context, true);
updateButtonWfcMode(context, wfcEnabled, wfcMode, wfcRoamingMode);
if (wfcEnabled) {
mMetricsFeatureProvider.action(getActivity(), getMetricsCategory(), wfcMode);
} else {
mMetricsFeatureProvider.action(getActivity(), getMetricsCategory(), -1);
public WifiCallingViewPagerAdapter(FragmentManager fragmentManager,
RtlCompatibleViewPager viewPager) {
super(fragmentManager);
mViewPager = viewPager;
}
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
final Context context = getActivity();
if (requestCode == REQUEST_CHECK_WFC_EMERGENCY_ADDRESS) {
Log.d(TAG, "WFC emergency address activity result = " + resultCode);
if (resultCode == Activity.RESULT_OK) {
updateWfcMode(context, true);
}
@Override
public CharSequence getPageTitle(int position) {
return String.valueOf(mSil.get(position).getDisplayName());
}
}
private void updateButtonWfcMode(Context context, boolean wfcEnabled,
int wfcMode, int wfcRoamingMode) {
mButtonWfcMode.setSummary(getWfcModeSummary(context, wfcMode));
mButtonWfcMode.setEnabled(wfcEnabled && mEditableWfcMode);
// mButtonWfcRoamingMode.setSummary is not needed; summary is just selected value.
mButtonWfcRoamingMode.setEnabled(wfcEnabled && mEditableWfcRoamingMode);
@Override
public Fragment getItem(int position) {
Log.d(TAG, "Adapter getItem " + position);
final Bundle args = new Bundle();
args.putInt(WifiCallingSettingsForSub.FRAGMENT_BUNDLE_SUBID,
mSil.get(position).getSubscriptionId());
WifiCallingSettingsForSub fragment = new WifiCallingSettingsForSub();
fragment.setArguments(args);
final PreferenceScreen preferenceScreen = getPreferenceScreen();
boolean updateAddressEnabled = (getCarrierActivityIntent(context) != null);
if (wfcEnabled) {
if (mEditableWfcMode) {
preferenceScreen.addPreference(mButtonWfcMode);
return fragment;
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
Log.d(TAG, "Adapter instantiateItem " + position);
return super.instantiateItem(container,
mViewPager.getRtlAwareIndex(position));
}
@Override
public int getCount() {
if (mSil == null) {
Log.d(TAG, "Adapter getCount null mSil ");
return 0;
} else {
// Don't show WFC (home) preference if it's not editable.
preferenceScreen.removePreference(mButtonWfcMode);
}
if (mEditableWfcRoamingMode) {
preferenceScreen.addPreference(mButtonWfcRoamingMode);
} else {
// Don't show WFC roaming preference if it's not editable.
preferenceScreen.removePreference(mButtonWfcRoamingMode);
}
if (updateAddressEnabled) {
preferenceScreen.addPreference(mUpdateAddress);
} else {
preferenceScreen.removePreference(mUpdateAddress);
}
} else {
preferenceScreen.removePreference(mButtonWfcMode);
preferenceScreen.removePreference(mButtonWfcRoamingMode);
preferenceScreen.removePreference(mUpdateAddress);
}
}
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
final Context context = getActivity();
if (preference == mButtonWfcMode) {
mButtonWfcMode.setValue((String) newValue);
int buttonMode = Integer.valueOf((String) newValue);
int currentWfcMode = ImsManager.getWfcMode(context, false);
if (buttonMode != currentWfcMode) {
ImsManager.setWfcMode(context, buttonMode, false);
mButtonWfcMode.setSummary(getWfcModeSummary(context, buttonMode));
mMetricsFeatureProvider.action(getActivity(), getMetricsCategory(), buttonMode);
}
if (!mEditableWfcRoamingMode) {
int currentWfcRoamingMode = ImsManager.getWfcMode(context, true);
if (buttonMode != currentWfcRoamingMode) {
ImsManager.setWfcMode(context, buttonMode, true);
// mButtonWfcRoamingMode.setSummary is not needed; summary is selected value
}
}
} else if (preference == mButtonWfcRoamingMode) {
mButtonWfcRoamingMode.setValue((String) newValue);
int buttonMode = Integer.valueOf((String) newValue);
int currentMode = ImsManager.getWfcMode(context, true);
if (buttonMode != currentMode) {
ImsManager.setWfcMode(context, buttonMode, true);
// mButtonWfcRoamingMode.setSummary is not needed; summary is just selected value.
mMetricsFeatureProvider.action(getActivity(), getMetricsCategory(), buttonMode);
Log.d(TAG, "Adapter getCount " + mSil.size());
return mSil.size();
}
}
return true;
}
public static int getWfcModeSummary(Context context, int wfcMode) {
@@ -464,4 +151,22 @@ public class WifiCallingSettings extends SettingsPreferenceFragment
}
return resId;
}
private void updateSubList() {
mSil = SubscriptionManager.from(getActivity()).getActiveSubscriptionInfoList();
// Only config Wfc if it's enabled by platform.
if (mSil == null) {
return;
}
for (int i = 0; i < mSil.size();) {
ImsManager imsManager = ImsManager.getInstance(getActivity(),
mSil.get(i).getSimSlotIndex());
if (!imsManager.isWfcEnabledByPlatform()) {
mSil.remove(i);
} else {
i++;
}
}
}
}

View File

@@ -0,0 +1,521 @@
/*
* Copyright (C) 2017 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;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.os.PersistableBundle;
import android.support.v7.preference.ListPreference;
import android.support.v7.preference.Preference;
import android.support.v7.preference.Preference.OnPreferenceClickListener;
import android.support.v7.preference.PreferenceScreen;
import android.telephony.CarrierConfigManager;
import android.telephony.PhoneStateListener;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Switch;
import android.widget.TextView;
import com.android.ims.ImsConfig;
import com.android.ims.ImsManager;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.telephony.Phone;
import com.android.settings.widget.SwitchBar;
/**
* This is the inner class of {@link WifiCallingSettings} fragment.
* The preference screen lets you enable/disable Wi-Fi Calling and change Wi-Fi Calling mode.
*/
public class WifiCallingSettingsForSub extends SettingsPreferenceFragment
implements SwitchBar.OnSwitchChangeListener,
Preference.OnPreferenceChangeListener {
private static final String TAG = "WifiCallingSettingsForSub";
//String keys for preference lookup
private static final String BUTTON_WFC_MODE = "wifi_calling_mode";
private static final String BUTTON_WFC_ROAMING_MODE = "wifi_calling_roaming_mode";
private static final String PREFERENCE_EMERGENCY_ADDRESS = "emergency_address_key";
private static final int REQUEST_CHECK_WFC_EMERGENCY_ADDRESS = 1;
public static final String EXTRA_LAUNCH_CARRIER_APP = "EXTRA_LAUNCH_CARRIER_APP";
protected static final String FRAGMENT_BUNDLE_SUBID = "subId";
public static final int LAUCH_APP_ACTIVATE = 0;
public static final int LAUCH_APP_UPDATE = 1;
//UI objects
private SwitchBar mSwitchBar;
private Switch mSwitch;
private ListPreference mButtonWfcMode;
private ListPreference mButtonWfcRoamingMode;
private Preference mUpdateAddress;
private TextView mEmptyView;
private boolean mValidListener = false;
private boolean mEditableWfcMode = true;
private boolean mEditableWfcRoamingMode = true;
private int mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
private ImsManager mImsManager;
private final PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
/*
* Enable/disable controls when in/out of a call and depending on
* TTY mode and TTY support over VoLTE.
* @see android.telephony.PhoneStateListener#onCallStateChanged(int,
* java.lang.String)
*/
@Override
public void onCallStateChanged(int state, String incomingNumber) {
final SettingsActivity activity = (SettingsActivity) getActivity();
boolean isNonTtyOrTtyOnVolteEnabled = mImsManager.isNonTtyOrTtyOnVolteEnabled();
boolean isWfcEnabled = mSwitchBar.isChecked()
&& isNonTtyOrTtyOnVolteEnabled;
mSwitchBar.setEnabled((state == TelephonyManager.CALL_STATE_IDLE)
&& isNonTtyOrTtyOnVolteEnabled);
boolean isWfcModeEditable = true;
boolean isWfcRoamingModeEditable = false;
final CarrierConfigManager configManager = (CarrierConfigManager)
activity.getSystemService(Context.CARRIER_CONFIG_SERVICE);
if (configManager != null) {
PersistableBundle b = configManager.getConfigForSubId(mSubId);
if (b != null) {
isWfcModeEditable = b.getBoolean(
CarrierConfigManager.KEY_EDITABLE_WFC_MODE_BOOL);
isWfcRoamingModeEditable = b.getBoolean(
CarrierConfigManager.KEY_EDITABLE_WFC_ROAMING_MODE_BOOL);
}
}
Preference pref = getPreferenceScreen().findPreference(BUTTON_WFC_MODE);
if (pref != null) {
pref.setEnabled(isWfcEnabled && isWfcModeEditable
&& (state == TelephonyManager.CALL_STATE_IDLE));
}
Preference pref_roam =
getPreferenceScreen().findPreference(BUTTON_WFC_ROAMING_MODE);
if (pref_roam != null) {
pref_roam.setEnabled(isWfcEnabled && isWfcRoamingModeEditable
&& (state == TelephonyManager.CALL_STATE_IDLE));
}
}
};
@Override
protected int getHelpResource() {
// Helper resource is already defined in the container fragment.
return 0;
}
private final OnPreferenceClickListener mUpdateAddressListener =
new OnPreferenceClickListener() {
/*
* Launch carrier emergency address managemnent activity
*/
@Override
public boolean onPreferenceClick(Preference preference) {
Intent carrierAppIntent = getCarrierActivityIntent();
if (carrierAppIntent != null) {
carrierAppIntent.putExtra(EXTRA_LAUNCH_CARRIER_APP, LAUCH_APP_UPDATE);
startActivity(carrierAppIntent);
}
return true;
}
};
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
final SettingsActivity activity = (SettingsActivity) getActivity();
mEmptyView = (TextView) getView().findViewById(android.R.id.empty);
setEmptyView(mEmptyView);
String emptyViewText = activity.getString(R.string.wifi_calling_off_explanation)
+ activity.getString(R.string.wifi_calling_off_explanation_2);
mEmptyView.setText(emptyViewText);
mSwitchBar = getView().findViewById(R.id.switch_bar);
mSwitchBar.show();
mSwitch = mSwitchBar.getSwitch();
}
@Override
public void onDestroyView() {
super.onDestroyView();
mSwitchBar.hide();
}
private void showAlert(Intent intent) {
Context context = getActivity();
CharSequence title = intent.getCharSequenceExtra(Phone.EXTRA_KEY_ALERT_TITLE);
CharSequence message = intent.getCharSequenceExtra(Phone.EXTRA_KEY_ALERT_MESSAGE);
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setMessage(message)
.setTitle(title)
.setIcon(android.R.drawable.ic_dialog_alert)
.setPositiveButton(android.R.string.ok, null);
AlertDialog dialog = builder.create();
dialog.show();
}
private IntentFilter mIntentFilter;
private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(ImsManager.ACTION_IMS_REGISTRATION_ERROR)) {
// If this fragment is active then we are immediately
// showing alert on screen. There is no need to add
// notification in this case.
//
// In order to communicate to ImsPhone that it should
// not show notification, we are changing result code here.
setResultCode(Activity.RESULT_CANCELED);
// UX requirement is to disable WFC in case of "permanent" registration failures.
mSwitch.setChecked(false);
showAlert(intent);
}
}
};
@Override
public int getMetricsCategory() {
return MetricsEvent.WIFI_CALLING_FOR_SUB;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.wifi_calling_settings);
// SubId should always be specified when creating this fragment. Either through
// fragment.setArguments() or through savedInstanceState.
if (getArguments() != null && getArguments().containsKey(FRAGMENT_BUNDLE_SUBID))
{
mSubId = getArguments().getInt(FRAGMENT_BUNDLE_SUBID);
} else if (savedInstanceState != null) {
mSubId = savedInstanceState.getInt(
FRAGMENT_BUNDLE_SUBID, SubscriptionManager.INVALID_SUBSCRIPTION_ID);
}
mImsManager = ImsManager.getInstance(
getActivity(), SubscriptionManager.getPhoneId(mSubId));
mButtonWfcMode = (ListPreference) findPreference(BUTTON_WFC_MODE);
mButtonWfcMode.setOnPreferenceChangeListener(this);
mButtonWfcRoamingMode = (ListPreference) findPreference(BUTTON_WFC_ROAMING_MODE);
mButtonWfcRoamingMode.setOnPreferenceChangeListener(this);
mUpdateAddress = (Preference) findPreference(PREFERENCE_EMERGENCY_ADDRESS);
mUpdateAddress.setOnPreferenceClickListener(mUpdateAddressListener);
mIntentFilter = new IntentFilter();
mIntentFilter.addAction(ImsManager.ACTION_IMS_REGISTRATION_ERROR);
}
@Override
public void onSaveInstanceState(Bundle outState) {
outState.putInt(FRAGMENT_BUNDLE_SUBID, mSubId);
super.onSaveInstanceState(outState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(
R.layout.wifi_calling_settings_preferences, container, false);
final ViewGroup prefs_container = view.findViewById(R.id.prefs_container);
Utils.prepareCustomPreferencesList(container, view, prefs_container, false);
View prefs = super.onCreateView(inflater, prefs_container, savedInstanceState);
prefs_container.addView(prefs);
return view;
}
private void updateBody() {
CarrierConfigManager configManager = (CarrierConfigManager)
getSystemService(Context.CARRIER_CONFIG_SERVICE);
boolean isWifiOnlySupported = true;
if (configManager != null) {
PersistableBundle b = configManager.getConfigForSubId(mSubId);
if (b != null) {
mEditableWfcMode = b.getBoolean(
CarrierConfigManager.KEY_EDITABLE_WFC_MODE_BOOL);
mEditableWfcRoamingMode = b.getBoolean(
CarrierConfigManager.KEY_EDITABLE_WFC_ROAMING_MODE_BOOL);
isWifiOnlySupported = b.getBoolean(
CarrierConfigManager.KEY_CARRIER_WFC_SUPPORTS_WIFI_ONLY_BOOL, true);
}
}
if (!isWifiOnlySupported) {
mButtonWfcMode.setEntries(R.array.wifi_calling_mode_choices_without_wifi_only);
mButtonWfcMode.setEntryValues(R.array.wifi_calling_mode_values_without_wifi_only);
mButtonWfcRoamingMode.setEntries(
R.array.wifi_calling_mode_choices_v2_without_wifi_only);
mButtonWfcRoamingMode.setEntryValues(
R.array.wifi_calling_mode_values_without_wifi_only);
}
// NOTE: Buttons will be enabled/disabled in mPhoneStateListener
boolean wfcEnabled = mImsManager.isWfcEnabledByUser()
&& mImsManager.isNonTtyOrTtyOnVolteEnabled();
mSwitch.setChecked(wfcEnabled);
int wfcMode = mImsManager.getWfcMode(false);
int wfcRoamingMode = mImsManager.getWfcMode(true);
mButtonWfcMode.setValue(Integer.toString(wfcMode));
mButtonWfcRoamingMode.setValue(Integer.toString(wfcRoamingMode));
updateButtonWfcMode(wfcEnabled, wfcMode, wfcRoamingMode);
}
@Override
public void onResume() {
super.onResume();
final Context context = getActivity();
updateBody();
if (mImsManager.isWfcEnabledByPlatform()) {
TelephonyManager tm =
(TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
tm.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
mSwitchBar.addOnSwitchChangeListener(this);
mValidListener = true;
}
context.registerReceiver(mIntentReceiver, mIntentFilter);
Intent intent = getActivity().getIntent();
if (intent.getBooleanExtra(Phone.EXTRA_KEY_ALERT_SHOW, false)) {
showAlert(intent);
}
}
@Override
public void onPause() {
super.onPause();
final Context context = getActivity();
if (mValidListener) {
mValidListener = false;
TelephonyManager tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
tm.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE);
mSwitchBar.removeOnSwitchChangeListener(this);
}
context.unregisterReceiver(mIntentReceiver);
}
/**
* Listens to the state change of the switch.
*/
@Override
public void onSwitchChanged(Switch switchView, boolean isChecked) {
Log.d(TAG, "onSwitchChanged(" + isChecked + ")");
if (!isChecked) {
updateWfcMode(false);
return;
}
// Call address management activity before turning on WFC
Intent carrierAppIntent = getCarrierActivityIntent();
if (carrierAppIntent != null) {
carrierAppIntent.putExtra(EXTRA_LAUNCH_CARRIER_APP, LAUCH_APP_ACTIVATE);
startActivityForResult(carrierAppIntent, REQUEST_CHECK_WFC_EMERGENCY_ADDRESS);
} else {
updateWfcMode(true);
}
}
/*
* Get the Intent to launch carrier emergency address management activity.
* Return null when no activity found.
*/
private Intent getCarrierActivityIntent() {
// Retrive component name from carrier config
CarrierConfigManager configManager =
getActivity().getSystemService(CarrierConfigManager.class);
if (configManager == null) return null;
PersistableBundle bundle = configManager.getConfigForSubId(mSubId);
if (bundle == null) return null;
String carrierApp = bundle.getString(
CarrierConfigManager.KEY_WFC_EMERGENCY_ADDRESS_CARRIER_APP_STRING);
if (TextUtils.isEmpty(carrierApp)) return null;
ComponentName componentName = ComponentName.unflattenFromString(carrierApp);
if (componentName == null) return null;
// Build and return intent
Intent intent = new Intent();
intent.setComponent(componentName);
return intent;
}
/*
* Turn on/off WFC mode with ImsManager and update UI accordingly
*/
private void updateWfcMode(boolean wfcEnabled) {
Log.i(TAG, "updateWfcMode(" + wfcEnabled + ")");
mImsManager.setWfcSetting(wfcEnabled);
int wfcMode = mImsManager.getWfcMode(false);
int wfcRoamingMode = mImsManager.getWfcMode(true);
updateButtonWfcMode(wfcEnabled, wfcMode, wfcRoamingMode);
if (wfcEnabled) {
mMetricsFeatureProvider.action(getActivity(), getMetricsCategory(), wfcMode);
} else {
mMetricsFeatureProvider.action(getActivity(), getMetricsCategory(), -1);
}
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
final Context context = getActivity();
if (requestCode == REQUEST_CHECK_WFC_EMERGENCY_ADDRESS) {
Log.d(TAG, "WFC emergency address activity result = " + resultCode);
if (resultCode == Activity.RESULT_OK) {
updateWfcMode(true);
}
}
}
private void updateButtonWfcMode(boolean wfcEnabled,
int wfcMode, int wfcRoamingMode) {
mButtonWfcMode.setSummary(getWfcModeSummary(wfcMode));
mButtonWfcMode.setEnabled(wfcEnabled && mEditableWfcMode);
// mButtonWfcRoamingMode.setSummary is not needed; summary is just selected value.
mButtonWfcRoamingMode.setEnabled(wfcEnabled && mEditableWfcRoamingMode);
final PreferenceScreen preferenceScreen = getPreferenceScreen();
boolean updateAddressEnabled = (getCarrierActivityIntent() != null);
if (wfcEnabled) {
if (mEditableWfcMode) {
preferenceScreen.addPreference(mButtonWfcMode);
} else {
// Don't show WFC (home) preference if it's not editable.
preferenceScreen.removePreference(mButtonWfcMode);
}
if (mEditableWfcRoamingMode) {
preferenceScreen.addPreference(mButtonWfcRoamingMode);
} else {
// Don't show WFC roaming preference if it's not editable.
preferenceScreen.removePreference(mButtonWfcRoamingMode);
}
if (updateAddressEnabled) {
preferenceScreen.addPreference(mUpdateAddress);
} else {
preferenceScreen.removePreference(mUpdateAddress);
}
} else {
preferenceScreen.removePreference(mButtonWfcMode);
preferenceScreen.removePreference(mButtonWfcRoamingMode);
preferenceScreen.removePreference(mUpdateAddress);
}
}
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
if (preference == mButtonWfcMode) {
Log.d(TAG, "onPreferenceChange mButtonWfcMode " + newValue);
mButtonWfcMode.setValue((String) newValue);
int buttonMode = Integer.valueOf((String) newValue);
int currentWfcMode = mImsManager.getWfcMode(false);
if (buttonMode != currentWfcMode) {
mImsManager.setWfcMode(buttonMode, false);
mButtonWfcMode.setSummary(getWfcModeSummary(buttonMode));
mMetricsFeatureProvider.action(getActivity(), getMetricsCategory(), buttonMode);
}
if (!mEditableWfcRoamingMode) {
int currentWfcRoamingMode = mImsManager.getWfcMode(true);
if (buttonMode != currentWfcRoamingMode) {
mImsManager.setWfcMode(buttonMode, true);
// mButtonWfcRoamingMode.setSummary is not needed; summary is selected value
}
}
} else if (preference == mButtonWfcRoamingMode) {
mButtonWfcRoamingMode.setValue((String) newValue);
int buttonMode = Integer.valueOf((String) newValue);
int currentMode = mImsManager.getWfcMode(true);
if (buttonMode != currentMode) {
mImsManager.setWfcMode(buttonMode, true);
// mButtonWfcRoamingMode.setSummary is not needed; summary is just selected value.
mMetricsFeatureProvider.action(getActivity(), getMetricsCategory(), buttonMode);
}
}
return true;
}
private int getWfcModeSummary(int wfcMode) {
int resId = com.android.internal.R.string.wifi_calling_off_summary;
if (mImsManager.isWfcEnabledByUser()) {
switch (wfcMode) {
case ImsConfig.WfcModeFeatureValueConstants.WIFI_ONLY:
resId = com.android.internal.R.string.wfc_mode_wifi_only_summary;
break;
case ImsConfig.WfcModeFeatureValueConstants.CELLULAR_PREFERRED:
resId = com.android.internal.R.string.wfc_mode_cellular_preferred_summary;
break;
case ImsConfig.WfcModeFeatureValueConstants.WIFI_PREFERRED:
resId = com.android.internal.R.string.wfc_mode_wifi_preferred_summary;
break;
default:
Log.e(TAG, "Unexpected WFC mode value: " + wfcMode);
}
}
return resId;
}
}

View File

@@ -79,6 +79,7 @@ com.android.settings.ApnSettings
com.android.settings.SecuritySettings$SecuritySubSettings
com.android.settings.PrivacySettings
com.android.settings.WifiCallingSettings
com.android.settings.WifiCallingSettingsForSub
com.android.settings.password.SetupChooseLockGeneric$SetupChooseLockGenericFragment
com.android.settings.SetupRedactionInterstitial$SetupRedactionInterstitialFragment
com.android.settings.TrustAgentSettings

View File

@@ -5,7 +5,7 @@ include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := tests
LOCAL_CERTIFICATE := platform
LOCAL_JAVA_LIBRARIES := android.test.runner
LOCAL_JAVA_LIBRARIES := android.test.runner telephony-common ims-common
LOCAL_STATIC_JAVA_LIBRARIES := \
android-support-test \

View File

@@ -0,0 +1,107 @@
/*
* Copyright (C) 2017 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.testutils;
import android.os.IBinder;
import android.os.ServiceManager;
import android.util.Log;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
// This class is for replacing existing system service with the mocked service.
// Copied from CellBroadcastReceiver app.
public final class MockedServiceManager {
private final String TAG = MockedServiceManager.class.getSimpleName();
private final HashMap<String, IBinder> mServiceManagerMockedServices = new HashMap<>();
private final HashMap<InstanceKey, Object> mOldInstances = new HashMap<>();
private final LinkedList<InstanceKey> mInstanceKeys = new LinkedList<>();
private static class InstanceKey {
final Class mClass;
final String mInstName;
final Object mObj;
InstanceKey(final Class c, final String instName, final Object obj) {
mClass = c;
mInstName = instName;
mObj = obj;
}
@Override
public int hashCode() {
return (mClass.getName().hashCode() * 31 + mInstName.hashCode()) * 31;
}
@Override
public boolean equals(Object obj) {
if (obj == null || obj.getClass() != getClass()) {
return false;
}
InstanceKey other = (InstanceKey) obj;
return (other.mClass == mClass && other.mInstName.equals(mInstName)
&& other.mObj == mObj);
}
}
public MockedServiceManager() throws Exception {
replaceInstance(ServiceManager.class, "sCache", null, mServiceManagerMockedServices);
}
public void replaceService(String key, IBinder binder) {
mServiceManagerMockedServices.put(key, binder);
}
public void restoreAllServices() throws Exception {
restoreInstances();
}
public synchronized void replaceInstance(final Class c, final String instanceName,
final Object obj, final Object newValue)
throws Exception {
Field field = c.getDeclaredField(instanceName);
field.setAccessible(true);
InstanceKey key = new InstanceKey(c, instanceName, obj);
if (!mOldInstances.containsKey(key)) {
mOldInstances.put(key, field.get(obj));
mInstanceKeys.add(key);
}
field.set(obj, newValue);
}
public synchronized void restoreInstances() throws Exception {
Iterator<InstanceKey> it = mInstanceKeys.descendingIterator();
while (it.hasNext()) {
InstanceKey key = it.next();
Field field = key.mClass.getDeclaredField(key.mInstName);
field.setAccessible(true);
field.set(key.mObj, mOldInstances.get(key));
}
mInstanceKeys.clear();
mOldInstances.clear();
}
}

View File

@@ -0,0 +1,299 @@
/**
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.wifi;
import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.action.ViewActions.click;
import static android.support.test.espresso.assertion.ViewAssertions.doesNotExist;
import static android.support.test.espresso.assertion.ViewAssertions.matches;
import static android.support.test.espresso.matcher.ViewMatchers.isCompletelyDisplayed;
import static android.support.test.espresso.matcher.ViewMatchers.isSelected;
import static android.support.test.espresso.matcher.ViewMatchers.withResourceName;
import static android.support.test.espresso.matcher.ViewMatchers.withText;
import static org.hamcrest.CoreMatchers.allOf;
import static org.hamcrest.CoreMatchers.anything;
import static org.junit.Assert.assertEquals;
import static org.junit.matchers.JUnitMatchers.containsString;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.doReturn;
import android.app.Activity;
import android.app.Instrumentation;
import android.content.Context;
import android.content.Intent;
import android.support.test.InstrumentationRegistry;
import android.support.test.espresso.NoMatchingViewException;
import android.support.test.espresso.ViewInteraction;
import android.support.test.runner.AndroidJUnit4;
import android.support.test.uiautomator.UiDevice;
import android.telephony.SubscriptionInfo;
import com.android.ims.ImsConfig;
import com.android.ims.ImsManager;
import com.android.internal.telephony.SubscriptionController;
import com.android.settings.testutils.MockedServiceManager;
import junit.framework.Assert;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@RunWith(AndroidJUnit4.class)
public class WifiCallingSettingUiTest {
private static final String SUBSCRIPTION0_NAME = "SUB0";
private static final String SUBSCRIPTION1_NAME = "SUB1";
private static final String WFC_MODE_TITLE = "Calling preference";
private static final String WFC_MODE_WIFI_ONLY = "Wi-Fi only";
private static final String WFC_MODE_WIFI_PREFERRED = "Wi-Fi preferred";
private static final String WFC_MODE_CELLULAR_PREFERRED = "Mobile preferred";
private Instrumentation mInstrumentation;
private Context mContext;
private UiDevice mDevice;
@Mock
SubscriptionController mSubscriptionController;
MockedServiceManager mMockedServiceManager;
protected HashMap<Integer, ImsManager> mImsManagerInstances = new HashMap<>();
List<SubscriptionInfo> mSils = new ArrayList();
@Mock
SubscriptionInfo mSubscriptionInfo0;
@Mock
SubscriptionInfo mSubscriptionInfo1;
@Mock
ImsManager mImsManager0;
@Mock
ImsManager mImsManager1;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
mInstrumentation = InstrumentationRegistry.getInstrumentation();
mContext = mInstrumentation.getTargetContext();
mDevice = UiDevice.getInstance(mInstrumentation);
mMockedServiceManager = new MockedServiceManager();
mMockedServiceManager.replaceService("isub", mSubscriptionController);
mMockedServiceManager.replaceInstance(
ImsManager.class, "sImsManagerInstances", null, mImsManagerInstances);
mMockedServiceManager.replaceInstance(
SubscriptionController.class, "sInstance", null, mSubscriptionController);
doReturn(mSubscriptionController)
.when(mSubscriptionController).queryLocalInterface(anyString());
mImsManagerInstances.put(0, mImsManager0);
mImsManagerInstances.put(1, mImsManager1);
doReturn(mSils).when(mSubscriptionController).getActiveSubscriptionInfoList(anyString());
doReturn(0).when(mSubscriptionController).getPhoneId(0);
doReturn(1).when(mSubscriptionController).getPhoneId(1);
doReturn(0).when(mSubscriptionInfo0).getSubscriptionId();
doReturn(1).when(mSubscriptionInfo1).getSubscriptionId();
doReturn(0).when(mSubscriptionInfo0).getSimSlotIndex();
doReturn(1).when(mSubscriptionInfo1).getSimSlotIndex();
doReturn(SUBSCRIPTION0_NAME).when(mSubscriptionInfo0).getDisplayName();
doReturn(SUBSCRIPTION1_NAME).when(mSubscriptionInfo1).getDisplayName();
doReturn(true).when(mImsManager0).isWfcEnabledByPlatform();
doReturn(true).when(mImsManager0).isNonTtyOrTtyOnVolteEnabled();
doReturn(true).when(mImsManager1).isWfcEnabledByPlatform();
doReturn(true).when(mImsManager1).isNonTtyOrTtyOnVolteEnabled();
mDevice.wakeUp();
mDevice.pressMenu();
}
@After
public void tearDown() throws Exception {
mMockedServiceManager.restoreAllServices();
}
@Test
public void testSingleSimUi() throws InterruptedException {
configureSingleSim();
doReturn(true).when(mImsManager0).isWfcEnabledByUser();
doReturn(ImsConfig.WfcModeFeatureValueConstants.WIFI_PREFERRED)
.when(mImsManager0).getWfcMode();
doReturn(ImsConfig.WfcModeFeatureValueConstants.WIFI_PREFERRED)
.when(mImsManager0).getWfcMode(anyBoolean());
mInstrumentation.startActivitySync(createActivityIntent());
checkSingleSimUi();
try {
mDevice.setOrientationLeft();
} catch (Exception e) {
Assert.fail("Exception " + e);
}
// Re-check after rotation. Fragment should be recreated properly.
checkSingleSimUi();
try {
mDevice.setOrientationNatural();
} catch (Exception e) {
Assert.fail("Exception " + e);
}
// Re-check after rotation. Fragment should be resumed properly.
checkSingleSimUi();
}
private void checkSingleSimUi() {
assertEquals(false, checkExists(onView(withText(SUBSCRIPTION0_NAME))));
assertEquals(false, checkExists(onView(withText(SUBSCRIPTION1_NAME))));
assertEquals(true, checkExists(onView(withText(WFC_MODE_TITLE))));
assertEquals(true, checkExists(onView(withText(WFC_MODE_WIFI_PREFERRED))));
checkSwitchBarStatus(true, true);
checkEmptyViewStatus(false);
}
@Test
public void testNoValidSub() throws InterruptedException {
configureDualSim();
doReturn(false).when(mImsManager0).isWfcEnabledByPlatform();
doReturn(false).when(mImsManager0).isNonTtyOrTtyOnVolteEnabled();
doReturn(false).when(mImsManager1).isWfcEnabledByPlatform();
doReturn(false).when(mImsManager1).isNonTtyOrTtyOnVolteEnabled();
doReturn(false).when(mImsManager0).isWfcEnabledByUser();
doReturn(ImsConfig.WfcModeFeatureValueConstants.WIFI_PREFERRED)
.when(mImsManager0).getWfcMode();
doReturn(ImsConfig.WfcModeFeatureValueConstants.WIFI_PREFERRED)
.when(mImsManager0).getWfcMode(anyBoolean());
Activity activity = mInstrumentation.startActivitySync(createActivityIntent());
assertEquals(false, checkExists(onView(withText(SUBSCRIPTION0_NAME))));
assertEquals(false, checkExists(onView(withText(SUBSCRIPTION1_NAME))));
assertEquals(false, checkExists(onView(withText(WFC_MODE_TITLE))));
checkSwitchBarStatus(false, false);
checkEmptyViewStatus(false);
}
@Test
public void testWfcDisabled() throws InterruptedException {
configureSingleSim();
doReturn(false).when(mImsManager0).isWfcEnabledByUser();
doReturn(ImsConfig.WfcModeFeatureValueConstants.WIFI_PREFERRED)
.when(mImsManager0).getWfcMode();
doReturn(ImsConfig.WfcModeFeatureValueConstants.WIFI_PREFERRED)
.when(mImsManager0).getWfcMode(anyBoolean());
Activity activity = mInstrumentation.startActivitySync(createActivityIntent());
assertEquals(false, checkExists(onView(withText(SUBSCRIPTION0_NAME))));
assertEquals(false, checkExists(onView(withText(SUBSCRIPTION1_NAME))));
assertEquals(false, checkExists(onView(withText(WFC_MODE_TITLE))));
checkSwitchBarStatus(true, false);
checkEmptyViewStatus(true);
}
@Test
public void testDualSimUi() throws InterruptedException {
configureDualSim();
doReturn(true).when(mImsManager0).isWfcEnabledByUser();
doReturn(false).when(mImsManager1).isWfcEnabledByUser();
doReturn(ImsConfig.WfcModeFeatureValueConstants.CELLULAR_PREFERRED)
.when(mImsManager0).getWfcMode();
doReturn(ImsConfig.WfcModeFeatureValueConstants.CELLULAR_PREFERRED)
.when(mImsManager0).getWfcMode(anyBoolean());
mInstrumentation.startActivitySync(createActivityIntent());
assertEquals(true, checkExists(onView(withText(SUBSCRIPTION0_NAME))));
assertEquals(true, checkExists(onView(withText(SUBSCRIPTION1_NAME))));
assertEquals(true, checkExists(onView(withText(WFC_MODE_TITLE))));
assertEquals(true, checkExists(onView(withText(WFC_MODE_CELLULAR_PREFERRED))));
onView(withText(SUBSCRIPTION0_NAME)).check(matches(isSelected()));
checkSwitchBarStatus(true, true);
checkEmptyViewStatus(false);
// Switch to SUB1.
onView(withText(SUBSCRIPTION1_NAME)).perform(click());
checkSwitchBarStatus(true, false);
checkEmptyViewStatus(true);
onView(withText(SUBSCRIPTION1_NAME)).check(matches(isSelected()));
}
private boolean checkExists(ViewInteraction v) {
try {
v.check(matches(isCompletelyDisplayed()));
return true;
} catch (NoMatchingViewException e) {
return false;
}
}
private Intent createActivityIntent() {
Intent intent = new Intent(mContext,
com.android.settings.Settings.WifiCallingSettingsActivity.class);
intent.setPackage("com.android.settings");
intent.setAction("android.intent.action.MAIN");
return intent;
}
private void configureSingleSim() {
mSils.clear();
mSils.add(mSubscriptionInfo0);
}
private void configureDualSim() {
mSils.clear();
mSils.add(mSubscriptionInfo0);
mSils.add(mSubscriptionInfo1);
}
private void checkSwitchBarStatus(boolean shouldDisplay, boolean statusOn) {
if (shouldDisplay) {
try {
onView(allOf(withResourceName("switch_text"), isCompletelyDisplayed()))
.check(matches(withText(containsString(statusOn ? "On" : "Off"))));
} catch (Exception e) {
Assert.fail("Exception " + e);
}
} else {
onView(allOf(withResourceName("switch_text"), isCompletelyDisplayed()))
.check(doesNotExist());
}
}
private void checkEmptyViewStatus(boolean shouldDisplay) {
try {
if (!shouldDisplay) {
onView(allOf(withResourceName("empty"), isCompletelyDisplayed()))
.check(doesNotExist());
} else {
onView(allOf(withResourceName("empty"), isCompletelyDisplayed()))
.check(matches(anything()));
}
} catch (Exception e) {
Assert.fail("Exception " + e);
}
}
}