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 17 package com.android.systemui.qs.tiles.dialog; 18 19 import static android.telephony.SubscriptionManager.PROFILE_CLASS_PROVISIONING; 20 21 import static com.android.settingslib.mobile.MobileMappings.getIconKey; 22 import static com.android.settingslib.mobile.MobileMappings.mapIconSets; 23 import static com.android.settingslib.wifi.WifiUtils.getHotspotIconResource; 24 import static com.android.wifitrackerlib.WifiEntry.CONNECTED_STATE_CONNECTED; 25 26 import android.animation.Animator; 27 import android.animation.AnimatorListenerAdapter; 28 import android.annotation.AnyThread; 29 import android.content.BroadcastReceiver; 30 import android.content.Context; 31 import android.content.Intent; 32 import android.content.IntentFilter; 33 import android.content.res.Resources; 34 import android.graphics.Color; 35 import android.graphics.PixelFormat; 36 import android.graphics.drawable.ColorDrawable; 37 import android.graphics.drawable.Drawable; 38 import android.graphics.drawable.LayerDrawable; 39 import android.net.ConnectivityManager; 40 import android.net.Network; 41 import android.net.NetworkCapabilities; 42 import android.net.wifi.WifiManager; 43 import android.os.Bundle; 44 import android.os.Handler; 45 import android.os.UserHandle; 46 import android.provider.Settings; 47 import android.telephony.AccessNetworkConstants; 48 import android.telephony.NetworkRegistrationInfo; 49 import android.telephony.ServiceState; 50 import android.telephony.SignalStrength; 51 import android.telephony.SubscriptionInfo; 52 import android.telephony.SubscriptionManager; 53 import android.telephony.TelephonyCallback; 54 import android.telephony.TelephonyDisplayInfo; 55 import android.telephony.TelephonyManager; 56 import android.text.TextUtils; 57 import android.util.Log; 58 import android.view.Gravity; 59 import android.view.View; 60 import android.view.WindowManager; 61 62 import androidx.annotation.MainThread; 63 import androidx.annotation.NonNull; 64 import androidx.annotation.Nullable; 65 import androidx.annotation.VisibleForTesting; 66 import androidx.annotation.WorkerThread; 67 68 import com.android.internal.logging.UiEventLogger; 69 import com.android.keyguard.KeyguardUpdateMonitor; 70 import com.android.keyguard.KeyguardUpdateMonitorCallback; 71 import com.android.settingslib.DeviceInfoUtils; 72 import com.android.settingslib.SignalIcon; 73 import com.android.settingslib.Utils; 74 import com.android.settingslib.graph.SignalDrawable; 75 import com.android.settingslib.mobile.MobileMappings; 76 import com.android.settingslib.mobile.TelephonyIcons; 77 import com.android.settingslib.net.SignalStrengthUtil; 78 import com.android.settingslib.wifi.WifiUtils; 79 import com.android.settingslib.wifi.dpp.WifiDppIntentHelper; 80 import com.android.systemui.animation.ActivityTransitionAnimator; 81 import com.android.systemui.animation.DialogTransitionAnimator; 82 import com.android.systemui.broadcast.BroadcastDispatcher; 83 import com.android.systemui.dagger.qualifiers.Background; 84 import com.android.systemui.dagger.qualifiers.Main; 85 import com.android.systemui.flags.FeatureFlags; 86 import com.android.systemui.flags.Flags; 87 import com.android.systemui.plugins.ActivityStarter; 88 import com.android.systemui.res.R; 89 import com.android.systemui.shade.ShadeDisplayAware; 90 import com.android.systemui.statusbar.connectivity.AccessPointController; 91 import com.android.systemui.statusbar.policy.KeyguardStateController; 92 import com.android.systemui.statusbar.policy.LocationController; 93 import com.android.systemui.toast.SystemUIToast; 94 import com.android.systemui.toast.ToastFactory; 95 import com.android.systemui.util.CarrierConfigTracker; 96 import com.android.systemui.util.settings.GlobalSettings; 97 import com.android.wifitrackerlib.HotspotNetworkEntry; 98 import com.android.wifitrackerlib.MergedCarrierEntry; 99 import com.android.wifitrackerlib.WifiEntry; 100 101 import java.util.ArrayList; 102 import java.util.HashMap; 103 import java.util.HashSet; 104 import java.util.List; 105 import java.util.Map; 106 import java.util.Objects; 107 import java.util.Set; 108 import java.util.concurrent.Executor; 109 import java.util.concurrent.atomic.AtomicReference; 110 import java.util.function.Supplier; 111 import java.util.stream.Collectors; 112 import java.util.stream.Stream; 113 114 import javax.inject.Inject; 115 116 /** 117 * Controller for Internet Dialog. 118 */ 119 public class InternetDetailsContentController implements AccessPointController.AccessPointCallback { 120 121 private static final String TAG = "InternetDetailsContentController"; 122 private static final String ACTION_WIFI_SCANNING_SETTINGS = 123 "android.settings.WIFI_SCANNING_SETTINGS"; 124 /** 125 * Fragment "key" argument passed thru {@link #SETTINGS_EXTRA_SHOW_FRAGMENT_ARGUMENTS} 126 */ 127 private static final String SETTINGS_EXTRA_FRAGMENT_ARG_KEY = ":settings:fragment_args_key"; 128 /** 129 * When starting this activity, this extra can also be specified to supply a Bundle of arguments 130 * to pass to that fragment when it is instantiated during the initial creation of the activity. 131 */ 132 private static final String SETTINGS_EXTRA_SHOW_FRAGMENT_ARGUMENTS = 133 ":settings:show_fragment_args"; 134 private static final String AUTO_DATA_SWITCH_SETTING_R_ID = "auto_data_switch"; 135 public static final Drawable EMPTY_DRAWABLE = new ColorDrawable(Color.TRANSPARENT); 136 public static final int NO_CELL_DATA_TYPE_ICON = 0; 137 private static final int SUBTITLE_TEXT_WIFI_IS_OFF = R.string.wifi_is_off; 138 private static final int SUBTITLE_TEXT_TAP_A_NETWORK_TO_CONNECT = 139 R.string.tap_a_network_to_connect; 140 private static final int SUBTITLE_TEXT_UNLOCK_TO_VIEW_NETWORKS = 141 R.string.unlock_to_view_networks; 142 private static final int SUBTITLE_TEXT_SEARCHING_FOR_NETWORKS = 143 R.string.wifi_empty_list_wifi_on; 144 private static final int SUBTITLE_TEXT_NON_CARRIER_NETWORK_UNAVAILABLE = 145 R.string.non_carrier_network_unavailable; 146 private static final int SUBTITLE_TEXT_ALL_CARRIER_NETWORK_UNAVAILABLE = 147 R.string.all_network_unavailable; 148 private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); 149 private static final TelephonyDisplayInfo DEFAULT_TELEPHONY_DISPLAY_INFO = 150 new TelephonyDisplayInfo(TelephonyManager.NETWORK_TYPE_UNKNOWN, 151 TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE, false, false, false); 152 153 static final int MAX_WIFI_ENTRY_COUNT = 3; 154 155 private final FeatureFlags mFeatureFlags; 156 157 @VisibleForTesting 158 /** Should be accessible only to the main thread. */ 159 final Map<Integer, TelephonyDisplayInfo> mSubIdTelephonyDisplayInfoMap = new HashMap<>(); 160 @VisibleForTesting 161 /** Should be accessible only to the main thread. */ 162 final Map<Integer, TelephonyManager> mSubIdTelephonyManagerMap = new HashMap<>(); 163 @VisibleForTesting 164 /** Should be accessible only to the main thread. */ 165 final Map<Integer, TelephonyCallback> mSubIdTelephonyCallbackMap = new HashMap<>(); 166 167 private WifiManager mWifiManager; 168 private Context mContext; 169 private SubscriptionManager mSubscriptionManager; 170 private TelephonyManager mTelephonyManager; 171 private ConnectivityManager mConnectivityManager; 172 private CarrierConfigTracker mCarrierConfigTracker; 173 private Handler mHandler; 174 private Handler mWorkerHandler; 175 private MobileMappings.Config mConfig = null; 176 private Executor mExecutor; 177 private AccessPointController mAccessPointController; 178 private IntentFilter mConnectionStateFilter; 179 @VisibleForTesting 180 @Nullable 181 InternetDialogCallback mCallback; 182 private UiEventLogger mUiEventLogger; 183 private BroadcastDispatcher mBroadcastDispatcher; 184 private KeyguardUpdateMonitor mKeyguardUpdateMonitor; 185 private GlobalSettings mGlobalSettings; 186 private int mDefaultDataSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; 187 private ConnectivityManager.NetworkCallback mConnectivityManagerNetworkCallback; 188 private WindowManager mWindowManager; 189 private ToastFactory mToastFactory; 190 private SignalDrawable mSignalDrawable; 191 private SignalDrawable mSecondarySignalDrawable; // For the secondary mobile data sub in DSDS 192 private LocationController mLocationController; 193 private DialogTransitionAnimator mDialogTransitionAnimator; 194 private boolean mHasWifiEntries; 195 private WifiStateWorker mWifiStateWorker; 196 private boolean mHasActiveSubIdOnDds; 197 private boolean mIsMobileDataEnabled = false; 198 199 @VisibleForTesting 200 Map<Integer, ServiceState> mSubIdServiceState = new HashMap<>(); 201 @VisibleForTesting 202 static final float TOAST_PARAMS_HORIZONTAL_WEIGHT = 1.0f; 203 @VisibleForTesting 204 static final float TOAST_PARAMS_VERTICAL_WEIGHT = 1.0f; 205 @VisibleForTesting 206 static final long SHORT_DURATION_TIMEOUT = 4000; 207 @VisibleForTesting 208 protected ActivityStarter mActivityStarter; 209 @VisibleForTesting 210 protected SubscriptionManager.OnSubscriptionsChangedListener mOnSubscriptionsChangedListener; 211 @VisibleForTesting 212 protected WifiUtils.InternetIconInjector mWifiIconInjector; 213 @VisibleForTesting 214 protected boolean mCanConfigWifi; 215 @VisibleForTesting 216 protected KeyguardStateController mKeyguardStateController; 217 @VisibleForTesting 218 protected boolean mHasEthernet = false; 219 @VisibleForTesting 220 protected ConnectedWifiInternetMonitor mConnectedWifiInternetMonitor; 221 @VisibleForTesting 222 protected boolean mCarrierNetworkChangeMode; 223 224 private final KeyguardUpdateMonitorCallback mKeyguardUpdateCallback = 225 new KeyguardUpdateMonitorCallback() { 226 @Override 227 public void onRefreshCarrierInfo() { 228 if (mCallback != null) { 229 mCallback.onRefreshCarrierInfo(); 230 } 231 } 232 233 @Override 234 public void onSimStateChanged(int subId, int slotId, int simState) { 235 if (mCallback != null) { 236 mCallback.onSimStateChanged(); 237 } 238 } 239 }; 240 getSubscriptionInfo()241 protected List<SubscriptionInfo> getSubscriptionInfo() { 242 return mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(); 243 } 244 245 @Inject InternetDetailsContentController(@hadeDisplayAware Context context, UiEventLogger uiEventLogger, ActivityStarter starter, AccessPointController accessPointController, SubscriptionManager subscriptionManager, TelephonyManager telephonyManager, @Nullable WifiManager wifiManager, ConnectivityManager connectivityManager, @Main Handler handler, @Main Executor mainExecutor, BroadcastDispatcher broadcastDispatcher, KeyguardUpdateMonitor keyguardUpdateMonitor, GlobalSettings globalSettings, KeyguardStateController keyguardStateController, @ShadeDisplayAware WindowManager windowManager, ToastFactory toastFactory, @Background Handler workerHandler, CarrierConfigTracker carrierConfigTracker, LocationController locationController, DialogTransitionAnimator dialogTransitionAnimator, WifiStateWorker wifiStateWorker, FeatureFlags featureFlags )246 public InternetDetailsContentController(@ShadeDisplayAware Context context, 247 UiEventLogger uiEventLogger, 248 ActivityStarter starter, AccessPointController accessPointController, 249 SubscriptionManager subscriptionManager, TelephonyManager telephonyManager, 250 @Nullable WifiManager wifiManager, ConnectivityManager connectivityManager, 251 @Main Handler handler, @Main Executor mainExecutor, 252 BroadcastDispatcher broadcastDispatcher, KeyguardUpdateMonitor keyguardUpdateMonitor, 253 GlobalSettings globalSettings, KeyguardStateController keyguardStateController, 254 @ShadeDisplayAware WindowManager windowManager, ToastFactory toastFactory, 255 @Background Handler workerHandler, 256 CarrierConfigTracker carrierConfigTracker, 257 LocationController locationController, 258 DialogTransitionAnimator dialogTransitionAnimator, 259 WifiStateWorker wifiStateWorker, 260 FeatureFlags featureFlags 261 ) { 262 if (DEBUG) { 263 Log.d(TAG, "Init InternetDetailsContentController"); 264 } 265 mHandler = handler; 266 mWorkerHandler = workerHandler; 267 mExecutor = mainExecutor; 268 mContext = context; 269 mGlobalSettings = globalSettings; 270 mWifiManager = wifiManager; 271 mTelephonyManager = telephonyManager; 272 mConnectivityManager = connectivityManager; 273 mSubscriptionManager = subscriptionManager; 274 mCarrierConfigTracker = carrierConfigTracker; 275 mBroadcastDispatcher = broadcastDispatcher; 276 mKeyguardUpdateMonitor = keyguardUpdateMonitor; 277 mKeyguardStateController = keyguardStateController; 278 mConnectionStateFilter = new IntentFilter(); 279 mConnectionStateFilter.addAction(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED); 280 mConnectionStateFilter.addAction(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION); 281 mUiEventLogger = uiEventLogger; 282 mActivityStarter = starter; 283 mAccessPointController = accessPointController; 284 mWifiIconInjector = new WifiUtils.InternetIconInjector(mContext); 285 mConnectivityManagerNetworkCallback = new DataConnectivityListener(); 286 mWindowManager = windowManager; 287 mToastFactory = toastFactory; 288 mSignalDrawable = new SignalDrawable(mContext); 289 mSecondarySignalDrawable = new SignalDrawable(mContext); 290 mLocationController = locationController; 291 mDialogTransitionAnimator = dialogTransitionAnimator; 292 mConnectedWifiInternetMonitor = new ConnectedWifiInternetMonitor(); 293 mWifiStateWorker = wifiStateWorker; 294 mFeatureFlags = featureFlags; 295 } 296 onStart(@onNull InternetDialogCallback callback, boolean canConfigWifi)297 void onStart(@NonNull InternetDialogCallback callback, boolean canConfigWifi) { 298 if (DEBUG) { 299 Log.d(TAG, "onStart"); 300 } 301 mCallback = callback; 302 mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateCallback); 303 mAccessPointController.addAccessPointCallback(this); 304 mBroadcastDispatcher.registerReceiver(mConnectionStateReceiver, mConnectionStateFilter, 305 mExecutor); 306 // Listen the subscription changes 307 mOnSubscriptionsChangedListener = new InternetOnSubscriptionChangedListener(); 308 refreshHasActiveSubIdOnDds(); 309 mSubscriptionManager.addOnSubscriptionsChangedListener(mExecutor, 310 mOnSubscriptionsChangedListener); 311 mDefaultDataSubId = getDefaultDataSubscriptionId(); 312 if (DEBUG) { 313 Log.d(TAG, "Init, SubId: " + mDefaultDataSubId); 314 } 315 mConfig = MobileMappings.Config.readConfig(mContext); 316 mTelephonyManager = mTelephonyManager.createForSubscriptionId(mDefaultDataSubId); 317 mSubIdTelephonyManagerMap.put(mDefaultDataSubId, mTelephonyManager); 318 registerInternetTelephonyCallback(mTelephonyManager, mDefaultDataSubId); 319 // Listen the connectivity changes 320 mConnectivityManager.registerDefaultNetworkCallback(mConnectivityManagerNetworkCallback); 321 mCanConfigWifi = canConfigWifi; 322 scanWifiAccessPoints(); 323 } 324 onStop()325 void onStop() { 326 if (DEBUG) { 327 Log.d(TAG, "onStop"); 328 } 329 mBroadcastDispatcher.unregisterReceiver(mConnectionStateReceiver); 330 for (TelephonyManager tm : mSubIdTelephonyManagerMap.values()) { 331 TelephonyCallback callback = mSubIdTelephonyCallbackMap.get(tm.getSubscriptionId()); 332 if (callback != null) { 333 tm.unregisterTelephonyCallback(callback); 334 } else if (DEBUG) { 335 Log.e(TAG, "Unexpected null telephony call back for Sub " + tm.getSubscriptionId()); 336 } 337 } 338 mSubIdTelephonyManagerMap.clear(); 339 mSubIdTelephonyCallbackMap.clear(); 340 mSubIdTelephonyDisplayInfoMap.clear(); 341 mSubscriptionManager.removeOnSubscriptionsChangedListener( 342 mOnSubscriptionsChangedListener); 343 mAccessPointController.removeAccessPointCallback(this); 344 mKeyguardUpdateMonitor.removeCallback(mKeyguardUpdateCallback); 345 mConnectivityManager.unregisterNetworkCallback(mConnectivityManagerNetworkCallback); 346 mConnectedWifiInternetMonitor.unregisterCallback(); 347 mCallback = null; 348 } 349 350 /** 351 * This is to generate and register the new callback to Telephony for uncached subscription id, 352 * then cache it. Telephony also cached this callback into 353 * {@link com.android.server.TelephonyRegistry}, so if subscription id and callback were cached 354 * already, it shall do nothing to avoid registering redundant callback to Telephony. 355 */ registerInternetTelephonyCallback( TelephonyManager telephonyManager, int subId)356 private void registerInternetTelephonyCallback( 357 TelephonyManager telephonyManager, int subId) { 358 if (mSubIdTelephonyCallbackMap.containsKey(subId)) { 359 // Avoid to generate and register unnecessary callback to Telephony. 360 return; 361 } 362 InternetTelephonyCallback telephonyCallback = new InternetTelephonyCallback(subId); 363 mSubIdTelephonyCallbackMap.put(subId, telephonyCallback); 364 telephonyManager.registerTelephonyCallback(mExecutor, telephonyCallback); 365 } 366 isAirplaneModeEnabled()367 boolean isAirplaneModeEnabled() { 368 return mGlobalSettings.getInt(Settings.Global.AIRPLANE_MODE_ON, 0) != 0; 369 } 370 setAirplaneModeDisabled()371 void setAirplaneModeDisabled() { 372 mConnectivityManager.setAirplaneMode(false); 373 } 374 getDefaultDataSubscriptionId()375 protected int getDefaultDataSubscriptionId() { 376 return mSubscriptionManager.getDefaultDataSubscriptionId(); 377 } 378 379 @VisibleForTesting getSettingsIntent()380 protected Intent getSettingsIntent() { 381 return new Intent(Settings.ACTION_NETWORK_PROVIDER_SETTINGS).addFlags( 382 Intent.FLAG_ACTIVITY_NEW_TASK); 383 } 384 385 @Nullable getWifiDetailsSettingsIntent(String key)386 protected Intent getWifiDetailsSettingsIntent(String key) { 387 if (TextUtils.isEmpty(key)) { 388 if (DEBUG) { 389 Log.d(TAG, "connected entry's key is empty"); 390 } 391 return null; 392 } 393 return WifiUtils.getWifiDetailsSettingsIntent(key); 394 } 395 getDialogTitleText()396 CharSequence getDialogTitleText() { 397 if (isAirplaneModeEnabled()) { 398 return mContext.getText(R.string.airplane_mode); 399 } 400 return mContext.getText(R.string.quick_settings_internet_label); 401 } 402 403 @Nullable getSubtitleText(boolean isProgressBarVisible)404 CharSequence getSubtitleText(boolean isProgressBarVisible) { 405 if (mCanConfigWifi && !isWifiEnabled()) { 406 // When Wi-Fi is disabled. 407 // Sub-Title: Wi-Fi is off 408 if (DEBUG) { 409 Log.d(TAG, "Wi-Fi off."); 410 } 411 return mContext.getText(SUBTITLE_TEXT_WIFI_IS_OFF); 412 } 413 414 if (isDeviceLocked()) { 415 // When the device is locked. 416 // Sub-Title: Unlock to view networks 417 if (DEBUG) { 418 Log.d(TAG, "The device is locked."); 419 } 420 return mContext.getText(SUBTITLE_TEXT_UNLOCK_TO_VIEW_NETWORKS); 421 } 422 423 if (mHasWifiEntries) { 424 return mCanConfigWifi ? mContext.getText(SUBTITLE_TEXT_TAP_A_NETWORK_TO_CONNECT) : null; 425 } 426 427 if (mCanConfigWifi && isProgressBarVisible) { 428 // When the Wi-Fi scan result callback is received 429 // Sub-Title: Searching for networks... 430 return mContext.getText(SUBTITLE_TEXT_SEARCHING_FOR_NETWORKS); 431 } 432 433 if (isCarrierNetworkActive()) { 434 return mContext.getText(SUBTITLE_TEXT_NON_CARRIER_NETWORK_UNAVAILABLE); 435 } 436 437 // Sub-Title: 438 // show non_carrier_network_unavailable 439 // - while Wi-Fi on + no Wi-Fi item 440 // - while Wi-Fi on + no Wi-Fi item + mobile data off 441 // show all_network_unavailable: 442 // - while Wi-Fi on + no Wi-Fi item + no carrier item 443 // - while Wi-Fi on + no Wi-Fi item + service is out of service 444 // - while Wi-Fi on + no Wi-Fi item + mobile data on + no carrier data. 445 if (DEBUG) { 446 Log.d(TAG, "No Wi-Fi item."); 447 } 448 boolean isActiveOnNonDds = getActiveAutoSwitchNonDdsSubId() != SubscriptionManager 449 .INVALID_SUBSCRIPTION_ID; 450 if (!hasActiveSubIdOnDds() || (!isVoiceStateInService(mDefaultDataSubId) 451 && !isDataStateInService(mDefaultDataSubId) && !isActiveOnNonDds)) { 452 if (DEBUG) { 453 Log.d(TAG, "No carrier or service is out of service."); 454 } 455 return mContext.getText(SUBTITLE_TEXT_ALL_CARRIER_NETWORK_UNAVAILABLE); 456 } 457 458 if (mCanConfigWifi && !mIsMobileDataEnabled) { 459 if (DEBUG) { 460 Log.d(TAG, "Mobile data off"); 461 } 462 return mContext.getText(SUBTITLE_TEXT_NON_CARRIER_NETWORK_UNAVAILABLE); 463 } 464 465 if (!activeNetworkIsCellular()) { 466 if (DEBUG) { 467 Log.d(TAG, "No carrier data."); 468 } 469 return mContext.getText(SUBTITLE_TEXT_ALL_CARRIER_NETWORK_UNAVAILABLE); 470 } 471 472 if (mCanConfigWifi) { 473 return mContext.getText(SUBTITLE_TEXT_NON_CARRIER_NETWORK_UNAVAILABLE); 474 } 475 return null; 476 } 477 478 @Nullable getInternetWifiDrawable(@onNull WifiEntry wifiEntry)479 Drawable getInternetWifiDrawable(@NonNull WifiEntry wifiEntry) { 480 Drawable drawable = getWifiDrawable(wifiEntry); 481 if (drawable == null) { 482 return null; 483 } 484 drawable.setTint(mContext.getColor(R.color.connected_network_primary_color)); 485 return drawable; 486 } 487 488 /** 489 * Returns a Wi-Fi icon {@link Drawable}. 490 * 491 * @param wifiEntry {@link WifiEntry} 492 */ 493 @Nullable getWifiDrawable(@onNull WifiEntry wifiEntry)494 Drawable getWifiDrawable(@NonNull WifiEntry wifiEntry) { 495 if (wifiEntry instanceof HotspotNetworkEntry) { 496 int deviceType = ((HotspotNetworkEntry) wifiEntry).getDeviceType(); 497 return mContext.getDrawable(getHotspotIconResource(deviceType)); 498 } 499 // If the Wi-Fi level is equal to WIFI_LEVEL_UNREACHABLE(-1), then a null drawable 500 // will be returned. 501 if (wifiEntry.getLevel() == WifiEntry.WIFI_LEVEL_UNREACHABLE) { 502 return null; 503 } 504 return mWifiIconInjector.getIcon(wifiEntry.shouldShowXLevelIcon(), wifiEntry.getLevel()); 505 } 506 getSignalStrengthDrawable(int subId)507 Drawable getSignalStrengthDrawable(int subId) { 508 Drawable drawable = mContext.getDrawable( 509 R.drawable.ic_signal_strength_zero_bar_no_internet); 510 try { 511 if (mTelephonyManager == null) { 512 if (DEBUG) { 513 Log.d(TAG, "TelephonyManager is null"); 514 } 515 return drawable; 516 } 517 518 boolean isCarrierNetworkActive = isCarrierNetworkActive(); 519 if (isDataStateInService(subId) || isVoiceStateInService(subId) 520 || isCarrierNetworkActive) { 521 AtomicReference<Drawable> shared = new AtomicReference<>(); 522 shared.set(getSignalStrengthDrawableWithLevel(isCarrierNetworkActive, subId)); 523 drawable = shared.get(); 524 } 525 526 int tintColor = Utils.getColorAttrDefaultColor(mContext, 527 android.R.attr.textColorTertiary); 528 if (activeNetworkIsCellular() || isCarrierNetworkActive) { 529 tintColor = mContext.getColor(R.color.connected_network_primary_color); 530 } 531 drawable.setTint(tintColor); 532 } catch (Throwable e) { 533 e.printStackTrace(); 534 } 535 return drawable; 536 } 537 538 /** 539 * To get the signal bar icon with level. 540 * 541 * @return The Drawable which is a signal bar icon with level. 542 */ getSignalStrengthDrawableWithLevel(boolean isCarrierNetworkActive, int subId)543 Drawable getSignalStrengthDrawableWithLevel(boolean isCarrierNetworkActive, int subId) { 544 TelephonyManager tm = mSubIdTelephonyManagerMap.getOrDefault(subId, mTelephonyManager); 545 final SignalStrength strength = tm.getSignalStrength(); 546 int level = (strength == null) ? 0 : strength.getLevel(); 547 int numLevels = SignalStrength.NUM_SIGNAL_STRENGTH_BINS; 548 if (isCarrierNetworkActive) { 549 level = getCarrierNetworkLevel(); 550 numLevels = WifiEntry.WIFI_LEVEL_MAX + 1; 551 } else if (mSubscriptionManager != null && shouldInflateSignalStrength(subId)) { 552 level += 1; 553 numLevels += 1; 554 } 555 return getSignalStrengthIcon(subId, mContext, level, numLevels, NO_CELL_DATA_TYPE_ICON, 556 !mIsMobileDataEnabled); 557 } 558 getSignalStrengthIcon(int subId, Context context, int level, int numLevels, int iconType, boolean cutOut)559 Drawable getSignalStrengthIcon(int subId, Context context, int level, int numLevels, 560 int iconType, boolean cutOut) { 561 boolean isForDds = subId == mDefaultDataSubId; 562 int levelDrawable = 563 mCarrierNetworkChangeMode ? SignalDrawable.getCarrierChangeState(numLevels) 564 : SignalDrawable.getState(level, numLevels, cutOut); 565 if (isForDds) { 566 mSignalDrawable.setLevel(levelDrawable); 567 } else { 568 mSecondarySignalDrawable.setLevel(levelDrawable); 569 } 570 571 // Make the network type drawable 572 final Drawable networkDrawable = 573 iconType == NO_CELL_DATA_TYPE_ICON 574 ? EMPTY_DRAWABLE 575 : context.getResources().getDrawable(iconType, context.getTheme()); 576 577 // Overlay the two drawables 578 final Drawable[] layers = {networkDrawable, isForDds 579 ? mSignalDrawable : mSecondarySignalDrawable}; 580 final int iconSize = 581 context.getResources().getDimensionPixelSize(R.dimen.signal_strength_icon_size); 582 583 final LayerDrawable icons = new LayerDrawable(layers); 584 // Set the network type icon at the top left 585 icons.setLayerGravity(0 /* index of networkDrawable */, Gravity.TOP | Gravity.LEFT); 586 // Set the signal strength icon at the bottom right 587 icons.setLayerGravity(1 /* index of SignalDrawable */, Gravity.BOTTOM | Gravity.RIGHT); 588 icons.setLayerSize(1 /* index of SignalDrawable */, iconSize, iconSize); 589 icons.setTintList(Utils.getColorAttr(context, android.R.attr.textColorTertiary)); 590 return icons; 591 } 592 shouldInflateSignalStrength(int subId)593 private boolean shouldInflateSignalStrength(int subId) { 594 return SignalStrengthUtil.shouldInflateSignalStrength(mContext, subId); 595 } 596 getUniqueSubscriptionDisplayName(int subscriptionId, Context context)597 private CharSequence getUniqueSubscriptionDisplayName(int subscriptionId, Context context) { 598 final Map<Integer, CharSequence> displayNames = getUniqueSubscriptionDisplayNames(context); 599 return displayNames.getOrDefault(subscriptionId, ""); 600 } 601 getUniqueSubscriptionDisplayNames(Context context)602 private Map<Integer, CharSequence> getUniqueSubscriptionDisplayNames(Context context) { 603 class DisplayInfo { 604 DisplayInfo(SubscriptionInfo subscriptionInfo, CharSequence originalName) { 605 this.subscriptionInfo = subscriptionInfo; 606 this.originalName = originalName; 607 } 608 609 public SubscriptionInfo subscriptionInfo; 610 public CharSequence originalName; 611 public CharSequence uniqueName; 612 } 613 614 // Map of SubscriptionId to DisplayName 615 final Supplier<Stream<DisplayInfo>> originalInfos = 616 () -> getSubscriptionInfo() 617 .stream() 618 .filter(i -> { 619 // Filter out null values. 620 return (i != null && i.getDisplayName() != null); 621 }) 622 .map(i -> new DisplayInfo(i, i.getDisplayName().toString().trim())); 623 624 // A Unique set of display names 625 Set<CharSequence> uniqueNames = new HashSet<>(); 626 // Return the set of duplicate names 627 final Set<CharSequence> duplicateOriginalNames = originalInfos.get() 628 .filter(info -> !uniqueNames.add(info.originalName)) 629 .map(info -> info.originalName) 630 .collect(Collectors.toSet()); 631 632 // If a display name is duplicate, append the final 4 digits of the phone number. 633 // Creates a mapping of Subscription id to original display name + phone number display name 634 final Supplier<Stream<DisplayInfo>> uniqueInfos = () -> originalInfos.get().map(info -> { 635 if (duplicateOriginalNames.contains(info.originalName)) { 636 // This may return null, if the user cannot view the phone number itself. 637 final String phoneNumber = DeviceInfoUtils.getBidiFormattedPhoneNumber(context, 638 info.subscriptionInfo); 639 String lastFourDigits = ""; 640 if (phoneNumber != null) { 641 lastFourDigits = (phoneNumber.length() > 4) 642 ? phoneNumber.substring(phoneNumber.length() - 4) : phoneNumber; 643 } 644 645 if (TextUtils.isEmpty(lastFourDigits)) { 646 info.uniqueName = info.originalName; 647 } else { 648 info.uniqueName = info.originalName + " " + lastFourDigits; 649 } 650 651 } else { 652 info.uniqueName = info.originalName; 653 } 654 return info; 655 }); 656 657 // Check uniqueness a second time. 658 // We might not have had permission to view the phone numbers. 659 // There might also be multiple phone numbers whose last 4 digits the same. 660 uniqueNames.clear(); 661 final Set<CharSequence> duplicatePhoneNames = uniqueInfos.get() 662 .filter(info -> !uniqueNames.add(info.uniqueName)) 663 .map(info -> info.uniqueName) 664 .collect(Collectors.toSet()); 665 666 return uniqueInfos.get().map(info -> { 667 if (duplicatePhoneNames.contains(info.uniqueName)) { 668 info.uniqueName = info.originalName + " " 669 + info.subscriptionInfo.getSubscriptionId(); 670 } 671 return info; 672 }).collect(Collectors.toMap( 673 info -> info.subscriptionInfo.getSubscriptionId(), 674 info -> info.uniqueName)); 675 } 676 677 /** 678 * @return the subId of the visible non-DDS if it's actively being used for data, otherwise 679 * return {@link SubscriptionManager#INVALID_SUBSCRIPTION_ID}. 680 */ 681 int getActiveAutoSwitchNonDdsSubId() { 682 if (!mFeatureFlags.isEnabled(Flags.QS_SECONDARY_DATA_SUB_INFO)) { 683 // sets the non-DDS to be not found to hide its visual 684 return SubscriptionManager.INVALID_SUBSCRIPTION_ID; 685 } 686 int activeDataSubId = SubscriptionManager.getActiveDataSubscriptionId(); 687 if (activeDataSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID 688 || mDefaultDataSubId == activeDataSubId) { 689 return SubscriptionManager.INVALID_SUBSCRIPTION_ID; 690 } 691 692 SubscriptionInfo subInfo = mSubscriptionManager.getActiveSubscriptionInfo( 693 SubscriptionManager.getActiveDataSubscriptionId()); 694 if (subInfo != null && subInfo.getSubscriptionId() != mDefaultDataSubId 695 && !subInfo.isOpportunistic()) { 696 int subId = subInfo.getSubscriptionId(); 697 if (mSubIdTelephonyManagerMap.get(subId) == null) { 698 TelephonyManager secondaryTm = mTelephonyManager.createForSubscriptionId(subId); 699 registerInternetTelephonyCallback(secondaryTm, subId); 700 mSubIdTelephonyManagerMap.put(subId, secondaryTm); 701 } 702 return subId; 703 } 704 return SubscriptionManager.INVALID_SUBSCRIPTION_ID; 705 706 } 707 708 CharSequence getMobileNetworkTitle(int subId) { 709 return getUniqueSubscriptionDisplayName(subId, mContext); 710 } 711 712 String getMobileNetworkSummary(int subId) { 713 String description = getNetworkTypeDescription(mContext, mConfig, subId); 714 return getMobileSummary(mContext, description, subId); 715 } 716 717 /** 718 * Get currently description of mobile network type. 719 */ 720 private String getNetworkTypeDescription(Context context, MobileMappings.Config config, 721 int subId) { 722 TelephonyDisplayInfo telephonyDisplayInfo = 723 mSubIdTelephonyDisplayInfoMap.getOrDefault(subId, DEFAULT_TELEPHONY_DISPLAY_INFO); 724 String iconKey = getIconKey(telephonyDisplayInfo); 725 726 if (mapIconSets(config) == null || mapIconSets(config).get(iconKey) == null) { 727 if (DEBUG) { 728 Log.d(TAG, "The description of network type is empty."); 729 } 730 return ""; 731 } 732 733 int resId = Objects.requireNonNull(mapIconSets(config).get(iconKey)).dataContentDescription; 734 SignalIcon.MobileIconGroup iconGroup; 735 if (isCarrierNetworkActive()) { 736 iconGroup = TelephonyIcons.CARRIER_MERGED_WIFI; 737 resId = iconGroup.dataContentDescription; 738 } else if (mCarrierNetworkChangeMode) { 739 iconGroup = TelephonyIcons.CARRIER_NETWORK_CHANGE; 740 resId = iconGroup.dataContentDescription; 741 } 742 743 return resId != 0 744 ? SubscriptionManager.getResourcesForSubId(context, subId).getString(resId) : ""; 745 } 746 747 private String getMobileSummary(Context context, String networkTypeDescription, int subId) { 748 if (!isMobileDataEnabled()) { 749 return context.getString(R.string.mobile_data_off_summary); 750 } 751 String summary = networkTypeDescription; 752 boolean isForDds = subId == mDefaultDataSubId; 753 int activeSubId = getActiveAutoSwitchNonDdsSubId(); 754 boolean isOnNonDds = activeSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID; 755 // Set network description for the carrier network when connecting to the carrier network 756 // under the airplane mode ON. 757 if (activeNetworkIsCellular() || isCarrierNetworkActive()) { 758 summary = context.getString( 759 com.android.settingslib.R.string.preference_summary_default_combination, 760 context.getString( 761 isForDds // if nonDds is active, explains Dds status as poor connection 762 ? (isOnNonDds ? R.string.mobile_data_poor_connection 763 : R.string.mobile_data_connection_active) 764 : R.string.mobile_data_temp_connection_active), 765 networkTypeDescription); 766 } else if (!isDataStateInService(subId)) { 767 summary = context.getString(R.string.mobile_data_no_connection); 768 } 769 return summary; 770 } 771 772 void startActivity(Intent intent, View view) { 773 ActivityTransitionAnimator.Controller controller = 774 mDialogTransitionAnimator.createActivityTransitionController(view); 775 776 if (controller == null && mCallback != null) { 777 mCallback.dismissDialog(); 778 } 779 780 mActivityStarter.postStartActivityDismissingKeyguard(intent, 0, controller); 781 } 782 783 void startActivityForDialog(Intent intent) { 784 mActivityStarter.startActivity(intent, false /* dismissShade */); 785 } 786 787 // Closes the dialog first, as the WEP dialog is in a different process and can have weird 788 // interactions otherwise. 789 void startActivityForDialogDismissDialogFirst(Intent intent, View view) { 790 ActivityTransitionAnimator.Controller controller = 791 mDialogTransitionAnimator.createActivityTransitionController(view); 792 if (mCallback != null) { 793 mCallback.dismissDialog(); 794 } 795 mActivityStarter.startActivity(intent, false /* dismissShade */, controller); 796 } 797 798 void launchNetworkSetting(View view) { 799 startActivity(getSettingsIntent(), view); 800 } 801 802 void launchWifiDetailsSetting(String key, View view) { 803 Intent intent = getWifiDetailsSettingsIntent(key); 804 if (intent != null) { 805 startActivity(intent, view); 806 } 807 } 808 809 void launchMobileNetworkSettings(View view) { 810 final int subId = getActiveAutoSwitchNonDdsSubId(); 811 if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { 812 Log.w(TAG, "launchMobileNetworkSettings fail, invalid subId:" + subId); 813 return; 814 } 815 startActivity(getSubSettingIntent(subId), view); 816 } 817 818 Intent getSubSettingIntent(int subId) { 819 final Intent intent = new Intent(Settings.ACTION_NETWORK_OPERATOR_SETTINGS); 820 final Bundle fragmentArgs = new Bundle(); 821 // Special contract for Settings to highlight permission row 822 fragmentArgs.putString(SETTINGS_EXTRA_FRAGMENT_ARG_KEY, AUTO_DATA_SWITCH_SETTING_R_ID); 823 intent.putExtra(Settings.EXTRA_SUB_ID, subId); 824 intent.putExtra(SETTINGS_EXTRA_SHOW_FRAGMENT_ARGUMENTS, fragmentArgs); 825 return intent; 826 } 827 828 void launchWifiScanningSetting(View view) { 829 final Intent intent = new Intent(ACTION_WIFI_SCANNING_SETTINGS); 830 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 831 startActivity(intent, view); 832 } 833 834 /** 835 * Enable or disable Wi-Fi. 836 * 837 * @param enabled {@code true} to enable, {@code false} to disable. 838 */ 839 @AnyThread 840 public void setWifiEnabled(boolean enabled) { 841 mWifiStateWorker.setWifiEnabled(enabled); 842 } 843 844 /** 845 * Return whether Wi-Fi is enabled or disabled. 846 * 847 * @return {@code true} if Wi-Fi is enabled or enabling 848 * @see WifiManager#getWifiState() 849 */ 850 @AnyThread 851 public boolean isWifiEnabled() { 852 return mWifiStateWorker.isWifiEnabled(); 853 } 854 855 void connectCarrierNetwork() { 856 String errorLogPrefix = "Fail to connect carrier network : "; 857 858 if (!isMobileDataEnabled()) { 859 if (DEBUG) { 860 Log.d(TAG, errorLogPrefix + "settings OFF"); 861 } 862 return; 863 } 864 if (isDeviceLocked()) { 865 if (DEBUG) { 866 Log.d(TAG, errorLogPrefix + "device locked"); 867 } 868 return; 869 } 870 if (activeNetworkIsCellular()) { 871 Log.d(TAG, errorLogPrefix + "already active"); 872 return; 873 } 874 875 MergedCarrierEntry mergedCarrierEntry = 876 mAccessPointController.getMergedCarrierEntry(); 877 if (mergedCarrierEntry == null) { 878 Log.e(TAG, errorLogPrefix + "no merged entry"); 879 return; 880 } 881 882 if (!mergedCarrierEntry.canConnect()) { 883 Log.w(TAG, errorLogPrefix + "merged entry connect state " 884 + mergedCarrierEntry.getConnectedState()); 885 return; 886 } 887 888 mergedCarrierEntry.connect(null /* ConnectCallback */, false); 889 makeOverlayToast(R.string.wifi_wont_autoconnect_for_now); 890 } 891 892 boolean isCarrierNetworkActive() { 893 final MergedCarrierEntry mergedCarrierEntry = 894 mAccessPointController.getMergedCarrierEntry(); 895 return mergedCarrierEntry != null && mergedCarrierEntry.isDefaultNetwork(); 896 } 897 898 int getCarrierNetworkLevel() { 899 final MergedCarrierEntry mergedCarrierEntry = 900 mAccessPointController.getMergedCarrierEntry(); 901 if (mergedCarrierEntry == null) return WifiEntry.WIFI_LEVEL_MIN; 902 903 int level = mergedCarrierEntry.getLevel(); 904 // To avoid icons not found with WIFI_LEVEL_UNREACHABLE(-1), use WIFI_LEVEL_MIN(0) instead. 905 if (level < WifiEntry.WIFI_LEVEL_MIN) level = WifiEntry.WIFI_LEVEL_MIN; 906 return level; 907 } 908 909 @WorkerThread 910 void setMergedCarrierWifiEnabledIfNeed(int subId, boolean enabled) { 911 // If the Carrier Provisions Wi-Fi Merged Networks enabled, do not set the merged carrier 912 // Wi-Fi state together. 913 if (mCarrierConfigTracker.getCarrierProvisionsWifiMergedNetworksBool(subId)) { 914 return; 915 } 916 917 final MergedCarrierEntry entry = mAccessPointController.getMergedCarrierEntry(); 918 if (entry == null) { 919 if (DEBUG) { 920 Log.d(TAG, "MergedCarrierEntry is null, can not set the status."); 921 } 922 return; 923 } 924 entry.setEnabled(enabled); 925 } 926 927 WifiManager getWifiManager() { 928 return mWifiManager; 929 } 930 931 TelephonyManager getTelephonyManager() { 932 return mTelephonyManager; 933 } 934 935 SubscriptionManager getSubscriptionManager() { 936 return mSubscriptionManager; 937 } 938 939 /** 940 * @return whether there is the carrier item in the slice. 941 */ 942 boolean hasActiveSubIdOnDds() { 943 if (isAirplaneModeEnabled() || mTelephonyManager == null) { 944 return false; 945 } 946 947 return mHasActiveSubIdOnDds; 948 } 949 950 private static boolean isEmbeddedSubscriptionVisible(@NonNull SubscriptionInfo subInfo) { 951 if (subInfo.isEmbedded() && subInfo.getProfileClass() == PROFILE_CLASS_PROVISIONING) { 952 return false; 953 } 954 return true; 955 } 956 957 private void refreshHasActiveSubIdOnDds() { 958 if (mSubscriptionManager == null) { 959 mHasActiveSubIdOnDds = false; 960 Log.e(TAG, "SubscriptionManager is null, set mHasActiveSubId = false"); 961 return; 962 } 963 int dds = getDefaultDataSubscriptionId(); 964 if (dds == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { 965 mHasActiveSubIdOnDds = false; 966 Log.d(TAG, "DDS is INVALID_SUBSCRIPTION_ID"); 967 return; 968 } 969 SubscriptionInfo ddsSubInfo = mSubscriptionManager.getActiveSubscriptionInfo(dds); 970 if (ddsSubInfo == null) { 971 mHasActiveSubIdOnDds = false; 972 Log.e(TAG, "Can't get DDS subscriptionInfo"); 973 return; 974 } else if (ddsSubInfo.isOnlyNonTerrestrialNetwork()) { 975 mHasActiveSubIdOnDds = false; 976 Log.d(TAG, "This is NTN, so do not show mobile data"); 977 return; 978 } 979 980 mHasActiveSubIdOnDds = isEmbeddedSubscriptionVisible(ddsSubInfo); 981 Log.i(TAG, "mHasActiveSubId:" + mHasActiveSubIdOnDds); 982 } 983 984 /** 985 * Return {@code true} if mobile data is enabled 986 */ 987 boolean isMobileDataEnabled() { 988 return mIsMobileDataEnabled; 989 } 990 991 /** 992 * Set whether to enable data for {@code subId}, also whether to disable data for other 993 * subscription 994 */ 995 void setMobileDataEnabled(Context context, int subId, boolean enabled, 996 boolean disableOtherSubscriptions) { 997 if (mTelephonyManager == null) { 998 if (DEBUG) { 999 Log.d(TAG, "TelephonyManager is null, can not set mobile data."); 1000 } 1001 return; 1002 } 1003 1004 if (mSubscriptionManager == null) { 1005 if (DEBUG) { 1006 Log.d(TAG, "SubscriptionManager is null, can not set mobile data."); 1007 } 1008 return; 1009 } 1010 1011 mTelephonyManager.setDataEnabledForReason( 1012 TelephonyManager.DATA_ENABLED_REASON_USER, enabled); 1013 if (disableOtherSubscriptions) { 1014 final List<SubscriptionInfo> subInfoList = 1015 mSubscriptionManager.getActiveSubscriptionInfoList(); 1016 if (subInfoList != null) { 1017 for (SubscriptionInfo subInfo : subInfoList) { 1018 // We never disable mobile data for opportunistic subscriptions. 1019 if (subInfo.getSubscriptionId() != subId && !subInfo.isOpportunistic()) { 1020 context.getSystemService(TelephonyManager.class).createForSubscriptionId( 1021 subInfo.getSubscriptionId()).setDataEnabled(false); 1022 } 1023 } 1024 } 1025 } 1026 mWorkerHandler.post(() -> setMergedCarrierWifiEnabledIfNeed(subId, enabled)); 1027 } 1028 1029 void setAutoDataSwitchMobileDataPolicy(int subId, boolean enable) { 1030 TelephonyManager tm = mSubIdTelephonyManagerMap.getOrDefault(subId, mTelephonyManager); 1031 if (tm == null) { 1032 if (DEBUG) { 1033 Log.d(TAG, "TelephonyManager is null, can not set mobile data."); 1034 } 1035 return; 1036 } 1037 tm.setMobileDataPolicyEnabled(TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH, enable); 1038 } 1039 1040 boolean isDataStateInService(int subId) { 1041 final ServiceState serviceState = mSubIdServiceState.getOrDefault(subId, 1042 new ServiceState()); 1043 NetworkRegistrationInfo regInfo = 1044 (serviceState == null) ? null : serviceState.getNetworkRegistrationInfo( 1045 NetworkRegistrationInfo.DOMAIN_PS, 1046 AccessNetworkConstants.TRANSPORT_TYPE_WWAN); 1047 return (regInfo == null) ? false : regInfo.isRegistered(); 1048 } 1049 1050 boolean isVoiceStateInService(int subId) { 1051 if (mTelephonyManager == null) { 1052 if (DEBUG) { 1053 Log.d(TAG, "TelephonyManager is null, can not detect voice state."); 1054 } 1055 return false; 1056 } 1057 1058 final ServiceState serviceState = mSubIdServiceState.getOrDefault(subId, 1059 new ServiceState()); 1060 return serviceState != null 1061 && serviceState.getState() == serviceState.STATE_IN_SERVICE; 1062 } 1063 1064 public boolean isDeviceLocked() { 1065 return !mKeyguardStateController.isUnlocked(); 1066 } 1067 1068 boolean activeNetworkIsCellular() { 1069 if (mConnectivityManager == null) { 1070 if (DEBUG) { 1071 Log.d(TAG, "ConnectivityManager is null, can not check active network."); 1072 } 1073 return false; 1074 } 1075 1076 final Network activeNetwork = mConnectivityManager.getActiveNetwork(); 1077 if (activeNetwork == null) { 1078 Log.d(TAG, "getActiveNetwork is null."); 1079 return false; 1080 } 1081 final NetworkCapabilities networkCapabilities = 1082 mConnectivityManager.getNetworkCapabilities(activeNetwork); 1083 if (networkCapabilities == null) { 1084 return false; 1085 } 1086 return networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR); 1087 } 1088 1089 boolean connect(WifiEntry ap) { 1090 if (ap == null) { 1091 if (DEBUG) { 1092 Log.d(TAG, "No Wi-Fi ap to connect."); 1093 } 1094 return false; 1095 } 1096 1097 if (ap.getWifiConfiguration() != null) { 1098 if (DEBUG) { 1099 Log.d(TAG, "connect networkId=" + ap.getWifiConfiguration().networkId); 1100 } 1101 } else { 1102 if (DEBUG) { 1103 Log.d(TAG, "connect to unsaved network " + ap.getTitle()); 1104 } 1105 } 1106 ap.connect(new WifiEntryConnectCallback(mActivityStarter, ap, this)); 1107 return false; 1108 } 1109 1110 @WorkerThread 1111 boolean isWifiScanEnabled() { 1112 if (!mLocationController.isLocationEnabled()) { 1113 return false; 1114 } 1115 return mWifiManager != null && mWifiManager.isScanAlwaysAvailable(); 1116 } 1117 1118 static class WifiEntryConnectCallback implements WifiEntry.ConnectCallback { 1119 final ActivityStarter mActivityStarter; 1120 final WifiEntry mWifiEntry; 1121 final InternetDetailsContentController mInternetDetailsContentController; 1122 1123 WifiEntryConnectCallback(ActivityStarter activityStarter, WifiEntry connectWifiEntry, 1124 InternetDetailsContentController internetDetailsContentController) { 1125 mActivityStarter = activityStarter; 1126 mWifiEntry = connectWifiEntry; 1127 mInternetDetailsContentController = internetDetailsContentController; 1128 } 1129 1130 @Override 1131 public void onConnectResult(@ConnectStatus int status) { 1132 if (DEBUG) { 1133 Log.d(TAG, "onConnectResult " + status); 1134 } 1135 1136 if (status == WifiEntry.ConnectCallback.CONNECT_STATUS_FAILURE_NO_CONFIG) { 1137 final Intent intent = WifiUtils.getWifiDialogIntent(mWifiEntry.getKey(), 1138 true /* connectForCaller */); 1139 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 1140 mActivityStarter.startActivity(intent, false /* dismissShade */); 1141 } else if (status == CONNECT_STATUS_FAILURE_UNKNOWN) { 1142 mInternetDetailsContentController.makeOverlayToast( 1143 R.string.wifi_failed_connect_message); 1144 } else { 1145 if (DEBUG) { 1146 Log.d(TAG, "connect failure reason=" + status); 1147 } 1148 } 1149 } 1150 } 1151 1152 private void scanWifiAccessPoints() { 1153 if (mCanConfigWifi) { 1154 mAccessPointController.scanForAccessPoints(); 1155 } 1156 } 1157 1158 @Override 1159 @WorkerThread 1160 public void onAccessPointsChanged(List<WifiEntry> accessPoints) { 1161 if (!mCanConfigWifi) { 1162 return; 1163 } 1164 1165 WifiEntry connectedEntry = null; 1166 List<WifiEntry> wifiEntries = null; 1167 final int accessPointsSize = (accessPoints == null) ? 0 : accessPoints.size(); 1168 final boolean hasMoreWifiEntries = (accessPointsSize > MAX_WIFI_ENTRY_COUNT); 1169 if (accessPointsSize > 0) { 1170 wifiEntries = new ArrayList<>(); 1171 final int count = hasMoreWifiEntries ? MAX_WIFI_ENTRY_COUNT : accessPointsSize; 1172 mConnectedWifiInternetMonitor.unregisterCallback(); 1173 for (int i = 0; i < count; i++) { 1174 WifiEntry entry = accessPoints.get(i); 1175 mConnectedWifiInternetMonitor.registerCallbackIfNeed(entry); 1176 if (connectedEntry == null && entry.isDefaultNetwork() 1177 && entry.hasInternetAccess()) { 1178 connectedEntry = entry; 1179 } else { 1180 wifiEntries.add(entry); 1181 } 1182 } 1183 mHasWifiEntries = true; 1184 } else { 1185 mHasWifiEntries = false; 1186 } 1187 1188 if (mCallback != null) { 1189 mCallback.onAccessPointsChanged(wifiEntries, connectedEntry, hasMoreWifiEntries); 1190 } 1191 } 1192 1193 @Override 1194 public void onSettingsActivityTriggered(Intent settingsIntent) { 1195 } 1196 1197 @Override 1198 public void onWifiScan(boolean isScan) { 1199 if (!isWifiEnabled() || isDeviceLocked()) { 1200 mCallback.onWifiScan(false); 1201 return; 1202 } 1203 mCallback.onWifiScan(isScan); 1204 } 1205 1206 private class InternetTelephonyCallback extends TelephonyCallback implements 1207 TelephonyCallback.DataEnabledListener, 1208 TelephonyCallback.DataConnectionStateListener, 1209 TelephonyCallback.DisplayInfoListener, 1210 TelephonyCallback.ServiceStateListener, 1211 TelephonyCallback.SignalStrengthsListener, 1212 TelephonyCallback.UserMobileDataStateListener, 1213 TelephonyCallback.CarrierNetworkListener { 1214 1215 private final int mSubId; 1216 1217 private InternetTelephonyCallback(int subId) { 1218 mSubId = subId; 1219 } 1220 1221 @Override 1222 public void onServiceStateChanged(@NonNull ServiceState serviceState) { 1223 if (mCallback != null) { 1224 mCallback.onServiceStateChanged(serviceState); 1225 } 1226 mSubIdServiceState.put(mSubId, serviceState); 1227 } 1228 1229 @Override 1230 public void onDataConnectionStateChanged(int state, int networkType) { 1231 if (mCallback != null) { 1232 mCallback.onDataConnectionStateChanged(state, networkType); 1233 } 1234 } 1235 1236 @Override 1237 public void onSignalStrengthsChanged(@NonNull SignalStrength signalStrength) { 1238 if (mCallback != null) { 1239 mCallback.onSignalStrengthsChanged(signalStrength); 1240 } 1241 } 1242 1243 @Override 1244 public void onDisplayInfoChanged(@NonNull TelephonyDisplayInfo telephonyDisplayInfo) { 1245 mSubIdTelephonyDisplayInfoMap.put(mSubId, telephonyDisplayInfo); 1246 if (mCallback != null) { 1247 mCallback.onDisplayInfoChanged(telephonyDisplayInfo); 1248 } 1249 } 1250 1251 @Override 1252 public void onUserMobileDataStateChanged(boolean enabled) { 1253 if (mCallback != null) { 1254 mCallback.onUserMobileDataStateChanged(enabled); 1255 } 1256 } 1257 1258 @Override 1259 public void onCarrierNetworkChange(boolean active) { 1260 mCarrierNetworkChangeMode = active; 1261 if (mCallback != null) { 1262 mCallback.onCarrierNetworkChange(active); 1263 } 1264 } 1265 1266 @Override 1267 public void onDataEnabledChanged(boolean b, int i) { 1268 if (mSubId == mDefaultDataSubId) { 1269 mIsMobileDataEnabled = b; 1270 } 1271 } 1272 } 1273 1274 private class InternetOnSubscriptionChangedListener 1275 extends SubscriptionManager.OnSubscriptionsChangedListener { 1276 InternetOnSubscriptionChangedListener() { 1277 super(); 1278 } 1279 1280 @Override 1281 public void onSubscriptionsChanged() { 1282 refreshHasActiveSubIdOnDds(); 1283 updateListener(); 1284 } 1285 } 1286 1287 private class DataConnectivityListener extends ConnectivityManager.NetworkCallback { 1288 @Override 1289 @WorkerThread 1290 public void onCapabilitiesChanged(@NonNull Network network, 1291 @NonNull NetworkCapabilities capabilities) { 1292 mHasEthernet = capabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET); 1293 if (mCanConfigWifi && (mHasEthernet || capabilities.hasTransport( 1294 NetworkCapabilities.TRANSPORT_WIFI))) { 1295 scanWifiAccessPoints(); 1296 } 1297 // update UI 1298 if (mCallback != null) { 1299 mCallback.onCapabilitiesChanged(network, capabilities); 1300 } 1301 } 1302 1303 @Override 1304 @WorkerThread 1305 public void onLost(@NonNull Network network) { 1306 mHasEthernet = false; 1307 if (mCallback != null) { 1308 mCallback.onLost(network); 1309 } 1310 } 1311 } 1312 1313 /** 1314 * Helper class for monitoring the Internet access of the connected WifiEntry. 1315 */ 1316 @VisibleForTesting 1317 protected class ConnectedWifiInternetMonitor implements WifiEntry.WifiEntryCallback { 1318 1319 private WifiEntry mWifiEntry; 1320 1321 public void registerCallbackIfNeed(WifiEntry entry) { 1322 if (entry == null || mWifiEntry != null) { 1323 return; 1324 } 1325 // If the Wi-Fi is not connected yet, or it's the connected Wi-Fi with Internet 1326 // access. Then we don't need to listen to the callback to update the Wi-Fi entries. 1327 if (entry.getConnectedState() != CONNECTED_STATE_CONNECTED 1328 || (entry.isDefaultNetwork() && entry.hasInternetAccess())) { 1329 return; 1330 } 1331 mWifiEntry = entry; 1332 entry.setListener(this); 1333 } 1334 1335 public void unregisterCallback() { 1336 if (mWifiEntry == null) { 1337 return; 1338 } 1339 mWifiEntry.setListener(null); 1340 mWifiEntry = null; 1341 } 1342 1343 @MainThread 1344 @Override 1345 public void onUpdated() { 1346 if (mWifiEntry == null) { 1347 return; 1348 } 1349 WifiEntry entry = mWifiEntry; 1350 if (entry.getConnectedState() != CONNECTED_STATE_CONNECTED) { 1351 unregisterCallback(); 1352 return; 1353 } 1354 if (entry.isDefaultNetwork() && entry.hasInternetAccess()) { 1355 unregisterCallback(); 1356 // Trigger onAccessPointsChanged() to update the Wi-Fi entries. 1357 scanWifiAccessPoints(); 1358 } 1359 } 1360 } 1361 1362 /** 1363 * Return {@code true} If the Ethernet exists 1364 */ 1365 @MainThread 1366 public boolean hasEthernet() { 1367 return mHasEthernet; 1368 } 1369 1370 private final BroadcastReceiver mConnectionStateReceiver = new BroadcastReceiver() { 1371 @Override 1372 public void onReceive(Context context, Intent intent) { 1373 final String action = intent.getAction(); 1374 if (TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED.equals(action)) { 1375 if (DEBUG) { 1376 Log.d(TAG, "ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED"); 1377 } 1378 mConfig = MobileMappings.Config.readConfig(context); 1379 refreshHasActiveSubIdOnDds(); 1380 updateListener(); 1381 } else if (WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION.equals(action)) { 1382 updateListener(); 1383 } 1384 } 1385 }; 1386 1387 private void updateListener() { 1388 int defaultDataSubId = getDefaultDataSubscriptionId(); 1389 if (mDefaultDataSubId == getDefaultDataSubscriptionId()) { 1390 if (DEBUG) { 1391 Log.d(TAG, "DDS: no change"); 1392 } 1393 return; 1394 } 1395 if (DEBUG) { 1396 Log.d(TAG, "DDS: defaultDataSubId:" + defaultDataSubId); 1397 } 1398 1399 if (SubscriptionManager.isUsableSubscriptionId(defaultDataSubId)) { 1400 // clean up old defaultDataSubId 1401 TelephonyCallback oldCallback = mSubIdTelephonyCallbackMap.get(mDefaultDataSubId); 1402 if (oldCallback != null) { 1403 mTelephonyManager.unregisterTelephonyCallback(oldCallback); 1404 } else if (DEBUG) { 1405 Log.e(TAG, "Unexpected null telephony call back for Sub " + mDefaultDataSubId); 1406 } 1407 mSubIdTelephonyCallbackMap.remove(mDefaultDataSubId); 1408 mSubIdTelephonyDisplayInfoMap.remove(mDefaultDataSubId); 1409 mSubIdTelephonyManagerMap.remove(mDefaultDataSubId); 1410 1411 // create for new defaultDataSubId 1412 mTelephonyManager = mTelephonyManager.createForSubscriptionId(defaultDataSubId); 1413 mSubIdTelephonyManagerMap.put(defaultDataSubId, mTelephonyManager); 1414 registerInternetTelephonyCallback(mTelephonyManager, defaultDataSubId); 1415 mCallback.onSubscriptionsChanged(defaultDataSubId); 1416 } 1417 mDefaultDataSubId = defaultDataSubId; 1418 } 1419 1420 boolean mayLaunchShareWifiSettings(WifiEntry wifiEntry, View view) { 1421 Intent intent = getConfiguratorQrCodeGeneratorIntentOrNull(wifiEntry); 1422 if (intent == null) { 1423 return false; 1424 } 1425 startActivity(intent, view); 1426 return true; 1427 } 1428 1429 interface InternetDialogCallback { 1430 1431 void onRefreshCarrierInfo(); 1432 1433 void onSimStateChanged(); 1434 1435 void onCapabilitiesChanged(Network network, NetworkCapabilities networkCapabilities); 1436 1437 void onLost(@NonNull Network network); 1438 1439 void onSubscriptionsChanged(int defaultDataSubId); 1440 1441 void onServiceStateChanged(ServiceState serviceState); 1442 1443 void onDataConnectionStateChanged(int state, int networkType); 1444 1445 void onSignalStrengthsChanged(SignalStrength signalStrength); 1446 1447 void onUserMobileDataStateChanged(boolean enabled); 1448 1449 void onDisplayInfoChanged(TelephonyDisplayInfo telephonyDisplayInfo); 1450 1451 void onCarrierNetworkChange(boolean active); 1452 1453 void dismissDialog(); 1454 1455 void onAccessPointsChanged(@Nullable List<WifiEntry> wifiEntries, 1456 @Nullable WifiEntry connectedEntry, boolean hasMoreWifiEntries); 1457 1458 void onWifiScan(boolean isScan); 1459 } 1460 1461 void makeOverlayToast(int stringId) { 1462 final Resources res = mContext.getResources(); 1463 1464 final SystemUIToast systemUIToast = mToastFactory.createToast(mContext, mContext, 1465 res.getString(stringId), mContext.getPackageName(), UserHandle.myUserId(), 1466 res.getConfiguration().orientation); 1467 if (systemUIToast == null) { 1468 return; 1469 } 1470 1471 View toastView = systemUIToast.getView(); 1472 1473 final WindowManager.LayoutParams params = new WindowManager.LayoutParams(); 1474 params.height = WindowManager.LayoutParams.WRAP_CONTENT; 1475 params.width = WindowManager.LayoutParams.WRAP_CONTENT; 1476 params.format = PixelFormat.TRANSLUCENT; 1477 params.type = WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL; 1478 params.flags = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON 1479 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE 1480 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; 1481 params.y = systemUIToast.getYOffset(); 1482 1483 int absGravity = Gravity.getAbsoluteGravity(systemUIToast.getGravity(), 1484 res.getConfiguration().getLayoutDirection()); 1485 params.gravity = absGravity; 1486 if ((absGravity & Gravity.HORIZONTAL_GRAVITY_MASK) == Gravity.FILL_HORIZONTAL) { 1487 params.horizontalWeight = TOAST_PARAMS_HORIZONTAL_WEIGHT; 1488 } 1489 if ((absGravity & Gravity.VERTICAL_GRAVITY_MASK) == Gravity.FILL_VERTICAL) { 1490 params.verticalWeight = TOAST_PARAMS_VERTICAL_WEIGHT; 1491 } 1492 1493 mWindowManager.addView(toastView, params); 1494 1495 Animator inAnimator = systemUIToast.getInAnimation(); 1496 if (inAnimator != null) { 1497 inAnimator.start(); 1498 } 1499 1500 mHandler.postDelayed(new Runnable() { 1501 @Override 1502 public void run() { 1503 Animator outAnimator = systemUIToast.getOutAnimation(); 1504 if (outAnimator != null) { 1505 outAnimator.start(); 1506 outAnimator.addListener(new AnimatorListenerAdapter() { 1507 @Override 1508 public void onAnimationEnd(Animator animator) { 1509 mWindowManager.removeViewImmediate(toastView); 1510 } 1511 }); 1512 } 1513 } 1514 }, SHORT_DURATION_TIMEOUT); 1515 } 1516 1517 Intent getConfiguratorQrCodeGeneratorIntentOrNull(WifiEntry wifiEntry) { 1518 if (!mFeatureFlags.isEnabled(Flags.SHARE_WIFI_QS_BUTTON) || wifiEntry == null 1519 || mWifiManager == null || !wifiEntry.canShare()) { 1520 return null; 1521 } 1522 var wifiConfiguration = wifiEntry.getWifiConfiguration(); 1523 if (wifiConfiguration == null) { 1524 return null; 1525 } 1526 Intent intent = new Intent(); 1527 intent.setAction(WifiDppIntentHelper.ACTION_CONFIGURATOR_AUTH_QR_CODE_GENERATOR); 1528 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); 1529 WifiDppIntentHelper.setConfiguratorIntentExtra(intent, mWifiManager, wifiConfiguration); 1530 return intent; 1531 } 1532 } 1533