diff --git a/res/layout/dialog_sim_status.xml b/res/layout/dialog_sim_status.xml new file mode 100644 index 00000000000..068a889def4 --- /dev/null +++ b/res/layout/dialog_sim_status.xml @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/values/strings.xml b/res/values/strings.xml index f0721fc7dcd..87abec52b22 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -2671,6 +2671,10 @@ MDN Phone number + + MDN on SIM + + Phone number on SIM MIN @@ -6430,6 +6434,10 @@ No SIM cards inserted SIM status + + SIM status (sim slot 1) + + SIM status (sim slot 2) Call back from default SIM diff --git a/res/values/styles.xml b/res/values/styles.xml index c9ef22cfb97..8815bb3c762 100644 --- a/res/values/styles.xml +++ b/res/values/styles.xml @@ -478,4 +478,14 @@ @dimen/search_bar_text_size + + + + diff --git a/res/xml/device_info_settings_v2.xml b/res/xml/device_info_settings_v2.xml index 0553f1ebc5c..037db63c94b 100644 --- a/res/xml/device_info_settings_v2.xml +++ b/res/xml/device_info_settings_v2.xml @@ -28,12 +28,19 @@ android:title="@string/status_number" android:summary="@string/summary_placeholder"/> - + + + + + 1; + } + + @Override + public void displayPreference(PreferenceScreen screen) { + super.displayPreference(screen); + mPreference = screen.findPreference(getPreferenceKey()); + if (mPreference == null) { + return; + } + + mPreference.setTitle(getPreferenceTitle()); + mPreference.setSummary(getCarrierName()); + } + + @Override + public boolean handlePreferenceTreeClick(Preference preference) { + if (!TextUtils.equals(preference.getKey(), getPreferenceKey())) { + return false; + } + + SimStatusDialogFragment.show(mFragment, getSimSlot(), getPreferenceTitle()); + return true; + } + + /** + * @return The preference title for the displayed preference. + */ + protected abstract String getPreferenceTitle(); + + /** + * @return The sim slot to retrieve sim status information about. + */ + protected abstract int getSimSlot(); + + private CharSequence getCarrierName() { + final List subscriptionInfoList = + mSubscriptionManager.getActiveSubscriptionInfoList(); + if (subscriptionInfoList != null) { + for (SubscriptionInfo info : subscriptionInfoList) { + if (info.getSimSlotIndex() == getSimSlot()) { + return info.getCarrierName(); + } + } + } + return mContext.getText(R.string.device_info_not_available); + } +} diff --git a/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogController.java b/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogController.java new file mode 100644 index 00000000000..a6cc28f1857 --- /dev/null +++ b/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogController.java @@ -0,0 +1,375 @@ +/* + * 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.deviceinfo.simstatus; + +import static android.content.Context.TELEPHONY_SERVICE; + +import android.Manifest; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.PackageManager; +import android.content.res.Resources; +import android.os.Bundle; +import android.os.UserHandle; +import android.support.annotation.NonNull; +import android.support.annotation.VisibleForTesting; +import android.telephony.CellBroadcastMessage; +import android.telephony.PhoneStateListener; +import android.telephony.ServiceState; +import android.telephony.SignalStrength; +import android.telephony.SubscriptionInfo; +import android.telephony.SubscriptionManager; +import android.telephony.TelephonyManager; +import android.text.TextUtils; +import android.util.Log; + +import com.android.settings.R; +import com.android.settingslib.DeviceInfoUtils; +import com.android.settingslib.core.lifecycle.Lifecycle; +import com.android.settingslib.core.lifecycle.LifecycleObserver; +import com.android.settingslib.core.lifecycle.events.OnPause; +import com.android.settingslib.core.lifecycle.events.OnResume; + +import java.util.List; + +public class SimStatusDialogController implements LifecycleObserver, OnResume, OnPause { + + private final static String TAG = "SimStatusDialogCtrl"; + + @VisibleForTesting + final static int NETWORK_PROVIDER_VALUE_ID = R.id.operator_name_value; + @VisibleForTesting + final static int PHONE_NUMBER_VALUE_ID = R.id.number_value; + @VisibleForTesting + final static int CELLULAR_NETWORK_STATE = R.id.data_state_value; + @VisibleForTesting + final static int OPERATOR_INFO_LABEL_ID = R.id.latest_area_info_label; + @VisibleForTesting + final static int OPERATOR_INFO_VALUE_ID = R.id.latest_area_info_value; + @VisibleForTesting + final static int SERVICE_STATE_VALUE_ID = R.id.service_state_value; + @VisibleForTesting + final static int SIGNAL_STRENGTH_VALUE_ID = R.id.signal_strength_value; + @VisibleForTesting + final static int CELLULAR_NETWORK_TYPE_VALUE_ID = R.id.network_type_value; + @VisibleForTesting + final static int ROAMING_INFO_VALUE_ID = R.id.roaming_state_value; + + private final static String CB_AREA_INFO_RECEIVED_ACTION = + "com.android.cellbroadcastreceiver.CB_AREA_INFO_RECEIVED"; + private final static String GET_LATEST_CB_AREA_INFO_ACTION = + "com.android.cellbroadcastreceiver.GET_LATEST_CB_AREA_INFO"; + private final static String CELL_BROADCAST_RECEIVER_APP = "com.android.cellbroadcastreceiver"; + + private final SimStatusDialogFragment mDialog; + private final SubscriptionInfo mSubscriptionInfo; + private final TelephonyManager mTelephonyManager; + private final Resources mRes; + private final Context mContext; + + private boolean mShowLatestAreaInfo; + + private final BroadcastReceiver mAreaInfoReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + final String action = intent.getAction(); + if (TextUtils.equals(action, CB_AREA_INFO_RECEIVED_ACTION)) { + final Bundle extras = intent.getExtras(); + if (extras == null) { + return; + } + final CellBroadcastMessage cbMessage = (CellBroadcastMessage) extras.get("message"); + if (cbMessage != null + && mSubscriptionInfo.getSubscriptionId() == cbMessage.getSubId()) { + final String latestAreaInfo = cbMessage.getMessageBody(); + mDialog.setText(OPERATOR_INFO_VALUE_ID, latestAreaInfo); + } + } + } + }; + + + private PhoneStateListener mPhoneStateListener; + + public SimStatusDialogController(@NonNull SimStatusDialogFragment dialog, Lifecycle lifecycle, + int slotId) { + mDialog = dialog; + mContext = dialog.getContext(); + mSubscriptionInfo = getPhoneSubscriptionInfo(slotId); + mTelephonyManager = (TelephonyManager) mContext.getSystemService( + TELEPHONY_SERVICE); + mRes = mContext.getResources(); + + if (lifecycle != null) { + lifecycle.addObserver(this); + } + } + + public void initialize() { + if (mSubscriptionInfo == null) { + return; + } + + mPhoneStateListener = getPhoneStateListener(); + + final ServiceState serviceState = getCurrentServiceState(); + updateNetworkProvider(serviceState); + updatePhoneNumber(); + updateLatestAreaInfo(); + updateServiceState(serviceState); + updateSignalStrength(getSignalStrength()); + updateNetworkType(); + updateRoamingStatus(serviceState); + } + + @Override + public void onResume() { + if (mSubscriptionInfo == null) { + return; + } + + mTelephonyManager.listen(mPhoneStateListener, + PhoneStateListener.LISTEN_DATA_CONNECTION_STATE + | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS + | PhoneStateListener.LISTEN_SERVICE_STATE); + + if (mShowLatestAreaInfo) { + mContext.registerReceiver(mAreaInfoReceiver, + new IntentFilter(CB_AREA_INFO_RECEIVED_ACTION), + Manifest.permission.RECEIVE_EMERGENCY_BROADCAST, null /* scheduler */); + // Ask CellBroadcastReceiver to broadcast the latest area info received + final Intent getLatestIntent = new Intent(GET_LATEST_CB_AREA_INFO_ACTION); + getLatestIntent.setPackage(CELL_BROADCAST_RECEIVER_APP); + mContext.sendBroadcastAsUser(getLatestIntent, UserHandle.ALL, + Manifest.permission.RECEIVE_EMERGENCY_BROADCAST); + } + } + + @Override + public void onPause() { + if (mSubscriptionInfo == null) { + return; + } + + mTelephonyManager.listen(mPhoneStateListener, + PhoneStateListener.LISTEN_NONE); + + if (mShowLatestAreaInfo) { + mContext.unregisterReceiver(mAreaInfoReceiver); + } + } + + private void updateNetworkProvider(ServiceState serviceState) { + mDialog.setText(NETWORK_PROVIDER_VALUE_ID, serviceState.getOperatorAlphaLong()); + } + + private void updatePhoneNumber() { + // If formattedNumber is null or empty, it'll display as "Unknown". + mDialog.setText(PHONE_NUMBER_VALUE_ID, getPhoneNumber()); + } + + private void updateDataState(int state) { + String networkStateValue; + + switch (state) { + case TelephonyManager.DATA_CONNECTED: + networkStateValue = mRes.getString(R.string.radioInfo_data_connected); + break; + case TelephonyManager.DATA_SUSPENDED: + networkStateValue = mRes.getString(R.string.radioInfo_data_suspended); + break; + case TelephonyManager.DATA_CONNECTING: + networkStateValue = mRes.getString(R.string.radioInfo_data_connecting); + break; + case TelephonyManager.DATA_DISCONNECTED: + networkStateValue = mRes.getString(R.string.radioInfo_data_disconnected); + break; + default: + networkStateValue = mRes.getString(R.string.radioInfo_unknown); + break; + } + + mDialog.setText(CELLULAR_NETWORK_STATE, networkStateValue); + } + + + private void updateLatestAreaInfo() { + mShowLatestAreaInfo = Resources.getSystem().getBoolean( + com.android.internal.R.bool.config_showAreaUpdateInfoSettings) + && mTelephonyManager.getPhoneType() != TelephonyManager.PHONE_TYPE_CDMA; + + if (!mShowLatestAreaInfo) { + mDialog.removeSettingFromScreen(OPERATOR_INFO_LABEL_ID); + mDialog.removeSettingFromScreen(OPERATOR_INFO_VALUE_ID); + } + } + + private void updateServiceState(ServiceState serviceState) { + final int state = serviceState.getState(); + if (state == ServiceState.STATE_OUT_OF_SERVICE || state == ServiceState.STATE_POWER_OFF) { + resetSignalStrength(); + } + + String serviceStateValue; + + switch (state) { + case ServiceState.STATE_IN_SERVICE: + serviceStateValue = mRes.getString(R.string.radioInfo_service_in); + break; + case ServiceState.STATE_OUT_OF_SERVICE: + case ServiceState.STATE_EMERGENCY_ONLY: + // Set summary string of service state to radioInfo_service_out when + // service state is both STATE_OUT_OF_SERVICE & STATE_EMERGENCY_ONLY + serviceStateValue = mRes.getString(R.string.radioInfo_service_out); + break; + case ServiceState.STATE_POWER_OFF: + serviceStateValue = mRes.getString(R.string.radioInfo_service_off); + break; + default: + serviceStateValue = mRes.getString(R.string.radioInfo_unknown); + break; + } + + mDialog.setText(SERVICE_STATE_VALUE_ID, serviceStateValue); + } + + private void updateSignalStrength(SignalStrength signalStrength) { + final int state = getCurrentServiceState().getState(); + + if ((ServiceState.STATE_OUT_OF_SERVICE == state) || + (ServiceState.STATE_POWER_OFF == state)) { + return; + } + + int signalDbm = getDbm(signalStrength); + int signalAsu = getAsuLevel(signalStrength); + + if (signalDbm == -1) { + signalDbm = 0; + } + + if (signalAsu == -1) { + signalAsu = 0; + } + + mDialog.setText(SIGNAL_STRENGTH_VALUE_ID, mRes.getString(R.string.sim_signal_strength, + signalDbm, signalAsu)); + } + + private void resetSignalStrength() { + mDialog.setText(SIGNAL_STRENGTH_VALUE_ID, "0"); + } + + private void updateNetworkType() { + // Whether EDGE, UMTS, etc... + String networktype = null; + final int subId = mSubscriptionInfo.getSubscriptionId(); + final int actualDataNetworkType = mTelephonyManager.getDataNetworkType(subId); + final int actualVoiceNetworkType = mTelephonyManager.getVoiceNetworkType(subId); + if (TelephonyManager.NETWORK_TYPE_UNKNOWN != actualDataNetworkType) { + networktype = mTelephonyManager.getNetworkTypeName(actualDataNetworkType); + } else if (TelephonyManager.NETWORK_TYPE_UNKNOWN != actualVoiceNetworkType) { + networktype = mTelephonyManager.getNetworkTypeName(actualVoiceNetworkType); + } + + boolean show4GForLTE = false; + try { + final Context con = mContext.createPackageContext( + "com.android.systemui", 0 /* flags */); + final int id = con.getResources().getIdentifier("config_show4GForLTE", + "bool" /* default type */, "com.android.systemui" /* default package */); + show4GForLTE = con.getResources().getBoolean(id); + } catch (PackageManager.NameNotFoundException e) { + Log.e(TAG, "NameNotFoundException for show4GFotLTE"); + } + + if (TextUtils.equals(networktype, "LTE") && show4GForLTE) { + networktype = "4G"; + } + mDialog.setText(CELLULAR_NETWORK_TYPE_VALUE_ID, networktype); + } + + private void updateRoamingStatus(ServiceState serviceState) { + if (serviceState.getRoaming()) { + mDialog.setText(ROAMING_INFO_VALUE_ID, mRes.getString(R.string.radioInfo_roaming_in)); + } else { + mDialog.setText(ROAMING_INFO_VALUE_ID, mRes.getString(R.string.radioInfo_roaming_not)); + } + } + + private SubscriptionInfo getPhoneSubscriptionInfo(int slotId) { + final List subscriptionInfoList = SubscriptionManager.from( + mContext).getActiveSubscriptionInfoList(); + if (subscriptionInfoList != null && subscriptionInfoList.size() > slotId) { + return subscriptionInfoList.get(slotId); + } else { + return null; + } + } + + @VisibleForTesting + ServiceState getCurrentServiceState() { + return mTelephonyManager.getServiceStateForSubscriber( + mSubscriptionInfo.getSubscriptionId()); + } + + @VisibleForTesting + int getDbm(SignalStrength signalStrength) { + return signalStrength.getDbm(); + } + + @VisibleForTesting + int getAsuLevel(SignalStrength signalStrength) { + return signalStrength.getAsuLevel(); + } + + @VisibleForTesting + PhoneStateListener getPhoneStateListener() { + return new PhoneStateListener( + mSubscriptionInfo.getSubscriptionId()) { + @Override + public void onDataConnectionStateChanged(int state) { + updateDataState(state); + updateNetworkType(); + } + + @Override + public void onSignalStrengthsChanged(SignalStrength signalStrength) { + updateSignalStrength(signalStrength); + } + + @Override + public void onServiceStateChanged(ServiceState serviceState) { + updateNetworkProvider(serviceState); + updateServiceState(serviceState); + updateRoamingStatus(serviceState); + } + }; + } + + @VisibleForTesting + String getPhoneNumber() { + return DeviceInfoUtils.getFormattedPhoneNumber(mContext, mSubscriptionInfo); + } + + @VisibleForTesting + SignalStrength getSignalStrength() { + return mTelephonyManager.getSignalStrength(); + } +} diff --git a/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogFragment.java b/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogFragment.java new file mode 100644 index 00000000000..a15cb81e011 --- /dev/null +++ b/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogFragment.java @@ -0,0 +1,92 @@ +/* + * 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.deviceinfo.simstatus; + +import android.app.AlertDialog; +import android.app.Dialog; +import android.app.Fragment; +import android.app.FragmentManager; +import android.os.Bundle; +import android.text.TextUtils; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.TextView; + +import com.android.internal.logging.nano.MetricsProto; +import com.android.settings.R; +import com.android.settings.core.instrumentation.InstrumentedDialogFragment; + +public class SimStatusDialogFragment extends InstrumentedDialogFragment { + + private static final String SIM_SLOT_BUNDLE_KEY = "arg_key_sim_slot"; + private static final String DIALOG_TITLE_BUNDLE_KEY = "arg_key_dialog_title"; + + private static final String TAG = "SimStatusDialog"; + + private View mRootView; + private SimStatusDialogController mController; + + @Override + public int getMetricsCategory() { + return MetricsProto.MetricsEvent.DIALOG_SIM_STATUS; + } + + public static void show(Fragment host, int slotId, String dialogTitle) { + final FragmentManager manager = host.getChildFragmentManager(); + if (manager.findFragmentByTag(TAG) == null) { + final Bundle bundle = new Bundle(); + bundle.putInt(SIM_SLOT_BUNDLE_KEY, slotId); + bundle.putString(DIALOG_TITLE_BUNDLE_KEY, dialogTitle); + final SimStatusDialogFragment dialog = + new SimStatusDialogFragment(); + dialog.setArguments(bundle); + dialog.show(manager, TAG); + } + } + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + final Bundle bundle = getArguments(); + final int slotId = bundle.getInt(SIM_SLOT_BUNDLE_KEY); + final String dialogTitle = bundle.getString(DIALOG_TITLE_BUNDLE_KEY); + mController = new SimStatusDialogController(this, mLifecycle, slotId); + final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()) + .setTitle(dialogTitle) + .setPositiveButton(android.R.string.ok, null /* onClickListener */); + mRootView = LayoutInflater.from(builder.getContext()) + .inflate(R.layout.dialog_sim_status, null /* parent */); + mController.initialize(); + return builder.setView(mRootView).create(); + } + + public void removeSettingFromScreen(int viewId) { + final View view = mRootView.findViewById(viewId); + if (view != null) { + view.setVisibility(View.GONE); + } + } + + public void setText(int viewId, CharSequence text) { + final TextView textView = mRootView.findViewById(viewId); + if (TextUtils.isEmpty(text)) { + text = getResources().getString(R.string.device_info_default); + } + if (textView != null) { + textView.setText(text); + } + } +} diff --git a/src/com/android/settings/deviceinfo/simstatus/SimStatusDualSimPreferenceController.java b/src/com/android/settings/deviceinfo/simstatus/SimStatusDualSimPreferenceController.java new file mode 100644 index 00000000000..ce73a294247 --- /dev/null +++ b/src/com/android/settings/deviceinfo/simstatus/SimStatusDualSimPreferenceController.java @@ -0,0 +1,52 @@ +/* + * 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.deviceinfo.simstatus; + +import android.app.Fragment; +import android.content.Context; + +import com.android.settings.R; + +public class SimStatusDualSimPreferenceController extends AbstractSimStatusPreferenceController { + + private static final int SIM_SLOT = 1; + private static final String SIM_STATUS_DUAL_SIM_KEY = "sim_status_sim_2"; + + public SimStatusDualSimPreferenceController(Context context, Fragment fragment) { + super(context, fragment); + } + + @Override + public boolean isAvailable() { + return super.isAvailable() && mIsMultiSim; + } + + @Override + protected String getPreferenceTitle() { + return mContext.getResources().getString(R.string.sim_status_title_sim_slot_2); + } + + @Override + protected int getSimSlot() { + return SIM_SLOT; + } + + @Override + public String getPreferenceKey() { + return SIM_STATUS_DUAL_SIM_KEY; + } +} diff --git a/src/com/android/settings/deviceinfo/simstatus/SimStatusPreferenceControllerV2.java b/src/com/android/settings/deviceinfo/simstatus/SimStatusPreferenceControllerV2.java new file mode 100644 index 00000000000..ee16eac5bf3 --- /dev/null +++ b/src/com/android/settings/deviceinfo/simstatus/SimStatusPreferenceControllerV2.java @@ -0,0 +1,49 @@ +/* + * 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.deviceinfo.simstatus; + +import android.app.Fragment; +import android.content.Context; + +import com.android.settings.R; + +public class SimStatusPreferenceControllerV2 extends AbstractSimStatusPreferenceController { + + public static final int SIM_SLOT = 0; + + private static final String KEY_SIM_1_STATUS = "sim_status_sim_1"; + + public SimStatusPreferenceControllerV2(Context context, Fragment fragment) { + super(context, fragment); + } + + @Override + protected String getPreferenceTitle() { + return mIsMultiSim ? mContext.getResources().getString(R.string.sim_status_title_sim_slot_1) + : mContext.getResources().getString(R.string.sim_status_title); + } + + @Override + protected int getSimSlot() { + return SIM_SLOT; + } + + @Override + public String getPreferenceKey() { + return KEY_SIM_1_STATUS; + } +} diff --git a/tests/robotests/src/com/android/settings/deviceinfo/simstatus/AbstractSimStatusPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/simstatus/AbstractSimStatusPreferenceControllerTest.java new file mode 100644 index 00000000000..ee749d085d3 --- /dev/null +++ b/tests/robotests/src/com/android/settings/deviceinfo/simstatus/AbstractSimStatusPreferenceControllerTest.java @@ -0,0 +1,113 @@ +/* + * 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.deviceinfo.simstatus; + +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.app.Fragment; +import android.app.FragmentManager; +import android.content.Context; +import android.os.UserManager; +import android.support.v7.preference.Preference; +import android.support.v7.preference.PreferenceScreen; + +import com.android.settings.TestConfig; +import com.android.settings.testutils.SettingsRobolectricTestRunner; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Answers; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; + +@RunWith(SettingsRobolectricTestRunner.class) +@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) +public class AbstractSimStatusPreferenceControllerTest { + + @Mock + private Preference mPreference; + @Mock + private PreferenceScreen mScreen; + @Mock + private UserManager mUserManager; + @Mock + private Fragment mFragment; + + private Context mContext; + private AbstractSimStatusPreferenceControllerImpl mController; + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + mContext = spy(RuntimeEnvironment.application); + doReturn(mUserManager).when(mContext).getSystemService(UserManager.class); + mController = new AbstractSimStatusPreferenceControllerImpl(mContext, mFragment); + when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference); + when(mPreference.getKey()).thenReturn(mController.getPreferenceKey()); + } + + @Test + public void displayPreference_shouldSetTitleAndSummary() { + mController.displayPreference(mScreen); + + verify(mPreference).setTitle(mController.getPreferenceTitle()); + verify(mPreference).setSummary(anyString()); + } + + @Test + public void handlePreferenceTreeClick_shouldStartDialogFragment() { + when(mFragment.getChildFragmentManager()).thenReturn( + mock(FragmentManager.class, Answers.RETURNS_DEEP_STUBS)); + when(mPreference.getTitle()).thenReturn("foo"); + mController.displayPreference(mScreen); + + mController.handlePreferenceTreeClick(mPreference); + + verify(mFragment).getChildFragmentManager(); + } + + public class AbstractSimStatusPreferenceControllerImpl extends + AbstractSimStatusPreferenceController { + + public AbstractSimStatusPreferenceControllerImpl(Context context, Fragment fragment) { + super(context, fragment); + } + + @Override + public String getPreferenceKey() { + return "foo"; + } + + @Override + protected String getPreferenceTitle() { + return "bar"; + } + + @Override + protected int getSimSlot() { + return 0; + } + } +} diff --git a/tests/robotests/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogControllerTest.java new file mode 100644 index 00000000000..73db81d9327 --- /dev/null +++ b/tests/robotests/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogControllerTest.java @@ -0,0 +1,202 @@ +/* + * 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.deviceinfo.simstatus; + +import static com.android.settings.deviceinfo.simstatus.SimStatusDialogController + .CELLULAR_NETWORK_TYPE_VALUE_ID; +import static com.android.settings.deviceinfo.simstatus.SimStatusDialogController + .NETWORK_PROVIDER_VALUE_ID; +import static com.android.settings.deviceinfo.simstatus.SimStatusDialogController + .OPERATOR_INFO_LABEL_ID; +import static com.android.settings.deviceinfo.simstatus.SimStatusDialogController + .OPERATOR_INFO_VALUE_ID; +import static com.android.settings.deviceinfo.simstatus.SimStatusDialogController + .PHONE_NUMBER_VALUE_ID; +import static com.android.settings.deviceinfo.simstatus.SimStatusDialogController + .ROAMING_INFO_VALUE_ID; +import static com.android.settings.deviceinfo.simstatus.SimStatusDialogController + .SERVICE_STATE_VALUE_ID; +import static com.android.settings.deviceinfo.simstatus.SimStatusDialogController + .SIGNAL_STRENGTH_VALUE_ID; + +import static org.mockito.ArgumentMatchers.any; +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.content.Context; +import android.telephony.PhoneStateListener; +import android.telephony.ServiceState; +import android.telephony.SignalStrength; +import android.telephony.SubscriptionInfo; +import android.telephony.TelephonyManager; + +import com.android.settings.R; +import com.android.settings.TestConfig; +import com.android.settings.testutils.SettingsRobolectricTestRunner; +import com.android.settingslib.core.lifecycle.Lifecycle; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; +import org.robolectric.util.ReflectionHelpers; + +@RunWith(SettingsRobolectricTestRunner.class) +@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) +public class SimStatusDialogControllerTest { + + @Mock + private SimStatusDialogFragment mDialog; + @Mock + private TelephonyManager mTelephonyManager; + @Mock + private SubscriptionInfo mSubscriptionInfo; + @Mock + private ServiceState mServiceState; + @Mock + private PhoneStateListener mPhoneStateListener; + @Mock + private SignalStrength mSignalStrength; + + + private SimStatusDialogController mController; + private Context mContext; + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + mContext = RuntimeEnvironment.application; + when(mDialog.getContext()).thenReturn(mContext); + mController = spy( + new SimStatusDialogController(mDialog, new Lifecycle(), 0 /* phone id */)); + doReturn(mServiceState).when(mController).getCurrentServiceState(); + doReturn(0).when(mController).getDbm(any()); + doReturn(0).when(mController).getAsuLevel(any()); + doReturn(mPhoneStateListener).when(mController).getPhoneStateListener(); + doReturn("").when(mController).getPhoneNumber(); + doReturn(mSignalStrength).when(mController).getSignalStrength(); + ReflectionHelpers.setField(mController, "mTelephonyManager", mTelephonyManager); + ReflectionHelpers.setField(mController, "mSubscriptionInfo", mSubscriptionInfo); + } + + @Test + public void initialize_updateNetworkProviderWithFoobarCarrier_shouldUpdateCarrierWithFoobar() { + final String carrierName = "foobar"; + when(mServiceState.getOperatorAlphaLong()).thenReturn(carrierName); + + mController.initialize(); + + verify(mDialog).setText(NETWORK_PROVIDER_VALUE_ID, carrierName); + } + + @Test + public void initialize_updatePhoneNumberWith1111111111_shouldUpdatePhoneNumber() { + final String phoneNumber = "1111111111"; + doReturn(phoneNumber).when(mController).getPhoneNumber(); + + mController.initialize(); + + verify(mDialog).setText(PHONE_NUMBER_VALUE_ID, phoneNumber); + } + + @Test + public void initialize_updateLatestAreaInfoWithCdmaPhone_shouldRemoveOperatorInfoSetting() { + when(mTelephonyManager.getPhoneType()).thenReturn(TelephonyManager.PHONE_TYPE_CDMA); + + mController.initialize(); + + verify(mDialog).removeSettingFromScreen(OPERATOR_INFO_LABEL_ID); + verify(mDialog).removeSettingFromScreen(OPERATOR_INFO_VALUE_ID); + } + + @Test + public void initialize_updateServiceStateWithInService_shouldUpdateTextToBeCInService() { + when(mServiceState.getState()).thenReturn(ServiceState.STATE_IN_SERVICE); + + mController.initialize(); + + final String inServiceText = mContext.getResources().getString( + R.string.radioInfo_service_in); + verify(mDialog).setText(SERVICE_STATE_VALUE_ID, inServiceText); + } + + @Test + public void initialize_updateDataStateWithPowerOff_shouldUpdateSettingAndResetSignalStrength() { + when(mServiceState.getState()).thenReturn(ServiceState.STATE_POWER_OFF); + + mController.initialize(); + + final String offServiceText = mContext.getResources().getString( + R.string.radioInfo_service_off); + verify(mDialog).setText(SERVICE_STATE_VALUE_ID, offServiceText); + verify(mDialog).setText(SIGNAL_STRENGTH_VALUE_ID, "0"); + } + + @Test + public void initialize_updateSignalStrengthWith50_shouldUpdateSignalStrengthTo50() { + final int signalDbm = 50; + final int signalAsu = 50; + doReturn(signalDbm).when(mController).getDbm(mSignalStrength); + doReturn(signalAsu).when(mController).getAsuLevel(mSignalStrength); + + mController.initialize(); + + final String signalStrengthString = mContext.getResources().getString( + R.string.sim_signal_strength, signalDbm, signalAsu); + verify(mDialog).setText(SIGNAL_STRENGTH_VALUE_ID, signalStrengthString); + } + + @Test + public void initialize_updateNetworkTypeWithEdge_shouldUpdateSettingToEdge() { + when(mTelephonyManager.getDataNetworkType(anyInt())).thenReturn( + TelephonyManager.NETWORK_TYPE_EDGE); + + mController.initialize(); + + verify(mDialog).setText(CELLULAR_NETWORK_TYPE_VALUE_ID, + TelephonyManager.getNetworkTypeName(TelephonyManager.NETWORK_TYPE_EDGE)); + } + + @Test + public void initialize_updateRoamingStatusIsRoaming_shouldSetSettingToRoaming() { + when(mServiceState.getRoaming()).thenReturn(true); + + mController.initialize(); + + final String roamingOnString = mContext.getResources().getString( + R.string.radioInfo_roaming_in); + verify(mDialog).setText(ROAMING_INFO_VALUE_ID, roamingOnString); + } + + @Test + public void initialize_updateRoamingStatusNotRoaming_shouldSetSettingToRoamingOff() { + when(mServiceState.getRoaming()).thenReturn(false); + + mController.initialize(); + + final String roamingOffString = mContext.getResources().getString( + R.string.radioInfo_roaming_not); + verify(mDialog).setText(ROAMING_INFO_VALUE_ID, roamingOffString); + } + +} diff --git a/tests/robotests/src/com/android/settings/deviceinfo/simstatus/SimStatusDualSimPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/simstatus/SimStatusDualSimPreferenceControllerTest.java new file mode 100644 index 00000000000..0845bfa95e9 --- /dev/null +++ b/tests/robotests/src/com/android/settings/deviceinfo/simstatus/SimStatusDualSimPreferenceControllerTest.java @@ -0,0 +1,93 @@ +/* + * 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.deviceinfo.simstatus; + +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; + +import android.app.Fragment; +import android.content.Context; +import android.net.ConnectivityManager; +import android.os.UserManager; +import android.support.v7.preference.Preference; +import android.support.v7.preference.PreferenceScreen; +import android.telephony.TelephonyManager; + +import com.android.settings.TestConfig; +import com.android.settings.testutils.SettingsRobolectricTestRunner; + +import com.google.common.truth.Truth; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; +import org.robolectric.util.ReflectionHelpers; + +@RunWith(SettingsRobolectricTestRunner.class) +@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) +public class SimStatusDualSimPreferenceControllerTest { + + @Mock + private Preference mPreference; + @Mock + private PreferenceScreen mScreen; + @Mock + private TelephonyManager mTelephonyManager; + @Mock + private UserManager mUserManager; + @Mock + private ConnectivityManager mConnectivityManager; + @Mock + private Fragment mFragment; + + private Context mContext; + private SimStatusDualSimPreferenceController mController; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mContext = spy(RuntimeEnvironment.application); + doReturn(mUserManager).when(mContext).getSystemService(UserManager.class); + doReturn(mConnectivityManager).when(mContext).getSystemService(ConnectivityManager.class); + when(mUserManager.isAdminUser()).thenReturn(true); + when(mConnectivityManager.isNetworkSupported(ConnectivityManager.TYPE_MOBILE)).thenReturn( + true); + mController = new SimStatusDualSimPreferenceController(mContext, mFragment); + ReflectionHelpers.setField(mController, "mTelephonyManager", mTelephonyManager); + when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference); + when(mPreference.getKey()).thenReturn(mController.getPreferenceKey()); + } + + @Test + public void isAvailable_multiSim_shouldBeTrue() { + ReflectionHelpers.setField(mController, "mIsMultiSim", true); + + Truth.assertThat(mController.isAvailable()).isTrue(); + } + + @Test + public void isAvailable_notMultiSim_shouldBeFalse() { + ReflectionHelpers.setField(mController, "mIsMultiSim", false); + + Truth.assertThat(mController.isAvailable()).isFalse(); + } +} diff --git a/tests/robotests/src/com/android/settings/deviceinfo/simstatus/SimStatusPreferenceControllerV2Test.java b/tests/robotests/src/com/android/settings/deviceinfo/simstatus/SimStatusPreferenceControllerV2Test.java new file mode 100644 index 00000000000..3282c3c85f7 --- /dev/null +++ b/tests/robotests/src/com/android/settings/deviceinfo/simstatus/SimStatusPreferenceControllerV2Test.java @@ -0,0 +1,89 @@ +/* + * 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.deviceinfo.simstatus; + +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.app.Fragment; +import android.content.Context; +import android.os.UserManager; +import android.support.v7.preference.Preference; +import android.support.v7.preference.PreferenceScreen; +import android.telephony.TelephonyManager; + +import com.android.settings.R; +import com.android.settings.TestConfig; +import com.android.settings.testutils.SettingsRobolectricTestRunner; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; +import org.robolectric.util.ReflectionHelpers; + +@RunWith(SettingsRobolectricTestRunner.class) +@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) +public class SimStatusPreferenceControllerV2Test { + + @Mock + private Preference mPreference; + @Mock + private PreferenceScreen mScreen; + @Mock + private TelephonyManager mTelephonyManager; + @Mock + private UserManager mUserManager; + @Mock + private Fragment mFragment; + + private Context mContext; + private SimStatusPreferenceControllerV2 mController; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mContext = spy(RuntimeEnvironment.application); + doReturn(mUserManager).when(mContext).getSystemService(UserManager.class); + mController = new SimStatusPreferenceControllerV2(mContext, mFragment); + ReflectionHelpers.setField(mController, "mTelephonyManager", mTelephonyManager); + when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference); + when(mPreference.getKey()).thenReturn(mController.getPreferenceKey()); + } + + @Test + public void getPreferenceTitle_noMultiSim_shouldReturnSingleSimString() { + ReflectionHelpers.setField(mController, "mIsMultiSim", false); + + assertThat(mController.getPreferenceTitle()).isEqualTo(mContext.getResources().getString( + R.string.sim_status_title)); + } + + @Test + public void getPreferenceTitle_multiSim_shouldReturnMultiSimString() { + ReflectionHelpers.setField(mController, "mIsMultiSim", true); + + assertThat(mController.getPreferenceTitle()).isEqualTo(mContext.getResources().getString( + R.string.sim_status_title_sim_slot_1)); + } +}