From e530d93382db30d0e8249936dfb8f20b91ebc0b0 Mon Sep 17 00:00:00 2001 From: Bonian Chen Date: Thu, 17 Jun 2021 11:18:14 +0800 Subject: [PATCH] [Settings] fix for Wifi calling settings page crash UI crash reported due to accessing telephony framework API with invalid subscription ID from SIM. Which comes with multiple reason. Besides of avoidance of crash, following updates are also required: 1. Close wifi calling settings UI when pSIM or eSIM not available or inserted. 2. Keep the selection of tab (under multi-SIM) when screen rotate 3. Only show 1 SIM when multi-SIM are grouped together Bug: 149190278 Test: local Change-Id: Ied9a088b6ee5da66972f27649cc07f4a31304f17 (cherry picked from commit fbe1293a54a84e0e835dc418a131b4c30799a2ae) (cherry picked from commit 05f29efe341af57904f0f12fc13ad488555fbf53) --- .../telephony/MobileNetworkActivity.java | 10 + .../wifi/calling/WifiCallingSettings.java | 171 +++++++++++++++--- 2 files changed, 155 insertions(+), 26 deletions(-) diff --git a/src/com/android/settings/network/telephony/MobileNetworkActivity.java b/src/com/android/settings/network/telephony/MobileNetworkActivity.java index 20b37c14834..f2be37fa985 100644 --- a/src/com/android/settings/network/telephony/MobileNetworkActivity.java +++ b/src/com/android/settings/network/telephony/MobileNetworkActivity.java @@ -36,6 +36,7 @@ import androidx.annotation.VisibleForTesting; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentTransaction; +import androidx.lifecycle.Lifecycle; import com.android.internal.util.CollectionUtils; import com.android.settings.R; @@ -68,6 +69,7 @@ public class MobileNetworkActivity extends SettingsBaseActivity // Set initial value to true allows subscription information fragment to be re-created when // Activity re-create occur. private boolean mFragmentForceReload = true; + private boolean mPendingSubscriptionChange = false; @Override protected void onNewIntent(Intent intent) { @@ -155,6 +157,10 @@ public class MobileNetworkActivity extends SettingsBaseActivity * Implementation of ProxySubscriptionManager.OnActiveSubscriptionChangedListener */ public void onChanged() { + if (!getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.STARTED)) { + mPendingSubscriptionChange = true; + return; + } SubscriptionInfo info = getSubscription(); int oldSubIndex = mCurSubscriptionId; updateSubscriptions(info, null); @@ -180,6 +186,10 @@ public class MobileNetworkActivity extends SettingsBaseActivity super.onStart(); // updateSubscriptions doesn't need to be called, onChanged will always be called after we // register a listener. + if (mPendingSubscriptionChange) { + mPendingSubscriptionChange = false; + onChanged(); + } } @Override diff --git a/src/com/android/settings/wifi/calling/WifiCallingSettings.java b/src/com/android/settings/wifi/calling/WifiCallingSettings.java index 86e7e8da670..25508f73caf 100644 --- a/src/com/android/settings/wifi/calling/WifiCallingSettings.java +++ b/src/com/android/settings/wifi/calling/WifiCallingSettings.java @@ -17,6 +17,7 @@ package com.android.settings.wifi.calling; import android.app.settings.SettingsEnums; +import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.provider.Settings; @@ -29,12 +30,14 @@ import android.view.ViewGroup; import androidx.annotation.VisibleForTesting; import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentActivity; import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentPagerAdapter; import com.android.internal.util.CollectionUtils; import com.android.settings.R; import com.android.settings.core.InstrumentedFragment; +import com.android.settings.network.ActiveSubscriptionsListener; import com.android.settings.network.SubscriptionUtil; import com.android.settings.network.ims.WifiCallingQueryImsState; import com.android.settings.search.actionbar.SearchMenuController; @@ -42,6 +45,9 @@ import com.android.settings.support.actionbar.HelpResourceProvider; import com.android.settings.widget.RtlCompatibleViewPager; import com.android.settings.widget.SlidingTabLayout; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; import java.util.List; /** @@ -50,7 +56,10 @@ import java.util.List; */ public class WifiCallingSettings extends InstrumentedFragment implements HelpResourceProvider { private static final String TAG = "WifiCallingSettings"; + private int mConstructionSubId; private List mSil; + private ActiveSubscriptionsListener mSubscriptionChangeListener; + private static final int [] EMPTY_SUB_ID_LIST = new int[0]; //UI objects private RtlCompatibleViewPager mViewPager; @@ -95,16 +104,26 @@ public class WifiCallingSettings extends InstrumentedFragment implements HelpRes return view; } + private int getConstructionSubId(Bundle bundle) { + int subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; + + Intent intent = getActivity().getIntent(); + if (intent != null) { + subId = intent.getIntExtra(Settings.EXTRA_SUB_ID, + SubscriptionManager.INVALID_SUBSCRIPTION_ID); + } + if ((subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) && (bundle != null)) { + subId = bundle.getInt(Settings.EXTRA_SUB_ID, + SubscriptionManager.INVALID_SUBSCRIPTION_ID); + } + return subId; + } + private void maybeSetViewForSubId() { if (mSil == null) { return; } - final Intent intent = getActivity().getIntent(); - if (intent == null) { - return; - } - final int subId = intent.getIntExtra(Settings.EXTRA_SUB_ID, - SubscriptionManager.INVALID_SUBSCRIPTION_ID); + int subId = mConstructionSubId; if (SubscriptionManager.isValidSubscriptionId(subId)) { for (SubscriptionInfo subInfo : mSil) { if (subId == subInfo.getSubscriptionId()) { @@ -117,11 +136,15 @@ public class WifiCallingSettings extends InstrumentedFragment implements HelpRes @Override public void onCreate(Bundle icicle) { + mConstructionSubId = getConstructionSubId(icicle); super.onCreate(icicle); + Log.d(TAG, "SubId=" + mConstructionSubId); - // TODO: besides in onCreate, we should also update subList when SIM / Sub status - // changes. - updateSubList(); + if (mConstructionSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) { + // Only config Wfc if it's enabled by platform. + mSubscriptionChangeListener = getSubscriptionChangeListener(getContext()); + } + mSil = updateSubList(); } @Override @@ -135,6 +158,26 @@ public class WifiCallingSettings extends InstrumentedFragment implements HelpRes } updateTitleForCurrentSub(); + + if (mSubscriptionChangeListener != null) { + mSubscriptionChangeListener.start(); + } + } + + @Override + public void onStop() { + if (mSubscriptionChangeListener != null) { + mSubscriptionChangeListener.stop(); + } + + super.onStop(); + } + + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + // keep subscription ID for recreation + outState.putInt(Settings.EXTRA_SUB_ID, mConstructionSubId); } @Override @@ -160,11 +203,11 @@ public class WifiCallingSettings extends InstrumentedFragment implements HelpRes @Override public Fragment getItem(int position) { - Log.d(TAG, "Adapter getItem " + position); + int subId = mSil.get(position).getSubscriptionId(); + Log.d(TAG, "Adapter getItem " + position + " for subId=" + subId); final Bundle args = new Bundle(); args.putBoolean(SearchMenuController.NEED_SEARCH_ICON_IN_ACTION_BAR, false); - args.putInt(WifiCallingSettingsForSub.FRAGMENT_BUNDLE_SUBID, - mSil.get(position).getSubscriptionId()); + args.putInt(WifiCallingSettingsForSub.FRAGMENT_BUNDLE_SUBID, subId); final WifiCallingSettingsForSub fragment = new WifiCallingSettingsForSub(); fragment.setArguments(args); @@ -190,22 +233,27 @@ public class WifiCallingSettings extends InstrumentedFragment implements HelpRes } } - private void updateSubList() { - mSil = SubscriptionUtil.getActiveSubscriptions( - getContext().getSystemService(SubscriptionManager.class)); + @VisibleForTesting + protected List getSelectableSubscriptions(Context context) { + return SubscriptionUtil.getSelectableSubscriptionInfoList(context); + } - // Only config Wfc if it's enabled by platform. - if (mSil == null) { - return; + private List updateSubList() { + List subInfoList = getSelectableSubscriptions(getContext()); + + if (subInfoList == null) { + return Collections.emptyList(); } - for (int i = 0; i < mSil.size(); ) { - final SubscriptionInfo info = mSil.get(i); - if (!queryImsState(info.getSubscriptionId()).isWifiCallingProvisioned()) { - mSil.remove(i); - } else { - i++; - } + List selectedList = new ArrayList(); + for (SubscriptionInfo subInfo : subInfoList) { + int subId = subInfo.getSubscriptionId(); + try { + if (queryImsState(subId).isWifiCallingProvisioned()) { + selectedList.add(subInfo); + } + } catch (Exception exception) {} } + return selectedList; } private void updateTitleForCurrentSub() { @@ -218,7 +266,78 @@ public class WifiCallingSettings extends InstrumentedFragment implements HelpRes } @VisibleForTesting - WifiCallingQueryImsState queryImsState(int subId) { + protected WifiCallingQueryImsState queryImsState(int subId) { return new WifiCallingQueryImsState(getContext(), subId); } + + @VisibleForTesting + protected ActiveSubscriptionsListener getSubscriptionChangeListener(Context context) { + return new ActiveSubscriptionsListener(context.getMainLooper(), context) { + public void onChanged() { + onSubscriptionChange(context); + } + }; + } + + protected void onSubscriptionChange(Context context) { + if (mSubscriptionChangeListener == null) { + return; + } + int [] previousSubIdList = subscriptionIdList(mSil); + List updateList = updateSubList(); + int [] currentSubIdList = subscriptionIdList(updateList); + + if (currentSubIdList.length > 0) { + // only keep fragment when any provisioned subscription is available + if (previousSubIdList.length == 0) { + // initial loading of list + mSil = updateList; + return; + } + if (previousSubIdList.length == currentSubIdList.length) { + // same number of subscriptions + if ( (!containsSubId(previousSubIdList, mConstructionSubId)) + // original request not yet appears in list + || containsSubId(currentSubIdList, mConstructionSubId) ) + // original request appears in list + { + mSil = updateList; + return; + } + } + } + Log.d(TAG, "Closed subId=" + mConstructionSubId + + " due to subscription change: " + Arrays.toString(previousSubIdList) + + " -> " + Arrays.toString(currentSubIdList)); + + // close this fragment when no provisioned subscriptions available + if (mSubscriptionChangeListener != null) { + mSubscriptionChangeListener.stop(); + mSubscriptionChangeListener = null; + } + + // close this fragment + finish(); + } + + protected void finish() { + FragmentActivity activity = getActivity(); + if (activity == null) return; + if (getFragmentManager().getBackStackEntryCount() > 0) { + getFragmentManager().popBackStack(); + } else { + activity.finish(); + } + } + + protected int [] subscriptionIdList(List subInfoList) { + return (subInfoList == null) ? EMPTY_SUB_ID_LIST : + subInfoList.stream().mapToInt(subInfo -> (subInfo == null) ? + SubscriptionManager.INVALID_SUBSCRIPTION_ID : subInfo.getSubscriptionId()) + .toArray(); + } + + protected boolean containsSubId(int [] subIdArray, int subIdLookUp) { + return Arrays.stream(subIdArray).anyMatch(subId -> (subId == subIdLookUp)); + } }