OSDN Git Service

Popup a dialog to display sim status information
authorjeffreyhuang <jeffreyhuang@google.com>
Fri, 27 Oct 2017 21:41:56 +0000 (14:41 -0700)
committerjeffreyhuang <jeffreyhuang@google.com>
Thu, 2 Nov 2017 17:55:18 +0000 (10:55 -0700)
 - Create layout files for the dialog
 - Create a new controller to launch the dialog activity
 - Create a new controller to update the contents of the dialog
 - Deprecate old files that are no longer used in about phone v2

Bug: 36458278
Test: make RunSettingsRoboTests -j40
Change-Id: Iaf4f5e53c83b27f148acb076f38bfeabff41087e

16 files changed:
res/layout/dialog_sim_status.xml [new file with mode: 0644]
res/values/strings.xml
res/values/styles.xml
res/xml/device_info_settings_v2.xml
src/com/android/settings/DeviceInfoSettings.java
src/com/android/settings/deviceinfo/SimStatus.java
src/com/android/settings/deviceinfo/SimStatusPreferenceController.java
src/com/android/settings/deviceinfo/simstatus/AbstractSimStatusPreferenceController.java [new file with mode: 0644]
src/com/android/settings/deviceinfo/simstatus/SimStatusDialogController.java [new file with mode: 0644]
src/com/android/settings/deviceinfo/simstatus/SimStatusDialogFragment.java [new file with mode: 0644]
src/com/android/settings/deviceinfo/simstatus/SimStatusDualSimPreferenceController.java [new file with mode: 0644]
src/com/android/settings/deviceinfo/simstatus/SimStatusPreferenceControllerV2.java [new file with mode: 0644]
tests/robotests/src/com/android/settings/deviceinfo/simstatus/AbstractSimStatusPreferenceControllerTest.java [new file with mode: 0644]
tests/robotests/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogControllerTest.java [new file with mode: 0644]
tests/robotests/src/com/android/settings/deviceinfo/simstatus/SimStatusDualSimPreferenceControllerTest.java [new file with mode: 0644]
tests/robotests/src/com/android/settings/deviceinfo/simstatus/SimStatusPreferenceControllerV2Test.java [new file with mode: 0644]

diff --git a/res/layout/dialog_sim_status.xml b/res/layout/dialog_sim_status.xml
new file mode 100644 (file)
index 0000000..068a889
--- /dev/null
@@ -0,0 +1,132 @@
+<?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.
+  -->
+
+<ScrollView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content">
+    <LinearLayout
+        android:orientation="vertical"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:padding="@dimen/sim_content_padding">
+
+        <TextView
+            style="@style/device_info_dialog_label"
+            android:id="@+id/operator_name_label"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="@string/status_operator"/>
+        <TextView
+            style="@style/device_info_dialog_value"
+            android:id="@+id/operator_name_value"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="@string/device_info_not_available"/>
+
+        <TextView
+            style="@style/device_info_dialog_label"
+            android:id="@+id/number_label"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="@string/status_number_sim_status"/>
+        <TextView
+            style="@style/device_info_dialog_value"
+            android:id="@+id/number_value"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="@string/device_info_not_available"/>
+
+        <TextView
+            style="@style/device_info_dialog_label"
+            android:id="@+id/data_state_label"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="@string/status_data_state"/>
+        <TextView
+            style="@style/device_info_dialog_value"
+            android:id="@+id/data_state_value"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="@string/device_info_not_available"/>
+
+        <TextView
+            style="@style/device_info_dialog_label"
+            android:id="@+id/latest_area_info_label"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="@string/status_latest_area_info"/>
+        <TextView
+            style="@style/device_info_dialog_value"
+            android:id="@+id/latest_area_info_value"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="@string/device_info_not_available"/>
+
+        <TextView
+            style="@style/device_info_dialog_label"
+            android:id="@+id/service_state_label"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="@string/status_service_state"/>
+        <TextView
+            style="@style/device_info_dialog_value"
+            android:id="@+id/service_state_value"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="@string/device_info_not_available"/>
+
+        <TextView
+            style="@style/device_info_dialog_label"
+            android:id="@+id/signal_strength_label"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="@string/status_signal_strength"/>
+        <TextView
+            style="@style/device_info_dialog_value"
+            android:id="@+id/signal_strength_value"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="@string/device_info_not_available"/>
+
+        <TextView
+            style="@style/device_info_dialog_label"
+            android:id="@+id/network_type_label"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="@string/status_network_type"/>
+        <TextView
+            style="@style/device_info_dialog_value"
+            android:id="@+id/network_type_value"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="@string/device_info_not_available"/>
+
+        <TextView
+            style="@style/device_info_dialog_label"
+            android:id="@+id/roaming_state_label"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="@string/status_roaming"/>
+        <TextView
+            style="@style/device_info_dialog_value"
+            android:id="@+id/roaming_state_value"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="@string/device_info_not_available"/>
+    </LinearLayout>
+</ScrollView>
index f0721fc..87abec5 100644 (file)
     <string name="status_number" product="tablet">MDN</string>
     <!-- About phone, status item title.  The phone number of the current device [CHAR LIMIT=30] -->
     <string name="status_number" product="default">Phone number</string>
+    <!-- About tablet, status item title.  The Mobile Directory Number [CHAR LIMIT=30] -->
+    <string name="status_number_sim_status" product="tablet">MDN on SIM</string>
+    <!-- About phone, status item title.  The phone number of the current device [CHAR LIMIT=30] -->
+    <string name="status_number_sim_status" product="default">Phone number on SIM</string>
     <!-- About phone, status item title.  The phone MIN number of the current device.-->
     <string name="status_min_number">MIN</string>
     <!-- About phone, status item title.  The phone MSID number of the current device.-->
     <string name="sim_no_inserted_msg">No SIM cards inserted</string>
     <!-- SIM status title  [CHAR LIMIT=40] -->
     <string name="sim_status_title">SIM status</string>
+    <!-- SIM status title  [CHAR LIMIT=40] -->
+    <string name="sim_status_title_sim_slot_1">SIM status (sim slot 1)</string>
+    <!-- SIM status title  [CHAR LIMIT=40] -->
+    <string name="sim_status_title_sim_slot_2">SIM status (sim slot 2)</string>
     <!-- Title for call back. [CHAR LIMIT=60] -->
     <string name="sim_call_back_title">Call back from default SIM</string>
     <!-- Title for outgoing back. [CHAR LIMIT=60] -->
index c9ef22c..8815bb3 100644 (file)
         <item name="android:textSize">@dimen/search_bar_text_size</item>
     </style>
 
+    <style name="device_info_dialog_label">
+        <item name="android:textAppearance">@android:style/TextAppearance.Material.Body1</item>
+        <item name="android:textColor">?android:attr/textColorSecondary</item>
+    </style>
+
+    <style name="device_info_dialog_value">
+        <item name="android:textAppearance">@android:style/TextAppearance.Material.Body2</item>
+        <item name="android:paddingBottom">24dp</item>
+    </style>
+
 </resources>
index 0553f1e..037db63 100644 (file)
         android:title="@string/status_number"
         android:summary="@string/summary_placeholder"/>
 
-    <!-- SIM status -->
+    <!-- SIM status Sim Slot 1 -->
     <Preference
-        android:key="sim_status"
+        android:key="sim_status_sim_1"
         android:title="@string/sim_status_title"
         android:summary="@string/summary_placeholder"/>
 
+    <!-- SIM status Sim Slot 2-->
+    <Preference
+        android:key="sim_status_sim_2"
+        android:title="@string/sim_status_title_sim_slot_2"
+        android:summary="@string/summary_placeholder"/>
+
+
     <!-- Model & hardware -->
     <Preference
         android:key="device_model"
index 4479eaa..1f20034 100644 (file)
@@ -37,6 +37,8 @@ import com.android.settings.deviceinfo.ManualPreferenceController;
 import com.android.settings.deviceinfo.RegulatoryInfoPreferenceController;
 import com.android.settings.deviceinfo.SafetyInfoPreferenceController;
 import com.android.settings.deviceinfo.SecurityPatchPreferenceController;
+import com.android.settings.deviceinfo.simstatus.SimStatusDualSimPreferenceController;
+import com.android.settings.deviceinfo.simstatus.SimStatusPreferenceControllerV2;
 import com.android.settings.search.BaseSearchIndexProvider;
 import com.android.settings.search.Indexable;
 import com.android.settingslib.core.AbstractPreferenceController;
@@ -125,7 +127,9 @@ public class DeviceInfoSettings extends DashboardFragment implements Indexable {
 
             // Phone number
 
-            // SIM status
+            controllers.add(new SimStatusPreferenceControllerV2(context, fragment));
+
+            controllers.add(new SimStatusDualSimPreferenceController(context, fragment));
 
             controllers.add(new DeviceModelPreferenceController(context, fragment));
 
index c3d3547..768beb8 100644 (file)
@@ -73,7 +73,9 @@ import java.util.List;
  * # Operator info (area update info cell broadcast)
  * # Signal Strength
  *
+ * deprecated in favor of {@link com.android.settings.deviceinfo.simstatus.SimStatusDialogFragment}
  */
+@Deprecated
 public class SimStatus extends SettingsPreferenceFragment {
     private static final String TAG = "SimStatus";
 
index 99441b5..ca531ea 100644 (file)
@@ -19,8 +19,13 @@ package com.android.settings.deviceinfo;
 import android.content.Context;
 
 import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settings.deviceinfo.simstatus.SimStatusPreferenceControllerV2;
 import com.android.settingslib.deviceinfo.AbstractSimStatusImeiInfoPreferenceController;
 
+/**
+ * deprecated in favor of {@link SimStatusPreferenceControllerV2}
+ */
+@Deprecated
 public class SimStatusPreferenceController extends AbstractSimStatusImeiInfoPreferenceController
         implements PreferenceControllerMixin {
 
diff --git a/src/com/android/settings/deviceinfo/simstatus/AbstractSimStatusPreferenceController.java b/src/com/android/settings/deviceinfo/simstatus/AbstractSimStatusPreferenceController.java
new file mode 100644 (file)
index 0000000..6107bf5
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * 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 android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceScreen;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+import android.text.TextUtils;
+
+import com.android.settings.R;
+import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settingslib.deviceinfo.AbstractSimStatusImeiInfoPreferenceController;
+
+import java.util.List;
+
+public abstract class AbstractSimStatusPreferenceController extends
+        AbstractSimStatusImeiInfoPreferenceController implements PreferenceControllerMixin {
+
+    protected final boolean mIsMultiSim;
+    protected final TelephonyManager mTelephonyManager;
+    private final SubscriptionManager mSubscriptionManager;
+    private final Fragment mFragment;
+
+    private Preference mPreference;
+
+    public AbstractSimStatusPreferenceController(Context context, Fragment fragment) {
+        super(context);
+
+        mTelephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
+        mSubscriptionManager = (SubscriptionManager) context.getSystemService(
+                Context.TELEPHONY_SUBSCRIPTION_SERVICE);
+        mFragment = fragment;
+        mIsMultiSim = mTelephonyManager.getPhoneCount() > 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<SubscriptionInfo> 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 (file)
index 0000000..a6cc28f
--- /dev/null
@@ -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<SubscriptionInfo> 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 (file)
index 0000000..a15cb81
--- /dev/null
@@ -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 (file)
index 0000000..ce73a29
--- /dev/null
@@ -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 (file)
index 0000000..ee16eac
--- /dev/null
@@ -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 (file)
index 0000000..ee749d0
--- /dev/null
@@ -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 (file)
index 0000000..73db81d
--- /dev/null
@@ -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 (file)
index 0000000..0845bfa
--- /dev/null
@@ -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 (file)
index 0000000..3282c3c
--- /dev/null
@@ -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));
+    }
+}