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 package com.android.systemui.qs.tiles.dialog;
17 
18 import static com.android.settingslib.satellite.SatelliteDialogUtils.TYPE_IS_WIFI;
19 import static com.android.systemui.Prefs.Key.QS_HAS_TURNED_OFF_MOBILE_DATA;
20 import static com.android.systemui.qs.tiles.dialog.InternetDialogController.MAX_WIFI_ENTRY_COUNT;
21 
22 import android.app.AlertDialog;
23 import android.content.Context;
24 import android.graphics.drawable.Drawable;
25 import android.net.Network;
26 import android.net.NetworkCapabilities;
27 import android.os.Bundle;
28 import android.os.Handler;
29 import android.telephony.ServiceState;
30 import android.telephony.SignalStrength;
31 import android.telephony.SubscriptionManager;
32 import android.telephony.TelephonyDisplayInfo;
33 import android.telephony.TelephonyManager;
34 import android.text.Html;
35 import android.text.Layout;
36 import android.text.TextUtils;
37 import android.text.method.LinkMovementMethod;
38 import android.util.Log;
39 import android.view.Gravity;
40 import android.view.LayoutInflater;
41 import android.view.View;
42 import android.view.ViewStub;
43 import android.view.Window;
44 import android.view.WindowManager;
45 import android.widget.Button;
46 import android.widget.ImageView;
47 import android.widget.LinearLayout;
48 import android.widget.ProgressBar;
49 import android.widget.Switch;
50 import android.widget.TextView;
51 
52 import androidx.annotation.MainThread;
53 import androidx.annotation.Nullable;
54 import androidx.annotation.VisibleForTesting;
55 import androidx.annotation.WorkerThread;
56 import androidx.recyclerview.widget.LinearLayoutManager;
57 import androidx.recyclerview.widget.RecyclerView;
58 
59 import com.android.internal.logging.UiEvent;
60 import com.android.internal.logging.UiEventLogger;
61 import com.android.internal.telephony.flags.Flags;
62 import com.android.settingslib.satellite.SatelliteDialogUtils;
63 import com.android.settingslib.wifi.WifiEnterpriseRestrictionUtils;
64 import com.android.systemui.Prefs;
65 import com.android.systemui.accessibility.floatingmenu.AnnotationLinkSpan;
66 import com.android.systemui.animation.DialogTransitionAnimator;
67 import com.android.systemui.dagger.qualifiers.Background;
68 import com.android.systemui.dagger.qualifiers.Main;
69 import com.android.systemui.res.R;
70 import com.android.systemui.statusbar.phone.SystemUIDialog;
71 import com.android.systemui.statusbar.policy.KeyguardStateController;
72 import com.android.wifitrackerlib.WifiEntry;
73 
74 import dagger.assisted.Assisted;
75 import dagger.assisted.AssistedFactory;
76 import dagger.assisted.AssistedInject;
77 
78 import kotlinx.coroutines.CoroutineScope;
79 import kotlinx.coroutines.Job;
80 
81 import java.util.List;
82 import java.util.concurrent.Executor;
83 
84 /**
85  * Dialog for showing mobile network, connected Wi-Fi network and Wi-Fi networks.
86  */
87 public class InternetDialogDelegate implements
88         SystemUIDialog.Delegate,
89         InternetDialogController.InternetDialogCallback {
90     private static final String TAG = "InternetDialog";
91     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
92 
93     private static final String ABOVE_STATUS_BAR = "above_status_bar";
94     private static final String CAN_CONFIG_MOBILE_DATA = "can_config_mobile_data";
95     private static final String CAN_CONFIG_WIFI = "can_config_wifi";
96 
97     static final int MAX_NETWORK_COUNT = 4;
98 
99     private final Handler mHandler;
100     private final Executor mBackgroundExecutor;
101     private final DialogTransitionAnimator mDialogTransitionAnimator;
102     private final boolean mAboveStatusBar;
103     private final SystemUIDialog.Factory mSystemUIDialogFactory;
104 
105     @VisibleForTesting
106     protected InternetAdapter mAdapter;
107     @VisibleForTesting
108     protected View mDialogView;
109     @VisibleForTesting
110     protected boolean mCanConfigWifi;
111 
112     private final InternetDialogManager mInternetDialogManager;
113     private TelephonyManager mTelephonyManager;
114     @Nullable
115     private AlertDialog mAlertDialog;
116     private final UiEventLogger mUiEventLogger;
117     private final InternetDialogController mInternetDialogController;
118     private TextView mInternetDialogTitle;
119     private TextView mInternetDialogSubTitle;
120     private View mDivider;
121     private ProgressBar mProgressBar;
122     private LinearLayout mConnectedWifListLayout;
123     private LinearLayout mMobileNetworkLayout;
124     private LinearLayout mSecondaryMobileNetworkLayout;
125     private LinearLayout mTurnWifiOnLayout;
126     private LinearLayout mEthernetLayout;
127     private TextView mWifiToggleTitleText;
128     private LinearLayout mWifiScanNotifyLayout;
129     private TextView mWifiScanNotifyText;
130     private LinearLayout mSeeAllLayout;
131     private RecyclerView mWifiRecyclerView;
132     private ImageView mConnectedWifiIcon;
133     private ImageView mWifiSettingsIcon;
134     private TextView mConnectedWifiTitleText;
135     private TextView mConnectedWifiSummaryText;
136     private ImageView mSignalIcon;
137     private TextView mMobileTitleText;
138     private TextView mMobileSummaryText;
139     private TextView mAirplaneModeSummaryText;
140     private Switch mMobileDataToggle;
141     private View mMobileToggleDivider;
142     private Switch mWiFiToggle;
143     private Button mDoneButton;
144 
145     @VisibleForTesting
146     protected Button mShareWifiButton;
147     private Button mAirplaneModeButton;
148     private Drawable mBackgroundOn;
149     private final KeyguardStateController mKeyguard;
150     @Nullable
151     private Drawable mBackgroundOff = null;
152     private int mDefaultDataSubId;
153     private final boolean mCanConfigMobileData;
154     private final boolean mCanChangeWifiState;
155     // Wi-Fi entries
156     private int mWifiNetworkHeight;
157     @Nullable
158     @VisibleForTesting
159     protected WifiEntry mConnectedWifiEntry;
160     @VisibleForTesting
161     protected int mWifiEntriesCount;
162     @VisibleForTesting
163     protected boolean mHasMoreWifiEntries;
164 
165     // Wi-Fi scanning progress bar
166     protected boolean mIsProgressBarVisible;
167     private SystemUIDialog mDialog;
168     private final CoroutineScope mCoroutineScope;
169     @Nullable
170     private Job mClickJob;
171 
172     @AssistedFactory
173     public interface Factory {
create( @ssistedABOVE_STATUS_BAR) boolean aboveStatusBar, @Assisted(CAN_CONFIG_MOBILE_DATA) boolean canConfigMobileData, @Assisted(CAN_CONFIG_WIFI) boolean canConfigWifi, @Assisted CoroutineScope coroutineScope)174         InternetDialogDelegate create(
175                 @Assisted(ABOVE_STATUS_BAR) boolean aboveStatusBar,
176                 @Assisted(CAN_CONFIG_MOBILE_DATA) boolean canConfigMobileData,
177                 @Assisted(CAN_CONFIG_WIFI) boolean canConfigWifi,
178                 @Assisted CoroutineScope coroutineScope);
179     }
180 
181     @AssistedInject
InternetDialogDelegate( Context context, InternetDialogManager internetDialogManager, InternetDialogController internetDialogController, @Assisted(ABOVE_STATUS_BAR) boolean canConfigMobileData, @Assisted(CAN_CONFIG_MOBILE_DATA) boolean canConfigWifi, @Assisted(CAN_CONFIG_WIFI) boolean aboveStatusBar, @Assisted CoroutineScope coroutineScope, UiEventLogger uiEventLogger, DialogTransitionAnimator dialogTransitionAnimator, @Main Handler handler, @Background Executor executor, KeyguardStateController keyguardStateController, SystemUIDialog.Factory systemUIDialogFactory)182     public InternetDialogDelegate(
183             Context context,
184             InternetDialogManager internetDialogManager,
185             InternetDialogController internetDialogController,
186             @Assisted(ABOVE_STATUS_BAR) boolean canConfigMobileData,
187             @Assisted(CAN_CONFIG_MOBILE_DATA) boolean canConfigWifi,
188             @Assisted(CAN_CONFIG_WIFI) boolean aboveStatusBar,
189             @Assisted CoroutineScope coroutineScope,
190             UiEventLogger uiEventLogger,
191             DialogTransitionAnimator dialogTransitionAnimator,
192             @Main Handler handler,
193             @Background Executor executor,
194             KeyguardStateController keyguardStateController,
195             SystemUIDialog.Factory systemUIDialogFactory) {
196         mAboveStatusBar = aboveStatusBar;
197         mSystemUIDialogFactory = systemUIDialogFactory;
198         if (DEBUG) {
199             Log.d(TAG, "Init InternetDialog");
200         }
201 
202         // Save the context that is wrapped with our theme.
203         mHandler = handler;
204         mBackgroundExecutor = executor;
205         mInternetDialogManager = internetDialogManager;
206         mInternetDialogController = internetDialogController;
207         mDefaultDataSubId = mInternetDialogController.getDefaultDataSubscriptionId();
208         mTelephonyManager = mInternetDialogController.getTelephonyManager();
209         mCanConfigMobileData = canConfigMobileData;
210         mCanConfigWifi = canConfigWifi;
211         mCanChangeWifiState = WifiEnterpriseRestrictionUtils.isChangeWifiStateAllowed(context);
212         mKeyguard = keyguardStateController;
213         mCoroutineScope = coroutineScope;
214         mUiEventLogger = uiEventLogger;
215         mDialogTransitionAnimator = dialogTransitionAnimator;
216         mAdapter = new InternetAdapter(mInternetDialogController, coroutineScope);
217     }
218 
219     @Override
createDialog()220     public SystemUIDialog createDialog() {
221         SystemUIDialog dialog = mSystemUIDialogFactory.create(this);
222         if (!mAboveStatusBar) {
223             dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY);
224         }
225 
226         if (mDialog != null) {
227             mDialog.dismiss();
228         }
229         mDialog = dialog;
230 
231         return dialog;
232     }
233 
234     @Override
onCreate(SystemUIDialog dialog, Bundle savedInstanceState)235     public void onCreate(SystemUIDialog dialog, Bundle savedInstanceState) {
236         if (DEBUG) {
237             Log.d(TAG, "onCreate");
238         }
239         Context context = dialog.getContext();
240         mUiEventLogger.log(InternetDialogEvent.INTERNET_DIALOG_SHOW);
241         mDialogView = LayoutInflater.from(context).inflate(
242                 R.layout.internet_connectivity_dialog, null);
243         mDialogView.setAccessibilityPaneTitle(
244                 context.getText(R.string.accessibility_desc_quick_settings));
245         final Window window = dialog.getWindow();
246         window.setContentView(mDialogView);
247 
248         window.setWindowAnimations(R.style.Animation_InternetDialog);
249 
250         mWifiNetworkHeight = context.getResources()
251                 .getDimensionPixelSize(R.dimen.internet_dialog_wifi_network_height);
252 
253         mInternetDialogTitle = mDialogView.requireViewById(R.id.internet_dialog_title);
254         mInternetDialogSubTitle = mDialogView.requireViewById(R.id.internet_dialog_subtitle);
255         mDivider = mDialogView.requireViewById(R.id.divider);
256         mProgressBar = mDialogView.requireViewById(R.id.wifi_searching_progress);
257         mEthernetLayout = mDialogView.requireViewById(R.id.ethernet_layout);
258         mMobileNetworkLayout = mDialogView.requireViewById(R.id.mobile_network_layout);
259         mTurnWifiOnLayout = mDialogView.requireViewById(R.id.turn_on_wifi_layout);
260         mWifiToggleTitleText = mDialogView.requireViewById(R.id.wifi_toggle_title);
261         mWifiScanNotifyLayout = mDialogView.requireViewById(R.id.wifi_scan_notify_layout);
262         mWifiScanNotifyText = mDialogView.requireViewById(R.id.wifi_scan_notify_text);
263         mConnectedWifListLayout = mDialogView.requireViewById(R.id.wifi_connected_layout);
264         mConnectedWifiIcon = mDialogView.requireViewById(R.id.wifi_connected_icon);
265         mConnectedWifiTitleText = mDialogView.requireViewById(R.id.wifi_connected_title);
266         mConnectedWifiSummaryText = mDialogView.requireViewById(R.id.wifi_connected_summary);
267         mWifiSettingsIcon = mDialogView.requireViewById(R.id.wifi_settings_icon);
268         mWifiRecyclerView = mDialogView.requireViewById(R.id.wifi_list_layout);
269         mSeeAllLayout = mDialogView.requireViewById(R.id.see_all_layout);
270         mDoneButton = mDialogView.requireViewById(R.id.done_button);
271         mShareWifiButton = mDialogView.requireViewById(R.id.share_wifi_button);
272         mAirplaneModeButton = mDialogView.requireViewById(R.id.apm_button);
273         mSignalIcon = mDialogView.requireViewById(R.id.signal_icon);
274         mMobileTitleText = mDialogView.requireViewById(R.id.mobile_title);
275         mMobileSummaryText = mDialogView.requireViewById(R.id.mobile_summary);
276         mAirplaneModeSummaryText = mDialogView.requireViewById(R.id.airplane_mode_summary);
277         mMobileToggleDivider = mDialogView.requireViewById(R.id.mobile_toggle_divider);
278         mMobileDataToggle = mDialogView.requireViewById(R.id.mobile_toggle);
279         mWiFiToggle = mDialogView.requireViewById(R.id.wifi_toggle);
280         mBackgroundOn = context.getDrawable(R.drawable.settingslib_switch_bar_bg_on);
281         mInternetDialogTitle.setText(getDialogTitleText());
282         mInternetDialogTitle.setGravity(Gravity.START | Gravity.CENTER_VERTICAL);
283         mBackgroundOff = context.getDrawable(R.drawable.internet_dialog_selected_effect);
284         setOnClickListener(dialog);
285         mTurnWifiOnLayout.setBackground(null);
286         mAirplaneModeButton.setVisibility(
287                 mInternetDialogController.isAirplaneModeEnabled() ? View.VISIBLE : View.GONE);
288         mWifiRecyclerView.setLayoutManager(new LinearLayoutManager(context));
289         mWifiRecyclerView.setAdapter(mAdapter);
290     }
291 
292     @Override
onStart(SystemUIDialog dialog)293     public void onStart(SystemUIDialog dialog) {
294         if (DEBUG) {
295             Log.d(TAG, "onStart");
296         }
297         mInternetDialogController.onStart(this, mCanConfigWifi);
298         if (!mCanConfigWifi) {
299             hideWifiViews();
300         }
301     }
302 
303     @VisibleForTesting
hideWifiViews()304     void hideWifiViews() {
305         setProgressBarVisible(false);
306         mTurnWifiOnLayout.setVisibility(View.GONE);
307         mConnectedWifListLayout.setVisibility(View.GONE);
308         mWifiRecyclerView.setVisibility(View.GONE);
309         mSeeAllLayout.setVisibility(View.GONE);
310         mShareWifiButton.setVisibility(View.GONE);
311     }
312 
313     @Override
onStop(SystemUIDialog dialog)314     public void onStop(SystemUIDialog dialog) {
315         if (DEBUG) {
316             Log.d(TAG, "onStop");
317         }
318         mMobileNetworkLayout.setOnClickListener(null);
319         mConnectedWifListLayout.setOnClickListener(null);
320         if (mSecondaryMobileNetworkLayout != null) {
321             mSecondaryMobileNetworkLayout.setOnClickListener(null);
322         }
323         mSeeAllLayout.setOnClickListener(null);
324         mWiFiToggle.setOnCheckedChangeListener(null);
325         mDoneButton.setOnClickListener(null);
326         mShareWifiButton.setOnClickListener(null);
327         mAirplaneModeButton.setOnClickListener(null);
328         mInternetDialogController.onStop();
329         mInternetDialogManager.destroyDialog();
330     }
331 
332     @Override
dismissDialog()333     public void dismissDialog() {
334         if (DEBUG) {
335             Log.d(TAG, "dismissDialog");
336         }
337         mInternetDialogManager.destroyDialog();
338         if (mDialog != null) {
339             mDialog.dismiss();
340             mDialog = null;
341         }
342     }
343 
344     /**
345      * Update the internet dialog when receiving the callback.
346      *
347      * @param shouldUpdateMobileNetwork {@code true} for update the mobile network layout,
348      *                                  otherwise {@code false}.
349      */
updateDialog(boolean shouldUpdateMobileNetwork)350     void updateDialog(boolean shouldUpdateMobileNetwork) {
351         if (DEBUG) {
352             Log.d(TAG, "updateDialog");
353         }
354         mInternetDialogTitle.setText(getDialogTitleText());
355         mInternetDialogSubTitle.setText(getSubtitleText());
356         mAirplaneModeButton.setVisibility(
357                 mInternetDialogController.isAirplaneModeEnabled() ? View.VISIBLE : View.GONE);
358 
359         updateEthernet();
360         if (shouldUpdateMobileNetwork) {
361             setMobileDataLayout(mInternetDialogController.activeNetworkIsCellular(),
362                     mInternetDialogController.isCarrierNetworkActive());
363         }
364 
365         if (!mCanConfigWifi) {
366             return;
367         }
368 
369         final boolean isDeviceLocked = mInternetDialogController.isDeviceLocked();
370         final boolean isWifiEnabled = mInternetDialogController.isWifiEnabled();
371         final boolean isWifiScanEnabled = mInternetDialogController.isWifiScanEnabled();
372         updateWifiToggle(isWifiEnabled, isDeviceLocked);
373         updateConnectedWifi(isWifiEnabled, isDeviceLocked);
374         updateWifiListAndSeeAll(isWifiEnabled, isDeviceLocked);
375         updateWifiScanNotify(isWifiEnabled, isWifiScanEnabled, isDeviceLocked);
376     }
377 
setOnClickListener(SystemUIDialog dialog)378     private void setOnClickListener(SystemUIDialog dialog) {
379         mMobileNetworkLayout.setOnClickListener(v -> {
380             int autoSwitchNonDdsSubId = mInternetDialogController.getActiveAutoSwitchNonDdsSubId();
381             if (autoSwitchNonDdsSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
382                 showTurnOffAutoDataSwitchDialog(dialog, autoSwitchNonDdsSubId);
383             }
384             mInternetDialogController.connectCarrierNetwork();
385         });
386         mMobileDataToggle.setOnClickListener(v -> {
387             boolean isChecked = mMobileDataToggle.isChecked();
388             if (!isChecked && shouldShowMobileDialog()) {
389                 mMobileDataToggle.setChecked(true);
390                 showTurnOffMobileDialog(dialog);
391             } else if (mInternetDialogController.isMobileDataEnabled() != isChecked) {
392                 mInternetDialogController.setMobileDataEnabled(
393                         dialog.getContext(), mDefaultDataSubId, isChecked, false);
394             }
395         });
396         mConnectedWifListLayout.setOnClickListener(this::onClickConnectedWifi);
397         mSeeAllLayout.setOnClickListener(this::onClickSeeMoreButton);
398         mWiFiToggle.setOnClickListener(v -> {
399             handleWifiToggleClicked(mWiFiToggle.isChecked());
400         });
401         mDoneButton.setOnClickListener(v -> dialog.dismiss());
402         mShareWifiButton.setOnClickListener(v -> {
403             if (mInternetDialogController.mayLaunchShareWifiSettings(mConnectedWifiEntry, v)) {
404                 mUiEventLogger.log(InternetDialogEvent.SHARE_WIFI_QS_BUTTON_CLICKED);
405             }
406         });
407         mAirplaneModeButton.setOnClickListener(v -> {
408             mInternetDialogController.setAirplaneModeDisabled();
409         });
410     }
411 
handleWifiToggleClicked(boolean isChecked)412     private void handleWifiToggleClicked(boolean isChecked) {
413         if (Flags.oemEnabledSatelliteFlag()) {
414             if (mClickJob != null && !mClickJob.isCompleted()) {
415                 return;
416             }
417             mClickJob = SatelliteDialogUtils.mayStartSatelliteWarningDialog(
418                     mDialog.getContext(), mCoroutineScope, TYPE_IS_WIFI, isAllowClick -> {
419                         if (isAllowClick) {
420                             setWifiEnable(isChecked);
421                         } else {
422                             mWiFiToggle.setChecked(!isChecked);
423                         }
424                         return null;
425                     });
426             return;
427         }
428         setWifiEnable(isChecked);
429     }
430 
setWifiEnable(boolean isChecked)431     private void setWifiEnable(boolean isChecked) {
432         if (mInternetDialogController.isWifiEnabled() == isChecked) {
433             return;
434         }
435         mInternetDialogController.setWifiEnabled(isChecked);
436     }
437 
438     @MainThread
updateEthernet()439     private void updateEthernet() {
440         mEthernetLayout.setVisibility(
441                 mInternetDialogController.hasEthernet() ? View.VISIBLE : View.GONE);
442     }
443 
setMobileDataLayout(boolean activeNetworkIsCellular, boolean isCarrierNetworkActive)444     private void setMobileDataLayout(boolean activeNetworkIsCellular,
445             boolean isCarrierNetworkActive) {
446 
447         if (mDialog != null) {
448             setMobileDataLayout(mDialog, activeNetworkIsCellular, isCarrierNetworkActive);
449         }
450     }
451 
setMobileDataLayout(SystemUIDialog dialog, boolean activeNetworkIsCellular, boolean isCarrierNetworkActive)452     private void setMobileDataLayout(SystemUIDialog dialog, boolean activeNetworkIsCellular,
453             boolean isCarrierNetworkActive) {
454         boolean isNetworkConnected = activeNetworkIsCellular || isCarrierNetworkActive;
455         // 1. Mobile network should be gone if airplane mode ON or the list of active
456         //    subscriptionId is null.
457         // 2. Carrier network should be gone if airplane mode ON and Wi-Fi is OFF.
458         if (DEBUG) {
459             Log.d(TAG, "setMobileDataLayout, isCarrierNetworkActive = " + isCarrierNetworkActive);
460         }
461 
462         boolean isWifiEnabled = mInternetDialogController.isWifiEnabled();
463         if (!mInternetDialogController.hasActiveSubIdOnDds()
464                 && (!isWifiEnabled || !isCarrierNetworkActive)) {
465             mMobileNetworkLayout.setVisibility(View.GONE);
466             if (mSecondaryMobileNetworkLayout != null) {
467                 mSecondaryMobileNetworkLayout.setVisibility(View.GONE);
468             }
469         } else {
470             mMobileNetworkLayout.setVisibility(View.VISIBLE);
471             mMobileDataToggle.setChecked(mInternetDialogController.isMobileDataEnabled());
472             mMobileTitleText.setText(getMobileNetworkTitle(mDefaultDataSubId));
473             String summary = getMobileNetworkSummary(mDefaultDataSubId);
474             if (!TextUtils.isEmpty(summary)) {
475                 mMobileSummaryText.setText(
476                         Html.fromHtml(summary, Html.FROM_HTML_MODE_LEGACY));
477                 mMobileSummaryText.setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE);
478                 mMobileSummaryText.setVisibility(View.VISIBLE);
479             } else {
480                 mMobileSummaryText.setVisibility(View.GONE);
481             }
482             mBackgroundExecutor.execute(() -> {
483                 Drawable drawable = getSignalStrengthDrawable(mDefaultDataSubId);
484                 mHandler.post(() -> {
485                     mSignalIcon.setImageDrawable(drawable);
486                 });
487             });
488 
489             mMobileDataToggle.setVisibility(mCanConfigMobileData ? View.VISIBLE : View.INVISIBLE);
490             mMobileToggleDivider.setVisibility(
491                     mCanConfigMobileData ? View.VISIBLE : View.INVISIBLE);
492             int primaryColor = isNetworkConnected
493                     ? R.color.connected_network_primary_color
494                     : R.color.disconnected_network_primary_color;
495             mMobileToggleDivider.setBackgroundColor(dialog.getContext().getColor(primaryColor));
496 
497             // Display the info for the non-DDS if it's actively being used
498             int autoSwitchNonDdsSubId = mInternetDialogController.getActiveAutoSwitchNonDdsSubId();
499             int nonDdsVisibility = autoSwitchNonDdsSubId
500                     != SubscriptionManager.INVALID_SUBSCRIPTION_ID ? View.VISIBLE : View.GONE;
501 
502             int secondaryRes = isNetworkConnected
503                     ? R.style.TextAppearance_InternetDialog_Secondary_Active
504                     : R.style.TextAppearance_InternetDialog_Secondary;
505             if (nonDdsVisibility == View.VISIBLE) {
506                 // non DDS is the currently active sub, set primary visual for it
507                 ViewStub stub = mDialogView.findViewById(R.id.secondary_mobile_network_stub);
508                 if (stub != null) {
509                     stub.inflate();
510                 }
511                 mSecondaryMobileNetworkLayout = dialog.findViewById(
512                         R.id.secondary_mobile_network_layout);
513                 mSecondaryMobileNetworkLayout.setOnClickListener(
514                         this::onClickConnectedSecondarySub);
515                 mSecondaryMobileNetworkLayout.setBackground(mBackgroundOn);
516 
517                 TextView mSecondaryMobileTitleText = mDialogView.requireViewById(
518                         R.id.secondary_mobile_title);
519                 mSecondaryMobileTitleText.setText(getMobileNetworkTitle(autoSwitchNonDdsSubId));
520                 mSecondaryMobileTitleText.setTextAppearance(
521                         R.style.TextAppearance_InternetDialog_Active);
522 
523                 TextView mSecondaryMobileSummaryText =
524                         mDialogView.requireViewById(R.id.secondary_mobile_summary);
525                 summary = getMobileNetworkSummary(autoSwitchNonDdsSubId);
526                 if (!TextUtils.isEmpty(summary)) {
527                     mSecondaryMobileSummaryText.setText(
528                             Html.fromHtml(summary, Html.FROM_HTML_MODE_LEGACY));
529                     mSecondaryMobileSummaryText.setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE);
530                     mSecondaryMobileSummaryText.setTextAppearance(
531                             R.style.TextAppearance_InternetDialog_Active);
532                 }
533 
534                 ImageView mSecondarySignalIcon =
535                         mDialogView.requireViewById(R.id.secondary_signal_icon);
536                 mBackgroundExecutor.execute(() -> {
537                     Drawable drawable = getSignalStrengthDrawable(autoSwitchNonDdsSubId);
538                     mHandler.post(() -> {
539                         mSecondarySignalIcon.setImageDrawable(drawable);
540                     });
541                 });
542 
543                 ImageView mSecondaryMobileSettingsIcon =
544                         mDialogView.requireViewById(R.id.secondary_settings_icon);
545                 mSecondaryMobileSettingsIcon.setColorFilter(
546                         dialog.getContext().getColor(R.color.connected_network_primary_color));
547 
548                 // set secondary visual for default data sub
549                 mMobileNetworkLayout.setBackground(mBackgroundOff);
550                 mMobileTitleText.setTextAppearance(R.style.TextAppearance_InternetDialog);
551                 mMobileSummaryText.setTextAppearance(
552                         R.style.TextAppearance_InternetDialog_Secondary);
553                 mSignalIcon.setColorFilter(
554                         dialog.getContext().getColor(R.color.connected_network_secondary_color));
555             } else {
556                 mMobileNetworkLayout.setBackground(
557                         isNetworkConnected ? mBackgroundOn : mBackgroundOff);
558                 mMobileTitleText.setTextAppearance(isNetworkConnected
559                         ?
560                         R.style.TextAppearance_InternetDialog_Active
561                         : R.style.TextAppearance_InternetDialog);
562                 mMobileSummaryText.setTextAppearance(secondaryRes);
563             }
564 
565             if (mSecondaryMobileNetworkLayout != null) {
566                 mSecondaryMobileNetworkLayout.setVisibility(nonDdsVisibility);
567             }
568 
569             // Set airplane mode to the summary for carrier network
570             if (mInternetDialogController.isAirplaneModeEnabled()) {
571                 mAirplaneModeSummaryText.setVisibility(View.VISIBLE);
572                 mAirplaneModeSummaryText.setText(
573                         dialog.getContext().getText(R.string.airplane_mode));
574                 mAirplaneModeSummaryText.setTextAppearance(secondaryRes);
575             } else {
576                 mAirplaneModeSummaryText.setVisibility(View.GONE);
577             }
578         }
579     }
580 
581     @MainThread
updateWifiToggle(boolean isWifiEnabled, boolean isDeviceLocked)582     private void updateWifiToggle(boolean isWifiEnabled, boolean isDeviceLocked) {
583         if (mWiFiToggle.isChecked() != isWifiEnabled) {
584             mWiFiToggle.setChecked(isWifiEnabled);
585         }
586         if (isDeviceLocked) {
587             mWifiToggleTitleText.setTextAppearance((mConnectedWifiEntry != null)
588                     ? R.style.TextAppearance_InternetDialog_Active
589                     : R.style.TextAppearance_InternetDialog);
590         }
591         mTurnWifiOnLayout.setBackground(
592                 (isDeviceLocked && mConnectedWifiEntry != null) ? mBackgroundOn : null);
593 
594         if (!mCanChangeWifiState && mWiFiToggle.isEnabled()) {
595             mWiFiToggle.setEnabled(false);
596             mWifiToggleTitleText.setEnabled(false);
597             final TextView summaryText = mDialogView.requireViewById(R.id.wifi_toggle_summary);
598             summaryText.setEnabled(false);
599             summaryText.setVisibility(View.VISIBLE);
600         }
601     }
602 
603     @MainThread
updateConnectedWifi(boolean isWifiEnabled, boolean isDeviceLocked)604     private void updateConnectedWifi(boolean isWifiEnabled, boolean isDeviceLocked) {
605         if (mDialog == null || !isWifiEnabled || mConnectedWifiEntry == null || isDeviceLocked) {
606             mConnectedWifListLayout.setVisibility(View.GONE);
607             mShareWifiButton.setVisibility(View.GONE);
608             return;
609         }
610         mConnectedWifListLayout.setVisibility(View.VISIBLE);
611         mConnectedWifiTitleText.setText(mConnectedWifiEntry.getTitle());
612         mConnectedWifiSummaryText.setText(mConnectedWifiEntry.getSummary(false));
613         mConnectedWifiIcon.setImageDrawable(
614                 mInternetDialogController.getInternetWifiDrawable(mConnectedWifiEntry));
615         mWifiSettingsIcon.setColorFilter(
616                 mDialog.getContext().getColor(R.color.connected_network_primary_color));
617         if (mInternetDialogController.getConfiguratorQrCodeGeneratorIntentOrNull(
618                 mConnectedWifiEntry) != null) {
619             mShareWifiButton.setVisibility(View.VISIBLE);
620         } else {
621             mShareWifiButton.setVisibility(View.GONE);
622         }
623 
624         if (mSecondaryMobileNetworkLayout != null) {
625             mSecondaryMobileNetworkLayout.setVisibility(View.GONE);
626         }
627     }
628 
629     @MainThread
updateWifiListAndSeeAll(boolean isWifiEnabled, boolean isDeviceLocked)630     private void updateWifiListAndSeeAll(boolean isWifiEnabled, boolean isDeviceLocked) {
631         if (!isWifiEnabled || isDeviceLocked) {
632             mWifiRecyclerView.setVisibility(View.GONE);
633             mSeeAllLayout.setVisibility(View.GONE);
634             return;
635         }
636         final int wifiListMaxCount = getWifiListMaxCount();
637         if (mAdapter.getItemCount() > wifiListMaxCount) {
638             mHasMoreWifiEntries = true;
639         }
640         mAdapter.setMaxEntriesCount(wifiListMaxCount);
641         final int wifiListMinHeight = mWifiNetworkHeight * wifiListMaxCount;
642         if (mWifiRecyclerView.getMinimumHeight() != wifiListMinHeight) {
643             mWifiRecyclerView.setMinimumHeight(wifiListMinHeight);
644         }
645         mWifiRecyclerView.setVisibility(View.VISIBLE);
646         mSeeAllLayout.setVisibility(mHasMoreWifiEntries ? View.VISIBLE : View.INVISIBLE);
647     }
648 
649     @VisibleForTesting
650     @MainThread
getWifiListMaxCount()651     int getWifiListMaxCount() {
652         // Use the maximum count of networks to calculate the remaining count for Wi-Fi networks.
653         int count = MAX_NETWORK_COUNT;
654         if (mEthernetLayout.getVisibility() == View.VISIBLE) {
655             count -= 1;
656         }
657         if (mMobileNetworkLayout.getVisibility() == View.VISIBLE) {
658             count -= 1;
659         }
660 
661         // If the remaining count is greater than the maximum count of the Wi-Fi network, the
662         // maximum count of the Wi-Fi network is used.
663         if (count > MAX_WIFI_ENTRY_COUNT) {
664             count = MAX_WIFI_ENTRY_COUNT;
665         }
666         if (mConnectedWifListLayout.getVisibility() == View.VISIBLE) {
667             count -= 1;
668         }
669         return count;
670     }
671 
672     @MainThread
updateWifiScanNotify(boolean isWifiEnabled, boolean isWifiScanEnabled, boolean isDeviceLocked)673     private void updateWifiScanNotify(boolean isWifiEnabled, boolean isWifiScanEnabled,
674             boolean isDeviceLocked) {
675         if (mDialog == null || isWifiEnabled || !isWifiScanEnabled || isDeviceLocked) {
676             mWifiScanNotifyLayout.setVisibility(View.GONE);
677             return;
678         }
679         if (TextUtils.isEmpty(mWifiScanNotifyText.getText())) {
680             final AnnotationLinkSpan.LinkInfo linkInfo = new AnnotationLinkSpan.LinkInfo(
681                     AnnotationLinkSpan.LinkInfo.DEFAULT_ANNOTATION,
682                     mInternetDialogController::launchWifiScanningSetting);
683             mWifiScanNotifyText.setText(AnnotationLinkSpan.linkify(
684                     mDialog.getContext().getText(R.string.wifi_scan_notify_message), linkInfo));
685             mWifiScanNotifyText.setMovementMethod(LinkMovementMethod.getInstance());
686         }
687         mWifiScanNotifyLayout.setVisibility(View.VISIBLE);
688     }
689 
onClickConnectedWifi(View view)690     void onClickConnectedWifi(View view) {
691         if (mConnectedWifiEntry == null) {
692             return;
693         }
694         mInternetDialogController.launchWifiDetailsSetting(mConnectedWifiEntry.getKey(), view);
695     }
696 
697     /** For DSDS auto data switch **/
onClickConnectedSecondarySub(View view)698     void onClickConnectedSecondarySub(View view) {
699         mInternetDialogController.launchMobileNetworkSettings(view);
700     }
701 
onClickSeeMoreButton(View view)702     void onClickSeeMoreButton(View view) {
703         mInternetDialogController.launchNetworkSetting(view);
704     }
705 
getDialogTitleText()706     CharSequence getDialogTitleText() {
707         return mInternetDialogController.getDialogTitleText();
708     }
709 
710     @Nullable
getSubtitleText()711     CharSequence getSubtitleText() {
712         return mInternetDialogController.getSubtitleText(mIsProgressBarVisible);
713     }
714 
getSignalStrengthDrawable(int subId)715     private Drawable getSignalStrengthDrawable(int subId) {
716         return mInternetDialogController.getSignalStrengthDrawable(subId);
717     }
718 
getMobileNetworkTitle(int subId)719     CharSequence getMobileNetworkTitle(int subId) {
720         return mInternetDialogController.getMobileNetworkTitle(subId);
721     }
722 
getMobileNetworkSummary(int subId)723     String getMobileNetworkSummary(int subId) {
724         return mInternetDialogController.getMobileNetworkSummary(subId);
725     }
726 
setProgressBarVisible(boolean visible)727     private void setProgressBarVisible(boolean visible) {
728         if (mIsProgressBarVisible == visible) {
729             return;
730         }
731         mIsProgressBarVisible = visible;
732         mProgressBar.setVisibility(visible ? View.VISIBLE : View.GONE);
733         mProgressBar.setIndeterminate(visible);
734         mDivider.setVisibility(visible ? View.GONE : View.VISIBLE);
735         mInternetDialogSubTitle.setText(getSubtitleText());
736     }
737 
shouldShowMobileDialog()738     private boolean shouldShowMobileDialog() {
739         if (mDialog == null) {
740             return false;
741         }
742         boolean flag = Prefs.getBoolean(mDialog.getContext(), QS_HAS_TURNED_OFF_MOBILE_DATA,
743                 false);
744         if (mInternetDialogController.isMobileDataEnabled() && !flag) {
745             return true;
746         }
747         return false;
748     }
749 
showTurnOffMobileDialog(SystemUIDialog dialog)750     private void showTurnOffMobileDialog(SystemUIDialog dialog) {
751         Context context = dialog.getContext();
752         CharSequence carrierName = getMobileNetworkTitle(mDefaultDataSubId);
753         boolean isInService = mInternetDialogController.isVoiceStateInService(mDefaultDataSubId);
754         if (TextUtils.isEmpty(carrierName) || !isInService) {
755             carrierName = context.getString(R.string.mobile_data_disable_message_default_carrier);
756         }
757         mAlertDialog = new AlertDialog.Builder(context)
758                 .setTitle(R.string.mobile_data_disable_title)
759                 .setMessage(context.getString(R.string.mobile_data_disable_message, carrierName))
760                 .setNegativeButton(android.R.string.cancel, (d, w) -> {
761                 })
762                 .setPositiveButton(
763                         com.android.internal.R.string.alert_windows_notification_turn_off_action,
764                         (d, w) -> {
765                             mInternetDialogController.setMobileDataEnabled(context,
766                                     mDefaultDataSubId, false, false);
767                             mMobileDataToggle.setChecked(false);
768                             Prefs.putBoolean(context, QS_HAS_TURNED_OFF_MOBILE_DATA, true);
769                         })
770                 .create();
771         mAlertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
772         SystemUIDialog.setShowForAllUsers(mAlertDialog, true);
773         SystemUIDialog.registerDismissListener(mAlertDialog);
774         SystemUIDialog.setWindowOnTop(mAlertDialog, mKeyguard.isShowing());
775         mDialogTransitionAnimator.showFromDialog(mAlertDialog, dialog, null, false);
776     }
777 
showTurnOffAutoDataSwitchDialog(SystemUIDialog dialog, int subId)778     private void showTurnOffAutoDataSwitchDialog(SystemUIDialog dialog, int subId) {
779         Context context = dialog.getContext();
780         CharSequence carrierName = getMobileNetworkTitle(mDefaultDataSubId);
781         if (TextUtils.isEmpty(carrierName)) {
782             carrierName = context.getString(R.string.mobile_data_disable_message_default_carrier);
783         }
784         mAlertDialog = new AlertDialog.Builder(context)
785                 .setTitle(context.getString(R.string.auto_data_switch_disable_title, carrierName))
786                 .setMessage(R.string.auto_data_switch_disable_message)
787                 .setNegativeButton(R.string.auto_data_switch_dialog_negative_button,
788                         (d, w) -> {
789                         })
790                 .setPositiveButton(R.string.auto_data_switch_dialog_positive_button,
791                         (d, w) -> {
792                             mInternetDialogController
793                                     .setAutoDataSwitchMobileDataPolicy(subId, false);
794                             if (mSecondaryMobileNetworkLayout != null) {
795                                 mSecondaryMobileNetworkLayout.setVisibility(View.GONE);
796                             }
797                         })
798                 .create();
799         mAlertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
800         SystemUIDialog.setShowForAllUsers(mAlertDialog, true);
801         SystemUIDialog.registerDismissListener(mAlertDialog);
802         SystemUIDialog.setWindowOnTop(mAlertDialog, mKeyguard.isShowing());
803         mDialogTransitionAnimator.showFromDialog(mAlertDialog, dialog, null, false);
804     }
805 
806     @Override
onRefreshCarrierInfo()807     public void onRefreshCarrierInfo() {
808         mHandler.post(() -> updateDialog(true /* shouldUpdateMobileNetwork */));
809     }
810 
811     @Override
onSimStateChanged()812     public void onSimStateChanged() {
813         mHandler.post(() -> updateDialog(true /* shouldUpdateMobileNetwork */));
814     }
815 
816     @Override
817     @WorkerThread
onCapabilitiesChanged(Network network, NetworkCapabilities networkCapabilities)818     public void onCapabilitiesChanged(Network network, NetworkCapabilities networkCapabilities) {
819         mHandler.post(() -> updateDialog(true /* shouldUpdateMobileNetwork */));
820     }
821 
822     @Override
823     @WorkerThread
onLost(Network network)824     public void onLost(Network network) {
825         mHandler.post(() -> updateDialog(true /* shouldUpdateMobileNetwork */));
826     }
827 
828     @Override
onSubscriptionsChanged(int defaultDataSubId)829     public void onSubscriptionsChanged(int defaultDataSubId) {
830         mDefaultDataSubId = defaultDataSubId;
831         mTelephonyManager = mTelephonyManager.createForSubscriptionId(mDefaultDataSubId);
832         mHandler.post(() -> updateDialog(true /* shouldUpdateMobileNetwork */));
833     }
834 
835     @Override
onUserMobileDataStateChanged(boolean enabled)836     public void onUserMobileDataStateChanged(boolean enabled) {
837         mHandler.post(() -> updateDialog(true /* shouldUpdateMobileNetwork */));
838     }
839 
840     @Override
onServiceStateChanged(ServiceState serviceState)841     public void onServiceStateChanged(ServiceState serviceState) {
842         mHandler.post(() -> updateDialog(true /* shouldUpdateMobileNetwork */));
843     }
844 
845     @Override
846     @WorkerThread
onDataConnectionStateChanged(int state, int networkType)847     public void onDataConnectionStateChanged(int state, int networkType) {
848         mHandler.post(() -> updateDialog(true /* shouldUpdateMobileNetwork */));
849     }
850 
851     @Override
onSignalStrengthsChanged(SignalStrength signalStrength)852     public void onSignalStrengthsChanged(SignalStrength signalStrength) {
853         mHandler.post(() -> updateDialog(true /* shouldUpdateMobileNetwork */));
854     }
855 
856     @Override
onDisplayInfoChanged(TelephonyDisplayInfo telephonyDisplayInfo)857     public void onDisplayInfoChanged(TelephonyDisplayInfo telephonyDisplayInfo) {
858         mHandler.post(() -> updateDialog(true /* shouldUpdateMobileNetwork */));
859     }
860 
861     @Override
onCarrierNetworkChange(boolean active)862     public void onCarrierNetworkChange(boolean active) {
863         mHandler.post(() -> updateDialog(true /* shouldUpdateMobileNetwork */));
864     }
865 
866     @Override
867     @WorkerThread
onAccessPointsChanged(@ullable List<WifiEntry> wifiEntries, @Nullable WifiEntry connectedEntry, boolean hasMoreWifiEntries)868     public void onAccessPointsChanged(@Nullable List<WifiEntry> wifiEntries,
869             @Nullable WifiEntry connectedEntry, boolean hasMoreWifiEntries) {
870         // Should update the carrier network layout when it is connected under airplane mode ON.
871         boolean shouldUpdateCarrierNetwork = mMobileNetworkLayout.getVisibility() == View.VISIBLE
872                 && mInternetDialogController.isAirplaneModeEnabled();
873         mHandler.post(() -> {
874             mConnectedWifiEntry = connectedEntry;
875             mWifiEntriesCount = wifiEntries == null ? 0 : wifiEntries.size();
876             mHasMoreWifiEntries = hasMoreWifiEntries;
877             updateDialog(shouldUpdateCarrierNetwork /* shouldUpdateMobileNetwork */);
878             mAdapter.setWifiEntries(wifiEntries, mWifiEntriesCount);
879             mAdapter.notifyDataSetChanged();
880         });
881     }
882 
883     @Override
onWifiScan(boolean isScan)884     public void onWifiScan(boolean isScan) {
885         setProgressBarVisible(isScan);
886     }
887 
888     @Override
onWindowFocusChanged(SystemUIDialog dialog, boolean hasFocus)889     public void onWindowFocusChanged(SystemUIDialog dialog, boolean hasFocus) {
890         if (mAlertDialog != null && !mAlertDialog.isShowing()) {
891             if (!hasFocus && dialog.isShowing()) {
892                 dialog.dismiss();
893             }
894         }
895     }
896 
897     public enum InternetDialogEvent implements UiEventLogger.UiEventEnum {
898         @UiEvent(doc = "The Internet dialog became visible on the screen.")
899         INTERNET_DIALOG_SHOW(843),
900 
901         @UiEvent(doc = "The share wifi button is clicked.")
902         SHARE_WIFI_QS_BUTTON_CLICKED(1462);
903 
904         private final int mId;
905 
InternetDialogEvent(int id)906         InternetDialogEvent(int id) {
907             mId = id;
908         }
909 
910         @Override
getId()911         public int getId() {
912             return mId;
913         }
914     }
915 }
916