Merge "[Settings] Allow disabled SIM to be controlled in UI" into sc-dev

This commit is contained in:
TreeHugger Robot
2021-07-30 08:18:01 +00:00
committed by Android (Google) Code Review
6 changed files with 273 additions and 71 deletions

View File

@@ -23,7 +23,6 @@ import android.content.Context;
import android.content.Intent;
import android.os.UserManager;
import android.provider.Settings;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.euicc.EuiccManager;
@@ -36,8 +35,9 @@ import androidx.preference.PreferenceScreen;
import com.android.settings.R;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.network.helper.SelectableSubscriptions;
import com.android.settings.network.helper.SubscriptionAnnotation;
import com.android.settings.network.telephony.MobileNetworkActivity;
import com.android.settings.network.telephony.MobileNetworkUtils;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.widget.AddPreference;
import com.android.settingslib.Utils;
@@ -61,6 +61,8 @@ public class MobileNetworkSummaryController extends AbstractPreferenceController
private SubscriptionsChangeListener mChangeListener;
private AddPreference mPreference;
private MobileNetworkSummaryStatus mStatusCache = new MobileNetworkSummaryStatus();
/**
* This controls the summary text and click behavior of the "Mobile network" item on the
* Network & internet page. There are 3 separate cases depending on the number of mobile network
@@ -82,8 +84,8 @@ public class MobileNetworkSummaryController extends AbstractPreferenceController
mSubscriptionManager = context.getSystemService(SubscriptionManager.class);
mUserManager = context.getSystemService(UserManager.class);
if (lifecycle != null) {
mChangeListener = new SubscriptionsChangeListener(context, this);
lifecycle.addObserver(this);
mChangeListener = new SubscriptionsChangeListener(context, this);
lifecycle.addObserver(this);
}
}
@@ -106,25 +108,24 @@ public class MobileNetworkSummaryController extends AbstractPreferenceController
@Override
public CharSequence getSummary() {
final List<SubscriptionInfo> subs = SubscriptionUtil.getAvailableSubscriptions(
mContext);
mStatusCache.update(mContext, null);
List<SubscriptionAnnotation> subs = mStatusCache.getSubscriptionList();
if (subs.isEmpty()) {
if (MobileNetworkUtils.showEuiccSettings(mContext)) {
if (mStatusCache.isEuiccConfigSupport()) {
return mContext.getResources().getString(
R.string.mobile_network_summary_add_a_network);
}
return null;
// set empty string to override previous text for carrier when SIM available
return "";
} else if (subs.size() == 1) {
final SubscriptionInfo info = subs.get(0);
final CharSequence displayName = SubscriptionUtil.getUniqueSubscriptionDisplayName(
info, mContext);
final int subId = info.getSubscriptionId();
if (!info.isEmbedded() && !mSubscriptionManager.isActiveSubscriptionId(subId)
&& !SubscriptionUtil.showToggleForPhysicalSim(mSubscriptionManager)) {
return mContext.getString(R.string.mobile_network_tap_to_activate, displayName);
} else {
SubscriptionAnnotation info = subs.get(0);
CharSequence displayName = mStatusCache.getDisplayName(info.getSubscriptionId());
if (info.getSubInfo().isEmbedded() || info.isActive()
|| mStatusCache.isPhysicalSimDisableSupport()) {
return displayName;
}
return mContext.getString(R.string.mobile_network_tap_to_activate, displayName);
} else {
if (com.android.settings.Utils.isProviderModelEnabled(mContext)) {
return getSummaryForProviderModel(subs);
@@ -135,10 +136,16 @@ public class MobileNetworkSummaryController extends AbstractPreferenceController
}
}
private CharSequence getSummaryForProviderModel(List<SubscriptionInfo> subs) {
return String.join(", ", subs.stream().map(subInfo -> {
return SubscriptionUtil.getUniqueSubscriptionDisplayName(subInfo, mContext);
}).collect(Collectors.toList()));
private CharSequence getSummaryForProviderModel(List<SubscriptionAnnotation> subs) {
return subs.stream()
.mapToInt(SubscriptionAnnotation::getSubscriptionId)
.mapToObj(subId -> mStatusCache.getDisplayName(subId))
.collect(Collectors.joining(", "));
}
private void logPreferenceClick(Preference preference) {
mMetricsFeatureProvider.logClickedPreference(preference,
preference.getExtras().getInt(DashboardFragment.CATEGORY));
}
private void startAddSimFlow() {
@@ -147,62 +154,64 @@ public class MobileNetworkSummaryController extends AbstractPreferenceController
mContext.startActivity(intent);
}
private void update() {
if (mPreference == null || mPreference.isDisabledByAdmin()) {
return;
}
private void initPreference() {
refreshSummary(mPreference);
mPreference.setOnPreferenceClickListener(null);
mPreference.setOnAddClickListener(null);
mPreference.setFragment(null);
mPreference.setEnabled(!mChangeListener.isAirplaneModeOn());
}
final List<SubscriptionInfo> subs = SubscriptionUtil.getAvailableSubscriptions(
mContext);
private void update() {
if (mPreference == null || mPreference.isDisabledByAdmin()) {
return;
}
mStatusCache.update(mContext, statusCache -> initPreference());
List<SubscriptionAnnotation> subs = mStatusCache.getSubscriptionList();
if (subs.isEmpty()) {
if (MobileNetworkUtils.showEuiccSettings(mContext)) {
if (mStatusCache.isEuiccConfigSupport()) {
mPreference.setOnPreferenceClickListener((Preference pref) -> {
mMetricsFeatureProvider.logClickedPreference(pref,
pref.getExtras().getInt(DashboardFragment.CATEGORY));
logPreferenceClick(pref);
startAddSimFlow();
return true;
});
} else {
mPreference.setEnabled(false);
}
} else {
// We have one or more existing subscriptions, so we want the plus button if eSIM is
// supported.
if (MobileNetworkUtils.showEuiccSettings(mContext)) {
mPreference.setAddWidgetEnabled(!mChangeListener.isAirplaneModeOn());
mPreference.setOnAddClickListener(p -> {
mMetricsFeatureProvider.logClickedPreference(p,
p.getExtras().getInt(DashboardFragment.CATEGORY));
startAddSimFlow();
});
}
return;
}
if (subs.size() == 1) {
mPreference.setOnPreferenceClickListener((Preference pref) -> {
mMetricsFeatureProvider.logClickedPreference(pref,
pref.getExtras().getInt(DashboardFragment.CATEGORY));
final SubscriptionInfo info = subs.get(0);
final int subId = info.getSubscriptionId();
if (!info.isEmbedded() && !mSubscriptionManager.isActiveSubscriptionId(subId)
&& !SubscriptionUtil.showToggleForPhysicalSim(mSubscriptionManager)) {
SubscriptionUtil.startToggleSubscriptionDialogActivity(
mContext, subId, true);
} else {
final Intent intent = new Intent(mContext, MobileNetworkActivity.class);
intent.putExtra(Settings.EXTRA_SUB_ID, subs.get(0).getSubscriptionId());
mContext.startActivity(intent);
}
// We have one or more existing subscriptions, so we want the plus button if eSIM is
// supported.
if (mStatusCache.isEuiccConfigSupport()) {
mPreference.setAddWidgetEnabled(!mChangeListener.isAirplaneModeOn());
mPreference.setOnAddClickListener(p -> {
logPreferenceClick(p);
startAddSimFlow();
});
}
if (subs.size() == 1) {
mPreference.setOnPreferenceClickListener((Preference pref) -> {
logPreferenceClick(pref);
SubscriptionAnnotation info = subs.get(0);
if (info.getSubInfo().isEmbedded() || info.isActive()
|| mStatusCache.isPhysicalSimDisableSupport()) {
final Intent intent = new Intent(mContext, MobileNetworkActivity.class);
intent.putExtra(Settings.EXTRA_SUB_ID, info.getSubscriptionId());
mContext.startActivity(intent);
return true;
});
} else {
mPreference.setFragment(MobileNetworkListFragment.class.getCanonicalName());
}
}
SubscriptionUtil.startToggleSubscriptionDialogActivity(
mContext, info.getSubscriptionId(), true);
return true;
});
} else {
mPreference.setFragment(MobileNetworkListFragment.class.getCanonicalName());
}
}
@@ -218,12 +227,14 @@ public class MobileNetworkSummaryController extends AbstractPreferenceController
@Override
public void onAirplaneModeChanged(boolean airplaneModeEnabled) {
update();
mStatusCache.update(mContext, statusCache -> update());
}
@Override
public void onSubscriptionsChanged() {
refreshSummary(mPreference);
update();
mStatusCache.update(mContext, statusCache -> {
refreshSummary(mPreference);
update();
});
}
}

View File

@@ -0,0 +1,176 @@
/*
* Copyright (C) 2021 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.network;
import android.content.Context;
import android.telephony.SubscriptionManager;
import android.util.Log;
import com.android.settings.network.SubscriptionUtil;
import com.android.settings.network.helper.SelectableSubscriptions;
import com.android.settings.network.helper.SubscriptionAnnotation;
import com.android.settings.network.helper.SubscriptionGrouping;
import com.android.settings.network.telephony.MobileNetworkUtils;
import com.android.settingslib.utils.ThreadUtils;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Future;
import java.util.function.Consumer;
import java.util.stream.Collectors;
/**
* This one keeps the information required by MobileNetworkSummaryController.
*/
public class MobileNetworkSummaryStatus {
private static final String LOG_TAG = "MobileNetworkSummaryStatus";
private Future<Map<Integer, CharSequence>> mUniqueNameMapping;
private Map<Integer, CharSequence> mUniqueNameMappingCache;
private Future<Boolean> mIsEuiccConfiguable;
private Boolean mIsEuiccConfiguableCache;
private Future<Boolean> mIsPsimDisableSupported;
private Boolean mIsPsimDisableSupportedCache;
private List<SubscriptionAnnotation> mSubscriptionList;
private boolean mDisableReEntranceUpdate;
// Constructor
public MobileNetworkSummaryStatus() {}
/**
* Update the status
* @param context
* @param andThen Consumer which always performed by the end of #update()
* and avoid from repeated queries.
*/
public void update(Context context, Consumer<MobileNetworkSummaryStatus> andThen) {
if (mDisableReEntranceUpdate) {
Log.d(LOG_TAG, "network summary query ignored");
if (andThen != null) {
andThen.accept(this);
}
return;
}
mDisableReEntranceUpdate = true;
Log.d(LOG_TAG, "network summary query");
// Query Euicc in background
mIsEuiccConfiguable = (Future<Boolean>)
ThreadUtils.postOnBackgroundThread(() -> isEuiccConfiguable(context));
// Query display name in background
mUniqueNameMapping = (Future<Map<Integer, CharSequence>>)
ThreadUtils.postOnBackgroundThread(() -> getUniqueNameForDisplay(context));
// Query support status of pSIM disable feature
mIsPsimDisableSupported = (Future<Boolean>) ThreadUtils.postOnBackgroundThread(()
-> isPhysicalSimDisableSupported(context));
// Query subscription
mSubscriptionList = getSubscriptions(context);
if (andThen != null) {
andThen.accept(this);
}
mDisableReEntranceUpdate = false;
}
/**
* Get the subscription information
* @return a list of SubscriptionAnnotation
*/
public List<SubscriptionAnnotation> getSubscriptionList() {
return mSubscriptionList;
}
/**
* Get unique display name for a specific subscription
* @param subscriptionId subscription ID
* @return display name for that subscription
*/
public CharSequence getDisplayName(int subscriptionId) {
if (mUniqueNameMapping != null) {
try {
mUniqueNameMappingCache = mUniqueNameMapping.get();
} catch (Exception exception) {
Log.w(LOG_TAG, "Fail to get display names", exception);
}
mUniqueNameMapping = null;
}
if (mUniqueNameMappingCache == null) {
return null;
}
return mUniqueNameMappingCache.get(subscriptionId);
}
// Check if Euicc is currently available
public boolean isEuiccConfigSupport() {
if (mIsEuiccConfiguable != null) {
try {
mIsEuiccConfiguableCache = mIsEuiccConfiguable.get();
} catch (Exception exception) {
Log.w(LOG_TAG, "Fail to get euicc config status", exception);
}
mIsEuiccConfiguable = null;
}
return (mIsEuiccConfiguableCache == null) ?
false : mIsEuiccConfiguableCache.booleanValue();
}
// Check if disable physical SIM is supported
public boolean isPhysicalSimDisableSupport() {
if (mIsPsimDisableSupported != null) {
try {
mIsPsimDisableSupportedCache = mIsPsimDisableSupported.get();
} catch (Exception exception) {
Log.w(LOG_TAG, "Fail to get pSIM disable support", exception);
}
mIsPsimDisableSupported = null;
}
return (mIsPsimDisableSupportedCache == null) ?
false : mIsPsimDisableSupportedCache.booleanValue();
}
private List<SubscriptionAnnotation> getSubscriptions(Context context) {
return (new SelectableSubscriptions(context, true))
// To maintain the consistency with SubscriptionUtil#getAvailableSubscriptions().
.addFinisher(new SubscriptionGrouping())
.call()
.stream()
.filter(SubscriptionAnnotation::isDisplayAllowed)
.collect(Collectors.toList());
}
private Map<Integer, CharSequence> getUniqueNameForDisplay(Context context) {
return SubscriptionUtil.getUniqueSubscriptionDisplayNames(context);
}
private boolean isPhysicalSimDisableSupported(Context context) {
SubscriptionManager subMgr = context.getSystemService(SubscriptionManager.class);
return SubscriptionUtil.showToggleForPhysicalSim(subMgr);
}
private boolean isEuiccConfiguable(Context context) {
return MobileNetworkUtils.showEuiccSettingsDetecting(context);
}
}

View File

@@ -50,8 +50,7 @@ public class QueryEsimCardId implements Callable<AtomicIntegerArray> {
}
return new AtomicIntegerArray(cardInfos.stream()
.filter(Objects::nonNull)
.filter(cardInfo -> (!cardInfo.isRemovable()
&& (cardInfo.getCardId() != TelephonyManager.UNSUPPORTED_CARD_ID)))
.filter(cardInfo -> (!cardInfo.isRemovable() && (cardInfo.getCardId() >= 0)))
.mapToInt(UiccCardInfo::getCardId)
.toArray());
}

View File

@@ -71,8 +71,17 @@ public class SelectableSubscriptions implements Callable<List<SubscriptionAnnota
mContext = context;
mSubscriptions = disabledSlotsIncluded ? (() -> getAvailableSubInfoList(context)) :
(() -> getActiveSubInfoList(context));
mFilter = disabledSlotsIncluded ? (subAnno -> subAnno.isExisted()) :
(subAnno -> subAnno.isActive());
if (disabledSlotsIncluded) {
mFilter = subAnno -> {
if (subAnno.isExisted()) {
return true;
}
return ((subAnno.getType() == SubscriptionAnnotation.TYPE_ESIM)
&& (subAnno.isDisplayAllowed()));
};
} else {
mFilter = subAnno -> subAnno.isActive();
}
mFinisher = annoList -> annoList;
}

View File

@@ -93,10 +93,9 @@ public class SubscriptionAnnotation {
if (mType == TYPE_ESIM) {
int cardId = mSubInfo.getCardId();
mIsExisted = eSimCardId.contains(cardId);
if (mIsExisted) {
mIsActive = activeSimSlotIndexList.contains(mSubInfo.getSimSlotIndex());
mIsAllowToDisplay = isDisplayAllowed(context);
}
mIsActive = activeSimSlotIndexList.contains(mSubInfo.getSimSlotIndex());
mIsAllowToDisplay = (cardId < 0) // always allow when eSIM not in slot
|| isDisplayAllowed(context);
return;
}
@@ -159,4 +158,11 @@ public class SubscriptionAnnotation {
return SubscriptionUtil.isSubscriptionVisible(
context.getSystemService(SubscriptionManager.class), context, mSubInfo);
}
public String toString() {
return TAG + "{" + "subId=" + getSubscriptionId()
+ ",type=" + getType() + ",exist=" + isExisted()
+ ",active=" + isActive() + ",displayAllow=" + isDisplayAllowed()
+ "}";
}
}

View File

@@ -266,7 +266,8 @@ public class MobileNetworkUtils {
return false;
}
private static Boolean showEuiccSettingsDetecting(Context context) {
// The same as #showEuiccSettings(Context context)
public static Boolean showEuiccSettingsDetecting(Context context) {
final EuiccManager euiccManager =
(EuiccManager) context.getSystemService(EuiccManager.class);
if (!euiccManager.isEnabled()) {