• 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.car.developeroptions.sim;
18 
19 import android.app.settings.SettingsEnums;
20 import android.content.Context;
21 import android.content.Intent;
22 import android.content.res.Resources;
23 import android.graphics.drawable.BitmapDrawable;
24 import android.os.Bundle;
25 import android.os.SystemProperties;
26 import android.provider.SearchIndexableResource;
27 import android.telecom.PhoneAccountHandle;
28 import android.telecom.TelecomManager;
29 import android.telephony.PhoneNumberUtils;
30 import android.telephony.PhoneStateListener;
31 import android.telephony.SubscriptionInfo;
32 import android.telephony.SubscriptionManager;
33 import android.telephony.TelephonyManager;
34 import android.text.TextUtils;
35 import android.util.Log;
36 
37 import androidx.preference.Preference;
38 import androidx.preference.PreferenceScreen;
39 
40 import com.android.internal.telephony.TelephonyProperties;
41 import com.android.car.developeroptions.R;
42 import com.android.car.developeroptions.RestrictedSettingsFragment;
43 import com.android.car.developeroptions.Utils;
44 import com.android.car.developeroptions.search.BaseSearchIndexProvider;
45 import com.android.car.developeroptions.search.Indexable;
46 import com.android.settingslib.search.SearchIndexable;
47 
48 import java.util.ArrayList;
49 import java.util.List;
50 
51 @SearchIndexable
52 public class SimSettings extends RestrictedSettingsFragment implements Indexable {
53     private static final String TAG = "SimSettings";
54     private static final boolean DBG = false;
55 
56     private static final String DISALLOW_CONFIG_SIM = "no_config_sim";
57     private static final String SIM_CARD_CATEGORY = "sim_cards";
58     private static final String KEY_CELLULAR_DATA = "sim_cellular_data";
59     private static final String KEY_CALLS = "sim_calls";
60     private static final String KEY_SMS = "sim_sms";
61     public static final String EXTRA_SLOT_ID = "slot_id";
62 
63     /**
64      * By UX design we use only one Subscription Information(SubInfo) record per SIM slot.
65      * mAvalableSubInfos is the list of SubInfos we present to the user.
66      * mSubInfoList is the list of all SubInfos.
67      * mSelectableSubInfos is the list of SubInfos that a user can select for data, calls, and SMS.
68      */
69     private List<SubscriptionInfo> mAvailableSubInfos = null;
70     private List<SubscriptionInfo> mSubInfoList = null;
71     private List<SubscriptionInfo> mSelectableSubInfos = null;
72     private PreferenceScreen mSimCards = null;
73     private SubscriptionManager mSubscriptionManager;
74     private int mNumSlots;
75     private Context mContext;
76 
77     private int mPhoneCount = TelephonyManager.getDefault().getPhoneCount();
78     private int[] mCallState = new int[mPhoneCount];
79     private PhoneStateListener[] mPhoneStateListener = new PhoneStateListener[mPhoneCount];
80 
SimSettings()81     public SimSettings() {
82         super(DISALLOW_CONFIG_SIM);
83     }
84 
85     @Override
getMetricsCategory()86     public int getMetricsCategory() {
87         return SettingsEnums.SIM;
88     }
89 
90     @Override
onCreate(final Bundle bundle)91     public void onCreate(final Bundle bundle) {
92         super.onCreate(bundle);
93         mContext = getActivity();
94 
95         mSubscriptionManager = SubscriptionManager.from(getActivity());
96         final TelephonyManager tm =
97                 (TelephonyManager) getActivity().getSystemService(Context.TELEPHONY_SERVICE);
98         addPreferencesFromResource(R.xml.sim_settings);
99 
100         mNumSlots = tm.getSimCount();
101         mSimCards = (PreferenceScreen)findPreference(SIM_CARD_CATEGORY);
102         mAvailableSubInfos = new ArrayList<SubscriptionInfo>(mNumSlots);
103         mSelectableSubInfos = new ArrayList<SubscriptionInfo>();
104         SimSelectNotification.cancelNotification(getActivity());
105     }
106 
107     private final SubscriptionManager.OnSubscriptionsChangedListener mOnSubscriptionsChangeListener
108             = new SubscriptionManager.OnSubscriptionsChangedListener() {
109         @Override
110         public void onSubscriptionsChanged() {
111             if (DBG) log("onSubscriptionsChanged:");
112             updateSubscriptions();
113         }
114     };
115 
updateSubscriptions()116     private void updateSubscriptions() {
117         mSubInfoList = mSubscriptionManager.getActiveSubscriptionInfoList(true);
118         for (int i = 0; i < mNumSlots; ++i) {
119             Preference pref = mSimCards.findPreference("sim" + i);
120             if (pref instanceof SimPreference) {
121                 mSimCards.removePreference(pref);
122             }
123         }
124         mAvailableSubInfos.clear();
125         mSelectableSubInfos.clear();
126 
127         for (int i = 0; i < mNumSlots; ++i) {
128             final SubscriptionInfo sir = mSubscriptionManager
129                     .getActiveSubscriptionInfoForSimSlotIndex(i);
130             SimPreference simPreference = new SimPreference(getPrefContext(), sir, i);
131             simPreference.setOrder(i-mNumSlots);
132             mSimCards.addPreference(simPreference);
133             mAvailableSubInfos.add(sir);
134             if (sir != null) {
135                 mSelectableSubInfos.add(sir);
136             }
137         }
138         updateAllOptions();
139     }
140 
updateAllOptions()141     private void updateAllOptions() {
142         updateSimSlotValues();
143         updateActivitesCategory();
144     }
145 
updateSimSlotValues()146     private void updateSimSlotValues() {
147         final int prefSize = mSimCards.getPreferenceCount();
148         for (int i = 0; i < prefSize; ++i) {
149             Preference pref = mSimCards.getPreference(i);
150             if (pref instanceof SimPreference) {
151                 ((SimPreference)pref).update();
152             }
153         }
154     }
155 
updateActivitesCategory()156     private void updateActivitesCategory() {
157         updateCellularDataValues();
158         updateCallValues();
159         updateSmsValues();
160     }
161 
updateSmsValues()162     private void updateSmsValues() {
163         final Preference simPref = findPreference(KEY_SMS);
164         final SubscriptionInfo sir = mSubscriptionManager.getDefaultSmsSubscriptionInfo();
165         simPref.setTitle(R.string.sms_messages_title);
166         if (DBG) log("[updateSmsValues] mSubInfoList=" + mSubInfoList);
167 
168         if (sir != null) {
169             simPref.setSummary(sir.getDisplayName());
170             simPref.setEnabled(mSelectableSubInfos.size() > 1);
171         } else if (sir == null) {
172             simPref.setSummary(R.string.sim_selection_required_pref);
173             simPref.setEnabled(mSelectableSubInfos.size() >= 1);
174         }
175     }
176 
updateCellularDataValues()177     private void updateCellularDataValues() {
178         final Preference simPref = findPreference(KEY_CELLULAR_DATA);
179         final SubscriptionInfo sir = mSubscriptionManager.getDefaultDataSubscriptionInfo();
180         simPref.setTitle(R.string.cellular_data_title);
181         if (DBG) log("[updateCellularDataValues] mSubInfoList=" + mSubInfoList);
182 
183         boolean callStateIdle = isCallStateIdle();
184         final boolean ecbMode = SystemProperties.getBoolean(
185                 TelephonyProperties.PROPERTY_INECM_MODE, false);
186         if (sir != null) {
187             simPref.setSummary(sir.getDisplayName());
188             // Enable data preference in msim mode and call state idle
189             simPref.setEnabled((mSelectableSubInfos.size() > 1) && callStateIdle && !ecbMode);
190         } else if (sir == null) {
191             simPref.setSummary(R.string.sim_selection_required_pref);
192             // Enable data preference in msim mode and call state idle
193             simPref.setEnabled((mSelectableSubInfos.size() >= 1) && callStateIdle && !ecbMode);
194         }
195     }
196 
updateCallValues()197     private void updateCallValues() {
198         final Preference simPref = findPreference(KEY_CALLS);
199         final TelecomManager telecomManager = TelecomManager.from(mContext);
200         final PhoneAccountHandle phoneAccount =
201             telecomManager.getUserSelectedOutgoingPhoneAccount();
202         final List<PhoneAccountHandle> allPhoneAccounts =
203             telecomManager.getCallCapablePhoneAccounts();
204 
205         simPref.setTitle(R.string.calls_title);
206         simPref.setSummary(phoneAccount == null
207                 ? mContext.getResources().getString(R.string.sim_calls_ask_first_prefs_title)
208                 : (String)telecomManager.getPhoneAccount(phoneAccount).getLabel());
209         simPref.setEnabled(allPhoneAccounts.size() > 1);
210     }
211 
212     @Override
onResume()213     public void onResume() {
214         super.onResume();
215         mSubscriptionManager.addOnSubscriptionsChangedListener(mOnSubscriptionsChangeListener);
216         updateSubscriptions();
217         final TelephonyManager tm =
218                 (TelephonyManager) getActivity().getSystemService(Context.TELEPHONY_SERVICE);
219         if (mSelectableSubInfos.size() > 1) {
220             Log.d(TAG, "Register for call state change");
221             for (int i = 0; i < mPhoneCount; i++) {
222                 int subId = mSelectableSubInfos.get(i).getSubscriptionId();
223                 tm.createForSubscriptionId(subId).listen(getPhoneStateListener(i),
224                         PhoneStateListener.LISTEN_CALL_STATE);
225             }
226         }
227     }
228 
229     @Override
onPause()230     public void onPause() {
231         super.onPause();
232         mSubscriptionManager.removeOnSubscriptionsChangedListener(mOnSubscriptionsChangeListener);
233         final TelephonyManager tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
234         for (int i = 0; i < mPhoneCount; i++) {
235             if (mPhoneStateListener[i] != null) {
236                 tm.listen(mPhoneStateListener[i], PhoneStateListener.LISTEN_NONE);
237                 mPhoneStateListener[i] = null;
238             }
239         }
240     }
241 
getPhoneStateListener(int phoneId)242     private PhoneStateListener getPhoneStateListener(int phoneId) {
243         // Disable Sim selection for Data when voice call is going on as changing the default data
244         // sim causes a modem reset currently and call gets disconnected
245         // ToDo : Add subtext on disabled preference to let user know that default data sim cannot
246         // be changed while call is going on
247         final int i = phoneId;
248         mPhoneStateListener[phoneId]  = new PhoneStateListener() {
249             @Override
250             public void onCallStateChanged(int state, String incomingNumber) {
251                 if (DBG) log("PhoneStateListener.onCallStateChanged: state=" + state);
252                 mCallState[i] = state;
253                 updateCellularDataValues();
254             }
255         };
256         return mPhoneStateListener[phoneId];
257     }
258 
259     @Override
onPreferenceTreeClick(final Preference preference)260     public boolean onPreferenceTreeClick(final Preference preference) {
261         final Context context = mContext;
262         Intent intent = new Intent(context, SimDialogActivity.class);
263         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
264 
265         if (preference instanceof SimPreference) {
266             Intent newIntent = new Intent(context, SimPreferenceDialog.class);
267             newIntent.putExtra(EXTRA_SLOT_ID, ((SimPreference)preference).getSlotId());
268             startActivity(newIntent);
269         } else if (findPreference(KEY_CELLULAR_DATA) == preference) {
270             intent.putExtra(SimDialogActivity.DIALOG_TYPE_KEY, SimDialogActivity.DATA_PICK);
271             context.startActivity(intent);
272         } else if (findPreference(KEY_CALLS) == preference) {
273             intent.putExtra(SimDialogActivity.DIALOG_TYPE_KEY, SimDialogActivity.CALLS_PICK);
274             context.startActivity(intent);
275         } else if (findPreference(KEY_SMS) == preference) {
276             intent.putExtra(SimDialogActivity.DIALOG_TYPE_KEY, SimDialogActivity.SMS_PICK);
277             context.startActivity(intent);
278         }
279 
280         return true;
281     }
282 
283     private class SimPreference extends Preference {
284         private SubscriptionInfo mSubInfoRecord;
285         private int mSlotId;
286         Context mContext;
287 
SimPreference(Context context, SubscriptionInfo subInfoRecord, int slotId)288         public SimPreference(Context context, SubscriptionInfo subInfoRecord, int slotId) {
289             super(context);
290 
291             mContext = context;
292             mSubInfoRecord = subInfoRecord;
293             mSlotId = slotId;
294             setKey("sim" + mSlotId);
295             update();
296         }
297 
update()298         public void update() {
299             final Resources res = mContext.getResources();
300 
301             setTitle(String.format(mContext.getResources()
302                     .getString(R.string.sim_editor_title), (mSlotId + 1)));
303             if (mSubInfoRecord != null) {
304                 if (TextUtils.isEmpty(getPhoneNumber(mSubInfoRecord))) {
305                     setSummary(mSubInfoRecord.getDisplayName());
306                 } else {
307                     setSummary(mSubInfoRecord.getDisplayName() + " - " +
308                             PhoneNumberUtils.createTtsSpannable(getPhoneNumber(mSubInfoRecord)));
309                     setEnabled(true);
310                 }
311                 setIcon(new BitmapDrawable(res, (mSubInfoRecord.createIconBitmap(mContext))));
312             } else {
313                 setSummary(R.string.sim_slot_empty);
314                 setFragment(null);
315                 setEnabled(false);
316             }
317         }
318 
getSlotId()319         private int getSlotId() {
320             return mSlotId;
321         }
322     }
323 
324     // Returns the line1Number. Line1number should always be read from TelephonyManager since it can
325     // be overridden for display purposes.
getPhoneNumber(SubscriptionInfo info)326     private String getPhoneNumber(SubscriptionInfo info) {
327         final TelephonyManager tm =
328             (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
329         return tm.getLine1Number(info.getSubscriptionId());
330     }
331 
log(String s)332     private void log(String s) {
333         Log.d(TAG, s);
334     }
335 
336     /**
337      * For search
338      */
339     public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
340             new BaseSearchIndexProvider() {
341                 @Override
342                 public List<SearchIndexableResource> getXmlResourcesToIndex(Context context,
343                         boolean enabled) {
344                     ArrayList<SearchIndexableResource> result =
345                             new ArrayList<SearchIndexableResource>();
346 
347                     if (Utils.showSimCardTile(context)) {
348                         SearchIndexableResource sir = new SearchIndexableResource(context);
349                         sir.xmlResId = R.xml.sim_settings;
350                         result.add(sir);
351                     }
352 
353                     return result;
354                 }
355             };
356 
isCallStateIdle()357     private boolean isCallStateIdle() {
358         boolean callStateIdle = true;
359         for (int i = 0; i < mCallState.length; i++) {
360             if (TelephonyManager.CALL_STATE_IDLE != mCallState[i]) {
361                 callStateIdle = false;
362             }
363         }
364         Log.d(TAG, "isCallStateIdle " + callStateIdle);
365         return callStateIdle;
366     }
367 }
368