1 /* 2 * Copyright (C) 2022 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 android.app.Dialog; 20 import android.app.settings.SettingsEnums; 21 import android.content.DialogInterface; 22 import android.os.Bundle; 23 import android.os.UserHandle; 24 import android.os.UserManager; 25 import android.telephony.SubscriptionInfo; 26 import android.telephony.SubscriptionManager; 27 import android.telephony.TelephonyManager; 28 import android.text.TextUtils; 29 import android.util.Log; 30 import android.view.LayoutInflater; 31 import android.view.View; 32 import android.widget.TextView; 33 34 import androidx.annotation.NonNull; 35 import androidx.annotation.Nullable; 36 import androidx.annotation.VisibleForTesting; 37 import androidx.appcompat.app.AlertDialog; 38 39 import com.android.settings.R; 40 import com.android.settings.network.SubscriptionUtil; 41 42 import java.util.List; 43 44 /** 45 * Show a dialog prompting the user to enable auto data switch following the dialog where user chose 46 * default data SIM. 47 */ 48 public class EnableAutoDataSwitchDialogFragment extends SimDialogFragment implements 49 DialogInterface.OnClickListener { 50 private static final String TAG = "EnableAutoDataSwitchDialogFragment"; 51 /** Sub Id of the non-default data SIM */ 52 private int mBackupDataSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; 53 54 /** @return a new instance of this fragment */ newInstance()55 public static EnableAutoDataSwitchDialogFragment newInstance() { 56 final EnableAutoDataSwitchDialogFragment fragment = 57 new EnableAutoDataSwitchDialogFragment(); 58 final Bundle args = initArguments(SimDialogActivity.ENABLE_AUTO_DATA_SWITCH, 59 R.string.enable_auto_data_switch_dialog_title); 60 fragment.setArguments(args); 61 return fragment; 62 } 63 64 @NonNull 65 @Override onCreateDialog(@ullable Bundle savedInstanceState)66 public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { 67 final AlertDialog dialog = new AlertDialog.Builder(getContext()) 68 .setPositiveButton(R.string.yes, this) 69 .setNegativeButton(R.string.sim_action_no_thanks, null) 70 .create(); 71 updateDialog(dialog); 72 return dialog; 73 } 74 75 @Override getMetricsCategory()76 public int getMetricsCategory() { 77 return SettingsEnums.DIALOG_AUTO_DATA_SWITCH; 78 } 79 80 /** update dialog */ updateDialog(AlertDialog dialog)81 public void updateDialog(AlertDialog dialog) { 82 Log.d(TAG, "Dialog updated, dismiss status: " + mWasDismissed); 83 84 if (mWasDismissed) { 85 return; 86 } 87 88 if (dialog == null) { 89 Log.d(TAG, "Dialog is null."); 90 dismiss(); 91 return; 92 } 93 94 // Set message 95 View content = LayoutInflater.from(getContext()).inflate( 96 R.layout.sim_confirm_dialog_multiple_enabled_profiles_supported, null); 97 TextView dialogMessage = content != null ? content.findViewById(R.id.msg) : null; 98 final String message = getMessage(); 99 if (TextUtils.isEmpty(message) || dialogMessage == null) { 100 onDismiss(dialog); 101 return; 102 } 103 dialogMessage.setText(message); 104 dialogMessage.setVisibility(View.VISIBLE); 105 dialog.setView(content); 106 107 // Set title 108 View titleView = LayoutInflater.from(getContext()).inflate( 109 R.layout.sim_confirm_dialog_title_multiple_enabled_profiles_supported, null); 110 TextView titleTextView = titleView.findViewById(R.id.title); 111 titleTextView.setText(getContext().getString(getTitleResId())); 112 dialog.setCustomTitle(titleTextView); 113 } 114 115 /** 116 * @return The message of the dialog. {@code null} if the dialog shouldn't be displayed. 117 */ 118 @VisibleForTesting getMessage()119 protected String getMessage() { 120 int ddsSubId = getDefaultDataSubId(); 121 if (ddsSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) return null; 122 Log.d(TAG, "DDS SubId: " + ddsSubId); 123 124 SubscriptionManager subscriptionManager = getSubscriptionManager(); 125 List<SubscriptionInfo> activeSubscriptions = subscriptionManager 126 .getActiveSubscriptionInfoList(); 127 if (activeSubscriptions == null) return null; 128 129 // Find if a backup data sub exists. 130 SubscriptionInfo backupSubInfo = activeSubscriptions.stream() 131 .filter(subInfo -> subInfo.getSubscriptionId() != ddsSubId) 132 .findFirst() 133 .orElse(null); 134 if (backupSubInfo == null) return null; 135 mBackupDataSubId = backupSubInfo.getSubscriptionId(); 136 137 // Check if auto data switch is already enabled 138 final TelephonyManager telephonyManager = getTelephonyManagerForSub(mBackupDataSubId); 139 if (telephonyManager == null) { 140 Log.d(TAG, "telephonyManager for " + mBackupDataSubId + " is null"); 141 return null; 142 } 143 if (telephonyManager.isMobileDataPolicyEnabled( 144 TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH)) { 145 Log.d(TAG, "AUTO_DATA_SWITCH already enabled"); 146 return null; 147 } 148 149 Log.d(TAG, "Backup data sub Id: " + mBackupDataSubId); 150 // The description of the feature 151 String message = 152 getContext().getString( 153 R.string.enable_auto_data_switch_dialog_message, 154 SubscriptionUtil.getUniqueSubscriptionDisplayName( 155 backupSubInfo, getContext())); 156 UserManager userManager = getUserManager(); 157 if (userManager == null) return message; 158 159 // If one of the sub is dedicated to work profile(enterprise-managed), which means we might 160 // switching between personal & work profile, append a warning to the message. 161 UserHandle ddsUserHandle = subscriptionManager.getSubscriptionUserHandle(ddsSubId); 162 UserHandle nDdsUserHandle = subscriptionManager.getSubscriptionUserHandle(mBackupDataSubId); 163 boolean isDdsManaged = ddsUserHandle != null && userManager.isManagedProfile( 164 ddsUserHandle.getIdentifier()); 165 boolean isNDdsManaged = nDdsUserHandle != null && userManager.isManagedProfile( 166 nDdsUserHandle.getIdentifier()); 167 Log.d(TAG, "isDdsManaged= " + isDdsManaged + " isNDdsManaged=" + isNDdsManaged); 168 if (isDdsManaged ^ isNDdsManaged) { 169 message += getContext().getString( 170 R.string.auto_data_switch_dialog_managed_profile_warning); 171 } 172 173 return message; 174 } 175 176 @Override updateDialog()177 public void updateDialog() { 178 updateDialog((AlertDialog) getDialog()); 179 } 180 181 @Override onClick(DialogInterface dialog, int buttonClicked)182 public void onClick(DialogInterface dialog, int buttonClicked) { 183 if (buttonClicked != DialogInterface.BUTTON_POSITIVE) { 184 return; 185 } 186 final SimDialogActivity activity = (SimDialogActivity) getActivity(); 187 if (mBackupDataSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) { 188 activity.onSubscriptionSelected(getDialogType(), mBackupDataSubId); 189 } 190 } 191 getTelephonyManagerForSub(int subId)192 private TelephonyManager getTelephonyManagerForSub(int subId) { 193 return getContext().getSystemService(TelephonyManager.class) 194 .createForSubscriptionId(subId); 195 } 196 getSubscriptionManager()197 private SubscriptionManager getSubscriptionManager() { 198 return getContext().getSystemService(SubscriptionManager.class).createForAllUserProfiles(); 199 } 200 201 @VisibleForTesting getDefaultDataSubId()202 protected int getDefaultDataSubId() { 203 return SubscriptionManager.getDefaultDataSubscriptionId(); 204 } 205 getUserManager()206 private UserManager getUserManager() { 207 return getContext().getSystemService(UserManager.class); 208 } 209 } 210