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.sim; 18 19 import static android.telephony.SubscriptionManager.PROFILE_CLASS_PROVISIONING; 20 21 import android.app.Dialog; 22 import android.app.settings.SettingsEnums; 23 import android.content.Context; 24 import android.os.Bundle; 25 import android.telephony.SubscriptionInfo; 26 import android.telephony.SubscriptionManager; 27 import android.text.TextUtils; 28 import android.util.Log; 29 import android.view.LayoutInflater; 30 import android.view.View; 31 import android.view.ViewGroup; 32 import android.widget.AdapterView; 33 import android.widget.BaseAdapter; 34 import android.widget.ListView; 35 import android.widget.TextView; 36 37 import androidx.annotation.NonNull; 38 import androidx.annotation.Nullable; 39 import androidx.annotation.VisibleForTesting; 40 import androidx.appcompat.app.AlertDialog; 41 42 import com.android.settings.R; 43 import com.android.settings.network.SubscriptionUtil; 44 45 import java.util.ArrayList; 46 import java.util.List; 47 48 /** 49 * Shows a dialog consisting of a list of SIMs (aka subscriptions), possibly including an additional 50 * entry indicating "ask me every time". 51 */ 52 public class SimListDialogFragment extends SimDialogFragment { 53 private static final String TAG = "SimListDialogFragment"; 54 protected static final String KEY_INCLUDE_ASK_EVERY_TIME = "include_ask_every_time"; 55 protected static final String KEY_SHOW_CANCEL_ITEM = "show_cancel_item"; 56 57 protected SelectSubscriptionAdapter mAdapter; 58 @VisibleForTesting 59 @NonNull 60 List<SubscriptionInfo> mSubscriptions = new ArrayList<>(); 61 newInstance(int dialogType, int titleResId, boolean includeAskEveryTime, boolean isCancelItemShowed)62 public static SimListDialogFragment newInstance(int dialogType, int titleResId, 63 boolean includeAskEveryTime, boolean isCancelItemShowed) { 64 final SimListDialogFragment fragment = new SimListDialogFragment(); 65 final Bundle args = initArguments(dialogType, titleResId); 66 args.putBoolean(KEY_INCLUDE_ASK_EVERY_TIME, includeAskEveryTime); 67 args.putBoolean(KEY_SHOW_CANCEL_ITEM, isCancelItemShowed); 68 fragment.setArguments(args); 69 return fragment; 70 } 71 72 @NonNull 73 @Override onCreateDialog(@ullable Bundle savedInstanceState)74 public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { 75 final AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); 76 View titleView = LayoutInflater.from(getContext()).inflate( 77 R.layout.sim_confirm_dialog_title_multiple_enabled_profiles_supported, null); 78 TextView titleTextView = titleView.findViewById(R.id.title); 79 titleTextView.setText(getContext().getString(getTitleResId())); 80 builder.setCustomTitle(titleTextView); 81 mAdapter = new SelectSubscriptionAdapter(builder.getContext(), mSubscriptions); 82 83 final AlertDialog dialog = builder.create(); 84 85 View content = LayoutInflater.from(getContext()).inflate( 86 R.layout.sim_confirm_dialog_multiple_enabled_profiles_supported, null); 87 88 final ListView lvItems = content != null ? content.findViewById(R.id.carrier_list) : null; 89 if (lvItems != null) { 90 setAdapter(lvItems); 91 lvItems.setVisibility(View.VISIBLE); 92 lvItems.setOnItemClickListener(new AdapterView.OnItemClickListener() { 93 @Override 94 public void onItemClick(AdapterView<?> parent, View view, int position, long id) { 95 onClick(position); 96 } 97 }); 98 } 99 100 dialog.setView(content); 101 updateDialog(); 102 103 return dialog; 104 } 105 106 /** 107 * If the user click the item at the list, then it sends the callback. 108 * @param selectionIndex the index of item in the list. 109 */ onClick(int selectionIndex)110 public void onClick(int selectionIndex) { 111 final SimDialogActivity activity = (SimDialogActivity) getActivity(); 112 if (selectionIndex >= 0 && selectionIndex < mSubscriptions.size()) { 113 int subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; 114 final SubscriptionInfo subscription = mSubscriptions.get(selectionIndex); 115 if (subscription != null) { 116 subId = subscription.getSubscriptionId(); 117 } 118 activity.onSubscriptionSelected(getDialogType(), subId); 119 } 120 Log.d(TAG, "Start showing auto data switch dialog"); 121 activity.showEnableAutoDataSwitchDialog(); 122 if (getDialog() != null) getDialog().dismiss(); 123 } 124 getCurrentSubscriptions()125 protected List<SubscriptionInfo> getCurrentSubscriptions() { 126 final SubscriptionManager manager = getContext().getSystemService( 127 SubscriptionManager.class).createForAllUserProfiles(); 128 return manager.getActiveSubscriptionInfoList(); 129 } 130 131 @Override updateDialog()132 public void updateDialog() { 133 Log.d(TAG, "Dialog updated, dismiss status: " + mWasDismissed); 134 if (mWasDismissed) { 135 return; 136 } 137 138 List<SubscriptionInfo> currentSubscriptions = getCurrentSubscriptions(); 139 if (currentSubscriptions == null) { 140 dismiss(); 141 return; 142 } 143 144 // Remove the provisioning or satellite eSIM from the subscription list. 145 currentSubscriptions.removeIf(info -> info.isEmbedded() 146 && (info.getProfileClass() == PROFILE_CLASS_PROVISIONING 147 || info.isOnlyNonTerrestrialNetwork())); 148 149 boolean includeAskEveryTime = getArguments().getBoolean(KEY_INCLUDE_ASK_EVERY_TIME); 150 boolean isCancelItemShowed = getArguments().getBoolean(KEY_SHOW_CANCEL_ITEM); 151 if (includeAskEveryTime || isCancelItemShowed) { 152 int arraySize = currentSubscriptions.size() 153 + (includeAskEveryTime ? 1 : 0) 154 + (isCancelItemShowed ? 1 : 0); 155 final List<SubscriptionInfo> tmp = new ArrayList<>(arraySize); 156 if (includeAskEveryTime) { 157 // add the value of 'AskEveryTime' item 158 tmp.add(null); 159 } 160 tmp.addAll(currentSubscriptions); 161 if (isCancelItemShowed) { 162 // add the value of 'Cancel' item 163 tmp.add(null); 164 } 165 currentSubscriptions = tmp; 166 } 167 if (currentSubscriptions.equals(mSubscriptions)) { 168 return; 169 } 170 171 mSubscriptions.clear(); 172 mSubscriptions.addAll(currentSubscriptions); 173 mAdapter.notifyDataSetChanged(); 174 } 175 176 @VisibleForTesting setAdapter(ListView lvItems)177 void setAdapter(ListView lvItems) { 178 lvItems.setAdapter(mAdapter); 179 } 180 181 @Override getMetricsCategory()182 public int getMetricsCategory() { 183 return SettingsEnums.DIALOG_SIM_LIST; 184 } 185 186 private static class SelectSubscriptionAdapter extends BaseAdapter { 187 private Context mContext; 188 private LayoutInflater mInflater; 189 List<SubscriptionInfo> mSubscriptions; 190 SelectSubscriptionAdapter(Context context, List<SubscriptionInfo> subscriptions)191 public SelectSubscriptionAdapter(Context context, List<SubscriptionInfo> subscriptions) { 192 mSubscriptions = subscriptions; 193 mContext = context; 194 } 195 196 @Override getCount()197 public int getCount() { 198 return mSubscriptions.size(); 199 } 200 201 @Override getItem(int position)202 public SubscriptionInfo getItem(int position) { 203 return mSubscriptions.get(position); 204 } 205 206 @Override getItemId(int position)207 public long getItemId(int position) { 208 final SubscriptionInfo info = mSubscriptions.get(position); 209 if (info == null) { 210 return SubscriptionManager.INVALID_SUBSCRIPTION_ID; 211 } 212 return info.getSubscriptionId(); 213 } 214 215 @Override getView(int position, View convertView, ViewGroup parent)216 public View getView(int position, View convertView, ViewGroup parent) { 217 if (convertView == null) { 218 if (mInflater == null) { 219 mInflater = LayoutInflater.from(parent.getContext()); 220 } 221 convertView = mInflater.inflate(R.layout.select_account_list_item, parent, false); 222 } 223 final SubscriptionInfo sub = getItem(position); 224 225 final TextView title = convertView.findViewById(R.id.title); 226 final TextView summary = convertView.findViewById(R.id.summary); 227 228 if (sub == null) { 229 if (position == 0) { 230 title.setText(R.string.sim_calls_ask_first_prefs_title); 231 } else { 232 title.setText(R.string.sim_action_cancel); 233 } 234 summary.setVisibility(View.GONE); 235 } else { 236 title.setText(SubscriptionUtil.getUniqueSubscriptionDisplayName(sub, mContext)); 237 String phoneNumber = isMdnProvisioned(sub.getNumber()) ? sub.getNumber() : ""; 238 if (!TextUtils.isEmpty(phoneNumber)) { 239 summary.setVisibility(View.VISIBLE); 240 summary.setText(phoneNumber); 241 } else { 242 summary.setVisibility(View.GONE); 243 } 244 } 245 return convertView; 246 } 247 248 // An MDN is considered not provisioned if it's empty or all 0's isMdnProvisioned(String mdn)249 private boolean isMdnProvisioned(String mdn) { 250 return !(TextUtils.isEmpty(mdn) || mdn.matches("[\\D0]+")); 251 } 252 } 253 } 254