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.network;
18 
19 import static androidx.lifecycle.Lifecycle.Event.ON_PAUSE;
20 import static androidx.lifecycle.Lifecycle.Event.ON_RESUME;
21 
22 import android.content.Context;
23 import android.content.Intent;
24 import android.os.UserManager;
25 import android.provider.Settings;
26 import android.telephony.SubscriptionManager;
27 import android.telephony.euicc.EuiccManager;
28 
29 import androidx.lifecycle.Lifecycle;
30 import androidx.lifecycle.LifecycleObserver;
31 import androidx.lifecycle.OnLifecycleEvent;
32 import androidx.preference.Preference;
33 import androidx.preference.PreferenceScreen;
34 
35 import com.android.settings.R;
36 import com.android.settings.core.PreferenceControllerMixin;
37 import com.android.settings.dashboard.DashboardFragment;
38 import com.android.settings.network.helper.SubscriptionAnnotation;
39 import com.android.settings.network.telephony.MobileNetworkActivity;
40 import com.android.settings.overlay.FeatureFactory;
41 import com.android.settings.widget.AddPreference;
42 import com.android.settingslib.Utils;
43 import com.android.settingslib.core.AbstractPreferenceController;
44 import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
45 
46 import java.util.List;
47 import java.util.stream.Collectors;
48 
49 public class MobileNetworkSummaryController extends AbstractPreferenceController implements
50         SubscriptionsChangeListener.SubscriptionsChangeListenerClient, LifecycleObserver,
51         PreferenceControllerMixin {
52     private static final String TAG = "MobileNetSummaryCtlr";
53 
54     private static final String KEY = "mobile_network_list";
55 
56     private final MetricsFeatureProvider mMetricsFeatureProvider;
57 
58     private SubscriptionManager mSubscriptionManager;
59     private UserManager mUserManager;
60     private SubscriptionsChangeListener mChangeListener;
61     private AddPreference mPreference;
62 
63     private MobileNetworkSummaryStatus mStatusCache = new MobileNetworkSummaryStatus();
64 
65     /**
66      * This controls the summary text and click behavior of the "Mobile network" item on the
67      * Network & internet page. There are 3 separate cases depending on the number of mobile network
68      * subscriptions:
69      * <ul>
70      * <li>No subscription: click action begins a UI flow to add a network subscription, and
71      * the summary text indicates this</li>
72      *
73      * <li>One subscription: click action takes you to details for that one network, and
74      * the summary text is the network name</li>
75      *
76      * <li>More than one subscription: click action takes you to a page listing the subscriptions,
77      * and the summary text gives the count of SIMs</li>
78      * </ul>
79      */
MobileNetworkSummaryController(Context context, Lifecycle lifecycle)80     public MobileNetworkSummaryController(Context context, Lifecycle lifecycle) {
81         super(context);
82         mMetricsFeatureProvider = FeatureFactory.getFactory(mContext).getMetricsFeatureProvider();
83         mSubscriptionManager = context.getSystemService(SubscriptionManager.class);
84         mUserManager = context.getSystemService(UserManager.class);
85         if (lifecycle != null) {
86             mChangeListener = new SubscriptionsChangeListener(context, this);
87             lifecycle.addObserver(this);
88         }
89     }
90 
91     @OnLifecycleEvent(ON_RESUME)
onResume()92     public void onResume() {
93         mChangeListener.start();
94         update();
95     }
96 
97     @OnLifecycleEvent(ON_PAUSE)
onPause()98     public void onPause() {
99         mChangeListener.stop();
100     }
101 
102     @Override
displayPreference(PreferenceScreen screen)103     public void displayPreference(PreferenceScreen screen) {
104         super.displayPreference(screen);
105         mPreference = screen.findPreference(getPreferenceKey());
106     }
107 
108     @Override
getSummary()109     public CharSequence getSummary() {
110         mStatusCache.update(mContext, null);
111         List<SubscriptionAnnotation> subs = mStatusCache.getSubscriptionList();
112 
113         if (subs.isEmpty()) {
114             if (mStatusCache.isEuiccConfigSupport()) {
115                 return mContext.getResources().getString(
116                         R.string.mobile_network_summary_add_a_network);
117             }
118             // set empty string to override previous text for carrier when SIM available
119             return "";
120         } else if (subs.size() == 1) {
121             SubscriptionAnnotation info = subs.get(0);
122             CharSequence displayName = mStatusCache.getDisplayName(info.getSubscriptionId());
123             if (info.getSubInfo().isEmbedded() || info.isActive()
124                     || mStatusCache.isPhysicalSimDisableSupport()) {
125                 return displayName;
126             }
127             return mContext.getString(R.string.mobile_network_tap_to_activate, displayName);
128         } else {
129             return subs.stream()
130                     .mapToInt(SubscriptionAnnotation::getSubscriptionId)
131                     .mapToObj(subId -> mStatusCache.getDisplayName(subId))
132                     .collect(Collectors.joining(", "));
133         }
134     }
135 
logPreferenceClick(Preference preference)136     private void logPreferenceClick(Preference preference) {
137         mMetricsFeatureProvider.logClickedPreference(preference,
138                 preference.getExtras().getInt(DashboardFragment.CATEGORY));
139     }
140 
startAddSimFlow()141     private void startAddSimFlow() {
142         final Intent intent = new Intent(EuiccManager.ACTION_PROVISION_EMBEDDED_SUBSCRIPTION);
143         intent.putExtra(EuiccManager.EXTRA_FORCE_PROVISION, true);
144         mContext.startActivity(intent);
145     }
146 
initPreference()147     private void initPreference() {
148         refreshSummary(mPreference);
149         mPreference.setOnPreferenceClickListener(null);
150         mPreference.setOnAddClickListener(null);
151         mPreference.setFragment(null);
152         mPreference.setEnabled(!mChangeListener.isAirplaneModeOn());
153     }
154 
update()155     private void update() {
156         if (mPreference == null || mPreference.isDisabledByAdmin()) {
157             return;
158         }
159 
160         mStatusCache.update(mContext, statusCache -> initPreference());
161 
162         List<SubscriptionAnnotation> subs = mStatusCache.getSubscriptionList();
163         if (subs.isEmpty()) {
164             if (mStatusCache.isEuiccConfigSupport()) {
165                 mPreference.setOnPreferenceClickListener((Preference pref) -> {
166                     logPreferenceClick(pref);
167                     startAddSimFlow();
168                     return true;
169                 });
170             } else {
171                 mPreference.setEnabled(false);
172             }
173             return;
174         }
175 
176         // We have one or more existing subscriptions, so we want the plus button if eSIM is
177         // supported.
178         if (mStatusCache.isEuiccConfigSupport()) {
179             mPreference.setAddWidgetEnabled(!mChangeListener.isAirplaneModeOn());
180             mPreference.setOnAddClickListener(p -> {
181                 logPreferenceClick(p);
182                 startAddSimFlow();
183             });
184         }
185 
186         if (subs.size() == 1) {
187             mPreference.setOnPreferenceClickListener((Preference pref) -> {
188                 logPreferenceClick(pref);
189 
190                 SubscriptionAnnotation info = subs.get(0);
191                 if (info.getSubInfo().isEmbedded() || info.isActive()
192                         || mStatusCache.isPhysicalSimDisableSupport()) {
193                     final Intent intent = new Intent(mContext, MobileNetworkActivity.class);
194                     intent.putExtra(Settings.EXTRA_SUB_ID, info.getSubscriptionId());
195                     // MobileNetworkActivity is singleTask, set SplitPairRule to show in 2-pane.
196                     MobileNetworkTwoPaneUtils.registerTwoPaneForMobileNetwork(mContext, intent,
197                             null);
198                     mContext.startActivity(intent);
199                     return true;
200                 }
201 
202                 SubscriptionUtil.startToggleSubscriptionDialogActivity(
203                         mContext, info.getSubscriptionId(), true);
204                 return true;
205             });
206         } else {
207             mPreference.setFragment(MobileNetworkListFragment.class.getCanonicalName());
208         }
209     }
210 
211     @Override
isAvailable()212     public boolean isAvailable() {
213         return !Utils.isWifiOnly(mContext) && mUserManager.isAdminUser();
214     }
215 
216     @Override
getPreferenceKey()217     public String getPreferenceKey() {
218         return KEY;
219     }
220 
221     @Override
onAirplaneModeChanged(boolean airplaneModeEnabled)222     public void onAirplaneModeChanged(boolean airplaneModeEnabled) {
223         mStatusCache.update(mContext, statusCache -> update());
224     }
225 
226     @Override
onSubscriptionsChanged()227     public void onSubscriptionsChanged() {
228         mStatusCache.update(mContext, statusCache -> {
229             refreshSummary(mPreference);
230             update();
231         });
232     }
233 }
234