• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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