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