Merge "[Settings] Replace getSimCount() API"
diff --git a/src/com/android/settings/IccLockSettings.java b/src/com/android/settings/IccLockSettings.java
index 605f483..8880001 100644
--- a/src/com/android/settings/IccLockSettings.java
+++ b/src/com/android/settings/IccLockSettings.java
@@ -29,8 +29,6 @@
 import android.os.Handler;
 import android.os.Message;
 import android.telephony.SubscriptionInfo;
-import android.telephony.SubscriptionManager;
-import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 import android.util.Log;
 import android.view.Gravity;
@@ -55,6 +53,9 @@
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneFactory;
 import com.android.internal.telephony.TelephonyIntents;
+import com.android.settings.network.ProxySubscriptionManager;
+
+import java.util.List;
 
 /**
  * Implements the preference screen to enable/disable ICC lock and
@@ -112,6 +113,7 @@
     private ListView mListView;
 
     private Phone mPhone;
+    private ProxySubscriptionManager mProxySubscriptionMgr;
 
     private EditPinPreference mPinDialog;
     private SwitchPreference mPinToggle;
@@ -129,7 +131,7 @@
     // For replies from IccCard interface
     private Handler mHandler = new Handler() {
         public void handleMessage(Message msg) {
-            AsyncResult ar = (AsyncResult) msg.obj;
+            final AsyncResult ar = (AsyncResult) msg.obj;
             switch (msg.what) {
                 case MSG_ENABLE_ICC_PIN_COMPLETE:
                     iccLockChanged(ar.exception == null, msg.arg1, ar.exception);
@@ -161,8 +163,8 @@
     }
 
     static String getSummary(Context context) {
-        Resources res = context.getResources();
-        String summary = isIccLockEnabled()
+        final Resources res = context.getResources();
+        final String summary = isIccLockEnabled()
                 ? res.getString(R.string.sim_lock_on)
                 : res.getString(R.string.sim_lock_off);
         return summary;
@@ -177,6 +179,11 @@
             return;
         }
 
+        // enable ProxySubscriptionMgr with Lifecycle support for all controllers
+        // live within this fragment
+        mProxySubscriptionMgr = ProxySubscriptionManager.getInstance(getContext());
+        mProxySubscriptionMgr.setLifecycle(getLifecycle());
+
         addPreferencesFromResource(R.xml.sim_lock_settings);
 
         mPinDialog = (EditPinPreference) findPreference(PIN_DIALOG);
@@ -217,14 +224,12 @@
     public View onCreateView(LayoutInflater inflater, ViewGroup container,
             Bundle savedInstanceState) {
 
-        final TelephonyManager tm =
-                (TelephonyManager) getContext().getSystemService(Context.TELEPHONY_SERVICE);
-        final int numSims = tm.getSimCount();
+        final int numSims = mProxySubscriptionMgr.getActiveSubscriptionInfoCountMax();
         if (numSims > 1) {
-            View view = inflater.inflate(R.layout.icc_lock_tabs, container, false);
+            final View view = inflater.inflate(R.layout.icc_lock_tabs, container, false);
             final ViewGroup prefs_container = (ViewGroup) view.findViewById(R.id.prefs_container);
             Utils.prepareCustomPreferencesList(container, view, prefs_container, false);
-            View prefs = super.onCreateView(inflater, prefs_container, savedInstanceState);
+            final View prefs = super.onCreateView(inflater, prefs_container, savedInstanceState);
             prefs_container.addView(prefs);
 
             mTabHost = (TabHost) view.findViewById(android.R.id.tabhost);
@@ -235,18 +240,19 @@
             mTabHost.setOnTabChangedListener(mTabListener);
             mTabHost.clearAllTabs();
 
-            SubscriptionManager sm = SubscriptionManager.from(getContext());
+            final List<SubscriptionInfo> subInfoList =
+                    mProxySubscriptionMgr.getActiveSubscriptionsInfo();
             for (int i = 0; i < numSims; ++i) {
-                final SubscriptionInfo subInfo = sm.getActiveSubscriptionInfoForSimSlotIndex(i);
+                final SubscriptionInfo subInfo =
+                        getActiveSubscriptionInfoForSimSlotIndex(subInfoList, i);
                 mTabHost.addTab(buildTabSpec(String.valueOf(i),
                         String.valueOf(subInfo == null
                             ? getContext().getString(R.string.sim_editor_title, i + 1)
                             : subInfo.getDisplayName())));
             }
-            final SubscriptionInfo sir = sm.getActiveSubscriptionInfoForSimSlotIndex(0);
+            final SubscriptionInfo sir = getActiveSubscriptionInfoForSimSlotIndex(subInfoList, 0);
 
-            mPhone = (sir == null) ? null
-                : PhoneFactory.getPhone(SubscriptionManager.getPhoneId(sir.getSubscriptionId()));
+            mPhone = (sir == null) ? null : PhoneFactory.getPhone(sir.getSimSlotIndex());
 
             if (savedInstanceState != null && savedInstanceState.containsKey(CURRENT_TAB)) {
                 mTabHost.setCurrentTabByTag(savedInstanceState.getString(CURRENT_TAB));
@@ -456,7 +462,7 @@
     private void tryChangeIccLockState() {
         // Try to change icc lock. If it succeeds, toggle the lock state and
         // reset dialog state. Else inject error message and show dialog again.
-        Message callback = Message.obtain(mHandler, MSG_ENABLE_ICC_PIN_COMPLETE);
+        final Message callback = Message.obtain(mHandler, MSG_ENABLE_ICC_PIN_COMPLETE);
         mPhone.getIccCard().setIccLockEnabled(mToState, mPin, callback);
         // Disable the setting till the response is received.
         mPinToggle.setEnabled(false);
@@ -467,7 +473,8 @@
             mPinToggle.setChecked(mToState);
         } else {
             if (exception instanceof CommandException) {
-                CommandException.Error err = ((CommandException)(exception)).getCommandError();
+                final CommandException.Error err =
+                        ((CommandException) exception).getCommandError();
                 if (err == CommandException.Error.PASSWORD_INCORRECT) {
                     createCustomTextToast(getPinPasswordErrorMessage(attemptsRemaining));
                 } else {
@@ -490,9 +497,9 @@
         // The window type of Toast is set by NotificationManagerService.
         // It can't be overwritten by LayoutParams.type.
         // Ovarlay a custom window with LayoutParams (TYPE_STATUS_BAR_PANEL) on PUK unlock screen.
-        View v = ((LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE))
+        final View v = ((LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE))
                 .inflate(com.android.internal.R.layout.transient_notification, null);
-        TextView tv = (TextView) v.findViewById(com.android.internal.R.id.message);
+        final TextView tv = (TextView) v.findViewById(com.android.internal.R.id.message);
         tv.setText(errorMessage);
 
         final WindowManager.LayoutParams params = new WindowManager.LayoutParams();
@@ -521,7 +528,7 @@
                 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
 
-        WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
+        final WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
         wm.addView(v, params);
 
         mHandler.postDelayed(new Runnable() {
@@ -545,7 +552,7 @@
     }
 
     private void tryChangePin() {
-        Message callback = Message.obtain(mHandler, MSG_CHANGE_ICC_PIN_COMPLETE);
+        final Message callback = Message.obtain(mHandler, MSG_CHANGE_ICC_PIN_COMPLETE);
         mPhone.getIccCard().changeIccLockPassword(mOldPin,
                 mNewPin, callback);
     }
@@ -583,15 +590,27 @@
         mDialogState = OFF_MODE;
     }
 
+    private static SubscriptionInfo getActiveSubscriptionInfoForSimSlotIndex(
+            List<SubscriptionInfo> subInfoList, int slotId) {
+        if (subInfoList == null) {
+            return null;
+        }
+        for (SubscriptionInfo subInfo : subInfoList) {
+            if (subInfo.getSimSlotIndex() == slotId) {
+                return subInfo;
+            }
+        }
+        return null;
+    }
+
     private OnTabChangeListener mTabListener = new OnTabChangeListener() {
         @Override
         public void onTabChanged(String tabId) {
             final int slotId = Integer.parseInt(tabId);
-            final SubscriptionInfo sir = SubscriptionManager.from(getActivity().getBaseContext())
-                    .getActiveSubscriptionInfoForSimSlotIndex(slotId);
+            final SubscriptionInfo sir = getActiveSubscriptionInfoForSimSlotIndex(
+                    mProxySubscriptionMgr.getActiveSubscriptionsInfo(), slotId);
 
-            mPhone = (sir == null) ? null
-                : PhoneFactory.getPhone(SubscriptionManager.getPhoneId(sir.getSubscriptionId()));
+            mPhone = (sir == null) ? null : PhoneFactory.getPhone(sir.getSimSlotIndex());
 
             // The User has changed tab; update the body.
             updatePreferences();
diff --git a/src/com/android/settings/network/telephony/RoamingDialogFragment.java b/src/com/android/settings/network/telephony/RoamingDialogFragment.java
index 1298445..bf22fba 100644
--- a/src/com/android/settings/network/telephony/RoamingDialogFragment.java
+++ b/src/com/android/settings/network/telephony/RoamingDialogFragment.java
@@ -42,7 +42,7 @@
 
     public static RoamingDialogFragment newInstance(int subId) {
         final RoamingDialogFragment dialogFragment = new RoamingDialogFragment();
-        Bundle args = new Bundle();
+        final Bundle args = new Bundle();
         args.putInt(SUB_ID_KEY, subId);
         dialogFragment.setArguments(args);
 
@@ -52,17 +52,17 @@
     @Override
     public void onAttach(Context context) {
         super.onAttach(context);
-        Bundle args = getArguments();
+        final Bundle args = getArguments();
         mSubId = args.getInt(SUB_ID_KEY);
         mCarrierConfigManager = new CarrierConfigManager(context);
     }
 
     @Override
     public Dialog onCreateDialog(Bundle savedInstanceState) {
-        AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
-        int title = R.string.roaming_alert_title;
+        final AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
+        final int title = R.string.roaming_alert_title;
         int message = R.string.roaming_warning;
-        PersistableBundle carrierConfig = mCarrierConfigManager.getConfigForSubId(mSubId);
+        final PersistableBundle carrierConfig = mCarrierConfigManager.getConfigForSubId(mSubId);
         if (carrierConfig != null && carrierConfig.getBoolean(
                 CarrierConfigManager.KEY_CHECK_PRICING_WITH_CARRIER_FOR_DATA_ROAMING_BOOL)) {
             message = R.string.roaming_check_price_warning;
@@ -84,8 +84,13 @@
     public void onClick(DialogInterface dialog, int which) {
         // let the host know that the positive button has been clicked
         if (which == dialog.BUTTON_POSITIVE) {
-            TelephonyManager.from(getContext()).createForSubscriptionId(
-                    mSubId).setDataRoamingEnabled(true);
+            final TelephonyManager telephonyManager =
+                    getContext().getSystemService(TelephonyManager.class)
+                    .createForSubscriptionId(mSubId);
+            if (telephonyManager == null) {
+                return;
+            }
+            telephonyManager.setDataRoamingEnabled(true);
         }
     }
 }
diff --git a/src/com/android/settings/network/telephony/RoamingPreferenceController.java b/src/com/android/settings/network/telephony/RoamingPreferenceController.java
index dd5fd0e..08fe323 100644
--- a/src/com/android/settings/network/telephony/RoamingPreferenceController.java
+++ b/src/com/android/settings/network/telephony/RoamingPreferenceController.java
@@ -17,22 +17,20 @@
 package com.android.settings.network.telephony;
 
 import android.content.Context;
-import android.database.ContentObserver;
-import android.net.Uri;
-import android.os.Handler;
-import android.os.Looper;
 import android.os.PersistableBundle;
 import android.provider.Settings;
 import android.telephony.CarrierConfigManager;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
+import android.util.Log;
 
 import androidx.annotation.VisibleForTesting;
 import androidx.fragment.app.FragmentManager;
 import androidx.preference.Preference;
 import androidx.preference.PreferenceScreen;
 
+import com.android.settings.network.GlobalSettingsChangeListener;
 import com.android.settingslib.RestrictedSwitchPreference;
 import com.android.settingslib.core.lifecycle.LifecycleObserver;
 import com.android.settingslib.core.lifecycle.events.OnStart;
@@ -44,31 +42,59 @@
 public class RoamingPreferenceController extends TelephonyTogglePreferenceController implements
         LifecycleObserver, OnStart, OnStop {
 
+    private static final String TAG = "RoamingController";
     private static final String DIALOG_TAG = "MobileDataDialog";
 
     private RestrictedSwitchPreference mSwitchPreference;
     private TelephonyManager mTelephonyManager;
     private CarrierConfigManager mCarrierConfigManager;
-    private DataContentObserver mDataContentObserver;
-    @VisibleForTesting
-    boolean mNeedDialog;
+
+    /**
+     * There're 2 listeners both activated at the same time.
+     * For project that access DATA_ROAMING, only first listener is functional.
+     * For project that access "DATA_ROAMING + subId", first listener will be stopped when receiving
+     * any onChange from second listener.
+     */
+    private GlobalSettingsChangeListener mListener;
+    private GlobalSettingsChangeListener mListenerForSubId;
+
     @VisibleForTesting
     FragmentManager mFragmentManager;
 
     public RoamingPreferenceController(Context context, String key) {
         super(context, key);
         mCarrierConfigManager = context.getSystemService(CarrierConfigManager.class);
-        mDataContentObserver = new DataContentObserver(new Handler(Looper.getMainLooper()));
     }
 
     @Override
     public void onStart() {
-        mDataContentObserver.register(mContext, mSubId);
+        if (mListener == null) {
+            mListener = new GlobalSettingsChangeListener(mContext,
+                    Settings.Global.DATA_ROAMING) {
+                public void onChanged(String field) {
+                    updateState(mSwitchPreference);
+                }
+            };
+        }
+        stopMonitorSubIdSpecific();
+
+        if (mSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
+            return;
+        }
+
+        mListenerForSubId = new GlobalSettingsChangeListener(mContext,
+                Settings.Global.DATA_ROAMING + mSubId) {
+            public void onChanged(String field) {
+                stopMonitor();
+                updateState(mSwitchPreference);
+            }
+        };
     }
 
     @Override
     public void onStop() {
-        mDataContentObserver.unRegister(mContext);
+        stopMonitor();
+        stopMonitorSubIdSpecific();
     }
 
     @Override
@@ -87,7 +113,7 @@
     @Override
     public boolean handlePreferenceTreeClick(Preference preference) {
         if (TextUtils.equals(preference.getKey(), getPreferenceKey())) {
-            if (mNeedDialog) {
+            if (isDialogNeeded()) {
                 showDialog();
             }
             return true;
@@ -98,9 +124,7 @@
 
     @Override
     public boolean setChecked(boolean isChecked) {
-        mNeedDialog = isDialogNeeded();
-
-        if (!mNeedDialog) {
+        if (!isDialogNeeded()) {
             // Update data directly if we don't need dialog
             mTelephonyManager.setDataRoamingEnabled(isChecked);
             return true;
@@ -141,7 +165,18 @@
     public void init(FragmentManager fragmentManager, int subId) {
         mFragmentManager = fragmentManager;
         mSubId = subId;
-        mTelephonyManager = TelephonyManager.from(mContext).createForSubscriptionId(mSubId);
+        mTelephonyManager = mContext.getSystemService(TelephonyManager.class);
+        if (mSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
+            return;
+        }
+        final TelephonyManager telephonyManager = mTelephonyManager
+                .createForSubscriptionId(mSubId);
+        if (telephonyManager == null) {
+            Log.w(TAG, "fail to init in sub" + mSubId);
+            mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+            return;
+        }
+        mTelephonyManager = telephonyManager;
     }
 
     private void showDialog() {
@@ -150,32 +185,17 @@
         dialogFragment.show(mFragmentManager, DIALOG_TAG);
     }
 
-    /**
-     * Listener that listens data roaming change
-     */
-    public class DataContentObserver extends ContentObserver {
-
-        public DataContentObserver(Handler handler) {
-            super(handler);
+    private void stopMonitor() {
+        if (mListener != null) {
+            mListener.close();
+            mListener = null;
         }
+    }
 
-        @Override
-        public void onChange(boolean selfChange) {
-            super.onChange(selfChange);
-            updateState(mSwitchPreference);
-        }
-
-        public void register(Context context, int subId) {
-            Uri uri = Settings.Global.getUriFor(Settings.Global.DATA_ROAMING);
-            if (TelephonyManager.getDefault().getSimCount() != 1) {
-                uri = Settings.Global.getUriFor(Settings.Global.DATA_ROAMING + subId);
-            }
-            context.getContentResolver().registerContentObserver(uri, false, this);
-
-        }
-
-        public void unRegister(Context context) {
-            context.getContentResolver().unregisterContentObserver(this);
+    private void stopMonitorSubIdSpecific() {
+        if (mListenerForSubId != null) {
+            mListenerForSubId.close();
+            mListenerForSubId = null;
         }
     }
 }
diff --git a/tests/robotests/src/com/android/settings/network/telephony/RoamingPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/network/telephony/RoamingPreferenceControllerTest.java
index a883c51..0abd6d5 100644
--- a/tests/robotests/src/com/android/settings/network/telephony/RoamingPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/network/telephony/RoamingPreferenceControllerTest.java
@@ -80,7 +80,7 @@
         doReturn(mFragmentTransaction).when(mFragmentManager).beginTransaction();
 
         mPreference = spy(new RestrictedSwitchPreference(mContext));
-        mController = new RoamingPreferenceController(mContext, "roaming");
+        mController = spy(new RoamingPreferenceController(mContext, "roaming"));
         mController.init(mFragmentManager, SUB_ID);
         mPreference.setKey(mController.getPreferenceKey());
     }
@@ -118,7 +118,7 @@
 
     @Test
     public void handlePreferenceTreeClick_needDialog_showDialog() {
-        mController.mNeedDialog = true;
+        doReturn(true).when(mController).isDialogNeeded();
 
         mController.handlePreferenceTreeClick(mPreference);