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