Merge "[Settings] Allow disabled SIM to be controlled in UI" into sc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
74060d3158
@@ -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();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
176
src/com/android/settings/network/MobileNetworkSummaryStatus.java
Normal file
176
src/com/android/settings/network/MobileNetworkSummaryStatus.java
Normal 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);
|
||||
}
|
||||
}
|
@@ -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());
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
|
@@ -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()
|
||||
+ "}";
|
||||
}
|
||||
}
|
@@ -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()) {
|
||||
|
Reference in New Issue
Block a user