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 List<SubscriptionInfo> mSubscriptions; 60 newInstance(int dialogType, int titleResId, boolean includeAskEveryTime, boolean isCancelItemShowed)61 public static SimListDialogFragment newInstance(int dialogType, int titleResId, 62 boolean includeAskEveryTime, boolean isCancelItemShowed) { 63 final SimListDialogFragment fragment = new SimListDialogFragment(); 64 final Bundle args = initArguments(dialogType, titleResId); 65 args.putBoolean(KEY_INCLUDE_ASK_EVERY_TIME, includeAskEveryTime); 66 args.putBoolean(KEY_SHOW_CANCEL_ITEM, isCancelItemShowed); 67 fragment.setArguments(args); 68 return fragment; 69 } 70 71 @NonNull 72 @Override onCreateDialog(@ullable Bundle savedInstanceState)73 public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { 74 mSubscriptions = new ArrayList<>(); 75 76 final AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); 77 View titleView = LayoutInflater.from(getContext()).inflate( 78 R.layout.sim_confirm_dialog_title_multiple_enabled_profiles_supported, null); 79 TextView titleTextView = titleView.findViewById(R.id.title); 80 titleTextView.setText(getContext().getString(getTitleResId())); 81 builder.setCustomTitle(titleTextView); 82 mAdapter = new SelectSubscriptionAdapter(builder.getContext(), mSubscriptions); 83 84 final AlertDialog dialog = builder.create(); 85 86 View content = LayoutInflater.from(getContext()).inflate( 87 R.layout.sim_confirm_dialog_multiple_enabled_profiles_supported, null); 88 89 final ListView lvItems = content != null ? content.findViewById(R.id.carrier_list) : null; 90 if (lvItems != null) { 91 setAdapter(lvItems); 92 lvItems.setVisibility(View.VISIBLE); 93 lvItems.setOnItemClickListener(new AdapterView.OnItemClickListener() { 94 @Override 95 public void onItemClick(AdapterView<?> parent, View view, int position, long id) { 96 onClick(position); 97 } 98 }); 99 } 100 101 dialog.setView(content); 102 updateDialog(); 103 104 return dialog; 105 } 106 107 /** 108 * If the user click the item at the list, then it sends the callback. 109 * @param selectionIndex the index of item in the list. 110 */ onClick(int selectionIndex)111 public void onClick(int selectionIndex) { 112 final SimDialogActivity activity = (SimDialogActivity) getActivity(); 113 if (selectionIndex >= 0 && selectionIndex < mSubscriptions.size()) { 114 int subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; 115 final SubscriptionInfo subscription = mSubscriptions.get(selectionIndex); 116 if (subscription != null) { 117 subId = subscription.getSubscriptionId(); 118 } 119 activity.onSubscriptionSelected(getDialogType(), subId); 120 } 121 Log.d(TAG, "Start showing auto data switch dialog"); 122 activity.showEnableAutoDataSwitchDialog(); 123 if (getDialog() != null) getDialog().dismiss(); 124 } 125 getCurrentSubscriptions()126 protected List<SubscriptionInfo> getCurrentSubscriptions() { 127 final SubscriptionManager manager = getContext().getSystemService( 128 SubscriptionManager.class); 129 return manager.getActiveSubscriptionInfoList(); 130 } 131 132 @Override updateDialog()133 public void updateDialog() { 134 Log.d(TAG, "Dialog updated, dismiss status: " + mWasDismissed); 135 if (mWasDismissed) { 136 return; 137 } 138 139 List<SubscriptionInfo> currentSubscriptions = getCurrentSubscriptions(); 140 if (currentSubscriptions == null) { 141 dismiss(); 142 return; 143 } 144 145 // Remove the provision eSIM from the subscription list. 146 currentSubscriptions.removeIf(info -> info.isEmbedded() 147 && info.getProfileClass() == PROFILE_CLASS_PROVISIONING); 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