1 /*
2  * Copyright (C) 2021 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.DialogInterface;
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.widget.TextView;
32 
33 import androidx.annotation.NonNull;
34 import androidx.annotation.Nullable;
35 import androidx.annotation.VisibleForTesting;
36 import androidx.appcompat.app.AlertDialog;
37 
38 import com.android.internal.telephony.flags.Flags;
39 import com.android.settings.R;
40 import com.android.settings.network.SubscriptionUtil;
41 
42 import java.util.List;
43 
44 /**
45  * Presents a dialog asking the user if they want to switch the data to another sim
46  */
47 public class SelectSpecificDataSimDialogFragment extends SimDialogFragment implements
48         DialogInterface.OnClickListener {
49     private static final String TAG = "PreferredSimDialogFrag";
50 
51     private SubscriptionInfo mSubscriptionInfo;
52 
53     /**
54      * @return the dialog fragment.
55      */
newInstance()56     public static SelectSpecificDataSimDialogFragment newInstance() {
57         final SelectSpecificDataSimDialogFragment
58                 fragment = new SelectSpecificDataSimDialogFragment();
59         final Bundle args = initArguments(SimDialogActivity.DATA_PICK,
60                 R.string.select_specific_sim_for_data_title);
61         fragment.setArguments(args);
62         return fragment;
63     }
64 
65     @NonNull
66     @Override
onCreateDialog(@ullable Bundle savedInstanceState)67     public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
68         final AlertDialog dialog = new AlertDialog.Builder(getContext())
69                 .setNegativeButton(R.string.sim_action_no_thanks, null)
70                 .create();
71         updateDialog(dialog);
72         return dialog;
73     }
74 
75     @Override
onDismiss(@onNull DialogInterface dialog)76     public void onDismiss(@NonNull DialogInterface dialog) {
77         Log.d(TAG, "Dialog onDismiss, dismiss status: " + mWasDismissed);
78         if (!mWasDismissed) {
79             // This dialog might be called onDismiss twice due to first time called by onDismiss()
80             // as a consequence of user action. We need this fragment alive so the activity
81             // doesn't end, which allows the following dialog to attach. Upon the second dialog
82             // dismiss, this fragment is removed from SimDialogActivity.onFragmentDismissed to
83             // end the activity.
84             mWasDismissed = true;
85             final SimDialogActivity activity = (SimDialogActivity) getActivity();
86             activity.showEnableAutoDataSwitchDialog();
87             // Not using super.onDismiss because it will result in an immediate end of the activity,
88             // before the second auto data switch dialog can attach.
89             if (getDialog() != null) getDialog().dismiss();
90         }
91     }
92 
93     @Override
onClick(DialogInterface dialog, int buttonClicked)94     public void onClick(DialogInterface dialog, int buttonClicked) {
95         final SimDialogActivity activity = (SimDialogActivity) getActivity();
96         if (buttonClicked == DialogInterface.BUTTON_POSITIVE) {
97             final SubscriptionInfo info = getTargetSubscriptionInfo();
98             if (info != null) {
99                 activity.onSubscriptionSelected(getDialogType(), info.getSubscriptionId());
100             }
101         }
102     }
103 
getNonDefaultDataSubscriptionInfo(SubscriptionInfo dds)104     private SubscriptionInfo getNonDefaultDataSubscriptionInfo(SubscriptionInfo dds) {
105         List<SubscriptionInfo> subInfos = getSubscriptionManager().getActiveSubscriptionInfoList();
106         if (subInfos == null || dds == null) {
107             return null;
108         }
109         return subInfos.stream().filter(subinfo -> subinfo.getSubscriptionId()
110                 != dds.getSubscriptionId()).findFirst().orElse(null);
111     }
112 
getDefaultDataSubInfo()113     private SubscriptionInfo getDefaultDataSubInfo() {
114         return getSubscriptionManager().getDefaultDataSubscriptionInfo();
115     }
116 
updateDialog(@ullable AlertDialog dialog)117     private void updateDialog(@Nullable AlertDialog dialog) {
118         Log.d(TAG, "Dialog updated, dismiss status: " + mWasDismissed);
119         if (mWasDismissed) {
120             return;
121         }
122 
123         if (dialog == null) {
124             Log.d(TAG, "Dialog is null.");
125             dismiss();
126             return;
127         }
128 
129         SubscriptionInfo currentDataSubInfo = getDefaultDataSubInfo();
130         SubscriptionInfo newSubInfo = getNonDefaultDataSubscriptionInfo(currentDataSubInfo);
131 
132         if (newSubInfo == null || currentDataSubInfo == null) {
133             Log.d(TAG, "one of target SubscriptionInfos is null");
134             dismiss();
135             return;
136         }
137 
138         if ((newSubInfo.isEmbedded()
139             && (newSubInfo.getProfileClass() == PROFILE_CLASS_PROVISIONING
140                 || (Flags.oemEnabledSatelliteFlag()
141                     && newSubInfo.isOnlyNonTerrestrialNetwork())))
142             || (currentDataSubInfo.isEmbedded()
143             && (currentDataSubInfo.getProfileClass() == PROFILE_CLASS_PROVISIONING
144                 || (Flags.oemEnabledSatelliteFlag()
145                     && currentDataSubInfo.isOnlyNonTerrestrialNetwork())))) {
146             Log.d(TAG, "do not set the provisioning or satellite eSIM");
147             dismiss();
148             return;
149         }
150 
151         Log.d(TAG, "newSubId: " + newSubInfo.getSubscriptionId()
152                 + "currentDataSubID: " + currentDataSubInfo.getSubscriptionId());
153         setTargetSubscriptionInfo(newSubInfo);
154 
155         CharSequence newDataCarrierName = SubscriptionUtil.getUniqueSubscriptionDisplayName(
156                 newSubInfo, getContext());
157         CharSequence currentDataCarrierName = SubscriptionUtil.getUniqueSubscriptionDisplayName(
158                 currentDataSubInfo, getContext());
159 
160         String positive = getContext().getString(
161                 R.string.select_specific_sim_for_data_button, newDataCarrierName);
162         String message = getContext().getString(R.string.select_specific_sim_for_data_msg,
163                 newDataCarrierName, currentDataCarrierName);
164 
165         View content = LayoutInflater.from(getContext()).inflate(
166                 R.layout.sim_confirm_dialog_multiple_enabled_profiles_supported, null);
167         TextView dialogMessage = content != null ? content.findViewById(R.id.msg) : null;
168         if (!TextUtils.isEmpty(message) && dialogMessage != null) {
169             dialogMessage.setText(message);
170             dialogMessage.setVisibility(View.VISIBLE);
171         }
172         dialog.setView(content);
173 
174         View titleView = LayoutInflater.from(getContext()).inflate(
175                 R.layout.sim_confirm_dialog_title_multiple_enabled_profiles_supported, null);
176         TextView titleTextView = titleView.findViewById(R.id.title);
177         titleTextView.setText(getContext().getString(getTitleResId(), newDataCarrierName));
178 
179         dialog.setCustomTitle(titleTextView);
180         dialog.setButton(AlertDialog.BUTTON_POSITIVE, positive, this);
181     }
182 
setTargetSubscriptionInfo(SubscriptionInfo subInfo)183     private void setTargetSubscriptionInfo(SubscriptionInfo subInfo) {
184         mSubscriptionInfo = subInfo;
185     }
186 
getTargetSubscriptionInfo()187     private SubscriptionInfo getTargetSubscriptionInfo() {
188         return mSubscriptionInfo;
189     }
190 
191     @Override
updateDialog()192     public void updateDialog() {
193         updateDialog((AlertDialog) getDialog());
194     }
195 
196     @VisibleForTesting
getSubscriptionManager()197     protected SubscriptionManager getSubscriptionManager() {
198         return getContext().getSystemService(SubscriptionManager.class).createForAllUserProfiles();
199     }
200 
201     @Override
getMetricsCategory()202     public int getMetricsCategory() {
203         return SettingsEnums.DIALOG_SPECIFIC_DDS_SIM_PICKER;
204     }
205 }
206