1 /* 2 * Copyright (C) 2019 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.settings.network.telephony; 18 19 import static androidx.lifecycle.Lifecycle.Event.ON_PAUSE; 20 import static androidx.lifecycle.Lifecycle.Event.ON_RESUME; 21 22 import android.content.Context; 23 import android.telephony.SubscriptionManager; 24 import android.view.View; 25 26 import androidx.lifecycle.LifecycleObserver; 27 import androidx.lifecycle.LifecycleOwner; 28 import androidx.lifecycle.OnLifecycleEvent; 29 import androidx.preference.ListPreference; 30 import androidx.preference.Preference; 31 import androidx.preference.PreferenceScreen; 32 33 import com.android.internal.annotations.VisibleForTesting; 34 import com.android.settings.R; 35 import com.android.settings.flags.Flags; 36 import com.android.settings.network.DefaultSubscriptionReceiver; 37 import com.android.settings.network.MobileNetworkRepository; 38 import com.android.settingslib.core.lifecycle.Lifecycle; 39 import com.android.settingslib.mobile.dataservice.SubscriptionInfoEntity; 40 41 import java.util.ArrayList; 42 import java.util.List; 43 44 /** 45 * This implements common controller functionality for a Preference letting the user see/change 46 * what mobile network subscription is used by default for some service controlled by the 47 * SubscriptionManager. This can be used for services such as Calls or SMS. 48 */ 49 public abstract class DefaultSubscriptionController extends TelephonyBasePreferenceController 50 implements LifecycleObserver, Preference.OnPreferenceChangeListener, 51 MobileNetworkRepository.MobileNetworkCallback, 52 DefaultSubscriptionReceiver.DefaultSubscriptionListener { 53 private static final String TAG = "DefaultSubController"; 54 55 protected ListPreference mPreference; 56 protected SubscriptionManager mManager; 57 protected MobileNetworkRepository mMobileNetworkRepository; 58 protected LifecycleOwner mLifecycleOwner; 59 private DefaultSubscriptionReceiver mDataSubscriptionChangedReceiver; 60 61 private boolean mIsRtlMode; 62 63 List<SubscriptionInfoEntity> mSubInfoEntityList = new ArrayList<>(); 64 DefaultSubscriptionController(Context context, String preferenceKey, Lifecycle lifecycle, LifecycleOwner lifecycleOwner)65 public DefaultSubscriptionController(Context context, String preferenceKey, Lifecycle lifecycle, 66 LifecycleOwner lifecycleOwner) { 67 this(context, preferenceKey); 68 mLifecycleOwner = lifecycleOwner; 69 if (lifecycle != null) { 70 lifecycle.addObserver(this); 71 } 72 } 73 DefaultSubscriptionController(Context context, String preferenceKey)74 public DefaultSubscriptionController(Context context, String preferenceKey) { 75 super(context, preferenceKey); 76 mManager = context.getSystemService(SubscriptionManager.class); 77 mIsRtlMode = context.getResources().getConfiguration().getLayoutDirection() 78 == View.LAYOUT_DIRECTION_RTL; 79 mMobileNetworkRepository = MobileNetworkRepository.getInstance(context); 80 mDataSubscriptionChangedReceiver = new DefaultSubscriptionReceiver(context, this); 81 } 82 83 /** @return the id of the default subscription for the service, or 84 * SubscriptionManager.INVALID_SUBSCRIPTION_ID if there isn't one. */ getDefaultSubscriptionId()85 protected abstract int getDefaultSubscriptionId(); 86 87 /** Called to change the default subscription for the service. */ setDefaultSubscription(int subscriptionId)88 protected abstract void setDefaultSubscription(int subscriptionId); 89 isAskEverytimeSupported()90 protected boolean isAskEverytimeSupported() { 91 return true; 92 } 93 94 @Override getAvailabilityStatus(int subId)95 public int getAvailabilityStatus(int subId) { 96 if (Flags.isDualSimOnboardingEnabled()) { 97 return CONDITIONALLY_UNAVAILABLE; 98 } 99 return AVAILABLE; 100 } 101 102 @OnLifecycleEvent(ON_RESUME) onResume()103 public void onResume() { 104 mMobileNetworkRepository.addRegister(mLifecycleOwner, this, 105 SubscriptionManager.INVALID_SUBSCRIPTION_ID); 106 mMobileNetworkRepository.updateEntity(); 107 mDataSubscriptionChangedReceiver.registerReceiver(); 108 } 109 110 @OnLifecycleEvent(ON_PAUSE) onPause()111 public void onPause() { 112 mMobileNetworkRepository.removeRegister(this); 113 mDataSubscriptionChangedReceiver.unRegisterReceiver(); 114 } 115 116 @Override displayPreference(PreferenceScreen screen)117 public void displayPreference(PreferenceScreen screen) { 118 super.displayPreference(screen); 119 mPreference = screen.findPreference(getPreferenceKey()); 120 updateEntries(); 121 } 122 123 @Override refreshSummary(Preference preference)124 protected void refreshSummary(Preference preference) { 125 // Currently, cannot use ListPreference.setSummary() when the summary contains user 126 // generated string, because ListPreference.getSummary() is using String.format() to format 127 // the summary when the summary is set by ListPreference.setSummary(). 128 if (preference != null && !mSubInfoEntityList.isEmpty()) { 129 preference.setSummaryProvider(pref -> getSummary()); 130 } 131 } 132 133 @VisibleForTesting updateEntries()134 void updateEntries() { 135 if (mPreference == null) { 136 return; 137 } 138 if (!isAvailable()) { 139 mPreference.setVisible(false); 140 return; 141 } 142 mPreference.setVisible(true); 143 144 // TODO(b/135142209) - for now we need to manually ensure we're registered as a change 145 // listener, because this might not have happened during displayPreference if 146 // getAvailabilityStatus returned CONDITIONALLY_UNAVAILABLE at the time. 147 mPreference.setOnPreferenceChangeListener(this); 148 149 // We'll have one entry for each available subscription, plus one for a "ask me every 150 // time" entry at the end. 151 final ArrayList<CharSequence> displayNames = new ArrayList<>(); 152 final ArrayList<CharSequence> subscriptionIds = new ArrayList<>(); 153 List<SubscriptionInfoEntity> list = getSubscriptionInfoList(); 154 if (list.isEmpty()) return; 155 156 if (list.size() == 1) { 157 mPreference.setEnabled(false); 158 mPreference.setSummaryProvider(pref -> list.get(0).uniqueName); 159 return; 160 } 161 162 final int serviceDefaultSubId = getDefaultSubscriptionId(); 163 boolean subIsAvailable = false; 164 165 for (SubscriptionInfoEntity sub : list) { 166 if (sub.isOpportunistic) { 167 continue; 168 } 169 displayNames.add(sub.uniqueName); 170 final int subId = Integer.parseInt(sub.subId); 171 subscriptionIds.add(sub.subId); 172 if (subId == serviceDefaultSubId) { 173 subIsAvailable = true; 174 } 175 } 176 177 if (isAskEverytimeSupported()) { 178 // Add the extra "Ask every time" value at the end. 179 displayNames.add(mContext.getString(R.string.calls_and_sms_ask_every_time)); 180 subscriptionIds.add(Integer.toString(SubscriptionManager.INVALID_SUBSCRIPTION_ID)); 181 } 182 183 mPreference.setEnabled(true); 184 mPreference.setEntries(displayNames.toArray(new CharSequence[0])); 185 mPreference.setEntryValues(subscriptionIds.toArray(new CharSequence[0])); 186 187 if (subIsAvailable) { 188 mPreference.setValue(Integer.toString(serviceDefaultSubId)); 189 } else { 190 mPreference.setValue(Integer.toString(SubscriptionManager.INVALID_SUBSCRIPTION_ID)); 191 } 192 } 193 194 @VisibleForTesting getSubscriptionInfoList()195 protected List<SubscriptionInfoEntity> getSubscriptionInfoList() { 196 return mSubInfoEntityList; 197 } 198 199 @Override onPreferenceChange(Preference preference, Object newValue)200 public boolean onPreferenceChange(Preference preference, Object newValue) { 201 final int subscriptionId = Integer.parseInt((String) newValue); 202 setDefaultSubscription(subscriptionId); 203 refreshSummary(mPreference); 204 return true; 205 } 206 isRtlMode()207 boolean isRtlMode() { 208 return mIsRtlMode; 209 } 210 211 @Override onActiveSubInfoChanged(List<SubscriptionInfoEntity> subInfoEntityList)212 public void onActiveSubInfoChanged(List<SubscriptionInfoEntity> subInfoEntityList) { 213 mSubInfoEntityList = subInfoEntityList; 214 updateEntries(); 215 refreshSummary(mPreference); 216 } 217 218 @Override onDefaultVoiceChanged(int defaultVoiceSubId)219 public void onDefaultVoiceChanged(int defaultVoiceSubId) { 220 updateEntries(); 221 refreshSummary(mPreference); 222 } 223 224 @Override onDefaultSmsChanged(int defaultSmsSubId)225 public void onDefaultSmsChanged(int defaultSmsSubId) { 226 updateEntries(); 227 refreshSummary(mPreference); 228 } 229 } 230