In MobileNetworkSettings handle no sims in first or only slot.

MobileNetworkSettings is the code for Settings -> More -> Cellular networks
this change allows it to handle no sims in first or only slot and also
hot swapping.

Also add some additional debug logging.

Bug: 18814002
Change-Id: I58e0cde4206bb737e25a018e101eaff00602c803
diff --git a/src/com/android/phone/MobileNetworkSettings.java b/src/com/android/phone/MobileNetworkSettings.java
index 48865ff..e6b066b 100644
--- a/src/com/android/phone/MobileNetworkSettings.java
+++ b/src/com/android/phone/MobileNetworkSettings.java
@@ -25,6 +25,7 @@
 import com.android.internal.telephony.TelephonyProperties;
 
 import java.util.ArrayList;
+import java.util.Iterator;
 import java.util.List;
 
 import android.app.ActionBar;
@@ -50,7 +51,6 @@
 import android.preference.PreferenceGroup;
 import android.preference.PreferenceScreen;
 import android.preference.SwitchPreference;
-import android.telecom.TelecomManager;
 import android.telephony.PhoneStateListener;
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
@@ -86,6 +86,9 @@
     private static final boolean DBG = true;
     public static final int REQUEST_CODE_EXIT_ECM = 17;
 
+    // Number of active Subscriptions to show tabs
+    private static final int TAB_THRESHOLD = 2;
+
     //String keys for preference lookup
     private static final String BUTTON_PREFERED_NETWORK_MODE = "preferred_network_mode_key";
     private static final String BUTTON_ROAMING_KEY = "button_roaming_key";
@@ -115,7 +118,7 @@
     private Preference mLteDataServicePref;
 
     private static final String iface = "rmnet0"; //TODO: this will go away
-    private List<SubscriptionInfo> mSelectableSubInfos = new ArrayList<SubscriptionInfo>();
+    private List<SubscriptionInfo> mActiveSubInfos;
 
     private UserManager mUm;
     private Phone mPhone;
@@ -123,8 +126,6 @@
     private boolean mOkClicked;
 
     private TabHost mTabHost;
-    private TabWidget mTabWidget;
-    private ListView mListView;
 
     //GsmUmts options and Cdma options
     GsmUmtsOptions mGsmUmtsOptions;
@@ -158,6 +159,7 @@
     private class PhoneChangeReceiver extends BroadcastReceiver {
         @Override
         public void onReceive(Context context, Intent intent) {
+            if (DBG) log("onReceive:");
             // When the radio changes (ex: CDMA->GSM), refresh all options.
             mGsmUmtsOptions = null;
             mCdmaOptions = null;
@@ -256,19 +258,148 @@
         }
     }
 
+    private final SubscriptionManager.OnSubscriptionsChangedListener mOnSubscriptionsChangeListener
+            = new SubscriptionManager.OnSubscriptionsChangedListener() {
+        @Override
+        public void onSubscriptionsChanged() {
+            if (DBG) log("onSubscriptionsChanged:");
+            initializeSubscriptions();
+        }
+    };
+
+    private void initializeSubscriptions() {
+        int currentTab = 0;
+        if (DBG) log("initializeSubscriptions:+");
+
+        // Before updating the the active subscription list check
+        // if tab updating is needed as the list is changing.
+        List<SubscriptionInfo> sil = mSubscriptionManager.getActiveSubscriptionInfoList();
+        TabState state = isUpdateTabsNeeded(sil);
+
+        // Update to the active subscription list
+        mActiveSubInfos.clear();
+        if (sil != null) {
+            mActiveSubInfos.addAll(sil);
+        }
+
+
+        switch (state) {
+            case UPDATE: {
+                if (DBG) log("initializeSubscriptions: UPDATE");
+                currentTab = mTabHost != null ? mTabHost.getCurrentTab() : 0;
+
+                setContentView(R.layout.network_settings);
+
+                mTabHost = (TabHost) findViewById(android.R.id.tabhost);
+                mTabHost.setup();
+
+                // Update the tabName. Since the mActiveSubInfos are in slot order
+                // we can iterate though the tabs and subscription info in one loop. But
+                // we need to handle the case where a slot may be empty.
+
+                Iterator<SubscriptionInfo> siIterator = mActiveSubInfos.listIterator();
+                SubscriptionInfo si = siIterator.hasNext() ? siIterator.next() : null;
+                for (int simSlotIndex = 0; simSlotIndex  < mActiveSubInfos.size(); simSlotIndex++) {
+                    String tabName;
+                    if (si != null && si.getSimSlotIndex() == simSlotIndex) {
+                        // Slot is not empty and we match
+                        tabName = String.valueOf(si.getDisplayName());
+                        si = siIterator.hasNext() ? siIterator.next() : null;
+                    } else {
+                        // Slot is empty, set name to unknown
+                        tabName = getResources().getString(R.string.unknown);
+                    }
+                    if (DBG) {
+                        log("initializeSubscriptions: tab=" + simSlotIndex + " name=" + tabName);
+                    }
+
+                    mTabHost.addTab(buildTabSpec(String.valueOf(simSlotIndex), tabName));
+                }
+
+                mTabHost.setOnTabChangedListener(mTabListener);
+                mTabHost.setCurrentTab(currentTab);
+                break;
+            }
+            case NO_TABS: {
+                if (DBG) log("initializeSubscriptions: NO_TABS");
+                currentTab = 0;
+
+                if (mTabHost != null) {
+                    mTabHost.clearAllTabs();
+                    mTabHost = null;
+                }
+                setContentView(R.layout.network_settings);
+                break;
+            }
+            case DO_NOTHING: {
+                if (DBG) log("initializeSubscriptions: DO_NOTHING");
+                currentTab = 0;
+                break;
+            }
+        }
+        updatePhone(currentTab);
+        updateBody();
+        if (DBG) log("initializeSubscriptions:-");
+    }
+
+    private enum TabState {
+        NO_TABS, UPDATE, DO_NOTHING
+    }
+    private TabState isUpdateTabsNeeded(List<SubscriptionInfo> newSil) {
+        TabState state = TabState.DO_NOTHING;
+        if (newSil == null) {
+            if (mActiveSubInfos.size() >= TAB_THRESHOLD) {
+                if (DBG) log("isUpdateTabsNeeded: NO_TABS, size unknown and was tabbed");
+                state = TabState.NO_TABS;
+            }
+        } else if (newSil.size() < TAB_THRESHOLD && mActiveSubInfos.size() >= TAB_THRESHOLD) {
+            if (DBG) log("isUpdateTabsNeeded: NO_TABS, size went to small");
+            state = TabState.NO_TABS;
+        } else if (newSil.size() >= TAB_THRESHOLD && mActiveSubInfos.size() < TAB_THRESHOLD) {
+            if (DBG) log("isUpdateTabsNeeded: UPDATE, size changed");
+            state = TabState.UPDATE;
+        } else if (newSil.size() >= TAB_THRESHOLD) {
+            Iterator<SubscriptionInfo> siIterator = mActiveSubInfos.iterator();
+            for(SubscriptionInfo newSi : newSil) {
+                SubscriptionInfo curSi = siIterator.next();
+                if (!newSi.getDisplayName().equals(curSi.getDisplayName())) {
+                    if (DBG) log("isUpdateTabsNeeded: UPDATE, new name=" + newSi.getDisplayName());
+                    state = TabState.UPDATE;
+                    break;
+                }
+            }
+        }
+        if (DBG) {
+            log("isUpdateTabsNeeded:- " + state
+                + " newSil.size()=" + ((newSil != null) ? newSil.size() : 0)
+                + " mActiveSubInfos.size()=" + mActiveSubInfos.size());
+        }
+        return state;
+    }
+
     private OnTabChangeListener mTabListener = new OnTabChangeListener() {
         @Override
         public void onTabChanged(String tabId) {
-            final int slotId = Integer.parseInt(tabId);
-            final SubscriptionInfo sir = findRecordBySlotId(slotId);
-            mPhone = PhoneFactory.getPhone(SubscriptionManager.getPhoneId(sir.getSubscriptionId()));
-            if (DBG) log("onTabChanged: slotId=" + slotId + " sir=" + sir);
-
+            if (DBG) log("onTabChanged:");
             // The User has changed tab; update the body.
+            updatePhone(Integer.parseInt(tabId));
             updateBody();
         }
     };
 
+    private void updatePhone(int slotId) {
+        final SubscriptionInfo sir = findRecordBySlotId(slotId);
+        if (sir != null) {
+            mPhone = PhoneFactory.getPhone(
+                    SubscriptionManager.getPhoneId(sir.getSubscriptionId()));
+        }
+        if (mPhone == null) {
+            // Do the best we can
+            mPhone = PhoneGlobals.getPhone();
+        }
+        if (DBG) log("updatePhone:- slotId=" + slotId + " sir=" + sir);
+    }
+
     private TabContentFactory mEmptyTabContent = new TabContentFactory() {
         @Override
         public View createTabContent(String tag) {
@@ -283,27 +414,14 @@
 
     @Override
     protected void onCreate(Bundle icicle) {
+        if (DBG) log("onCreate:+");
         setTheme(R.style.Theme_Material_Settings);
         super.onCreate(icicle);
-        final Context context = getApplicationContext();
 
         mHandler = new MyHandler();
         mUm = (UserManager) getSystemService(Context.USER_SERVICE);
-        final TelephonyManager tm =
-                (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
         mSubscriptionManager = SubscriptionManager.from(this);
 
-        // Initialize Phone to the phone associated with slotId 0
-        final SubscriptionInfo si = findRecordBySlotId(0);
-        mPhone = PhoneFactory.getPhone(SubscriptionManager.getPhoneId(si.getSubscriptionId()));
-
-        for (int i = 0; i < tm.getSimCount(); i++) {
-            SubscriptionInfo sir = findRecordBySlotId(i);
-            if (sir != null) {
-                mSelectableSubInfos.add(sir);
-            }
-        }
-
         if (mUm.hasUserRestriction(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS)) {
             mUnavailable = true;
             setContentView(R.layout.telephony_disallowed_preference_screen);
@@ -338,35 +456,25 @@
 
         mLteDataServicePref = prefSet.findPreference(BUTTON_CDMA_LTE_DATA_SERVICE_KEY);
 
-        if (mSelectableSubInfos.size() > 1) {
-            setContentView(R.layout.network_settings);
+        // Initialize mActiveSubInfo
+        int max = mSubscriptionManager.getActiveSubscriptionInfoCountMax();
+        mActiveSubInfos = new ArrayList<SubscriptionInfo>(max);
 
-            mTabHost = (TabHost) findViewById(android.R.id.tabhost);
-            mTabWidget = (TabWidget) findViewById(android.R.id.tabs);
-            mListView = (ListView) findViewById(android.R.id.list);
-
-            mTabHost.setup();
-            mTabHost.setOnTabChangedListener(mTabListener);
-            mTabHost.clearAllTabs();
-
-            for (int i = 0; i < mSelectableSubInfos.size(); i++) {
-                mTabHost.addTab(buildTabSpec(String.valueOf(i),
-                        String.valueOf(mSelectableSubInfos.get(i).getDisplayName())));
-            }
-        }
-
-        updateBody();
+        initializeSubscriptions();
 
         IntentFilter intentFilter = new IntentFilter(
                 TelephonyIntents.ACTION_RADIO_TECHNOLOGY_CHANGED);
         registerReceiver(mPhoneChangeReceiver, intentFilter);
+        if (DBG) log("onCreate:-");
     }
 
     @Override
     protected void onResume() {
         super.onResume();
+        if (DBG) log("onResume:+");
 
         if (mUnavailable) {
+            if (DBG) log("onResume:- ignore mUnavailable == false");
             return;
         }
 
@@ -397,6 +505,11 @@
         mButton4glte.setChecked(ImsManager.isEnhanced4gLteModeSettingEnabledByUser(this)
                 && ImsManager.isNonTtyOrTtyOnVolteEnabled(this));
         // NOTE: The button will be enabled/disabled in mPhoneStateListener
+
+        mSubscriptionManager.registerOnSubscriptionsChangedListener(mOnSubscriptionsChangeListener);
+
+        if (DBG) log("onResume:-");
+
     }
 
     private void updateBody() {
@@ -568,22 +681,65 @@
             }
         }
 
-        //Get the networkMode from Settings.System and displays it
+        // Get the networkMode from Settings.System and displays it
         mButtonDataRoam.setChecked(mPhone.getDataRoamingEnabled());
         mButtonEnabledNetworks.setValue(Integer.toString(settingsNetworkMode));
         mButtonPreferredNetworkMode.setValue(Integer.toString(settingsNetworkMode));
         UpdatePreferredNetworkModeSummary(settingsNetworkMode);
         UpdateEnabledNetworksValueAndSummary(settingsNetworkMode);
+
+        /**
+         * Enable/disable depending upon if there are any active subscriptions.
+         *
+         * I've decided to put this enable/disable code at the bottom as the
+         * code above works even when there are no active subscriptions, thus
+         * putting it afterwards is a smaller change. This can be refined later,
+         * but you do need to remember that this all needs to work when subscriptions
+         * change dynamically such as when hot swapping sims.
+         */
+        boolean hasActiveSubscriptions = mActiveSubInfos.size() > 0;
+        mButtonDataRoam.setEnabled(hasActiveSubscriptions);
+        mButtonPreferredNetworkMode.setEnabled(hasActiveSubscriptions);
+        mButtonEnabledNetworks.setEnabled(hasActiveSubscriptions);
+        mButton4glte.setEnabled(hasActiveSubscriptions);
+        mLteDataServicePref.setEnabled(hasActiveSubscriptions);
+        Preference ps;
+        PreferenceScreen root = getPreferenceScreen();
+        ps = findPreference(BUTTON_CELL_BROADCAST_SETTINGS);
+        if (ps != null) {
+            ps.setEnabled(hasActiveSubscriptions);
+        }
+        ps = findPreference(BUTTON_APN_EXPAND_KEY);
+        if (ps != null) {
+            ps.setEnabled(hasActiveSubscriptions);
+        }
+        ps = findPreference(BUTTON_OPERATOR_SELECTION_EXPAND_KEY);
+        if (ps != null) {
+            ps.setEnabled(hasActiveSubscriptions);
+        }
+        ps = findPreference(BUTTON_CARRIER_SETTINGS_KEY);
+        if (ps != null) {
+            ps.setEnabled(hasActiveSubscriptions);
+        }
+        ps = findPreference(BUTTON_CDMA_SYSTEM_SELECT_KEY);
+        if (ps != null) {
+            ps.setEnabled(hasActiveSubscriptions);
+        }
     }
 
     @Override
     protected void onPause() {
         super.onPause();
+        if (DBG) log("onPause:+");
 
         if (ImsManager.isVolteEnabledByPlatform(this)) {
             TelephonyManager tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
             tm.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE);
         }
+
+        mSubscriptionManager
+            .unregisterOnSubscriptionsChangedListener(mOnSubscriptionsChangeListener);
+        if (DBG) log("onPause:-");
     }
 
     /**
@@ -1056,7 +1212,7 @@
         }
 
         if (DBG) {
-            log("World mode is set to" + worldModeOn);
+            log("isWorldMode=" + worldModeOn);
         }
 
         return worldModeOn;
@@ -1109,13 +1265,11 @@
      * Since the number of SIMs are few, an array is fine.
      */
     public SubscriptionInfo findRecordBySlotId(final int slotId) {
-        final List<SubscriptionInfo> subInfoList =
-            mSubscriptionManager.getActiveSubscriptionInfoList();
-        if (subInfoList != null) {
-            final int subInfoLength = subInfoList.size();
+        if (mActiveSubInfos != null) {
+            final int subInfoLength = mActiveSubInfos.size();
 
             for (int i = 0; i < subInfoLength; ++i) {
-                final SubscriptionInfo sir = subInfoList.get(i);
+                final SubscriptionInfo sir = mActiveSubInfos.get(i);
                 if (sir.getSimSlotIndex() == slotId) {
                     //Right now we take the first subscription on a SIM.
                     return sir;