1 /* 2 * Copyright (C) 2024 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.network.telephony; 18 19 import static android.telephony.CarrierConfigManager.KEY_SATELLITE_ATTACH_SUPPORTED_BOOL; 20 import static android.telephony.CarrierConfigManager.KEY_SATELLITE_INFORMATION_REDIRECT_URL_STRING; 21 22 import android.app.Activity; 23 import android.app.settings.SettingsEnums; 24 import android.content.Intent; 25 import android.graphics.Typeface; 26 import android.graphics.drawable.Drawable; 27 import android.net.Uri; 28 import android.os.Bundle; 29 import android.os.PersistableBundle; 30 import android.os.UserManager; 31 import android.telephony.CarrierConfigManager; 32 import android.telephony.SubscriptionManager; 33 import android.telephony.TelephonyManager; 34 import android.telephony.satellite.SatelliteManager; 35 import android.text.SpannableString; 36 import android.text.Spanned; 37 import android.text.style.StyleSpan; 38 import android.text.style.UnderlineSpan; 39 import android.util.Log; 40 import android.view.View; 41 42 import androidx.annotation.NonNull; 43 import androidx.annotation.Nullable; 44 import androidx.preference.Preference; 45 import androidx.preference.PreferenceCategory; 46 47 import com.android.internal.telephony.flags.Flags; 48 import com.android.settings.R; 49 import com.android.settings.dashboard.RestrictedDashboardFragment; 50 import com.android.settingslib.HelpUtils; 51 import com.android.settingslib.Utils; 52 import com.android.settingslib.widget.FooterPreference; 53 54 import java.util.Set; 55 56 /** Handle Satellite Setting Preference Layout. */ 57 public class SatelliteSetting extends RestrictedDashboardFragment { 58 private static final String TAG = "SatelliteSetting"; 59 public static final String PREF_KEY_ABOUT_SATELLITE_MESSAGING = "key_about_satellite_messaging"; 60 public static final String PREF_KEY_CATEGORY_YOUR_SATELLITE_PLAN = 61 "key_category_your_satellite_plan"; 62 public static final String PREF_KEY_YOUR_SATELLITE_PLAN = "key_your_satellite_plan"; 63 public static final String PREF_KEY_CATEGORY_HOW_IT_WORKS = "key_category_how_it_works"; 64 private static final String KEY_FOOTER_PREFERENCE = "satellite_setting_extra_info_footer_pref"; 65 public static final String SUB_ID = "sub_id"; 66 67 private Activity mActivity; 68 private TelephonyManager mTelephonymanager; 69 private CarrierConfigManager mCarrierConfigManager; 70 private SatelliteManager mSatelliteManager; 71 private PersistableBundle mConfigBundle; 72 private int mSubId; 73 SatelliteSetting()74 public SatelliteSetting() { 75 super(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS); 76 } 77 78 @Override getMetricsCategory()79 public int getMetricsCategory() { 80 return SettingsEnums.SATELLITE_SETTING; 81 } 82 83 @Override onCreate(@onNull Bundle savedInstanceState)84 public void onCreate(@NonNull Bundle savedInstanceState) { 85 super.onCreate(savedInstanceState); 86 87 // In case carrier roaming satellite is not supported, do nothing. 88 if (!Flags.carrierEnabledSatelliteFlag()) { 89 Log.d(TAG, "SatelliteSettings: satellite feature is not supported, do nothing."); 90 finish(); 91 return; 92 } 93 94 mActivity = getActivity(); 95 mSubId = mActivity.getIntent().getIntExtra(SUB_ID, 96 SubscriptionManager.INVALID_SUBSCRIPTION_ID); 97 98 mCarrierConfigManager = mActivity.getSystemService(CarrierConfigManager.class); 99 if (!isSatelliteAttachSupported(mSubId)) { 100 Log.d(TAG, "SatelliteSettings: KEY_SATELLITE_ATTACH_SUPPORTED_BOOL is false, " 101 + "do nothing."); 102 finish(); 103 return; 104 } 105 106 mTelephonymanager = mActivity.getSystemService(TelephonyManager.class); 107 mSatelliteManager = mActivity.getSystemService(SatelliteManager.class); 108 } 109 110 @Override onViewCreated(@onNull View view, @Nullable Bundle savedInstanceState)111 public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { 112 super.onViewCreated(view, savedInstanceState); 113 updateDynamicPreferenceViews(); 114 } 115 116 @Override getLogTag()117 protected String getLogTag() { 118 return TAG; 119 } 120 121 @Override getPreferenceScreenResId()122 protected int getPreferenceScreenResId() { 123 return R.xml.satellite_setting; 124 } 125 updateDynamicPreferenceViews()126 private void updateDynamicPreferenceViews() { 127 String operatorName = mTelephonymanager.getSimOperatorName(mSubId); 128 boolean isSatelliteEligible = isSatelliteEligible(); 129 130 // About satellite messaging 131 Preference preference = findPreference(PREF_KEY_ABOUT_SATELLITE_MESSAGING); 132 preference.setTitle( 133 getResources().getString(R.string.title_about_satellite_setting, operatorName)); 134 135 // Your mobile plan 136 PreferenceCategory prefCategory = findPreference(PREF_KEY_CATEGORY_YOUR_SATELLITE_PLAN); 137 prefCategory.setTitle(getResources().getString(R.string.category_title_your_satellite_plan, 138 operatorName)); 139 140 preference = findPreference(PREF_KEY_YOUR_SATELLITE_PLAN); 141 Drawable icon; 142 if (isSatelliteEligible) { 143 /* In case satellite is allowed by carrier's entitlement server, the page will show 144 the check icon with guidance that satellite is included in user's mobile plan */ 145 preference.setTitle(R.string.title_have_satellite_plan); 146 icon = getResources().getDrawable(R.drawable.ic_check_circle_24px); 147 } else { 148 /* Or, it will show the blocked icon with the guidance that satellite is not included 149 in user's mobile plan */ 150 preference.setTitle(R.string.title_no_satellite_plan); 151 /* And, the link url provides more information via web page will be shown */ 152 SpannableString spannable = new SpannableString( 153 getResources().getString(R.string.summary_add_satellite_setting)); 154 spannable.setSpan(new UnderlineSpan(), 0, spannable.length(), 155 Spanned.SPAN_INCLUSIVE_INCLUSIVE); 156 spannable.setSpan(new StyleSpan(Typeface.BOLD), 0, spannable.length(), 157 Spanned.SPAN_INCLUSIVE_INCLUSIVE); 158 preference.setSummary(spannable); 159 /* The link will lead users to a guide page */ 160 preference.setOnPreferenceClickListener(pref -> { 161 String url = readSatelliteMoreInfoString(mSubId); 162 if (!url.isEmpty()) { 163 Uri uri = Uri.parse(url); 164 Intent intent = new Intent(Intent.ACTION_VIEW, uri); 165 startActivity(intent); 166 } 167 return true; 168 }); 169 icon = getResources().getDrawable(R.drawable.ic_block_24px); 170 } 171 icon.setTintList(Utils.getColorAttr(getContext(), android.R.attr.textColorPrimary)); 172 preference.setIcon(icon); 173 174 /* Composes "How it works" section, which guides how users can use satellite messaging, when 175 satellite messaging is included in user's mobile plan, or it'll will be grey out. */ 176 if (!isSatelliteEligible) { 177 PreferenceCategory category = findPreference(PREF_KEY_CATEGORY_HOW_IT_WORKS); 178 category.setEnabled(false); 179 category.setShouldDisableView(true); 180 } 181 182 // More about satellite messaging 183 FooterPreference footerPreference = findPreference(KEY_FOOTER_PREFERENCE); 184 if (footerPreference != null) { 185 footerPreference.setSummary( 186 getResources().getString(R.string.satellite_setting_summary_more_information, 187 operatorName)); 188 189 final String[] link = new String[1]; 190 link[0] = readSatelliteMoreInfoString(mSubId); 191 footerPreference.setLearnMoreAction(view -> { 192 if (!link[0].isEmpty()) { 193 Intent helpIntent = HelpUtils.getHelpIntent(mActivity, link[0], 194 this.getClass().getName()); 195 if (helpIntent != null) { 196 mActivity.startActivityForResult(helpIntent, /*requestCode=*/ 0); 197 } 198 } 199 }); 200 footerPreference.setLearnMoreText( 201 getResources().getString(R.string.more_about_satellite_messaging)); 202 203 // TODO : b/320467418 add rounded rectangle border line to footer preference. 204 } 205 } 206 isSatelliteEligible()207 private boolean isSatelliteEligible() { 208 try { 209 Set<Integer> restrictionReason = 210 mSatelliteManager.getAttachRestrictionReasonsForCarrier(mSubId); 211 return !restrictionReason.contains( 212 SatelliteManager.SATELLITE_COMMUNICATION_RESTRICTION_REASON_ENTITLEMENT); 213 } catch (SecurityException | IllegalStateException | IllegalArgumentException ex) { 214 loge(ex.toString()); 215 return false; 216 } 217 } 218 readSatelliteMoreInfoString(int subId)219 private String readSatelliteMoreInfoString(int subId) { 220 if (mConfigBundle == null) { 221 mConfigBundle = mCarrierConfigManager.getConfigForSubId(subId, 222 KEY_SATELLITE_INFORMATION_REDIRECT_URL_STRING); 223 if (mConfigBundle.isEmpty()) { 224 Log.d(TAG, "SatelliteSettings: getDefaultConfig"); 225 mConfigBundle = CarrierConfigManager.getDefaultConfig(); 226 } 227 } 228 return mConfigBundle.getString(KEY_SATELLITE_INFORMATION_REDIRECT_URL_STRING, ""); 229 } 230 isSatelliteAttachSupported(int subId)231 private boolean isSatelliteAttachSupported(int subId) { 232 PersistableBundle bundle = mCarrierConfigManager.getConfigForSubId(subId, 233 KEY_SATELLITE_ATTACH_SUPPORTED_BOOL); 234 if (bundle.isEmpty()) { 235 Log.d(TAG, "SatelliteSettings: getDefaultConfig"); 236 bundle = CarrierConfigManager.getDefaultConfig(); 237 } 238 return bundle.getBoolean(KEY_SATELLITE_ATTACH_SUPPORTED_BOOL, false); 239 } 240 loge(String message)241 private static void loge(String message) { 242 Log.e(TAG, message); 243 } 244 } 245