From b373aeedfe15c5928e9449e5ccb06307f05a9299 Mon Sep 17 00:00:00 2001 From: Bonian Chen Date: Thu, 26 Dec 2019 19:02:57 +0800 Subject: [PATCH] [Settings] Replace getSimCount() API Change design of monitor change in Settings.Global.MOBILE_DATA and Settings.Global.DATA_ROAMING in order to avoid from accessing getSimCount(). Bug: 144251589 Test: make RunSettingsRoboTests -j ROBOTEST_FILTER=RoamingPreferenceControllerTest Change-Id: If50c57e7c1b27f9a0baf2bd46cc0930e0a0be2bd --- src/com/android/settings/IccLockSettings.java | 69 ++++++++----- .../telephony/RoamingDialogFragment.java | 19 ++-- .../RoamingPreferenceController.java | 98 +++++++++++-------- .../RoamingPreferenceControllerTest.java | 4 +- 4 files changed, 117 insertions(+), 73 deletions(-) diff --git a/src/com/android/settings/IccLockSettings.java b/src/com/android/settings/IccLockSettings.java index 605f483c725..8880001b121 100644 --- a/src/com/android/settings/IccLockSettings.java +++ b/src/com/android/settings/IccLockSettings.java @@ -29,8 +29,6 @@ import android.os.Bundle; 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.CommandException; 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 @@ public class IccLockSettings extends SettingsPreferenceFragment private ListView mListView; private Phone mPhone; + private ProxySubscriptionManager mProxySubscriptionMgr; private EditPinPreference mPinDialog; private SwitchPreference mPinToggle; @@ -129,7 +131,7 @@ public class IccLockSettings extends SettingsPreferenceFragment // 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 @@ public class IccLockSettings extends SettingsPreferenceFragment } 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 @@ public class IccLockSettings extends SettingsPreferenceFragment 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 class IccLockSettings extends SettingsPreferenceFragment 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 @@ public class IccLockSettings extends SettingsPreferenceFragment mTabHost.setOnTabChangedListener(mTabListener); mTabHost.clearAllTabs(); - SubscriptionManager sm = SubscriptionManager.from(getContext()); + final List 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 @@ public class IccLockSettings extends SettingsPreferenceFragment 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 @@ public class IccLockSettings extends SettingsPreferenceFragment 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 @@ public class IccLockSettings extends SettingsPreferenceFragment // 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 @@ public class IccLockSettings extends SettingsPreferenceFragment | 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 @@ public class IccLockSettings extends SettingsPreferenceFragment } 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 @@ public class IccLockSettings extends SettingsPreferenceFragment mDialogState = OFF_MODE; } + private static SubscriptionInfo getActiveSubscriptionInfoForSimSlotIndex( + List 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 1298445c874..bf22fba10f7 100644 --- a/src/com/android/settings/network/telephony/RoamingDialogFragment.java +++ b/src/com/android/settings/network/telephony/RoamingDialogFragment.java @@ -42,7 +42,7 @@ public class RoamingDialogFragment extends InstrumentedDialogFragment implements 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 @@ public class RoamingDialogFragment extends InstrumentedDialogFragment implements @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 class RoamingDialogFragment extends InstrumentedDialogFragment implements 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 dd5fd0e8fef..08fe3230ee5 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 @@ import com.android.settingslib.core.lifecycle.events.OnStop; 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 @@ public class RoamingPreferenceController extends TelephonyTogglePreferenceContro @Override public boolean handlePreferenceTreeClick(Preference preference) { if (TextUtils.equals(preference.getKey(), getPreferenceKey())) { - if (mNeedDialog) { + if (isDialogNeeded()) { showDialog(); } return true; @@ -98,9 +124,7 @@ public class RoamingPreferenceController extends TelephonyTogglePreferenceContro @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 class RoamingPreferenceController extends TelephonyTogglePreferenceContro 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 @@ public class RoamingPreferenceController extends TelephonyTogglePreferenceContro 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 a883c51075b..0abd6d563e1 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 @@ public class RoamingPreferenceControllerTest { 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 @@ public class RoamingPreferenceControllerTest { @Test public void handlePreferenceTreeClick_needDialog_showDialog() { - mController.mNeedDialog = true; + doReturn(true).when(mController).isDialogNeeded(); mController.handlePreferenceTreeClick(mPreference);