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