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.systemui.Prefs.Key.QS_HAS_TURNED_OFF_MOBILE_DATA;
19 import static com.android.systemui.qs.tiles.dialog.InternetDialogController.MAX_WIFI_ENTRY_COUNT;
20 
21 import android.app.AlertDialog;
22 import android.content.Context;
23 import android.content.res.TypedArray;
24 import android.graphics.drawable.Drawable;
25 import android.net.Network;
26 import android.net.NetworkCapabilities;
27 import android.net.wifi.WifiManager;
28 import android.os.Bundle;
29 import android.os.Handler;
30 import android.telephony.ServiceState;
31 import android.telephony.SignalStrength;
32 import android.telephony.SubscriptionManager;
33 import android.telephony.TelephonyDisplayInfo;
34 import android.telephony.TelephonyManager;
35 import android.text.Html;
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.Window;
43 import android.view.WindowManager;
44 import android.widget.Button;
45 import android.widget.FrameLayout;
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.settingslib.Utils;
62 import com.android.systemui.Prefs;
63 import com.android.systemui.R;
64 import com.android.systemui.accessibility.floatingmenu.AnnotationLinkSpan;
65 import com.android.systemui.dagger.SysUISingleton;
66 import com.android.systemui.dagger.qualifiers.Background;
67 import com.android.systemui.dagger.qualifiers.Main;
68 import com.android.systemui.statusbar.phone.SystemUIDialog;
69 import com.android.wifitrackerlib.WifiEntry;
70 
71 import java.util.List;
72 import java.util.concurrent.Executor;
73 
74 /**
75  * Dialog for showing mobile network, connected Wi-Fi network and Wi-Fi networks.
76  */
77 @SysUISingleton
78 public class InternetDialog extends SystemUIDialog implements
79         InternetDialogController.InternetDialogCallback, Window.Callback {
80     private static final String TAG = "InternetDialog";
81     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
82 
83     static final long PROGRESS_DELAY_MS = 1500L;
84     static final int MAX_NETWORK_COUNT = 4;
85 
86     private final Handler mHandler;
87     private final Executor mBackgroundExecutor;
88 
89     @VisibleForTesting
90     protected InternetAdapter mAdapter;
91     @VisibleForTesting
92     protected WifiManager mWifiManager;
93     @VisibleForTesting
94     protected View mDialogView;
95     @VisibleForTesting
96     protected boolean mCanConfigWifi;
97 
98     private InternetDialogFactory mInternetDialogFactory;
99     private SubscriptionManager mSubscriptionManager;
100     private TelephonyManager mTelephonyManager;
101     private AlertDialog mAlertDialog;
102     private UiEventLogger mUiEventLogger;
103     private Context mContext;
104     private InternetDialogController mInternetDialogController;
105     private TextView mInternetDialogTitle;
106     private TextView mInternetDialogSubTitle;
107     private View mDivider;
108     private ProgressBar mProgressBar;
109     private LinearLayout mInternetDialogLayout;
110     private LinearLayout mConnectedWifListLayout;
111     private LinearLayout mMobileNetworkLayout;
112     private LinearLayout mTurnWifiOnLayout;
113     private LinearLayout mEthernetLayout;
114     private TextView mWifiToggleTitleText;
115     private LinearLayout mWifiScanNotifyLayout;
116     private TextView mWifiScanNotifyText;
117     private LinearLayout mSeeAllLayout;
118     private RecyclerView mWifiRecyclerView;
119     private ImageView mConnectedWifiIcon;
120     private ImageView mWifiSettingsIcon;
121     private TextView mConnectedWifiTitleText;
122     private TextView mConnectedWifiSummaryText;
123     private ImageView mSignalIcon;
124     private TextView mMobileTitleText;
125     private TextView mMobileSummaryText;
126     private TextView mAirplaneModeSummaryText;
127     private Switch mMobileDataToggle;
128     private View mMobileToggleDivider;
129     private Switch mWiFiToggle;
130     private Button mDoneButton;
131     private Button mAirplaneModeButton;
132     private Drawable mBackgroundOn;
133     private Drawable mBackgroundOff = null;
134     private int mDefaultDataSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
135     private boolean mCanConfigMobileData;
136 
137     // Wi-Fi entries
138     private int mWifiNetworkHeight;
139     @VisibleForTesting
140     protected WifiEntry mConnectedWifiEntry;
141     @VisibleForTesting
142     protected int mWifiEntriesCount;
143     @VisibleForTesting
144     protected boolean mHasMoreWifiEntries;
145 
146     // Wi-Fi scanning progress bar
147     protected boolean mIsProgressBarVisible;
148     protected boolean mIsSearchingHidden;
149     protected final Runnable mHideProgressBarRunnable = () -> {
150         setProgressBarVisible(false);
151     };
152     protected Runnable mHideSearchingRunnable = () -> {
153         mIsSearchingHidden = true;
154         mInternetDialogSubTitle.setText(getSubtitleText());
155     };
156 
InternetDialog(Context context, InternetDialogFactory internetDialogFactory, InternetDialogController internetDialogController, boolean canConfigMobileData, boolean canConfigWifi, boolean aboveStatusBar, UiEventLogger uiEventLogger, @Main Handler handler, @Background Executor executor)157     public InternetDialog(Context context, InternetDialogFactory internetDialogFactory,
158             InternetDialogController internetDialogController, boolean canConfigMobileData,
159             boolean canConfigWifi, boolean aboveStatusBar, UiEventLogger uiEventLogger,
160             @Main Handler handler, @Background Executor executor) {
161         super(context);
162         if (DEBUG) {
163             Log.d(TAG, "Init InternetDialog");
164         }
165 
166         // Save the context that is wrapped with our theme.
167         mContext = getContext();
168         mHandler = handler;
169         mBackgroundExecutor = executor;
170         mInternetDialogFactory = internetDialogFactory;
171         mInternetDialogController = internetDialogController;
172         mSubscriptionManager = mInternetDialogController.getSubscriptionManager();
173         mDefaultDataSubId = mInternetDialogController.getDefaultDataSubscriptionId();
174         mTelephonyManager = mInternetDialogController.getTelephonyManager();
175         mWifiManager = mInternetDialogController.getWifiManager();
176         mCanConfigMobileData = canConfigMobileData;
177         mCanConfigWifi = canConfigWifi;
178 
179         mUiEventLogger = uiEventLogger;
180         mAdapter = new InternetAdapter(mInternetDialogController);
181         if (!aboveStatusBar) {
182             getWindow().setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY);
183         }
184     }
185 
186     @Override
onCreate(Bundle savedInstanceState)187     public void onCreate(Bundle savedInstanceState) {
188         super.onCreate(savedInstanceState);
189         if (DEBUG) {
190             Log.d(TAG, "onCreate");
191         }
192         mUiEventLogger.log(InternetDialogEvent.INTERNET_DIALOG_SHOW);
193         mDialogView = LayoutInflater.from(mContext).inflate(R.layout.internet_connectivity_dialog,
194                 null);
195         final Window window = getWindow();
196         window.setContentView(mDialogView);
197 
198         window.setWindowAnimations(R.style.Animation_InternetDialog);
199 
200         mWifiNetworkHeight = mContext.getResources()
201                 .getDimensionPixelSize(R.dimen.internet_dialog_wifi_network_height);
202 
203         mInternetDialogLayout = mDialogView.requireViewById(R.id.internet_connectivity_dialog);
204         mInternetDialogTitle = mDialogView.requireViewById(R.id.internet_dialog_title);
205         mInternetDialogSubTitle = mDialogView.requireViewById(R.id.internet_dialog_subtitle);
206         mDivider = mDialogView.requireViewById(R.id.divider);
207         mProgressBar = mDialogView.requireViewById(R.id.wifi_searching_progress);
208         mEthernetLayout = mDialogView.requireViewById(R.id.ethernet_layout);
209         mMobileNetworkLayout = mDialogView.requireViewById(R.id.mobile_network_layout);
210         mTurnWifiOnLayout = mDialogView.requireViewById(R.id.turn_on_wifi_layout);
211         mWifiToggleTitleText = mDialogView.requireViewById(R.id.wifi_toggle_title);
212         mWifiScanNotifyLayout = mDialogView.requireViewById(R.id.wifi_scan_notify_layout);
213         mWifiScanNotifyText = mDialogView.requireViewById(R.id.wifi_scan_notify_text);
214         mConnectedWifListLayout = mDialogView.requireViewById(R.id.wifi_connected_layout);
215         mConnectedWifiIcon = mDialogView.requireViewById(R.id.wifi_connected_icon);
216         mConnectedWifiTitleText = mDialogView.requireViewById(R.id.wifi_connected_title);
217         mConnectedWifiSummaryText = mDialogView.requireViewById(R.id.wifi_connected_summary);
218         mWifiSettingsIcon = mDialogView.requireViewById(R.id.wifi_settings_icon);
219         mWifiRecyclerView = mDialogView.requireViewById(R.id.wifi_list_layout);
220         mSeeAllLayout = mDialogView.requireViewById(R.id.see_all_layout);
221         mDoneButton = mDialogView.requireViewById(R.id.done_button);
222         mAirplaneModeButton = mDialogView.requireViewById(R.id.apm_button);
223         mSignalIcon = mDialogView.requireViewById(R.id.signal_icon);
224         mMobileTitleText = mDialogView.requireViewById(R.id.mobile_title);
225         mMobileSummaryText = mDialogView.requireViewById(R.id.mobile_summary);
226         mAirplaneModeSummaryText = mDialogView.requireViewById(R.id.airplane_mode_summary);
227         mMobileToggleDivider = mDialogView.requireViewById(R.id.mobile_toggle_divider);
228         mMobileDataToggle = mDialogView.requireViewById(R.id.mobile_toggle);
229         mWiFiToggle = mDialogView.requireViewById(R.id.wifi_toggle);
230         mBackgroundOn = mContext.getDrawable(R.drawable.settingslib_switch_bar_bg_on);
231         mInternetDialogTitle.setText(getDialogTitleText());
232         mInternetDialogTitle.setGravity(Gravity.START | Gravity.CENTER_VERTICAL);
233 
234         TypedArray typedArray = mContext.obtainStyledAttributes(
235                 new int[]{android.R.attr.selectableItemBackground});
236         try {
237             mBackgroundOff = typedArray.getDrawable(0 /* index */);
238         } finally {
239             typedArray.recycle();
240         }
241 
242         setOnClickListener();
243         mTurnWifiOnLayout.setBackground(null);
244         mAirplaneModeButton.setVisibility(
245                 mInternetDialogController.isAirplaneModeEnabled() ? View.VISIBLE : View.GONE);
246         mWifiRecyclerView.setLayoutManager(new LinearLayoutManager(mContext));
247         mWifiRecyclerView.setAdapter(mAdapter);
248     }
249 
250     @Override
onStart()251     public void onStart() {
252         super.onStart();
253         if (DEBUG) {
254             Log.d(TAG, "onStart");
255         }
256         mInternetDialogController.onStart(this, mCanConfigWifi);
257         if (!mCanConfigWifi) {
258             hideWifiViews();
259         }
260     }
261 
262     @VisibleForTesting
hideWifiViews()263     void hideWifiViews() {
264         setProgressBarVisible(false);
265         mTurnWifiOnLayout.setVisibility(View.GONE);
266         mConnectedWifListLayout.setVisibility(View.GONE);
267         mWifiRecyclerView.setVisibility(View.GONE);
268         mSeeAllLayout.setVisibility(View.GONE);
269     }
270 
271     @Override
onStop()272     public void onStop() {
273         super.onStop();
274         if (DEBUG) {
275             Log.d(TAG, "onStop");
276         }
277         mHandler.removeCallbacks(mHideProgressBarRunnable);
278         mHandler.removeCallbacks(mHideSearchingRunnable);
279         mMobileNetworkLayout.setOnClickListener(null);
280         mMobileDataToggle.setOnCheckedChangeListener(null);
281         mConnectedWifListLayout.setOnClickListener(null);
282         mSeeAllLayout.setOnClickListener(null);
283         mWiFiToggle.setOnCheckedChangeListener(null);
284         mDoneButton.setOnClickListener(null);
285         mAirplaneModeButton.setOnClickListener(null);
286         mInternetDialogController.onStop();
287         mInternetDialogFactory.destroyDialog();
288     }
289 
290     @Override
dismissDialog()291     public void dismissDialog() {
292         if (DEBUG) {
293             Log.d(TAG, "dismissDialog");
294         }
295         mInternetDialogFactory.destroyDialog();
296         dismiss();
297     }
298 
299     /**
300      * Update the internet dialog when receiving the callback.
301      *
302      * @param shouldUpdateMobileNetwork {@code true} for update the mobile network layout,
303      * otherwise {@code false}.
304      */
updateDialog(boolean shouldUpdateMobileNetwork)305     void updateDialog(boolean shouldUpdateMobileNetwork) {
306         if (DEBUG) {
307             Log.d(TAG, "updateDialog");
308         }
309         mInternetDialogTitle.setText(getDialogTitleText());
310         mInternetDialogSubTitle.setText(getSubtitleText());
311         mAirplaneModeButton.setVisibility(
312                 mInternetDialogController.isAirplaneModeEnabled() ? View.VISIBLE : View.GONE);
313 
314         updateEthernet();
315         if (shouldUpdateMobileNetwork) {
316             setMobileDataLayout(mInternetDialogController.activeNetworkIsCellular(),
317                     mInternetDialogController.isCarrierNetworkActive());
318         }
319 
320         if (!mCanConfigWifi) {
321             return;
322         }
323 
324         showProgressBar();
325         final boolean isDeviceLocked = mInternetDialogController.isDeviceLocked();
326         final boolean isWifiEnabled = mWifiManager.isWifiEnabled();
327         final boolean isWifiScanEnabled = mInternetDialogController.isWifiScanEnabled();
328         updateWifiToggle(isWifiEnabled, isDeviceLocked);
329         updateConnectedWifi(isWifiEnabled, isDeviceLocked);
330         updateWifiListAndSeeAll(isWifiEnabled, isDeviceLocked);
331         updateWifiScanNotify(isWifiEnabled, isWifiScanEnabled, isDeviceLocked);
332     }
333 
setOnClickListener()334     private void setOnClickListener() {
335         mMobileNetworkLayout.setOnClickListener(v -> {
336             if (mInternetDialogController.isMobileDataEnabled()
337                     && !mInternetDialogController.isDeviceLocked()) {
338                 if (!mInternetDialogController.activeNetworkIsCellular()) {
339                     mInternetDialogController.connectCarrierNetwork();
340                 }
341             }
342         });
343         mMobileDataToggle.setOnCheckedChangeListener(
344                 (buttonView, isChecked) -> {
345                     if (!isChecked && shouldShowMobileDialog()) {
346                         showTurnOffMobileDialog();
347                     } else if (!shouldShowMobileDialog()) {
348                         mInternetDialogController.setMobileDataEnabled(mContext, mDefaultDataSubId,
349                                 isChecked, false);
350                     }
351                 });
352         mConnectedWifListLayout.setOnClickListener(v -> onClickConnectedWifi());
353         mSeeAllLayout.setOnClickListener(v -> onClickSeeMoreButton());
354         mWiFiToggle.setOnCheckedChangeListener(
355                 (buttonView, isChecked) -> {
356                     buttonView.setChecked(isChecked);
357                     mWifiManager.setWifiEnabled(isChecked);
358                 });
359         mDoneButton.setOnClickListener(v -> dismiss());
360         mAirplaneModeButton.setOnClickListener(v -> {
361             mInternetDialogController.setAirplaneModeDisabled();
362         });
363     }
364 
365     @MainThread
updateEthernet()366     private void updateEthernet() {
367         mEthernetLayout.setVisibility(
368                 mInternetDialogController.hasEthernet() ? View.VISIBLE : View.GONE);
369     }
370 
setMobileDataLayout(boolean activeNetworkIsCellular, boolean isCarrierNetworkActive)371     private void setMobileDataLayout(boolean activeNetworkIsCellular,
372             boolean isCarrierNetworkActive) {
373         boolean isNetworkConnected = activeNetworkIsCellular || isCarrierNetworkActive;
374         // 1. Mobile network should be gone if airplane mode ON or the list of active
375         //    subscriptionId is null.
376         // 2. Carrier network should be gone if airplane mode ON and Wi-Fi is OFF.
377         if (DEBUG) {
378             Log.d(TAG, "setMobileDataLayout, isCarrierNetworkActive = " + isCarrierNetworkActive);
379         }
380 
381         if (!mInternetDialogController.hasActiveSubId()
382                 && (!mWifiManager.isWifiEnabled() || !isCarrierNetworkActive)) {
383             mMobileNetworkLayout.setVisibility(View.GONE);
384         } else {
385             mMobileNetworkLayout.setVisibility(View.VISIBLE);
386             mMobileDataToggle.setChecked(mInternetDialogController.isMobileDataEnabled());
387             mMobileTitleText.setText(getMobileNetworkTitle());
388             String summary = getMobileNetworkSummary();
389             if (!TextUtils.isEmpty(summary)) {
390                 mMobileSummaryText.setText(
391                         Html.fromHtml(summary, Html.FROM_HTML_MODE_LEGACY));
392                 mMobileSummaryText.setVisibility(View.VISIBLE);
393             } else {
394                 mMobileSummaryText.setVisibility(View.GONE);
395             }
396             mBackgroundExecutor.execute(() -> {
397                 Drawable drawable = getSignalStrengthDrawable();
398                 mHandler.post(() -> {
399                     mSignalIcon.setImageDrawable(drawable);
400                 });
401             });
402             mMobileTitleText.setTextAppearance(isNetworkConnected
403                     ? R.style.TextAppearance_InternetDialog_Active
404                     : R.style.TextAppearance_InternetDialog);
405             int secondaryRes = isNetworkConnected
406                     ? R.style.TextAppearance_InternetDialog_Secondary_Active
407                     : R.style.TextAppearance_InternetDialog_Secondary;
408             mMobileSummaryText.setTextAppearance(secondaryRes);
409             // Set airplane mode to the summary for carrier network
410             if (mInternetDialogController.isAirplaneModeEnabled()) {
411                 mAirplaneModeSummaryText.setVisibility(View.VISIBLE);
412                 mAirplaneModeSummaryText.setText(mContext.getText(R.string.airplane_mode));
413                 mAirplaneModeSummaryText.setTextAppearance(secondaryRes);
414             } else {
415                 mAirplaneModeSummaryText.setVisibility(View.GONE);
416             }
417             mMobileNetworkLayout.setBackground(
418                     isNetworkConnected ? mBackgroundOn : mBackgroundOff);
419 
420             TypedArray array = mContext.obtainStyledAttributes(
421                     R.style.InternetDialog_Divider_Active, new int[]{android.R.attr.background});
422             int dividerColor = Utils.getColorAttrDefaultColor(mContext,
423                     android.R.attr.textColorSecondary);
424             mMobileToggleDivider.setBackgroundColor(isNetworkConnected
425                     ? array.getColor(0, dividerColor) : dividerColor);
426             array.recycle();
427 
428             mMobileDataToggle.setVisibility(mCanConfigMobileData ? View.VISIBLE : View.INVISIBLE);
429             mMobileToggleDivider.setVisibility(
430                     mCanConfigMobileData ? View.VISIBLE : View.INVISIBLE);
431         }
432     }
433 
434     @MainThread
updateWifiToggle(boolean isWifiEnabled, boolean isDeviceLocked)435     private void updateWifiToggle(boolean isWifiEnabled, boolean isDeviceLocked) {
436         mWiFiToggle.setChecked(isWifiEnabled);
437         if (isDeviceLocked) {
438             mWifiToggleTitleText.setTextAppearance((mConnectedWifiEntry != null)
439                     ? R.style.TextAppearance_InternetDialog_Active
440                     : R.style.TextAppearance_InternetDialog);
441         }
442         mTurnWifiOnLayout.setBackground(
443                 (isDeviceLocked && mConnectedWifiEntry != null) ? mBackgroundOn : null);
444     }
445 
446     @MainThread
updateConnectedWifi(boolean isWifiEnabled, boolean isDeviceLocked)447     private void updateConnectedWifi(boolean isWifiEnabled, boolean isDeviceLocked) {
448         if (!isWifiEnabled || mConnectedWifiEntry == null || isDeviceLocked) {
449             mConnectedWifListLayout.setVisibility(View.GONE);
450             return;
451         }
452         mConnectedWifListLayout.setVisibility(View.VISIBLE);
453         mConnectedWifiTitleText.setText(mConnectedWifiEntry.getTitle());
454         mConnectedWifiSummaryText.setText(mConnectedWifiEntry.getSummary(false));
455         mConnectedWifiIcon.setImageDrawable(
456                 mInternetDialogController.getInternetWifiDrawable(mConnectedWifiEntry));
457         mWifiSettingsIcon.setColorFilter(
458                 mContext.getColor(R.color.connected_network_primary_color));
459     }
460 
461     @MainThread
updateWifiListAndSeeAll(boolean isWifiEnabled, boolean isDeviceLocked)462     private void updateWifiListAndSeeAll(boolean isWifiEnabled, boolean isDeviceLocked) {
463         if (!isWifiEnabled || isDeviceLocked) {
464             mWifiRecyclerView.setVisibility(View.GONE);
465             mSeeAllLayout.setVisibility(View.GONE);
466             return;
467         }
468         final int wifiListMaxCount = getWifiListMaxCount();
469         if (mAdapter.getItemCount() > wifiListMaxCount) {
470             mHasMoreWifiEntries = true;
471         }
472         mAdapter.setMaxEntriesCount(wifiListMaxCount);
473         final int wifiListMinHeight = mWifiNetworkHeight * wifiListMaxCount;
474         if (mWifiRecyclerView.getMinimumHeight() != wifiListMinHeight) {
475             mWifiRecyclerView.setMinimumHeight(wifiListMinHeight);
476         }
477         mWifiRecyclerView.setVisibility(View.VISIBLE);
478         mSeeAllLayout.setVisibility(mHasMoreWifiEntries ? View.VISIBLE : View.INVISIBLE);
479     }
480 
481     @VisibleForTesting
482     @MainThread
getWifiListMaxCount()483     int getWifiListMaxCount() {
484         // Use the maximum count of networks to calculate the remaining count for Wi-Fi networks.
485         int count = MAX_NETWORK_COUNT;
486         if (mEthernetLayout.getVisibility() == View.VISIBLE) {
487             count -= 1;
488         }
489         if (mMobileNetworkLayout.getVisibility() == View.VISIBLE) {
490             count -= 1;
491         }
492 
493         // If the remaining count is greater than the maximum count of the Wi-Fi network, the
494         // maximum count of the Wi-Fi network is used.
495         if (count > MAX_WIFI_ENTRY_COUNT) {
496             count = MAX_WIFI_ENTRY_COUNT;
497         }
498         if (mConnectedWifListLayout.getVisibility() == View.VISIBLE) {
499             count -= 1;
500         }
501         return count;
502     }
503 
504     @MainThread
updateWifiScanNotify(boolean isWifiEnabled, boolean isWifiScanEnabled, boolean isDeviceLocked)505     private void updateWifiScanNotify(boolean isWifiEnabled, boolean isWifiScanEnabled,
506             boolean isDeviceLocked) {
507         if (isWifiEnabled || !isWifiScanEnabled || isDeviceLocked) {
508             mWifiScanNotifyLayout.setVisibility(View.GONE);
509             return;
510         }
511         if (TextUtils.isEmpty(mWifiScanNotifyText.getText())) {
512             final AnnotationLinkSpan.LinkInfo linkInfo = new AnnotationLinkSpan.LinkInfo(
513                     AnnotationLinkSpan.LinkInfo.DEFAULT_ANNOTATION,
514                     v -> mInternetDialogController.launchWifiScanningSetting());
515             mWifiScanNotifyText.setText(AnnotationLinkSpan.linkify(
516                     getContext().getText(R.string.wifi_scan_notify_message), linkInfo));
517             mWifiScanNotifyText.setMovementMethod(LinkMovementMethod.getInstance());
518         }
519         mWifiScanNotifyLayout.setVisibility(View.VISIBLE);
520     }
521 
onClickConnectedWifi()522     void onClickConnectedWifi() {
523         if (mConnectedWifiEntry == null) {
524             return;
525         }
526         mInternetDialogController.launchWifiNetworkDetailsSetting(mConnectedWifiEntry.getKey());
527     }
528 
onClickSeeMoreButton()529     void onClickSeeMoreButton() {
530         mInternetDialogController.launchNetworkSetting();
531     }
532 
getDialogTitleText()533     CharSequence getDialogTitleText() {
534         return mInternetDialogController.getDialogTitleText();
535     }
536 
getSubtitleText()537     CharSequence getSubtitleText() {
538         return mInternetDialogController.getSubtitleText(
539                 mIsProgressBarVisible && !mIsSearchingHidden);
540     }
541 
getSignalStrengthDrawable()542     private Drawable getSignalStrengthDrawable() {
543         return mInternetDialogController.getSignalStrengthDrawable();
544     }
545 
getMobileNetworkTitle()546     CharSequence getMobileNetworkTitle() {
547         return mInternetDialogController.getMobileNetworkTitle();
548     }
549 
getMobileNetworkSummary()550     String getMobileNetworkSummary() {
551         return mInternetDialogController.getMobileNetworkSummary();
552     }
553 
showProgressBar()554     protected void showProgressBar() {
555         if (mWifiManager == null || !mWifiManager.isWifiEnabled()
556                 || mInternetDialogController.isDeviceLocked()) {
557             setProgressBarVisible(false);
558             return;
559         }
560         setProgressBarVisible(true);
561         if (mConnectedWifiEntry != null || mWifiEntriesCount > 0) {
562             mHandler.postDelayed(mHideProgressBarRunnable, PROGRESS_DELAY_MS);
563         } else if (!mIsSearchingHidden) {
564             mHandler.postDelayed(mHideSearchingRunnable, PROGRESS_DELAY_MS);
565         }
566     }
567 
setProgressBarVisible(boolean visible)568     private void setProgressBarVisible(boolean visible) {
569         if (mIsProgressBarVisible == visible) {
570             return;
571         }
572         mIsProgressBarVisible = visible;
573         mProgressBar.setVisibility(visible ? View.VISIBLE : View.GONE);
574         mProgressBar.setIndeterminate(visible);
575         mDivider.setVisibility(visible ? View.GONE : View.VISIBLE);
576         mInternetDialogSubTitle.setText(getSubtitleText());
577     }
578 
shouldShowMobileDialog()579     private boolean shouldShowMobileDialog() {
580         boolean flag = Prefs.getBoolean(mContext, QS_HAS_TURNED_OFF_MOBILE_DATA,
581                 false);
582         if (mInternetDialogController.isMobileDataEnabled() && !flag) {
583             return true;
584         }
585         return false;
586     }
587 
showTurnOffMobileDialog()588     private void showTurnOffMobileDialog() {
589         CharSequence carrierName = getMobileNetworkTitle();
590         boolean isInService = mInternetDialogController.isVoiceStateInService();
591         if (TextUtils.isEmpty(carrierName) || !isInService) {
592             carrierName = mContext.getString(R.string.mobile_data_disable_message_default_carrier);
593         }
594         mAlertDialog = new Builder(mContext)
595                 .setTitle(R.string.mobile_data_disable_title)
596                 .setMessage(mContext.getString(R.string.mobile_data_disable_message, carrierName))
597                 .setNegativeButton(android.R.string.cancel, (d, w) -> {
598                     mMobileDataToggle.setChecked(true);
599                 })
600                 .setPositiveButton(
601                         com.android.internal.R.string.alert_windows_notification_turn_off_action,
602                         (d, w) -> {
603                             mInternetDialogController.setMobileDataEnabled(mContext,
604                                     mDefaultDataSubId, false, false);
605                             mMobileDataToggle.setChecked(false);
606                             Prefs.putBoolean(mContext, QS_HAS_TURNED_OFF_MOBILE_DATA, true);
607                         })
608                 .create();
609         mAlertDialog.setOnCancelListener(dialog -> mMobileDataToggle.setChecked(true));
610         mAlertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
611         SystemUIDialog.setShowForAllUsers(mAlertDialog, true);
612         SystemUIDialog.registerDismissListener(mAlertDialog);
613         SystemUIDialog.setWindowOnTop(mAlertDialog);
614         mAlertDialog.show();
615     }
616 
617     @Override
onRefreshCarrierInfo()618     public void onRefreshCarrierInfo() {
619         mHandler.post(() -> updateDialog(true /* shouldUpdateMobileNetwork */));
620     }
621 
622     @Override
onSimStateChanged()623     public void onSimStateChanged() {
624         mHandler.post(() -> updateDialog(true /* shouldUpdateMobileNetwork */));
625     }
626 
627     @Override
628     @WorkerThread
onCapabilitiesChanged(Network network, NetworkCapabilities networkCapabilities)629     public void onCapabilitiesChanged(Network network, NetworkCapabilities networkCapabilities) {
630         mHandler.post(() -> updateDialog(true /* shouldUpdateMobileNetwork */));
631     }
632 
633     @Override
634     @WorkerThread
onLost(Network network)635     public void onLost(Network network) {
636         mHandler.post(() -> updateDialog(true /* shouldUpdateMobileNetwork */));
637     }
638 
639     @Override
onSubscriptionsChanged(int defaultDataSubId)640     public void onSubscriptionsChanged(int defaultDataSubId) {
641         mDefaultDataSubId = defaultDataSubId;
642         mTelephonyManager = mTelephonyManager.createForSubscriptionId(mDefaultDataSubId);
643         mHandler.post(() -> updateDialog(true /* shouldUpdateMobileNetwork */));
644     }
645 
646     @Override
onUserMobileDataStateChanged(boolean enabled)647     public void onUserMobileDataStateChanged(boolean enabled) {
648         mHandler.post(() -> updateDialog(true /* shouldUpdateMobileNetwork */));
649     }
650 
651     @Override
onServiceStateChanged(ServiceState serviceState)652     public void onServiceStateChanged(ServiceState serviceState) {
653         mHandler.post(() -> updateDialog(true /* shouldUpdateMobileNetwork */));
654     }
655 
656     @Override
657     @WorkerThread
onDataConnectionStateChanged(int state, int networkType)658     public void onDataConnectionStateChanged(int state, int networkType) {
659         mHandler.post(() -> updateDialog(true /* shouldUpdateMobileNetwork */));
660     }
661 
662     @Override
onSignalStrengthsChanged(SignalStrength signalStrength)663     public void onSignalStrengthsChanged(SignalStrength signalStrength) {
664         mHandler.post(() -> updateDialog(true /* shouldUpdateMobileNetwork */));
665     }
666 
667     @Override
onDisplayInfoChanged(TelephonyDisplayInfo telephonyDisplayInfo)668     public void onDisplayInfoChanged(TelephonyDisplayInfo telephonyDisplayInfo) {
669         mHandler.post(() -> updateDialog(true /* shouldUpdateMobileNetwork */));
670     }
671 
672     @Override
673     @WorkerThread
onAccessPointsChanged(@ullable List<WifiEntry> wifiEntries, @Nullable WifiEntry connectedEntry, boolean hasMoreWifiEntries)674     public void onAccessPointsChanged(@Nullable List<WifiEntry> wifiEntries,
675             @Nullable WifiEntry connectedEntry, boolean hasMoreWifiEntries) {
676         // Should update the carrier network layout when it is connected under airplane mode ON.
677         boolean shouldUpdateCarrierNetwork = mMobileNetworkLayout.getVisibility() == View.VISIBLE
678                 && mInternetDialogController.isAirplaneModeEnabled();
679         mHandler.post(() -> {
680             mConnectedWifiEntry = connectedEntry;
681             mWifiEntriesCount = wifiEntries == null ? 0 : wifiEntries.size();
682             mHasMoreWifiEntries = hasMoreWifiEntries;
683             updateDialog(shouldUpdateCarrierNetwork /* shouldUpdateMobileNetwork */);
684             mAdapter.setWifiEntries(wifiEntries, mWifiEntriesCount);
685             mAdapter.notifyDataSetChanged();
686         });
687     }
688 
689     @Override
onWindowFocusChanged(boolean hasFocus)690     public void onWindowFocusChanged(boolean hasFocus) {
691         super.onWindowFocusChanged(hasFocus);
692         if (mAlertDialog != null && !mAlertDialog.isShowing()) {
693             if (!hasFocus && isShowing()) {
694                 dismiss();
695             }
696         }
697     }
698 
699     public enum InternetDialogEvent implements UiEventLogger.UiEventEnum {
700         @UiEvent(doc = "The Internet dialog became visible on the screen.")
701         INTERNET_DIALOG_SHOW(843);
702 
703         private final int mId;
704 
InternetDialogEvent(int id)705         InternetDialogEvent(int id) {
706             mId = id;
707         }
708 
709         @Override
getId()710         public int getId() {
711             return mId;
712         }
713     }
714 }
715