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.internal.telephony.flags.Flags; 43 import com.android.settings.R; 44 import com.android.settings.network.SubscriptionUtil; 45 46 import java.util.ArrayList; 47 import java.util.List; 48 49 /** 50 * Shows a dialog consisting of a list of SIMs (aka subscriptions), possibly including an additional 51 * entry indicating "ask me every time". 52 */ 53 public class SimListDialogFragment extends SimDialogFragment { 54 private static final String TAG = "SimListDialogFragment"; 55 protected static final String KEY_INCLUDE_ASK_EVERY_TIME = "include_ask_every_time"; 56 protected static final String KEY_SHOW_CANCEL_ITEM = "show_cancel_item"; 57 58 protected SelectSubscriptionAdapter mAdapter; 59 @VisibleForTesting 60 @NonNull 61 List<SubscriptionInfo> mSubscriptions = new ArrayList<>(); 62 newInstance(int dialogType, int titleResId, boolean includeAskEveryTime, boolean isCancelItemShowed)63 public static SimListDialogFragment newInstance(int dialogType, int titleResId, 64 boolean includeAskEveryTime, boolean isCancelItemShowed) { 65 final SimListDialogFragment fragment = new SimListDialogFragment(); 66 final Bundle args = initArguments(dialogType, titleResId); 67 args.putBoolean(KEY_INCLUDE_ASK_EVERY_TIME, includeAskEveryTime); 68 args.putBoolean(KEY_SHOW_CANCEL_ITEM, isCancelItemShowed); 69 fragment.setArguments(args); 70 return fragment; 71 } 72 73 @NonNull 74 @Override onCreateDialog(@ullable Bundle savedInstanceState)75 public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { 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).createForAllUserProfiles(); 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 provisioning or satellite eSIM from the subscription list. 146 currentSubscriptions.removeIf(info -> info.isEmbedded() 147 && (info.getProfileClass() == PROFILE_CLASS_PROVISIONING 148 || (Flags.oemEnabledSatelliteFlag() && info.isOnlyNonTerrestrialNetwork()))); 149 150 boolean includeAskEveryTime = getArguments().getBoolean(KEY_INCLUDE_ASK_EVERY_TIME); 151 boolean isCancelItemShowed = getArguments().getBoolean(KEY_SHOW_CANCEL_ITEM); 152 if (includeAskEveryTime || isCancelItemShowed) { 153 int arraySize = currentSubscriptions.size() 154 + (includeAskEveryTime ? 1 : 0) 155 + (isCancelItemShowed ? 1 : 0); 156 final List<SubscriptionInfo> tmp = new ArrayList<>(arraySize); 157 if (includeAskEveryTime) { 158 // add the value of 'AskEveryTime' item 159 tmp.add(null); 160 } 161 tmp.addAll(currentSubscriptions); 162 if (isCancelItemShowed) { 163 // add the value of 'Cancel' item 164 tmp.add(null); 165 } 166 currentSubscriptions = tmp; 167 } 168 if (currentSubscriptions.equals(mSubscriptions)) { 169 return; 170 } 171 172 mSubscriptions.clear(); 173 mSubscriptions.addAll(currentSubscriptions); 174 mAdapter.notifyDataSetChanged(); 175 } 176 177 @VisibleForTesting setAdapter(ListView lvItems)178 void setAdapter(ListView lvItems) { 179 lvItems.setAdapter(mAdapter); 180 } 181 182 @Override getMetricsCategory()183 public int getMetricsCategory() { 184 return SettingsEnums.DIALOG_SIM_LIST; 185 } 186 187 private static class SelectSubscriptionAdapter extends BaseAdapter { 188 private Context mContext; 189 private LayoutInflater mInflater; 190 List<SubscriptionInfo> mSubscriptions; 191 SelectSubscriptionAdapter(Context context, List<SubscriptionInfo> subscriptions)192 public SelectSubscriptionAdapter(Context context, List<SubscriptionInfo> subscriptions) { 193 mSubscriptions = subscriptions; 194 mContext = context; 195 } 196 197 @Override getCount()198 public int getCount() { 199 return mSubscriptions.size(); 200 } 201 202 @Override getItem(int position)203 public SubscriptionInfo getItem(int position) { 204 return mSubscriptions.get(position); 205 } 206 207 @Override getItemId(int position)208 public long getItemId(int position) { 209 final SubscriptionInfo info = mSubscriptions.get(position); 210 if (info == null) { 211 return SubscriptionManager.INVALID_SUBSCRIPTION_ID; 212 } 213 return info.getSubscriptionId(); 214 } 215 216 @Override getView(int position, View convertView, ViewGroup parent)217 public View getView(int position, View convertView, ViewGroup parent) { 218 if (convertView == null) { 219 if (mInflater == null) { 220 mInflater = LayoutInflater.from(parent.getContext()); 221 } 222 convertView = mInflater.inflate(R.layout.select_account_list_item, parent, false); 223 } 224 final SubscriptionInfo sub = getItem(position); 225 226 final TextView title = convertView.findViewById(R.id.title); 227 final TextView summary = convertView.findViewById(R.id.summary); 228 229 if (sub == null) { 230 if (position == 0) { 231 title.setText(R.string.sim_calls_ask_first_prefs_title); 232 } else { 233 title.setText(R.string.sim_action_cancel); 234 } 235 summary.setVisibility(View.GONE); 236 } else { 237 title.setText(SubscriptionUtil.getUniqueSubscriptionDisplayName(sub, mContext)); 238 String phoneNumber = isMdnProvisioned(sub.getNumber()) ? sub.getNumber() : ""; 239 if (!TextUtils.isEmpty(phoneNumber)) { 240 summary.setVisibility(View.VISIBLE); 241 summary.setText(phoneNumber); 242 } else { 243 summary.setVisibility(View.GONE); 244 } 245 } 246 return convertView; 247 } 248 249 // An MDN is considered not provisioned if it's empty or all 0's isMdnProvisioned(String mdn)250 private boolean isMdnProvisioned(String mdn) { 251 return !(TextUtils.isEmpty(mdn) || mdn.matches("[\\D0]+")); 252 } 253 } 254 } 255